@oai404iao/pi-codex-web-search 0.1.0 → 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 +6 -1
- package/package.json +9 -9
- package/src/code-mode-adapter.ts +23 -0
- package/src/index.ts +4 -1
- package/src/tools/web-search.ts +10 -9
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Alpha bootstrap candidate; initial npm publication is still pending.
|
|
4
4
|
|
|
5
|
-
Peer floor: Pi 0.
|
|
5
|
+
Peer floor: Pi 0.86.1; tested against 0.86.1.
|
|
6
6
|
|
|
7
7
|
Installs `web_search` and search activity rendering. Depends only on
|
|
8
8
|
`pi-codex-runtime`, not core, imagegen or the old bundle.
|
|
@@ -10,6 +10,11 @@ Catalog-supported standalone profiles call `alpha/search` using Pi's model
|
|
|
10
10
|
registry authentication. Hosted profiles require core; without it the tool stays
|
|
11
11
|
inactive and explicit execution reports the missing provider capability.
|
|
12
12
|
|
|
13
|
+
Optional Code Mode discovery offers `codex_web__web_search` on standalone
|
|
14
|
+
profiles only, reusing the same authentication/client and capturing turn identity
|
|
15
|
+
and history before auth I/O. It requires an exact Code Mode grant and adds no
|
|
16
|
+
Code Mode dependency. Hosted placeholders remain direct; no direct tool is hidden.
|
|
17
|
+
|
|
13
18
|
When core is present, the broker contributes response-local search capture and
|
|
14
19
|
citation signatures without a second provider registration.
|
|
15
20
|
Uses the existing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oai404iao/pi-codex-web-search",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Unpublished pi-codex-web-search workspace for the staged Codex split",
|
|
6
6
|
"type": "module",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
]
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@earendil-works/pi-ai": ">=0.
|
|
32
|
-
"@earendil-works/pi-coding-agent": ">=0.
|
|
33
|
-
"@earendil-works/pi-tui": ">=0.
|
|
31
|
+
"@earendil-works/pi-ai": ">=0.86.1",
|
|
32
|
+
"@earendil-works/pi-coding-agent": ">=0.86.1",
|
|
33
|
+
"@earendil-works/pi-tui": ">=0.86.1",
|
|
34
34
|
"typebox": "*"
|
|
35
35
|
},
|
|
36
36
|
"peerDependenciesMeta": {
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@oai404iao/pi-codex-runtime": "0.
|
|
48
|
+
"@oai404iao/pi-codex-runtime": "0.3.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@earendil-works/pi-ai": "0.
|
|
52
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
53
|
-
"@earendil-works/pi-tui": "0.
|
|
51
|
+
"@earendil-works/pi-ai": "0.86.1",
|
|
52
|
+
"@earendil-works/pi-coding-agent": "0.86.1",
|
|
53
|
+
"@earendil-works/pi-tui": "0.86.1",
|
|
54
54
|
"@types/node": "^26.2.0",
|
|
55
55
|
"tsx": "^4.20.6",
|
|
56
56
|
"typebox": "^1.1.24",
|
|
@@ -77,5 +77,5 @@
|
|
|
77
77
|
"engines": {
|
|
78
78
|
"node": ">=22.19.0"
|
|
79
79
|
},
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "b02484cecad9081886797bf9b4438135aaae1e07"
|
|
81
81
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { registerCodeModeContribution, type OwnedCodeModeTool } from "@oai404iao/pi-codex-runtime/internal/code-mode-contributions";
|
|
3
|
+
import { loadModelSettings } from "@oai404iao/pi-codex-runtime/internal/model-catalog/runtime";
|
|
4
|
+
import { standaloneWebSearch, webSearchToolSchema, type WebSearchInput } from "./tools/web-search.js";
|
|
5
|
+
|
|
6
|
+
export function registerSearchContribution(pi: ExtensionAPI): void {
|
|
7
|
+
const enabled = (ctx: ExtensionContext) => {
|
|
8
|
+
const settings = loadModelSettings(ctx.model, ctx.cwd);
|
|
9
|
+
return settings.enabled && settings.webSearchImplementation === "standalone";
|
|
10
|
+
};
|
|
11
|
+
const tool: OwnedCodeModeTool = {
|
|
12
|
+
name: "web_search", effect: "read", parallel: true,
|
|
13
|
+
description: "Run the installed Codex standalone alpha/search client with the current model/profile and Pi credentials. Returns text and structured results to JavaScript. Sends the owner's bounded recent conversation tail. Hosted placeholders are never executed; Pi direct tool hooks are not inherited.",
|
|
14
|
+
parameters: webSearchToolSchema,
|
|
15
|
+
async invoke(input, ctx) {
|
|
16
|
+
ctx.signal.throwIfAborted();
|
|
17
|
+
if (!ctx.pi || !enabled(ctx.pi)) throw new Error("Only an enabled Codex standalone search profile can be nested; hosted search stays direct");
|
|
18
|
+
const result = await standaloneWebSearch(input as WebSearchInput, ctx.pi, ctx.signal);
|
|
19
|
+
return { value: { text: result.content.map((part) => part.text).join("\n"), results: result.details.results } };
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
registerCodeModeContribution(pi, "codex_web", (ctx) => enabled(ctx) ? [tool] : []);
|
|
23
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { addPackageTool, ensureCodexServices } from "@oai404iao/pi-codex-runtime";
|
|
3
|
+
import { registerCodeModeOwnedTool } from "@oai404iao/pi-codex-runtime/internal/code-mode-contributions";
|
|
3
4
|
import { currentCodexTurn, resolveCodexRequestIdentity } from "@oai404iao/pi-codex-runtime/internal/codex-wire-identity";
|
|
4
5
|
import { createWebSearchToolDefinition } from "./tools/web-search.js";
|
|
5
6
|
import { createWebSearchCapture } from "./tools/web-search/capture.js";
|
|
6
7
|
import { registerWebSearchActivityRenderer } from "./tools/web-search/render.js";
|
|
8
|
+
import { registerSearchContribution } from "./code-mode-adapter.js";
|
|
7
9
|
|
|
8
10
|
export default function codexWebSearch(pi: ExtensionAPI): void {
|
|
9
11
|
const broker = ensureCodexServices(pi);
|
|
10
12
|
if (!broker.claim("package:web-search")) return;
|
|
13
|
+
registerSearchContribution(pi);
|
|
11
14
|
broker.addPresentation("web_search", {
|
|
12
15
|
clear() {}, flush() {}, scheduleFlush() {},
|
|
13
16
|
registerRenderers: () => registerWebSearchActivityRenderer(pi),
|
|
14
17
|
streamEffects: () => ({ createEventObserver: createWebSearchCapture }),
|
|
15
18
|
});
|
|
16
19
|
addPackageTool(broker, "web_search", () => {
|
|
17
|
-
pi
|
|
20
|
+
registerCodeModeOwnedTool(pi, createWebSearchToolDefinition({
|
|
18
21
|
getCurrentTurnId: sessionId => currentCodexTurn(sessionId)?.turnId,
|
|
19
22
|
getRequestIdentity: sessionId => resolveCodexRequestIdentity(sessionId, undefined, "turn"),
|
|
20
23
|
hasProviderRuntime: () => broker.coreEnabled,
|
package/src/tools/web-search.ts
CHANGED
|
@@ -241,6 +241,7 @@ export async function standaloneWebSearch(
|
|
|
241
241
|
signal?: AbortSignal,
|
|
242
242
|
invocation: StandaloneWebSearchInvocation = {},
|
|
243
243
|
) {
|
|
244
|
+
signal?.throwIfAborted();
|
|
244
245
|
const model = ctx.model;
|
|
245
246
|
if (!model || !ctx.modelRegistry) throw new Error("No active model is available for standalone web search.");
|
|
246
247
|
const settings = loadModelSettings(model, ctx.cwd);
|
|
@@ -257,15 +258,6 @@ export async function standaloneWebSearch(
|
|
|
257
258
|
if (input.image_query?.length && !contentTypes.includes("image")) {
|
|
258
259
|
throw new Error("Image search is disabled by the current model profile.");
|
|
259
260
|
}
|
|
260
|
-
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
261
|
-
if (!auth.ok) throw new Error(auth.error);
|
|
262
|
-
if (!hasCodexRequestAuth({
|
|
263
|
-
modelHeaders: model.headers,
|
|
264
|
-
auth: { apiKey: auth.apiKey, headers: auth.headers },
|
|
265
|
-
})) {
|
|
266
|
-
throw new Error(`No request authentication for provider: ${model.provider}`);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
261
|
const url = resolveCodexApiEndpoint(model.baseUrl, settings.apiKeyMode, "alpha/search");
|
|
270
262
|
const piSessionId = ctx.sessionManager?.getSessionId();
|
|
271
263
|
const identity = invocation.identity
|
|
@@ -293,6 +285,14 @@ export async function standaloneWebSearch(
|
|
|
293
285
|
model: model.id,
|
|
294
286
|
})
|
|
295
287
|
: undefined;
|
|
288
|
+
// A nested cell may survive a user-turn rollover while auth is pending.
|
|
289
|
+
// Identity and visible history must describe this invocation, not that later turn.
|
|
290
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
291
|
+
signal?.throwIfAborted();
|
|
292
|
+
if (!auth.ok) throw new Error(auth.error);
|
|
293
|
+
if (!hasCodexRequestAuth({ modelHeaders: model.headers, auth: { apiKey: auth.apiKey, headers: auth.headers } })) {
|
|
294
|
+
throw new Error(`No request authentication for provider: ${model.provider}`);
|
|
295
|
+
}
|
|
296
296
|
const response = await fetch(url, {
|
|
297
297
|
method: "POST",
|
|
298
298
|
headers: buildCodexJsonHeaders({
|
|
@@ -322,6 +322,7 @@ export async function standaloneWebSearch(
|
|
|
322
322
|
throw new Error(`Standalone web search failed: HTTP ${response.status}: ${await response.text()}`);
|
|
323
323
|
}
|
|
324
324
|
const result = await response.json() as StandaloneSearchResponse;
|
|
325
|
+
signal?.throwIfAborted();
|
|
325
326
|
if (typeof result.output !== "string" || !result.output.trim()) {
|
|
326
327
|
throw new Error("Standalone web search returned no output.");
|
|
327
328
|
}
|