|
|
@@ -29,6 +29,12 @@ function rememberEnv(k: string) {
|
|
|
if (!originalEnv.has(k)) originalEnv.set(k, process.env[k])
|
|
|
}
|
|
|
|
|
|
+const setProcessEnv = (k: string, v: string) =>
|
|
|
+ Effect.sync(() => {
|
|
|
+ rememberEnv(k)
|
|
|
+ process.env[k] = v
|
|
|
+ })
|
|
|
+
|
|
|
const set = (ctx: InstanceContext, k: string, v: string) => {
|
|
|
rememberEnv(k)
|
|
|
process.env[k] = v
|
|
|
@@ -128,160 +134,99 @@ const alphaProviderConfig = {
|
|
|
},
|
|
|
}
|
|
|
|
|
|
-test("provider loaded from env variable", async () => {
|
|
|
- await using tmp = await tmpdir({
|
|
|
- init: async (dir) => {
|
|
|
- await Bun.write(
|
|
|
- path.join(dir, "opencode.json"),
|
|
|
- JSON.stringify({
|
|
|
- $schema: "https://opencode.ai/config.json",
|
|
|
- }),
|
|
|
- )
|
|
|
- },
|
|
|
- })
|
|
|
- await withTestInstance({
|
|
|
- directory: tmp.path,
|
|
|
- fn: async (ctx) => {
|
|
|
- await set(ctx, "ANTHROPIC_API_KEY", "test-api-key")
|
|
|
- const providers = await list(ctx)
|
|
|
- expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
- // Provider should retain its connection source even if custom loaders
|
|
|
- // merge additional options.
|
|
|
- expect(providers[ProviderID.anthropic].source).toBe("env")
|
|
|
- expect(providers[ProviderID.anthropic].options.headers["anthropic-beta"]).toBeDefined()
|
|
|
- },
|
|
|
- })
|
|
|
-})
|
|
|
+it.instance("provider loaded from env variable", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
+ const providers = yield* Provider.Service.use((provider) => provider.list())
|
|
|
+ expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
+ // Provider should retain its connection source even if custom loaders
|
|
|
+ // merge additional options.
|
|
|
+ expect(providers[ProviderID.anthropic].source).toBe("env")
|
|
|
+ expect(providers[ProviderID.anthropic].options.headers["anthropic-beta"]).toBeDefined()
|
|
|
+ }),
|
|
|
+)
|
|
|
|
|
|
-test("provider loaded from config with apiKey option", async () => {
|
|
|
- await using tmp = await tmpdir({
|
|
|
- init: async (dir) => {
|
|
|
- await Bun.write(
|
|
|
- path.join(dir, "opencode.json"),
|
|
|
- JSON.stringify({
|
|
|
- $schema: "https://opencode.ai/config.json",
|
|
|
- provider: {
|
|
|
- anthropic: {
|
|
|
- options: {
|
|
|
- apiKey: "config-api-key",
|
|
|
- },
|
|
|
- },
|
|
|
+it.instance(
|
|
|
+ "provider loaded from config with apiKey option",
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const providers = yield* Provider.Service.use((provider) => provider.list())
|
|
|
+ expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
+ }),
|
|
|
+ {
|
|
|
+ config: {
|
|
|
+ provider: {
|
|
|
+ anthropic: {
|
|
|
+ options: {
|
|
|
+ apiKey: "config-api-key",
|
|
|
},
|
|
|
- }),
|
|
|
- )
|
|
|
- },
|
|
|
- })
|
|
|
- await withTestInstance({
|
|
|
- directory: tmp.path,
|
|
|
- fn: async (ctx) => {
|
|
|
- const providers = await list(ctx)
|
|
|
- expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
+ },
|
|
|
+ },
|
|
|
},
|
|
|
- })
|
|
|
-})
|
|
|
+ },
|
|
|
+)
|
|
|
|
|
|
-test("disabled_providers excludes provider", async () => {
|
|
|
- await using tmp = await tmpdir({
|
|
|
- init: async (dir) => {
|
|
|
- await Bun.write(
|
|
|
- path.join(dir, "opencode.json"),
|
|
|
- JSON.stringify({
|
|
|
- $schema: "https://opencode.ai/config.json",
|
|
|
- disabled_providers: ["anthropic"],
|
|
|
- }),
|
|
|
- )
|
|
|
- },
|
|
|
- })
|
|
|
- await withTestInstance({
|
|
|
- directory: tmp.path,
|
|
|
- fn: async (ctx) => {
|
|
|
- await set(ctx, "ANTHROPIC_API_KEY", "test-api-key")
|
|
|
- const providers = await list(ctx)
|
|
|
- expect(providers[ProviderID.anthropic]).toBeUndefined()
|
|
|
- },
|
|
|
- })
|
|
|
-})
|
|
|
+it.instance(
|
|
|
+ "disabled_providers excludes provider",
|
|
|
+ Effect.gen(function* () {
|
|
|
+ yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
+ const providers = yield* Provider.Service.use((provider) => provider.list())
|
|
|
+ expect(providers[ProviderID.anthropic]).toBeUndefined()
|
|
|
+ }),
|
|
|
+ { config: { disabled_providers: ["anthropic"] } },
|
|
|
+)
|
|
|
|
|
|
-test("enabled_providers restricts to only listed providers", async () => {
|
|
|
- await using tmp = await tmpdir({
|
|
|
- init: async (dir) => {
|
|
|
- await Bun.write(
|
|
|
- path.join(dir, "opencode.json"),
|
|
|
- JSON.stringify({
|
|
|
- $schema: "https://opencode.ai/config.json",
|
|
|
- enabled_providers: ["anthropic"],
|
|
|
- }),
|
|
|
- )
|
|
|
- },
|
|
|
- })
|
|
|
- await withTestInstance({
|
|
|
- directory: tmp.path,
|
|
|
- fn: async (ctx) => {
|
|
|
- await set(ctx, "ANTHROPIC_API_KEY", "test-api-key")
|
|
|
- await set(ctx, "OPENAI_API_KEY", "test-openai-key")
|
|
|
- const providers = await list(ctx)
|
|
|
- expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
- expect(providers[ProviderID.openai]).toBeUndefined()
|
|
|
- },
|
|
|
- })
|
|
|
-})
|
|
|
+it.instance(
|
|
|
+ "enabled_providers restricts to only listed providers",
|
|
|
+ Effect.gen(function* () {
|
|
|
+ yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
+ yield* setProcessEnv("OPENAI_API_KEY", "test-openai-key")
|
|
|
+ const providers = yield* Provider.Service.use((provider) => provider.list())
|
|
|
+ expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
+ expect(providers[ProviderID.openai]).toBeUndefined()
|
|
|
+ }),
|
|
|
+ { config: { enabled_providers: ["anthropic"] } },
|
|
|
+)
|
|
|
|
|
|
-test("model whitelist filters models for provider", async () => {
|
|
|
- await using tmp = await tmpdir({
|
|
|
- init: async (dir) => {
|
|
|
- await Bun.write(
|
|
|
- path.join(dir, "opencode.json"),
|
|
|
- JSON.stringify({
|
|
|
- $schema: "https://opencode.ai/config.json",
|
|
|
- provider: {
|
|
|
- anthropic: {
|
|
|
- whitelist: ["claude-sonnet-4-20250514"],
|
|
|
- },
|
|
|
- },
|
|
|
- }),
|
|
|
- )
|
|
|
- },
|
|
|
- })
|
|
|
- await withTestInstance({
|
|
|
- directory: tmp.path,
|
|
|
- fn: async (ctx) => {
|
|
|
- await set(ctx, "ANTHROPIC_API_KEY", "test-api-key")
|
|
|
- const providers = await list(ctx)
|
|
|
- expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
- const models = Object.keys(providers[ProviderID.anthropic].models)
|
|
|
- expect(models).toContain("claude-sonnet-4-20250514")
|
|
|
- expect(models.length).toBe(1)
|
|
|
+it.instance(
|
|
|
+ "model whitelist filters models for provider",
|
|
|
+ Effect.gen(function* () {
|
|
|
+ yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
+ const providers = yield* Provider.Service.use((provider) => provider.list())
|
|
|
+ expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
+ const models = Object.keys(providers[ProviderID.anthropic].models)
|
|
|
+ expect(models).toContain("claude-sonnet-4-20250514")
|
|
|
+ expect(models.length).toBe(1)
|
|
|
+ }),
|
|
|
+ {
|
|
|
+ config: {
|
|
|
+ provider: {
|
|
|
+ anthropic: {
|
|
|
+ whitelist: ["claude-sonnet-4-20250514"],
|
|
|
+ },
|
|
|
+ },
|
|
|
},
|
|
|
- })
|
|
|
-})
|
|
|
+ },
|
|
|
+)
|
|
|
|
|
|
-test("model blacklist excludes specific models", async () => {
|
|
|
- await using tmp = await tmpdir({
|
|
|
- init: async (dir) => {
|
|
|
- await Bun.write(
|
|
|
- path.join(dir, "opencode.json"),
|
|
|
- JSON.stringify({
|
|
|
- $schema: "https://opencode.ai/config.json",
|
|
|
- provider: {
|
|
|
- anthropic: {
|
|
|
- blacklist: ["claude-sonnet-4-20250514"],
|
|
|
- },
|
|
|
- },
|
|
|
- }),
|
|
|
- )
|
|
|
- },
|
|
|
- })
|
|
|
- await withTestInstance({
|
|
|
- directory: tmp.path,
|
|
|
- fn: async (ctx) => {
|
|
|
- await set(ctx, "ANTHROPIC_API_KEY", "test-api-key")
|
|
|
- const providers = await list(ctx)
|
|
|
- expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
- const models = Object.keys(providers[ProviderID.anthropic].models)
|
|
|
- expect(models).not.toContain("claude-sonnet-4-20250514")
|
|
|
+it.instance(
|
|
|
+ "model blacklist excludes specific models",
|
|
|
+ Effect.gen(function* () {
|
|
|
+ yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
+ const providers = yield* Provider.Service.use((provider) => provider.list())
|
|
|
+ expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
|
+ const models = Object.keys(providers[ProviderID.anthropic].models)
|
|
|
+ expect(models).not.toContain("claude-sonnet-4-20250514")
|
|
|
+ }),
|
|
|
+ {
|
|
|
+ config: {
|
|
|
+ provider: {
|
|
|
+ anthropic: {
|
|
|
+ blacklist: ["claude-sonnet-4-20250514"],
|
|
|
+ },
|
|
|
+ },
|
|
|
},
|
|
|
- })
|
|
|
-})
|
|
|
+ },
|
|
|
+)
|
|
|
|
|
|
test("custom model alias via config", async () => {
|
|
|
await using tmp = await tmpdir({
|