import { describe, expect } from "bun:test" import { LLM } from "@opencode-ai/llm" import { OpenAI } from "@opencode-ai/llm/providers" import { LLMClient } from "@opencode-ai/llm/route" import { DateTime, Effect } from "effect" import { Headers } from "effect/unstable/http" import { Credential } from "@opencode-ai/core/credential" import { ModelV2 } from "@opencode-ai/core/model" import { ProviderV2 } from "@opencode-ai/core/provider" import { ProjectV2 } from "@opencode-ai/core/project" import { SessionRunnerModel } from "@opencode-ai/core/session/runner/model" import { SessionV2 } from "@opencode-ai/core/session" import { AbsolutePath } from "@opencode-ai/core/schema" import { it } from "./lib/effect" type Transport = { readonly package: string readonly settings?: Record } const model = (transport: Transport, variants?: NonNullable) => ModelV2.Info.make({ id: ModelV2.ID.make("test-model"), modelID: ModelV2.ID.make("api-test-model"), providerID: ProviderV2.ID.make("test-provider"), name: "Test model", ...transport, settings: { apiKey: "secret", ...transport.settings }, capabilities: { tools: true, input: ["text"], output: ["text"] }, headers: { "x-test": "header" }, body: { custom_extension: { enabled: true } }, variants, time: { released: 0 }, cost: [], status: "active", enabled: true, limit: { context: 100, output: 20 }, }) const aisdkDependencies = { loadAISDK: (input: ModelV2.Info) => Effect.succeed( OpenAI.model(input.modelID ?? input.id, { ...input.settings, headers: input.headers, body: input.body, limits: { context: input.limit.context, output: input.limit.output }, }), ), } describe("SessionRunnerModel", () => { it.effect("constructs native provider package models mechanically", () => Effect.gen(function* () { const resolved = yield* SessionRunnerModel.fromCatalogModel( model({ package: "@opencode-ai/llm/providers/openai", settings: { baseURL: "https://openai.example/v1" }, }), Credential.Key.make({ type: "key", key: "runtime-secret" }), ) const headers = yield* resolved.route.auth.apply({ request: LLM.request({ model: resolved, prompt: "Hello" }), method: "POST", url: "https://openai.example/v1/responses", body: "{}", headers: Headers.empty, }) expect(String(resolved.id)).toBe("api-test-model") expect(resolved.route.id).toBe("openai-responses") expect(resolved.route.defaults.headers).toEqual({ "x-test": "header" }) expect(resolved.route.defaults.http?.body).toEqual({ custom_extension: { enabled: true } }) expect(resolved.route.defaults.limits).toEqual({ context: 100, output: 20 }) expect(headers.authorization).toBe("Bearer runtime-secret") }), ) it.effect("maps catalog OpenAI native provider packages into Responses routes", () => Effect.gen(function* () { const resolved = yield* SessionRunnerModel.fromCatalogModel( model({ package: "@opencode-ai/llm/providers/openai", settings: { baseURL: "https://openai.example/v1" } }), ) expect(resolved).toMatchObject({ id: "api-test-model", provider: "test-provider" }) expect(resolved.route).toMatchObject({ id: "openai-responses", endpoint: { baseURL: "https://openai.example/v1" }, defaults: { headers: { "x-test": "header" }, limits: { context: 100, output: 20 }, http: { body: { custom_extension: { enabled: true } } }, }, }) }), ) it.effect("keeps catalog apiKey credentials out of provider JSON", () => Effect.gen(function* () { const resolved = yield* SessionRunnerModel.fromCatalogModel( model({ package: "@opencode-ai/llm/providers/openai", settings: { baseURL: "https://openai.example/v1" } }), ) const prepared = yield* LLMClient.prepare(LLM.request({ model: resolved, prompt: "Hello" })) expect(JSON.stringify(prepared.body)).not.toContain("apiKey") expect(JSON.stringify(prepared.body)).not.toContain("secret") }), ) it.effect("uses merged API settings for OpenAI-compatible auth and request defaults", () => Effect.gen(function* () { const resolved = yield* SessionRunnerModel.fromCatalogModel( ModelV2.Info.make({ ...model({ package: "@opencode-ai/llm/providers/openai-compatible", settings: { apiKey: "settings-secret", baseURL: "https://compatible.example/v1", compatibility: "strict", }, }), headers: {}, body: {}, }), ) const request = LLM.request({ model: resolved, prompt: "Hello" }) const headers = yield* resolved.route.auth.apply({ request, method: "POST", url: "https://compatible.example/v1/chat/completions", body: "{}", headers: Headers.empty, }) expect(headers.authorization).toBe("Bearer settings-secret") expect(resolved.route.defaults.http?.body).toEqual({}) }), ) it.effect("overlays selected OpenAI Session variant bodies", () => Effect.gen(function* () { const catalog = model({ package: "@opencode-ai/llm/providers/openai", settings: { baseURL: "https://openai.example/v1" } }, [ { id: ModelV2.VariantID.make("high"), headers: { "x-variant": "high" }, body: { store: false, service_tier: "priority", temperature: 0.2, reasoning: { effort: "high" }, }, }, ]) const session = SessionV2.Info.make({ id: SessionV2.ID.make("ses_model_variant"), projectID: ProjectV2.ID.global, title: "test", model: { id: catalog.id, providerID: catalog.providerID, variant: ModelV2.VariantID.make("high"), }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, time: { created: DateTime.makeUnsafe(0), updated: DateTime.makeUnsafe(0) }, location: { directory: AbsolutePath.make("/project") }, }) const resolved = yield* SessionRunnerModel.resolve(session, catalog) expect(resolved.route.defaults.headers).toMatchObject({ "x-test": "header", "x-variant": "high" }) expect(resolved.route.defaults.http?.body).toEqual({ custom_extension: { enabled: true }, store: false, service_tier: "priority", temperature: 0.2, reasoning: { effort: "high" }, }) }), ) it.effect("overlays selected OpenAI-compatible Session variant bodies", () => Effect.gen(function* () { const catalog = model( { package: "@opencode-ai/llm/providers/openai-compatible", settings: { baseURL: "https://compatible.example/v1" }, }, [ { id: ModelV2.VariantID.make("high"), headers: {}, body: { store: false, reasoning_effort: "high" }, }, ], ) const session = SessionV2.Info.make({ id: SessionV2.ID.make("ses_compatible_variant"), projectID: ProjectV2.ID.global, title: "test", model: { id: catalog.id, providerID: catalog.providerID, variant: ModelV2.VariantID.make("high") }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, time: { created: DateTime.makeUnsafe(0), updated: DateTime.makeUnsafe(0) }, location: { directory: AbsolutePath.make("/project") }, }) const resolved = yield* SessionRunnerModel.resolve(session, catalog) expect(resolved.route.defaults.http?.body).toEqual({ custom_extension: { enabled: true }, store: false, reasoning_effort: "high", }) }), ) it.effect("rejects an explicit unavailable Session variant during model resolution", () => Effect.gen(function* () { const catalog = model({ package: "@opencode-ai/llm/providers/openai", settings: { baseURL: "https://openai.example/v1" } }) const session = SessionV2.Info.make({ id: SessionV2.ID.make("ses_model_variant_unavailable"), projectID: ProjectV2.ID.global, title: "test", model: { id: catalog.id, providerID: catalog.providerID, variant: ModelV2.VariantID.make("unknown"), }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, time: { created: DateTime.makeUnsafe(0), updated: DateTime.makeUnsafe(0) }, location: { directory: AbsolutePath.make("/project") }, }) const failure = yield* SessionRunnerModel.resolve(session, catalog).pipe(Effect.flip) expect(failure).toMatchObject({ _tag: "SessionRunnerModel.VariantUnavailableError", providerID: "test-provider", modelID: "test-model", variant: "unknown", }) expect(failure.message).toBe("Variant unavailable for test-provider/test-model: unknown") }), ) it.effect("overlays selected Anthropic Session variant bodies", () => Effect.gen(function* () { const catalog = model( { package: "@opencode-ai/llm/providers/anthropic", settings: { baseURL: "https://anthropic.example/v1" } }, [ { id: ModelV2.VariantID.make("high"), headers: {}, body: { thinking: { type: "enabled", budget_tokens: 12000 } }, }, ], ) const session = SessionV2.Info.make({ id: SessionV2.ID.make("ses_anthropic_variant"), projectID: ProjectV2.ID.global, title: "test", model: { id: catalog.id, providerID: catalog.providerID, variant: ModelV2.VariantID.make("high") }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, time: { created: DateTime.makeUnsafe(0), updated: DateTime.makeUnsafe(0) }, location: { directory: AbsolutePath.make("/project") }, }) const resolved = yield* SessionRunnerModel.resolve(session, catalog) expect(resolved.route.defaults.http?.body).toEqual({ custom_extension: { enabled: true }, thinking: { type: "enabled", budget_tokens: 12000 }, }) }), ) it.effect("maps catalog Anthropic native provider packages into native routes", () => Effect.gen(function* () { const resolved = yield* SessionRunnerModel.fromCatalogModel( model({ package: "@opencode-ai/llm/providers/anthropic", settings: { baseURL: "https://anthropic.example/v1" } }), ) expect(resolved.route).toMatchObject({ id: "anthropic-messages", endpoint: { baseURL: "https://anthropic.example/v1" }, }) }), ) it.effect("uses resolved credentials for bearer auth", () => Effect.gen(function* () { const resolved = yield* SessionRunnerModel.fromCatalogModel( ModelV2.Info.make({ ...model({ package: "@opencode-ai/llm/providers/openai", settings: { baseURL: "https://openai.example/v1" } }), headers: {}, body: {}, }), Credential.Key.make({ type: "key", key: "secret" }), ) const request = LLM.request({ model: resolved, prompt: "Hello" }) const headers = yield* resolved.route.auth.apply({ request, method: "POST", url: "https://openai.example/v1/responses", body: "{}", headers: Headers.empty, }) expect(headers.authorization).toBe("Bearer secret") }), ) it.effect("prefers stored credentials over configured auth", () => Effect.gen(function* () { const credential = Credential.Key.make({ type: "key", key: "stored-secret", metadata: { tenant: "work" } }) const resolved = yield* SessionRunnerModel.fromCatalogModel( ModelV2.Info.make({ ...model({ package: "@opencode-ai/llm/providers/openai", settings: { baseURL: "https://openai.example/v1" } }), settings: { apiKey: "configured-secret", baseURL: "https://openai.example/v1" }, headers: {}, body: {}, }), credential, ) const headers = yield* resolved.route.auth.apply({ request: LLM.request({ model: resolved, prompt: "Hello" }), method: "POST", url: "https://openai.example/v1/responses", body: "{}", headers: Headers.empty, }) expect(headers.authorization).toBe("Bearer stored-secret") expect(resolved.route.defaults.http?.body).toEqual({}) }), ) it.effect("delegates aisdk-prefixed packages to the compatibility resolver", () => Effect.gen(function* () { const resolved = yield* SessionRunnerModel.fromCatalogModel( model({ package: "aisdk:@ai-sdk/google", settings: { baseURL: "https://google.example/v1" } }), undefined, aisdkDependencies, ) expect(resolved.route.id).toBe("openai-responses") expect(resolved.route.endpoint).toMatchObject({ baseURL: "https://google.example/v1" }) }), ) it.effect("reports whether a catalog model has a supported package", () => Effect.sync(() => { expect( SessionRunnerModel.supported( model({ package: "aisdk:@ai-sdk/google", settings: { baseURL: "https://google.example/v1" } }), ), ).toBe(true) expect(SessionRunnerModel.supported(model({ package: "native-provider-package" }))).toBe(true) }), ) })