From 3d5892cd74a187a945f65e2ba8461144e14a8f1c Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 27 Aug 2026 15:18:13 -0400 Subject: [PATCH 1/2] test(core): simplify provider smoke tests --- .../convert-to-copilot-messages.test.ts | 38 +++++++++---------- .../core/test/plugin/provider-dynamic.test.ts | 2 - .../core/test/plugin/provider-kilo.test.ts | 8 ++-- .../test/plugin/provider-llmgateway.test.ts | 11 +++--- .../core/test/plugin/provider-nvidia.test.ts | 8 ++-- .../test/plugin/provider-openrouter.test.ts | 8 ++-- .../core/test/plugin/provider-vercel.test.ts | 2 - .../core/test/plugin/provider-zenmux.test.ts | 8 ++-- 8 files changed, 40 insertions(+), 45 deletions(-) diff --git a/packages/core/test/github-copilot/convert-to-copilot-messages.test.ts b/packages/core/test/github-copilot/convert-to-copilot-messages.test.ts index 65f4b6a5369c..2654810441d8 100644 --- a/packages/core/test/github-copilot/convert-to-copilot-messages.test.ts +++ b/packages/core/test/github-copilot/convert-to-copilot-messages.test.ts @@ -1,9 +1,9 @@ -import { convertToOpenAICompatibleChatMessages as convertToCopilotMessages } from "@opencode-ai/core/github-copilot/chat/convert-to-openai-compatible-chat-messages" +import { convertToOpenAICompatibleChatMessages } from "@opencode-ai/core/github-copilot/chat/convert-to-openai-compatible-chat-messages" import { describe, test, expect } from "bun:test" describe("system messages", () => { test("should convert system message content to string", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "system", content: "You are a helpful assistant with AGENTS.md instructions.", @@ -21,7 +21,7 @@ describe("system messages", () => { describe("user messages", () => { test("should convert messages with only a text part to a string content", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "user", content: [{ type: "text", text: "Hello" }], @@ -32,7 +32,7 @@ describe("user messages", () => { }) test("should convert messages with image parts", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "user", content: [ @@ -61,7 +61,7 @@ describe("user messages", () => { }) test("should convert messages with image parts from Uint8Array", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "user", content: [ @@ -90,7 +90,7 @@ describe("user messages", () => { }) test("should handle URL-based images", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "user", content: [ @@ -117,7 +117,7 @@ describe("user messages", () => { }) test("should handle multiple text parts without flattening", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "user", content: [ @@ -141,7 +141,7 @@ describe("user messages", () => { describe("assistant messages", () => { test("should convert assistant text messages", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [{ type: "text", text: "Hello back!" }], @@ -160,7 +160,7 @@ describe("assistant messages", () => { }) test("should handle assistant message with null content when only tool calls", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -195,7 +195,7 @@ describe("assistant messages", () => { }) test("should concatenate multiple text parts", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -211,7 +211,7 @@ describe("assistant messages", () => { describe("tool calls", () => { test("should stringify arguments to tool calls", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -262,7 +262,7 @@ describe("tool calls", () => { }) test("should handle text output type in tool results", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "tool", content: [ @@ -286,7 +286,7 @@ describe("tool calls", () => { }) test("should handle multiple tool results as separate messages", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "tool", content: [ @@ -320,7 +320,7 @@ describe("tool calls", () => { }) test("should handle text plus multiple tool calls", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -373,7 +373,7 @@ describe("tool calls", () => { describe("reasoning (copilot-specific)", () => { test("should omit reasoning_text without reasoning_opaque", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -395,7 +395,7 @@ describe("reasoning (copilot-specific)", () => { }) test("should include reasoning_opaque from providerOptions", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -423,7 +423,7 @@ describe("reasoning (copilot-specific)", () => { }) test("should include reasoning_opaque from text part providerOptions", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -450,7 +450,7 @@ describe("reasoning (copilot-specific)", () => { }) test("should handle reasoning-only assistant message", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "assistant", content: [ @@ -479,7 +479,7 @@ describe("reasoning (copilot-specific)", () => { describe("full conversation", () => { test("should convert a multi-turn conversation with reasoning", () => { - const result = convertToCopilotMessages([ + const result = convertToOpenAICompatibleChatMessages([ { role: "system", content: "You are a helpful assistant.", diff --git a/packages/core/test/plugin/provider-dynamic.test.ts b/packages/core/test/plugin/provider-dynamic.test.ts index 731bda5abb8b..7b4d5d1cc18e 100644 --- a/packages/core/test/plugin/provider-dynamic.test.ts +++ b/packages/core/test/plugin/provider-dynamic.test.ts @@ -156,7 +156,6 @@ describe("DynamicProviderPlugin", () => { itWithAISDK.live("wraps missing provider factory exports as AISDK init errors", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service const tmp = yield* tempEntrypoint("export const notAProviderFactory = true\n") yield* addPlugin(npmEntrypoint(tmp.entrypoint)) @@ -176,7 +175,6 @@ describe("DynamicProviderPlugin", () => { itWithAISDK.effect("uses the model modelID for the default language model", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service yield* addPlugin() const language = yield* aisdk.language( diff --git a/packages/core/test/plugin/provider-kilo.test.ts b/packages/core/test/plugin/provider-kilo.test.ts index e45cf39a3bd7..6b9635da20fa 100644 --- a/packages/core/test/plugin/provider-kilo.test.ts +++ b/packages/core/test/plugin/provider-kilo.test.ts @@ -1,4 +1,4 @@ -import { describe, expect } from "bun:test" +import { describe, expect, test } from "bun:test" import { Effect } from "effect" import { Catalog } from "@opencode-ai/core/catalog" import { Plugin } from "@opencode-ai/core/plugin" @@ -18,9 +18,9 @@ const addPlugin = Effect.fn(function* () { }) describe("KiloPlugin", () => { - it.effect("is registered so legacy referer headers can be applied", () => - Effect.sync(() => expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.kilo")), - ) + test("is registered so legacy referer headers can be applied", () => { + expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.kilo") + }) it.effect("applies legacy referer headers only to Kilo endpoints", () => Effect.gen(function* () { diff --git a/packages/core/test/plugin/provider-llmgateway.test.ts b/packages/core/test/plugin/provider-llmgateway.test.ts index 8672db044a07..06cc4324a153 100644 --- a/packages/core/test/plugin/provider-llmgateway.test.ts +++ b/packages/core/test/plugin/provider-llmgateway.test.ts @@ -1,4 +1,4 @@ -import { describe, expect } from "bun:test" +import { describe, expect, test } from "bun:test" import { Effect } from "effect" import { Catalog } from "@opencode-ai/core/catalog" import { Integration } from "@opencode-ai/core/integration" @@ -15,14 +15,13 @@ const it = testEffect(PluginTestLayer) const addPlugin = Effect.fn(function* () { 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)) + yield* LLMGatewayPlugin.effect(host) }) describe("LLMGatewayPlugin", () => { - it.effect("is registered so legacy referer headers can be applied", () => - Effect.sync(() => expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.llmgateway")), - ) + test("is registered so legacy referer headers can be applied", () => { + expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.llmgateway") + }) it.effect("applies legacy referer headers only to enabled llmgateway", () => Effect.gen(function* () { diff --git a/packages/core/test/plugin/provider-nvidia.test.ts b/packages/core/test/plugin/provider-nvidia.test.ts index 278e4f99c144..23e5c185a74d 100644 --- a/packages/core/test/plugin/provider-nvidia.test.ts +++ b/packages/core/test/plugin/provider-nvidia.test.ts @@ -1,4 +1,4 @@ -import { describe, expect } from "bun:test" +import { describe, expect, test } from "bun:test" import { Effect } from "effect" import { Catalog } from "@opencode-ai/core/catalog" import { Plugin } from "@opencode-ai/core/plugin" @@ -18,9 +18,9 @@ const addPlugin = Effect.fn(function* () { }) describe("NvidiaPlugin", () => { - it.effect("is registered so legacy referer headers can be applied", () => - Effect.sync(() => expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.nvidia")), - ) + test("is registered so legacy referer headers can be applied", () => { + expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.nvidia") + }) it.effect("applies NVIDIA tracking headers only to nvidia", () => Effect.gen(function* () { diff --git a/packages/core/test/plugin/provider-openrouter.test.ts b/packages/core/test/plugin/provider-openrouter.test.ts index ce97f1b6a3ce..e93b2a9172bb 100644 --- a/packages/core/test/plugin/provider-openrouter.test.ts +++ b/packages/core/test/plugin/provider-openrouter.test.ts @@ -1,4 +1,4 @@ -import { describe, expect } from "bun:test" +import { describe, expect, test } from "bun:test" import { Effect } from "effect" import { Catalog } from "@opencode-ai/core/catalog" import { Model } from "@opencode-ai/core/model" @@ -19,9 +19,9 @@ const addPlugin = Effect.fn(function* () { }) describe("OpenRouterPlugin", () => { - it.effect("is registered so legacy OpenRouter behavior can be applied", () => - Effect.sync(() => expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.openrouter")), - ) + test("is registered so legacy OpenRouter behavior can be applied", () => { + expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.openrouter") + }) it.effect("applies legacy referer headers only to openrouter", () => Effect.gen(function* () { diff --git a/packages/core/test/plugin/provider-vercel.test.ts b/packages/core/test/plugin/provider-vercel.test.ts index bf4998ae7d30..e5cc83a4d7f8 100644 --- a/packages/core/test/plugin/provider-vercel.test.ts +++ b/packages/core/test/plugin/provider-vercel.test.ts @@ -14,7 +14,6 @@ const it = testEffect(PluginTestLayer) const addPlugin = Effect.fn(function* () { const plugin = yield* Plugin.Service - const aisdk = yield* AISDK.Service const host = yield* PluginHost.make(plugin) yield* VercelPlugin.effect(host) }) @@ -54,7 +53,6 @@ describe("VercelPlugin", () => { it.effect("creates @ai-sdk/vercel SDKs for custom provider IDs", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service yield* addPlugin() const event = yield* aisdk.runSDK({ diff --git a/packages/core/test/plugin/provider-zenmux.test.ts b/packages/core/test/plugin/provider-zenmux.test.ts index de599148dbc1..e88ceac88de0 100644 --- a/packages/core/test/plugin/provider-zenmux.test.ts +++ b/packages/core/test/plugin/provider-zenmux.test.ts @@ -1,4 +1,4 @@ -import { describe, expect } from "bun:test" +import { describe, expect, test } from "bun:test" import { Effect } from "effect" import { Catalog } from "@opencode-ai/core/catalog" import { Plugin } from "@opencode-ai/core/plugin" @@ -23,9 +23,9 @@ function required(value: T | undefined): T { } describe("ZenmuxPlugin", () => { - it.effect("is registered so legacy referer headers can be applied", () => - Effect.sync(() => expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.zenmux")), - ) + test("is registered so legacy referer headers can be applied", () => { + expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.zenmux") + }) it.effect("applies the exact legacy Zenmux headers", () => Effect.gen(function* () { From 16f3ebff6cf4115881b3915304392952a6155670 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 27 Aug 2026 15:46:26 -0400 Subject: [PATCH 2/2] test(core): simplify provider test bindings --- .../plugin/provider-github-copilot.test.ts | 20 ++++++++----------- .../test/plugin/provider-lmstudio.test.ts | 12 +++++------ .../core/test/plugin/provider-openai.test.ts | 6 +++--- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/packages/core/test/plugin/provider-github-copilot.test.ts b/packages/core/test/plugin/provider-github-copilot.test.ts index 2410dcd47196..3ea0ee35a7f8 100644 --- a/packages/core/test/plugin/provider-github-copilot.test.ts +++ b/packages/core/test/plugin/provider-github-copilot.test.ts @@ -21,7 +21,6 @@ const it = testEffect(PluginTestLayer) const addPlugin = Effect.fn(function* () { const plugin = yield* Plugin.Service - const aisdk = yield* AISDK.Service const host = yield* PluginHost.make(plugin) yield* GithubCopilotPlugin.effect(host) }) @@ -57,7 +56,8 @@ describe("GithubCopilotPlugin", () => { it.effect("registers GitHub Copilot device OAuth", () => Effect.gen(function* () { yield* addPlugin() - expect((yield* (yield* Integration.Service).get(Integration.ID.make("github-copilot")))?.methods).toContainEqual({ + const integrations = yield* Integration.Service + expect((yield* integrations.get(Integration.ID.make("github-copilot")))?.methods).toContainEqual({ id: Integration.MethodID.make("device"), type: "oauth", label: "Login with GitHub Copilot", @@ -124,7 +124,8 @@ describe("GithubCopilotPlugin", () => { it.effect("adds Copilot authentication to native Anthropic requests", () => Effect.gen(function* () { yield* addPlugin() - const event = yield* (yield* PluginHooks.Service).trigger("session", "http.request", { + const hooks = yield* PluginHooks.Service + const event = yield* hooks.trigger("session", "http.request", { sessionID: Session.ID.make("ses_test"), agent: Agent.ID.make("build"), model: Model.Ref.make({ providerID: Provider.ID.githubCopilot, id: Model.ID.make("claude-sonnet-4.5") }), @@ -145,7 +146,8 @@ describe("GithubCopilotPlugin", () => { it.effect("classifies title generation as a background interaction", () => Effect.gen(function* () { yield* addPlugin() - const event = yield* (yield* PluginHooks.Service).trigger("session", "http.request", { + const hooks = yield* PluginHooks.Service + const event = yield* hooks.trigger("session", "http.request", { sessionID: Session.ID.make("ses_title"), agent: Agent.ID.make("title"), model: Model.Ref.make({ providerID: Provider.ID.githubCopilot, id: Model.ID.make("gpt-5.4-nano") }), @@ -158,7 +160,8 @@ describe("GithubCopilotPlugin", () => { it.effect("classifies compaction requests", () => Effect.gen(function* () { yield* addPlugin() - const event = yield* (yield* PluginHooks.Service).trigger("session", "http.request", { + const hooks = yield* PluginHooks.Service + const event = yield* hooks.trigger("session", "http.request", { sessionID: Session.ID.make("ses_compaction"), agent: Agent.ID.make("compaction"), model: Model.Ref.make({ providerID: Provider.ID.githubCopilot, id: Model.ID.make("gpt-5.4") }), @@ -170,7 +173,6 @@ describe("GithubCopilotPlugin", () => { it.effect("creates the bundled Copilot SDK for the GitHub Copilot package", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service yield* addPlugin() const ignored = yield* aisdk.runSDK({ @@ -221,7 +223,6 @@ describe("GithubCopilotPlugin", () => { it.effect("selects languageModel when responses and chat are absent", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service const calls: string[] = [] yield* addPlugin() @@ -240,7 +241,6 @@ describe("GithubCopilotPlugin", () => { it.effect("selects languageModel with the API model ID when responses and chat are absent", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service const calls: string[] = [] yield* addPlugin() @@ -259,7 +259,6 @@ describe("GithubCopilotPlugin", () => { it.effect("uses responses for gpt-5 models except gpt-5-mini", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service const calls: string[] = [] yield* addPlugin() @@ -320,7 +319,6 @@ describe("GithubCopilotPlugin", () => { it.effect("uses advertised Copilot endpoint metadata before model ID fallbacks", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service const calls: string[] = [] yield* addPlugin() @@ -350,7 +348,6 @@ describe("GithubCopilotPlugin", () => { it.effect("uses the API model ID when selecting responses or chat", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service const calls: string[] = [] yield* addPlugin() @@ -417,7 +414,6 @@ describe("GithubCopilotPlugin", () => { it.effect("ignores non-Copilot providers", () => Effect.gen(function* () { - const plugin = yield* Plugin.Service const aisdk = yield* AISDK.Service const calls: string[] = [] yield* addPlugin() diff --git a/packages/core/test/plugin/provider-lmstudio.test.ts b/packages/core/test/plugin/provider-lmstudio.test.ts index e434b0899b30..38d1ef1a34c9 100644 --- a/packages/core/test/plugin/provider-lmstudio.test.ts +++ b/packages/core/test/plugin/provider-lmstudio.test.ts @@ -9,7 +9,7 @@ import { LMStudioPlugin, make } from "@opencode-ai/core/plugin/provider/lmstudio import { ProviderPlugins } from "@opencode-ai/core/plugin/provider" import { Provider } from "@opencode-ai/core/provider" import { Document, Event, Info } from "@opencode-ai/schema/config" -import { describe, expect } from "bun:test" +import { describe, expect, test } from "bun:test" import { Duration, Effect, Layer, Schema } from "effect" import { testEffect } from "../lib/effect" import { PluginTestLayer } from "./fixture" @@ -38,12 +38,10 @@ function eventually( } describe("LMStudioPlugin", () => { - it.effect("is registered as a built-in provider plugin", () => - Effect.sync(() => { - expect(LMStudioPlugin.id).toBe("opencode.provider.lmstudio") - expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.lmstudio") - }), - ) + test("is registered as a built-in provider plugin", () => { + expect(LMStudioPlugin.id).toBe("opencode.provider.lmstudio") + expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.lmstudio") + }) it.live("discovers local language models with their capabilities and effective context", () => Effect.acquireUseRelease( diff --git a/packages/core/test/plugin/provider-openai.test.ts b/packages/core/test/plugin/provider-openai.test.ts index 2e96b3f8a077..f69a84199a9a 100644 --- a/packages/core/test/plugin/provider-openai.test.ts +++ b/packages/core/test/plugin/provider-openai.test.ts @@ -28,8 +28,7 @@ const it = testEffect(PluginTestLayer) const addPlugin = Effect.fn(function* () { const plugin = yield* Plugin.Service const host = yield* PluginHost.make(plugin) - const integrations = yield* Integration.Service - yield* OpenAIPlugin.effect(host).pipe(Effect.provideService(Integration.Service, integrations)) + yield* OpenAIPlugin.effect(host) }) const addGithubCopilotPlugin = Effect.fn(function* () { @@ -65,7 +64,8 @@ describe("OpenAIPlugin", () => { it.effect("registers browser and headless ChatGPT OAuth methods", () => Effect.gen(function* () { yield* addPlugin() - expect((yield* (yield* Integration.Service).get(Integration.ID.make("openai")))?.methods).toEqual([ + const integrations = yield* Integration.Service + expect((yield* integrations.get(Integration.ID.make("openai")))?.methods).toEqual([ { id: Integration.MethodID.make("chatgpt-browser"), type: "oauth",