|
|
@@ -19,6 +19,7 @@ import { Filesystem } from "@/util/filesystem"
|
|
|
import { InstanceLayer } from "@/project/instance-layer"
|
|
|
import { testEffect } from "../lib/effect"
|
|
|
import { ProviderV2 } from "@opencode-ai/core/provider"
|
|
|
+import { ModelV2 } from "@opencode-ai/core/model"
|
|
|
|
|
|
const originalEnv = new Map<string, string | undefined>()
|
|
|
|
|
|
@@ -293,7 +294,7 @@ it.instance("getModel returns model for valid provider/model", () =>
|
|
|
Effect.gen(function* () {
|
|
|
yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
const provider = yield* Provider.Service
|
|
|
- const model = yield* provider.getModel(ProviderV2.ID.anthropic, ProviderV2.ModelID.make("claude-sonnet-4-20250514"))
|
|
|
+ const model = yield* provider.getModel(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-sonnet-4-20250514"))
|
|
|
expect(model).toBeDefined()
|
|
|
expect(String(model.providerID)).toBe("anthropic")
|
|
|
expect(String(model.id)).toBe("claude-sonnet-4-20250514")
|
|
|
@@ -306,7 +307,7 @@ it.instance("getModel throws ModelNotFoundError for invalid model", () =>
|
|
|
Effect.gen(function* () {
|
|
|
yield* set("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
const exit = yield* Provider.use
|
|
|
- .getModel(ProviderV2.ID.anthropic, ProviderV2.ModelID.make("nonexistent-model"))
|
|
|
+ .getModel(ProviderV2.ID.anthropic, ModelV2.ID.make("nonexistent-model"))
|
|
|
.pipe(Effect.exit)
|
|
|
expect(exit._tag).toBe("Failure")
|
|
|
}),
|
|
|
@@ -315,7 +316,7 @@ it.instance("getModel throws ModelNotFoundError for invalid model", () =>
|
|
|
it.instance("getModel throws ModelNotFoundError for invalid provider", () =>
|
|
|
Effect.gen(function* () {
|
|
|
const exit = yield* Provider.use
|
|
|
- .getModel(ProviderV2.ID.make("nonexistent-provider"), ProviderV2.ModelID.make("some-model"))
|
|
|
+ .getModel(ProviderV2.ID.make("nonexistent-provider"), ModelV2.ID.make("some-model"))
|
|
|
.pipe(Effect.exit)
|
|
|
expect(exit._tag).toBe("Failure")
|
|
|
}),
|
|
|
@@ -464,7 +465,7 @@ it.instance(
|
|
|
const providers = yield* list
|
|
|
expect(providers[ProviderV2.ID.anthropic].models["my-sonnet"]).toBeDefined()
|
|
|
|
|
|
- const model = yield* Provider.use.getModel(ProviderV2.ID.anthropic, ProviderV2.ModelID.make("my-sonnet"))
|
|
|
+ const model = yield* Provider.use.getModel(ProviderV2.ID.anthropic, ModelV2.ID.make("my-sonnet"))
|
|
|
expect(model).toBeDefined()
|
|
|
expect(String(model.id)).toBe("my-sonnet")
|
|
|
expect(model.name).toBe("My Sonnet Alias")
|
|
|
@@ -981,11 +982,11 @@ it.instance("getModel returns consistent results", () =>
|
|
|
yield* set("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
const model1 = yield* Provider.use.getModel(
|
|
|
ProviderV2.ID.anthropic,
|
|
|
- ProviderV2.ModelID.make("claude-sonnet-4-20250514"),
|
|
|
+ ModelV2.ID.make("claude-sonnet-4-20250514"),
|
|
|
)
|
|
|
const model2 = yield* Provider.use.getModel(
|
|
|
ProviderV2.ID.anthropic,
|
|
|
- ProviderV2.ModelID.make("claude-sonnet-4-20250514"),
|
|
|
+ ModelV2.ID.make("claude-sonnet-4-20250514"),
|
|
|
)
|
|
|
expect(model1.providerID).toEqual(model2.providerID)
|
|
|
expect(model1.id).toEqual(model2.id)
|
|
|
@@ -1017,7 +1018,7 @@ it.instance("ModelNotFoundError includes suggestions for typos", () =>
|
|
|
Effect.gen(function* () {
|
|
|
yield* set("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
const error = yield* Provider.use
|
|
|
- .getModel(ProviderV2.ID.anthropic, ProviderV2.ModelID.make("claude-sonet-4"))
|
|
|
+ .getModel(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-sonet-4"))
|
|
|
.pipe(Effect.flip)
|
|
|
expect(error.suggestions).toBeDefined()
|
|
|
expect((error.suggestions ?? []).length).toBeGreaterThan(0)
|
|
|
@@ -1028,7 +1029,7 @@ it.instance("ModelNotFoundError for provider includes suggestions", () =>
|
|
|
Effect.gen(function* () {
|
|
|
yield* set("ANTHROPIC_API_KEY", "test-api-key")
|
|
|
const error = yield* Provider.use
|
|
|
- .getModel(ProviderV2.ID.make("antropic"), ProviderV2.ModelID.make("claude-sonnet-4"))
|
|
|
+ .getModel(ProviderV2.ID.make("antropic"), ModelV2.ID.make("claude-sonnet-4"))
|
|
|
.pipe(Effect.flip)
|
|
|
expect(error.suggestions).toBeDefined()
|
|
|
expect(error.suggestions).toContain("anthropic")
|
|
|
@@ -1039,7 +1040,7 @@ it.instance("ModelNotFoundError suggests catalog models for unloaded providers",
|
|
|
Effect.gen(function* () {
|
|
|
yield* remove("OPENCODE_API_KEY")
|
|
|
const error = yield* Provider.use
|
|
|
- .getModel(ProviderV2.ID.opencode, ProviderV2.ModelID.make("claude-haiku-fake-model"))
|
|
|
+ .getModel(ProviderV2.ID.opencode, ModelV2.ID.make("claude-haiku-fake-model"))
|
|
|
.pipe(Effect.flip)
|
|
|
if (!Provider.ModelNotFoundError.isInstance(error)) throw error
|
|
|
expect(error.suggestions ?? []).toContain("claude-haiku-4-5")
|
|
|
@@ -1577,7 +1578,7 @@ it.instance("Google Vertex: uses REP endpoint for Claude continental multi-regio
|
|
|
const provider = yield* Provider.Service
|
|
|
const model = yield* provider.getModel(
|
|
|
ProviderV2.ID.make("google-vertex"),
|
|
|
- ProviderV2.ModelID.make("claude-sonnet-4-6@default"),
|
|
|
+ ModelV2.ID.make("claude-sonnet-4-6@default"),
|
|
|
)
|
|
|
const language = yield* provider.getLanguage(model)
|
|
|
expect(languageBaseURL(language)).toBe(
|
|
|
@@ -1593,7 +1594,7 @@ it.instance("Google Vertex Anthropic: uses REP endpoint for continental multi-re
|
|
|
const provider = yield* Provider.Service
|
|
|
const model = yield* provider.getModel(
|
|
|
ProviderV2.ID.make("google-vertex-anthropic"),
|
|
|
- ProviderV2.ModelID.make("claude-sonnet-4-6@default"),
|
|
|
+ ModelV2.ID.make("claude-sonnet-4-6@default"),
|
|
|
)
|
|
|
const language = yield* provider.getLanguage(model)
|
|
|
expect(languageBaseURL(language)).toBe(
|
|
|
@@ -1609,7 +1610,7 @@ it.instance("Google Vertex: keeps regional Claude endpoints unchanged", () =>
|
|
|
const provider = yield* Provider.Service
|
|
|
const model = yield* provider.getModel(
|
|
|
ProviderV2.ID.make("google-vertex"),
|
|
|
- ProviderV2.ModelID.make("claude-sonnet-4-6@default"),
|
|
|
+ ModelV2.ID.make("claude-sonnet-4-6@default"),
|
|
|
)
|
|
|
const language = yield* provider.getLanguage(model)
|
|
|
expect(languageBaseURL(language)).toBe(
|
|
|
@@ -1700,13 +1701,13 @@ it.effect("plugin config providers persist after instance dispose", () =>
|
|
|
|
|
|
const first = yield* loadAndList
|
|
|
expect(first[ProviderV2.ID.make("demo")]).toBeDefined()
|
|
|
- expect(first[ProviderV2.ID.make("demo")].models[ProviderV2.ModelID.make("chat")]).toBeDefined()
|
|
|
+ expect(first[ProviderV2.ID.make("demo")].models[ModelV2.ID.make("chat")]).toBeDefined()
|
|
|
|
|
|
yield* Effect.promise(() => disposeAllInstances())
|
|
|
|
|
|
const second = yield* loadAndList
|
|
|
expect(second[ProviderV2.ID.make("demo")]).toBeDefined()
|
|
|
- expect(second[ProviderV2.ID.make("demo")].models[ProviderV2.ModelID.make("chat")]).toBeDefined()
|
|
|
+ expect(second[ProviderV2.ID.make("demo")].models[ModelV2.ID.make("chat")]).toBeDefined()
|
|
|
}).pipe(provideMultiInstance),
|
|
|
)
|
|
|
|