| 1 | import * as Config from "@effect/ai-codegen/Config" |
| 2 | import * as Generator from "@effect/ai-codegen/Generator" |
| 3 | import * as NodeServices from "@effect/platform-node/NodeServices" |
| 4 | import { assert, describe, it } from "@effect/vitest" |
| 5 | import * as Effect from "effect/Effect" |
| 6 | import * as Yaml from "effect/encoding/Yaml" |
| 7 | import * as FileSystem from "effect/FileSystem" |
| 8 | import * as Layer from "effect/Layer" |
| 9 | import * as Schema from "effect/Schema" |
| 10 | |
| 11 | const operation = (operationId: string) => ({ |
| 12 | operationId, |
| 13 | requestBody: { |
| 14 | required: true, |
| 15 | content: { |
| 16 | "application/json": { |
| 17 | schema: { type: "object", properties: { input_audio: { type: "string" } }, required: ["input_audio"] } |
| 18 | }, |
| 19 | "multipart/form-data": { |
| 20 | schema: { type: "object", properties: { file: { type: "string", format: "binary" } }, required: ["file"] } |
| 21 | } |
| 22 | } |
| 23 | }, |
| 24 | responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "string" } } } } } |
| 25 | }) |
| 26 | |
| 27 | describe("OpenRouter transcription spec patch", () => { |
| 28 | it.effect("selects JSON only for transcriptions while preserving multipart elsewhere", () => |
| 29 | Effect.gen(function*() { |
| 30 | const fs = yield* FileSystem.FileSystem |
| 31 | const generator = yield* Generator.CodeGenerator |
| 32 | const config = Schema.decodeUnknownSync(Config.CodegenConfig)(Yaml.parse( |
| 33 | yield* fs.readFileString(new URL("../../../ai/openrouter/codegen.yml", import.meta.url).pathname) |
| 34 | )) |
| 35 | const patches = config.patchList.filter((patch) => patch.includes("/paths/~1audio~1transcriptions/")) |
| 36 | assert.strictEqual(patches.length, 1) |
| 37 | const generate = (patches: ReadonlyArray<string>) => |
| 38 | generator.generate({ |
| 39 | name: "openrouter", |
| 40 | packagePath: ".", |
| 41 | outputPath: "Generated.ts", |
| 42 | specSource: Config.SpecSource.File("fixture.json"), |
| 43 | config: new Config.CodegenConfig({ ...config, patches }) |
| 44 | }, { |
| 45 | openapi: "3.1.0", |
| 46 | info: { title: "Transcriptions", version: "1.0.0" }, |
| 47 | paths: { |
| 48 | "/audio/transcriptions": { post: operation("createAudioTranscriptions") }, |
| 49 | "/uploads": { post: operation("upload") } |
| 50 | } |
| 51 | }) |
| 52 | const before = yield* generate([]) |
| 53 | const after = yield* generate(patches) |
| 54 | assert.include(before, "CreateAudioTranscriptionsRequestFormData.Encoded") |
| 55 | assert.notInclude(after, "CreateAudioTranscriptionsRequestFormData") |
| 56 | assert.include(after, "CreateAudioTranscriptionsRequestJson.Encoded") |
| 57 | assert.include(after, "UploadRequestFormData.Encoded") |
| 58 | assert.strictEqual(before.match(/HttpClientRequest.bodyFormDataRecord/g)?.length, 2) |
| 59 | assert.strictEqual(after.match(/HttpClientRequest.bodyFormDataRecord/g)?.length, 1) |
| 60 | assert.strictEqual(after.match(/HttpClientRequest.bodyJsonUnsafe/g)?.length, 1) |
| 61 | }).pipe(Effect.provide(Generator.layerSchema.pipe(Layer.provideMerge(NodeServices.layer))))) |
| 62 | }) |