opencode-websearch-deepseek 0.1.1 → 0.2.0
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 +7 -2
- package/dist/index.d.ts +20 -0
- package/dist/index.js +45 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,8 +63,8 @@ in:
|
|
|
63
63
|
|
|
64
64
|
| Variable | Required | Default | Description |
|
|
65
65
|
| ------------------- | -------- | ------------------ | ------------------------------------------------------------------ |
|
|
66
|
-
| `DEEPSEEK_API_KEY` |
|
|
67
|
-
| `WEBSEARCH_API_KEY` | no | — | Fallback key used when `DEEPSEEK_API_KEY` is not set.
|
|
66
|
+
| `DEEPSEEK_API_KEY` | no\* | — | DeepSeek API key (takes precedence over the stored credential). |
|
|
67
|
+
| `WEBSEARCH_API_KEY` | no | — | Fallback env key used when `DEEPSEEK_API_KEY` is not set. |
|
|
68
68
|
| `WEBSEARCH_MODEL` | no | `deepseek-v4-flash`| Model used for search and synthesis. |
|
|
69
69
|
| `WEBSEARCH_MAX_USES`| no | `5` | Max server-side searches per query (positive integer). |
|
|
70
70
|
| `WEBSEARCH_THINKING`| no | `enabled` | `enabled` or `disabled`; disables extended thinking when set to `disabled`. |
|
|
@@ -72,6 +72,11 @@ in:
|
|
|
72
72
|
> `WEBSEARCH_MODEL` is passed through as-is. DeepSeek maps unknown model names
|
|
73
73
|
> to its default, so any server-side-search-capable DeepSeek model works.
|
|
74
74
|
|
|
75
|
+
> \* If no environment key is set, the plugin reuses the API key OpenCode
|
|
76
|
+
> stores for the `deepseek` provider (for example after `opencode auth login`),
|
|
77
|
+
> so no environment variable is required when that provider is already
|
|
78
|
+
> authenticated.
|
|
79
|
+
|
|
75
80
|
> The plugin always selects the DeepSeek provider. Without an API key, a
|
|
76
81
|
> `websearch` call fails with a clear error rather than silently falling back
|
|
77
82
|
> to a different provider.
|
package/dist/index.d.ts
CHANGED
|
@@ -83,12 +83,32 @@ interface WebsearchEditor {
|
|
|
83
83
|
set(providerID: string | false): void;
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
/** A credential returned by OpenCode for a configured provider. */
|
|
87
|
+
export interface StoredCredential {
|
|
88
|
+
type?: string;
|
|
89
|
+
key?: string;
|
|
90
|
+
}
|
|
91
|
+
/** Minimal slice of OpenCode's integration API used to read a stored provider key. */
|
|
92
|
+
export interface IntegrationContext {
|
|
93
|
+
connection: {
|
|
94
|
+
active(integrationID: string): Promise<unknown>;
|
|
95
|
+
resolve(connection: unknown): Promise<StoredCredential | undefined>;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
86
98
|
/** Context passed to the plugin's `setup`. */
|
|
87
99
|
export interface WebsearchContext {
|
|
88
100
|
websearch: {
|
|
89
101
|
transform(callback: (editor: WebsearchEditor) => void): Promise<unknown> | unknown;
|
|
90
102
|
};
|
|
103
|
+
/** Present in OpenCode 2.x; used to reuse the DeepSeek provider credential. */
|
|
104
|
+
integration?: IntegrationContext;
|
|
91
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Resolve the DeepSeek API key. An explicit environment variable takes
|
|
108
|
+
* precedence; otherwise the key OpenCode stores for the `deepseek` provider
|
|
109
|
+
* (configured via `opencode auth login`) is used.
|
|
110
|
+
*/
|
|
111
|
+
export declare function resolveApiKey(ctx: WebsearchContext): Promise<string | undefined>;
|
|
92
112
|
/**
|
|
93
113
|
* Resolve the `max_uses` value for the search tool declaration.
|
|
94
114
|
* Falls back to {@link DEFAULT_MAX_USES} for missing or invalid input.
|
package/dist/index.js
CHANGED
|
@@ -46,11 +46,52 @@ export const SYSTEM_PROMPT = [
|
|
|
46
46
|
"",
|
|
47
47
|
"Your response must be the final answer, not another search request.",
|
|
48
48
|
].join("\n");
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the DeepSeek API key. An explicit environment variable takes
|
|
51
|
+
* precedence; otherwise the key OpenCode stores for the `deepseek` provider
|
|
52
|
+
* (configured via `opencode auth login`) is used.
|
|
53
|
+
*/
|
|
54
|
+
export async function resolveApiKey(ctx) {
|
|
55
|
+
const fromEnv = readEnv("DEEPSEEK_API_KEY") ?? readEnv("WEBSEARCH_API_KEY");
|
|
56
|
+
if (fromEnv)
|
|
57
|
+
return fromEnv;
|
|
58
|
+
const integration = ctx.integration;
|
|
59
|
+
if (!integration)
|
|
60
|
+
return undefined;
|
|
61
|
+
try {
|
|
62
|
+
const connection = await integration.connection.active("deepseek");
|
|
63
|
+
if (!connection)
|
|
64
|
+
return undefined;
|
|
65
|
+
const credential = await integration.connection.resolve(connection);
|
|
66
|
+
const key = credential?.key;
|
|
67
|
+
return typeof key === "string" && key.trim() ? key.trim() : undefined;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
49
73
|
/** Read an environment variable, treating blank strings as unset. */
|
|
50
74
|
function readEnv(name, env = process.env) {
|
|
51
75
|
const value = env[name];
|
|
52
76
|
return value && value.trim() ? value.trim() : undefined;
|
|
53
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Rethrow the cancellation reason from `signal`. `Error` and `DOMException`
|
|
80
|
+
* (e.g. `AbortError`) are preserved as-is; other values (primitives) are
|
|
81
|
+
* normalised to an `Error` so callers always receive one.
|
|
82
|
+
*/
|
|
83
|
+
function throwCancellation(signal, fallback) {
|
|
84
|
+
const reason = signal.reason;
|
|
85
|
+
if (reason instanceof Error)
|
|
86
|
+
throw reason;
|
|
87
|
+
if (typeof reason === "object" && reason !== null)
|
|
88
|
+
throw reason;
|
|
89
|
+
if (reason !== undefined && reason !== null)
|
|
90
|
+
throw new Error(String(reason));
|
|
91
|
+
if (fallback instanceof Error)
|
|
92
|
+
throw fallback;
|
|
93
|
+
throw new Error("The web search was aborted");
|
|
94
|
+
}
|
|
54
95
|
/**
|
|
55
96
|
* Resolve the `max_uses` value for the search tool declaration.
|
|
56
97
|
* Falls back to {@link DEFAULT_MAX_USES} for missing or invalid input.
|
|
@@ -194,9 +235,9 @@ export const plugin = {
|
|
|
194
235
|
id: "deepseek",
|
|
195
236
|
name: "DeepSeek Web Search",
|
|
196
237
|
execute: async ({ query }, { signal } = {}) => {
|
|
197
|
-
const apiKey =
|
|
238
|
+
const apiKey = await resolveApiKey(ctx);
|
|
198
239
|
if (!apiKey) {
|
|
199
|
-
throw new Error("DEEPSEEK_API_KEY is not set in the OpenCode
|
|
240
|
+
throw new Error("DEEPSEEK_API_KEY is not set and no stored DeepSeek credential was found; set the env var or sign in to the deepseek provider in OpenCode");
|
|
200
241
|
}
|
|
201
242
|
if (!/^[\x21-\x7e]+$/.test(apiKey)) {
|
|
202
243
|
throw new Error("The API key contains invalid characters");
|
|
@@ -220,7 +261,7 @@ export const plugin = {
|
|
|
220
261
|
const text = await response.text().catch((error) => {
|
|
221
262
|
// Preserve cancellation: never turn an abort into an API error.
|
|
222
263
|
if (signal?.aborted)
|
|
223
|
-
|
|
264
|
+
return throwCancellation(signal, error);
|
|
224
265
|
if (error?.name === "AbortError")
|
|
225
266
|
throw error;
|
|
226
267
|
return "";
|
|
@@ -228,7 +269,7 @@ export const plugin = {
|
|
|
228
269
|
// An abort can also arrive after the body resolves; re-check so it
|
|
229
270
|
// is not masked as an API error.
|
|
230
271
|
if (signal?.aborted)
|
|
231
|
-
|
|
272
|
+
throwCancellation(signal, undefined);
|
|
232
273
|
throw new Error(`DeepSeek API error ${response.status}: ${text.slice(0, 300)}`);
|
|
233
274
|
}
|
|
234
275
|
const data = (await response.json());
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-websearch-deepseek",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "DeepSeek-powered web search provider for OpenCode's built-in websearch tool.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|