| author | |
| committer | |
| log | 75ab5ab3fb6ad35117da754644c404a31b2fed84 |
| tree | 84dbe12f5605ca367f8a843a2f241b479bcdd01a |
| parent | b90898077e60290a1eb7bea4224f325fd3bb1595 |
| signature | Signed by PGP key B5690EEEBB952194 |
3 files changed, 86 insertions(+), 1 deletions(-)
packages/effect-codex-app-server/scripts/generate.ts+36-1| ... | @@ -194,6 +194,40 @@ const Codex0150DefinitionSchemas: Record<string, Schema.Json> = { | ... | @@ -194,6 +194,40 @@ const Codex0150DefinitionSchemas: Record<string, Schema.Json> = { |
| 194 | }, | 194 | }, |
| 195 | }; | 195 | }; |
| 196 | 196 | ||
| 197 | function applyCodex0151DefinitionCompatibility( | ||
| 198 | exportName: string, | ||
| 199 | definitionName: string, | ||
| 200 | definitionSchema: Schema.Json, | ||
| 201 | ): Schema.Json { | ||
| 202 | const isThreadResponse = | ||
| 203 | exportName === "V2ThreadReadResponse" || | ||
| 204 | exportName === "V2ThreadResumeResponse" || | ||
| 205 | exportName === "V2ThreadRollbackResponse"; | ||
| 206 | if ( | ||
| 207 | !isThreadResponse || | ||
| 208 | definitionName !== "CodexErrorInfo" || | ||
| 209 | typeof definitionSchema !== "object" | ||
| 210 | ) { | ||
| 211 | return definitionSchema; | ||
| 212 | } | ||
| 213 | |||
| 214 | const schema = definitionSchema as { | ||
| 215 | readonly oneOf?: ReadonlyArray<{ readonly enum?: ReadonlyArray<string> }>; | ||
| 216 | }; | ||
| 217 | const [firstVariant, ...remainingVariants] = schema.oneOf ?? []; | ||
| 218 | if (!firstVariant?.enum || firstVariant.enum.includes("rateLimitExceeded")) { | ||
| 219 | return definitionSchema; | ||
| 220 | } | ||
| 221 | |||
| 222 | return { | ||
| 223 | ...definitionSchema, | ||
| 224 | oneOf: [ | ||
| 225 | { ...firstVariant, enum: [...firstVariant.enum, "rateLimitExceeded"] }, | ||
| 226 | ...remainingVariants, | ||
| 227 | ], | ||
| 228 | }; | ||
| 229 | } | ||
| 230 | |||
| 197 | const getGeneratedPaths = Effect.fn("getGeneratedPaths")(function* () { | 231 | const getGeneratedPaths = Effect.fn("getGeneratedPaths")(function* () { |
| 198 | const path = yield* Path.Path; | 232 | const path = yield* Path.Path; |
| 199 | const generatedDir = path.join(import.meta.dirname, "..", "src", "_generated"); | 233 | const generatedDir = path.join(import.meta.dirname, "..", "src", "_generated"); |
| ... | @@ -660,7 +694,8 @@ const generateFiles = Effect.fn("generateFiles")(function* () { | ... | @@ -660,7 +694,8 @@ const generateFiles = Effect.fn("generateFiles")(function* () { |
| 660 | 694 | ||
| 661 | for (const [definitionName, definitionSchema] of Object.entries(parsed.definitions ?? {})) { | 695 | for (const [definitionName, definitionSchema] of Object.entries(parsed.definitions ?? {})) { |
| 662 | const compatibleDefinitionSchema = | 696 | const compatibleDefinitionSchema = |
| 663 | Codex0150DefinitionSchemas[definitionName] ?? definitionSchema; | 697 | Codex0150DefinitionSchemas[definitionName] ?? |
| 698 | applyCodex0151DefinitionCompatibility(file.exportName, definitionName, definitionSchema); | ||
| 664 | aggregateSchemas[localDefinitionNames.get(definitionName)!] = stripNullDefaults( | 699 | aggregateSchemas[localDefinitionNames.get(definitionName)!] = stripNullDefaults( |
| 665 | normalizeNullableTypes( | 700 | normalizeNullableTypes( |
| 666 | rewriteExternalRefs( | 701 | rewriteExternalRefs( |
packages/effect-codex-app-server/src/_generated/schema.gen.ts+6| ... | @@ -16854,6 +16854,7 @@ export type V2ThreadReadResponse__CodexErrorInfo = | ... | @@ -16854,6 +16854,7 @@ export type V2ThreadReadResponse__CodexErrorInfo = |
| 16854 | | "badRequest" | 16854 | | "badRequest" |
| 16855 | | "threadRollbackFailed" | 16855 | | "threadRollbackFailed" |
| 16856 | | "sandboxError" | 16856 | | "sandboxError" |
| 16857 | | "rateLimitExceeded" | ||
| 16857 | | "other" | 16858 | | "other" |
| 16858 | | { readonly httpConnectionFailed: { readonly httpStatusCode?: number | null } } | 16859 | | { readonly httpConnectionFailed: { readonly httpStatusCode?: number | null } } |
| 16859 | | { readonly responseStreamConnectionFailed: { readonly httpStatusCode?: number | null } } | 16860 | | { readonly responseStreamConnectionFailed: { readonly httpStatusCode?: number | null } } |
| ... | @@ -16877,6 +16878,7 @@ export const V2ThreadReadResponse__CodexErrorInfo = Schema.Union( | ... | @@ -16877,6 +16878,7 @@ export const V2ThreadReadResponse__CodexErrorInfo = Schema.Union( |
| 16877 | "badRequest", | 16878 | "badRequest", |
| 16878 | "threadRollbackFailed", | 16879 | "threadRollbackFailed", |
| 16879 | "sandboxError", | 16880 | "sandboxError", |
| 16881 | "rateLimitExceeded", | ||
| 16880 | "other", | 16882 | "other", |
| 16881 | ]), | 16883 | ]), |
| 16882 | Schema.Struct({ | 16884 | Schema.Struct({ |
| ... | @@ -17207,6 +17209,7 @@ export type V2ThreadResumeResponse__CodexErrorInfo = | ... | @@ -17207,6 +17209,7 @@ export type V2ThreadResumeResponse__CodexErrorInfo = |
| 17207 | | "badRequest" | 17209 | | "badRequest" |
| 17208 | | "threadRollbackFailed" | 17210 | | "threadRollbackFailed" |
| 17209 | | "sandboxError" | 17211 | | "sandboxError" |
| 17212 | | "rateLimitExceeded" | ||
| 17210 | | "other" | 17213 | | "other" |
| 17211 | | { readonly httpConnectionFailed: { readonly httpStatusCode?: number | null } } | 17214 | | { readonly httpConnectionFailed: { readonly httpStatusCode?: number | null } } |
| 17212 | | { readonly responseStreamConnectionFailed: { readonly httpStatusCode?: number | null } } | 17215 | | { readonly responseStreamConnectionFailed: { readonly httpStatusCode?: number | null } } |
| ... | @@ -17230,6 +17233,7 @@ export const V2ThreadResumeResponse__CodexErrorInfo = Schema.Union( | ... | @@ -17230,6 +17233,7 @@ export const V2ThreadResumeResponse__CodexErrorInfo = Schema.Union( |
| 17230 | "badRequest", | 17233 | "badRequest", |
| 17231 | "threadRollbackFailed", | 17234 | "threadRollbackFailed", |
| 17232 | "sandboxError", | 17235 | "sandboxError", |
| 17236 | "rateLimitExceeded", | ||
| 17233 | "other", | 17237 | "other", |
| 17234 | ]), | 17238 | ]), |
| 17235 | Schema.Struct({ | 17239 | Schema.Struct({ |
| ... | @@ -17485,6 +17489,7 @@ export type V2ThreadRollbackResponse__CodexErrorInfo = | ... | @@ -17485,6 +17489,7 @@ export type V2ThreadRollbackResponse__CodexErrorInfo = |
| 17485 | | "badRequest" | 17489 | | "badRequest" |
| 17486 | | "threadRollbackFailed" | 17490 | | "threadRollbackFailed" |
| 17487 | | "sandboxError" | 17491 | | "sandboxError" |
| 17492 | | "rateLimitExceeded" | ||
| 17488 | | "other" | 17493 | | "other" |
| 17489 | | { readonly httpConnectionFailed: { readonly httpStatusCode?: number | null } } | 17494 | | { readonly httpConnectionFailed: { readonly httpStatusCode?: number | null } } |
| 17490 | | { readonly responseStreamConnectionFailed: { readonly httpStatusCode?: number | null } } | 17495 | | { readonly responseStreamConnectionFailed: { readonly httpStatusCode?: number | null } } |
| ... | @@ -17508,6 +17513,7 @@ export const V2ThreadRollbackResponse__CodexErrorInfo = Schema.Union( | ... | @@ -17508,6 +17513,7 @@ export const V2ThreadRollbackResponse__CodexErrorInfo = Schema.Union( |
| 17508 | "badRequest", | 17513 | "badRequest", |
| 17509 | "threadRollbackFailed", | 17514 | "threadRollbackFailed", |
| 17510 | "sandboxError", | 17515 | "sandboxError", |
| 17516 | "rateLimitExceeded", | ||
| 17511 | "other", | 17517 | "other", |
| 17512 | ]), | 17518 | ]), |
| 17513 | Schema.Struct({ | 17519 | Schema.Struct({ |
packages/effect-codex-app-server/src/schema.test.ts+44| ... | @@ -4,6 +4,9 @@ import * as Schema from "effect/Schema"; | ... | @@ -4,6 +4,9 @@ import * as Schema from "effect/Schema"; |
| 4 | import * as CodexSchema from "./schema.ts"; | 4 | import * as CodexSchema from "./schema.ts"; |
| 5 | 5 | ||
| 6 | const isGetAccountResponse = Schema.is(CodexSchema.V2GetAccountResponse); | 6 | const isGetAccountResponse = Schema.is(CodexSchema.V2GetAccountResponse); |
| 7 | const isThreadReadResponse = Schema.is(CodexSchema.V2ThreadReadResponse); | ||
| 8 | const isThreadResumeResponse = Schema.is(CodexSchema.V2ThreadResumeResponse); | ||
| 9 | const isThreadRollbackResponse = Schema.is(CodexSchema.V2ThreadRollbackResponse); | ||
| 7 | 10 | ||
| 8 | it("keeps async questions in live notifications and thread history", () => { | 11 | it("keeps async questions in live notifications and thread history", () => { |
| 9 | const item = { | 12 | const item = { |
| ... | @@ -97,6 +100,47 @@ it("accepts Codex 0.150 multi-agent values", () => { | ... | @@ -97,6 +100,47 @@ it("accepts Codex 0.150 multi-agent values", () => { |
| 97 | assert.equal(Schema.is(CodexSchema.V2ThreadResumeResponse)(resumeResponse), true); | 100 | assert.equal(Schema.is(CodexSchema.V2ThreadResumeResponse)(resumeResponse), true); |
| 98 | }); | 101 | }); |
| 99 | 102 | ||
| 103 | it("accepts Codex rate limit errors for thread responses", () => { | ||
| 104 | const failedThread = { | ||
| 105 | cliVersion: "0.150.0", | ||
| 106 | createdAt: 0, | ||
| 107 | cwd: "/tmp/project", | ||
| 108 | ephemeral: false, | ||
| 109 | id: "thread-1", | ||
| 110 | modelProvider: "openai", | ||
| 111 | preview: "", | ||
| 112 | sessionId: "session-1", | ||
| 113 | source: "cli", | ||
| 114 | status: { type: "idle" }, | ||
| 115 | turns: [ | ||
| 116 | { | ||
| 117 | error: { | ||
| 118 | codexErrorInfo: "rateLimitExceeded", | ||
| 119 | message: "Rate limit exceeded", | ||
| 120 | }, | ||
| 121 | id: "turn-1", | ||
| 122 | items: [], | ||
| 123 | status: "failed", | ||
| 124 | }, | ||
| 125 | ], | ||
| 126 | updatedAt: 0, | ||
| 127 | }; | ||
| 128 | assert.equal(isThreadReadResponse({ thread: failedThread }), true); | ||
| 129 | assert.equal( | ||
| 130 | isThreadResumeResponse({ | ||
| 131 | approvalPolicy: "never", | ||
| 132 | approvalsReviewer: "user", | ||
| 133 | cwd: "/tmp/project", | ||
| 134 | model: "gpt-5.6-sol", | ||
| 135 | modelProvider: "openai", | ||
| 136 | sandbox: { type: "dangerFullAccess" }, | ||
| 137 | thread: failedThread, | ||
| 138 | }), | ||
| 139 | true, | ||
| 140 | ); | ||
| 141 | assert.equal(isThreadRollbackResponse({ thread: failedThread }), true); | ||
| 142 | }); | ||
| 143 | |||
| 100 | it("accepts Codex 0.150 account plan values", () => { | 144 | it("accepts Codex 0.150 account plan values", () => { |
| 101 | const planTypes = [ | 145 | const planTypes = [ |
| 102 | "self_serve_business_prolite", | 146 | "self_serve_business_prolite", |