refactor(core): consolidate tool architecture
This commit is contained in:
parent
0fd73a2976
commit
8db7487c89
466 changed files with 9405 additions and 11071 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, expect } from "bun:test"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { CommandV2 } from "@opencode-ai/core/command"
|
||||
import { Command } from "@opencode-ai/core/command"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { CommandPlugin } from "@opencode-ai/core/plugin/command"
|
||||
|
|
@ -15,12 +15,12 @@ const locationLayer = Layer.succeed(
|
|||
Location.Service,
|
||||
Location.Service.of(location({ directory }, { projectDirectory: project })),
|
||||
)
|
||||
const it = testEffect(AppNodeBuilder.build(CommandV2.node, [[Location.node, locationLayer]]))
|
||||
const it = testEffect(AppNodeBuilder.build(Command.node, [[Location.node, locationLayer]]))
|
||||
|
||||
describe("CommandPlugin.Plugin", () => {
|
||||
it.effect("registers built-in init and review commands", () =>
|
||||
Effect.gen(function* () {
|
||||
const command = yield* CommandV2.Service
|
||||
const command = yield* Command.Service
|
||||
yield* CommandPlugin.Plugin.effect(
|
||||
host({
|
||||
command: {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,25 @@
|
|||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { CommandV2 } from "@opencode-ai/core/command"
|
||||
import { Command } from "@opencode-ai/core/command"
|
||||
import { Config } from "@opencode-ai/core/config"
|
||||
import { Credential } from "@opencode-ai/core/credential"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { LayerNodePlatform } from "@opencode-ai/util/effect/app-node-platform"
|
||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
import { FileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { Form } from "@opencode-ai/core/form"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { Npm } from "@opencode-ai/util/npm"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHooks } from "@opencode-ai/core/plugin/hooks"
|
||||
import { PluginRuntime } from "@opencode-ai/core/plugin/runtime"
|
||||
import { Reference } from "@opencode-ai/core/reference"
|
||||
import { SkillV2 } from "@opencode-ai/core/skill"
|
||||
import { ToolHooks } from "@opencode-ai/core/tool/hooks"
|
||||
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
||||
import { Skill } from "@opencode-ai/core/skill"
|
||||
import { Tool } from "@opencode-ai/core/tool"
|
||||
import { WebSearch } from "@opencode-ai/core/websearch"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { tempLocationLayer } from "../fixture/location"
|
||||
|
|
@ -41,21 +40,21 @@ export const PluginTestLayer = AppNodeBuilder.build(
|
|||
Location.node,
|
||||
Npm.node,
|
||||
Credential.node,
|
||||
EventV2.node,
|
||||
Bus.node,
|
||||
Form.node,
|
||||
LayerNodePlatform.httpClient,
|
||||
PluginV2.node,
|
||||
AgentV2.node,
|
||||
Plugin.node,
|
||||
Agent.node,
|
||||
AISDK.node,
|
||||
Catalog.node,
|
||||
CommandV2.node,
|
||||
Command.node,
|
||||
Integration.node,
|
||||
PluginRuntime.node,
|
||||
PluginHooks.node,
|
||||
Reference.node,
|
||||
SkillV2.node,
|
||||
ToolHooks.node,
|
||||
ToolRegistry.toolsNode,
|
||||
Skill.node,
|
||||
PluginHooks.node,
|
||||
Tool.node,
|
||||
WebSearch.node,
|
||||
]),
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Plugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import { Plugin } from "@opencode-ai/plugin/effect"
|
||||
import { Effect } from "effect"
|
||||
|
||||
export default Plugin.define({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
import { Plugin } from "@opencode-ai/plugin"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "config-promise-plugin",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Plugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import { Plugin } from "@opencode-ai/plugin/effect"
|
||||
import { Effect } from "effect"
|
||||
|
||||
export default Plugin.define({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Plugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Plugin } from "@opencode-ai/plugin/effect"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { Effect } from "effect"
|
||||
|
||||
export default Plugin.define({
|
||||
|
|
@ -8,14 +9,14 @@ export default Plugin.define({
|
|||
ctx.catalog
|
||||
.transform((catalog) => {
|
||||
catalog.provider.update("configured", (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
})
|
||||
catalog.model.update("configured", "glm-5.2", (model) => {
|
||||
model.modelID = "glm-5.2"
|
||||
model.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
model.modelID = Model.ID.make("glm-5.2")
|
||||
model.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
model.variants = [
|
||||
{
|
||||
id: "high",
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: {},
|
||||
headers: { custom: "true" },
|
||||
body: {},
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
import { Plugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { Plugin } from "@opencode-ai/plugin/effect"
|
||||
import type { IntegrationMethodRegistration } from "@opencode-ai/plugin/effect/integration"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { Credential } from "@opencode-ai/core/credential"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Project } from "@opencode-ai/core/project"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { WebSearch } from "@opencode-ai/core/websearch"
|
||||
import type {
|
||||
CredentialOAuth,
|
||||
IntegrationCommandMethod,
|
||||
IntegrationEnvMethod,
|
||||
IntegrationKeyMethod,
|
||||
IntegrationOAuthMethod,
|
||||
} from "@opencode-ai/sdk/v2/types"
|
||||
import { Effect, Stream } from "effect"
|
||||
|
||||
type Overrides = Partial<Omit<Plugin.Context, "options" | "session">> & {
|
||||
|
|
@ -41,7 +35,6 @@ export function host(overrides: Overrides = {}): Plugin.Context {
|
|||
get: () => Effect.die("unused catalog.provider.get"),
|
||||
},
|
||||
model: {
|
||||
get: () => Effect.die("unused catalog.model.get"),
|
||||
list: () => Effect.die("unused catalog.model.list"),
|
||||
default: () => Effect.die("unused catalog.model.default"),
|
||||
},
|
||||
|
|
@ -116,9 +109,22 @@ export function host(overrides: Overrides = {}): Plugin.Context {
|
|||
}
|
||||
}
|
||||
|
||||
export function agentHost(agent: AgentV2.Interface): Plugin.Context["agent"] {
|
||||
export function agentHost(agent: Agent.Interface): Plugin.Context["agent"] {
|
||||
return {
|
||||
get: (id) => agent.get(AgentV2.ID.make(id)).pipe(Effect.map((value) => value && agentInfo(value))),
|
||||
get: (input) =>
|
||||
agent.get(input.agentID).pipe(
|
||||
Effect.flatMap((value) =>
|
||||
value
|
||||
? Effect.succeed({
|
||||
location: new Location.Info({
|
||||
directory: AbsolutePath.make("/"),
|
||||
project: { id: Project.ID.make("test"), directory: AbsolutePath.make("/") },
|
||||
}),
|
||||
data: agentInfo(value),
|
||||
})
|
||||
: Effect.fail(new Error(`Agent not found: ${input.agentID}`)),
|
||||
),
|
||||
),
|
||||
list: () => Effect.die("unused agent.list"),
|
||||
reload: agent.reload,
|
||||
transform: (callback) =>
|
||||
|
|
@ -126,17 +132,17 @@ export function agentHost(agent: AgentV2.Interface): Plugin.Context["agent"] {
|
|||
callback({
|
||||
list: () => draft.list().map(agentInfo),
|
||||
get: (id) => {
|
||||
const value = draft.get(AgentV2.ID.make(id))
|
||||
const value = draft.get(Agent.ID.make(id))
|
||||
return value && agentInfo(value)
|
||||
},
|
||||
default: (id) => draft.default(id === undefined ? undefined : AgentV2.ID.make(id)),
|
||||
default: (id) => draft.default(id === undefined ? undefined : Agent.ID.make(id)),
|
||||
update: (id, update) =>
|
||||
draft.update(AgentV2.ID.make(id), (value) => {
|
||||
draft.update(Agent.ID.make(id), (value) => {
|
||||
const current = agentInfo(value)
|
||||
update(current)
|
||||
Object.assign(value, current, { id: AgentV2.ID.make(current.id) })
|
||||
Object.assign(value, current, { id: Agent.ID.make(current.id) })
|
||||
}),
|
||||
remove: (id) => draft.remove(AgentV2.ID.make(id)),
|
||||
remove: (id) => draft.remove(Agent.ID.make(id)),
|
||||
}),
|
||||
),
|
||||
}
|
||||
|
|
@ -149,10 +155,6 @@ export function catalogHost(catalog: Catalog.Interface): Plugin.Context["catalog
|
|||
get: () => Effect.die("unused catalog.provider.get"),
|
||||
},
|
||||
model: {
|
||||
get: (providerID, modelID) =>
|
||||
catalog.model
|
||||
.get(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID))
|
||||
.pipe(Effect.map((value) => value && modelInfo(value))),
|
||||
list: () => Effect.die("unused catalog.model.list"),
|
||||
default: () => Effect.die("unused catalog.model.default"),
|
||||
},
|
||||
|
|
@ -167,7 +169,7 @@ export function catalogHost(catalog: Catalog.Interface): Plugin.Context["catalog
|
|||
models: new Map(Array.from(value.models, ([id, model]) => [id, modelInfo(model)])),
|
||||
})),
|
||||
get: (id) => {
|
||||
const value = draft.provider.get(ProviderV2.ID.make(id))
|
||||
const value = draft.provider.get(Provider.ID.make(id))
|
||||
return (
|
||||
value && {
|
||||
provider: providerInfo(value.provider),
|
||||
|
|
@ -176,41 +178,41 @@ export function catalogHost(catalog: Catalog.Interface): Plugin.Context["catalog
|
|||
)
|
||||
},
|
||||
update: (id, update) =>
|
||||
draft.provider.update(ProviderV2.ID.make(id), (value) => {
|
||||
draft.provider.update(Provider.ID.make(id), (value) => {
|
||||
const current = providerInfo(value)
|
||||
update(current)
|
||||
Object.assign(value, current, { id: ProviderV2.ID.make(current.id) })
|
||||
Object.assign(value, current, { id: Provider.ID.make(current.id) })
|
||||
}),
|
||||
remove: (id) => draft.provider.remove(ProviderV2.ID.make(id)),
|
||||
remove: (id) => draft.provider.remove(Provider.ID.make(id)),
|
||||
},
|
||||
model: {
|
||||
get: (providerID, modelID) => {
|
||||
const value = draft.model.get(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID))
|
||||
const value = draft.model.get(Provider.ID.make(providerID), Model.ID.make(modelID))
|
||||
return value && modelInfo(value)
|
||||
},
|
||||
update: (providerID, modelID, update) =>
|
||||
draft.model.update(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID), (value) => {
|
||||
draft.model.update(Provider.ID.make(providerID), Model.ID.make(modelID), (value) => {
|
||||
const current = modelInfo(value)
|
||||
update(current)
|
||||
Object.assign(value, current, {
|
||||
id: ModelV2.ID.make(current.id),
|
||||
providerID: ProviderV2.ID.make(current.providerID),
|
||||
family: current.family === undefined ? undefined : ModelV2.Family.make(current.family),
|
||||
id: Model.ID.make(current.id),
|
||||
providerID: Provider.ID.make(current.providerID),
|
||||
family: current.family === undefined ? undefined : Model.Family.make(current.family),
|
||||
variants: current.variants?.map((variant) => ({
|
||||
...variant,
|
||||
id: ModelV2.VariantID.make(variant.id),
|
||||
id: Model.VariantID.make(variant.id),
|
||||
})),
|
||||
})
|
||||
}),
|
||||
remove: (providerID, modelID) =>
|
||||
draft.model.remove(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)),
|
||||
draft.model.remove(Provider.ID.make(providerID), Model.ID.make(modelID)),
|
||||
default: {
|
||||
get: () => {
|
||||
const value = draft.model.default.get()
|
||||
return value && { providerID: value.providerID, modelID: value.modelID }
|
||||
},
|
||||
set: (providerID, modelID) =>
|
||||
draft.model.default.set(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)),
|
||||
draft.model.default.set(Provider.ID.make(providerID), Model.ID.make(modelID)),
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
|
@ -370,7 +372,7 @@ export function webSearchHost(websearch: WebSearch.Interface): Plugin.Context["w
|
|||
}
|
||||
}
|
||||
|
||||
function oauthCredential(value: CredentialOAuth) {
|
||||
function oauthCredential(value: Credential.OAuth) {
|
||||
return Credential.OAuth.make({ ...value, methodID: Integration.MethodID.make(value.methodID) })
|
||||
}
|
||||
|
||||
|
|
@ -390,7 +392,7 @@ function method(value: Integration.Method) {
|
|||
}
|
||||
|
||||
function internalMethod(
|
||||
value: IntegrationOAuthMethod | IntegrationCommandMethod | IntegrationKeyMethod | IntegrationEnvMethod,
|
||||
value: IntegrationMethodRegistration["method"],
|
||||
): Integration.Method {
|
||||
if (value.type === "env") return value
|
||||
if (value.type === "key") return value
|
||||
|
|
@ -407,7 +409,7 @@ function internalMethod(
|
|||
}
|
||||
}
|
||||
|
||||
function agentInfo(value: AgentV2.Info) {
|
||||
function agentInfo(value: Agent.Info) {
|
||||
return {
|
||||
...value,
|
||||
model: value.model && { ...value.model },
|
||||
|
|
@ -420,7 +422,7 @@ function agentInfo(value: AgentV2.Info) {
|
|||
}
|
||||
}
|
||||
|
||||
function providerInfo(value: ProviderV2.MutableInfo) {
|
||||
function providerInfo(value: Provider.MutableInfo) {
|
||||
return {
|
||||
...value,
|
||||
settings: value.settings && { ...value.settings },
|
||||
|
|
@ -429,7 +431,7 @@ function providerInfo(value: ProviderV2.MutableInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
function modelInfo(value: ModelV2.Info | ModelV2.MutableInfo) {
|
||||
function modelInfo(value: Model.Info | Model.MutableInfo) {
|
||||
return {
|
||||
...value,
|
||||
settings: value.settings && { ...value.settings },
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import { Catalog } from "@opencode-ai/core/catalog"
|
|||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { ModelsDev } from "@opencode-ai/core/models-dev"
|
||||
import { ModelsDevPlugin } from "@opencode-ai/core/plugin/models-dev"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { location } from "../fixture/location"
|
||||
import { testEffect } from "../lib/effect"
|
||||
|
|
@ -21,7 +21,7 @@ const locationLayer = Layer.succeed(
|
|||
Location.Service,
|
||||
Location.Service.of(location({ directory: AbsolutePath.make(import.meta.dir) })),
|
||||
)
|
||||
const layer = AppNodeBuilder.build(LayerNode.group([Catalog.node, Integration.node, EventV2.node]), [
|
||||
const layer = AppNodeBuilder.build(LayerNode.group([Catalog.node, Integration.node, Bus.node]), [
|
||||
[Location.node, locationLayer],
|
||||
])
|
||||
const it = testEffect(layer)
|
||||
|
|
@ -33,8 +33,8 @@ describe("ModelsDevPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const integrations = yield* Integration.Service
|
||||
const catalog = yield* Catalog.Service
|
||||
const providerID = ProviderV2.ID.make("acme")
|
||||
const modelID = ModelV2.ID.make("gpt-5.4")
|
||||
const providerID = Provider.ID.make("acme")
|
||||
const modelID = Model.ID.make("gpt-5.4")
|
||||
const models = ModelsDev.Service.of({
|
||||
get: () =>
|
||||
Effect.succeed([
|
||||
|
|
@ -42,7 +42,7 @@ describe("ModelsDevPlugin", () => {
|
|||
info: {
|
||||
id: providerID,
|
||||
name: "Acme",
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai-compatible"),
|
||||
package: Provider.aisdk("@ai-sdk/openai-compatible"),
|
||||
settings: { baseURL: "https://api.acme.test/v1" },
|
||||
},
|
||||
environment: [],
|
||||
|
|
@ -52,7 +52,7 @@ describe("ModelsDevPlugin", () => {
|
|||
modelID,
|
||||
providerID,
|
||||
name: "GPT-5.4",
|
||||
family: ModelV2.Family.make("gpt"),
|
||||
family: Model.Family.make("gpt"),
|
||||
capabilities: { tools: true, input: [], output: [] },
|
||||
variants: [],
|
||||
time: { released: Date.parse("2026-01-01") },
|
||||
|
|
@ -89,12 +89,12 @@ describe("ModelsDevPlugin", () => {
|
|||
limit: { context: 1_050_000, input: 922_000, output: 128_000 },
|
||||
},
|
||||
{
|
||||
id: ModelV2.ID.make("gpt-5.4-fast"),
|
||||
id: Model.ID.make("gpt-5.4-fast"),
|
||||
modelID,
|
||||
providerID,
|
||||
name: "GPT-5.4 Fast",
|
||||
family: ModelV2.Family.make("gpt"),
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai-compatible"),
|
||||
family: Model.Family.make("gpt"),
|
||||
package: Provider.aisdk("@ai-sdk/openai-compatible"),
|
||||
settings: { baseURL: "https://api.acme.test/v1" },
|
||||
headers: { "x-mode": "fast" },
|
||||
body: { service_tier: "priority" },
|
||||
|
|
@ -146,8 +146,8 @@ describe("ModelsDevPlugin", () => {
|
|||
}),
|
||||
).pipe(Effect.provideService(ModelsDev.Service, models))
|
||||
|
||||
const base = yield* catalog.model.get(providerID, ModelV2.ID.make("gpt-5.4"))
|
||||
const fast = yield* catalog.model.get(providerID, ModelV2.ID.make("gpt-5.4-fast"))
|
||||
const base = yield* catalog.model.get(providerID, Model.ID.make("gpt-5.4"))
|
||||
const fast = yield* catalog.model.get(providerID, Model.ID.make("gpt-5.4-fast"))
|
||||
|
||||
expect(base?.variants).toEqual([])
|
||||
expect(base?.body).toBeUndefined()
|
||||
|
|
@ -156,7 +156,7 @@ describe("ModelsDevPlugin", () => {
|
|||
modelID: "gpt-5.4",
|
||||
providerID: "acme",
|
||||
name: "GPT-5.4 Fast",
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai-compatible"),
|
||||
package: Provider.aisdk("@ai-sdk/openai-compatible"),
|
||||
settings: { baseURL: "https://api.acme.test/v1" },
|
||||
headers: { "x-mode": "fast" },
|
||||
body: { service_tier: "priority" },
|
||||
|
|
@ -231,13 +231,13 @@ describe("ModelsDevPlugin", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
const model = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning"))
|
||||
const model = yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-reasoning"))
|
||||
expect(model?.variants?.map((variant) => variant.id)).toEqual([
|
||||
ModelV2.VariantID.make("low"),
|
||||
ModelV2.VariantID.make("high"),
|
||||
Model.VariantID.make("low"),
|
||||
Model.VariantID.make("high"),
|
||||
])
|
||||
expect(model?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: {
|
||||
reasoningEffort: "low",
|
||||
reasoningSummary: "auto",
|
||||
|
|
@ -245,7 +245,7 @@ describe("ModelsDevPlugin", () => {
|
|||
},
|
||||
})
|
||||
expect(model?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: {
|
||||
reasoningEffort: "high",
|
||||
reasoningSummary: "auto",
|
||||
|
|
@ -253,7 +253,7 @@ describe("ModelsDevPlugin", () => {
|
|||
},
|
||||
})
|
||||
|
||||
const mode = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning-high"))
|
||||
const mode = yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-reasoning-high"))
|
||||
expect(mode).toMatchObject({
|
||||
id: "gpt-reasoning-high",
|
||||
name: "GPT Reasoning High",
|
||||
|
|
@ -261,229 +261,229 @@ describe("ModelsDevPlugin", () => {
|
|||
body: { service_tier: "priority" },
|
||||
})
|
||||
expect(mode?.variants?.map((variant) => variant.id)).toEqual([
|
||||
ModelV2.VariantID.make("low"),
|
||||
ModelV2.VariantID.make("high"),
|
||||
Model.VariantID.make("low"),
|
||||
Model.VariantID.make("high"),
|
||||
])
|
||||
|
||||
const pro = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning-pro"))
|
||||
const pro = yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-reasoning-pro"))
|
||||
expect(pro).toMatchObject({
|
||||
id: "gpt-reasoning-pro",
|
||||
body: { reasoning: { mode: "pro" } },
|
||||
})
|
||||
|
||||
const budgetModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-budget"))
|
||||
const budgetModel = yield* catalog.model.get(Provider.ID.anthropic, Model.ID.make("claude-budget"))
|
||||
expect(budgetModel?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { thinking: { type: "enabled", budgetTokens: 16000 } },
|
||||
})
|
||||
expect(budgetModel?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
id: Model.VariantID.make("max"),
|
||||
settings: { thinking: { type: "enabled", budgetTokens: 31999 } },
|
||||
})
|
||||
|
||||
const anthropicEffortModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-opus-4.7"))
|
||||
const anthropicEffortModel = yield* catalog.model.get(Provider.ID.anthropic, Model.ID.make("claude-opus-4.7"))
|
||||
expect(anthropicEffortModel?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("none"), settings: { thinking: { type: "disabled" } } },
|
||||
{ id: Model.VariantID.make("none"), settings: { thinking: { type: "disabled" } } },
|
||||
{
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: { thinking: { type: "adaptive", display: "summarized" }, effort: "low" },
|
||||
},
|
||||
])
|
||||
|
||||
const anthropicToggleModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-toggle"))
|
||||
const anthropicToggleModel = yield* catalog.model.get(Provider.ID.anthropic, Model.ID.make("claude-toggle"))
|
||||
expect(anthropicToggleModel?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("none"), settings: { thinking: { type: "disabled" } } },
|
||||
{ id: Model.VariantID.make("none"), settings: { thinking: { type: "disabled" } } },
|
||||
{
|
||||
id: ModelV2.VariantID.make("thinking"),
|
||||
id: Model.VariantID.make("thinking"),
|
||||
settings: { thinking: { type: "adaptive", display: "summarized" } },
|
||||
},
|
||||
])
|
||||
|
||||
const opus45 = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-opus-4-5"))
|
||||
const opus45 = yield* catalog.model.get(Provider.ID.anthropic, Model.ID.make("claude-opus-4-5"))
|
||||
expect(opus45?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("low"), settings: { effort: "low" } },
|
||||
{ id: ModelV2.VariantID.make("high"), settings: { effort: "high" } },
|
||||
{ id: Model.VariantID.make("low"), settings: { effort: "low" } },
|
||||
{ id: Model.VariantID.make("high"), settings: { effort: "high" } },
|
||||
])
|
||||
|
||||
const grok = yield* catalog.model.get(ProviderV2.ID.make("xai"), ModelV2.ID.make("grok-4.5"))
|
||||
const grok = yield* catalog.model.get(Provider.ID.make("xai"), Model.ID.make("grok-4.5"))
|
||||
expect(grok?.variants).toEqual(
|
||||
["low", "medium", "high"].map((id) => ({
|
||||
id: ModelV2.VariantID.make(id),
|
||||
id: Model.VariantID.make(id),
|
||||
settings: { reasoningEffort: id },
|
||||
})),
|
||||
)
|
||||
|
||||
const minimax = yield* catalog.model.get(ProviderV2.ID.make("opencode-go"), ModelV2.ID.make("minimax-m3"))
|
||||
const minimax = yield* catalog.model.get(Provider.ID.make("opencode-go"), Model.ID.make("minimax-m3"))
|
||||
expect(minimax?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("none"), settings: { thinking: { type: "disabled" } } },
|
||||
{ id: Model.VariantID.make("none"), settings: { thinking: { type: "disabled" } } },
|
||||
{
|
||||
id: ModelV2.VariantID.make("thinking"),
|
||||
id: Model.VariantID.make("thinking"),
|
||||
settings: { thinking: { type: "adaptive", display: "summarized" } },
|
||||
},
|
||||
])
|
||||
|
||||
const toggle = yield* catalog.model.get(ProviderV2.ID.make("alibaba"), ModelV2.ID.make("toggle-only"))
|
||||
const toggle = yield* catalog.model.get(Provider.ID.make("alibaba"), Model.ID.make("toggle-only"))
|
||||
expect(toggle?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("none"), settings: { enableThinking: false } },
|
||||
{ id: ModelV2.VariantID.make("thinking"), settings: { enableThinking: true } },
|
||||
{ id: Model.VariantID.make("none"), settings: { enableThinking: false } },
|
||||
{ id: Model.VariantID.make("thinking"), settings: { enableThinking: true } },
|
||||
])
|
||||
|
||||
const combined = yield* catalog.model.get(ProviderV2.ID.make("alibaba"), ModelV2.ID.make("toggle-budget"))
|
||||
const combined = yield* catalog.model.get(Provider.ID.make("alibaba"), Model.ID.make("toggle-budget"))
|
||||
expect(combined?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("none"), settings: { enableThinking: false } },
|
||||
{ id: Model.VariantID.make("none"), settings: { enableThinking: false } },
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { enableThinking: true, thinkingBudget: 8000 },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
id: Model.VariantID.make("max"),
|
||||
settings: { enableThinking: true, thinkingBudget: 16000 },
|
||||
},
|
||||
])
|
||||
|
||||
const gateway = yield* catalog.model.get(ProviderV2.ID.make("vercel"), ModelV2.ID.make("alibaba/qwen-toggle"))
|
||||
const gateway = yield* catalog.model.get(Provider.ID.make("vercel"), Model.ID.make("alibaba/qwen-toggle"))
|
||||
expect(gateway?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("none"), settings: { enableThinking: false } },
|
||||
{ id: Model.VariantID.make("none"), settings: { enableThinking: false } },
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { enableThinking: true, thinkingBudget: 8000 },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
id: Model.VariantID.make("max"),
|
||||
settings: { enableThinking: true, thinkingBudget: 16000 },
|
||||
},
|
||||
])
|
||||
|
||||
const gatewayNova = yield* catalog.model.get(ProviderV2.ID.make("vercel"), ModelV2.ID.make("amazon/nova-2-lite"))
|
||||
const gatewayNova = yield* catalog.model.get(Provider.ID.make("vercel"), Model.ID.make("amazon/nova-2-lite"))
|
||||
expect(gatewayNova?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: { additionalModelRequestFields: { reasoningConfig: { type: "disabled" } } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: { reasoningConfig: { type: "enabled", maxReasoningEffort: "low" } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { reasoningConfig: { type: "enabled", maxReasoningEffort: "high" } },
|
||||
},
|
||||
])
|
||||
|
||||
const gatewayFallback = yield* catalog.model.get(
|
||||
ProviderV2.ID.make("vercel"),
|
||||
ModelV2.ID.make("deepseek/deepseek-toggle"),
|
||||
Provider.ID.make("vercel"),
|
||||
Model.ID.make("deepseek/deepseek-toggle"),
|
||||
)
|
||||
expect(gatewayFallback?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: { reasoning: { enabled: false } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: { reasoningEffort: "low" },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { reasoningEffort: "high" },
|
||||
},
|
||||
])
|
||||
|
||||
const openrouter = yield* catalog.model.get(
|
||||
ProviderV2.ID.make("openrouter"),
|
||||
ModelV2.ID.make("openrouter-toggle"),
|
||||
Provider.ID.make("openrouter"),
|
||||
Model.ID.make("openrouter-toggle"),
|
||||
)
|
||||
expect(openrouter?.variants).toEqual([
|
||||
{ id: ModelV2.VariantID.make("none"), settings: { reasoning: { enabled: false } } },
|
||||
{ id: ModelV2.VariantID.make("thinking"), settings: { reasoning: { enabled: true } } },
|
||||
{ id: Model.VariantID.make("none"), settings: { reasoning: { enabled: false } } },
|
||||
{ id: Model.VariantID.make("thinking"), settings: { reasoning: { enabled: true } } },
|
||||
])
|
||||
|
||||
const google = yield* catalog.model.get(ProviderV2.ID.make("google"), ModelV2.ID.make("gemini-2.5-flash"))
|
||||
const google = yield* catalog.model.get(Provider.ID.make("google"), Model.ID.make("gemini-2.5-flash"))
|
||||
expect(google?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: { thinkingConfig: { includeThoughts: false, thinkingBudget: 0 } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { thinkingConfig: { includeThoughts: true, thinkingBudget: 8000 } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
id: Model.VariantID.make("max"),
|
||||
settings: { thinkingConfig: { includeThoughts: true, thinkingBudget: 16000 } },
|
||||
},
|
||||
])
|
||||
|
||||
const vertex = yield* catalog.model.get(
|
||||
ProviderV2.ID.make("google-vertex"),
|
||||
ModelV2.ID.make("gemini-2.5-flash-lite"),
|
||||
Provider.ID.make("google-vertex"),
|
||||
Model.ID.make("gemini-2.5-flash-lite"),
|
||||
)
|
||||
expect(vertex?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: { thinkingConfig: { includeThoughts: false, thinkingBudget: 0 } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { thinkingConfig: { includeThoughts: true, thinkingBudget: 8000 } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
id: Model.VariantID.make("max"),
|
||||
settings: { thinkingConfig: { includeThoughts: true, thinkingBudget: 16000 } },
|
||||
},
|
||||
])
|
||||
|
||||
const bedrock = yield* catalog.model.get(
|
||||
ProviderV2.ID.make("amazon-bedrock"),
|
||||
ModelV2.ID.make("amazon.nova-2-lite-v1:0"),
|
||||
Provider.ID.make("amazon-bedrock"),
|
||||
Model.ID.make("amazon.nova-2-lite-v1:0"),
|
||||
)
|
||||
expect(bedrock?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: { additionalModelRequestFields: { reasoningConfig: { type: "disabled" } } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: { reasoningConfig: { type: "enabled", maxReasoningEffort: "low" } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { reasoningConfig: { type: "enabled", maxReasoningEffort: "high" } },
|
||||
},
|
||||
])
|
||||
|
||||
const sapGemini = yield* catalog.model.get(ProviderV2.ID.make("sap-ai-core"), ModelV2.ID.make("gemini-2.5-flash"))
|
||||
const sapGemini = yield* catalog.model.get(Provider.ID.make("sap-ai-core"), Model.ID.make("gemini-2.5-flash"))
|
||||
expect(sapGemini?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: { modelParams: { thinkingConfig: { includeThoughts: false, thinkingBudget: 0 } } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { modelParams: { thinkingConfig: { includeThoughts: true, thinkingBudget: 8000 } } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
id: Model.VariantID.make("max"),
|
||||
settings: { modelParams: { thinkingConfig: { includeThoughts: true, thinkingBudget: 16000 } } },
|
||||
},
|
||||
])
|
||||
|
||||
const sapNova = yield* catalog.model.get(ProviderV2.ID.make("sap-ai-core"), ModelV2.ID.make("amazon--nova-lite"))
|
||||
const sapNova = yield* catalog.model.get(Provider.ID.make("sap-ai-core"), Model.ID.make("amazon--nova-lite"))
|
||||
expect(sapNova?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: {
|
||||
modelParams: { additionalModelRequestFields: { thinking: { type: "disabled" } } },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: {
|
||||
modelParams: { additionalModelRequestFields: { output_config: { effort: "low" } } },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: {
|
||||
modelParams: { additionalModelRequestFields: { output_config: { effort: "high" } } },
|
||||
},
|
||||
|
|
@ -491,31 +491,31 @@ describe("ModelsDevPlugin", () => {
|
|||
])
|
||||
|
||||
const sapCohere = yield* catalog.model.get(
|
||||
ProviderV2.ID.make("sap-ai-core"),
|
||||
ModelV2.ID.make("cohere--command-a-reasoning"),
|
||||
Provider.ID.make("sap-ai-core"),
|
||||
Model.ID.make("cohere--command-a-reasoning"),
|
||||
)
|
||||
expect(sapCohere?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
id: Model.VariantID.make("none"),
|
||||
settings: { modelParams: { thinking: { type: "disabled" } } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: { modelParams: { reasoning_effort: "low" } },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { modelParams: { reasoning_effort: "high" } },
|
||||
},
|
||||
])
|
||||
|
||||
const sapAnthropicEffort = yield* catalog.model.get(
|
||||
ProviderV2.ID.make("sap-ai-core"),
|
||||
ModelV2.ID.make("anthropic--claude-4.7-opus"),
|
||||
Provider.ID.make("sap-ai-core"),
|
||||
Model.ID.make("anthropic--claude-4.7-opus"),
|
||||
)
|
||||
expect(sapAnthropicEffort?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
id: Model.VariantID.make("low"),
|
||||
settings: {
|
||||
modelParams: {
|
||||
additionalModelRequestFields: {
|
||||
|
|
@ -528,12 +528,12 @@ describe("ModelsDevPlugin", () => {
|
|||
])
|
||||
|
||||
const sapAnthropicBudget = yield* catalog.model.get(
|
||||
ProviderV2.ID.make("sap-ai-core"),
|
||||
ModelV2.ID.make("anthropic--claude-4-sonnet"),
|
||||
Provider.ID.make("sap-ai-core"),
|
||||
Model.ID.make("anthropic--claude-4-sonnet"),
|
||||
)
|
||||
expect(sapAnthropicBudget?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: {
|
||||
modelParams: {
|
||||
additionalModelRequestFields: { thinking: { type: "enabled", budget_tokens: 8000 } },
|
||||
|
|
@ -541,7 +541,7 @@ describe("ModelsDevPlugin", () => {
|
|||
},
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
id: Model.VariantID.make("max"),
|
||||
settings: {
|
||||
modelParams: {
|
||||
additionalModelRequestFields: { thinking: { type: "enabled", budget_tokens: 16000 } },
|
||||
|
|
|
|||
|
|
@ -1,24 +1,21 @@
|
|||
import { describe, expect } from "bun:test"
|
||||
import { Message, SystemPart } from "@opencode-ai/ai"
|
||||
import { DateTime, Effect, Schema } from "effect"
|
||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHooks } from "@opencode-ai/core/plugin/hooks"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { PluginPromise } from "@opencode-ai/core/plugin/promise"
|
||||
import { WebSearch } from "@opencode-ai/core/websearch"
|
||||
import { SessionV2 } from "@opencode-ai/core/session"
|
||||
import { Session } from "@opencode-ai/core/session"
|
||||
import { SessionMessage } from "@opencode-ai/core/session/message"
|
||||
import { SessionPending } from "@opencode-ai/core/session/pending"
|
||||
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
import { Tool } from "@opencode-ai/plugin/v2/tool"
|
||||
import type { SessionHooks } from "@opencode-ai/plugin/v2/effect/session"
|
||||
import { Model } from "@opencode-ai/schema/model"
|
||||
import { Provider } from "@opencode-ai/schema/provider"
|
||||
import { Tool } from "@opencode-ai/core/tool"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { define } from "@opencode-ai/plugin/promise/plugin"
|
||||
import type { SessionHooks } from "@opencode-ai/plugin/effect/session"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
import { host as testHost } from "./host"
|
||||
|
|
@ -35,7 +32,7 @@ describe("fromPromise", () => {
|
|||
})
|
||||
|
||||
yield* PluginPromise.fromPromise(
|
||||
Plugin.define({
|
||||
define({
|
||||
id: "promise-session-generate",
|
||||
setup: async (ctx) => {
|
||||
expect(await ctx.session.generate({ sessionID: "ses_generate", prompt: "Summarize" })).toEqual({
|
||||
|
|
@ -67,7 +64,7 @@ describe("fromPromise", () => {
|
|||
SessionPending.Synthetic.make({
|
||||
admittedSeq: 1,
|
||||
id: SessionMessage.ID.make(input.id),
|
||||
sessionID: SessionV2.ID.make(input.sessionID),
|
||||
sessionID: Session.ID.make(input.sessionID),
|
||||
timeCreated: DateTime.makeUnsafe(0),
|
||||
type: "synthetic",
|
||||
data: {
|
||||
|
|
@ -82,7 +79,7 @@ describe("fromPromise", () => {
|
|||
})
|
||||
|
||||
yield* PluginPromise.fromPromise(
|
||||
Plugin.define({
|
||||
define({
|
||||
id: "promise-session-synthetic",
|
||||
setup: async (ctx) => {
|
||||
await ctx.session.synthetic(input)
|
||||
|
|
@ -101,10 +98,10 @@ describe("fromPromise", () => {
|
|||
|
||||
it.effect("forwards standard client reads", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const seen: string[] = []
|
||||
const promisePlugin = Plugin.define({
|
||||
const promisePlugin = define({
|
||||
id: "promise-client-reads",
|
||||
setup: async (ctx) => {
|
||||
const results = await Promise.all([
|
||||
|
|
@ -128,31 +125,36 @@ describe("fromPromise", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("forwards direct agent and model reads", () =>
|
||||
it.effect("forwards direct agent and model list reads", () =>
|
||||
Effect.gen(function* () {
|
||||
const agents = yield* AgentV2.Service
|
||||
const agents = yield* Agent.Service
|
||||
const catalog = yield* Catalog.Service
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* agents.transform((draft) =>
|
||||
draft.update(AgentV2.ID.make("reviewer"), (agent) => {
|
||||
draft.update(Agent.ID.make("reviewer"), (agent) => {
|
||||
agent.description = "Reviews code"
|
||||
}),
|
||||
)
|
||||
yield* catalog.transform((draft) =>
|
||||
draft.model.update(ProviderV2.ID.make("test"), ModelV2.ID.make("alias"), (model) => {
|
||||
model.modelID = ModelV2.ID.make("gpt-5")
|
||||
draft.model.update(Provider.ID.make("test"), Model.ID.make("alias"), (model) => {
|
||||
model.modelID = Model.ID.make("gpt-5")
|
||||
}),
|
||||
)
|
||||
|
||||
yield* PluginPromise.fromPromise(
|
||||
Plugin.define({
|
||||
define({
|
||||
id: "promise-direct-reads",
|
||||
setup: async (ctx) => {
|
||||
expect(await ctx.agent.get("reviewer")).toMatchObject({ description: "Reviews code" })
|
||||
expect(await ctx.agent.get("missing")).toBeUndefined()
|
||||
expect(await ctx.catalog.model.get("test", "alias")).toMatchObject({ modelID: "gpt-5" })
|
||||
expect(await ctx.catalog.model.get("test", "missing")).toBeUndefined()
|
||||
expect((await ctx.agent.get({ agentID: Agent.ID.make("reviewer") })).data).toMatchObject({
|
||||
description: "Reviews code",
|
||||
})
|
||||
await expect(ctx.agent.get({ agentID: Agent.ID.make("missing") })).rejects.toThrow("Agent not found: missing")
|
||||
const models = (await ctx.catalog.model.list()).data
|
||||
expect(models.find((model) => model.providerID === "test" && model.id === "alias")).toMatchObject({
|
||||
modelID: "gpt-5",
|
||||
})
|
||||
expect(models.find((model) => model.providerID === "test" && model.id === "missing")).toBeUndefined()
|
||||
},
|
||||
}),
|
||||
).effect(host)
|
||||
|
|
@ -161,11 +163,11 @@ describe("fromPromise", () => {
|
|||
|
||||
it.effect("loads a promise plugin and registers a transform hook", () =>
|
||||
Effect.gen(function* () {
|
||||
const agents = yield* AgentV2.Service
|
||||
const plugin = yield* PluginV2.Service
|
||||
const agents = yield* Agent.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
|
||||
const promisePlugin = Plugin.define({
|
||||
const promisePlugin = define({
|
||||
id: "promise-example",
|
||||
setup: async (ctx) => {
|
||||
expect(ctx.options.mode).toBe("strict")
|
||||
|
|
@ -181,7 +183,7 @@ describe("fromPromise", () => {
|
|||
const adapted = PluginPromise.fromPromise(promisePlugin)
|
||||
yield* adapted.effect({ ...host, options: { mode: "strict" } })
|
||||
|
||||
expect(yield* agents.get(AgentV2.ID.make("reviewer"))).toMatchObject({
|
||||
expect(yield* agents.get(Agent.ID.make("reviewer"))).toMatchObject({
|
||||
description: "Reviews code",
|
||||
mode: "subagent",
|
||||
})
|
||||
|
|
@ -190,11 +192,11 @@ describe("fromPromise", () => {
|
|||
|
||||
it.effect("forwards session context hooks", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const hooks = yield* PluginHooks.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* PluginPromise.fromPromise(
|
||||
Plugin.define({
|
||||
define({
|
||||
id: "promise-session-context",
|
||||
setup: async (ctx) => {
|
||||
await ctx.session.hook("context", (event) => {
|
||||
|
|
@ -205,8 +207,8 @@ describe("fromPromise", () => {
|
|||
}),
|
||||
).effect(host)
|
||||
const event: SessionHooks["context"] = {
|
||||
sessionID: SessionV2.ID.make("ses_promise_session_context"),
|
||||
agent: AgentV2.ID.make("build"),
|
||||
sessionID: Session.ID.make("ses_promise_session_context"),
|
||||
agent: Agent.ID.make("build"),
|
||||
model: Model.Ref.make({ providerID: Provider.ID.make("test"), id: Model.ID.make("model") }),
|
||||
system: [SystemPart.make("Initial")],
|
||||
messages: [Message.user("Hello")],
|
||||
|
|
@ -222,11 +224,11 @@ describe("fromPromise", () => {
|
|||
|
||||
it.effect("disposes a hook registration on request", () =>
|
||||
Effect.gen(function* () {
|
||||
const agents = yield* AgentV2.Service
|
||||
const plugin = yield* PluginV2.Service
|
||||
const agents = yield* Agent.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
|
||||
const promisePlugin = Plugin.define({
|
||||
const promisePlugin = define({
|
||||
id: "promise-dispose",
|
||||
setup: async (ctx) => {
|
||||
const registration = await ctx.agent.transform((draft) => {
|
||||
|
|
@ -241,16 +243,16 @@ describe("fromPromise", () => {
|
|||
const adapted = PluginPromise.fromPromise(promisePlugin)
|
||||
yield* adapted.effect(host)
|
||||
|
||||
expect(yield* agents.get(AgentV2.ID.make("temp"))).toBeUndefined()
|
||||
expect(yield* agents.get(Agent.ID.make("temp"))).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("registers a standalone web search provider", () =>
|
||||
Effect.gen(function* () {
|
||||
const websearch = yield* WebSearch.Service
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const promisePlugin = Plugin.define({
|
||||
const promisePlugin = define({
|
||||
id: "promise-websearch",
|
||||
setup: async (ctx) => {
|
||||
await ctx.websearch.transform((draft) => {
|
||||
|
|
@ -279,10 +281,10 @@ describe("fromPromise", () => {
|
|||
|
||||
it.effect("runs the setup cleanup when the plugin scope closes", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const events: string[] = []
|
||||
const promisePlugin = Plugin.define({
|
||||
const promisePlugin = define({
|
||||
id: "promise-cleanup",
|
||||
setup: async () => {
|
||||
events.push("setup")
|
||||
|
|
@ -306,17 +308,18 @@ describe("fromPromise", () => {
|
|||
|
||||
it.effect("constructs plain Promise tool definitions in the host", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugins = yield* PluginV2.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
const plugins = yield* Plugin.Service
|
||||
const registry = yield* Tool.Service
|
||||
const host = yield* PluginHost.make(plugins)
|
||||
const progress: ToolRegistry.Progress[] = []
|
||||
const promisePlugin = Plugin.define({
|
||||
const progress: Tool.Metadata[] = []
|
||||
const promisePlugin = define({
|
||||
id: "promise-tool",
|
||||
setup: async (ctx) => {
|
||||
await ctx.tool.transform((tools) => {
|
||||
tools.add(
|
||||
"hello",
|
||||
Tool.make({
|
||||
{
|
||||
name: "hello",
|
||||
options: { codemode: false },
|
||||
description: "Hello",
|
||||
input: Schema.Struct({ name: Schema.String }),
|
||||
output: Schema.String,
|
||||
|
|
@ -324,8 +327,7 @@ describe("fromPromise", () => {
|
|||
await context.progress({ phase: "greeting" })
|
||||
return { output: `Hello, ${name}!` }
|
||||
},
|
||||
}),
|
||||
{ codemode: false },
|
||||
},
|
||||
)
|
||||
})
|
||||
},
|
||||
|
|
@ -337,8 +339,8 @@ describe("fromPromise", () => {
|
|||
expect(toolSet.definitions).toContainEqual(expect.objectContaining({ name: "hello", description: "Hello" }))
|
||||
expect(
|
||||
yield* toolSet.execute({
|
||||
sessionID: SessionV2.ID.make("ses_promise_tool"),
|
||||
agent: AgentV2.ID.make("build"),
|
||||
sessionID: Session.ID.make("ses_promise_tool"),
|
||||
agent: Agent.ID.make("build"),
|
||||
messageID: SessionMessage.ID.make("msg_promise_tool"),
|
||||
progress: (update) => Effect.sync(() => progress.push(update)),
|
||||
call: { type: "tool-call", id: "call_promise_tool", name: "hello", input: { name: "world" } },
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ 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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } 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 { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* AmazonBedrockPlugin.effect(host)
|
||||
|
|
@ -83,9 +83,9 @@ describe("AmazonBedrockPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const bedrock = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.amazonBedrock),
|
||||
package: ProviderV2.aisdk("@ai-sdk/amazon-bedrock"),
|
||||
const bedrock = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.amazonBedrock),
|
||||
package: Provider.aisdk("@ai-sdk/amazon-bedrock"),
|
||||
settings: { endpoint: "https://bedrock.example" },
|
||||
})
|
||||
catalog.provider.update(bedrock.id, (item) => {
|
||||
|
|
@ -94,8 +94,8 @@ describe("AmazonBedrockPlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
const result = required(yield* catalog.provider.get(ProviderV2.ID.amazonBedrock))
|
||||
expect(result.package).toBe(ProviderV2.aisdk("@ai-sdk/amazon-bedrock"))
|
||||
const result = required(yield* catalog.provider.get(Provider.ID.amazonBedrock))
|
||||
expect(result.package).toBe(Provider.aisdk("@ai-sdk/amazon-bedrock"))
|
||||
expect(result.settings).toEqual({ baseURL: "https://bedrock.example" })
|
||||
}),
|
||||
)
|
||||
|
|
@ -103,14 +103,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: {
|
||||
|
|
@ -129,14 +129,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: {
|
||||
|
|
@ -164,14 +164,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
},
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: { name: "amazon-bedrock" },
|
||||
|
|
@ -185,14 +185,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: { name: "amazon-bedrock", region: "eu-west-1" },
|
||||
|
|
@ -205,14 +205,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: { name: "amazon-bedrock" },
|
||||
|
|
@ -225,14 +225,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: { name: "amazon-bedrock" },
|
||||
|
|
@ -245,15 +245,15 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const headers: Array<string | null> = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: {
|
||||
|
|
@ -275,15 +275,15 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const headers: Array<string | null> = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: {
|
||||
|
|
@ -305,14 +305,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("openai.gpt-5.5")),
|
||||
modelID: ModelV2.ID.make("openai.gpt-5.5"),
|
||||
package: ProviderV2.aisdk("@ai-sdk/amazon-bedrock/mantle"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("openai.gpt-5.5")),
|
||||
modelID: Model.ID.make("openai.gpt-5.5"),
|
||||
package: Provider.aisdk("@ai-sdk/amazon-bedrock/mantle"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock/mantle",
|
||||
options: {
|
||||
|
|
@ -332,24 +332,24 @@ describe("AmazonBedrockPlugin", () => {
|
|||
|
||||
it.effect("selects Mantle APIs without Bedrock cross-region prefixes", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("openai.gpt-5.5")),
|
||||
modelID: ModelV2.ID.make("openai.gpt-5.5"),
|
||||
package: ProviderV2.aisdk("@ai-sdk/amazon-bedrock/mantle"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("openai.gpt-5.5")),
|
||||
modelID: Model.ID.make("openai.gpt-5.5"),
|
||||
package: Provider.aisdk("@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.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("openai.gpt-oss-safeguard-120b")),
|
||||
modelID: ModelV2.ID.make("openai.gpt-oss-safeguard-120b"),
|
||||
package: ProviderV2.aisdk("@ai-sdk/amazon-bedrock/mantle"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("openai.gpt-oss-safeguard-120b")),
|
||||
modelID: Model.ID.make("openai.gpt-oss-safeguard-120b"),
|
||||
package: Provider.aisdk("@ai-sdk/amazon-bedrock/mantle"),
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: { region: "us-east-1" },
|
||||
|
|
@ -360,14 +360,14 @@ describe("AmazonBedrockPlugin", () => {
|
|||
|
||||
it.effect("ignores other Bedrock provider subpaths", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("@ai-sdk/amazon-bedrock/anthropic"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("@ai-sdk/amazon-bedrock/anthropic"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock/anthropic",
|
||||
options: { name: "amazon-bedrock" },
|
||||
|
|
@ -387,15 +387,15 @@ describe("AmazonBedrockPlugin", () => {
|
|||
},
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const headers: Array<string | null> = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/amazon-bedrock",
|
||||
options: {
|
||||
|
|
@ -419,51 +419,51 @@ describe("AmazonBedrockPlugin", () => {
|
|||
|
||||
it.effect("applies legacy cross-region inference prefixes", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: { region: "eu-west-1" },
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("global.anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("global.anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("global.anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("global.anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: { region: "eu-west-1" },
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: { region: "ap-northeast-1" },
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: { region: "ap-southeast-2" },
|
||||
|
|
@ -481,15 +481,15 @@ describe("AmazonBedrockPlugin", () => {
|
|||
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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: {},
|
||||
|
|
@ -501,7 +501,7 @@ describe("AmazonBedrockPlugin", () => {
|
|||
|
||||
it.effect("applies the full legacy cross-region prefix matrix", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
const cases = [
|
||||
|
|
@ -573,10 +573,10 @@ describe("AmazonBedrockPlugin", () => {
|
|||
yield* addPlugin()
|
||||
for (const item of cases) {
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.amazonBedrock, ModelV2.ID.make(item.modelID)),
|
||||
modelID: ModelV2.ID.make(item.modelID),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.amazonBedrock, Model.ID.make(item.modelID)),
|
||||
modelID: Model.ID.make(item.modelID),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: { region: item.region },
|
||||
|
|
@ -588,15 +588,15 @@ describe("AmazonBedrockPlugin", () => {
|
|||
|
||||
it.effect("ignores non-Bedrock providers for language selection", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.openai, ModelV2.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.openai, Model.ID.make("anthropic.claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("anthropic.claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
options: { region: "eu-west-1" },
|
||||
|
|
|
|||
|
|
@ -2,18 +2,18 @@ import { AISDK } from "@opencode-ai/core/aisdk"
|
|||
import { describe, expect } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { AnthropicPlugin } from "@opencode-ai/core/plugin/provider/anthropic"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* AnthropicPlugin.effect(host)
|
||||
|
|
@ -29,9 +29,9 @@ describe("AnthropicPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const item = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.anthropic),
|
||||
package: ProviderV2.aisdk("@ai-sdk/anthropic"),
|
||||
const item = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.anthropic),
|
||||
package: Provider.aisdk("@ai-sdk/anthropic"),
|
||||
headers: { Existing: "1" },
|
||||
})
|
||||
catalog.provider.update(item.id, (draft) => {
|
||||
|
|
@ -40,32 +40,32 @@ describe("AnthropicPlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.anthropic)).headers?.["anthropic-beta"]).toBe(
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.anthropic)).headers?.["anthropic-beta"]).toBe(
|
||||
"interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14",
|
||||
)
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.anthropic)).headers?.Existing).toBe("1")
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.anthropic)).headers?.Existing).toBe("1")
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("ignores non-Anthropic providers", () =>
|
||||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => catalog.provider.update(ProviderV2.ID.openai, () => {}))
|
||||
yield* catalog.transform((catalog) => catalog.provider.update(Provider.ID.openai, () => {}))
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.openai)).headers?.["anthropic-beta"]).toBeUndefined()
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.openai)).headers?.["anthropic-beta"]).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("creates Anthropic SDKs with the model provider ID as the SDK name", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-anthropic"), ModelV2.ID.make("claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("@ai-sdk/anthropic"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-anthropic"), Model.ID.make("claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("@ai-sdk/anthropic"),
|
||||
}),
|
||||
package: "@ai-sdk/anthropic",
|
||||
options: { name: "custom-anthropic", apiKey: "test" },
|
||||
|
|
@ -76,14 +76,14 @@ describe("AnthropicPlugin", () => {
|
|||
|
||||
it.effect("uses the Anthropic provider ID as the SDK name for the bundled Anthropic provider", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
package: ProviderV2.aisdk("@ai-sdk/anthropic"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.anthropic, Model.ID.make("claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-5"),
|
||||
package: Provider.aisdk("@ai-sdk/anthropic"),
|
||||
}),
|
||||
package: "@ai-sdk/anthropic",
|
||||
options: { name: "anthropic", apiKey: "test" },
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ 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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { AzureCognitiveServicesPlugin } from "@opencode-ai/core/plugin/provider/azure"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* AzureCognitiveServicesPlugin.effect(host)
|
||||
|
|
@ -65,12 +65,12 @@ describe("AzureCognitiveServicesPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("azure-cognitive-services"), (item) => {
|
||||
item.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("azure-cognitive-services"), (item) => {
|
||||
item.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
const result = required(yield* catalog.provider.get(ProviderV2.ID.make("azure-cognitive-services")))
|
||||
const result = required(yield* catalog.provider.get(Provider.ID.make("azure-cognitive-services")))
|
||||
expect(result).toMatchObject({
|
||||
package: "aisdk:@ai-sdk/openai-compatible",
|
||||
settings: { baseURL: "https://cognitive.cognitiveservices.azure.com/openai" },
|
||||
|
|
@ -85,12 +85,12 @@ describe("AzureCognitiveServicesPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const azure = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.make("azure-cognitive-services")),
|
||||
const azure = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.make("azure-cognitive-services")),
|
||||
package: "aisdk:@ai-sdk/openai-compatible",
|
||||
})
|
||||
const openai = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.openai),
|
||||
const openai = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.openai),
|
||||
package: "aisdk:test-provider",
|
||||
})
|
||||
catalog.provider.update(azure.id, (item) => {
|
||||
|
|
@ -103,8 +103,8 @@ describe("AzureCognitiveServicesPlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
const azure = required(yield* catalog.provider.get(ProviderV2.ID.make("azure-cognitive-services")))
|
||||
const openai = required(yield* catalog.provider.get(ProviderV2.ID.openai))
|
||||
const azure = required(yield* catalog.provider.get(Provider.ID.make("azure-cognitive-services")))
|
||||
const openai = required(yield* catalog.provider.get(Provider.ID.openai))
|
||||
expect(azure.settings?.baseURL).toBeUndefined()
|
||||
expect(azure).toMatchObject({ package: "aisdk:@ai-sdk/openai-compatible" })
|
||||
expect(openai.settings?.baseURL).toBeUndefined()
|
||||
|
|
@ -115,14 +115,14 @@ describe("AzureCognitiveServicesPlugin", () => {
|
|||
|
||||
it.effect("selects chat only for completion URLs", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("azure-cognitive-services"), ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("azure-cognitive-services"), Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
@ -134,23 +134,23 @@ describe("AzureCognitiveServicesPlugin", () => {
|
|||
|
||||
it.effect("uses the legacy Azure selector order and provider guard", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("azure-cognitive-services"), ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("azure-cognitive-services"), Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
const ignored = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.openai, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.openai, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
@ -163,33 +163,33 @@ describe("AzureCognitiveServicesPlugin", () => {
|
|||
|
||||
it.effect("falls back from responses to messages, chat, then languageModel", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
const sdk = fakeSelectorSdk(calls)
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("azure-cognitive-services"), ModelV2.ID.make("messages-deployment")),
|
||||
modelID: ModelV2.ID.make("messages-deployment"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("azure-cognitive-services"), Model.ID.make("messages-deployment")),
|
||||
modelID: Model.ID.make("messages-deployment"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { messages: sdk.messages, chat: sdk.chat, languageModel: sdk.languageModel },
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("azure-cognitive-services"), ModelV2.ID.make("chat-deployment")),
|
||||
modelID: ModelV2.ID.make("chat-deployment"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("azure-cognitive-services"), Model.ID.make("chat-deployment")),
|
||||
modelID: Model.ID.make("chat-deployment"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { chat: sdk.chat, languageModel: sdk.languageModel },
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("azure-cognitive-services"), ModelV2.ID.make("language-deployment")),
|
||||
modelID: ModelV2.ID.make("language-deployment"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("azure-cognitive-services"), Model.ID.make("language-deployment")),
|
||||
modelID: Model.ID.make("language-deployment"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { languageModel: sdk.languageModel },
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ 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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { AzurePlugin } from "@opencode-ai/core/plugin/provider/azure"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* AzurePlugin.effect(host)
|
||||
|
|
@ -65,12 +65,12 @@ describe("AzurePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.azure, (item) => {
|
||||
item.package = ProviderV2.aisdk("@ai-sdk/azure")
|
||||
catalog.provider.update(Provider.ID.azure, (item) => {
|
||||
item.package = Provider.aisdk("@ai-sdk/azure")
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.azure)).settings?.resourceName).toBe("from-env")
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.azure)).settings?.resourceName).toBe("from-env")
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -80,20 +80,20 @@ describe("AzurePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const azure = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.azure),
|
||||
package: ProviderV2.aisdk("@ai-sdk/azure"),
|
||||
const azure = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.azure),
|
||||
package: Provider.aisdk("@ai-sdk/azure"),
|
||||
settings: { resourceName: "from-config" },
|
||||
})
|
||||
catalog.provider.update(azure.id, (item) => {
|
||||
item.package = azure.package
|
||||
item.settings = { resourceName: "from-config" }
|
||||
})
|
||||
catalog.provider.update(ProviderV2.ID.openai, () => {})
|
||||
catalog.provider.update(Provider.ID.openai, () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.azure)).settings?.resourceName).toBe("from-config")
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.openai)).settings?.resourceName).toBeUndefined()
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.azure)).settings?.resourceName).toBe("from-config")
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.openai)).settings?.resourceName).toBeUndefined()
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -103,9 +103,9 @@ describe("AzurePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const azure = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.azure),
|
||||
package: ProviderV2.aisdk("@ai-sdk/azure"),
|
||||
const azure = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.azure),
|
||||
package: Provider.aisdk("@ai-sdk/azure"),
|
||||
settings: { resourceName: "" },
|
||||
})
|
||||
catalog.provider.update(azure.id, (item) => {
|
||||
|
|
@ -114,7 +114,7 @@ describe("AzurePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.azure)).settings?.resourceName).toBe("from-env")
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.azure)).settings?.resourceName).toBe("from-env")
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -124,9 +124,9 @@ describe("AzurePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const azure = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.azure),
|
||||
package: ProviderV2.aisdk("@ai-sdk/azure"),
|
||||
const azure = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.azure),
|
||||
package: Provider.aisdk("@ai-sdk/azure"),
|
||||
settings: { resourceName: " " },
|
||||
})
|
||||
catalog.provider.update(azure.id, (item) => {
|
||||
|
|
@ -135,7 +135,7 @@ describe("AzurePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.azure)).settings?.resourceName).toBe("from-env")
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.azure)).settings?.resourceName).toBe("from-env")
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -143,14 +143,14 @@ describe("AzurePlugin", () => {
|
|||
it.effect("allows configured baseURL without resourceName", () =>
|
||||
withEnv({ AZURE_RESOURCE_NAME: undefined }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/azure",
|
||||
options: { name: "azure", baseURL: "https://proxy.example.com/openai" },
|
||||
|
|
@ -167,10 +167,10 @@ describe("AzurePlugin", () => {
|
|||
yield* addPlugin()
|
||||
const exit = yield* aisdk
|
||||
.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/azure",
|
||||
options: { name: "azure" },
|
||||
|
|
@ -183,15 +183,15 @@ describe("AzurePlugin", () => {
|
|||
|
||||
it.effect("selects chat only for completion URLs", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: { useCompletionUrls: true },
|
||||
|
|
@ -202,15 +202,15 @@ describe("AzurePlugin", () => {
|
|||
|
||||
it.effect("selects chat from per-call useCompletionUrls", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: { useCompletionUrls: true },
|
||||
|
|
@ -221,15 +221,15 @@ describe("AzurePlugin", () => {
|
|||
|
||||
it.effect("ignores model useCompletionUrls when per-call option is unset", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
body: { useCompletionUrls: true },
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
@ -241,24 +241,24 @@ describe("AzurePlugin", () => {
|
|||
|
||||
it.effect("uses the legacy Azure selector order and provider guard", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
const ignored = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.openai, ModelV2.ID.make("deployment")),
|
||||
modelID: ModelV2.ID.make("deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.openai, Model.ID.make("deployment")),
|
||||
modelID: Model.ID.make("deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
|
|
@ -270,7 +270,7 @@ describe("AzurePlugin", () => {
|
|||
|
||||
it.effect("falls back through the legacy Azure selector order", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
const make = (method: string) => (id: string) => {
|
||||
|
|
@ -279,19 +279,19 @@ describe("AzurePlugin", () => {
|
|||
}
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("messages-deployment")),
|
||||
modelID: ModelV2.ID.make("messages-deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("messages-deployment")),
|
||||
modelID: Model.ID.make("messages-deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { messages: make("messages"), chat: make("chat"), languageModel: make("languageModel") },
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.azure, ModelV2.ID.make("language-deployment")),
|
||||
modelID: ModelV2.ID.make("language-deployment"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.azure, Model.ID.make("language-deployment")),
|
||||
modelID: Model.ID.make("language-deployment"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: { languageModel: make("languageModel") },
|
||||
options: {},
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { AISDK } from "@opencode-ai/core/aisdk"
|
|||
import { describe, expect, mock } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { CerebrasPlugin } from "@opencode-ai/core/plugin/provider/cerebras"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ const cerebrasOptions: Record<string, unknown>[] = []
|
|||
const it = testEffect(PluginTestLayer)
|
||||
|
||||
const addPlugin = Effect.fn(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* CerebrasPlugin.effect(host)
|
||||
|
|
@ -35,13 +35,13 @@ describe("CerebrasPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("cerebras"), (item) => {
|
||||
item.package = ProviderV2.aisdk("@ai-sdk/cerebras")
|
||||
catalog.provider.update(Provider.ID.make("cerebras"), (item) => {
|
||||
item.package = Provider.aisdk("@ai-sdk/cerebras")
|
||||
item.headers = { ...item.headers, Existing: "1" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("cerebras")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("cerebras")))?.headers).toEqual({
|
||||
Existing: "1",
|
||||
"X-Cerebras-3rd-Party-Integration": "opencode",
|
||||
})
|
||||
|
|
@ -51,25 +51,25 @@ describe("CerebrasPlugin", () => {
|
|||
it.effect("ignores non-Cerebras providers", () =>
|
||||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => catalog.provider.update(ProviderV2.ID.make("groq"), () => {}))
|
||||
yield* catalog.transform((catalog) => catalog.provider.update(Provider.ID.make("groq"), () => {}))
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("groq")))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("groq")))?.headers).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("creates a bundled Cerebras SDK with the model provider ID as the SDK name", () =>
|
||||
Effect.gen(function* () {
|
||||
cerebrasOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(
|
||||
ProviderV2.ID.make("custom-cerebras"),
|
||||
ModelV2.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(
|
||||
Provider.ID.make("custom-cerebras"),
|
||||
Model.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
),
|
||||
modelID: ModelV2.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
modelID: Model.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/cerebras",
|
||||
|
|
@ -83,16 +83,16 @@ describe("CerebrasPlugin", () => {
|
|||
it.effect("preserves an explicit bundled Cerebras SDK name option", () =>
|
||||
Effect.gen(function* () {
|
||||
cerebrasOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(
|
||||
ProviderV2.ID.make("custom-cerebras"),
|
||||
ModelV2.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(
|
||||
Provider.ID.make("custom-cerebras"),
|
||||
Model.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
),
|
||||
modelID: ModelV2.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
modelID: Model.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/cerebras",
|
||||
|
|
@ -105,16 +105,16 @@ describe("CerebrasPlugin", () => {
|
|||
it.effect("ignores non-Cerebras SDK packages", () =>
|
||||
Effect.gen(function* () {
|
||||
cerebrasOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(
|
||||
ProviderV2.ID.make("custom-cerebras"),
|
||||
ModelV2.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(
|
||||
Provider.ID.make("custom-cerebras"),
|
||||
Model.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
),
|
||||
modelID: ModelV2.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
modelID: Model.ID.make("llama-4-scout-17b-16e-instruct"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/groq",
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { describe, expect, mock } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { CloudflareAIGatewayPlugin } from "@opencode-ai/core/plugin/provider/cloudflare-ai-gateway"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* CloudflareAIGatewayPlugin.effect(host)
|
||||
|
|
@ -112,13 +112,13 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
},
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -133,14 +133,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv(), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -178,14 +178,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv(), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -208,14 +208,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv(), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -246,14 +246,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -278,14 +278,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv({ CLOUDFLARE_API_TOKEN: undefined, CF_AIG_TOKEN: "cf-aig-token" }), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -301,14 +301,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv({ CLOUDFLARE_ACCOUNT_ID: undefined, CLOUDFLARE_GATEWAY_ID: undefined }), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -325,14 +325,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv({ CLOUDFLARE_API_TOKEN: undefined, CF_AIG_TOKEN: undefined }), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -355,14 +355,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -379,17 +379,17 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv(), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(
|
||||
ProviderV2.ID.make("cloudflare-ai-gateway"),
|
||||
ModelV2.ID.make("anthropic/claude-sonnet-4-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(
|
||||
Provider.ID.make("cloudflare-ai-gateway"),
|
||||
Model.ID.make("anthropic/claude-sonnet-4-5"),
|
||||
),
|
||||
modelID: ModelV2.ID.make("anthropic/claude-sonnet-4-5"),
|
||||
modelID: Model.ID.make("anthropic/claude-sonnet-4-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "ai-gateway-provider",
|
||||
|
|
@ -411,14 +411,14 @@ describe("CloudflareAIGatewayPlugin", () => {
|
|||
withEnv(cloudflareEnv(), () =>
|
||||
Effect.gen(function* () {
|
||||
resetCalls()
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-ai-gateway"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-ai-gateway"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { AISDK } from "@opencode-ai/core/aisdk"
|
|||
import { describe, expect } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { CloudflareWorkersAIPlugin } from "@opencode-ai/core/plugin/provider/cloudflare-workers-ai"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import type { LanguageModelV3 } from "@ai-sdk/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
|
@ -14,7 +14,7 @@ import { PluginTestLayer } from "./fixture"
|
|||
const it = testEffect(PluginTestLayer)
|
||||
|
||||
const addPlugin = Effect.fn(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* CloudflareWorkersAIPlugin.effect(host)
|
||||
|
|
@ -82,20 +82,20 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
it.effect("maps account ID to endpoint URL and creates an OpenAI-compatible SDK", () =>
|
||||
withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "key" }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("cloudflare-workers-ai"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("test-provider")
|
||||
catalog.provider.update(Provider.ID.make("cloudflare-workers-ai"), (provider) => {
|
||||
provider.package = Provider.aisdk("test-provider")
|
||||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.make("cloudflare-workers-ai")))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.make("cloudflare-workers-ai")))
|
||||
const sdk = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("@cf/model")),
|
||||
modelID: ModelV2.ID.make("@cf/model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-workers-ai"), Model.ID.make("@cf/model")),
|
||||
modelID: Model.ID.make("@cf/model"),
|
||||
package: provider.package,
|
||||
settings: provider.settings,
|
||||
}),
|
||||
|
|
@ -116,13 +116,13 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("cloudflare-workers-ai"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("test-provider")
|
||||
catalog.provider.update(Provider.ID.make("cloudflare-workers-ai"), (provider) => {
|
||||
provider.package = Provider.aisdk("test-provider")
|
||||
provider.settings = { ...provider.settings, baseURL: "https://proxy.example/v1" }
|
||||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.make("cloudflare-workers-ai")))).toMatchObject({
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.make("cloudflare-workers-ai")))).toMatchObject({
|
||||
package: "aisdk:test-provider",
|
||||
settings: { baseURL: "https://proxy.example/v1" },
|
||||
})
|
||||
|
|
@ -133,13 +133,13 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
it.effect("allows a configured baseURL without account ID", () =>
|
||||
withEnv({ CLOUDFLARE_ACCOUNT_ID: undefined, CLOUDFLARE_API_KEY: "key" }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("@cf/model")),
|
||||
modelID: ModelV2.ID.make("@cf/model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-workers-ai"), Model.ID.make("@cf/model")),
|
||||
modelID: Model.ID.make("@cf/model"),
|
||||
package: "aisdk:@ai-sdk/openai-compatible",
|
||||
settings: { baseURL: "https://proxy.example/v1" },
|
||||
}),
|
||||
|
|
@ -156,13 +156,13 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("cloudflare-workers-ai"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("test-provider")
|
||||
catalog.provider.update(Provider.ID.make("cloudflare-workers-ai"), (provider) => {
|
||||
provider.package = Provider.aisdk("test-provider")
|
||||
provider.settings = { ...provider.settings, accountId: "configured-acct" }
|
||||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.make("cloudflare-workers-ai")))).toMatchObject({
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.make("cloudflare-workers-ai")))).toMatchObject({
|
||||
package: "aisdk:test-provider",
|
||||
settings: { baseURL: "https://api.cloudflare.com/client/v4/accounts/env-acct/ai/v1" },
|
||||
})
|
||||
|
|
@ -173,13 +173,13 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
it.effect("uses env API key over auth or configured API key and keeps the Cloudflare User-Agent", () =>
|
||||
withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "env-key" }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("@cf/model")),
|
||||
modelID: ModelV2.ID.make("@cf/model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-workers-ai"), Model.ID.make("@cf/model")),
|
||||
modelID: Model.ID.make("@cf/model"),
|
||||
package: "aisdk:@ai-sdk/openai-compatible",
|
||||
settings: { baseURL: "https://proxy.example/v1" },
|
||||
}),
|
||||
|
|
@ -202,13 +202,13 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
it.effect("expands account ID vars in endpoint URLs", () =>
|
||||
withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "key" }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("@cf/model")),
|
||||
modelID: ModelV2.ID.make("@cf/model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-workers-ai"), Model.ID.make("@cf/model")),
|
||||
modelID: Model.ID.make("@cf/model"),
|
||||
package: "aisdk:@ai-sdk/openai-compatible",
|
||||
settings: { baseURL: "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1" },
|
||||
}),
|
||||
|
|
@ -227,14 +227,14 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
|
||||
it.effect("selects languageModel with the API model ID", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("@cf/api-model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-workers-ai"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("@cf/api-model"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
@ -248,13 +248,13 @@ describe("CloudflareWorkersAIPlugin", () => {
|
|||
it.effect("does not create an SDK for non OpenAI-compatible packages", () =>
|
||||
withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "key" }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("@cf/model")),
|
||||
modelID: ModelV2.ID.make("@cf/model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-workers-ai"), Model.ID.make("@cf/model")),
|
||||
modelID: Model.ID.make("@cf/model"),
|
||||
package: "aisdk:@ai-sdk/anthropic",
|
||||
settings: { baseURL: "https://proxy.example/v1" },
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ import path from "path"
|
|||
import { fileURLToPath } from "url"
|
||||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { DynamicProviderPlugin } from "@opencode-ai/core/plugin/provider/dynamic"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ function npmEntrypoint(entrypoint?: string) {
|
|||
}
|
||||
|
||||
const addPlugin = Effect.fn(function* (npm?: Npm.Interface) {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* DynamicProviderPlugin.effect(host).pipe(Effect.provideService(Npm.Service, npm ?? (yield* Npm.Service)))
|
||||
})
|
||||
|
|
@ -52,10 +52,10 @@ describe("DynamicProviderPlugin", () => {
|
|||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom"), ModelV2.ID.make("test-model")),
|
||||
modelID: ModelV2.ID.make("test-model"),
|
||||
package: ProviderV2.aisdk(fixtureProvider),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom"), Model.ID.make("test-model")),
|
||||
modelID: Model.ID.make("test-model"),
|
||||
package: Provider.aisdk(fixtureProvider),
|
||||
}),
|
||||
package: fixtureProvider,
|
||||
options: { name: "custom", marker: "dynamic" },
|
||||
|
|
@ -71,10 +71,10 @@ describe("DynamicProviderPlugin", () => {
|
|||
const sdk = { marker: "existing" }
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom"), ModelV2.ID.make("test-model")),
|
||||
modelID: ModelV2.ID.make("test-model"),
|
||||
package: ProviderV2.aisdk(fixtureProvider),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom"), Model.ID.make("test-model")),
|
||||
modelID: Model.ID.make("test-model"),
|
||||
package: Provider.aisdk(fixtureProvider),
|
||||
}),
|
||||
package: fixtureProvider,
|
||||
options: { name: "custom", marker: "dynamic" },
|
||||
|
|
@ -89,10 +89,10 @@ describe("DynamicProviderPlugin", () => {
|
|||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-provider"), ModelV2.ID.make("test-model")),
|
||||
modelID: ModelV2.ID.make("test-model"),
|
||||
package: ProviderV2.aisdk(fixtureProvider),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-provider"), Model.ID.make("test-model")),
|
||||
modelID: Model.ID.make("test-model"),
|
||||
package: Provider.aisdk(fixtureProvider),
|
||||
}),
|
||||
package: fixtureProvider,
|
||||
options: { name: "custom-provider", marker: "dynamic" },
|
||||
|
|
@ -106,9 +106,9 @@ describe("DynamicProviderPlugin", () => {
|
|||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin(npmEntrypoint(fixtureProviderPath))
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("npm-provider"), ModelV2.ID.make("test-model")),
|
||||
modelID: ModelV2.ID.make("test-model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("npm-provider"), Model.ID.make("test-model")),
|
||||
modelID: Model.ID.make("test-model"),
|
||||
package: "aisdk:fixture-provider",
|
||||
}),
|
||||
package: "fixture-provider",
|
||||
|
|
@ -124,9 +124,9 @@ describe("DynamicProviderPlugin", () => {
|
|||
yield* addPlugin(npmEntrypoint())
|
||||
const exit = yield* aisdk
|
||||
.language(
|
||||
ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("missing-entrypoint"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("alias"),
|
||||
Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("missing-entrypoint"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("alias"),
|
||||
package: "aisdk:fixture-provider",
|
||||
}),
|
||||
)
|
||||
|
|
@ -142,9 +142,9 @@ describe("DynamicProviderPlugin", () => {
|
|||
yield* addPlugin()
|
||||
const exit = yield* aisdk
|
||||
.language(
|
||||
ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("bad-import"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("alias"),
|
||||
Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("bad-import"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("alias"),
|
||||
package: "aisdk:file:///missing/provider-factory.js",
|
||||
}),
|
||||
)
|
||||
|
|
@ -156,15 +156,15 @@ describe("DynamicProviderPlugin", () => {
|
|||
|
||||
itWithAISDK.live("wraps missing provider factory exports as AISDK init errors", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const tmp = yield* tempEntrypoint("export const notAProviderFactory = true\n")
|
||||
yield* addPlugin(npmEntrypoint(tmp.entrypoint))
|
||||
const exit = yield* aisdk
|
||||
.language(
|
||||
ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("missing-factory"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("alias"),
|
||||
Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("missing-factory"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("alias"),
|
||||
package: "aisdk:fixture-provider",
|
||||
}),
|
||||
)
|
||||
|
|
@ -176,14 +176,14 @@ describe("DynamicProviderPlugin", () => {
|
|||
|
||||
itWithAISDK.effect("uses the model modelID for the default language model", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const language = yield* aisdk.language(
|
||||
ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("test-model-api"),
|
||||
package: ProviderV2.aisdk(fixtureProvider),
|
||||
Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("test-model-api"),
|
||||
package: Provider.aisdk(fixtureProvider),
|
||||
}),
|
||||
)
|
||||
expect(language).toMatchObject({ modelID: "test-model-api", options: { name: "custom" } })
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { AlibabaPlugin } from "@opencode-ai/core/plugin/provider/alibaba"
|
||||
import { CoherePlugin } from "@opencode-ai/core/plugin/provider/cohere"
|
||||
|
|
@ -13,11 +13,11 @@ import { MistralPlugin } from "@opencode-ai/core/plugin/provider/mistral"
|
|||
import { PerplexityPlugin } from "@opencode-ai/core/plugin/provider/perplexity"
|
||||
import { TogetherAIPlugin } from "@opencode-ai/core/plugin/provider/togetherai"
|
||||
import { VenicePlugin } from "@opencode-ai/core/plugin/provider/venice"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
||||
const modelID = ModelV2.ID.make("test-model")
|
||||
const modelID = Model.ID.make("test-model")
|
||||
const options = { name: "custom-provider", apiKey: "test", baseURL: "https://example.test" }
|
||||
const providers = [
|
||||
{ id: "alibaba", plugin: AlibabaPlugin, package: "@ai-sdk/alibaba", provider: "alibaba.chat" },
|
||||
|
|
@ -36,14 +36,14 @@ const it = testEffect(PluginTestLayer)
|
|||
providers.forEach((item) =>
|
||||
it.effect(`${item.id} loads only its exact package`, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* item.plugin.effect(host)
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make(item.id), modelID),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make(item.id), modelID),
|
||||
modelID,
|
||||
package: ProviderV2.aisdk(item.package),
|
||||
package: Provider.aisdk(item.package),
|
||||
})
|
||||
const matched = yield* aisdk.runSDK({ model, package: item.package, options })
|
||||
const ignored = yield* aisdk.runSDK({ model, package: `${item.package}/unsupported`, options })
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import { App } from "@opencode-ai/core/app"
|
|||
import { describe, expect, test } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { copilotBaseURL, copilotFetch, GithubCopilotPlugin } from "@opencode-ai/core/plugin/provider/github-copilot"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import type { LanguageModelV3 } from "@ai-sdk/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
|
|
@ -16,7 +16,7 @@ import { PluginTestLayer } from "./fixture"
|
|||
const it = testEffect(PluginTestLayer)
|
||||
|
||||
const addPlugin = Effect.fn(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* GithubCopilotPlugin.effect(host)
|
||||
|
|
@ -94,22 +94,22 @@ describe("GithubCopilotPlugin", () => {
|
|||
|
||||
it.effect("creates the bundled Copilot SDK for the GitHub Copilot package", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const ignored = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
options: { name: "github-copilot" },
|
||||
})
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/github-copilot",
|
||||
|
|
@ -122,14 +122,14 @@ describe("GithubCopilotPlugin", () => {
|
|||
|
||||
it.effect("selects languageModel when responses and chat are absent", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("claude-sonnet-4")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("claude-sonnet-4")),
|
||||
modelID: Model.ID.make("claude-sonnet-4"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
|
|
@ -141,14 +141,14 @@ describe("GithubCopilotPlugin", () => {
|
|||
|
||||
it.effect("selects languageModel with the API model ID when responses and chat are absent", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("claude-sonnet-4"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
|
|
@ -160,50 +160,50 @@ describe("GithubCopilotPlugin", () => {
|
|||
|
||||
it.effect("uses responses for gpt-5 models except gpt-5-mini", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5.1-codex")),
|
||||
modelID: ModelV2.ID.make("gpt-5.1-codex"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5.1-codex")),
|
||||
modelID: Model.ID.make("gpt-5.1-codex"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-4o")),
|
||||
modelID: ModelV2.ID.make("gpt-4o"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-4o")),
|
||||
modelID: Model.ID.make("gpt-4o"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5-mini")),
|
||||
modelID: ModelV2.ID.make("gpt-5-mini"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5-mini")),
|
||||
modelID: Model.ID.make("gpt-5-mini"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5-mini-2025-08-07")),
|
||||
modelID: ModelV2.ID.make("gpt-5-mini-2025-08-07"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5-mini-2025-08-07")),
|
||||
modelID: Model.ID.make("gpt-5-mini-2025-08-07"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
@ -221,14 +221,14 @@ describe("GithubCopilotPlugin", () => {
|
|||
|
||||
it.effect("uses advertised Copilot endpoint metadata before model ID fallbacks", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("mai-code-1-flash-picker")),
|
||||
modelID: ModelV2.ID.make("mai-code-1-flash-picker"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("mai-code-1-flash-picker")),
|
||||
modelID: Model.ID.make("mai-code-1-flash-picker"),
|
||||
package: "aisdk:test-provider",
|
||||
settings: { endpoint: "responses" },
|
||||
}),
|
||||
|
|
@ -236,9 +236,9 @@ describe("GithubCopilotPlugin", () => {
|
|||
options: { endpoint: "responses" },
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
settings: { endpoint: "chat" },
|
||||
}),
|
||||
|
|
@ -251,32 +251,32 @@ describe("GithubCopilotPlugin", () => {
|
|||
|
||||
it.effect("uses the API model ID when selecting responses or chat", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("default")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("default")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("small")),
|
||||
modelID: ModelV2.ID.make("gpt-5-mini"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("small")),
|
||||
modelID: Model.ID.make("gpt-5-mini"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
})
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("sonnet")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("github-copilot"), Model.ID.make("sonnet")),
|
||||
modelID: Model.ID.make("claude-sonnet-4"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
@ -290,12 +290,12 @@ describe("GithubCopilotPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("github-copilot"), () => {})
|
||||
catalog.model.update(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5-chat-latest"), () => {})
|
||||
catalog.provider.update(Provider.ID.make("github-copilot"), () => {})
|
||||
catalog.model.update(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5-chat-latest"), () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(
|
||||
required(yield* catalog.model.get(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5-chat-latest")))
|
||||
required(yield* catalog.model.get(Provider.ID.make("github-copilot"), Model.ID.make("gpt-5-chat-latest")))
|
||||
.enabled,
|
||||
).toBe(false)
|
||||
}),
|
||||
|
|
@ -305,12 +305,12 @@ describe("GithubCopilotPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("custom-copilot"), () => {})
|
||||
catalog.model.update(ProviderV2.ID.make("custom-copilot"), ModelV2.ID.make("gpt-5-chat-latest"), () => {})
|
||||
catalog.provider.update(Provider.ID.make("custom-copilot"), () => {})
|
||||
catalog.model.update(Provider.ID.make("custom-copilot"), Model.ID.make("gpt-5-chat-latest"), () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(
|
||||
required(yield* catalog.model.get(ProviderV2.ID.make("custom-copilot"), ModelV2.ID.make("gpt-5-chat-latest")))
|
||||
required(yield* catalog.model.get(Provider.ID.make("custom-copilot"), Model.ID.make("gpt-5-chat-latest")))
|
||||
.enabled,
|
||||
).toBe(true)
|
||||
}),
|
||||
|
|
@ -318,14 +318,14 @@ describe("GithubCopilotPlugin", () => {
|
|||
|
||||
it.effect("ignores non-Copilot providers", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("openai"), ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("openai"), Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { AISDK } from "@opencode-ai/core/aisdk"
|
|||
import { describe, expect, mock } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { GitLabPlugin } from "@opencode-ai/core/plugin/provider/gitlab"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ const gitlabSDKOptions: Record<string, unknown>[] = []
|
|||
const it = testEffect(PluginTestLayer)
|
||||
|
||||
const addPlugin = Effect.fn(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* GitLabPlugin.effect(host)
|
||||
|
|
@ -64,13 +64,13 @@ describe("GitLabPlugin", () => {
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
gitlabSDKOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("claude")),
|
||||
modelID: ModelV2.ID.make("claude"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("claude")),
|
||||
modelID: Model.ID.make("claude"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "gitlab-ai-provider",
|
||||
|
|
@ -102,13 +102,13 @@ describe("GitLabPlugin", () => {
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
gitlabSDKOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("claude")),
|
||||
modelID: ModelV2.ID.make("claude"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("claude")),
|
||||
modelID: Model.ID.make("claude"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "gitlab-ai-provider",
|
||||
|
|
@ -128,13 +128,13 @@ describe("GitLabPlugin", () => {
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
gitlabSDKOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("claude")),
|
||||
modelID: ModelV2.ID.make("claude"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("claude")),
|
||||
modelID: Model.ID.make("claude"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "gitlab-ai-provider",
|
||||
|
|
@ -170,13 +170,13 @@ describe("GitLabPlugin", () => {
|
|||
it.effect("ignores non-GitLab SDK packages", () =>
|
||||
Effect.gen(function* () {
|
||||
gitlabSDKOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("claude")),
|
||||
modelID: ModelV2.ID.make("claude"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("claude")),
|
||||
modelID: Model.ID.make("claude"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai",
|
||||
|
|
@ -189,14 +189,14 @@ describe("GitLabPlugin", () => {
|
|||
|
||||
it.effect("uses workflowChat for duo workflow models and preserves selectedModelRef", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: [string, unknown][] = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("duo-workflow-custom")),
|
||||
modelID: ModelV2.ID.make("duo-workflow-custom"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("duo-workflow-custom")),
|
||||
modelID: Model.ID.make("duo-workflow-custom"),
|
||||
package: "aisdk:test-provider",
|
||||
headers: {},
|
||||
settings: { workflowRef: "ref", workflowDefinition: "definition" },
|
||||
|
|
@ -223,14 +223,14 @@ describe("GitLabPlugin", () => {
|
|||
|
||||
it.effect("uses exact static workflow model ids when the provider recognizes them", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: [string, unknown][] = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("duo-workflow-exact")),
|
||||
modelID: ModelV2.ID.make("duo-workflow-exact"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("duo-workflow-exact")),
|
||||
modelID: Model.ID.make("duo-workflow-exact"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: {
|
||||
|
|
@ -251,14 +251,14 @@ describe("GitLabPlugin", () => {
|
|||
|
||||
it.effect("uses provider feature flags instead of model settings feature flags", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: [string, unknown][] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("duo-workflow-custom")),
|
||||
modelID: ModelV2.ID.make("duo-workflow-custom"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("duo-workflow-custom")),
|
||||
modelID: Model.ID.make("duo-workflow-custom"),
|
||||
package: "aisdk:test-provider",
|
||||
headers: {},
|
||||
settings: { featureFlags: { request_flag: true } },
|
||||
|
|
@ -278,14 +278,14 @@ describe("GitLabPlugin", () => {
|
|||
|
||||
it.effect("uses agenticChat with provider aiGatewayHeaders and feature flags for normal models", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: [string, unknown][] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("gitlab"), ModelV2.ID.make("claude")),
|
||||
modelID: ModelV2.ID.make("claude"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("gitlab"), Model.ID.make("claude")),
|
||||
modelID: Model.ID.make("claude"),
|
||||
package: "aisdk:test-provider",
|
||||
headers: { h: "v" },
|
||||
settings: {},
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ import type { LanguageModelV3 } from "@ai-sdk/provider"
|
|||
import { describe, expect } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { GoogleVertexAnthropicPlugin, GoogleVertexPlugin } from "@opencode-ai/core/plugin/provider/google-vertex"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
||||
const it = testEffect(PluginTestLayer)
|
||||
|
||||
const addPlugin = Effect.fn(function* (definition: typeof GoogleVertexAnthropicPlugin | typeof GoogleVertexPlugin) {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* definition.effect(host)
|
||||
|
|
@ -63,15 +63,15 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("google-vertex-anthropic"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/google-vertex/anthropic")
|
||||
catalog.provider.update(Provider.ID.make("google-vertex-anthropic"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/google-vertex/anthropic")
|
||||
}),
|
||||
)
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("google-vertex-anthropic")))?.settings?.project).toBe(
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("google-vertex-anthropic")))?.settings?.project).toBe(
|
||||
"cloud-project",
|
||||
)
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("google-vertex-anthropic")))?.settings?.location).toBe(
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("google-vertex-anthropic")))?.settings?.location).toBe(
|
||||
"cloud-location",
|
||||
)
|
||||
}),
|
||||
|
|
@ -83,16 +83,16 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("google-vertex-anthropic"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/google-vertex/anthropic")
|
||||
catalog.provider.update(Provider.ID.make("google-vertex-anthropic"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/google-vertex/anthropic")
|
||||
provider.settings = { ...provider.settings, project: "configured-project", location: "configured-location" }
|
||||
}),
|
||||
)
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("google-vertex-anthropic")))?.settings?.project).toBe(
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("google-vertex-anthropic")))?.settings?.project).toBe(
|
||||
"configured-project",
|
||||
)
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("google-vertex-anthropic")))?.settings?.location).toBe(
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("google-vertex-anthropic")))?.settings?.location).toBe(
|
||||
"configured-location",
|
||||
)
|
||||
}),
|
||||
|
|
@ -111,16 +111,16 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
},
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(
|
||||
ProviderV2.ID.make("google-vertex-anthropic"),
|
||||
ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(
|
||||
Provider.ID.make("google-vertex-anthropic"),
|
||||
Model.ID.make("claude-sonnet-4-5"),
|
||||
),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
modelID: Model.ID.make("claude-sonnet-4-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex/anthropic",
|
||||
|
|
@ -138,16 +138,16 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
{ GOOGLE_CLOUD_PROJECT: "project", GOOGLE_CLOUD_LOCATION: "cloud-location", VERTEX_LOCATION: "vertex-location" },
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(
|
||||
ProviderV2.ID.make("google-vertex-anthropic"),
|
||||
ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(
|
||||
Provider.ID.make("google-vertex-anthropic"),
|
||||
Model.ID.make("claude-sonnet-4-5"),
|
||||
),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
modelID: Model.ID.make("claude-sonnet-4-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex/anthropic",
|
||||
|
|
@ -162,13 +162,13 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
|
||||
it.effect("creates SDKs for google-vertex Anthropic models with multi-region endpoints", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make("claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make("claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex/anthropic",
|
||||
|
|
@ -182,13 +182,13 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
|
||||
it.effect("keeps configured baseURL for google-vertex Anthropic models", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make("claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make("claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex/anthropic",
|
||||
|
|
@ -198,25 +198,25 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("selects google-vertex Anthropic language models through V2 plugins", () =>
|
||||
it.effect("selects google-vertex Anthropic language models through plugins", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin(GoogleVertexPlugin)
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
const sdkResult = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make(" claude-sonnet-4-5 ")),
|
||||
modelID: ModelV2.ID.make(" claude-sonnet-4-5 "),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make(" claude-sonnet-4-5 ")),
|
||||
modelID: Model.ID.make(" claude-sonnet-4-5 "),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex/anthropic",
|
||||
options: { name: "google-vertex", project: "project", location: "us" },
|
||||
})
|
||||
const languageResult = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make(" claude-sonnet-4-5 ")),
|
||||
modelID: ModelV2.ID.make(" claude-sonnet-4-5 "),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make(" claude-sonnet-4-5 ")),
|
||||
modelID: Model.ID.make(" claude-sonnet-4-5 "),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: sdkResult.sdk,
|
||||
|
|
@ -232,14 +232,14 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
|
||||
it.effect("trims model IDs before selecting language models", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex-anthropic"), ModelV2.ID.make(" claude-sonnet-4-5 ")),
|
||||
modelID: ModelV2.ID.make(" claude-sonnet-4-5 "),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex-anthropic"), Model.ID.make(" claude-sonnet-4-5 ")),
|
||||
modelID: Model.ID.make(" claude-sonnet-4-5 "),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { languageModel: selector(calls) },
|
||||
|
|
@ -251,14 +251,14 @@ describe("GoogleVertexAnthropicPlugin", () => {
|
|||
|
||||
it.effect("ignores non Vertex Anthropic providers for language selection", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin(GoogleVertexAnthropicPlugin)
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make("claude-sonnet-4-5")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-5"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make("claude-sonnet-4-5")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-5"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { languageModel: selector(calls) },
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { AISDK } from "@opencode-ai/core/aisdk"
|
|||
import { describe, expect, mock } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { GoogleVertexPlugin } from "@opencode-ai/core/plugin/provider/google-vertex"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import type { LanguageModelV3 } from "@ai-sdk/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
|
@ -16,7 +16,7 @@ const googleAuthOptions: Record<string, any>[] = []
|
|||
const it = testEffect(PluginTestLayer)
|
||||
|
||||
const addPlugin = Effect.fn(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* GoogleVertexPlugin.effect(host)
|
||||
|
|
@ -91,14 +91,14 @@ describe("GoogleVertexPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.opencode, (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.opencode, (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { ...provider.settings, baseURL: "https://opencode.ai/zen/v1" }
|
||||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.opencode))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.opencode))
|
||||
expect(provider.settings).toEqual({ baseURL: "https://opencode.ai/zen/v1" })
|
||||
}),
|
||||
)
|
||||
|
|
@ -117,8 +117,8 @@ describe("GoogleVertexPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = {
|
||||
...provider.settings,
|
||||
baseURL:
|
||||
|
|
@ -127,7 +127,7 @@ describe("GoogleVertexPlugin", () => {
|
|||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.make("google-vertex")))
|
||||
expect(provider.settings?.project).toBe("google-cloud-project")
|
||||
expect(provider.settings?.location).toBe("google-vertex-location")
|
||||
expect(provider).toMatchObject({
|
||||
|
|
@ -155,12 +155,12 @@ describe("GoogleVertexPlugin", () => {
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
vertexOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = {
|
||||
...provider.settings,
|
||||
baseURL:
|
||||
|
|
@ -169,11 +169,11 @@ describe("GoogleVertexPlugin", () => {
|
|||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.make("google-vertex")))
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make("gemini")),
|
||||
modelID: ModelV2.ID.make("gemini"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make("gemini")),
|
||||
modelID: Model.ID.make("gemini"),
|
||||
package: "aisdk:@ai-sdk/google-vertex",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex",
|
||||
|
|
@ -208,8 +208,8 @@ describe("GoogleVertexPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = {
|
||||
...provider.settings,
|
||||
baseURL:
|
||||
|
|
@ -219,7 +219,7 @@ describe("GoogleVertexPlugin", () => {
|
|||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.make("google-vertex")))
|
||||
expect(provider.settings?.project).toBe("config-project")
|
||||
expect(provider.settings?.location).toBe("global")
|
||||
expect(provider).toMatchObject({
|
||||
|
|
@ -234,8 +234,8 @@ describe("GoogleVertexPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = {
|
||||
...provider.settings,
|
||||
baseURL:
|
||||
|
|
@ -245,7 +245,7 @@ describe("GoogleVertexPlugin", () => {
|
|||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.make("google-vertex")))
|
||||
expect(provider).toMatchObject({
|
||||
package: "aisdk:@ai-sdk/openai-compatible",
|
||||
settings: { baseURL: "https://eu-aiplatform.googleapis.com/v1/projects/config-project/locations/eu" },
|
||||
|
|
@ -267,13 +267,13 @@ describe("GoogleVertexPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/google-vertex")
|
||||
catalog.provider.update(Provider.ID.make("google-vertex"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/google-vertex")
|
||||
provider.settings = { ...provider.settings, project: "config-project" }
|
||||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.make("google-vertex")))
|
||||
expect(provider.settings?.project).toBe("config-project")
|
||||
expect(provider.settings?.location).toBe("us-central1")
|
||||
}),
|
||||
|
|
@ -289,13 +289,13 @@ describe("GoogleVertexPlugin", () => {
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
vertexOptions.length = 0
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make("gemini")),
|
||||
modelID: ModelV2.ID.make("gemini"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make("gemini")),
|
||||
modelID: Model.ID.make("gemini"),
|
||||
package: "aisdk:@ai-sdk/google-vertex",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex",
|
||||
|
|
@ -313,7 +313,7 @@ describe("GoogleVertexPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
googleAuthOptions.length = 0
|
||||
const fetchCalls: { input: Parameters<typeof fetch>[0]; init?: RequestInit }[] = []
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
yield* aisdk.hook.sdk((evt) =>
|
||||
|
|
@ -338,9 +338,9 @@ describe("GoogleVertexPlugin", () => {
|
|||
Effect.void,
|
||||
() =>
|
||||
aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make("gemini")),
|
||||
modelID: ModelV2.ID.make("gemini"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make("gemini")),
|
||||
modelID: Model.ID.make("gemini"),
|
||||
package: "aisdk:@ai-sdk/openai-compatible",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -361,14 +361,14 @@ describe("GoogleVertexPlugin", () => {
|
|||
|
||||
it.effect("trims model IDs before selecting language models", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google-vertex"), ModelV2.ID.make(" gemini-2.5-pro ")),
|
||||
modelID: ModelV2.ID.make(" gemini-2.5-pro "),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google-vertex"), Model.ID.make(" gemini-2.5-pro ")),
|
||||
modelID: Model.ID.make(" gemini-2.5-pro "),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
sdk: { languageModel: fakeSelectorSdk(calls).languageModel },
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { GooglePlugin } from "@opencode-ai/core/plugin/provider/google"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* GooglePlugin.effect(host)
|
||||
|
|
@ -21,13 +21,13 @@ const addPlugin = Effect.fn(function* () {
|
|||
describe("GooglePlugin", () => {
|
||||
it.effect("creates a Google Generative AI SDK for @ai-sdk/google using the provider ID as SDK name", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-google"), ModelV2.ID.make("gemini")),
|
||||
modelID: ModelV2.ID.make("gemini"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-google"), Model.ID.make("gemini")),
|
||||
modelID: Model.ID.make("gemini"),
|
||||
package: "aisdk:@ai-sdk/google",
|
||||
}),
|
||||
package: "@ai-sdk/google",
|
||||
|
|
@ -40,13 +40,13 @@ describe("GooglePlugin", () => {
|
|||
|
||||
it.effect("ignores non-Google SDK packages", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("google"), ModelV2.ID.make("gemini")),
|
||||
modelID: ModelV2.ID.make("gemini"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("google"), Model.ID.make("gemini")),
|
||||
modelID: Model.ID.make("gemini"),
|
||||
package: "aisdk:@ai-sdk/google",
|
||||
}),
|
||||
package: "@ai-sdk/google-vertex",
|
||||
|
|
@ -58,13 +58,13 @@ describe("GooglePlugin", () => {
|
|||
|
||||
it.effect("uses default languageModel loading with provider ID parity", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const sdkEvent = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-google"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("gemini-api"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-google"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("gemini-api"),
|
||||
package: "aisdk:@ai-sdk/google",
|
||||
}),
|
||||
package: "@ai-sdk/google",
|
||||
|
|
@ -87,9 +87,9 @@ describe("GooglePlugin", () => {
|
|||
yield* addPlugin()
|
||||
|
||||
const resolved = yield* aisdk.model(
|
||||
ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-google"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("gemini-api"),
|
||||
Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-google"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("gemini-api"),
|
||||
package: "aisdk:@ai-sdk/google",
|
||||
settings: { apiKey: "test" },
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { ProviderPlugins } from "@opencode-ai/core/plugin/provider"
|
||||
import { KiloPlugin } from "@opencode-ai/core/plugin/provider/kilo"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* KiloPlugin.effect(host)
|
||||
})
|
||||
|
|
@ -26,20 +26,20 @@ describe("KiloPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("kilo"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("kilo"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://api.kilo.ai/api/gateway" }
|
||||
provider.headers = { Existing: "value" }
|
||||
})
|
||||
catalog.provider.update(ProviderV2.ID.openrouter, () => {})
|
||||
catalog.provider.update(Provider.ID.openrouter, () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("kilo")))?.headers).toEqual({
|
||||
Existing: "value",
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
})
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.openrouter))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.openrouter))?.headers).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -47,20 +47,20 @@ describe("KiloPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("kilo"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("kilo"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://api.kilo.ai/api/gateway" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("kilo")))?.headers).toEqual({
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
})
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo")))?.headers).not.toHaveProperty("http-referer")
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo")))?.headers).not.toHaveProperty("x-title")
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo")))?.headers).not.toHaveProperty("X-Source")
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("kilo")))?.headers).not.toHaveProperty("http-referer")
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("kilo")))?.headers).not.toHaveProperty("x-title")
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("kilo")))?.headers).not.toHaveProperty("X-Source")
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -68,18 +68,18 @@ describe("KiloPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("kilo"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("kilo")
|
||||
catalog.provider.update(Provider.ID.make("kilo"), (provider) => {
|
||||
provider.package = Provider.aisdk("kilo")
|
||||
})
|
||||
catalog.provider.update(ProviderV2.ID.make("custom-kilo"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("custom-kilo"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://api.kilo.ai/api/gateway" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo")))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("custom-kilo")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("kilo")))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("custom-kilo")))?.headers).toEqual({
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,18 +2,18 @@ import { describe, expect } from "bun:test"
|
|||
import { Effect } from "effect"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { ProviderPlugins } from "@opencode-ai/core/plugin/provider"
|
||||
import { LLMGatewayPlugin } from "@opencode-ai/core/plugin/provider/llmgateway"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const integration = yield* Integration.Service
|
||||
yield* LLMGatewayPlugin.effect(host).pipe(Effect.provideService(Integration.Service, integration))
|
||||
|
|
@ -33,21 +33,21 @@ describe("LLMGatewayPlugin", () => {
|
|||
editor.update(Integration.ID.make("openrouter"), () => {})
|
||||
})
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("llmgateway"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("llmgateway"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://api.llmgateway.io/v1" }
|
||||
provider.headers = { Existing: "value" }
|
||||
})
|
||||
catalog.provider.update(ProviderV2.ID.openrouter, () => {})
|
||||
catalog.provider.update(Provider.ID.openrouter, () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("llmgateway")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("llmgateway")))?.headers).toEqual({
|
||||
Existing: "value",
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
"X-Source": "opencode",
|
||||
})
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.openrouter))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.openrouter))?.headers).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -59,16 +59,16 @@ describe("LLMGatewayPlugin", () => {
|
|||
editor.update(Integration.ID.make("llmgateway"), () => {})
|
||||
})
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("llmgateway"), (provider) => {
|
||||
catalog.provider.update(Provider.ID.make("llmgateway"), (provider) => {
|
||||
provider.disabled = true
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://api.llmgateway.io/v1" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("llmgateway")))?.disabled).toBe(true)
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("llmgateway")))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("llmgateway")))?.disabled).toBe(true)
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("llmgateway")))?.headers).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { ProviderPlugins } from "@opencode-ai/core/plugin/provider"
|
||||
import { NvidiaPlugin } from "@opencode-ai/core/plugin/provider/nvidia"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* NvidiaPlugin.effect(host)
|
||||
})
|
||||
|
|
@ -26,21 +26,21 @@ describe("NvidiaPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("nvidia"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("nvidia"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://integrate.api.nvidia.com/v1" }
|
||||
provider.headers = { Existing: "value" }
|
||||
})
|
||||
catalog.provider.update(ProviderV2.ID.openrouter, () => {})
|
||||
catalog.provider.update(Provider.ID.openrouter, () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("nvidia")))?.headers).toEqual({
|
||||
Existing: "value",
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
"X-BILLING-INVOKE-ORIGIN": "OpenCode",
|
||||
})
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.openrouter))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.openrouter))?.headers).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -48,14 +48,14 @@ describe("NvidiaPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("nvidia"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("nvidia"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://integrate.api.nvidia.com/v1" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("nvidia")))?.headers).toEqual({
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
"X-BILLING-INVOKE-ORIGIN": "OpenCode",
|
||||
|
|
@ -67,15 +67,15 @@ describe("NvidiaPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("nvidia"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("nvidia"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { baseURL: "https://integrate.api.nvidia.com/v1" }
|
||||
provider.headers = { "X-BILLING-INVOKE-ORIGIN": "CustomOrigin" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("nvidia")))?.headers).toEqual({
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
"X-BILLING-INVOKE-ORIGIN": "CustomOrigin",
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { OpenAICompatiblePlugin } from "@opencode-ai/core/plugin/provider/openai-compatible"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* OpenAICompatiblePlugin.effect(host)
|
||||
|
|
@ -21,22 +21,22 @@ const addPlugin = Effect.fn(function* () {
|
|||
describe("OpenAICompatiblePlugin", () => {
|
||||
it.effect("preserves explicit includeUsage false and defaults it to true", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const defaulted = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom"), ModelV2.ID.make("model")),
|
||||
modelID: ModelV2.ID.make("model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom"), Model.ID.make("model")),
|
||||
modelID: Model.ID.make("model"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
options: { name: "custom" },
|
||||
})
|
||||
const disabled = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom"), ModelV2.ID.make("model")),
|
||||
modelID: ModelV2.ID.make("model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom"), Model.ID.make("model")),
|
||||
modelID: Model.ID.make("model"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -49,13 +49,13 @@ describe("OpenAICompatiblePlugin", () => {
|
|||
|
||||
it.effect("defaults includeUsage for OpenAI-compatible package matches", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom"), ModelV2.ID.make("model")),
|
||||
modelID: ModelV2.ID.make("model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom"), Model.ID.make("model")),
|
||||
modelID: Model.ID.make("model"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "file:///tmp/@ai-sdk/openai-compatible-provider.js",
|
||||
|
|
@ -67,7 +67,7 @@ describe("OpenAICompatiblePlugin", () => {
|
|||
|
||||
it.effect("uses the provider ID as the OpenAI-compatible provider name", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const observed: string[] = []
|
||||
yield* addPlugin()
|
||||
|
|
@ -77,9 +77,9 @@ describe("OpenAICompatiblePlugin", () => {
|
|||
}),
|
||||
)
|
||||
yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-provider"), ModelV2.ID.make("model")),
|
||||
modelID: ModelV2.ID.make("model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-provider"), Model.ID.make("model")),
|
||||
modelID: Model.ID.make("model"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -98,9 +98,9 @@ describe("OpenAICompatiblePlugin", () => {
|
|||
})
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("model")),
|
||||
modelID: ModelV2.ID.make("model"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("cloudflare-workers-ai"), Model.ID.make("model")),
|
||||
modelID: Model.ID.make("model"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
|
|||
|
|
@ -6,18 +6,18 @@ import { Effect } from "effect"
|
|||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { Credential } from "@opencode-ai/core/credential"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { OpenAIPlugin } from "@opencode-ai/core/plugin/provider/openai"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const integrations = yield* Integration.Service
|
||||
|
|
@ -63,14 +63,14 @@ describe("OpenAIPlugin", () => {
|
|||
|
||||
it.effect("creates an OpenAI SDK for @ai-sdk/openai using the provider ID as SDK name", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-openai"), ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-openai"), Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/openai",
|
||||
options: { name: "custom-openai", apiKey: "test" },
|
||||
|
|
@ -81,14 +81,14 @@ describe("OpenAIPlugin", () => {
|
|||
|
||||
it.effect("ignores non-OpenAI SDK packages", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.openai, Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
options: { name: "openai" },
|
||||
|
|
@ -99,15 +99,15 @@ describe("OpenAIPlugin", () => {
|
|||
|
||||
it.effect("uses the Responses API for language models", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.openai, ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.openai, Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
|
|
@ -119,15 +119,15 @@ describe("OpenAIPlugin", () => {
|
|||
|
||||
it.effect("ignores non-OpenAI providers", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const calls: string[] = []
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.anthropic, ModelV2.ID.make("gpt-5")),
|
||||
modelID: ModelV2.ID.make("gpt-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.anthropic, Model.ID.make("gpt-5")),
|
||||
modelID: Model.ID.make("gpt-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
options: {},
|
||||
|
|
@ -141,20 +141,20 @@ describe("OpenAIPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const item = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.openai),
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai"),
|
||||
const item = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.openai),
|
||||
package: Provider.aisdk("@ai-sdk/openai"),
|
||||
})
|
||||
catalog.provider.update(item.id, (draft) => {
|
||||
draft.package = item.package
|
||||
})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5"), () => {})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5-chat-latest"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5-chat-latest"), () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5"))).enabled).toBe(true)
|
||||
expect(
|
||||
required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5-chat-latest"))).enabled,
|
||||
required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5-chat-latest"))).enabled,
|
||||
).toBe(false)
|
||||
}),
|
||||
)
|
||||
|
|
@ -164,14 +164,14 @@ describe("OpenAIPlugin", () => {
|
|||
const catalog = yield* Catalog.Service
|
||||
const credentials = yield* Credential.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const item = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.openai),
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai"),
|
||||
const item = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.openai),
|
||||
package: Provider.aisdk("@ai-sdk/openai"),
|
||||
})
|
||||
catalog.provider.update(item.id, (draft) => {
|
||||
draft.package = item.package
|
||||
})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5.5"), (model) => {
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5.5"), (model) => {
|
||||
model.cost = [
|
||||
{
|
||||
input: Money.USDPerMillionTokens.make(1),
|
||||
|
|
@ -183,14 +183,14 @@ describe("OpenAIPlugin", () => {
|
|||
},
|
||||
]
|
||||
})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5.5-pro"), () => {})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5.4-pro"), (model) => {
|
||||
model.modelID = ModelV2.ID.make("gpt-5.4")
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5.5-pro"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5.4-pro"), (model) => {
|
||||
model.modelID = Model.ID.make("gpt-5.4")
|
||||
model.body = { reasoning: { mode: "pro" } }
|
||||
})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5.6"), () => {})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5.6-sol"), () => {})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-4.1"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5.6"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5.6-sol"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-4.1"), () => {})
|
||||
})
|
||||
yield* credentials.create({
|
||||
integrationID: Integration.ID.make("openai"),
|
||||
|
|
@ -205,20 +205,20 @@ describe("OpenAIPlugin", () => {
|
|||
})
|
||||
yield* addPlugin()
|
||||
|
||||
const eligible = required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5.5")))
|
||||
const eligible = required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.5")))
|
||||
expect(eligible.cost).toEqual([])
|
||||
expect(eligible.enabled).toBe(true)
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5.5-pro"))).enabled).toBe(
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.5-pro"))).enabled).toBe(
|
||||
false,
|
||||
)
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5.4-pro"))).enabled).toBe(
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.4-pro"))).enabled).toBe(
|
||||
false,
|
||||
)
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5.6"))).enabled).toBe(false)
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5.6-sol"))).enabled).toBe(
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.6"))).enabled).toBe(false)
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.6-sol"))).enabled).toBe(
|
||||
true,
|
||||
)
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-4.1"))).enabled).toBe(false)
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-4.1"))).enabled).toBe(false)
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -227,15 +227,15 @@ describe("OpenAIPlugin", () => {
|
|||
const catalog = yield* Catalog.Service
|
||||
const credentials = yield* Credential.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const item = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.openai),
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai"),
|
||||
const item = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.openai),
|
||||
package: Provider.aisdk("@ai-sdk/openai"),
|
||||
})
|
||||
catalog.provider.update(item.id, (draft) => {
|
||||
draft.package = item.package
|
||||
})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5.5"), () => {})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-4.1"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5.5"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-4.1"), () => {})
|
||||
})
|
||||
yield* credentials.create({
|
||||
integrationID: Integration.ID.make("openai"),
|
||||
|
|
@ -243,8 +243,8 @@ describe("OpenAIPlugin", () => {
|
|||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5.5"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-4.1"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.5"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-4.1"))).enabled).toBe(true)
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -252,18 +252,18 @@ describe("OpenAIPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const item = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.make("custom-openai")),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const item = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.make("custom-openai")),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
})
|
||||
catalog.provider.update(item.id, (draft) => {
|
||||
draft.package = item.package
|
||||
})
|
||||
catalog.model.update(item.id, ModelV2.ID.make("gpt-5-chat-latest"), () => {})
|
||||
catalog.model.update(item.id, Model.ID.make("gpt-5-chat-latest"), () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(
|
||||
required(yield* catalog.model.get(ProviderV2.ID.make("custom-openai"), ModelV2.ID.make("gpt-5-chat-latest")))
|
||||
required(yield* catalog.model.get(Provider.ID.make("custom-openai"), Model.ID.make("gpt-5-chat-latest")))
|
||||
.enabled,
|
||||
).toBe(true)
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -3,25 +3,25 @@ import { Money } from "@opencode-ai/schema/money"
|
|||
import { Effect } from "effect"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { Credential } from "@opencode-ai/core/credential"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { OpencodePlugin } from "@opencode-ai/core/plugin/provider/opencode"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const events = yield* EventV2.Service
|
||||
const bus = yield* Bus.Service
|
||||
const integration = yield* Integration.Service
|
||||
yield* OpencodePlugin.effect(host).pipe(
|
||||
Effect.provideService(EventV2.Service, events),
|
||||
Effect.provideService(Bus.Service, bus),
|
||||
Effect.provideService(Integration.Service, integration),
|
||||
)
|
||||
})
|
||||
|
|
@ -215,18 +215,18 @@ describe("OpencodePlugin", () => {
|
|||
const credentials = yield* Credential.Service
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((draft) => {
|
||||
draft.provider.update(ProviderV2.ID.make("remote"), () => {})
|
||||
draft.model.update(ProviderV2.ID.make("remote"), ModelV2.ID.make("model"), (model) => {
|
||||
draft.provider.update(Provider.ID.make("remote"), () => {})
|
||||
draft.model.update(Provider.ID.make("remote"), Model.ID.make("model"), (model) => {
|
||||
model.variants = [
|
||||
{
|
||||
id: ModelV2.VariantID.make("custom"),
|
||||
id: Model.VariantID.make("custom"),
|
||||
settings: {},
|
||||
headers: { "x-custom": "true" },
|
||||
body: { custom: true },
|
||||
},
|
||||
]
|
||||
})
|
||||
draft.model.update(ProviderV2.ID.make("remote"), ModelV2.ID.make("stale"), () => {})
|
||||
draft.model.update(Provider.ID.make("remote"), Model.ID.make("stale"), () => {})
|
||||
})
|
||||
yield* credentials.create({
|
||||
integrationID: Integration.ID.make("opencode"),
|
||||
|
|
@ -240,44 +240,44 @@ describe("OpencodePlugin", () => {
|
|||
yield* addPlugin()
|
||||
expect(authorization).toEqual(["Bearer secret"])
|
||||
|
||||
const provider = required(yield* catalog.provider.get(ProviderV2.ID.make("remote")))
|
||||
const provider = required(yield* catalog.provider.get(Provider.ID.make("remote")))
|
||||
expect(provider).toMatchObject({
|
||||
name: "Remote",
|
||||
integrationID: "opencode",
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai-compatible"),
|
||||
package: Provider.aisdk("@ai-sdk/openai-compatible"),
|
||||
settings: { baseURL: `${server.url.origin}/v1`, custom: "value" },
|
||||
headers: { "x-org-id": "org" },
|
||||
})
|
||||
expect(yield* (yield* Integration.Service).get(Integration.ID.make("remote"))).toBeUndefined()
|
||||
|
||||
const model = required(yield* catalog.model.get(ProviderV2.ID.make("remote"), ModelV2.ID.make("model")))
|
||||
const model = required(yield* catalog.model.get(Provider.ID.make("remote"), Model.ID.make("model")))
|
||||
expect(model).toMatchObject({
|
||||
name: "Remote Model",
|
||||
family: "remote",
|
||||
capabilities: { tools: true, input: ["text", "image"], output: ["text"] },
|
||||
cost: [{ input: 1, output: 2, cache: { read: 0.1, write: 0 } }],
|
||||
limit: { context: 1000, output: 100 },
|
||||
package: ProviderV2.aisdk("@ai-sdk/openai-compatible"),
|
||||
package: Provider.aisdk("@ai-sdk/openai-compatible"),
|
||||
settings: { baseURL: `${server.url.origin}/v1`, custom: "value", temperature: 0.5 },
|
||||
headers: { "x-org-id": "org" },
|
||||
})
|
||||
expect(model.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("custom"),
|
||||
id: Model.VariantID.make("custom"),
|
||||
settings: {},
|
||||
headers: { "x-custom": "true" },
|
||||
body: { custom: true },
|
||||
},
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
id: Model.VariantID.make("high"),
|
||||
settings: { temperature: 0.2 },
|
||||
headers: {},
|
||||
},
|
||||
])
|
||||
expect(
|
||||
required(yield* catalog.model.get(ProviderV2.ID.make("remote"), ModelV2.ID.make("disabled"))).enabled,
|
||||
required(yield* catalog.model.get(Provider.ID.make("remote"), Model.ID.make("disabled"))).enabled,
|
||||
).toBe(false)
|
||||
expect(yield* catalog.model.get(ProviderV2.ID.make("remote"), ModelV2.ID.make("stale"))).toBeDefined()
|
||||
expect(yield* catalog.model.get(Provider.ID.make("remote"), Model.ID.make("stale"))).toBeDefined()
|
||||
}),
|
||||
({ server }) => Effect.promise(() => server.stop(true)),
|
||||
),
|
||||
|
|
@ -288,14 +288,14 @@ describe("OpencodePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const provider = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const provider = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.opencode),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
})
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(provider.id, ModelV2.ID.make("paid")),
|
||||
modelID: ModelV2.ID.make("paid"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(provider.id, Model.ID.make("paid")),
|
||||
modelID: Model.ID.make("paid"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
cost: cost(1),
|
||||
})
|
||||
catalog.provider.update(provider.id, () => {})
|
||||
|
|
@ -304,8 +304,8 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.opencode)).settings?.apiKey).toBe("public")
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(false)
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.opencode)).settings?.apiKey).toBe("public")
|
||||
expect(required(yield* catalog.model.get(Provider.ID.opencode, Model.ID.make("paid"))).enabled).toBe(false)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -315,14 +315,14 @@ describe("OpencodePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const provider = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const provider = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.opencode),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
})
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(provider.id, ModelV2.ID.make("free")),
|
||||
modelID: ModelV2.ID.make("free"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(provider.id, Model.ID.make("free")),
|
||||
modelID: Model.ID.make("free"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
cost: cost(0),
|
||||
})
|
||||
catalog.provider.update(provider.id, () => {})
|
||||
|
|
@ -331,8 +331,8 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.opencode)).settings?.apiKey).toBe("public")
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("free"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.opencode)).settings?.apiKey).toBe("public")
|
||||
expect(required(yield* catalog.model.get(Provider.ID.opencode, Model.ID.make("free"))).enabled).toBe(true)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -342,14 +342,14 @@ describe("OpencodePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const provider = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const provider = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.opencode),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
})
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(provider.id, ModelV2.ID.make("output-only")),
|
||||
modelID: ModelV2.ID.make("output-only"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(provider.id, Model.ID.make("output-only")),
|
||||
modelID: Model.ID.make("output-only"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
cost: cost(0, 1),
|
||||
})
|
||||
catalog.provider.update(provider.id, () => {})
|
||||
|
|
@ -358,8 +358,8 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.opencode)).settings?.apiKey).toBe("public")
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("output-only"))).enabled).toBe(
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.opencode)).settings?.apiKey).toBe("public")
|
||||
expect(required(yield* catalog.model.get(Provider.ID.opencode, Model.ID.make("output-only"))).enabled).toBe(
|
||||
true,
|
||||
)
|
||||
}),
|
||||
|
|
@ -371,14 +371,14 @@ describe("OpencodePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const provider = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const provider = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.opencode),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
})
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(provider.id, ModelV2.ID.make("paid")),
|
||||
modelID: ModelV2.ID.make("paid"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(provider.id, Model.ID.make("paid")),
|
||||
modelID: Model.ID.make("paid"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
cost: cost(1),
|
||||
})
|
||||
catalog.provider.update(provider.id, () => {})
|
||||
|
|
@ -387,8 +387,8 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.opencode)).settings?.apiKey).toBeUndefined()
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.opencode)).settings?.apiKey).toBeUndefined()
|
||||
expect(required(yield* catalog.model.get(Provider.ID.opencode, Model.ID.make("paid"))).enabled).toBe(true)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -405,14 +405,14 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* catalog.transform((catalog) => {
|
||||
const provider = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const provider = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.opencode),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
})
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(provider.id, ModelV2.ID.make("paid")),
|
||||
modelID: ModelV2.ID.make("paid"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(provider.id, Model.ID.make("paid")),
|
||||
modelID: Model.ID.make("paid"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
cost: cost(1),
|
||||
})
|
||||
catalog.provider.update(provider.id, () => {})
|
||||
|
|
@ -421,8 +421,8 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.opencode)).settings?.apiKey).toBeUndefined()
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.opencode)).settings?.apiKey).toBeUndefined()
|
||||
expect(required(yield* catalog.model.get(Provider.ID.opencode, Model.ID.make("paid"))).enabled).toBe(true)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -432,15 +432,15 @@ describe("OpencodePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const provider = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const provider = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.opencode),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
settings: { apiKey: "configured" },
|
||||
})
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(provider.id, ModelV2.ID.make("paid")),
|
||||
modelID: ModelV2.ID.make("paid"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(provider.id, Model.ID.make("paid")),
|
||||
modelID: Model.ID.make("paid"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
cost: cost(1),
|
||||
})
|
||||
catalog.provider.update(provider.id, (draft) => {
|
||||
|
|
@ -452,8 +452,8 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.opencode)).settings?.apiKey).toBe("configured")
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.opencode)).settings?.apiKey).toBe("configured")
|
||||
expect(required(yield* catalog.model.get(Provider.ID.opencode, Model.ID.make("paid"))).enabled).toBe(true)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -463,14 +463,14 @@ describe("OpencodePlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
const provider = ProviderV2.Info.make({
|
||||
...ProviderV2.Info.empty(ProviderV2.ID.openai),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const provider = Provider.Info.make({
|
||||
...Provider.Info.empty(Provider.ID.openai),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
})
|
||||
const model = ModelV2.Info.make({
|
||||
...ModelV2.Info.default(provider.id, ModelV2.ID.make("paid")),
|
||||
modelID: ModelV2.ID.make("paid"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
const model = Model.Info.make({
|
||||
...Model.Info.default(provider.id, Model.ID.make("paid")),
|
||||
modelID: Model.ID.make("paid"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
cost: cost(1),
|
||||
})
|
||||
catalog.provider.update(provider.id, () => {})
|
||||
|
|
@ -479,8 +479,8 @@ describe("OpencodePlugin", () => {
|
|||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.openai)).settings?.apiKey).toBeUndefined()
|
||||
expect(required(yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("paid"))).enabled).toBe(true)
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.openai)).settings?.apiKey).toBeUndefined()
|
||||
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("paid"))).enabled).toBe(true)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -488,17 +488,17 @@ describe("OpencodePlugin", () => {
|
|||
it.effect("prefers gpt-5-nano as the opencode small model", () =>
|
||||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
const providerID = ProviderV2.ID.opencode
|
||||
const providerID = Provider.ID.opencode
|
||||
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(providerID, () => {})
|
||||
catalog.model.update(providerID, ModelV2.ID.make("cheap-mini"), (model) => {
|
||||
catalog.model.update(providerID, Model.ID.make("cheap-mini"), (model) => {
|
||||
model.capabilities.input = ["text"]
|
||||
model.capabilities.output = ["text"]
|
||||
model.cost = [...cost(1, 1)]
|
||||
model.time.released = Date.now()
|
||||
})
|
||||
catalog.model.update(providerID, ModelV2.ID.make("gpt-5-nano"), (model) => {
|
||||
catalog.model.update(providerID, Model.ID.make("gpt-5-nano"), (model) => {
|
||||
model.capabilities.input = ["text"]
|
||||
model.capabilities.output = ["text"]
|
||||
model.cost = [...cost(10, 10)]
|
||||
|
|
@ -508,7 +508,7 @@ describe("OpencodePlugin", () => {
|
|||
|
||||
const selected = yield* catalog.model.small(providerID)
|
||||
|
||||
expect(selected?.id).toBe(ModelV2.ID.make("gpt-5-nano"))
|
||||
expect(selected?.id).toBe(Model.ID.make("gpt-5-nano"))
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,19 +2,19 @@ import { AISDK } from "@opencode-ai/core/aisdk"
|
|||
import { describe, expect } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { ProviderPlugins } from "@opencode-ai/core/plugin/provider"
|
||||
import { OpenRouterPlugin } from "@opencode-ai/core/plugin/provider/openrouter"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* OpenRouterPlugin.effect(host)
|
||||
|
|
@ -29,34 +29,34 @@ describe("OpenRouterPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.openrouter, (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@openrouter/ai-sdk-provider")
|
||||
catalog.provider.update(Provider.ID.openrouter, (provider) => {
|
||||
provider.package = Provider.aisdk("@openrouter/ai-sdk-provider")
|
||||
provider.headers = { Existing: "value" }
|
||||
})
|
||||
catalog.provider.update(ProviderV2.ID.make("nvidia"), () => {})
|
||||
catalog.provider.update(Provider.ID.make("nvidia"), () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.openrouter))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.openrouter))?.headers).toEqual({
|
||||
Existing: "value",
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
})
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia")))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("nvidia")))?.headers).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("creates an SDK only for the OpenRouter package", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
|
||||
const ignored = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.openrouter, Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
options: { name: "openrouter" },
|
||||
|
|
@ -64,10 +64,10 @@ describe("OpenRouterPlugin", () => {
|
|||
expect(ignored.sdk).toBeUndefined()
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom"), ModelV2.ID.make("openai/gpt-5")),
|
||||
modelID: ModelV2.ID.make("openai/gpt-5"),
|
||||
package: ProviderV2.aisdk("test-provider"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom"), Model.ID.make("openai/gpt-5")),
|
||||
modelID: Model.ID.make("openai/gpt-5"),
|
||||
package: Provider.aisdk("test-provider"),
|
||||
}),
|
||||
package: "@openrouter/ai-sdk-provider",
|
||||
options: { name: "custom" },
|
||||
|
|
@ -80,21 +80,21 @@ describe("OpenRouterPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.openrouter, (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@openrouter/ai-sdk-provider")
|
||||
catalog.provider.update(Provider.ID.openrouter, (provider) => {
|
||||
provider.package = Provider.aisdk("@openrouter/ai-sdk-provider")
|
||||
})
|
||||
catalog.provider.update(ProviderV2.ID.openai, () => {})
|
||||
catalog.model.update(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5-chat"), () => {})
|
||||
catalog.model.update(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5"), () => {})
|
||||
catalog.model.update(ProviderV2.ID.openai, ModelV2.ID.make("openai/gpt-5-chat"), () => {})
|
||||
catalog.provider.update(Provider.ID.openai, () => {})
|
||||
catalog.model.update(Provider.ID.openrouter, Model.ID.make("openai/gpt-5-chat"), () => {})
|
||||
catalog.model.update(Provider.ID.openrouter, Model.ID.make("openai/gpt-5"), () => {})
|
||||
catalog.model.update(Provider.ID.openai, Model.ID.make("openai/gpt-5-chat"), () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect((yield* catalog.model.get(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5-chat")))?.enabled).toBe(
|
||||
expect((yield* catalog.model.get(Provider.ID.openrouter, Model.ID.make("openai/gpt-5-chat")))?.enabled).toBe(
|
||||
false,
|
||||
)
|
||||
expect((yield* catalog.model.get(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5")))?.enabled).toBe(true)
|
||||
expect((yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("openai/gpt-5-chat")))?.enabled).toBe(true)
|
||||
expect((yield* catalog.model.get(Provider.ID.openrouter, Model.ID.make("openai/gpt-5")))?.enabled).toBe(true)
|
||||
expect((yield* catalog.model.get(Provider.ID.openai, Model.ID.make("openai/gpt-5-chat")))?.enabled).toBe(true)
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -102,12 +102,12 @@ describe("OpenRouterPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("custom-openrouter"), () => {})
|
||||
catalog.model.update(ProviderV2.ID.make("custom-openrouter"), ModelV2.ID.make("gpt-5-chat-latest"), () => {})
|
||||
catalog.provider.update(Provider.ID.make("custom-openrouter"), () => {})
|
||||
catalog.model.update(Provider.ID.make("custom-openrouter"), Model.ID.make("gpt-5-chat-latest"), () => {})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect(
|
||||
(yield* catalog.model.get(ProviderV2.ID.make("custom-openrouter"), ModelV2.ID.make("gpt-5-chat-latest")))
|
||||
(yield* catalog.model.get(Provider.ID.make("custom-openrouter"), Model.ID.make("gpt-5-chat-latest")))
|
||||
?.enabled,
|
||||
).toBe(true)
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { Npm } from "@opencode-ai/util/npm"
|
||||
import { SapAICorePlugin } from "@opencode-ai/core/plugin/provider/sap-ai-core"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "./fixture"
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ const npm = Npm.Service.of({
|
|||
})
|
||||
|
||||
const addPlugin = Effect.fn(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* SapAICorePlugin.effect(host).pipe(Effect.provideService(Npm.Service, npm))
|
||||
|
|
@ -47,10 +47,10 @@ function withEnv<A, E, R>(vars: Record<string, string | undefined>, effect: () =
|
|||
}
|
||||
|
||||
function model(providerID: string) {
|
||||
return ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make(providerID), ModelV2.ID.make("sap-model")),
|
||||
modelID: ModelV2.ID.make("sap-model"),
|
||||
package: ProviderV2.aisdk(fixtureProvider),
|
||||
return Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make(providerID), Model.ID.make("sap-model")),
|
||||
modelID: Model.ID.make("sap-model"),
|
||||
package: Provider.aisdk(fixtureProvider),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ describe("SapAICorePlugin", () => {
|
|||
{ AICORE_SERVICE_KEY: undefined, AICORE_DEPLOYMENT_ID: "deployment", AICORE_RESOURCE_GROUP: "resource-group" },
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const sdk = yield* aisdk.runSDK({
|
||||
|
|
@ -83,7 +83,7 @@ describe("SapAICorePlugin", () => {
|
|||
},
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const sdk = yield* aisdk.runSDK({
|
||||
|
|
@ -102,7 +102,7 @@ describe("SapAICorePlugin", () => {
|
|||
{ AICORE_SERVICE_KEY: undefined, AICORE_DEPLOYMENT_ID: "deployment", AICORE_RESOURCE_GROUP: "resource-group" },
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const sdk = yield* aisdk.runSDK({
|
||||
|
|
@ -118,7 +118,7 @@ describe("SapAICorePlugin", () => {
|
|||
|
||||
it.effect("uses the callable SDK for language selection", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const sdk = Object.assign((modelID: string) => ({ modelID, provider: "callable" }), {
|
||||
|
|
@ -136,7 +136,7 @@ describe("SapAICorePlugin", () => {
|
|||
{ AICORE_SERVICE_KEY: undefined, AICORE_DEPLOYMENT_ID: "deployment", AICORE_RESOURCE_GROUP: "resource-group" },
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const sdk = yield* aisdk.runSDK({
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
import { AISDK } from "@opencode-ai/core/aisdk"
|
||||
import { describe, expect, it as bun_it } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { SnowflakeCortexPlugin, cortexFetch } from "@opencode-ai/core/plugin/provider/snowflake-cortex"
|
||||
import { ProviderPlugins } from "@opencode-ai/core/plugin/provider"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* SnowflakeCortexPlugin.effect(host)
|
||||
|
|
@ -53,13 +53,13 @@ describe("SnowflakeCortexPlugin", () => {
|
|||
|
||||
it.effect("ignores non-snowflake-cortex providers", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("openai"), ModelV2.ID.make("gpt-4")),
|
||||
modelID: ModelV2.ID.make("gpt-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("openai"), Model.ID.make("gpt-4")),
|
||||
modelID: Model.ID.make("gpt-4"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai",
|
||||
|
|
@ -72,13 +72,13 @@ describe("SnowflakeCortexPlugin", () => {
|
|||
it.effect("creates SDK for snowflake-cortex using SNOWFLAKE_CORTEX_PAT env var", () =>
|
||||
withEnv({ SNOWFLAKE_CORTEX_PAT: "test-pat" }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("snowflake-cortex"), ModelV2.ID.make("claude-sonnet-4-6")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-6"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("snowflake-cortex"), Model.ID.make("claude-sonnet-4-6")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-6"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -92,13 +92,13 @@ describe("SnowflakeCortexPlugin", () => {
|
|||
it.effect("falls back to options.apiKey when SNOWFLAKE_CORTEX_PAT env var is absent", () =>
|
||||
withEnv({ SNOWFLAKE_CORTEX_PAT: undefined }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("snowflake-cortex"), ModelV2.ID.make("claude-sonnet-4-6")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-6"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("snowflake-cortex"), Model.ID.make("claude-sonnet-4-6")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-6"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -116,13 +116,13 @@ describe("SnowflakeCortexPlugin", () => {
|
|||
it.effect("uses SNOWFLAKE_CORTEX_TOKEN env var", () =>
|
||||
withEnv({ SNOWFLAKE_CORTEX_TOKEN: "oauth-token", SNOWFLAKE_CORTEX_PAT: undefined }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("snowflake-cortex"), ModelV2.ID.make("claude-sonnet-4-6")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-6"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("snowflake-cortex"), Model.ID.make("claude-sonnet-4-6")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-6"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -136,13 +136,13 @@ describe("SnowflakeCortexPlugin", () => {
|
|||
it.effect("falls back to options.token when no Snowflake env token is set", () =>
|
||||
withEnv({ SNOWFLAKE_CORTEX_TOKEN: undefined, SNOWFLAKE_CORTEX_PAT: undefined }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("snowflake-cortex"), ModelV2.ID.make("claude-sonnet-4-6")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-6"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("snowflake-cortex"), Model.ID.make("claude-sonnet-4-6")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-6"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -160,13 +160,13 @@ describe("SnowflakeCortexPlugin", () => {
|
|||
it.effect("sets includeUsage on the SDK options", () =>
|
||||
withEnv({ SNOWFLAKE_CORTEX_PAT: "test-pat" }, () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("snowflake-cortex"), ModelV2.ID.make("claude-sonnet-4-6")),
|
||||
modelID: ModelV2.ID.make("claude-sonnet-4-6"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("snowflake-cortex"), Model.ID.make("claude-sonnet-4-6")),
|
||||
modelID: Model.ID.make("claude-sonnet-4-6"),
|
||||
package: "aisdk:test-provider",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
|
|||
|
|
@ -2,18 +2,18 @@ import { AISDK } from "@opencode-ai/core/aisdk"
|
|||
import { describe, expect } from "bun:test"
|
||||
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 { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { VercelPlugin } from "@opencode-ai/core/plugin/provider/vercel"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* VercelPlugin.effect(host)
|
||||
|
|
@ -24,13 +24,13 @@ describe("VercelPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("vercel"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/vercel")
|
||||
catalog.provider.update(Provider.ID.make("vercel"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/vercel")
|
||||
provider.headers = { ...provider.headers, Existing: "1" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("vercel")))?.headers).toEqual({
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("vercel")))?.headers).toEqual({
|
||||
Existing: "1",
|
||||
"http-referer": "https://opencode.ai/",
|
||||
"x-title": "opencode",
|
||||
|
|
@ -42,25 +42,25 @@ describe("VercelPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) =>
|
||||
catalog.provider.update(ProviderV2.ID.make("vercel"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/vercel")
|
||||
catalog.provider.update(Provider.ID.make("vercel"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/vercel")
|
||||
}),
|
||||
)
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("vercel")))?.headers).not.toHaveProperty("HTTP-Referer")
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("vercel")))?.headers).not.toHaveProperty("X-Title")
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("vercel")))?.headers).not.toHaveProperty("HTTP-Referer")
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("vercel")))?.headers).not.toHaveProperty("X-Title")
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("creates @ai-sdk/vercel SDKs for custom provider IDs", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* addPlugin()
|
||||
const event = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-vercel"), ModelV2.ID.make("v0-1.0-md")),
|
||||
modelID: ModelV2.ID.make("v0-1.0-md"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-vercel"), Model.ID.make("v0-1.0-md")),
|
||||
modelID: Model.ID.make("v0-1.0-md"),
|
||||
package: "aisdk:@ai-sdk/vercel",
|
||||
}),
|
||||
package: "@ai-sdk/vercel",
|
||||
|
|
@ -74,9 +74,9 @@ describe("VercelPlugin", () => {
|
|||
it.effect("ignores non-Vercel providers", () =>
|
||||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => catalog.provider.update(ProviderV2.ID.make("gateway"), () => {}))
|
||||
yield* catalog.transform((catalog) => catalog.provider.update(Provider.ID.make("gateway"), () => {}))
|
||||
yield* addPlugin()
|
||||
expect((yield* catalog.provider.get(ProviderV2.ID.make("gateway")))?.headers).toBeUndefined()
|
||||
expect((yield* catalog.provider.get(Provider.ID.make("gateway")))?.headers).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ import type { LanguageModelV3 } from "@ai-sdk/provider"
|
|||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { XAIPlugin } from "@opencode-ai/core/plugin/provider/xai"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* XAIPlugin.effect(host)
|
||||
})
|
||||
|
|
@ -61,9 +61,9 @@ describe("XAIPlugin", () => {
|
|||
yield* addPlugin()
|
||||
|
||||
const ignored = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("xai"), ModelV2.ID.make("grok-4")),
|
||||
modelID: ModelV2.ID.make("grok-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("xai"), Model.ID.make("grok-4")),
|
||||
modelID: Model.ID.make("grok-4"),
|
||||
package: "aisdk:@ai-sdk/xai",
|
||||
}),
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
|
|
@ -71,9 +71,9 @@ describe("XAIPlugin", () => {
|
|||
})
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("xai"), ModelV2.ID.make("grok-4")),
|
||||
modelID: ModelV2.ID.make("grok-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("xai"), Model.ID.make("grok-4")),
|
||||
modelID: Model.ID.make("grok-4"),
|
||||
package: "aisdk:@ai-sdk/xai",
|
||||
}),
|
||||
package: "@ai-sdk/xai",
|
||||
|
|
@ -91,9 +91,9 @@ describe("XAIPlugin", () => {
|
|||
yield* addPlugin()
|
||||
|
||||
const result = yield* aisdk.runSDK({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("custom-xai"), ModelV2.ID.make("grok-4")),
|
||||
modelID: ModelV2.ID.make("grok-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("custom-xai"), Model.ID.make("grok-4")),
|
||||
modelID: Model.ID.make("grok-4"),
|
||||
package: "aisdk:@ai-sdk/xai",
|
||||
}),
|
||||
package: "@ai-sdk/xai",
|
||||
|
|
@ -111,9 +111,9 @@ describe("XAIPlugin", () => {
|
|||
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.make("xai"), ModelV2.ID.make("alias")),
|
||||
modelID: ModelV2.ID.make("grok-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.make("xai"), Model.ID.make("alias")),
|
||||
modelID: Model.ID.make("grok-4"),
|
||||
package: "aisdk:@ai-sdk/xai",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
@ -132,9 +132,9 @@ describe("XAIPlugin", () => {
|
|||
|
||||
yield* addPlugin()
|
||||
const result = yield* aisdk.runLanguage({
|
||||
model: ModelV2.Info.make({
|
||||
...ModelV2.Info.default(ProviderV2.ID.openai, ModelV2.ID.make("grok-4")),
|
||||
modelID: ModelV2.ID.make("grok-4"),
|
||||
model: Model.Info.make({
|
||||
...Model.Info.default(Provider.ID.openai, Model.ID.make("grok-4")),
|
||||
modelID: Model.ID.make("grok-4"),
|
||||
package: "aisdk:@ai-sdk/xai",
|
||||
}),
|
||||
sdk: fakeSelectorSdk(calls),
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { ProviderPlugins } from "@opencode-ai/core/plugin/provider"
|
||||
import { ZenmuxPlugin } from "@opencode-ai/core/plugin/provider/zenmux"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } 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 plugin = yield* Plugin.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
yield* ZenmuxPlugin.effect(host)
|
||||
})
|
||||
|
|
@ -31,13 +31,13 @@ describe("ZenmuxPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("zenmux"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("zenmux"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { ...provider.settings, baseURL: "https://zenmux.ai/api/v1" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
const result = required(yield* catalog.provider.get(ProviderV2.ID.make("zenmux")))
|
||||
const result = required(yield* catalog.provider.get(Provider.ID.make("zenmux")))
|
||||
expect(result.headers).toEqual({ "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode" })
|
||||
expect(Object.keys(required(result.headers)).sort()).toEqual(["HTTP-Referer", "X-Title"])
|
||||
}),
|
||||
|
|
@ -47,15 +47,15 @@ describe("ZenmuxPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("zenmux"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("zenmux"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { ...provider.settings, baseURL: "https://zenmux.ai/api/v1" }
|
||||
provider.headers = { ...provider.headers, Existing: "value" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.make("zenmux"))).headers).toEqual({
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.make("zenmux"))).headers).toEqual({
|
||||
Existing: "value",
|
||||
"HTTP-Referer": "https://opencode.ai/",
|
||||
"X-Title": "opencode",
|
||||
|
|
@ -67,15 +67,15 @@ describe("ZenmuxPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.make("zenmux"), (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.make("zenmux"), (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
provider.settings = { ...provider.settings, baseURL: "https://zenmux.ai/api/v1" }
|
||||
provider.headers = { "HTTP-Referer": "https://example.com/", "X-Title": "custom-title" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.make("zenmux"))).headers).toEqual({
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.make("zenmux"))).headers).toEqual({
|
||||
"HTTP-Referer": "https://example.com/",
|
||||
"X-Title": "custom-title",
|
||||
})
|
||||
|
|
@ -86,13 +86,13 @@ describe("ZenmuxPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.openrouter, (provider) => {
|
||||
catalog.provider.update(Provider.ID.openrouter, (provider) => {
|
||||
provider.headers = { "HTTP-Referer": "https://example.com/", "X-Title": "custom-title" }
|
||||
})
|
||||
})
|
||||
yield* addPlugin()
|
||||
|
||||
expect(required(yield* catalog.provider.get(ProviderV2.ID.openrouter)).headers).toEqual({
|
||||
expect(required(yield* catalog.provider.get(Provider.ID.openrouter)).headers).toEqual({
|
||||
"HTTP-Referer": "https://example.com/",
|
||||
"X-Title": "custom-title",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@ import { Location } from "@opencode-ai/core/location"
|
|||
import { Effect } from "effect"
|
||||
import { SkillPlugin } from "@opencode-ai/core/plugin/skill"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { SkillV2 } from "@opencode-ai/core/skill"
|
||||
import { Skill } from "@opencode-ai/core/skill"
|
||||
import { location } from "../fixture/location"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { host } from "./host"
|
||||
|
||||
const it = testEffect(AppNodeBuilder.build(SkillV2.node))
|
||||
const it = testEffect(AppNodeBuilder.build(Skill.node))
|
||||
|
||||
describe("SkillPlugin.Plugin", () => {
|
||||
it.effect("registers built-in skills", () =>
|
||||
Effect.gen(function* () {
|
||||
const skill = yield* SkillV2.Service
|
||||
const skill = yield* Skill.Service
|
||||
yield* SkillPlugin.Plugin.effect(
|
||||
host({
|
||||
app: { name: "test", version: "1.2.3", channel: "beta" },
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { SystemPart } from "@opencode-ai/ai"
|
||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { Plugin } from "@opencode-ai/core/plugin"
|
||||
import { PluginHooks } from "@opencode-ai/core/plugin/hooks"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { SystemPromptPlugin } from "@opencode-ai/core/plugin/system-prompt"
|
||||
import { SessionV2 } from "@opencode-ai/core/session"
|
||||
import type { SessionHooks } from "@opencode-ai/plugin/v2/effect/session"
|
||||
import { Session } from "@opencode-ai/core/session"
|
||||
import type { SessionHooks } from "@opencode-ai/plugin/effect/session"
|
||||
import { Model } from "@opencode-ai/schema/model"
|
||||
import { Provider } from "@opencode-ai/schema/provider"
|
||||
import { Effect } from "effect"
|
||||
|
|
@ -19,13 +19,15 @@ import PROMPT_DEFAULT from "../../src/session/runner/prompt/base.txt"
|
|||
const it = testEffect(PluginTestLayer)
|
||||
const fallback = PROMPT_DEFAULT
|
||||
const makeHost = Effect.gen(function* () {
|
||||
const plugins = yield* PluginV2.Service
|
||||
const agents = yield* Agent.Service
|
||||
const plugins = yield* Plugin.Service
|
||||
yield* agents.transform((draft) => draft.update(Agent.ID.make("build"), () => {}))
|
||||
return yield* PluginHost.make(plugins)
|
||||
})
|
||||
|
||||
const context = (id: string, system = fallback): SessionHooks["context"] => ({
|
||||
sessionID: SessionV2.ID.make("ses_system_prompt"),
|
||||
agent: AgentV2.ID.make("build"),
|
||||
sessionID: Session.ID.make("ses_system_prompt"),
|
||||
agent: Agent.ID.make("build"),
|
||||
model: Model.Ref.make({ providerID: Provider.ID.make("test"), id: Model.ID.make(id) }),
|
||||
system: [SystemPart.make(system)],
|
||||
messages: [],
|
||||
|
|
@ -33,7 +35,7 @@ const context = (id: string, system = fallback): SessionHooks["context"] => ({
|
|||
})
|
||||
|
||||
describe("SystemPromptPlugin", () => {
|
||||
test("uses V2 vocabulary in the Meta prompt", () => {
|
||||
test("uses current vocabulary in the Meta prompt", () => {
|
||||
expect(PROMPT_META).toContain("webfetch tool")
|
||||
expect(PROMPT_META).toContain("subagent tool")
|
||||
expect(PROMPT_META).toContain("shell tool")
|
||||
|
|
@ -92,10 +94,10 @@ describe("SystemPromptPlugin", () => {
|
|||
|
||||
it.effect("preserves an explicit agent system prompt", () =>
|
||||
Effect.gen(function* () {
|
||||
const agents = yield* AgentV2.Service
|
||||
const agents = yield* Agent.Service
|
||||
const hooks = yield* PluginHooks.Service
|
||||
yield* agents.transform((draft) =>
|
||||
draft.update(AgentV2.ID.make("build"), (agent) => {
|
||||
draft.update(Agent.ID.make("build"), (agent) => {
|
||||
agent.system = "Custom agent prompt"
|
||||
}),
|
||||
)
|
||||
|
|
@ -111,6 +113,21 @@ describe("SystemPromptPlugin", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("skips the hook when agent lookup fails", () =>
|
||||
Effect.gen(function* () {
|
||||
const agents = yield* Agent.Service
|
||||
const hooks = yield* PluginHooks.Service
|
||||
const pluginHost = yield* makeHost
|
||||
yield* SystemPromptPlugin.OpenAIPlugin.effect(pluginHost)
|
||||
yield* agents.transform((draft) => draft.remove(Agent.ID.make("build")))
|
||||
const event = context("gpt-5")
|
||||
|
||||
yield* hooks.trigger("session", "context", event)
|
||||
|
||||
expect(event.system[0]?.text).toBe(fallback)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("allows one model-lab prompt plugin to be enabled independently", () =>
|
||||
Effect.gen(function* () {
|
||||
const hooks = yield* PluginHooks.Service
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { Catalog } from "@opencode-ai/core/catalog"
|
|||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
import { VariantPlugin } from "@opencode-ai/core/plugin/variant"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Provider } from "@opencode-ai/core/provider"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { location } from "../fixture/location"
|
||||
|
|
@ -23,17 +23,17 @@ describe("VariantPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const service = yield* Catalog.Service
|
||||
yield* service.transform((catalog) => {
|
||||
catalog.provider.update(ProviderV2.ID.opencode, (provider) => {
|
||||
provider.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.provider.update(Provider.ID.opencode, (provider) => {
|
||||
provider.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
})
|
||||
catalog.model.update(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2"), (model) => {
|
||||
model.modelID = ModelV2.ID.make("glm-5.2")
|
||||
model.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
catalog.model.update(Provider.ID.opencode, Model.ID.make("glm-5.2"), (model) => {
|
||||
model.modelID = Model.ID.make("glm-5.2")
|
||||
model.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
})
|
||||
})
|
||||
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
|
||||
|
||||
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
|
||||
expect((yield* service.model.get(Provider.ID.opencode, Model.ID.make("glm-5.2")))?.variants).toEqual([
|
||||
expect.objectContaining({ id: "high", settings: { reasoningEffort: "high" } }),
|
||||
expect.objectContaining({ id: "max", settings: { reasoningEffort: "max" } }),
|
||||
])
|
||||
|
|
@ -44,15 +44,15 @@ describe("VariantPlugin", () => {
|
|||
Effect.gen(function* () {
|
||||
const service = yield* Catalog.Service
|
||||
yield* service.transform((catalog) => {
|
||||
catalog.model.update(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2"), (model) => {
|
||||
model.modelID = ModelV2.ID.make("glm-5.2")
|
||||
model.package = ProviderV2.aisdk("@ai-sdk/openai-compatible")
|
||||
model.variants = [{ id: ModelV2.VariantID.make("high"), settings: {}, headers: { custom: "true" }, body: {} }]
|
||||
catalog.model.update(Provider.ID.opencode, Model.ID.make("glm-5.2"), (model) => {
|
||||
model.modelID = Model.ID.make("glm-5.2")
|
||||
model.package = Provider.aisdk("@ai-sdk/openai-compatible")
|
||||
model.variants = [{ id: Model.VariantID.make("high"), settings: {}, headers: { custom: "true" }, body: {} }]
|
||||
})
|
||||
})
|
||||
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
|
||||
|
||||
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
|
||||
expect((yield* service.model.get(Provider.ID.opencode, Model.ID.make("glm-5.2")))?.variants).toEqual([
|
||||
expect.objectContaining({ id: "high", headers: { custom: "true" } }),
|
||||
expect.objectContaining({ id: "max", settings: { reasoningEffort: "max" } }),
|
||||
])
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
|||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { Credential } from "@opencode-ai/core/credential"
|
||||
import { Config } from "@opencode-ai/core/config"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
import { Form } from "@opencode-ai/core/form"
|
||||
import { Integration } from "@opencode-ai/core/integration"
|
||||
import { WebSearch } from "@opencode-ai/core/websearch"
|
||||
|
|
@ -42,7 +42,7 @@ const http = Layer.succeed(
|
|||
export const webSearchIntegrationTest = testEffect(
|
||||
Layer.merge(
|
||||
AppNodeBuilder.build(
|
||||
LayerNode.group([Integration.node, Credential.node, EventV2.node, Form.node, WebSearch.node]),
|
||||
LayerNode.group([Integration.node, Credential.node, Bus.node, Form.node, WebSearch.node]),
|
||||
[[Config.node, Layer.succeed(Config.Service, Config.Service.of({ entries: () => Effect.succeed([]) }))]],
|
||||
),
|
||||
http,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue