@oh-my-pi/pi-coding-agent 15.3.1 → 15.4.1
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/CHANGELOG.md +119 -0
- package/dist/types/cli/auth-gateway-cli.d.ts +1 -1
- package/dist/types/cli/file-processor.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +45 -3
- package/dist/types/config/settings.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +2 -0
- package/dist/types/edit/file-read-cache.d.ts +15 -4
- package/dist/types/edit/index.d.ts +3 -8
- package/dist/types/edit/renderer.d.ts +1 -2
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +1 -0
- package/dist/types/eval/js/shared/local-module-loader.d.ts +16 -0
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +4 -0
- package/dist/types/eval/js/shared/runtime.d.ts +14 -8
- package/dist/types/eval/py/executor.d.ts +1 -2
- package/dist/types/eval/py/kernel.d.ts +6 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -5
- package/dist/types/eval/session-id.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +1 -3
- package/dist/types/hashline/anchors.d.ts +15 -9
- package/dist/types/hashline/constants.d.ts +0 -2
- package/dist/types/hashline/diff.d.ts +1 -2
- package/dist/types/hashline/executor.d.ts +52 -0
- package/dist/types/hashline/hash.d.ts +44 -93
- package/dist/types/hashline/index.d.ts +2 -1
- package/dist/types/hashline/input.d.ts +2 -9
- package/dist/types/hashline/recovery.d.ts +3 -9
- package/dist/types/hashline/tokenizer.d.ts +91 -0
- package/dist/types/hashline/types.d.ts +5 -7
- package/dist/types/modes/components/extensions/types.d.ts +0 -4
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +11 -15
- package/dist/types/session/agent-storage.d.ts +11 -10
- package/dist/types/slash-commands/acp-builtins.d.ts +3 -3
- package/dist/types/slash-commands/types.d.ts +0 -5
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/task/types.d.ts +8 -0
- package/dist/types/tool-discovery/tool-index.d.ts +0 -50
- package/dist/types/tools/index.d.ts +2 -8
- package/dist/types/tools/match-line-format.d.ts +4 -4
- package/dist/types/tools/output-schema-validator.d.ts +64 -0
- package/dist/types/tools/review.d.ts +13 -0
- package/dist/types/tools/search-tool-bm25.d.ts +1 -1
- package/dist/types/tools/search.d.ts +4 -3
- package/dist/types/utils/edit-mode.d.ts +1 -1
- package/dist/types/web/kagi.d.ts +4 -2
- package/dist/types/web/parallel.d.ts +4 -3
- package/dist/types/web/scrapers/types.d.ts +2 -1
- package/dist/types/web/search/index.d.ts +12 -4
- package/dist/types/web/search/provider.d.ts +2 -1
- package/dist/types/web/search/providers/anthropic.d.ts +9 -4
- package/dist/types/web/search/providers/base.d.ts +34 -2
- package/dist/types/web/search/providers/brave.d.ts +8 -1
- package/dist/types/web/search/providers/codex.d.ts +13 -9
- package/dist/types/web/search/providers/exa.d.ts +10 -1
- package/dist/types/web/search/providers/gemini.d.ts +20 -23
- package/dist/types/web/search/providers/jina.d.ts +2 -1
- package/dist/types/web/search/providers/kagi.d.ts +4 -1
- package/dist/types/web/search/providers/kimi.d.ts +10 -1
- package/dist/types/web/search/providers/parallel.d.ts +3 -2
- package/dist/types/web/search/providers/perplexity.d.ts +5 -2
- package/dist/types/web/search/providers/searxng.d.ts +2 -1
- package/dist/types/web/search/providers/synthetic.d.ts +5 -8
- package/dist/types/web/search/providers/tavily.d.ts +11 -4
- package/dist/types/web/search/providers/utils.d.ts +8 -6
- package/dist/types/web/search/providers/zai.d.ts +12 -3
- package/package.json +7 -7
- package/src/cli/auth-gateway-cli.ts +71 -2
- package/src/cli/file-processor.ts +12 -2
- package/src/cli.ts +0 -8
- package/src/commands/auth-gateway.ts +2 -0
- package/src/commands/commit.ts +8 -8
- package/src/config/prompt-templates.ts +6 -6
- package/src/config/settings-schema.ts +47 -3
- package/src/config/settings.ts +5 -5
- package/src/debug/raw-sse.ts +68 -3
- package/src/edit/file-read-cache.ts +68 -25
- package/src/edit/index.ts +6 -37
- package/src/edit/renderer.ts +9 -47
- package/src/edit/streaming.ts +43 -56
- package/src/eval/__tests__/shared-executors.test.ts +520 -0
- package/src/eval/js/context-manager.ts +64 -53
- package/src/eval/js/shared/local-module-loader.ts +265 -0
- package/src/eval/js/shared/prelude.txt +4 -0
- package/src/eval/js/shared/rewrite-imports.ts +85 -0
- package/src/eval/js/shared/runtime.ts +129 -86
- package/src/eval/js/worker-core.ts +23 -38
- package/src/eval/py/executor.ts +155 -84
- package/src/eval/py/kernel.ts +10 -1
- package/src/eval/py/prelude.py +22 -24
- package/src/eval/py/runner.py +203 -85
- package/src/eval/py/tool-bridge.ts +17 -10
- package/src/eval/session-id.ts +8 -0
- package/src/exec/bash-executor.ts +27 -16
- package/src/extensibility/extensions/runner.ts +0 -1
- package/src/extensibility/extensions/types.ts +1 -3
- package/src/extensibility/plugins/marketplace/manager.ts +20 -1
- package/src/hashline/anchors.ts +56 -65
- package/src/hashline/apply.ts +29 -31
- package/src/hashline/constants.ts +0 -3
- package/src/hashline/diff-preview.ts +4 -5
- package/src/hashline/diff.ts +30 -4
- package/src/hashline/execute.ts +91 -26
- package/src/hashline/executor.ts +239 -0
- package/src/hashline/grammar.lark +12 -10
- package/src/hashline/hash.ts +69 -114
- package/src/hashline/index.ts +2 -1
- package/src/hashline/input.ts +48 -41
- package/src/hashline/prefixes.ts +21 -11
- package/src/hashline/recovery.ts +63 -71
- package/src/hashline/stream.ts +2 -2
- package/src/hashline/tokenizer.ts +467 -0
- package/src/hashline/types.ts +6 -8
- package/src/internal-urls/docs-index.generated.ts +9 -8
- package/src/lsp/config.ts +87 -22
- package/src/modes/components/extensions/types.ts +0 -5
- package/src/modes/components/session-observer-overlay.ts +11 -2
- package/src/modes/components/tree-selector.ts +10 -2
- package/src/modes/controllers/command-controller.ts +1 -3
- package/src/modes/controllers/extension-ui-controller.ts +10 -11
- package/src/modes/controllers/selector-controller.ts +5 -5
- package/src/modes/types.ts +4 -1
- package/src/modes/utils/ui-helpers.ts +4 -0
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/eval.md +1 -1
- package/src/prompts/tools/hashline.md +73 -94
- package/src/prompts/tools/read.md +4 -4
- package/src/prompts/tools/search.md +3 -3
- package/src/sdk.ts +21 -24
- package/src/session/agent-session.ts +59 -66
- package/src/session/agent-storage.ts +13 -14
- package/src/slash-commands/acp-builtins.ts +3 -3
- package/src/slash-commands/types.ts +0 -6
- package/src/task/executor.ts +55 -57
- package/src/task/index.ts +8 -4
- package/src/task/render.ts +53 -1
- package/src/task/types.ts +8 -0
- package/src/tool-discovery/tool-index.ts +0 -134
- package/src/tools/ast-edit.ts +36 -13
- package/src/tools/ast-grep.ts +45 -4
- package/src/tools/browser/tab-worker.ts +3 -2
- package/src/tools/eval.ts +2 -1
- package/src/tools/fetch.ts +23 -14
- package/src/tools/index.ts +2 -8
- package/src/tools/irc.ts +59 -5
- package/src/tools/jtd-to-json-schema.ts +5 -1
- package/src/tools/match-line-format.ts +5 -7
- package/src/tools/output-schema-validator.ts +132 -0
- package/src/tools/read.ts +142 -63
- package/src/tools/review.ts +23 -0
- package/src/tools/search-tool-bm25.ts +3 -30
- package/src/tools/search.ts +48 -16
- package/src/tools/write.ts +3 -3
- package/src/tools/yield.ts +32 -41
- package/src/utils/edit-mode.ts +1 -2
- package/src/utils/file-mentions.ts +2 -2
- package/src/web/kagi.ts +15 -6
- package/src/web/parallel.ts +9 -6
- package/src/web/scrapers/types.ts +7 -1
- package/src/web/scrapers/youtube.ts +13 -7
- package/src/web/search/index.ts +37 -11
- package/src/web/search/provider.ts +5 -3
- package/src/web/search/providers/anthropic.ts +30 -21
- package/src/web/search/providers/base.ts +35 -2
- package/src/web/search/providers/brave.ts +4 -4
- package/src/web/search/providers/codex.ts +118 -89
- package/src/web/search/providers/exa.ts +3 -2
- package/src/web/search/providers/gemini.ts +58 -155
- package/src/web/search/providers/jina.ts +4 -4
- package/src/web/search/providers/kagi.ts +17 -11
- package/src/web/search/providers/kimi.ts +29 -13
- package/src/web/search/providers/parallel.ts +171 -23
- package/src/web/search/providers/perplexity.ts +38 -37
- package/src/web/search/providers/searxng.ts +3 -1
- package/src/web/search/providers/synthetic.ts +16 -19
- package/src/web/search/providers/tavily.ts +23 -18
- package/src/web/search/providers/utils.ts +11 -17
- package/src/web/search/providers/zai.ts +16 -8
- package/dist/types/hashline/parser.d.ts +0 -7
- package/dist/types/mcp/discoverable-tool-metadata.d.ts +0 -7
- package/dist/types/tools/vim.d.ts +0 -58
- package/dist/types/vim/buffer.d.ts +0 -41
- package/dist/types/vim/commands.d.ts +0 -6
- package/dist/types/vim/engine.d.ts +0 -47
- package/dist/types/vim/parser.d.ts +0 -3
- package/dist/types/vim/render.d.ts +0 -25
- package/dist/types/vim/types.d.ts +0 -182
- package/src/hashline/parser.ts +0 -212
- package/src/mcp/discoverable-tool-metadata.ts +0 -24
- package/src/prompts/tools/vim.md +0 -98
- package/src/tools/vim.ts +0 -949
- package/src/vim/buffer.ts +0 -309
- package/src/vim/commands.ts +0 -382
- package/src/vim/engine.ts +0 -2409
- package/src/vim/parser.ts +0 -134
- package/src/vim/render.ts +0 -252
- package/src/vim/types.ts +0 -197
package/src/web/search/index.ts
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Single tool supporting Anthropic, Perplexity, Exa, Brave, Jina, Kimi, Gemini, Codex, Tavily, Kagi, Z.AI, SearXNG, and Synthetic
|
|
5
5
|
* providers with provider-specific parameters exposed conditionally.
|
|
6
|
-
*
|
|
7
6
|
*/
|
|
8
7
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
8
|
+
import type { AuthStorage } from "@oh-my-pi/pi-ai";
|
|
9
9
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
10
10
|
import * as z from "zod/v4";
|
|
11
11
|
import type { CustomTool, CustomToolContext, RenderResultOptions } from "../../extensibility/custom-tools/types";
|
|
12
12
|
import type { Theme } from "../../modes/theme/theme";
|
|
13
13
|
import webSearchSystemPrompt from "../../prompts/system/web-search.md" with { type: "text" };
|
|
14
14
|
import webSearchDescription from "../../prompts/tools/web-search.md" with { type: "text" };
|
|
15
|
+
import { discoverAuthStorage } from "../../sdk";
|
|
15
16
|
import type { ToolSession } from "../../tools";
|
|
16
17
|
import { formatAge } from "../../tools/render-utils";
|
|
17
18
|
import { throwIfAborted } from "../../tools/tool-errors";
|
|
@@ -114,18 +115,25 @@ function formatForLLM(response: SearchResponse): string {
|
|
|
114
115
|
return parts.join("\n");
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
interface ExecuteSearchOptions {
|
|
119
|
+
authStorage: AuthStorage;
|
|
120
|
+
sessionId?: string;
|
|
121
|
+
signal?: AbortSignal;
|
|
122
|
+
}
|
|
123
|
+
|
|
117
124
|
/** Execute web search */
|
|
118
125
|
async function executeSearch(
|
|
119
126
|
_toolCallId: string,
|
|
120
127
|
params: SearchQueryParams,
|
|
121
|
-
|
|
128
|
+
options: ExecuteSearchOptions,
|
|
122
129
|
): Promise<{ content: Array<{ type: "text"; text: string }>; details: SearchRenderDetails }> {
|
|
130
|
+
const { authStorage, sessionId, signal } = options;
|
|
123
131
|
const providers =
|
|
124
132
|
params.provider && params.provider !== "auto"
|
|
125
|
-
? await getSearchProvider(params.provider).then(provider =>
|
|
126
|
-
provider.isAvailable() ? [provider] : resolveProviderChain("auto"),
|
|
133
|
+
? await getSearchProvider(params.provider).then(async provider =>
|
|
134
|
+
(await provider.isAvailable(authStorage)) ? [provider] : resolveProviderChain(authStorage, "auto"),
|
|
127
135
|
)
|
|
128
|
-
: await resolveProviderChain();
|
|
136
|
+
: await resolveProviderChain(authStorage);
|
|
129
137
|
if (providers.length === 0) {
|
|
130
138
|
const message = "No web search provider configured.";
|
|
131
139
|
return {
|
|
@@ -148,6 +156,8 @@ async function executeSearch(
|
|
|
148
156
|
numSearchResults: params.num_search_results,
|
|
149
157
|
temperature: params.temperature,
|
|
150
158
|
signal,
|
|
159
|
+
authStorage,
|
|
160
|
+
sessionId,
|
|
151
161
|
});
|
|
152
162
|
|
|
153
163
|
const text = formatForLLM(response);
|
|
@@ -190,18 +200,27 @@ async function executeSearch(
|
|
|
190
200
|
|
|
191
201
|
/**
|
|
192
202
|
* Execute a web search query for CLI/testing workflows.
|
|
203
|
+
*
|
|
204
|
+
* `authStorage` may be omitted; in that case we discover one via the standard
|
|
205
|
+
* factory (`discoverAuthStorage`), which honours `OMP_AUTH_BROKER_URL` and
|
|
206
|
+
* otherwise opens the local SQLite credential store.
|
|
193
207
|
*/
|
|
194
208
|
export async function runSearchQuery(
|
|
195
209
|
params: SearchQueryParams,
|
|
210
|
+
options: { authStorage?: AuthStorage; sessionId?: string; signal?: AbortSignal } = {},
|
|
196
211
|
): Promise<{ content: Array<{ type: "text"; text: string }>; details: SearchRenderDetails }> {
|
|
197
|
-
|
|
212
|
+
const authStorage = options.authStorage ?? (await discoverAuthStorage());
|
|
213
|
+
return executeSearch("cli-web-search", params, {
|
|
214
|
+
authStorage,
|
|
215
|
+
sessionId: options.sessionId,
|
|
216
|
+
signal: options.signal,
|
|
217
|
+
});
|
|
198
218
|
}
|
|
199
219
|
|
|
200
220
|
/**
|
|
201
221
|
* Web search tool implementation.
|
|
202
222
|
*
|
|
203
223
|
* Supports Anthropic, Perplexity, Exa, Brave, Jina, Kimi, Gemini, Codex, Z.AI, SearXNG, and Synthetic providers with automatic fallback.
|
|
204
|
-
* Session is accepted for interface consistency but not used.
|
|
205
224
|
*/
|
|
206
225
|
export class WebSearchTool implements AgentTool<typeof webSearchSchema, SearchRenderDetails> {
|
|
207
226
|
readonly name = "web_search";
|
|
@@ -212,7 +231,10 @@ export class WebSearchTool implements AgentTool<typeof webSearchSchema, SearchRe
|
|
|
212
231
|
readonly loadMode = "discoverable";
|
|
213
232
|
readonly summary = "Search the web for up-to-date information";
|
|
214
233
|
|
|
215
|
-
|
|
234
|
+
#session: ToolSession;
|
|
235
|
+
|
|
236
|
+
constructor(session: ToolSession) {
|
|
237
|
+
this.#session = session;
|
|
216
238
|
this.description = prompt.render(webSearchDescription);
|
|
217
239
|
}
|
|
218
240
|
|
|
@@ -223,7 +245,9 @@ export class WebSearchTool implements AgentTool<typeof webSearchSchema, SearchRe
|
|
|
223
245
|
_onUpdate?: AgentToolUpdateCallback<SearchRenderDetails>,
|
|
224
246
|
_context?: AgentToolContext,
|
|
225
247
|
): Promise<AgentToolResult<SearchRenderDetails>> {
|
|
226
|
-
|
|
248
|
+
const authStorage = this.#session.authStorage ?? (await discoverAuthStorage());
|
|
249
|
+
const sessionId = this.#session.getSessionId?.() ?? undefined;
|
|
250
|
+
return executeSearch(_toolCallId, params, { authStorage, sessionId, signal });
|
|
227
251
|
}
|
|
228
252
|
}
|
|
229
253
|
|
|
@@ -238,10 +262,12 @@ export const webSearchCustomTool: CustomTool<typeof webSearchSchema, SearchRende
|
|
|
238
262
|
toolCallId: string,
|
|
239
263
|
params: SearchToolParams,
|
|
240
264
|
_onUpdate,
|
|
241
|
-
|
|
265
|
+
ctx: CustomToolContext,
|
|
242
266
|
signal?: AbortSignal,
|
|
243
267
|
) {
|
|
244
|
-
|
|
268
|
+
const authStorage = ctx.modelRegistry?.authStorage ?? (await discoverAuthStorage());
|
|
269
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
270
|
+
return executeSearch(toolCallId, params, { authStorage, sessionId, signal });
|
|
245
271
|
},
|
|
246
272
|
|
|
247
273
|
renderCall(args: SearchToolParams, options: RenderResultOptions, theme: Theme) {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// The `label`/`id` metadata is kept inline so callers needing a display name
|
|
9
9
|
// (error formatting, UI listings) do not force a load.
|
|
10
10
|
|
|
11
|
+
import type { AuthStorage } from "@oh-my-pi/pi-ai";
|
|
11
12
|
import type { SearchProvider } from "./providers/base";
|
|
12
13
|
import type { SearchProviderId } from "./types";
|
|
13
14
|
|
|
@@ -64,7 +65,7 @@ const PROVIDER_META: Record<SearchProviderId, ProviderMeta> = {
|
|
|
64
65
|
},
|
|
65
66
|
codex: {
|
|
66
67
|
id: "codex",
|
|
67
|
-
label: "
|
|
68
|
+
label: "OpenAI",
|
|
68
69
|
load: async () => new (await import("./providers/codex")).CodexProvider(),
|
|
69
70
|
},
|
|
70
71
|
tavily: {
|
|
@@ -148,13 +149,14 @@ export function setPreferredSearchProvider(provider: SearchProviderId | "auto"):
|
|
|
148
149
|
* is walked, so unconfigured providers never pay the load cost.
|
|
149
150
|
*/
|
|
150
151
|
export async function resolveProviderChain(
|
|
152
|
+
authStorage: AuthStorage,
|
|
151
153
|
preferredProvider: SearchProviderId | "auto" = preferredProvId,
|
|
152
154
|
): Promise<SearchProvider[]> {
|
|
153
155
|
const providers: SearchProvider[] = [];
|
|
154
156
|
|
|
155
157
|
if (preferredProvider !== "auto") {
|
|
156
158
|
const provider = await getSearchProvider(preferredProvider);
|
|
157
|
-
if (await provider.isAvailable()) {
|
|
159
|
+
if (await provider.isAvailable(authStorage)) {
|
|
158
160
|
providers.push(provider);
|
|
159
161
|
}
|
|
160
162
|
}
|
|
@@ -162,7 +164,7 @@ export async function resolveProviderChain(
|
|
|
162
164
|
for (const id of SEARCH_PROVIDER_ORDER) {
|
|
163
165
|
if (id === preferredProvider) continue;
|
|
164
166
|
const provider = await getSearchProvider(id);
|
|
165
|
-
if (await provider.isAvailable()) {
|
|
167
|
+
if (await provider.isAvailable(authStorage)) {
|
|
166
168
|
providers.push(provider);
|
|
167
169
|
}
|
|
168
170
|
}
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
import {
|
|
8
8
|
type AnthropicAuthConfig,
|
|
9
9
|
type AnthropicSystemBlock,
|
|
10
|
+
type AuthStorage,
|
|
11
|
+
buildAnthropicAuthConfig,
|
|
10
12
|
buildAnthropicSearchHeaders,
|
|
11
13
|
buildAnthropicSystemBlocks,
|
|
12
14
|
buildAnthropicUrl,
|
|
13
|
-
findAnthropicAuth,
|
|
14
15
|
stripClaudeToolPrefix,
|
|
15
16
|
} from "@oh-my-pi/pi-ai";
|
|
16
17
|
import { $env } from "@oh-my-pi/pi-utils";
|
|
@@ -34,9 +35,7 @@ export interface AnthropicSearchParams {
|
|
|
34
35
|
query: string;
|
|
35
36
|
system_prompt?: string;
|
|
36
37
|
num_results?: number;
|
|
37
|
-
/** Maximum output tokens. Defaults to 4096. */
|
|
38
38
|
max_tokens?: number;
|
|
39
|
-
/** Sampling temperature (0–1). Lower = more focused/factual. */
|
|
40
39
|
temperature?: number;
|
|
41
40
|
signal?: AbortSignal;
|
|
42
41
|
}
|
|
@@ -242,30 +241,47 @@ function parseResponse(response: AnthropicApiResponse): SearchResponse {
|
|
|
242
241
|
* @returns Search response with synthesized answer, sources, and citations
|
|
243
242
|
* @throws {Error} If no Anthropic credentials are configured
|
|
244
243
|
*/
|
|
245
|
-
export async function searchAnthropic(
|
|
246
|
-
|
|
244
|
+
export async function searchAnthropic(
|
|
245
|
+
params: SearchParams | AnthropicSearchParams,
|
|
246
|
+
_legacyStorage?: unknown,
|
|
247
|
+
): Promise<SearchResponse> {
|
|
248
|
+
const searchApiKey = $env.ANTHROPIC_SEARCH_API_KEY;
|
|
249
|
+
const searchBaseUrl = $env.ANTHROPIC_SEARCH_BASE_URL;
|
|
250
|
+
let auth: AnthropicAuthConfig | undefined;
|
|
251
|
+
|
|
252
|
+
if (searchApiKey) {
|
|
253
|
+
auth = buildAnthropicAuthConfig(searchApiKey, searchBaseUrl);
|
|
254
|
+
} else if ("authStorage" in params) {
|
|
255
|
+
const apiKey = await params.authStorage.getApiKey("anthropic", params.sessionId, {
|
|
256
|
+
signal: params.signal,
|
|
257
|
+
});
|
|
258
|
+
if (apiKey) auth = buildAnthropicAuthConfig(apiKey);
|
|
259
|
+
}
|
|
260
|
+
|
|
247
261
|
if (!auth) {
|
|
248
262
|
throw new Error(
|
|
249
|
-
"No Anthropic credentials found. Set ANTHROPIC_API_KEY or configure OAuth
|
|
263
|
+
"No Anthropic credentials found. Set ANTHROPIC_SEARCH_API_KEY or ANTHROPIC_API_KEY, or configure Anthropic OAuth.",
|
|
250
264
|
);
|
|
251
265
|
}
|
|
252
266
|
|
|
253
267
|
const model = getModel();
|
|
268
|
+
const systemPrompt = "authStorage" in params ? params.systemPrompt : params.system_prompt;
|
|
269
|
+
const maxTokens = "authStorage" in params ? params.maxOutputTokens : params.max_tokens;
|
|
254
270
|
const response = await callSearch(
|
|
255
271
|
auth,
|
|
256
272
|
model,
|
|
257
273
|
params.query,
|
|
258
|
-
|
|
259
|
-
|
|
274
|
+
systemPrompt,
|
|
275
|
+
maxTokens,
|
|
260
276
|
params.temperature,
|
|
261
277
|
params.signal,
|
|
262
278
|
);
|
|
263
279
|
|
|
264
280
|
const result = parseResponse(response);
|
|
265
281
|
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
result.sources = result.sources.slice(0,
|
|
282
|
+
const numResults = "authStorage" in params ? (params.numSearchResults ?? params.limit) : params.num_results;
|
|
283
|
+
if (numResults && result.sources.length > numResults) {
|
|
284
|
+
result.sources = result.sources.slice(0, numResults);
|
|
269
285
|
}
|
|
270
286
|
|
|
271
287
|
return result;
|
|
@@ -276,18 +292,11 @@ export class AnthropicProvider extends SearchProvider {
|
|
|
276
292
|
readonly id = "anthropic";
|
|
277
293
|
readonly label = "Anthropic";
|
|
278
294
|
|
|
279
|
-
isAvailable() {
|
|
280
|
-
return
|
|
295
|
+
isAvailable(authStorage: AuthStorage): Promise<boolean> | boolean {
|
|
296
|
+
return Boolean($env.ANTHROPIC_SEARCH_API_KEY) || authStorage.hasAuth("anthropic");
|
|
281
297
|
}
|
|
282
298
|
|
|
283
299
|
search(params: SearchParams): Promise<SearchResponse> {
|
|
284
|
-
return searchAnthropic(
|
|
285
|
-
query: params.query,
|
|
286
|
-
system_prompt: params.systemPrompt,
|
|
287
|
-
num_results: params.numSearchResults ?? params.limit,
|
|
288
|
-
max_tokens: params.maxOutputTokens,
|
|
289
|
-
temperature: params.temperature,
|
|
290
|
-
signal: params.signal,
|
|
291
|
-
});
|
|
300
|
+
return searchAnthropic(params);
|
|
292
301
|
}
|
|
293
302
|
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import type { AuthStorage } from "@oh-my-pi/pi-ai";
|
|
1
2
|
import type { SearchProviderId, SearchResponse } from "../types";
|
|
2
3
|
|
|
3
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Shared web search parameters passed to providers.
|
|
6
|
+
*
|
|
7
|
+
* `authStorage` is the **only** credential source providers may consult.
|
|
8
|
+
* Opening a sibling SQLite handle or calling provider-direct refresh helpers
|
|
9
|
+
* (e.g. `refreshOpenAICodexToken`, `refreshGoogleCloudToken`) is prohibited:
|
|
10
|
+
* it races the broker's per-credential refresh and POSTs the broker sentinel
|
|
11
|
+
* (`REMOTE_REFRESH_SENTINEL`) to the upstream token endpoint, which classifies
|
|
12
|
+
* as `invalid_grant` and disables the row.
|
|
13
|
+
*/
|
|
4
14
|
export interface SearchParams {
|
|
5
15
|
query: string;
|
|
6
16
|
limit?: number;
|
|
@@ -26,6 +36,20 @@ export interface SearchParams {
|
|
|
26
36
|
googleSearch?: Record<string, unknown>;
|
|
27
37
|
codeExecution?: Record<string, unknown>;
|
|
28
38
|
urlContext?: Record<string, unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* The single source of truth for credentials. Providers MUST consult this
|
|
41
|
+
* handle exclusively (`getApiKey` for bearer-style auth, `getOAuthAccess`
|
|
42
|
+
* when identity metadata is required). Do not open `AgentStorage` or any
|
|
43
|
+
* `AuthCredentialStore` directly — that bypasses the broker pipeline and
|
|
44
|
+
* the per-credential single-flight refresh.
|
|
45
|
+
*/
|
|
46
|
+
authStorage: AuthStorage;
|
|
47
|
+
/**
|
|
48
|
+
* Optional session id used as the round-robin / sticky key when selecting
|
|
49
|
+
* among multiple credentials for the same provider. Pass through from the
|
|
50
|
+
* caller's agent session when available; otherwise omit.
|
|
51
|
+
*/
|
|
52
|
+
sessionId?: string;
|
|
29
53
|
}
|
|
30
54
|
|
|
31
55
|
/** Base class for web search providers. */
|
|
@@ -33,6 +57,15 @@ export abstract class SearchProvider {
|
|
|
33
57
|
abstract readonly id: SearchProviderId;
|
|
34
58
|
abstract readonly label: string;
|
|
35
59
|
|
|
36
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Indicates whether this provider has the credentials/config it needs to
|
|
62
|
+
* service a request right now. Implementations consult the passed
|
|
63
|
+
* {@link AuthStorage} — never a sibling store.
|
|
64
|
+
*/
|
|
65
|
+
abstract isAvailable(authStorage: AuthStorage): Promise<boolean> | boolean;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Execute a search. Credentials MUST be resolved through `params.authStorage`.
|
|
69
|
+
*/
|
|
37
70
|
abstract search(params: SearchParams): Promise<SearchResponse>;
|
|
38
71
|
}
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* Calls Brave's web search REST API and maps results into the unified
|
|
5
5
|
* SearchResponse shape used by the web search tool.
|
|
6
6
|
*/
|
|
7
|
-
import { getEnvApiKey } from "@oh-my-pi/pi-ai";
|
|
7
|
+
import { type AuthStorage, getEnvApiKey } from "@oh-my-pi/pi-ai";
|
|
8
8
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
9
9
|
import { SearchProviderError } from "../../../web/search/types";
|
|
10
10
|
import { clampNumResults, dateToAgeSeconds } from "../utils";
|
|
11
11
|
import type { SearchParams } from "./base";
|
|
12
12
|
import { SearchProvider } from "./base";
|
|
13
|
-
import { classifyProviderHttpError,
|
|
13
|
+
import { classifyProviderHttpError, withHardTimeout } from "./utils";
|
|
14
14
|
|
|
15
15
|
const BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
|
|
16
16
|
const DEFAULT_NUM_RESULTS = 10;
|
|
@@ -134,8 +134,8 @@ export class BraveProvider extends SearchProvider {
|
|
|
134
134
|
readonly id = "brave";
|
|
135
135
|
readonly label = "Brave";
|
|
136
136
|
|
|
137
|
-
isAvailable() {
|
|
138
|
-
return
|
|
137
|
+
isAvailable(_authStorage: AuthStorage): boolean {
|
|
138
|
+
return !!findApiKey();
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
search(params: SearchParams): Promise<SearchResponse> {
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
* OpenAI Codex Web Search Provider
|
|
3
3
|
*
|
|
4
4
|
* Uses Codex's built-in web_search tool via the Responses API.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Auth is resolved through `AuthStorage.getOAuthAccess("openai-codex")` so the
|
|
6
|
+
* broker is the sole refresh authority — this module never opens a sibling
|
|
7
|
+
* SQLite store, never POSTs the broker sentinel to an OpenAI token endpoint.
|
|
7
8
|
*/
|
|
8
9
|
import * as os from "node:os";
|
|
9
|
-
import { getBundledModels } from "@oh-my-pi/pi-ai";
|
|
10
|
+
import { type AuthStorage, getBundledModels } from "@oh-my-pi/pi-ai";
|
|
10
11
|
import { decodeJwt } from "@oh-my-pi/pi-ai/utils/oauth/openai-codex";
|
|
11
|
-
import { $env,
|
|
12
|
+
import { $env, readSseJson } from "@oh-my-pi/pi-utils";
|
|
12
13
|
import packageJson from "../../../../package.json" with { type: "json" };
|
|
13
|
-
import { AgentStorage } from "../../../session/agent-storage";
|
|
14
14
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
15
15
|
import { SearchProviderError } from "../../../web/search/types";
|
|
16
16
|
import type { SearchParams } from "./base";
|
|
@@ -19,29 +19,48 @@ import { classifyProviderHttpError, withHardTimeout } from "./utils";
|
|
|
19
19
|
|
|
20
20
|
const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
|
|
21
21
|
const CODEX_RESPONSES_PATH = "/codex/responses";
|
|
22
|
-
const FALLBACK_MODEL = "gpt-5
|
|
22
|
+
const FALLBACK_MODEL = "gpt-5.4";
|
|
23
23
|
const DEFAULT_MODEL_PREFERENCES = [
|
|
24
|
-
"gpt-5-codex-mini",
|
|
25
24
|
"gpt-5.4",
|
|
25
|
+
"gpt-5-codex",
|
|
26
|
+
"gpt-5",
|
|
26
27
|
"gpt-5.3-codex",
|
|
27
28
|
"gpt-5.2-codex",
|
|
28
29
|
"gpt-5.1-codex",
|
|
29
|
-
"gpt-5-codex",
|
|
30
|
+
"gpt-5-codex-mini",
|
|
30
31
|
];
|
|
31
32
|
const JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
32
33
|
const DEFAULT_INSTRUCTIONS =
|
|
33
34
|
"You are a helpful assistant with web search capabilities. Search the web to answer the user's question accurately and cite your sources.";
|
|
34
35
|
|
|
35
|
-
function
|
|
36
|
+
function getConfiguredModel(): string | undefined {
|
|
36
37
|
const configuredModel = $env.PI_CODEX_WEB_SEARCH_MODEL?.trim();
|
|
37
|
-
|
|
38
|
+
return configuredModel ? configuredModel : undefined;
|
|
39
|
+
}
|
|
38
40
|
|
|
41
|
+
function getDefaultModelCandidates(): string[] {
|
|
39
42
|
const bundledModels = getBundledModels("openai-codex");
|
|
40
43
|
const bundledIds = new Set(bundledModels.map(model => model.id));
|
|
41
|
-
const
|
|
42
|
-
|
|
44
|
+
const candidates = DEFAULT_MODEL_PREFERENCES.filter(modelId => bundledIds.has(modelId));
|
|
45
|
+
|
|
46
|
+
if (candidates.length > 0) {
|
|
47
|
+
return candidates;
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
const nonMini = bundledModels.find(model => !model.id.includes("mini") && !model.id.includes("spark"));
|
|
44
|
-
|
|
51
|
+
if (nonMini) {
|
|
52
|
+
return [nonMini.id];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return bundledModels[0]?.id ? [bundledModels[0].id] : [FALLBACK_MODEL];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function shouldRetryWithNextDefaultModel(error: unknown): boolean {
|
|
59
|
+
if (!(error instanceof SearchProviderError)) return false;
|
|
60
|
+
if (error.provider !== "codex" || error.status !== 400) return false;
|
|
61
|
+
return /model is not supported|requested model is not supported|not supported when using codex with a chatgpt account/i.test(
|
|
62
|
+
error.message,
|
|
63
|
+
);
|
|
45
64
|
}
|
|
46
65
|
|
|
47
66
|
export interface CodexSearchParams {
|
|
@@ -53,15 +72,6 @@ export interface CodexSearchParams {
|
|
|
53
72
|
search_context_size?: "low" | "medium" | "high";
|
|
54
73
|
}
|
|
55
74
|
|
|
56
|
-
/** OAuth credential stored in agent.db */
|
|
57
|
-
interface CodexOAuthCredential {
|
|
58
|
-
type: "oauth";
|
|
59
|
-
access: string;
|
|
60
|
-
refresh?: string;
|
|
61
|
-
expires: number;
|
|
62
|
-
accountId?: string;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
75
|
/** Codex API response structure */
|
|
66
76
|
interface CodexResponseItem {
|
|
67
77
|
type: string;
|
|
@@ -231,7 +241,7 @@ function extractTextSources(text: string): SearchSource[] {
|
|
|
231
241
|
* @param accessToken - JWT access token
|
|
232
242
|
* @returns Account ID string, or null if not found
|
|
233
243
|
*/
|
|
234
|
-
function
|
|
244
|
+
function getAccountIdFromJwt(accessToken: string): string | null {
|
|
235
245
|
const payload = decodeJwt(accessToken);
|
|
236
246
|
const auth = payload?.[JWT_CLAIM_PATH] as { chatgpt_account_id?: string } | undefined;
|
|
237
247
|
const accountId = auth?.chatgpt_account_id;
|
|
@@ -239,43 +249,25 @@ function getAccountId(accessToken: string): string | null {
|
|
|
239
249
|
}
|
|
240
250
|
|
|
241
251
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
252
|
+
* Resolve a Codex bearer + accountId through {@link AuthStorage} — the single
|
|
253
|
+
* refresh authority. Returns `null` when no OAuth credential is configured,
|
|
254
|
+
* when the credential cannot be refreshed (broker error, revoked token, etc.),
|
|
255
|
+
* or when the access token carries no `chatgpt_account_id` claim.
|
|
245
256
|
*/
|
|
246
|
-
async function findCodexAuth(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (credential.type !== "oauth") continue;
|
|
257
|
-
|
|
258
|
-
const oauthCred = credential as CodexOAuthCredential;
|
|
259
|
-
if (!oauthCred.access) continue;
|
|
260
|
-
if (oauthCred.expires <= now + expiryBuffer) continue;
|
|
261
|
-
|
|
262
|
-
const accountId = oauthCred.accountId ?? getAccountId(oauthCred.access);
|
|
263
|
-
if (!accountId) continue;
|
|
264
|
-
|
|
265
|
-
return { accessToken: oauthCred.access, accountId };
|
|
266
|
-
}
|
|
267
|
-
} catch {
|
|
268
|
-
return null;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return null;
|
|
257
|
+
async function findCodexAuth(
|
|
258
|
+
authStorage: AuthStorage,
|
|
259
|
+
sessionId: string | undefined,
|
|
260
|
+
signal: AbortSignal | undefined,
|
|
261
|
+
): Promise<{ accessToken: string; accountId: string } | null> {
|
|
262
|
+
const access = await authStorage.getOAuthAccess("openai-codex", sessionId, { signal });
|
|
263
|
+
if (!access) return null;
|
|
264
|
+
const accountId = access.accountId ?? getAccountIdFromJwt(access.accessToken);
|
|
265
|
+
if (!accountId) return null;
|
|
266
|
+
return { accessToken: access.accessToken, accountId };
|
|
272
267
|
}
|
|
273
268
|
|
|
274
269
|
/**
|
|
275
270
|
* Builds HTTP headers for Codex API requests.
|
|
276
|
-
* @param accessToken - OAuth access token
|
|
277
|
-
* @param accountId - ChatGPT account ID
|
|
278
|
-
* @returns Headers object for fetch requests
|
|
279
271
|
*/
|
|
280
272
|
function buildCodexHeaders(accessToken: string, accountId: string): Record<string, string> {
|
|
281
273
|
return {
|
|
@@ -291,17 +283,19 @@ function buildCodexHeaders(accessToken: string, accountId: string): Record<strin
|
|
|
291
283
|
|
|
292
284
|
/**
|
|
293
285
|
* Calls the Codex Responses API with web search tool enabled.
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
* @param options - Search options including system prompt and context size
|
|
298
|
-
* @returns Parsed response with answer, sources, and usage
|
|
299
|
-
* @throws {SearchProviderError} If the API request fails
|
|
286
|
+
* The caller provides the exact model id to send; retry / fallback policy
|
|
287
|
+
* lives one layer up in `searchCodex()` so we can distinguish explicit user
|
|
288
|
+
* overrides from the default ChatGPT-account model-selection path.
|
|
300
289
|
*/
|
|
301
290
|
async function callCodexSearch(
|
|
302
291
|
auth: { accessToken: string; accountId: string },
|
|
303
292
|
query: string,
|
|
304
|
-
options: {
|
|
293
|
+
options: {
|
|
294
|
+
signal?: AbortSignal;
|
|
295
|
+
systemPrompt?: string;
|
|
296
|
+
searchContextSize?: "low" | "medium" | "high";
|
|
297
|
+
modelId: string;
|
|
298
|
+
},
|
|
305
299
|
): Promise<{
|
|
306
300
|
answer: string;
|
|
307
301
|
sources: SearchSource[];
|
|
@@ -312,7 +306,7 @@ async function callCodexSearch(
|
|
|
312
306
|
const url = `${CODEX_BASE_URL}${CODEX_RESPONSES_PATH}`;
|
|
313
307
|
const headers = buildCodexHeaders(auth.accessToken, auth.accountId);
|
|
314
308
|
|
|
315
|
-
const requestedModel =
|
|
309
|
+
const requestedModel = options.modelId;
|
|
316
310
|
|
|
317
311
|
const body: Record<string, unknown> = {
|
|
318
312
|
model: requestedModel,
|
|
@@ -457,29 +451,67 @@ async function callCodexSearch(
|
|
|
457
451
|
|
|
458
452
|
/**
|
|
459
453
|
* Executes a web search using OpenAI Codex's built-in web search tool.
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
454
|
+
*
|
|
455
|
+
* Default-model behavior:
|
|
456
|
+
* - If `PI_CODEX_WEB_SEARCH_MODEL` is set, use it exactly once and surface any
|
|
457
|
+
* upstream error verbatim.
|
|
458
|
+
* - Otherwise prefer ChatGPT-account-safe bundled defaults (GPT-5.4, GPT-5
|
|
459
|
+
* Codex, GPT-5, …) and retry the next candidate only when Codex returns the
|
|
460
|
+
* known 400 "model is not supported" family. This avoids selecting
|
|
461
|
+
* `gpt-5-codex-mini` first on ChatGPT accounts, which OpenAI rejects.
|
|
464
462
|
*/
|
|
465
|
-
export async function searchCodex(params:
|
|
466
|
-
const auth = await findCodexAuth();
|
|
463
|
+
export async function searchCodex(params: SearchParams): Promise<SearchResponse> {
|
|
464
|
+
const auth = await findCodexAuth(params.authStorage, params.sessionId, params.signal);
|
|
467
465
|
if (!auth) {
|
|
468
466
|
throw new Error(
|
|
469
467
|
"No Codex OAuth credentials found. Login with 'omp /login openai-codex' to enable Codex web search.",
|
|
470
468
|
);
|
|
471
469
|
}
|
|
472
470
|
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
471
|
+
const configuredModel = getConfiguredModel();
|
|
472
|
+
const modelCandidates = configuredModel ? [configuredModel] : getDefaultModelCandidates();
|
|
473
|
+
|
|
474
|
+
let result:
|
|
475
|
+
| {
|
|
476
|
+
answer: string;
|
|
477
|
+
sources: SearchSource[];
|
|
478
|
+
model: string;
|
|
479
|
+
requestId: string;
|
|
480
|
+
usage?: { inputTokens: number; outputTokens: number; totalTokens: number };
|
|
481
|
+
}
|
|
482
|
+
| undefined;
|
|
483
|
+
let lastError: unknown;
|
|
484
|
+
|
|
485
|
+
for (let index = 0; index < modelCandidates.length; index += 1) {
|
|
486
|
+
const modelId = modelCandidates[index];
|
|
487
|
+
if (!modelId) continue;
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
result = await callCodexSearch(auth, params.query, {
|
|
491
|
+
signal: params.signal,
|
|
492
|
+
systemPrompt: params.systemPrompt,
|
|
493
|
+
searchContextSize: "high",
|
|
494
|
+
modelId,
|
|
495
|
+
});
|
|
496
|
+
break;
|
|
497
|
+
} catch (error) {
|
|
498
|
+
lastError = error;
|
|
499
|
+
const isLastCandidate = index === modelCandidates.length - 1;
|
|
500
|
+
if (configuredModel || isLastCandidate || !shouldRetryWithNextDefaultModel(error)) {
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (!result) {
|
|
507
|
+
throw lastError ?? new Error("Codex search failed without returning a result");
|
|
508
|
+
}
|
|
477
509
|
|
|
478
510
|
let sources = result.sources;
|
|
479
511
|
|
|
480
|
-
|
|
481
|
-
if (
|
|
482
|
-
sources = sources.slice(0,
|
|
512
|
+
const numResults = params.numSearchResults ?? params.limit;
|
|
513
|
+
if (numResults && sources.length > numResults) {
|
|
514
|
+
sources = sources.slice(0, numResults);
|
|
483
515
|
}
|
|
484
516
|
|
|
485
517
|
return {
|
|
@@ -500,28 +532,25 @@ export async function searchCodex(params: CodexSearchParams): Promise<SearchResp
|
|
|
500
532
|
|
|
501
533
|
/**
|
|
502
534
|
* Checks if Codex web search is available.
|
|
503
|
-
* @returns True if valid OAuth credentials exist for openai-codex
|
|
504
535
|
*/
|
|
505
|
-
export async function hasCodexSearch(): Promise<boolean> {
|
|
506
|
-
|
|
507
|
-
|
|
536
|
+
export async function hasCodexSearch(authStorage: AuthStorage): Promise<boolean> {
|
|
537
|
+
// `isAvailable` runs before every request — keep the probe cheap.
|
|
538
|
+
// `hasOAuth(...)` is a synchronous in-memory check that returns true as soon
|
|
539
|
+
// as a Codex OAuth credential is loaded, without driving the refresh
|
|
540
|
+
// pipeline. The actual refresh happens lazily in `searchCodex`.
|
|
541
|
+
return authStorage.hasOAuth("openai-codex");
|
|
508
542
|
}
|
|
509
543
|
|
|
510
544
|
/** Search provider for OpenAI Codex web search. */
|
|
511
545
|
export class CodexProvider extends SearchProvider {
|
|
512
546
|
readonly id = "codex";
|
|
513
|
-
readonly label = "
|
|
547
|
+
readonly label = "OpenAI";
|
|
514
548
|
|
|
515
|
-
isAvailable(): Promise<boolean> {
|
|
516
|
-
return
|
|
549
|
+
isAvailable(authStorage: AuthStorage): Promise<boolean> | boolean {
|
|
550
|
+
return hasCodexSearch(authStorage);
|
|
517
551
|
}
|
|
518
552
|
|
|
519
553
|
search(params: SearchParams): Promise<SearchResponse> {
|
|
520
|
-
return searchCodex(
|
|
521
|
-
signal: params.signal,
|
|
522
|
-
query: params.query,
|
|
523
|
-
system_prompt: params.systemPrompt,
|
|
524
|
-
num_results: params.numSearchResults ?? params.limit,
|
|
525
|
-
});
|
|
554
|
+
return searchCodex(params);
|
|
526
555
|
}
|
|
527
556
|
}
|