| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- import { beforeEach, describe, expect } from "bun:test"
- import { Effect } from "effect"
- import { Integration } from "@opencode-ai/core/integration"
- import { WebSearch } from "@opencode-ai/core/websearch"
- import { WebSearchExa } from "@opencode-ai/core/plugin/websearch/exa"
- import { WebSearchParallel } from "@opencode-ai/core/plugin/websearch/parallel"
- import { host, integrationHost, webSearchHost } from "./host"
- import { requests, resetWebSearchFixture, webSearchIntegrationTest } from "./websearch-fixture"
- beforeEach(() => {
- resetWebSearchFixture(
- `event: message\ndata: ${JSON.stringify({
- jsonrpc: "2.0",
- id: 1,
- result: {
- content: [
- {
- type: "text",
- text: "Title: Effect\nURL: https://effect.website\nPublished: 2026-07-25T00:00:00.000Z\nAuthor: N/A\nHighlights:\nEffect documentation",
- _meta: { searchTime: 123 },
- },
- ],
- },
- })}\n\n`,
- )
- })
- const it = webSearchIntegrationTest
- describe("built-in web search providers", () => {
- it.effect("registers a provider without an integration", () =>
- Effect.gen(function* () {
- const integrations = yield* Integration.Service
- const websearch = yield* WebSearch.Service
- const registration = yield* webSearchHost(websearch).transform((draft) => {
- draft.add({
- id: "test-websearch",
- name: "Test Web Search",
- execute: (input) => Effect.succeed([{ url: "https://example.com", content: input.query, time: {} }]),
- })
- })
- expect(yield* integrations.get(Integration.ID.make("test-websearch"))).toBeUndefined()
- expect(yield* websearch.providers()).toContainEqual({
- id: WebSearch.ID.make("test-websearch"),
- name: "Test Web Search",
- })
- yield* registration.dispose
- expect(yield* websearch.providers()).not.toContainEqual({
- id: WebSearch.ID.make("test-websearch"),
- name: "Test Web Search",
- })
- }),
- )
- it.effect("registers Exa with its MCP schema", () =>
- Effect.gen(function* () {
- const integrations = yield* Integration.Service
- const websearch = yield* WebSearch.Service
- yield* WebSearchExa.Plugin.effect(
- host({ integration: integrationHost(integrations), websearch: webSearchHost(websearch) }),
- )
- const info = yield* integrations.get(Integration.ID.make("exa"))
- expect(info).toMatchObject({
- id: "exa",
- name: "Exa",
- methods: [{ type: "key" }, { type: "env", names: ["EXA_API_KEY"] }],
- })
- yield* integrations.connection.key({ integrationID: Integration.ID.make("exa"), key: "exa secret" })
- expect(yield* websearch.query({ query: "effect typescript", providerID: WebSearch.ID.make("exa") })).toEqual(
- new WebSearch.Response({
- providerID: WebSearch.ID.make("exa"),
- results: [
- {
- url: "https://effect.website",
- title: "Effect",
- content: "Effect documentation",
- time: { published: Date.parse("2026-07-25T00:00:00.000Z") },
- },
- ],
- }),
- )
- expect(requests).toEqual([
- {
- url: `${WebSearchExa.endpoint}?exaApiKey=exa+secret`,
- headers: expect.any(Object),
- body: {
- jsonrpc: "2.0",
- id: 1,
- method: "tools/call",
- params: {
- name: "web_search_exa",
- arguments: { query: "effect typescript", numResults: 8 },
- },
- },
- },
- ])
- }),
- )
- it.effect("registers Parallel and keeps its credential in the authorization header", () =>
- Effect.gen(function* () {
- resetWebSearchFixture(
- JSON.stringify({
- jsonrpc: "2.0",
- id: 1,
- result: {
- content: [{ type: "text", text: "search results" }],
- structuredContent: {
- search_id: "search_1",
- results: [
- {
- url: "https://effect.website",
- title: "Effect",
- publish_date: null,
- excerpts: ["Effect documentation"],
- },
- ],
- warnings: null,
- usage: [{ name: "sku_search", count: 1 }],
- session_id: "ses_parallel",
- },
- },
- }),
- )
- const integrations = yield* Integration.Service
- const websearch = yield* WebSearch.Service
- yield* WebSearchParallel.Plugin.effect(
- host({ integration: integrationHost(integrations), websearch: webSearchHost(websearch) }),
- )
- yield* integrations.connection.key({ integrationID: Integration.ID.make("parallel"), key: "parallel-secret" })
- const output = yield* websearch.query({
- query: "effect layers",
- providerID: WebSearch.ID.make("parallel"),
- })
- expect(output).toEqual(
- new WebSearch.Response({
- providerID: WebSearch.ID.make("parallel"),
- results: [
- {
- url: "https://effect.website",
- title: "Effect",
- content: "Effect documentation",
- time: {},
- },
- ],
- }),
- )
- expect(requests[0]).toMatchObject({
- url: WebSearchParallel.endpoint,
- headers: { authorization: "Bearer parallel-secret" },
- body: {
- jsonrpc: "2.0",
- id: 1,
- method: "tools/call",
- params: {
- name: "web_search",
- arguments: {
- objective: "effect layers",
- search_queries: ["effect layers"],
- },
- },
- },
- })
- expect(JSON.stringify(output)).not.toContain("parallel-secret")
- }),
- )
- })
|