@dbx-tools/appkit-web-search 0.9.70 → 0.9.72

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/lib/src/tool.js CHANGED
@@ -26,7 +26,7 @@ import { createTool } from "@mastra/core/tools";
26
26
  import { approvalMatches, toApprovalPolicy, } from "./config.js";
27
27
  import { runWebFetch } from "./fetch.js";
28
28
  import { createWebSearchRuntime } from "./runtime.js";
29
- import { webFetchRequestSchema, webFetchResultSchema, webSearchRequestSchema, webSearchResultSchema, WEB_FETCH_TOOL_DESCRIPTION, WEB_SEARCH_TOOL_DESCRIPTION, } from "./schema.js";
29
+ import { webFetchRequestSchema, webFetchResultSchema, webSearchToolRequestSchema, webSearchResultSchema, WEB_FETCH_TOOL_DESCRIPTION, WEB_SEARCH_TOOL_DESCRIPTION, } from "./schema.js";
30
30
  import { resolveWebSearchContext, runWebSearch } from "./search.js";
31
31
  /**
32
32
  * Validate a tool call's arguments at the runtime boundary. Mastra checks the
@@ -73,13 +73,13 @@ export function webSearchTool(opts = {}) {
73
73
  return createTool({
74
74
  id: opts.id ?? "web_search",
75
75
  description: WEB_SEARCH_TOOL_DESCRIPTION,
76
- inputSchema: webSearchRequestSchema,
76
+ inputSchema: webSearchToolRequestSchema,
77
77
  outputSchema: webSearchResultSchema,
78
78
  // A search's result URLs aren't known before the call, so a pattern gate
79
79
  // is treated as "always gate".
80
80
  ...(gate.mode === "none" ? {} : { requireApproval: () => true }),
81
81
  execute: async (input) => {
82
- const request = parseToolInput(webSearchRequestSchema, input);
82
+ const request = parseToolInput(webSearchToolRequestSchema, input);
83
83
  return runWebSearch(request, runtime, await resolveWebSearchContext());
84
84
  },
85
85
  });
@@ -116,4 +116,4 @@ export function webFetchTool(opts = {}) {
116
116
  },
117
117
  });
118
118
  }
119
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90b29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVoRCxPQUFPLEVBQ0wsZUFBZSxFQUNmLGdCQUFnQixHQUlqQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxzQkFBc0IsRUFBeUIsTUFBTSxjQUFjLENBQUM7QUFDN0UsT0FBTyxFQUNMLHFCQUFxQixFQUNyQixvQkFBb0IsRUFDcEIsc0JBQXNCLEVBQ3RCLHFCQUFxQixFQUNyQiwwQkFBMEIsRUFDMUIsMkJBQTJCLEdBQzVCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxZQUFZLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFcEU7Ozs7O0dBS0c7QUFDSCxTQUFTLGNBQWMsQ0FBc0IsTUFBUyxFQUFFLEtBQWM7SUFDcEUsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2QyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3BCLE1BQU0sZUFBZSxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLHNDQUFzQyxDQUFDLENBQUM7SUFDN0YsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQztBQUNyQixDQUFDO0FBa0JELDRFQUE0RTtBQUM1RSxTQUFTLFdBQVcsQ0FBQyxJQUEwQjtJQUM3QyxJQUFJLElBQUksQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ2hDLE1BQU0sSUFBSSxTQUFTLENBQUMsbUVBQW1FLENBQUMsQ0FBQztJQUMzRixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUMsT0FBTyxJQUFJLHNCQUFzQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBRUQsa0ZBQWtGO0FBQ2xGLFNBQVMsYUFBYSxDQUFDLElBQTBCLEVBQUUsT0FBeUI7SUFDMUUsT0FBTyxJQUFJLENBQUMsUUFBUSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUNqRyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLE9BQTZCLEVBQUU7SUFDM0QsTUFBTSxPQUFPLEdBQUcsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sSUFBSSxHQUFHLGFBQWEsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDMUMsT0FBTyxVQUFVLENBQUM7UUFDaEIsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLElBQUksWUFBWTtRQUMzQixXQUFXLEVBQUUsMkJBQTJCO1FBQ3hDLFdBQVcsRUFBRSxzQkFBc0I7UUFDbkMsWUFBWSxFQUFFLHFCQUFxQjtRQUNuQyx5RUFBeUU7UUFDekUsK0JBQStCO1FBQy9CLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLGVBQWUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNoRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3ZCLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQyxzQkFBc0IsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM5RCxPQUFPLFlBQVksQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sdUJBQXVCLEVBQUUsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsT0FBNkIsRUFBRTtJQUMxRCxNQUFNLE9BQU8sR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMxQyxPQUFPLFVBQVUsQ0FBQztRQUNoQixFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUsSUFBSSxXQUFXO1FBQzFCLFdBQVcsRUFBRSwwQkFBMEI7UUFDdkMsV0FBVyxFQUFFLHFCQUFxQjtRQUNsQyxZQUFZLEVBQUUsb0JBQW9CO1FBQ2xDLHNFQUFzRTtRQUN0RSx3QkFBd0I7UUFDeEIsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssTUFBTTtZQUN0QixDQUFDLENBQUMsRUFBRTtZQUNKLENBQUMsQ0FBQztnQkFDRSxlQUFlLEVBQUUsQ0FBQyxLQUFjLEVBQUUsRUFBRSxDQUNsQyxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVE7b0JBQ3RCLGVBQWUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxjQUFjLENBQUMscUJBQXFCLEVBQUUsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDNUUsQ0FBQztRQUNOLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDdkIsT0FBTyxXQUFXLENBQUMsY0FBYyxDQUFDLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzVFLENBQUM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGUgYHdlYl9zZWFyY2hgIGFuZCBgd2ViX2ZldGNoYCBNYXN0cmEgdG9vbHMuXG4gKlxuICogYHdlYl9zZWFyY2hgIGlzIGJhY2tlZCBieSB0aGUgRGF0YWJyaWNrcyBNb2RlbCBTZXJ2aW5nIG5hdGl2ZSB3ZWItc2VhcmNoXG4gKiB0b29sOiBpdCByZXNvbHZlcyBpdHMgb3duIHdlYi1zZWFyY2gtY2FwYWJsZSBtb2RlbCAoc2VlIGBzZWFyY2gudHNgKSBhbmRcbiAqIGNhbGxzIHRoZSB3b3Jrc3BhY2Ugc2VydmluZyBlbmRwb2ludCB1bmRlciB0aGUgY2FsbGVyJ3MgT0JPIHNjb3BlLCBzbyB0aGVcbiAqIHNlYXJjaCBydW5zIGFzIHRoZSByZXF1ZXN0aW5nIHVzZXIgYW5kIGluZGVwZW5kZW50bHkgb2YgdGhlIGFnZW50J3MgY2hhdFxuICogbW9kZWwuIGB3ZWJfZmV0Y2hgIHJlYWRzIGEgcGFnZSB2aWEgZ290LXNjcmFwaW5nLlxuICpcbiAqIEJvdGggYXJlIHJlYWQtb25seSBhbmQgcnVuIHdpdGhvdXQgYXBwcm92YWwgYnkgZGVmYXVsdDsgZWFjaCBhY2NlcHRzIGFuXG4gKiBvcHRpb25hbCB7QGxpbmsgQXBwcm92YWxHYXRlfSAoYGFwcHJvdmFsYCkgdGhhdCBtYXBzIG9udG8gTWFzdHJhJ3NcbiAqIGByZXF1aXJlQXBwcm92YWxgLiBgdHJ1ZWAgZ2F0ZXMgZXZlcnkgY2FsbDsgYSBVUkwtcGF0dGVybiAob3Ige0BsaW5rIE9uZU9yTWFueX1cbiAqIGxpc3QpIGdhdGVzIG9ubHkgY2FsbHMgd2hvc2UgVVJMIG1hdGNoZXMgLSBmb3IgYHdlYl9mZXRjaGAgdGhhdCBpcyBldmFsdWF0ZWRcbiAqIGFnYWluc3QgdGhlIHRhcmdldCBVUkwsIHdoaWxlIGB3ZWJfc2VhcmNoYCAod2hvc2UgcmVzdWx0IFVSTHMgYXJlbid0IGtub3duXG4gKiBiZWZvcmUgdGhlIGNhbGwpIHRyZWF0cyBhIHBhdHRlcm4gZ2F0ZSBhcyBcImFsd2F5cyBnYXRlXCIuIGBhcHByb3ZhbGAgZmFsbHNcbiAqIGJhY2sgdG8gdGhlIHN0YW5kYWxvbmUgcnVudGltZSdzIGBhcHByb3ZhbGAgY29uZmlnIHdoZW4gYSB0b29sIG9taXRzIGl0cyBvd24uXG4gKlxuICogQXBwLWludGVncmF0ZWQgYWdlbnRzIHNob3VsZCBjb25zdW1lIHRoZSBwbHVnaW4ncyBuYXRpdmUgdG9vbGtpdCBzbyBjYWxsc1xuICogcmV0YWluIHRoYXQgcGx1Z2luJ3MgcG9saWN5IGFuZCBleGVjdXRvci4gVGhlc2UgZmFjdG9yaWVzIGFyZSB0aGUgc3RhbmRhbG9uZVxuICogTWFzdHJhIHN1cmZhY2UgYW5kIGNhcHR1cmUgYW4gZXhwbGljaXQgcnVudGltZSBvciBpc29sYXRlZCBjb25maWcuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGNyZWF0ZVRvb2wgfSBmcm9tIFwiQG1hc3RyYS9jb3JlL3Rvb2xzXCI7XG5pbXBvcnQgdHlwZSB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQge1xuICBhcHByb3ZhbE1hdGNoZXMsXG4gIHRvQXBwcm92YWxQb2xpY3ksXG4gIHR5cGUgQXBwcm92YWxHYXRlLFxuICB0eXBlIEFwcHJvdmFsUG9saWN5LFxuICB0eXBlIFdlYlNlYXJjaFBsdWdpbkNvbmZpZyxcbn0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5pbXBvcnQgeyBydW5XZWJGZXRjaCB9IGZyb20gXCIuL2ZldGNoLnRzXCI7XG5pbXBvcnQgeyBjcmVhdGVXZWJTZWFyY2hSdW50aW1lLCB0eXBlIFdlYlNlYXJjaFJ1bnRpbWUgfSBmcm9tIFwiLi9ydW50aW1lLnRzXCI7XG5pbXBvcnQge1xuICB3ZWJGZXRjaFJlcXVlc3RTY2hlbWEsXG4gIHdlYkZldGNoUmVzdWx0U2NoZW1hLFxuICB3ZWJTZWFyY2hSZXF1ZXN0U2NoZW1hLFxuICB3ZWJTZWFyY2hSZXN1bHRTY2hlbWEsXG4gIFdFQl9GRVRDSF9UT09MX0RFU0NSSVBUSU9OLFxuICBXRUJfU0VBUkNIX1RPT0xfREVTQ1JJUFRJT04sXG59IGZyb20gXCIuL3NjaGVtYS50c1wiO1xuaW1wb3J0IHsgcmVzb2x2ZVdlYlNlYXJjaENvbnRleHQsIHJ1bldlYlNlYXJjaCB9IGZyb20gXCIuL3NlYXJjaC50c1wiO1xuXG4vKipcbiAqIFZhbGlkYXRlIGEgdG9vbCBjYWxsJ3MgYXJndW1lbnRzIGF0IHRoZSBydW50aW1lIGJvdW5kYXJ5LiBNYXN0cmEgY2hlY2tzIHRoZVxuICogaW5wdXQgc2NoZW1hIGJlZm9yZSBkaXNwYXRjaCwgYnV0IHRoZSBhcmd1bWVudCBzdGlsbCBhcnJpdmVzIHR5cGVkIGFzXG4gKiBgdW5rbm93bmAgYW5kIHRoZSBtb2RlbCBpcyB0aGUgb25lIGZpbGxpbmcgaXQgaW4uIFRoZSByZWplY3RlZCB2YWx1ZSBpcyBub3RcbiAqIGVjaG9lZCBiYWNrLlxuICovXG5mdW5jdGlvbiBwYXJzZVRvb2xJbnB1dDxTIGV4dGVuZHMgei5ab2RUeXBlPihzY2hlbWE6IFMsIGlucHV0OiB1bmtub3duKTogei5pbmZlcjxTPiB7XG4gIGNvbnN0IHBhcnNlZCA9IHNjaGVtYS5zYWZlUGFyc2UoaW5wdXQpO1xuICBpZiAoIXBhcnNlZC5zdWNjZXNzKSB7XG4gICAgdGhyb3cgVmFsaWRhdGlvbkVycm9yLmludmFsaWRWYWx1ZShcImlucHV0XCIsIGlucHV0LCBcImFyZ3VtZW50cyBtYXRjaGluZyB0aGUgdG9vbCdzIHNjaGVtYVwiKTtcbiAgfVxuICByZXR1cm4gcGFyc2VkLmRhdGE7XG59XG5cbi8qKiBPcHRpb25zIHNoYXJlZCBieSBib3RoIHdlYiB0b29scy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV2ViU2VhcmNoVG9vbE9wdGlvbnMge1xuICAvKiogT3ZlcnJpZGUgdGhlIHRvb2wgaWQuICovXG4gIGlkPzogc3RyaW5nO1xuICAvKiogSXNvbGF0ZWQgcnVudGltZSB1c2VkIGJ5IHRoaXMgc3RhbmRhbG9uZSB0b29sLiBNdXR1YWxseSBleGNsdXNpdmUgd2l0aCBgY29uZmlnYC4gKi9cbiAgcnVudGltZT86IFdlYlNlYXJjaFJ1bnRpbWU7XG4gIC8qKiBDb25maWcgdXNlZCB0byBjcmVhdGUgYW4gaXNvbGF0ZWQgZGlyZWN0LWV4ZWN1dGlvbiBydW50aW1lLiAqL1xuICBjb25maWc/OiBXZWJTZWFyY2hQbHVnaW5Db25maWc7XG4gIC8qKlxuICAgKiBBcHByb3ZhbCBnYXRlIGZvciB0aGlzIHRvb2wsIG92ZXJyaWRpbmcgdGhlIHJ1bnRpbWUncyBgYXBwcm92YWxgLiBgdHJ1ZWBcbiAgICogZ2F0ZXMgZXZlcnkgY2FsbDsgYSBVUkwtcGF0dGVybiAob3IgbGlzdCkgZ2F0ZXMgb25seSBtYXRjaGluZyBjYWxscztcbiAgICogb21pdCAvIGBmYWxzZWAgZm9yIG5vIGFwcHJvdmFsLiBTZWUge0BsaW5rIEFwcHJvdmFsR2F0ZX0uXG4gICAqL1xuICBhcHByb3ZhbD86IEFwcHJvdmFsR2F0ZSB8IEFwcHJvdmFsUG9saWN5O1xufVxuXG4vKiogUmVzb2x2ZSB0aGUgaXNvbGF0ZWQgcnVudGltZSBjYXB0dXJlZCBieSBvbmUgc3RhbmRhbG9uZSB0b29sIGZhY3RvcnkuICovXG5mdW5jdGlvbiB0b29sUnVudGltZShvcHRzOiBXZWJTZWFyY2hUb29sT3B0aW9ucyk6IFdlYlNlYXJjaFJ1bnRpbWUge1xuICBpZiAob3B0cy5ydW50aW1lICYmIG9wdHMuY29uZmlnKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIndlYi1zZWFyY2ggdG9vbCBvcHRpb25zIGFjY2VwdCBlaXRoZXIgcnVudGltZSBvciBjb25maWcsIG5vdCBib3RoXCIpO1xuICB9XG4gIHJldHVybiBvcHRzLnJ1bnRpbWUgPz8gY3JlYXRlV2ViU2VhcmNoUnVudGltZShvcHRzLmNvbmZpZyk7XG59XG5cbi8qKiBSZXNvbHZlIHRoZSBlZmZlY3RpdmUgZ2F0ZTogZXhwbGljaXQgdG9vbCBvcHRpb24sIGVsc2UgdGhlIHJ1bnRpbWUgZGVmYXVsdC4gKi9cbmZ1bmN0aW9uIGVmZmVjdGl2ZUdhdGUob3B0czogV2ViU2VhcmNoVG9vbE9wdGlvbnMsIHJ1bnRpbWU6IFdlYlNlYXJjaFJ1bnRpbWUpOiBBcHByb3ZhbFBvbGljeSB7XG4gIHJldHVybiBvcHRzLmFwcHJvdmFsID09PSB1bmRlZmluZWQgPyBydW50aW1lLmNvbmZpZy5hcHByb3ZhbCA6IHRvQXBwcm92YWxQb2xpY3kob3B0cy5hcHByb3ZhbCk7XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIGB3ZWJfc2VhcmNoYCB0b29sLiBTcHJlYWQgaXQgaW50byB0aGUgYWdlbnRzIHRoYXQgc2hvdWxkIGJlIGFibGVcbiAqIHRvIHNlYXJjaCB0aGUgd2ViLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgd2ViU2VhcmNoVG9vbCB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdC13ZWItc2VhcmNoXCI7XG4gKiBpbXBvcnQgeyBjcmVhdGVBZ2VudCB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdC1tYXN0cmFcIjtcbiAqXG4gKiBjb25zdCByZXNlYXJjaGVyID0gY3JlYXRlQWdlbnQoe1xuICogICBpbnN0cnVjdGlvbnM6IFwiLi4uXCIsXG4gKiAgIHRvb2xzOiAoKSA9PiAoeyB3ZWJfc2VhcmNoOiB3ZWJTZWFyY2hUb29sKCkgfSksXG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gd2ViU2VhcmNoVG9vbChvcHRzOiBXZWJTZWFyY2hUb29sT3B0aW9ucyA9IHt9KSB7XG4gIGNvbnN0IHJ1bnRpbWUgPSB0b29sUnVudGltZShvcHRzKTtcbiAgY29uc3QgZ2F0ZSA9IGVmZmVjdGl2ZUdhdGUob3B0cywgcnVudGltZSk7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogb3B0cy5pZCA/PyBcIndlYl9zZWFyY2hcIixcbiAgICBkZXNjcmlwdGlvbjogV0VCX1NFQVJDSF9UT09MX0RFU0NSSVBUSU9OLFxuICAgIGlucHV0U2NoZW1hOiB3ZWJTZWFyY2hSZXF1ZXN0U2NoZW1hLFxuICAgIG91dHB1dFNjaGVtYTogd2ViU2VhcmNoUmVzdWx0U2NoZW1hLFxuICAgIC8vIEEgc2VhcmNoJ3MgcmVzdWx0IFVSTHMgYXJlbid0IGtub3duIGJlZm9yZSB0aGUgY2FsbCwgc28gYSBwYXR0ZXJuIGdhdGVcbiAgICAvLyBpcyB0cmVhdGVkIGFzIFwiYWx3YXlzIGdhdGVcIi5cbiAgICAuLi4oZ2F0ZS5tb2RlID09PSBcIm5vbmVcIiA/IHt9IDogeyByZXF1aXJlQXBwcm92YWw6ICgpID0+IHRydWUgfSksXG4gICAgZXhlY3V0ZTogYXN5bmMgKGlucHV0KSA9PiB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gcGFyc2VUb29sSW5wdXQod2ViU2VhcmNoUmVxdWVzdFNjaGVtYSwgaW5wdXQpO1xuICAgICAgcmV0dXJuIHJ1bldlYlNlYXJjaChyZXF1ZXN0LCBydW50aW1lLCBhd2FpdCByZXNvbHZlV2ViU2VhcmNoQ29udGV4dCgpKTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgYHdlYl9mZXRjaGAgdG9vbC4gU3ByZWFkIGl0IGludG8gdGhlIGFnZW50cyB0aGF0IHNob3VsZCBiZSBhYmxlXG4gKiB0byByZWFkIGEgcGFnZSdzIGNvbnRlbnRzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgd2ViRmV0Y2hUb29sIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0LXdlYi1zZWFyY2hcIjtcbiAqXG4gKiB0b29sczogKCkgPT4gKHsgd2ViX2ZldGNoOiB3ZWJGZXRjaFRvb2woeyBhcHByb3ZhbDogXCIqLmludGVybmFsLmV4YW1wbGUuY29tXCIgfSkgfSlcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gd2ViRmV0Y2hUb29sKG9wdHM6IFdlYlNlYXJjaFRvb2xPcHRpb25zID0ge30pIHtcbiAgY29uc3QgcnVudGltZSA9IHRvb2xSdW50aW1lKG9wdHMpO1xuICBjb25zdCBnYXRlID0gZWZmZWN0aXZlR2F0ZShvcHRzLCBydW50aW1lKTtcbiAgcmV0dXJuIGNyZWF0ZVRvb2woe1xuICAgIGlkOiBvcHRzLmlkID8/IFwid2ViX2ZldGNoXCIsXG4gICAgZGVzY3JpcHRpb246IFdFQl9GRVRDSF9UT09MX0RFU0NSSVBUSU9OLFxuICAgIGlucHV0U2NoZW1hOiB3ZWJGZXRjaFJlcXVlc3RTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiB3ZWJGZXRjaFJlc3VsdFNjaGVtYSxcbiAgICAvLyBBIGZldGNoIGtub3dzIGl0cyBzaW5nbGUgdGFyZ2V0IFVSTCwgc28gYSBwYXR0ZXJuIGdhdGUgaXMgZXZhbHVhdGVkXG4gICAgLy8gcHJlY2lzZWx5IGFnYWluc3QgaXQuXG4gICAgLi4uKGdhdGUubW9kZSA9PT0gXCJub25lXCJcbiAgICAgID8ge31cbiAgICAgIDoge1xuICAgICAgICAgIHJlcXVpcmVBcHByb3ZhbDogKGlucHV0OiB1bmtub3duKSA9PlxuICAgICAgICAgICAgZ2F0ZS5tb2RlID09PSBcImFsd2F5c1wiIHx8XG4gICAgICAgICAgICBhcHByb3ZhbE1hdGNoZXMoZ2F0ZSwgW3BhcnNlVG9vbElucHV0KHdlYkZldGNoUmVxdWVzdFNjaGVtYSwgaW5wdXQpLnVybF0pLFxuICAgICAgICB9KSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQpID0+IHtcbiAgICAgIHJldHVybiBydW5XZWJGZXRjaChwYXJzZVRvb2xJbnB1dCh3ZWJGZXRjaFJlcXVlc3RTY2hlbWEsIGlucHV0KSwgcnVudGltZSk7XG4gICAgfSxcbiAgfSk7XG59XG4iXX0=
119
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90b29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVoRCxPQUFPLEVBQ0wsZUFBZSxFQUNmLGdCQUFnQixHQUlqQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxzQkFBc0IsRUFBeUIsTUFBTSxjQUFjLENBQUM7QUFDN0UsT0FBTyxFQUNMLHFCQUFxQixFQUNyQixvQkFBb0IsRUFDcEIsMEJBQTBCLEVBQzFCLHFCQUFxQixFQUNyQiwwQkFBMEIsRUFDMUIsMkJBQTJCLEdBQzVCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxZQUFZLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFcEU7Ozs7O0dBS0c7QUFDSCxTQUFTLGNBQWMsQ0FBc0IsTUFBUyxFQUFFLEtBQWM7SUFDcEUsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2QyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3BCLE1BQU0sZUFBZSxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLHNDQUFzQyxDQUFDLENBQUM7SUFDN0YsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQztBQUNyQixDQUFDO0FBa0JELDRFQUE0RTtBQUM1RSxTQUFTLFdBQVcsQ0FBQyxJQUEwQjtJQUM3QyxJQUFJLElBQUksQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ2hDLE1BQU0sSUFBSSxTQUFTLENBQUMsbUVBQW1FLENBQUMsQ0FBQztJQUMzRixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUMsT0FBTyxJQUFJLHNCQUFzQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBRUQsa0ZBQWtGO0FBQ2xGLFNBQVMsYUFBYSxDQUFDLElBQTBCLEVBQUUsT0FBeUI7SUFDMUUsT0FBTyxJQUFJLENBQUMsUUFBUSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUNqRyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLE9BQTZCLEVBQUU7SUFDM0QsTUFBTSxPQUFPLEdBQUcsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sSUFBSSxHQUFHLGFBQWEsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDMUMsT0FBTyxVQUFVLENBQUM7UUFDaEIsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLElBQUksWUFBWTtRQUMzQixXQUFXLEVBQUUsMkJBQTJCO1FBQ3hDLFdBQVcsRUFBRSwwQkFBMEI7UUFDdkMsWUFBWSxFQUFFLHFCQUFxQjtRQUNuQyx5RUFBeUU7UUFDekUsK0JBQStCO1FBQy9CLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLGVBQWUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNoRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3ZCLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQywwQkFBMEIsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsRSxPQUFPLFlBQVksQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sdUJBQXVCLEVBQUUsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsT0FBNkIsRUFBRTtJQUMxRCxNQUFNLE9BQU8sR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMxQyxPQUFPLFVBQVUsQ0FBQztRQUNoQixFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUsSUFBSSxXQUFXO1FBQzFCLFdBQVcsRUFBRSwwQkFBMEI7UUFDdkMsV0FBVyxFQUFFLHFCQUFxQjtRQUNsQyxZQUFZLEVBQUUsb0JBQW9CO1FBQ2xDLHNFQUFzRTtRQUN0RSx3QkFBd0I7UUFDeEIsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssTUFBTTtZQUN0QixDQUFDLENBQUMsRUFBRTtZQUNKLENBQUMsQ0FBQztnQkFDRSxlQUFlLEVBQUUsQ0FBQyxLQUFjLEVBQUUsRUFBRSxDQUNsQyxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVE7b0JBQ3RCLGVBQWUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxjQUFjLENBQUMscUJBQXFCLEVBQUUsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDNUUsQ0FBQztRQUNOLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDdkIsT0FBTyxXQUFXLENBQUMsY0FBYyxDQUFDLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzVFLENBQUM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGUgYHdlYl9zZWFyY2hgIGFuZCBgd2ViX2ZldGNoYCBNYXN0cmEgdG9vbHMuXG4gKlxuICogYHdlYl9zZWFyY2hgIGlzIGJhY2tlZCBieSB0aGUgRGF0YWJyaWNrcyBNb2RlbCBTZXJ2aW5nIG5hdGl2ZSB3ZWItc2VhcmNoXG4gKiB0b29sOiBpdCByZXNvbHZlcyBpdHMgb3duIHdlYi1zZWFyY2gtY2FwYWJsZSBtb2RlbCAoc2VlIGBzZWFyY2gudHNgKSBhbmRcbiAqIGNhbGxzIHRoZSB3b3Jrc3BhY2Ugc2VydmluZyBlbmRwb2ludCB1bmRlciB0aGUgY2FsbGVyJ3MgT0JPIHNjb3BlLCBzbyB0aGVcbiAqIHNlYXJjaCBydW5zIGFzIHRoZSByZXF1ZXN0aW5nIHVzZXIgYW5kIGluZGVwZW5kZW50bHkgb2YgdGhlIGFnZW50J3MgY2hhdFxuICogbW9kZWwuIGB3ZWJfZmV0Y2hgIHJlYWRzIGEgcGFnZSB2aWEgZ290LXNjcmFwaW5nLlxuICpcbiAqIEJvdGggYXJlIHJlYWQtb25seSBhbmQgcnVuIHdpdGhvdXQgYXBwcm92YWwgYnkgZGVmYXVsdDsgZWFjaCBhY2NlcHRzIGFuXG4gKiBvcHRpb25hbCB7QGxpbmsgQXBwcm92YWxHYXRlfSAoYGFwcHJvdmFsYCkgdGhhdCBtYXBzIG9udG8gTWFzdHJhJ3NcbiAqIGByZXF1aXJlQXBwcm92YWxgLiBgdHJ1ZWAgZ2F0ZXMgZXZlcnkgY2FsbDsgYSBVUkwtcGF0dGVybiAob3Ige0BsaW5rIE9uZU9yTWFueX1cbiAqIGxpc3QpIGdhdGVzIG9ubHkgY2FsbHMgd2hvc2UgVVJMIG1hdGNoZXMgLSBmb3IgYHdlYl9mZXRjaGAgdGhhdCBpcyBldmFsdWF0ZWRcbiAqIGFnYWluc3QgdGhlIHRhcmdldCBVUkwsIHdoaWxlIGB3ZWJfc2VhcmNoYCAod2hvc2UgcmVzdWx0IFVSTHMgYXJlbid0IGtub3duXG4gKiBiZWZvcmUgdGhlIGNhbGwpIHRyZWF0cyBhIHBhdHRlcm4gZ2F0ZSBhcyBcImFsd2F5cyBnYXRlXCIuIGBhcHByb3ZhbGAgZmFsbHNcbiAqIGJhY2sgdG8gdGhlIHN0YW5kYWxvbmUgcnVudGltZSdzIGBhcHByb3ZhbGAgY29uZmlnIHdoZW4gYSB0b29sIG9taXRzIGl0cyBvd24uXG4gKlxuICogQXBwLWludGVncmF0ZWQgYWdlbnRzIHNob3VsZCBjb25zdW1lIHRoZSBwbHVnaW4ncyBuYXRpdmUgdG9vbGtpdCBzbyBjYWxsc1xuICogcmV0YWluIHRoYXQgcGx1Z2luJ3MgcG9saWN5IGFuZCBleGVjdXRvci4gVGhlc2UgZmFjdG9yaWVzIGFyZSB0aGUgc3RhbmRhbG9uZVxuICogTWFzdHJhIHN1cmZhY2UgYW5kIGNhcHR1cmUgYW4gZXhwbGljaXQgcnVudGltZSBvciBpc29sYXRlZCBjb25maWcuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGNyZWF0ZVRvb2wgfSBmcm9tIFwiQG1hc3RyYS9jb3JlL3Rvb2xzXCI7XG5pbXBvcnQgdHlwZSB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQge1xuICBhcHByb3ZhbE1hdGNoZXMsXG4gIHRvQXBwcm92YWxQb2xpY3ksXG4gIHR5cGUgQXBwcm92YWxHYXRlLFxuICB0eXBlIEFwcHJvdmFsUG9saWN5LFxuICB0eXBlIFdlYlNlYXJjaFBsdWdpbkNvbmZpZyxcbn0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5pbXBvcnQgeyBydW5XZWJGZXRjaCB9IGZyb20gXCIuL2ZldGNoLnRzXCI7XG5pbXBvcnQgeyBjcmVhdGVXZWJTZWFyY2hSdW50aW1lLCB0eXBlIFdlYlNlYXJjaFJ1bnRpbWUgfSBmcm9tIFwiLi9ydW50aW1lLnRzXCI7XG5pbXBvcnQge1xuICB3ZWJGZXRjaFJlcXVlc3RTY2hlbWEsXG4gIHdlYkZldGNoUmVzdWx0U2NoZW1hLFxuICB3ZWJTZWFyY2hUb29sUmVxdWVzdFNjaGVtYSxcbiAgd2ViU2VhcmNoUmVzdWx0U2NoZW1hLFxuICBXRUJfRkVUQ0hfVE9PTF9ERVNDUklQVElPTixcbiAgV0VCX1NFQVJDSF9UT09MX0RFU0NSSVBUSU9OLFxufSBmcm9tIFwiLi9zY2hlbWEudHNcIjtcbmltcG9ydCB7IHJlc29sdmVXZWJTZWFyY2hDb250ZXh0LCBydW5XZWJTZWFyY2ggfSBmcm9tIFwiLi9zZWFyY2gudHNcIjtcblxuLyoqXG4gKiBWYWxpZGF0ZSBhIHRvb2wgY2FsbCdzIGFyZ3VtZW50cyBhdCB0aGUgcnVudGltZSBib3VuZGFyeS4gTWFzdHJhIGNoZWNrcyB0aGVcbiAqIGlucHV0IHNjaGVtYSBiZWZvcmUgZGlzcGF0Y2gsIGJ1dCB0aGUgYXJndW1lbnQgc3RpbGwgYXJyaXZlcyB0eXBlZCBhc1xuICogYHVua25vd25gIGFuZCB0aGUgbW9kZWwgaXMgdGhlIG9uZSBmaWxsaW5nIGl0IGluLiBUaGUgcmVqZWN0ZWQgdmFsdWUgaXMgbm90XG4gKiBlY2hvZWQgYmFjay5cbiAqL1xuZnVuY3Rpb24gcGFyc2VUb29sSW5wdXQ8UyBleHRlbmRzIHouWm9kVHlwZT4oc2NoZW1hOiBTLCBpbnB1dDogdW5rbm93bik6IHouaW5mZXI8Uz4ge1xuICBjb25zdCBwYXJzZWQgPSBzY2hlbWEuc2FmZVBhcnNlKGlucHV0KTtcbiAgaWYgKCFwYXJzZWQuc3VjY2Vzcykge1xuICAgIHRocm93IFZhbGlkYXRpb25FcnJvci5pbnZhbGlkVmFsdWUoXCJpbnB1dFwiLCBpbnB1dCwgXCJhcmd1bWVudHMgbWF0Y2hpbmcgdGhlIHRvb2wncyBzY2hlbWFcIik7XG4gIH1cbiAgcmV0dXJuIHBhcnNlZC5kYXRhO1xufVxuXG4vKiogT3B0aW9ucyBzaGFyZWQgYnkgYm90aCB3ZWIgdG9vbHMuICovXG5leHBvcnQgaW50ZXJmYWNlIFdlYlNlYXJjaFRvb2xPcHRpb25zIHtcbiAgLyoqIE92ZXJyaWRlIHRoZSB0b29sIGlkLiAqL1xuICBpZD86IHN0cmluZztcbiAgLyoqIElzb2xhdGVkIHJ1bnRpbWUgdXNlZCBieSB0aGlzIHN0YW5kYWxvbmUgdG9vbC4gTXV0dWFsbHkgZXhjbHVzaXZlIHdpdGggYGNvbmZpZ2AuICovXG4gIHJ1bnRpbWU/OiBXZWJTZWFyY2hSdW50aW1lO1xuICAvKiogQ29uZmlnIHVzZWQgdG8gY3JlYXRlIGFuIGlzb2xhdGVkIGRpcmVjdC1leGVjdXRpb24gcnVudGltZS4gKi9cbiAgY29uZmlnPzogV2ViU2VhcmNoUGx1Z2luQ29uZmlnO1xuICAvKipcbiAgICogQXBwcm92YWwgZ2F0ZSBmb3IgdGhpcyB0b29sLCBvdmVycmlkaW5nIHRoZSBydW50aW1lJ3MgYGFwcHJvdmFsYC4gYHRydWVgXG4gICAqIGdhdGVzIGV2ZXJ5IGNhbGw7IGEgVVJMLXBhdHRlcm4gKG9yIGxpc3QpIGdhdGVzIG9ubHkgbWF0Y2hpbmcgY2FsbHM7XG4gICAqIG9taXQgLyBgZmFsc2VgIGZvciBubyBhcHByb3ZhbC4gU2VlIHtAbGluayBBcHByb3ZhbEdhdGV9LlxuICAgKi9cbiAgYXBwcm92YWw/OiBBcHByb3ZhbEdhdGUgfCBBcHByb3ZhbFBvbGljeTtcbn1cblxuLyoqIFJlc29sdmUgdGhlIGlzb2xhdGVkIHJ1bnRpbWUgY2FwdHVyZWQgYnkgb25lIHN0YW5kYWxvbmUgdG9vbCBmYWN0b3J5LiAqL1xuZnVuY3Rpb24gdG9vbFJ1bnRpbWUob3B0czogV2ViU2VhcmNoVG9vbE9wdGlvbnMpOiBXZWJTZWFyY2hSdW50aW1lIHtcbiAgaWYgKG9wdHMucnVudGltZSAmJiBvcHRzLmNvbmZpZykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJ3ZWItc2VhcmNoIHRvb2wgb3B0aW9ucyBhY2NlcHQgZWl0aGVyIHJ1bnRpbWUgb3IgY29uZmlnLCBub3QgYm90aFwiKTtcbiAgfVxuICByZXR1cm4gb3B0cy5ydW50aW1lID8/IGNyZWF0ZVdlYlNlYXJjaFJ1bnRpbWUob3B0cy5jb25maWcpO1xufVxuXG4vKiogUmVzb2x2ZSB0aGUgZWZmZWN0aXZlIGdhdGU6IGV4cGxpY2l0IHRvb2wgb3B0aW9uLCBlbHNlIHRoZSBydW50aW1lIGRlZmF1bHQuICovXG5mdW5jdGlvbiBlZmZlY3RpdmVHYXRlKG9wdHM6IFdlYlNlYXJjaFRvb2xPcHRpb25zLCBydW50aW1lOiBXZWJTZWFyY2hSdW50aW1lKTogQXBwcm92YWxQb2xpY3kge1xuICByZXR1cm4gb3B0cy5hcHByb3ZhbCA9PT0gdW5kZWZpbmVkID8gcnVudGltZS5jb25maWcuYXBwcm92YWwgOiB0b0FwcHJvdmFsUG9saWN5KG9wdHMuYXBwcm92YWwpO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBgd2ViX3NlYXJjaGAgdG9vbC4gU3ByZWFkIGl0IGludG8gdGhlIGFnZW50cyB0aGF0IHNob3VsZCBiZSBhYmxlXG4gKiB0byBzZWFyY2ggdGhlIHdlYi5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIGltcG9ydCB7IHdlYlNlYXJjaFRvb2wgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXQtd2ViLXNlYXJjaFwiO1xuICogaW1wb3J0IHsgY3JlYXRlQWdlbnQgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXQtbWFzdHJhXCI7XG4gKlxuICogY29uc3QgcmVzZWFyY2hlciA9IGNyZWF0ZUFnZW50KHtcbiAqICAgaW5zdHJ1Y3Rpb25zOiBcIi4uLlwiLFxuICogICB0b29sczogKCkgPT4gKHsgd2ViX3NlYXJjaDogd2ViU2VhcmNoVG9vbCgpIH0pLFxuICogfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdlYlNlYXJjaFRvb2wob3B0czogV2ViU2VhcmNoVG9vbE9wdGlvbnMgPSB7fSkge1xuICBjb25zdCBydW50aW1lID0gdG9vbFJ1bnRpbWUob3B0cyk7XG4gIGNvbnN0IGdhdGUgPSBlZmZlY3RpdmVHYXRlKG9wdHMsIHJ1bnRpbWUpO1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IG9wdHMuaWQgPz8gXCJ3ZWJfc2VhcmNoXCIsXG4gICAgZGVzY3JpcHRpb246IFdFQl9TRUFSQ0hfVE9PTF9ERVNDUklQVElPTixcbiAgICBpbnB1dFNjaGVtYTogd2ViU2VhcmNoVG9vbFJlcXVlc3RTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiB3ZWJTZWFyY2hSZXN1bHRTY2hlbWEsXG4gICAgLy8gQSBzZWFyY2gncyByZXN1bHQgVVJMcyBhcmVuJ3Qga25vd24gYmVmb3JlIHRoZSBjYWxsLCBzbyBhIHBhdHRlcm4gZ2F0ZVxuICAgIC8vIGlzIHRyZWF0ZWQgYXMgXCJhbHdheXMgZ2F0ZVwiLlxuICAgIC4uLihnYXRlLm1vZGUgPT09IFwibm9uZVwiID8ge30gOiB7IHJlcXVpcmVBcHByb3ZhbDogKCkgPT4gdHJ1ZSB9KSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQpID0+IHtcbiAgICAgIGNvbnN0IHJlcXVlc3QgPSBwYXJzZVRvb2xJbnB1dCh3ZWJTZWFyY2hUb29sUmVxdWVzdFNjaGVtYSwgaW5wdXQpO1xuICAgICAgcmV0dXJuIHJ1bldlYlNlYXJjaChyZXF1ZXN0LCBydW50aW1lLCBhd2FpdCByZXNvbHZlV2ViU2VhcmNoQ29udGV4dCgpKTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgYHdlYl9mZXRjaGAgdG9vbC4gU3ByZWFkIGl0IGludG8gdGhlIGFnZW50cyB0aGF0IHNob3VsZCBiZSBhYmxlXG4gKiB0byByZWFkIGEgcGFnZSdzIGNvbnRlbnRzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgd2ViRmV0Y2hUb29sIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0LXdlYi1zZWFyY2hcIjtcbiAqXG4gKiB0b29sczogKCkgPT4gKHsgd2ViX2ZldGNoOiB3ZWJGZXRjaFRvb2woeyBhcHByb3ZhbDogXCIqLmludGVybmFsLmV4YW1wbGUuY29tXCIgfSkgfSlcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gd2ViRmV0Y2hUb29sKG9wdHM6IFdlYlNlYXJjaFRvb2xPcHRpb25zID0ge30pIHtcbiAgY29uc3QgcnVudGltZSA9IHRvb2xSdW50aW1lKG9wdHMpO1xuICBjb25zdCBnYXRlID0gZWZmZWN0aXZlR2F0ZShvcHRzLCBydW50aW1lKTtcbiAgcmV0dXJuIGNyZWF0ZVRvb2woe1xuICAgIGlkOiBvcHRzLmlkID8/IFwid2ViX2ZldGNoXCIsXG4gICAgZGVzY3JpcHRpb246IFdFQl9GRVRDSF9UT09MX0RFU0NSSVBUSU9OLFxuICAgIGlucHV0U2NoZW1hOiB3ZWJGZXRjaFJlcXVlc3RTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiB3ZWJGZXRjaFJlc3VsdFNjaGVtYSxcbiAgICAvLyBBIGZldGNoIGtub3dzIGl0cyBzaW5nbGUgdGFyZ2V0IFVSTCwgc28gYSBwYXR0ZXJuIGdhdGUgaXMgZXZhbHVhdGVkXG4gICAgLy8gcHJlY2lzZWx5IGFnYWluc3QgaXQuXG4gICAgLi4uKGdhdGUubW9kZSA9PT0gXCJub25lXCJcbiAgICAgID8ge31cbiAgICAgIDoge1xuICAgICAgICAgIHJlcXVpcmVBcHByb3ZhbDogKGlucHV0OiB1bmtub3duKSA9PlxuICAgICAgICAgICAgZ2F0ZS5tb2RlID09PSBcImFsd2F5c1wiIHx8XG4gICAgICAgICAgICBhcHByb3ZhbE1hdGNoZXMoZ2F0ZSwgW3BhcnNlVG9vbElucHV0KHdlYkZldGNoUmVxdWVzdFNjaGVtYSwgaW5wdXQpLnVybF0pLFxuICAgICAgICB9KSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQpID0+IHtcbiAgICAgIHJldHVybiBydW5XZWJGZXRjaChwYXJzZVRvb2xJbnB1dCh3ZWJGZXRjaFJlcXVlc3RTY2hlbWEsIGlucHV0KSwgcnVudGltZSk7XG4gICAgfSxcbiAgfSk7XG59XG4iXX0=
package/package.json CHANGED
@@ -27,12 +27,12 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@databricks/appkit": "0.81.0",
30
- "@dbx-tools/appkit": "^0.9.70",
31
- "@dbx-tools/core": "^0.9.70",
32
- "@dbx-tools/model": "^0.9.70",
33
- "@dbx-tools/path": "^0.9.70",
34
- "@dbx-tools/shared-core": "^0.9.70",
35
- "@dbx-tools/shared-model": "^0.9.70",
30
+ "@dbx-tools/appkit": "^0.9.72",
31
+ "@dbx-tools/core": "^0.9.72",
32
+ "@dbx-tools/model": "^0.9.72",
33
+ "@dbx-tools/path": "^0.9.72",
34
+ "@dbx-tools/shared-core": "^0.9.72",
35
+ "@dbx-tools/shared-model": "^0.9.72",
36
36
  "@mastra/core": "1.71.0",
37
37
  "cheerio": "^1.2.0",
38
38
  "entities": "^4.5.0",
@@ -102,7 +102,7 @@
102
102
  "./package.json": "./package.json"
103
103
  }
104
104
  },
105
- "version": "0.9.70",
105
+ "version": "0.9.72",
106
106
  "types": "./lib/index.d.ts",
107
107
  "dbxToolsConfig": {
108
108
  "tags": [
package/src/config.ts CHANGED
@@ -88,18 +88,11 @@ export const SERVING_ENDPOINT_ENV = "DATABRICKS_SERVING_ENDPOINT_NAME";
88
88
  export type ModelSource = "config" | typeof MODEL_ENV | typeof SERVING_ENDPOINT_ENV | "none";
89
89
 
90
90
  /**
91
- * Default web-search model preference, tried in order when no model is
92
- * pinned. Gemini first, then GPT - both support the native web-search tool;
93
- * a workspace typically has at least one. Each is fuzzy-matched against the
94
- * live catalogue, so a close variant (e.g. `databricks-gemini-3-1-pro`) is
95
- * picked when the exact id isn't present.
91
+ * Default web-search family preference, tried in order when no model is
92
+ * pinned. Each query selects the highest-ranked deployed model in that family
93
+ * after model-owned web-search capability filtering.
96
94
  */
