pi-openai-toolkit 0.15.0 → 0.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-openai-toolkit",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -294,10 +294,12 @@ function createWebRunTool(deps: WebRunExecutorDependencies): ToolDefinition<
294
294
  };
295
295
  }
296
296
 
297
+ type StandaloneRegistrationState = "verified" | "excluded" | "unavailable";
298
+
297
299
  function verifyStandaloneRegistration(
298
300
  pi: ExtensionAPI,
299
301
  definition: ToolDefinition<typeof STANDALONE_WEB_RUN_PARAMETERS, AlphaSearchDetails>,
300
- ): boolean {
302
+ ): StandaloneRegistrationState {
301
303
  try {
302
304
  const api = pi as ExtensionAPI & {
303
305
  getAllTools?: () => Array<{
@@ -307,14 +309,17 @@ function verifyStandaloneRegistration(
307
309
  promptGuidelines?: string[];
308
310
  }>;
309
311
  };
310
- if (typeof api.getAllTools !== "function") return false;
312
+ if (typeof api.getAllTools !== "function") return "unavailable";
311
313
  const actual = api.getAllTools().find((tool) => tool.name === WEB_RUN_TOOL_NAME);
312
- return actual !== undefined &&
313
- actual.description === definition.description &&
314
+ // Pi publishes only tools permitted by --tools/--exclude-tools/--no-tools.
315
+ // After successful registration, an absent definition means this session
316
+ // cannot use search; it is not a reason to abort ordinary model requests.
317
+ if (actual === undefined) return "excluded";
318
+ return actual.description === definition.description &&
314
319
  actual.parameters === definition.parameters &&
315
- actual.promptGuidelines === definition.promptGuidelines;
320
+ actual.promptGuidelines === definition.promptGuidelines ? "verified" : "unavailable";
316
321
  } catch {
317
- return false;
322
+ return "unavailable";
318
323
  }
319
324
  }
320
325
 
@@ -399,8 +404,8 @@ export function registerWebSearchExtension(
399
404
  standaloneRegistrationSucceeded = false;
400
405
  }
401
406
 
402
- function standaloneReady(): boolean {
403
- if (!standaloneRegistrationSucceeded || !canManageActiveTools(pi)) return false;
407
+ function standaloneRegistrationState(): StandaloneRegistrationState {
408
+ if (!standaloneRegistrationSucceeded || !canManageActiveTools(pi)) return "unavailable";
404
409
  // Recheck on every lifecycle boundary so a later extension cannot replace
405
410
  // the definition after startup and leave a stale active name executable.
406
411
  // Do not use getAllTools() during extension loading; lifecycle callbacks
@@ -408,6 +413,10 @@ export function registerWebSearchExtension(
408
413
  return verifyStandaloneRegistration(pi, standaloneTool);
409
414
  }
410
415
 
416
+ function standaloneReady(): boolean {
417
+ return standaloneRegistrationState() === "verified";
418
+ }
419
+
411
420
  function readConfig(model: WebSearchModel | undefined, ctx?: ExtensionContext): ResolvedToolkitConfig {
412
421
  const resolved = resolveToolkitConfig(loadConfig(), model);
413
422
  if (ctx) notifyConfigIssues(ctx, resolved);
@@ -459,13 +468,15 @@ export function registerWebSearchExtension(
459
468
  catch (error) { abortAndThrow(ctx, error instanceof Error ? error.message : "Invalid Web Search configuration."); }
460
469
  const { config } = resolved;
461
470
  const resolution = synchronizeResolved(ctx.model, resolved);
462
- if (resolution.route === "standalone-alpha" && resolution.available && !standaloneReady()) {
471
+ const registration = standaloneRegistrationState();
472
+ if (resolution.route === "standalone-alpha" && resolution.available && registration === "unavailable") {
463
473
  abortAndThrow(ctx, `${WEB_RUN_TOOL_NAME} is not registered by the toolkit; standalone Web Search request aborted.`);
464
474
  }
465
475
  const transformed = transformWebSearchPayload({
466
476
  model: ctx.model,
467
477
  config: config.webSearch,
468
478
  payload: event.payload,
479
+ standaloneToolExcluded: registration === "excluded",
469
480
  });
470
481
  if (transformed.fatal) {
471
482
  abortAndThrow(ctx, transformed.errorMessage ?? "Web Search route request aborted.");
@@ -49,8 +49,9 @@ function unavailableRouteTransform(
49
49
  function transformStandalonePayload(args: {
50
50
  payload: JsonObject;
51
51
  resolution: ReturnType<typeof resolveWebSearchRoute>;
52
+ standaloneToolExcluded?: boolean;
52
53
  }): WebSearchPayloadTransform {
53
- const { payload, resolution } = args;
54
+ const { payload, resolution, standaloneToolExcluded = false } = args;
54
55
  const toolsValue = payload.tools;
55
56
  if (toolsValue !== undefined && !Array.isArray(toolsValue)) {
56
57
  return {
@@ -77,6 +78,7 @@ function transformStandalonePayload(args: {
77
78
  const normalizedTools = tools.filter((tool) => {
78
79
  if (isLocalWebSearchFunction(tool) || isNativeWebSearchTool(tool)) return false;
79
80
  if (!isStandaloneWebRunFunction(tool)) return true;
81
+ if (standaloneToolExcluded) return false;
80
82
  standaloneToolCount += 1;
81
83
  return standaloneToolCount === 1;
82
84
  });
@@ -84,7 +86,7 @@ function transformStandalonePayload(args: {
84
86
  const normalizedInclude = include.filter((item) => item !== WEB_SEARCH_SOURCE_INCLUDE);
85
87
  const toolsChanged = normalizedTools.length !== tools.length;
86
88
  const includeChanged = normalizedInclude.length !== include.length;
87
- if (toolsValue !== undefined && !normalizedTools.some(isStandaloneWebRunFunction)) {
89
+ if (!standaloneToolExcluded && toolsValue !== undefined && !normalizedTools.some(isStandaloneWebRunFunction)) {
88
90
  return {
89
91
  payload,
90
92
  outcome: "unavailable-route",
@@ -159,6 +161,8 @@ export function transformWebSearchPayload(args: {
159
161
  model: WebSearchModel | undefined;
160
162
  config: WebSearchConfig;
161
163
  payload: unknown;
164
+ /** The host filtered a successfully registered web_run out of this session's tool catalog. */
165
+ standaloneToolExcluded?: boolean;
162
166
  }): WebSearchPayloadTransform {
163
167
  const { model, config, payload } = args;
164
168
  const resolution = resolveWebSearchRoute({ model, config });
@@ -195,7 +199,7 @@ export function transformWebSearchPayload(args: {
195
199
  errorMessage: "Standalone Web Search requires an object provider payload.",
196
200
  };
197
201
  }
198
- return transformStandalonePayload({ payload, resolution });
202
+ return transformStandalonePayload({ payload, resolution, standaloneToolExcluded: args.standaloneToolExcluded });
199
203
  }
200
204
 
201
205
  if (!isRecord(payload)) {