opencode icon indicating copy to clipboard operation
opencode copied to clipboard

web search tool

Open adamdotdevin opened this issue 8 months ago • 18 comments

adamdotdevin avatar Jun 22 '25 16:06 adamdotdevin

Does this exist now? I see websearch.txt, but no corresponding websearch.ts implementation? (And websearch -> "Search" styling) @rekram1-node, can you point me to what closed this?

garrett-hopper avatar Aug 29 '25 15:08 garrett-hopper

@garrett-hopper https://github.com/sst/opencode/blob/dev/packages/opencode/src/tool/webfetch.ts

rekram1-node avatar Aug 29 '25 15:08 rekram1-node

The title of the issue and contents of websearch.txt refer to actual search functionality rather than the web fetching supported by that tool. Should a different issue be opened? Though maybe web search should be left to MCP servers since there are few (if any?) free APIs for it?

garrett-hopper avatar Aug 29 '25 15:08 garrett-hopper

Ig you are correct they are different

rekram1-node avatar Aug 29 '25 15:08 rekram1-node

I can open a PR to add websearch tool using Gemini search grounding tool, which can search and fetch pages and make a summary, very similar to how Claude Code works

This tool would be enabled only for users that logged in with Gemini

PR welcome?

remorses avatar Sep 09 '25 13:09 remorses