97
- export const DEFAULT_MODEL_FALLBACKS: readonly string[] = [
98
- "databricks-gemini-3-pro",
99
- "databricks-gemini-2-5-pro",
100
- "databricks-gpt-5",
101
- "databricks-gpt-5-mini",
102
- ];
95
+ export const DEFAULT_MODEL_FALLBACKS: readonly string[] = ["gemini", "gpt"];
103
96
 
104
97
  /** Default cap on the number of citations returned from a single search. */
105
98
  export const DEFAULT_MAX_CITATIONS = 10;
@@ -108,17 +101,14 @@ export const DEFAULT_MAX_CITATIONS = 10;
108
101
  export const DEFAULT_FETCH_MAX_LENGTH = 50_000;
109
102
 
110
103
  /** Default per-request network timeout (ms) for search + fetch. */
111
- export const DEFAULT_TIMEOUT_MS = 30_000;
104
+ export const DEFAULT_TIMEOUT_MS = 60_000;
112
105
 
113
106
  /** AppKit config accepted by the web-search plugin. */
114
107
  export interface WebSearchPluginConfig extends BasePluginConfig {
115
108
  /**
116
- * The web-search model to use by default: a Databricks serving endpoint
117
- * name (`"databricks-gemini-3-pro"`), a loose name (`"gemini"`, `"gpt"`),
118
- * or a capability class. Fuzzy-matched against the live catalogue. Falls
119
- * back to `WEB_SEARCH_MODEL`, then `DATABRICKS_SERVING_ENDPOINT_NAME`, then
120
- * the {@link modelFallbacks} order. Chosen independently of the calling
121
- * agent's chat model.
109
+ * GPT preference used when no capable Gemini is available. Accepts a
110
+ * Databricks serving endpoint name or loose family search and falls back to
111
+ * `WEB_SEARCH_MODEL`, then `DATABRICKS_SERVING_ENDPOINT_NAME`.
122
112
  */
123
113
  model?: string;
124
114
  /**
@@ -129,9 +119,9 @@ export interface WebSearchPluginConfig extends BasePluginConfig {
129
119
  */
130
120
  modelFallbacks?: string | string[];
131
121
  /**
132
- * Provider -> tool-spec override map, merged over the built-in
122
+ * Provider -> request-fragment override map, merged over the built-in
133
123
  * {@link WEB_SEARCH_PROVIDERS} defaults. Keyed by provider family
134
- * (`"openai"`, `"gemini"`); each value may override the `tool` entry
124
+ * (`"openai"`, `"gemini"`); each value may override the `request` fragment
135
125
  * and/or the `api` surface. Use to change the tool shape as the platform
136
126
  * evolves without a code change. Falls back to `WEB_SEARCH_TOOLS` parsed as
137
127
  * JSON. This is the `WEB_SEARCH_TOOLS` setting.
@@ -203,7 +193,7 @@ export interface ResolvedWebSearchConfig {
203
193
  modelSource: ModelSource;
204
194
  /** Ordered fallback model candidates (Gemini, then GPT, then a floor). */
205
195
  modelFallbacks: readonly string[];
206
- /** Provider -> tool-spec override map, merged over the built-in defaults. */
196
+ /** Provider -> request-fragment override map, merged over the built-in defaults. */
207
197
  webSearchTools: Record<string, unknown>;
208
198
  /** Whether to fuzzy-match loose model names. */
209
199
  fuzzy: boolean;
@@ -240,7 +230,7 @@ export const WEB_SEARCH_CONFIG_SCHEMA: JSONSchema7 = {
240
230
  webSearchTools: {
241
231
  type: "object",
242
232
  description:
243
- 'Provider -> tool-spec override map merged over the built-in defaults (openai -> {"type":"web_search"}, gemini -> {"google_search":{}}). Env: WEB_SEARCH_TOOLS (JSON).',
233
+ 'Provider -> request-fragment override map merged over the built-in defaults (openai -> {"tools":[{"type":"web_search"}]}, gemini -> {"google_search":{}}). Env: WEB_SEARCH_TOOLS (JSON).',
244
234
  },
245
235
  modelFuzzyMatch: {
246
236
  type: "boolean",
@@ -312,7 +302,7 @@ function parseToolsEnv(): Record<string, unknown> {
312
302
  const parsed = json.parseRecord(raw);
313
303
  if (!parsed) {
314
304
  throw new ConfigurationError(
315
- "WEB_SEARCH_TOOLS must be a JSON object mapping a provider family to its tool spec",
305
+ "WEB_SEARCH_TOOLS must be a JSON object mapping a provider family to its request fragment",
316
306
  { context: { envVar: "WEB_SEARCH_TOOLS" } },
317
307
  );
318
308
  }
package/src/fetch.ts CHANGED
@@ -78,6 +78,9 @@ export async function runWebFetch(
78
78
  async (executeSignal): Promise<FetchedPage> => {
79
79
  const response = await gotScraping({
80
80
  url: request.url,
81
+ // Bun's node:http2 reports default-port origins with :443 while
82
+ // http2-wrapper compares them against URL-normalized origins.
83
+ http2: false,
81
84
  // got's own timeout aborts the socket and reports which phase timed
82
85
  // out; the interceptor timeout bounds the whole attempt around it.
83
86
  timeout: { request: config.timeoutMs },
package/src/plugin.ts CHANGED
@@ -23,6 +23,7 @@ import {
23
23
  } from "@databricks/appkit";
24
24
  import { defineTool, type ToolRegistry } from "@databricks/appkit/beta";
25
25
  import { ToolRegistryPlugin } from "@dbx-tools/appkit";
26
+ import type { AgentToolExecutionContext } from "@dbx-tools/appkit/tool-provider";
26
27
  import { log, stringUtils } from "@dbx-tools/shared-core";
27
28
  import {
28
29
  MODEL_ENV,
@@ -34,7 +35,7 @@ import { runWebFetch } from "./fetch.ts";
34
35
  import { createWebSearchRuntime, type WebSearchRuntime } from "./runtime.ts";
35
36
  import {
36
37
  webFetchRequestSchema,
37
- webSearchRequestSchema,
38
+ webSearchToolRequestSchema,
38
39
  WEB_FETCH_TOOL_DESCRIPTION,
39
40
  WEB_SEARCH_TOOL_DESCRIPTION,
40
41
  } from "./schema.ts";
@@ -149,10 +150,10 @@ export class WebSearchPlugin extends ToolRegistryPlugin<WebSearchPluginConfig> {
149
150
  protected readonly toolRegistry: ToolRegistry = {
150
151
  web_search: defineTool({
151
152
  description: WEB_SEARCH_TOOL_DESCRIPTION,
152
- schema: webSearchRequestSchema,
153
+ schema: webSearchToolRequestSchema,
153
154
  annotations: { effect: "read", requiresUserContext: true },
154
155
  autoInheritable: false,
155
- execute: async (args, signal) => this.search(webSearchRequestSchema.parse(args), signal),
156
+ execute: async (args, signal) => this.search(webSearchToolRequestSchema.parse(args), signal),
156
157
  }),
157
158
  web_fetch: defineTool({
158
159
  description: WEB_FETCH_TOOL_DESCRIPTION,
@@ -163,6 +164,25 @@ export class WebSearchPlugin extends ToolRegistryPlugin<WebSearchPluginConfig> {
163
164
  }),
164
165
  };
165
166
 
167
+ /** Dispatch with the actual calling model and optional host progress sink. */
168
+ override executeAgentTool(
169
+ name: string,
170
+ args: unknown,
171
+ signal?: AbortSignal,
172
+ context?: AgentToolExecutionContext,
173
+ ): Promise<unknown> {
174
+ if (name !== "web_search") return super.executeAgentTool(name, args, signal, context);
175
+ const request = webSearchToolRequestSchema.parse(args);
176
+ return this.search(
177
+ {
178
+ ...request,
179
+ ...(context?.model ? { model: context.model } : {}),
180
+ },
181
+ signal,
182
+ context?.writeProgress,
183
+ );
184
+ }
185
+
166
186
  /**
167
187
  * Log the effective policy so an active allow-list and caps are obvious at
168
188
  * boot. Runtime construction already resolved config and captured this
@@ -213,8 +233,18 @@ export class WebSearchPlugin extends ToolRegistryPlugin<WebSearchPluginConfig> {
213
233
  };
214
234
  }
215
235
 
216
- private async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult> {
217
- return runWebSearch(request, this.runtime, await resolveWebSearchContext(), signal);
236
+ private async search(
237
+ request: WebSearchRequest,
238
+ signal?: AbortSignal,
239
+ writeProgress?: AgentToolExecutionContext["writeProgress"],
240
+ ): Promise<WebSearchResult> {
241
+ return runWebSearch(
242
+ request,
243
+ this.runtime,
244
+ await resolveWebSearchContext(),
245
+ signal,
246
+ writeProgress,
247
+ );
218
248
  }
219
249
 
220
250
  private async fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult> {
package/src/provider.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  * - OpenAI GPT models, via the Responses API (`/serving-endpoints/responses`):
11
11
  * `tools: [{ "type": "web_search" }]`
12
12
  * - Google Gemini models, via Chat Completions
13
- * (`/serving-endpoints/chat/completions`): `tools: [{ "google_search": {} }]`
13
+ * (`/serving-endpoints/chat/completions`): top-level `"google_search": {}`
14
14
  *
15
15
  * (Anthropic exposes it over MCP, which needs a different call shape; only
16
16
  * GPT + Gemini are wired here, matching what the platform supports today.)
@@ -24,22 +24,28 @@
24
24
  */
25
25
 
26
26
  import { ValidationError } from "@databricks/appkit";
27
+ import { metadata, policy } from "@dbx-tools/model";
28
+ import type { ServingEndpointSummary } from "@dbx-tools/shared-model";
27
29
  import { z } from "zod";
28
30
 
29
31
  /** A web-search-capable model provider family. */
30
32
  export type WebSearchProvider = "openai" | "gemini";
31
33
 
34
+ /** Serialized provider request fragment for native web search. */
35
+ export const WebSearchProviderSpecSchema = z
36
+ .object({
37
+ api: z
38
+ .enum(["responses", "chat"])
39
+ .describe("Databricks serving API that accepts the provider request."),
40
+ request: z
41
+ .record(z.string(), z.unknown())
42
+ .describe("Provider-specific fields merged into the serving request body."),
43
+ })
44
+ .strict()
45
+ .describe("Native web-search request contract for one provider family.");
46
+
32
47
  /** How a provider's native web-search call is shaped. */
33
- export interface WebSearchProviderSpec {
34
- /**
35
- * Which serving REST surface to call. `"responses"` posts to
36
- * `/serving-endpoints/responses` (OpenAI Responses API); `"chat"` posts to
37
- * `/serving-endpoints/chat/completions`.
38
- */
39
- api: "responses" | "chat";
40
- /** The tool entry appended to the request's `tools` array. */
41
- tool: Record<string, unknown>;
42
- }
48
+ export type WebSearchProviderSpec = z.infer<typeof WebSearchProviderSpecSchema>;
43
49
 
44
50
  /**
45
51
  * Built-in provider -> tool-spec map. Operators can override or extend this
@@ -47,30 +53,33 @@ export interface WebSearchProviderSpec {
47
53
  * `WEB_SEARCH_TOOLS`), which is merged over these defaults.
48
54
  */
49
55
  export const WEB_SEARCH_PROVIDERS: Readonly<Record<WebSearchProvider, WebSearchProviderSpec>> = {
50
- openai: { api: "responses", tool: { type: "web_search" } },
51
- gemini: { api: "chat", tool: { google_search: {} } },
56
+ openai: { api: "responses", request: { tools: [{ type: "web_search" }] } },
57
+ gemini: { api: "chat", request: { google_search: {} } },
52
58
  };
53
59
 
54
60
  /**
55
- * Detect the web-search provider family for an endpoint id, or `null` when
56
- * the model is not one of the web-search-capable families. Anthropic
57
- * (`opus`/`sonnet`/`haiku`) is intentionally excluded - it needs an MCP call
58
- * shape this module doesn't implement - so a Claude endpoint returns `null`
59
- * and is treated as unsupported.
61
+ * Map a model-owned family value to its native web-search provider contract.
60
62
  */
61
- export function detectWebSearchProvider(modelId: string): WebSearchProvider | null {
62
- const n = modelId.toLowerCase();
63
- // gpt-oss open-weights don't carry the hosted web-search tool; only the
64
- // hosted GPT family (Responses API) does. Both contain "gpt", so exclude
65
- // the open-weights explicitly.
66
- if (n.includes("gpt") && !n.includes("gpt-oss")) return "openai";
67
- if (n.includes("gemini")) return "gemini";
68
- return null;
63
+ export function webSearchProviderForFamily(
64
+ family: policy.ModelFamily | undefined,
65
+ ): WebSearchProvider | null {
66
+ switch (family) {
67
+ case policy.ModelFamily.Gpt:
68
+ return "openai";
69
+ case policy.ModelFamily.Gemini:
70
+ return "gemini";
71
+ default:
72
+ return null;
73
+ }
69
74
  }
70
75
 
71
- /** Whether `modelId` is a web-search-capable model. */
72
- export function supportsWebSearch(modelId: string): boolean {
73
- return detectWebSearchProvider(modelId) !== null;
76
+ /** Whether a model has both native capability and a supported provider contract. */
77
+ export function supportsWebSearch(model: string | ServingEndpointSummary): boolean {
78
+ const identity = typeof model === "string" ? model : (model.modelServiceName ?? model.name);
79
+ return (
80
+ webSearchProviderForFamily(policy.modelFamily(identity)) !== null &&
81
+ metadata.modelCapabilitiesFor(model).webSearch
82
+ );
74
83
  }
75
84
 
76
85
  /**
@@ -78,16 +87,15 @@ export function supportsWebSearch(modelId: string): boolean {
78
87
  * parsed JSON (config or `WEB_SEARCH_TOOLS`), so it is validated rather than
79
88
  * asserted.
80
89
  */
81
- const providerOverrideSchema = z.object({
82
- api: z.enum(["responses", "chat"]).optional(),
83
- tool: z.record(z.string(), z.unknown()).optional(),
84
- });
90
+ const providerOverrideSchema = WebSearchProviderSpecSchema.partial()
91
+ .strict()
92
+ .describe("Partial native web-search provider override.");
85
93
 
86
94
  /**
87
95
  * Resolve the effective {@link WebSearchProviderSpec} for a provider: the
88
96
  * built-in default, with any operator override (the `webSearchTools` map,
89
97
  * keyed by provider) shallow-merged over it. An override may replace just the
90
- * `tool` (the common case - a new tool type) or also the `api`. An override
98
+ * `request` fragment or also the `api`. An override
91
99
  * that is not one of those two fields is a deployment mistake that would
92
100
  * otherwise be silently dropped, so it throws.
93
101
  */
@@ -103,11 +111,11 @@ export function webSearchToolSpec(
103
111
  throw ValidationError.invalidValue(
104
112
  `webSearchTools.${provider}`,
105
113
  raw,
106
- 'an object with an optional "api" ("responses" | "chat") and an optional "tool" object',
114
+ 'an object with an optional "api" ("responses" | "chat") and an optional "request" object',
107
115
  );
108
116
  }
109
117
  return {
110
118
  api: parsed.data.api ?? base.api,
111
- tool: parsed.data.tool ?? base.tool,
119
+ request: parsed.data.request ?? base.request,
112
120
  };
113
121
  }
package/src/runtime.ts CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  import type { ExecutionResult } from "@databricks/appkit";
12
12
  import { pluginExecution } from "@dbx-tools/appkit";
13
+ import { policy } from "@dbx-tools/model";
13
14
  import { execution, log } from "@dbx-tools/shared-core";
14
15
  import {
15
16
  resolveWebSearchConfig,
@@ -34,6 +35,8 @@ export type WebSearchExecutor = <T>(
34
35
  export interface WebSearchRuntime {
35
36
  config: ResolvedWebSearchConfig;
36
37
  execute: WebSearchExecutor;
38
+ /** Provider-family cooldown deadlines learned from workspace failures. */
39
+ familyCooldowns: Map<policy.ModelFamily, number>;
37
40
  }
38
41
 
39
42
  /** Runtime-aware operation input, retaining resolved-config compatibility. */
@@ -51,7 +54,7 @@ export function createWebSearchRuntime(
51
54
  overrides?: WebSearchPluginConfig,
52
55
  execute: WebSearchExecutor = directExecute,
53
56
  ): WebSearchRuntime {
54
- return { config: resolveWebSearchConfig(overrides), execute };
57
+ return { config: resolveWebSearchConfig(overrides), execute, familyCooldowns: new Map() };
55
58
  }
56
59
 
57
60
  /** Build an isolated runtime from config that has already been resolved. */
@@ -59,7 +62,7 @@ export function createResolvedWebSearchRuntime(
59
62
  config: ResolvedWebSearchConfig,
60
63
  execute: WebSearchExecutor = directExecute,
61
64
  ): WebSearchRuntime {
62
- return { config, execute };
65
+ return { config, execute, familyCooldowns: new Map() };
63
66
  }
64
67
 
65
68
  /** Normalize an explicit runtime or legacy resolved config for one operation. */
package/src/schema.ts CHANGED
@@ -54,12 +54,9 @@ export const webSearchRequestSchema = z.object({
54
54
  .optional()
55
55
  .describe(
56
56
  stringUtils.toDescription(`
57
- Optional web-search-capable model to use (a Databricks serving
58
- endpoint name like "databricks-gemini-3-pro", a loose name like "gpt"
59
- or "gemini", or a capability class). Defaults to the plugin's
60
- configured web-search model. The web-search tool resolves its own
61
- model independently of the calling agent's chat model, since not
62
- every chat model supports web search.
57
+ Optional calling-model preference. The tool always tries the highest
58
+ web-search-capable Gemini first. When Gemini is unavailable, a matching
59
+ GPT endpoint wins before the highest-ranked GPT fallback.
63
60
  `),
64
61
  ),
65
62
  });
@@ -67,6 +64,14 @@ export const webSearchRequestSchema = z.object({
67
64
  /** A validated `web_search` request. */
68
65
  export type WebSearchRequest = z.infer<typeof webSearchRequestSchema>;
69
66
 
67
+ /** Model-facing `web_search` input; the host owns model selection. */
68
+ export const webSearchToolRequestSchema = webSearchRequestSchema
69
+ .omit({ model: true })
70
+ .describe("Model-facing web-search input with host-owned model selection.");
71
+
72
+ /** Model-facing `web_search` request. */
73
+ export type WebSearchToolRequest = z.infer<typeof webSearchToolRequestSchema>;
74
+
70
75
  /** Schema for a single source the model cited while answering. */
71
76
  export const webSearchCitationSchema = z.object({
72
77
  url: z.string().describe("The source URL the answer drew on."),