Download packages/core/test/plugin/provider-amazon-bedrock.test.ts from SaylorTwift/opencode: direct link, hf CLI and curl.
- Browser
- Download file 26.9 kB
-
https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/core/test/plugin/provider-amazon-bedrock.test.ts
- Command line
-
hf download hf://SaylorTwift/opencode/packages/core/test/plugin/provider-amazon-bedrock.test.ts
-
curl -L -o provider-amazon-bedrock.test.ts https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/core/test/plugin/provider-amazon-bedrock.test.ts
26.9 kB
| import { AISDK } from "@opencode-ai/core/aisdk" | |
| import { describe, expect } from "bun:test" | |
| import type { LanguageModelV3 } from "@ai-sdk/provider" | |
| import { Effect } from "effect" | |
| import { Catalog } from "@opencode-ai/core/catalog" | |
| import { ModelV2 } from "@opencode-ai/core/model" | |
| import { PluginV2 } from "@opencode-ai/core/plugin" | |
| import { PluginHost } from "@opencode-ai/core/plugin/host" | |
| import { AmazonBedrockPlugin } from "@opencode-ai/core/plugin/provider/amazon-bedrock" | |
| import { ProviderV2 } from "@opencode-ai/core/provider" | |
| import { testEffect } from "../lib/effect" | |
| import { PluginTestLayer } from "./fixture" | |
| const it = testEffect(PluginTestLayer) | |
| const addPlugin = Effect.fn(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const host = yield* PluginHost.make(plugin) | |
| yield* AmazonBedrockPlugin.effect(host) | |
| }) | |
| function required<T>(value: T | undefined): T { | |
| if (value === undefined) throw new Error("Expected value") | |
| return value | |
| } | |
| function withEnv<A, E, R>(vars: Record<string, string | undefined>, fx: () => Effect.Effect<A, E, R>) { | |
| return Effect.acquireUseRelease( | |
| Effect.sync(() => { | |
| const previous = Object.fromEntries(Object.keys(vars).map((key) => [key, process.env[key]])) | |
| Object.entries(vars).forEach(([key, value]) => { | |
| if (value === undefined) delete process.env[key] | |
| else process.env[key] = value | |
| }) | |
| return previous | |
| }), | |
| fx, | |
| (previous) => | |
| Effect.sync(() => { | |
| Object.entries(previous).forEach(([key, value]) => { | |
| if (value === undefined) delete process.env[key] | |
| else process.env[key] = value | |
| }) | |
| }), | |
| ) | |
| } | |
| function fakeSelectorSdk(calls: string[]) { | |
| const make = (method: string) => (id: string) => { | |
| calls.push(`${method}:${id}`) | |
| return { modelId: id, provider: method, specificationVersion: "v3" } as unknown as LanguageModelV3 | |
| } | |
| return { | |
| responses: make("responses"), | |
| messages: make("messages"), | |
| chat: make("chat"), | |
| languageModel: make("languageModel"), | |
| } | |
| } | |
| function bedrockBaseURL(sdk: unknown, modelID = "anthropic.claude-sonnet-4-5") { | |
| const language = (sdk as { languageModel: (id: string) => unknown }).languageModel(modelID) | |
| return (language as { config: { baseUrl: () => string } }).config.baseUrl() | |
| } | |
| function bedrockFetch(sdk: unknown, modelID = "anthropic.claude-sonnet-4-5") { | |
| const language = (sdk as { languageModel: (id: string) => unknown }).languageModel(modelID) | |
| return ( | |
| language as { config: { fetch: (input: Parameters<typeof fetch>[0], init?: RequestInit) => Promise<Response> } } | |
| ).config.fetch | |
| } | |
| function openAIUrl(language: unknown, path: string, modelId: string) { | |
| return (language as { config: { url: (input: { path: string; modelId: string }) => string } }).config.url({ | |
| path, | |
| modelId, | |
| }) | |
| } | |
| describe("AmazonBedrockPlugin", () => { | |
| it.effect("moves endpoint option to api URL", () => | |
| Effect.gen(function* () { | |
| const catalog = yield* Catalog.Service | |
| yield* catalog.transform((catalog) => { | |
| const bedrock = ProviderV2.Info.make({ | |
| ...ProviderV2.Info.empty(ProviderV2.ID.amazonBedrock), | |
| api: { type: "aisdk", package: "@ai-sdk/amazon-bedrock" }, | |
| request: { | |
| headers: {}, | |
| body: { endpoint: "https://bedrock.example" }, | |
| }, | |
| }) | |
| catalog.provider.update(bedrock.id, (item) => { | |
| item.api = bedrock.api | |
| item.request = bedrock.request | |
| }) | |
| }) | |
| yield* addPlugin() | |
| const result = required(yield* catalog.provider.get(ProviderV2.ID.amazonBedrock)) | |
| expect(result.api).toEqual({ | |
| type: "aisdk", | |
| package: "@ai-sdk/amazon-bedrock", | |
| url: "https://bedrock.example", | |
| }) | |
| expect(result.request.body.endpoint).toBeUndefined() | |
| }), | |
| ) | |
| it.effect("prefers endpoint over baseURL for SDK base URL", () => | |
| withEnv({ AWS_BEARER_TOKEN_BEDROCK: undefined, AWS_PROFILE: undefined, AWS_ACCESS_KEY_ID: undefined }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { | |
| name: "amazon-bedrock", | |
| bearerToken: "token", | |
| baseURL: "https://base.example", | |
| endpoint: "https://endpoint.example", | |
| region: "us-east-1", | |
| }, | |
| }) | |
| expect(bedrockBaseURL(result.sdk)).toBe("https://endpoint.example") | |
| }), | |
| ), | |
| ) | |
| it.effect("uses baseURL as SDK base URL", () => | |
| withEnv({ AWS_BEARER_TOKEN_BEDROCK: undefined, AWS_PROFILE: undefined, AWS_ACCESS_KEY_ID: undefined }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { | |
| name: "amazon-bedrock", | |
| bearerToken: "token", | |
| baseURL: "https://base.example", | |
| region: "us-east-1", | |
| }, | |
| }) | |
| expect(bedrockBaseURL(result.sdk)).toBe("https://base.example") | |
| }), | |
| ), | |
| ) | |
| it.effect("creates SDK without explicit credential env so the default AWS chain can resolve credentials", () => | |
| withEnv( | |
| { | |
| AWS_ACCESS_KEY_ID: undefined, | |
| AWS_BEARER_TOKEN_BEDROCK: undefined, | |
| AWS_CONTAINER_CREDENTIALS_FULL_URI: undefined, | |
| AWS_CONTAINER_CREDENTIALS_RELATIVE_URI: undefined, | |
| AWS_PROFILE: undefined, | |
| AWS_REGION: undefined, | |
| AWS_WEB_IDENTITY_TOKEN_FILE: undefined, | |
| }, | |
| () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { | |
| id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), | |
| type: "aisdk", | |
| package: "test-provider", | |
| }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { name: "amazon-bedrock" }, | |
| }) | |
| expect(result.sdk).toBeDefined() | |
| expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.us-east-1.amazonaws.com") | |
| }), | |
| ), | |
| ) | |
| it.effect("uses config region over AWS_REGION for SDK base URL", () => | |
| withEnv({ AWS_BEARER_TOKEN_BEDROCK: "token", AWS_REGION: "us-east-1" }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { name: "amazon-bedrock", region: "eu-west-1" }, | |
| }) | |
| expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.eu-west-1.amazonaws.com") | |
| }), | |
| ), | |
| ) | |
| it.effect("uses AWS_REGION for SDK base URL when config region is absent", () => | |
| withEnv({ AWS_BEARER_TOKEN_BEDROCK: "token", AWS_REGION: "eu-west-1" }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { name: "amazon-bedrock" }, | |
| }) | |
| expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.eu-west-1.amazonaws.com") | |
| }), | |
| ), | |
| ) | |
| it.effect("defaults SDK region to us-east-1", () => | |
| withEnv({ AWS_BEARER_TOKEN_BEDROCK: "token", AWS_REGION: undefined }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { name: "amazon-bedrock" }, | |
| }) | |
| expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.us-east-1.amazonaws.com") | |
| }), | |
| ), | |
| ) | |
| it.effect("loads bearer token option into env and uses bearer auth", () => | |
| withEnv({ AWS_ACCESS_KEY_ID: undefined, AWS_BEARER_TOKEN_BEDROCK: undefined, AWS_PROFILE: undefined }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const headers: Array<string | null> = [] | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { | |
| name: "amazon-bedrock", | |
| bearerToken: "option-token", | |
| fetch: async (_input: Parameters<typeof fetch>[0], init?: RequestInit) => { | |
| headers.push(new Headers(init?.headers).get("Authorization")) | |
| return new Response("{}") | |
| }, | |
| }, | |
| }) | |
| yield* Effect.promise(() => bedrockFetch(result.sdk)("https://bedrock.example", { method: "POST" })) | |
| expect(process.env.AWS_BEARER_TOKEN_BEDROCK).toBe("option-token") | |
| expect(headers).toEqual(["Bearer option-token"]) | |
| }), | |
| ), | |
| ) | |
| it.effect("prefers bearer token env over bearer token option", () => | |
| withEnv({ AWS_BEARER_TOKEN_BEDROCK: "env-token" }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const headers: Array<string | null> = [] | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { | |
| name: "amazon-bedrock", | |
| bearerToken: "option-token", | |
| fetch: async (_input: Parameters<typeof fetch>[0], init?: RequestInit) => { | |
| headers.push(new Headers(init?.headers).get("Authorization")) | |
| return new Response("{}") | |
| }, | |
| }, | |
| }) | |
| yield* Effect.promise(() => bedrockFetch(result.sdk)("https://bedrock.example", { method: "POST" })) | |
| expect(process.env.AWS_BEARER_TOKEN_BEDROCK).toBe("env-token") | |
| expect(headers).toEqual(["Bearer env-token"]) | |
| }), | |
| ), | |
| ) | |
| it.effect("creates Mantle SDK with GPT-5 OpenAI base path", () => | |
| withEnv({ AWS_BEARER_TOKEN_BEDROCK: undefined, AWS_PROFILE: undefined, AWS_ACCESS_KEY_ID: undefined }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("openai.gpt-5.5")), | |
| api: { | |
| id: ModelV2.ID.make("openai.gpt-5.5"), | |
| type: "aisdk", | |
| package: "@ai-sdk/amazon-bedrock/mantle", | |
| }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock/mantle", | |
| options: { | |
| name: "amazon-bedrock", | |
| bearerToken: "token", | |
| baseURL: "https://bedrock-mantle.us-east-2.api.aws/openai/v1", | |
| region: "us-east-2", | |
| }, | |
| }) | |
| const language = result.sdk.responses("openai.gpt-5.5") | |
| expect(openAIUrl(language, "/responses", "openai.gpt-5.5")).toBe( | |
| "https://bedrock-mantle.us-east-2.api.aws/openai/v1/responses", | |
| ) | |
| }), | |
| ), | |
| ) | |
| it.effect("selects Mantle APIs without Bedrock cross-region prefixes", () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const calls: string[] = [] | |
| yield* addPlugin() | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("openai.gpt-5.5")), | |
| api: { | |
| id: ModelV2.ID.make("openai.gpt-5.5"), | |
| type: "aisdk", | |
| package: "@ai-sdk/amazon-bedrock/mantle", | |
| }, | |
| }), | |
| sdk: fakeSelectorSdk(calls), | |
| options: { baseURL: "https://bedrock-mantle.us-east-2.api.aws/openai/v1", region: "us-east-2" }, | |
| }) | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("openai.gpt-oss-safeguard-120b")), | |
| api: { | |
| id: ModelV2.ID.make("openai.gpt-oss-safeguard-120b"), | |
| type: "aisdk", | |
| package: "@ai-sdk/amazon-bedrock/mantle", | |
| }, | |
| }), | |
| sdk: fakeSelectorSdk(calls), | |
| options: { region: "us-east-1" }, | |
| }) | |
| expect(calls).toEqual(["responses:openai.gpt-5.5", "chat:openai.gpt-oss-safeguard-120b"]) | |
| }), | |
| ) | |
| it.effect("ignores other Bedrock provider subpaths", () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { | |
| id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), | |
| type: "aisdk", | |
| package: "@ai-sdk/amazon-bedrock/anthropic", | |
| }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock/anthropic", | |
| options: { name: "amazon-bedrock" }, | |
| }) | |
| expect(result.sdk).toBeUndefined() | |
| }), | |
| ) | |
| it.effect("uses SigV4 credential env when bearer token is absent", () => | |
| withEnv( | |
| { | |
| AWS_ACCESS_KEY_ID: "test-access-key", | |
| AWS_BEARER_TOKEN_BEDROCK: undefined, | |
| AWS_REGION: "us-east-1", | |
| AWS_SECRET_ACCESS_KEY: "test-secret-key", | |
| AWS_SESSION_TOKEN: "test-session-token", | |
| }, | |
| () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const headers: Array<string | null> = [] | |
| yield* addPlugin() | |
| const result = yield* aisdk.runSDK({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { | |
| id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), | |
| type: "aisdk", | |
| package: "test-provider", | |
| }, | |
| }), | |
| package: "@ai-sdk/amazon-bedrock", | |
| options: { | |
| name: "amazon-bedrock", | |
| fetch: async (_input: Parameters<typeof fetch>[0], init?: RequestInit) => { | |
| headers.push(new Headers(init?.headers).get("Authorization")) | |
| return new Response("{}") | |
| }, | |
| }, | |
| }) | |
| yield* Effect.promise(() => | |
| bedrockFetch(result.sdk)("https://bedrock-runtime.us-east-1.amazonaws.com/model/test/invoke", { | |
| body: "{}", | |
| method: "POST", | |
| }), | |
| ) | |
| expect(headers[0]?.startsWith("AWS4-HMAC-SHA256 ")).toBe(true) | |
| }), | |
| ), | |
| ) | |
| it.effect("applies legacy cross-region inference prefixes", () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const calls: string[] = [] | |
| yield* addPlugin() | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: {}, | |
| }) | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: { region: "eu-west-1" }, | |
| }) | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("global.anthropic.claude-sonnet-4-5")), | |
| api: { | |
| id: ModelV2.ID.make("global.anthropic.claude-sonnet-4-5"), | |
| type: "aisdk", | |
| package: "test-provider", | |
| }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: { region: "eu-west-1" }, | |
| }) | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: { region: "ap-northeast-1" }, | |
| }) | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: { region: "ap-southeast-2" }, | |
| }) | |
| expect(calls).toEqual([ | |
| "languageModel:us.anthropic.claude-sonnet-4-5", | |
| "languageModel:eu.anthropic.claude-sonnet-4-5", | |
| "languageModel:global.anthropic.claude-sonnet-4-5", | |
| "languageModel:jp.anthropic.claude-sonnet-4-5", | |
| "languageModel:au.anthropic.claude-sonnet-4-5", | |
| ]) | |
| }), | |
| ) | |
| it.effect("uses AWS_REGION for language prefixes when region option is absent", () => | |
| withEnv({ AWS_REGION: "eu-west-1" }, () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const calls: string[] = [] | |
| yield* addPlugin() | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: {}, | |
| }) | |
| expect(calls).toEqual(["languageModel:eu.anthropic.claude-sonnet-4-5"]) | |
| }), | |
| ), | |
| ) | |
| it.effect("applies the full legacy cross-region prefix matrix", () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const calls: string[] = [] | |
| const cases = [ | |
| { region: "us-east-1", modelID: "amazon.nova-micro-v1:0", expected: "us.amazon.nova-micro-v1:0" }, | |
| { region: "us-east-1", modelID: "amazon.nova-lite-v1:0", expected: "us.amazon.nova-lite-v1:0" }, | |
| { region: "us-east-1", modelID: "amazon.nova-pro-v1:0", expected: "us.amazon.nova-pro-v1:0" }, | |
| { region: "us-east-1", modelID: "amazon.nova-premier-v1:0", expected: "us.amazon.nova-premier-v1:0" }, | |
| { region: "us-east-1", modelID: "amazon.nova-2-lite-v1:0", expected: "us.amazon.nova-2-lite-v1:0" }, | |
| { region: "us-east-1", modelID: "anthropic.claude-sonnet-4-5", expected: "us.anthropic.claude-sonnet-4-5" }, | |
| { region: "us-east-1", modelID: "deepseek.r1-v1:0", expected: "us.deepseek.r1-v1:0" }, | |
| { region: "us-east-1", modelID: "us.deepseek.r1-v1:0", expected: "us.deepseek.r1-v1:0" }, | |
| { region: "us-east-1", modelID: "deepseek.v3.2", expected: "deepseek.v3.2" }, | |
| { | |
| region: "us-east-1", | |
| modelID: "arn:aws:bedrock:us-east-1::foundation-model/deepseek.v3.2", | |
| expected: "arn:aws:bedrock:us-east-1::foundation-model/deepseek.v3.2", | |
| }, | |
| { region: "us-gov-west-1", modelID: "anthropic.claude-sonnet-4-5", expected: "anthropic.claude-sonnet-4-5" }, | |
| { region: "us-east-1", modelID: "cohere.command-r-plus-v1:0", expected: "cohere.command-r-plus-v1:0" }, | |
| { region: "eu-west-1", modelID: "anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, | |
| { region: "eu-west-2", modelID: "amazon.nova-lite-v1:0", expected: "eu.amazon.nova-lite-v1:0" }, | |
| { region: "eu-west-3", modelID: "amazon.nova-micro-v1:0", expected: "eu.amazon.nova-micro-v1:0" }, | |
| { | |
| region: "eu-north-1", | |
| modelID: "meta.llama3-70b-instruct-v1:0", | |
| expected: "eu.meta.llama3-70b-instruct-v1:0", | |
| }, | |
| { region: "eu-central-1", modelID: "mistral.pixtral-large-v1:0", expected: "eu.mistral.pixtral-large-v1:0" }, | |
| { region: "eu-south-1", modelID: "anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, | |
| { region: "eu-south-2", modelID: "anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, | |
| { region: "eu-central-2", modelID: "anthropic.claude-sonnet-4-5", expected: "anthropic.claude-sonnet-4-5" }, | |
| { region: "eu-west-1", modelID: "cohere.command-r-plus-v1:0", expected: "cohere.command-r-plus-v1:0" }, | |
| { | |
| region: "ap-southeast-2", | |
| modelID: "anthropic.claude-sonnet-4-5", | |
| expected: "au.anthropic.claude-sonnet-4-5", | |
| }, | |
| { | |
| region: "ap-southeast-4", | |
| modelID: "anthropic.claude-haiku-v1:0", | |
| expected: "au.anthropic.claude-haiku-v1:0", | |
| }, | |
| { region: "ap-southeast-2", modelID: "anthropic.claude-opus-4", expected: "apac.anthropic.claude-opus-4" }, | |
| { | |
| region: "ap-northeast-1", | |
| modelID: "anthropic.claude-sonnet-4-5", | |
| expected: "jp.anthropic.claude-sonnet-4-5", | |
| }, | |
| { region: "ap-northeast-1", modelID: "amazon.nova-pro-v1:0", expected: "jp.amazon.nova-pro-v1:0" }, | |
| { region: "ap-south-1", modelID: "anthropic.claude-sonnet-4-5", expected: "apac.anthropic.claude-sonnet-4-5" }, | |
| { region: "ap-south-1", modelID: "amazon.nova-lite-v1:0", expected: "apac.amazon.nova-lite-v1:0" }, | |
| { region: "ca-central-1", modelID: "anthropic.claude-sonnet-4-5", expected: "anthropic.claude-sonnet-4-5" }, | |
| { | |
| region: "us-east-1", | |
| modelID: "global.anthropic.claude-sonnet-4-5", | |
| expected: "global.anthropic.claude-sonnet-4-5", | |
| }, | |
| { region: "us-east-1", modelID: "us.anthropic.claude-sonnet-4-5", expected: "us.anthropic.claude-sonnet-4-5" }, | |
| { region: "eu-west-1", modelID: "eu.anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, | |
| { | |
| region: "ap-northeast-1", | |
| modelID: "jp.anthropic.claude-sonnet-4-5", | |
| expected: "jp.anthropic.claude-sonnet-4-5", | |
| }, | |
| { | |
| region: "ap-south-1", | |
| modelID: "apac.anthropic.claude-sonnet-4-5", | |
| expected: "apac.anthropic.claude-sonnet-4-5", | |
| }, | |
| { | |
| region: "ap-southeast-2", | |
| modelID: "au.anthropic.claude-sonnet-4-5", | |
| expected: "au.anthropic.claude-sonnet-4-5", | |
| }, | |
| ] | |
| yield* addPlugin() | |
| for (const item of cases) { | |
| yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.amazonBedrock, ModelV2.ID.make(item.modelID)), | |
| api: { id: ModelV2.ID.make(item.modelID), type: "aisdk", package: "test-provider" }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: { region: item.region }, | |
| }) | |
| } | |
| expect(calls).toEqual(cases.map((item) => `languageModel:${item.expected}`)) | |
| }), | |
| ) | |
| it.effect("ignores non-Bedrock providers for language selection", () => | |
| Effect.gen(function* () { | |
| const plugin = yield* PluginV2.Service | |
| const aisdk = yield* AISDK.Service | |
| const calls: string[] = [] | |
| yield* addPlugin() | |
| const result = yield* aisdk.runLanguage({ | |
| model: ModelV2.Info.make({ | |
| ...ModelV2.Info.empty(ProviderV2.ID.openai, ModelV2.ID.make("anthropic.claude-sonnet-4-5")), | |
| api: { id: ModelV2.ID.make("anthropic.claude-sonnet-4-5"), type: "aisdk", package: "test-provider" }, | |
| }), | |
| sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, | |
| options: { region: "eu-west-1" }, | |
| }) | |
| expect(calls).toEqual([]) | |
| expect(result.language).toBeUndefined() | |
| }), | |
| ) | |
| }) | |