opencode-websearch 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,41 +16,49 @@ OpenCode will install it automatically at startup.
16
16
 
17
17
  ## Configuration
18
18
 
19
- The plugin needs an Anthropic API key. It resolves credentials in this order:
19
+ The plugin looks for an Anthropic provider (`@ai-sdk/anthropic`) with `"websearch": true` set on at least one model. It picks up credentials however you've configured them in OpenCode -- via `/connect`, environment variables, or `options.apiKey` in your config.
20
20
 
21
- 1. **opencode.json** -- looks for an `@ai-sdk/anthropic` provider in your project or global config
22
- 2. **Environment variable** -- falls back to `ANTHROPIC_API_KEY`
21
+ Add `"websearch": true` to the model you want the plugin to use for searches:
23
22
 
24
- ### Option 1: opencode.json provider (recommended)
23
+ ```json
24
+ {
25
+ "provider": {
26
+ "anthropic": {
27
+ "models": {
28
+ "claude-sonnet-4-5": {
29
+ "options": {
30
+ "websearch": true
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ ```
25
38
 
26
- If you already have an Anthropic provider configured, the plugin will use it automatically:
39
+ This also works with custom providers that use `@ai-sdk/anthropic`, such as a LiteLLM proxy:
27
40
 
28
41
  ```json
29
42
  {
30
43
  "provider": {
31
- "anthropic": {
44
+ "my-anthropic": {
32
45
  "npm": "@ai-sdk/anthropic",
33
46
  "options": {
34
- "apiKey": "{env:ANTHROPIC_API_KEY}"
47
+ "baseURL": "http://localhost:4000/v1/",
48
+ "apiKey": "{env:MY_API_KEY}"
35
49
  },
36
50
  "models": {
37
- "claude-sonnet-4-5": { "name": "Claude Sonnet 4.5" }
51
+ "claude-sonnet-4-5": {
52
+ "options": {
53
+ "websearch": true
54
+ }
55
+ }
38
56
  }
39
57
  }
40
58
  }
41
59
  }
42
60
  ```
43
61
 
44
- The model used for search is the first model listed in the provider config.
45
-
46
- ### Option 2: environment variable
47
-
48
- ```sh
49
- export ANTHROPIC_API_KEY=sk-ant-...
50
- ```
51
-
52
- When using the env var fallback, `claude-sonnet-4-5` is used as the default model.
53
-
54
62
  ## Usage
55
63
 
56
64
  Once configured, the `web-search` tool is available to the AI agent. It accepts:
@@ -68,15 +76,36 @@ Results are returned as formatted markdown with source links.
68
76
 
69
77
  ## Development
70
78
 
79
+ ### Local Development
80
+
81
+ To develop or customize the plugin locally, clone the repo and symlink the
82
+ source entry point into your OpenCode plugin directory:
83
+
71
84
  ```sh
72
- # Install dependencies
85
+ git clone https://github.com/emilsvennesson/opencode-websearch ~/.config/opencode/opencode-websearch
86
+ cd ~/.config/opencode/opencode-websearch
73
87
  bun install
88
+ mkdir -p ~/.config/opencode/plugin
89
+ ln -sf ~/.config/opencode/opencode-websearch/src/index.ts ~/.config/opencode/plugin/websearch.ts
90
+ ```
91
+
92
+ OpenCode will load the plugin directly from source on startup. Any edits to the
93
+ files in `src/` take effect next time you start OpenCode.
74
94
 
75
- # Type check
76
- bun run typecheck
95
+ > **Note:** When using the symlink approach, remove `"opencode-websearch"` from
96
+ > the `plugin` array in your `opencode.json` to avoid loading the plugin twice.
77
97
 
78
- # Build
79
- bun run build
98
+ ### Commands
99
+
100
+ ```sh
101
+ bun install # install dependencies
102
+ bun run format # auto-format source files
103
+ bun run format:check # verify formatting (no changes)
104
+ bun run lint # run oxlint
105
+ bun run lint:fix # auto-fix lint issues
106
+ bun run typecheck # type check with tsc
107
+ bun run check # format:check + lint + typecheck (full quality gate)
108
+ bun run build # ESM bundle + declaration files → dist/
80
109
  ```
81
110
 
82
111
  ## License
package/dist/config.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { AnthropicConfig } from "./types.js";
2
2
  interface ProviderData {
3
+ id: string;
4
+ key?: string;
3
5
  models: Record<string, {
4
6
  api: {
5
7
  npm: string;
@@ -7,7 +9,6 @@ interface ProviderData {
7
9
  id: string;
8
10
  options: Record<string, unknown>;
9
11
  }>;
10
- key?: string;
11
12
  options: Record<string, unknown>;
12
13
  }
13
14
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAI7C,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC/F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAqBD;;;GAGG;AACH,QAAA,MAAM,oBAAoB,GAAI,WAAW,YAAY,EAAE,KAAG,eAAe,GAAG,IAgB3E,CAAC;AAIF,QAAA,MAAM,iBAAiB,QAAO,MA6B0B,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAI7C,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC/F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AA4BD;;;GAGG;AACH,QAAA,MAAM,oBAAoB,GAAI,WAAW,YAAY,EAAE,KAAG,eAAe,GAAG,IAiB3E,CAAC;AAIF,QAAA,MAAM,iBAAiB,QAAO,MA6B0B,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -14,6 +14,12 @@ import { tool } from "@opencode-ai/plugin";
14
14
  var isAnthropicModel = (model) => model.api.npm === ANTHROPIC_NPM_PACKAGE;
15
15
  var hasWebSearch = (model) => model.options.websearch === true;
16
16
  var normalizeBaseURL = (url) => url.replace(/\/v1\/?$/, "");
17
+ var extractApiKey = (options) => {
18
+ if (typeof options.apiKey !== "string") {
19
+ return;
20
+ }
21
+ return options.apiKey;
22
+ };
17
23
  var extractBaseURL = (options) => {
18
24
  if (typeof options.baseURL !== "string") {
19
25
  return;
@@ -24,11 +30,12 @@ var resolveFromProviders = (providers) => {
24
30
  for (const provider of providers) {
25
31
  for (const model of Object.values(provider.models)) {
26
32
  if (isAnthropicModel(model) && hasWebSearch(model)) {
27
- if (!provider.key) {
33
+ const apiKey = provider.key ?? extractApiKey(provider.options);
34
+ if (!apiKey) {
28
35
  return null;
29
36
  }
30
37
  return {
31
- apiKey: provider.key,
38
+ apiKey,
32
39
  baseURL: extractBaseURL(provider.options),
33
40
  model: model.id
34
41
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opencode-websearch",
3
- "version": "0.2.1",
4
- "description": "Claude Code's WebSearch tool ported to OpenCode",
3
+ "version": "0.2.3",
4
+ "description": "Web search plugin for OpenCode, inspired by Claude Code's WebSearch tool",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",