Curious if Claude Code's builtin search could be used as well in a similar fashion for those using Anthropic Pro/Max logins. 🤔 Would probably be ideal to have support for the providers' builtin tools when possible. Groq has builtin Exa search tool (https://console.groq.com/docs/browser-search) for openai/gpt-oss-120b and Tavily for their compound models (https://console.groq.com/docs/web-search). Not sure how difficult it'd be to support any/all of these.

garrett-hopper avatar Sep 09 '25 13:09 garrett-hopper

@adamdotdevin @thdxr is search something opencode is planning on adding?

eugene-kim avatar Sep 12 '25 13:09 eugene-kim

I've been using the python lib/cli ddgs with a lightweight local MCP wrapper and it's fantastic so far. Much faster & precise results for agent web searches than the builtin Cursor websearch I was using before. Note that the npm package by the same name is not a direct analog and lacks many of the features. I could take a crack at creating a direct typescript port of the python implementation if y'all were interested in integrating advanced search functionality.

trose avatar Sep 22 '25 17:09 trose

I can see that currently there are websearch and codesearch tools behind the OPENCODE_ENABLE_EXA flag. It uses the Exa API under the hood.

nikaro avatar Dec 23 '25 11:12 nikaro

Is that OPENCODE_ENABLE_EXA Zen only or can I provide my own Exa API key?

garrett-hopper avatar Dec 23 '25 18:12 garrett-hopper

I've run OPENCODE_ENABLE_EXA=true opencode without API key (and without Zen either) and it worked 🤷 I did not see anything about setting an API key in the opencode source code. I guess there is a free tier or something like that?

nikaro avatar Dec 24 '25 09:12 nikaro

I am searching for a solution for web search, and I just found the websearch tool in the codebase. I tried it just like @nikaro did, and it works for me too.

Even in free tier, you still need API key by the way.

gasatrya avatar Dec 29 '25 15:12 gasatrya

I was surprised there was no search, so cooked a quick tool for opencode to use codex w/ search enabled to do some webresearch. I suppose it's a bit like amp's "Librarian" but with a bad ui. Anyway, it's working for me.

Sharing in case it's helpful for someone else

//.opencode/tool/webresearch.ts
import { tool } from "@opencode-ai/plugin";

const QUALITY_PRESETS = {
  fast: {
    effort: "low",
    directive: "Keep it quick; use only the most relevant sources.",
  },
  balanced: {
    effort: "medium",
    directive: "Cover the main angles; resolve contradictions if they appear.",
  },
  deep: {
    effort: "high",
    directive:
      "Follow second-order leads and resolve contradictions until extra sources stop adding value.",
  },
} as const;

type Quality = keyof typeof QUALITY_PRESETS;

function buildPrompt({
  reason,
  query,
  additionalContext,
  quality,
}: {
  reason: string;
  query: string;
  additionalContext?: string;
  quality: Quality;
}) {
  const preset = QUALITY_PRESETS[quality];
  const contextBlock = additionalContext
    ? `Additional context (optional): ${additionalContext}`
    : "Additional context (optional):";

  return [
    "Hi, I’m stuck and need help with a research task.",
    "",
    `Reason: ${reason}`,
    `Search queries: ${query}`,
    contextBlock,
    `Depth: ${quality}`,
    "",
    "Please search the web and send back:",
    "- A 2-4 sentence summary",
    "- Key findings or caveats (bullets)",
    "- Sources with full URLs",
    "",
    "If anything is ambiguous, cover the plausible interpretations and state your assumptions instead of asking questions.",
    "Please don’t edit any code or files.",
    preset.directive,
  ].join("\n");
}

async function runCodex({
  prompt,
  effort,
  timeoutSeconds,
}: {
  prompt: string;
  effort: string;
  timeoutSeconds?: number;
}) {
  const args = [
    "exec",
    "--enable",
    "web_search_request",
    "--sandbox",
    "read-only",
    "-c",
    `model_reasoning_effort=${effort}`,
    prompt,
  ];

  const proc = Bun.spawn(["codex", ...args], {
    stdout: "pipe",
    stderr: "pipe",
  });

  let timeoutId: ReturnType<typeof setTimeout> | undefined;
  if (timeoutSeconds && timeoutSeconds > 0) {
    timeoutId = setTimeout(
      () => {
        proc.kill();
      },
      Math.round(timeoutSeconds * 1000),
    );
  }

  const [stdout, stderr] = await Promise.all([
    new Response(proc.stdout).text(),
    new Response(proc.stderr).text(),
  ]);
  const exitCode = await proc.exited;
  if (timeoutId) {
    clearTimeout(timeoutId);
  }

  if (exitCode !== 0) {
    const message =
      stderr.trim() || `codex exec failed with exit code ${exitCode}`;
    throw new Error(message);
  }

  return stdout.trim();
}

export default tool({
  description:
    "Run a web search and return a concise summary with source links. Use when you need current, verifiable information or citations.",
  args: {
    reason: tool.schema
      .string()
      .describe(
        "Describe the core reason you’re reaching for web search and the decision or output you’re aiming for.",
      ),
    query: tool.schema
      .string()
      .describe(
        'List the search queries you want run; use new lines or ";" to include multiple angles.',
      ),
    additional_context: tool.schema
      .string()
      .optional()
      .describe(
        "Add constraints or background: versions, product names, prior findings, relevant files/code, or must-include sources.",
      ),
    quality: tool.schema
      .enum(["fast", "balanced", "deep"])
      .describe(
        "Fast = quick scan, balanced = normal depth, deep = thorough with follow-up leads.",
      ),
    timeout: tool.schema
      .number()
      .optional()
      .describe("Optional max seconds to cap the search."),
  },
  async execute(args) {
    const quality = args.quality as Quality;
    const prompt = buildPrompt({
      reason: args.reason,
      query: args.query,
      additionalContext: args.additional_context,
      quality,
    });

    const effort = QUALITY_PRESETS[quality].effort;
    return runCodex({
      prompt,
      effort,
      timeoutSeconds: args.timeout,
    });
  },
});

brennanmceachran avatar Dec 31 '25 21:12 brennanmceachran

existing exa search is great. feels more accurate than google search. doesn't even require api key, impressive

rakibdev avatar Jan 03 '26 09:01 rakibdev

I'm hitting 429 when using it and can't debug the request/response because the provider is missing log.debug calls (actually no logging). Would be nice to add them to debug these issues. probably the server response tells something

It seems that the web search is still not working due to rate limiting (429 error

scratchmex avatar Jan 05 '26 19:01 scratchmex

Might be worth to auto enable it if a zen auth was detected?

lopi-py avatar Jan 12 '26 08:01 lopi-py

I would expect opencode to support the models' native search tool instead of using a 3rd party API, e.g.:

  • https://platform.openai.com/docs/guides/tools-web-search
  • https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool

angristan avatar Jan 18 '26 11:01 angristan

I would expect opencode to support the models' native search tool instead of using a 3rd party API, e.g.:

* https://platform.openai.com/docs/guides/tools-web-search

* https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool

Do these consume credits if used with API key?

lopi-py avatar Jan 18 '26 23:01 lopi-py

Do these consume credits if used with API key?

Of course 😃

Btw, different web search tools aren’t the same; e.g., some may be blocked from certain websites, and others can differ in their summarization results versus returning the actual raw content – it’d be really nice to have something universal that could fall back through the different available tools, suitable for the specific request. In the ideal case, even using the compatible MCP tools as well.

I'm using DuckDuckGo search MCP, and it often provides better results and is free. But models from all the different providers tend to forget to try it without my explicit command even after they have failed the request using the default web access tools.

art-shen avatar Jan 19 '26 08:01 art-shen