@dbx-tools/appkit-web-search 0.3.44 → 0.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/lib/index.d.ts +32 -0
- package/lib/index.js +28 -0
- package/lib/src/allowlist.d.ts +66 -0
- package/lib/src/allowlist.js +113 -0
- package/lib/src/config.d.ts +233 -0
- package/lib/src/config.js +269 -0
- package/lib/src/defaults.d.ts +98 -0
- package/lib/src/defaults.js +96 -0
- package/lib/src/fetch.d.ts +27 -0
- package/lib/src/fetch.js +86 -0
- package/lib/src/html-text.d.ts +30 -0
- package/lib/src/html-text.js +66 -0
- package/lib/src/plugin.d.ts +162 -0
- package/lib/src/plugin.js +225 -0
- package/lib/src/provider.d.ts +62 -0
- package/lib/src/provider.js +89 -0
- package/lib/src/runtime.d.ts +61 -0
- package/lib/src/runtime.js +95 -0
- package/lib/src/schema.d.ts +76 -0
- package/lib/src/schema.js +102 -0
- package/lib/src/scrape.d.ts +29 -0
- package/lib/src/scrape.js +113 -0
- package/lib/src/search.d.ts +49 -0
- package/lib/src/search.js +252 -0
- package/lib/src/tool.d.ts +85 -0
- package/lib/src/tool.js +113 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +13 -9
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export * as allowlist from "./src/allowlist.js";
|
|
2
|
+
export * as config from "./src/config.js";
|
|
3
|
+
export * as defaults from "./src/defaults.js";
|
|
4
|
+
export * as fetch from "./src/fetch.js";
|
|
5
|
+
export * as htmlText from "./src/html-text.js";
|
|
6
|
+
export * as plugin from "./src/plugin.js";
|
|
7
|
+
export * as provider from "./src/provider.js";
|
|
8
|
+
export * as runtime from "./src/runtime.js";
|
|
9
|
+
export * as schema from "./src/schema.js";
|
|
10
|
+
export * as scrape from "./src/scrape.js";
|
|
11
|
+
export * as search from "./src/search.js";
|
|
12
|
+
export * as tool from "./src/tool.js";
|
|
13
|
+
export { normalizeUrlPattern, parseAllowedUrls, toUrlAllowList, assertUrlAllowed } from "./src/allowlist.js";
|
|
14
|
+
export type { UrlAllowList } from "./src/allowlist.js";
|
|
15
|
+
export { MODEL_ENV, SERVING_ENDPOINT_ENV, DEFAULT_MODEL_FALLBACKS, DEFAULT_MAX_CITATIONS, DEFAULT_FETCH_MAX_LENGTH, DEFAULT_TIMEOUT_MS, WEB_SEARCH_CONFIG_SCHEMA, toApprovalPolicy, resolveWebSearchConfig, approvalMatches } from "./src/config.js";
|
|
16
|
+
export type { ApprovalGate, ApprovalPolicy, UrlPolicyMode, ModelSource, WebSearchPluginConfig, ResolvedWebSearchConfig } from "./src/config.js";
|
|
17
|
+
export { SEARCH_CACHE_TTL_SECONDS, FETCH_CACHE_TTL_SECONDS, SERVING_RETRY_ATTEMPTS, WEB_RETRY_ATTEMPTS, webSearchExecuteDefaults, webFetchExecuteDefaults, scrapeSearchExecuteDefaults, toCallSettings } from "./src/defaults.js";
|
|
18
|
+
export type { WebSearchExecuteConfig, WebSearchExecutionSettings } from "./src/defaults.js";
|
|
19
|
+
export { runWebFetch } from "./src/fetch.js";
|
|
20
|
+
export { decodeHtmlEntities, htmlFragmentToText, htmlToText } from "./src/html-text.js";
|
|
21
|
+
export { WebSearchPlugin, webSearch } from "./src/plugin.js";
|
|
22
|
+
export { WEB_SEARCH_PROVIDERS, detectWebSearchProvider, supportsWebSearch, webSearchToolSpec } from "./src/provider.js";
|
|
23
|
+
export type { WebSearchProvider, WebSearchProviderSpec } from "./src/provider.js";
|
|
24
|
+
export { getWebSearchRuntime, setWebSearchExecutor, resetWebSearchRuntime, executeRead } from "./src/runtime.js";
|
|
25
|
+
export type { WebSearchExecutor, WebSearchRuntime } from "./src/runtime.js";
|
|
26
|
+
export { WEB_SEARCH_TOOL_DESCRIPTION, WEB_FETCH_TOOL_DESCRIPTION, webSearchRequestSchema, webSearchCitationSchema, webSearchResultSchema, webFetchRequestSchema, webFetchResultSchema } from "./src/schema.js";
|
|
27
|
+
export type { WebSearchRequest, WebSearchCitation, WebSearchResult, WebFetchRequest, WebFetchResult } from "./src/schema.js";
|
|
28
|
+
export { runScrapeSearch } from "./src/scrape.js";
|
|
29
|
+
export { resolveWebSearchContext, runWebSearch } from "./src/search.js";
|
|
30
|
+
export type { WebSearchContext } from "./src/search.js";
|
|
31
|
+
export { webSearchTool, webFetchTool } from "./src/tool.js";
|
|
32
|
+
export type { WebSearchToolOptions } from "./src/tool.js";
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// GENERATED by projen watch - DO NOT EDIT.
|
|
2
|
+
// Regenerated from the exporting modules in ./src.
|
|
3
|
+
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
|
+
export * as allowlist from "./src/allowlist.js";
|
|
5
|
+
export * as config from "./src/config.js";
|
|
6
|
+
export * as defaults from "./src/defaults.js";
|
|
7
|
+
export * as fetch from "./src/fetch.js";
|
|
8
|
+
export * as htmlText from "./src/html-text.js";
|
|
9
|
+
export * as plugin from "./src/plugin.js";
|
|
10
|
+
export * as provider from "./src/provider.js";
|
|
11
|
+
export * as runtime from "./src/runtime.js";
|
|
12
|
+
export * as schema from "./src/schema.js";
|
|
13
|
+
export * as scrape from "./src/scrape.js";
|
|
14
|
+
export * as search from "./src/search.js";
|
|
15
|
+
export * as tool from "./src/tool.js";
|
|
16
|
+
export { normalizeUrlPattern, parseAllowedUrls, toUrlAllowList, assertUrlAllowed } from "./src/allowlist.js";
|
|
17
|
+
export { MODEL_ENV, SERVING_ENDPOINT_ENV, DEFAULT_MODEL_FALLBACKS, DEFAULT_MAX_CITATIONS, DEFAULT_FETCH_MAX_LENGTH, DEFAULT_TIMEOUT_MS, WEB_SEARCH_CONFIG_SCHEMA, toApprovalPolicy, resolveWebSearchConfig, approvalMatches } from "./src/config.js";
|
|
18
|
+
export { SEARCH_CACHE_TTL_SECONDS, FETCH_CACHE_TTL_SECONDS, SERVING_RETRY_ATTEMPTS, WEB_RETRY_ATTEMPTS, webSearchExecuteDefaults, webFetchExecuteDefaults, scrapeSearchExecuteDefaults, toCallSettings } from "./src/defaults.js";
|
|
19
|
+
export { runWebFetch } from "./src/fetch.js";
|
|
20
|
+
export { decodeHtmlEntities, htmlFragmentToText, htmlToText } from "./src/html-text.js";
|
|
21
|
+
export { WebSearchPlugin, webSearch } from "./src/plugin.js";
|
|
22
|
+
export { WEB_SEARCH_PROVIDERS, detectWebSearchProvider, supportsWebSearch, webSearchToolSpec } from "./src/provider.js";
|
|
23
|
+
export { getWebSearchRuntime, setWebSearchExecutor, resetWebSearchRuntime, executeRead } from "./src/runtime.js";
|
|
24
|
+
export { WEB_SEARCH_TOOL_DESCRIPTION, WEB_FETCH_TOOL_DESCRIPTION, webSearchRequestSchema, webSearchCitationSchema, webSearchResultSchema, webFetchRequestSchema, webFetchResultSchema } from "./src/schema.js";
|
|
25
|
+
export { runScrapeSearch } from "./src/scrape.js";
|
|
26
|
+
export { resolveWebSearchContext, runWebSearch } from "./src/search.js";
|
|
27
|
+
export { webSearchTool, webFetchTool } from "./src/tool.js";
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssU0FBUyxNQUFNLGlCQUFpQixDQUFDO0FBQzdDLE9BQU8sS0FBSyxNQUFNLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sS0FBSyxRQUFRLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0MsT0FBTyxLQUFLLEtBQUssTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxLQUFLLFFBQVEsTUFBTSxpQkFBaUIsQ0FBQztBQUM1QyxPQUFPLEtBQUssTUFBTSxNQUFNLGNBQWMsQ0FBQztBQUN2QyxPQUFPLEtBQUssUUFBUSxNQUFNLGdCQUFnQixDQUFDO0FBQzNDLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxNQUFNLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sS0FBSyxNQUFNLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sS0FBSyxNQUFNLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sS0FBSyxJQUFJLE1BQU0sWUFBWSxDQUFDO0FBQ25DLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUUxRyxPQUFPLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLHVCQUF1QixFQUFFLHFCQUFxQixFQUFFLHdCQUF3QixFQUFFLGtCQUFrQixFQUFFLHdCQUF3QixFQUFFLGdCQUFnQixFQUFFLHNCQUFzQixFQUFFLGVBQWUsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUVsUCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsdUJBQXVCLEVBQUUsc0JBQXNCLEVBQUUsa0JBQWtCLEVBQUUsd0JBQXdCLEVBQUUsdUJBQXVCLEVBQUUsMkJBQTJCLEVBQUUsY0FBYyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFL04sT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMxQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckYsT0FBTyxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDMUQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLHVCQUF1QixFQUFFLGlCQUFpQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFckgsT0FBTyxFQUFFLG1CQUFtQixFQUFFLG9CQUFvQixFQUFFLHFCQUFxQixFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU5RyxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsMEJBQTBCLEVBQUUsc0JBQXNCLEVBQUUsdUJBQXVCLEVBQUUscUJBQXFCLEVBQUUscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFNU0sT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXJFLE9BQU8sRUFBRSxhQUFhLEVBQUUsWUFBWSxFQUFFLE1BQU0sWUFBWSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gR0VORVJBVEVEIGJ5IHByb2plbiB3YXRjaCAtIERPIE5PVCBFRElULlxuLy8gUmVnZW5lcmF0ZWQgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZXMgaW4gLi9zcmMuXG4vLyBIYW5kIGVkaXRzIGFyZSBvdmVyd3JpdHRlbiBvbiB0aGUgbmV4dCB3YXRjaDsgdGhpcyBmaWxlIGlzIHJlYWQtb25seS5cblxuZXhwb3J0ICogYXMgYWxsb3dsaXN0IGZyb20gXCIuL3NyYy9hbGxvd2xpc3RcIjtcbmV4cG9ydCAqIGFzIGNvbmZpZyBmcm9tIFwiLi9zcmMvY29uZmlnXCI7XG5leHBvcnQgKiBhcyBkZWZhdWx0cyBmcm9tIFwiLi9zcmMvZGVmYXVsdHNcIjtcbmV4cG9ydCAqIGFzIGZldGNoIGZyb20gXCIuL3NyYy9mZXRjaFwiO1xuZXhwb3J0ICogYXMgaHRtbFRleHQgZnJvbSBcIi4vc3JjL2h0bWwtdGV4dFwiO1xuZXhwb3J0ICogYXMgcGx1Z2luIGZyb20gXCIuL3NyYy9wbHVnaW5cIjtcbmV4cG9ydCAqIGFzIHByb3ZpZGVyIGZyb20gXCIuL3NyYy9wcm92aWRlclwiO1xuZXhwb3J0ICogYXMgcnVudGltZSBmcm9tIFwiLi9zcmMvcnVudGltZVwiO1xuZXhwb3J0ICogYXMgc2NoZW1hIGZyb20gXCIuL3NyYy9zY2hlbWFcIjtcbmV4cG9ydCAqIGFzIHNjcmFwZSBmcm9tIFwiLi9zcmMvc2NyYXBlXCI7XG5leHBvcnQgKiBhcyBzZWFyY2ggZnJvbSBcIi4vc3JjL3NlYXJjaFwiO1xuZXhwb3J0ICogYXMgdG9vbCBmcm9tIFwiLi9zcmMvdG9vbFwiO1xuZXhwb3J0IHsgbm9ybWFsaXplVXJsUGF0dGVybiwgcGFyc2VBbGxvd2VkVXJscywgdG9VcmxBbGxvd0xpc3QsIGFzc2VydFVybEFsbG93ZWQgfSBmcm9tIFwiLi9zcmMvYWxsb3dsaXN0XCI7XG5leHBvcnQgdHlwZSB7IFVybEFsbG93TGlzdCB9IGZyb20gXCIuL3NyYy9hbGxvd2xpc3RcIjtcbmV4cG9ydCB7IE1PREVMX0VOViwgU0VSVklOR19FTkRQT0lOVF9FTlYsIERFRkFVTFRfTU9ERUxfRkFMTEJBQ0tTLCBERUZBVUxUX01BWF9DSVRBVElPTlMsIERFRkFVTFRfRkVUQ0hfTUFYX0xFTkdUSCwgREVGQVVMVF9USU1FT1VUX01TLCBXRUJfU0VBUkNIX0NPTkZJR19TQ0hFTUEsIHRvQXBwcm92YWxQb2xpY3ksIHJlc29sdmVXZWJTZWFyY2hDb25maWcsIGFwcHJvdmFsTWF0Y2hlcyB9IGZyb20gXCIuL3NyYy9jb25maWdcIjtcbmV4cG9ydCB0eXBlIHsgQXBwcm92YWxHYXRlLCBBcHByb3ZhbFBvbGljeSwgVXJsUG9saWN5TW9kZSwgTW9kZWxTb3VyY2UsIFdlYlNlYXJjaFBsdWdpbkNvbmZpZywgUmVzb2x2ZWRXZWJTZWFyY2hDb25maWcgfSBmcm9tIFwiLi9zcmMvY29uZmlnXCI7XG5leHBvcnQgeyBTRUFSQ0hfQ0FDSEVfVFRMX1NFQ09ORFMsIEZFVENIX0NBQ0hFX1RUTF9TRUNPTkRTLCBTRVJWSU5HX1JFVFJZX0FUVEVNUFRTLCBXRUJfUkVUUllfQVRURU1QVFMsIHdlYlNlYXJjaEV4ZWN1dGVEZWZhdWx0cywgd2ViRmV0Y2hFeGVjdXRlRGVmYXVsdHMsIHNjcmFwZVNlYXJjaEV4ZWN1dGVEZWZhdWx0cywgdG9DYWxsU2V0dGluZ3MgfSBmcm9tIFwiLi9zcmMvZGVmYXVsdHNcIjtcbmV4cG9ydCB0eXBlIHsgV2ViU2VhcmNoRXhlY3V0ZUNvbmZpZywgV2ViU2VhcmNoRXhlY3V0aW9uU2V0dGluZ3MgfSBmcm9tIFwiLi9zcmMvZGVmYXVsdHNcIjtcbmV4cG9ydCB7IHJ1bldlYkZldGNoIH0gZnJvbSBcIi4vc3JjL2ZldGNoXCI7XG5leHBvcnQgeyBkZWNvZGVIdG1sRW50aXRpZXMsIGh0bWxGcmFnbWVudFRvVGV4dCwgaHRtbFRvVGV4dCB9IGZyb20gXCIuL3NyYy9odG1sLXRleHRcIjtcbmV4cG9ydCB7IFdlYlNlYXJjaFBsdWdpbiwgd2ViU2VhcmNoIH0gZnJvbSBcIi4vc3JjL3BsdWdpblwiO1xuZXhwb3J0IHsgV0VCX1NFQVJDSF9QUk9WSURFUlMsIGRldGVjdFdlYlNlYXJjaFByb3ZpZGVyLCBzdXBwb3J0c1dlYlNlYXJjaCwgd2ViU2VhcmNoVG9vbFNwZWMgfSBmcm9tIFwiLi9zcmMvcHJvdmlkZXJcIjtcbmV4cG9ydCB0eXBlIHsgV2ViU2VhcmNoUHJvdmlkZXIsIFdlYlNlYXJjaFByb3ZpZGVyU3BlYyB9IGZyb20gXCIuL3NyYy9wcm92aWRlclwiO1xuZXhwb3J0IHsgZ2V0V2ViU2VhcmNoUnVudGltZSwgc2V0V2ViU2VhcmNoRXhlY3V0b3IsIHJlc2V0V2ViU2VhcmNoUnVudGltZSwgZXhlY3V0ZVJlYWQgfSBmcm9tIFwiLi9zcmMvcnVudGltZVwiO1xuZXhwb3J0IHR5cGUgeyBXZWJTZWFyY2hFeGVjdXRvciwgV2ViU2VhcmNoUnVudGltZSB9IGZyb20gXCIuL3NyYy9ydW50aW1lXCI7XG5leHBvcnQgeyBXRUJfU0VBUkNIX1RPT0xfREVTQ1JJUFRJT04sIFdFQl9GRVRDSF9UT09MX0RFU0NSSVBUSU9OLCB3ZWJTZWFyY2hSZXF1ZXN0U2NoZW1hLCB3ZWJTZWFyY2hDaXRhdGlvblNjaGVtYSwgd2ViU2VhcmNoUmVzdWx0U2NoZW1hLCB3ZWJGZXRjaFJlcXVlc3RTY2hlbWEsIHdlYkZldGNoUmVzdWx0U2NoZW1hIH0gZnJvbSBcIi4vc3JjL3NjaGVtYVwiO1xuZXhwb3J0IHR5cGUgeyBXZWJTZWFyY2hSZXF1ZXN0LCBXZWJTZWFyY2hDaXRhdGlvbiwgV2ViU2VhcmNoUmVzdWx0LCBXZWJGZXRjaFJlcXVlc3QsIFdlYkZldGNoUmVzdWx0IH0gZnJvbSBcIi4vc3JjL3NjaGVtYVwiO1xuZXhwb3J0IHsgcnVuU2NyYXBlU2VhcmNoIH0gZnJvbSBcIi4vc3JjL3NjcmFwZVwiO1xuZXhwb3J0IHsgcmVzb2x2ZVdlYlNlYXJjaENvbnRleHQsIHJ1bldlYlNlYXJjaCB9IGZyb20gXCIuL3NyYy9zZWFyY2hcIjtcbmV4cG9ydCB0eXBlIHsgV2ViU2VhcmNoQ29udGV4dCB9IGZyb20gXCIuL3NyYy9zZWFyY2hcIjtcbmV4cG9ydCB7IHdlYlNlYXJjaFRvb2wsIHdlYkZldGNoVG9vbCB9IGZyb20gXCIuL3NyYy90b29sXCI7XG5leHBvcnQgdHlwZSB7IFdlYlNlYXJjaFRvb2xPcHRpb25zIH0gZnJvbSBcIi4vc3JjL3Rvb2xcIjtcbiJdfQ==
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL allow-list policy for the web-search add-on.
|
|
3
|
+
*
|
|
4
|
+
* A configured allow-list restricts which URLs the tools will surface or
|
|
5
|
+
* fetch. Each entry is a glob compiled by `@dbx-tools/path`'s
|
|
6
|
+
* {@link match.toPathMatcher} (the same `Minimatch`-backed matcher the
|
|
7
|
+
* package's file scanning uses). Because that matcher treats `/` as a
|
|
8
|
+
* path-segment boundary, entries are matched against the right slice of the
|
|
9
|
+
* URL rather than the raw `href`:
|
|
10
|
+
*
|
|
11
|
+
* - A **host** entry (no `/` after the optional scheme, e.g. `databricks.com`
|
|
12
|
+
* or `*.databricks.com`) is tested against the URL's `hostname`. A bare
|
|
13
|
+
* host with no wildcard also matches its subdomains, so `databricks.com`
|
|
14
|
+
* permits `docs.databricks.com` - the intuitive reading of a domain
|
|
15
|
+
* allow-list.
|
|
16
|
+
* - A **path** entry (contains a `/`, e.g. `docs.example.com/api/**`) is
|
|
17
|
+
* tested against `host + pathname` (scheme and query stripped), so path
|
|
18
|
+
* globs work without fighting the `https://` prefix.
|
|
19
|
+
*
|
|
20
|
+
* Enforcement is asymmetric by design (see the module's two consumers):
|
|
21
|
+
* `web_search` results are SILENTLY filtered to the permitted set, while an
|
|
22
|
+
* explicit `web_fetch` of a disallowed URL is refused with an error - the
|
|
23
|
+
* search never leaks a URL the caller then can't fetch, but a direct fetch
|
|
24
|
+
* of a blocked URL is a visible, correctable mistake rather than a silent
|
|
25
|
+
* empty.
|
|
26
|
+
*
|
|
27
|
+
* An empty / absent allow-list permits everything.
|
|
28
|
+
*
|
|
29
|
+
* @module
|
|
30
|
+
*/
|
|
31
|
+
/** A compiled URL allow-list. Build one with {@link toUrlAllowList}. */
|
|
32
|
+
export interface UrlAllowList {
|
|
33
|
+
/** The normalized entries backing this list (for diagnostics). */
|
|
34
|
+
readonly patterns: readonly string[];
|
|
35
|
+
/** Whether the list actually restricts anything (`false` == permit all). */
|
|
36
|
+
readonly restricted: boolean;
|
|
37
|
+
/** Whether `url` is permitted. An unrestricted list permits everything. */
|
|
38
|
+
allows(url: string): boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Normalize one raw allow-list entry: trim it and drop any scheme. The
|
|
42
|
+
* scheme is irrelevant to matching (we compare against hostname / host+path),
|
|
43
|
+
* so `https://docs.example.com/x` and `docs.example.com/x` are equivalent.
|
|
44
|
+
*/
|
|
45
|
+
export declare function normalizeUrlPattern(pattern: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Parse a raw allow-list from config (`string[]`) or an env var (a CSV /
|
|
48
|
+
* whitespace-separated string) into a normalized, de-duplicated entry list.
|
|
49
|
+
* Entries are trimmed and scheme-stripped; empties are dropped. Mirrors the
|
|
50
|
+
* email add-on's `parseAllowedSenders` so the two policies read their config
|
|
51
|
+
* identically.
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseAllowedUrls(raw: string | string[] | undefined): string[];
|
|
54
|
+
/**
|
|
55
|
+
* Compile a normalized entry list into a {@link UrlAllowList}. An empty list
|
|
56
|
+
* yields a permit-all allow-list whose {@link UrlAllowList.allows} always
|
|
57
|
+
* returns `true`. A URL that can't be parsed is never permitted by a
|
|
58
|
+
* restricted list.
|
|
59
|
+
*/
|
|
60
|
+
export declare function toUrlAllowList(patterns: readonly string[]): UrlAllowList;
|
|
61
|
+
/**
|
|
62
|
+
* Throw when `url` is not permitted by the allow-list. No-op when the
|
|
63
|
+
* allow-list is unrestricted. The single enforcement point for the
|
|
64
|
+
* `web_fetch` path.
|
|
65
|
+
*/
|
|
66
|
+
export declare function assertUrlAllowed(url: string, allow: UrlAllowList): void;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL allow-list policy for the web-search add-on.
|
|
3
|
+
*
|
|
4
|
+
* A configured allow-list restricts which URLs the tools will surface or
|
|
5
|
+
* fetch. Each entry is a glob compiled by `@dbx-tools/path`'s
|
|
6
|
+
* {@link match.toPathMatcher} (the same `Minimatch`-backed matcher the
|
|
7
|
+
* package's file scanning uses). Because that matcher treats `/` as a
|
|
8
|
+
* path-segment boundary, entries are matched against the right slice of the
|
|
9
|
+
* URL rather than the raw `href`:
|
|
10
|
+
*
|
|
11
|
+
* - A **host** entry (no `/` after the optional scheme, e.g. `databricks.com`
|
|
12
|
+
* or `*.databricks.com`) is tested against the URL's `hostname`. A bare
|
|
13
|
+
* host with no wildcard also matches its subdomains, so `databricks.com`
|
|
14
|
+
* permits `docs.databricks.com` - the intuitive reading of a domain
|
|
15
|
+
* allow-list.
|
|
16
|
+
* - A **path** entry (contains a `/`, e.g. `docs.example.com/api/**`) is
|
|
17
|
+
* tested against `host + pathname` (scheme and query stripped), so path
|
|
18
|
+
* globs work without fighting the `https://` prefix.
|
|
19
|
+
*
|
|
20
|
+
* Enforcement is asymmetric by design (see the module's two consumers):
|
|
21
|
+
* `web_search` results are SILENTLY filtered to the permitted set, while an
|
|
22
|
+
* explicit `web_fetch` of a disallowed URL is refused with an error - the
|
|
23
|
+
* search never leaks a URL the caller then can't fetch, but a direct fetch
|
|
24
|
+
* of a blocked URL is a visible, correctable mistake rather than a silent
|
|
25
|
+
* empty.
|
|
26
|
+
*
|
|
27
|
+
* An empty / absent allow-list permits everything.
|
|
28
|
+
*
|
|
29
|
+
* @module
|
|
30
|
+
*/
|
|
31
|
+
import { ValidationError } from "@databricks/appkit";
|
|
32
|
+
import { match } from "@dbx-tools/path";
|
|
33
|
+
import { string } from "@dbx-tools/shared-core";
|
|
34
|
+
/** Strip a leading `scheme://` (or bare `scheme:`) from a pattern. */
|
|
35
|
+
function stripScheme(pattern) {
|
|
36
|
+
return pattern.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").replace(/^[a-z][a-z0-9+.-]*:/i, "");
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Normalize one raw allow-list entry: trim it and drop any scheme. The
|
|
40
|
+
* scheme is irrelevant to matching (we compare against hostname / host+path),
|
|
41
|
+
* so `https://docs.example.com/x` and `docs.example.com/x` are equivalent.
|
|
42
|
+
*/
|
|
43
|
+
export function normalizeUrlPattern(pattern) {
|
|
44
|
+
return stripScheme(pattern.trim());
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse a raw allow-list from config (`string[]`) or an env var (a CSV /
|
|
48
|
+
* whitespace-separated string) into a normalized, de-duplicated entry list.
|
|
49
|
+
* Entries are trimmed and scheme-stripped; empties are dropped. Mirrors the
|
|
50
|
+
* email add-on's `parseAllowedSenders` so the two policies read their config
|
|
51
|
+
* identically.
|
|
52
|
+
*/
|
|
53
|
+
export function parseAllowedUrls(raw) {
|
|
54
|
+
return string.parseList(raw, normalizeUrlPattern);
|
|
55
|
+
}
|
|
56
|
+
/** Compile a single normalized entry into a {@link CompiledPattern}. */
|
|
57
|
+
function compilePattern(pattern) {
|
|
58
|
+
if (pattern.includes("/")) {
|
|
59
|
+
// A path entry matches against `host + pathname` (no scheme, no query).
|
|
60
|
+
return { target: "hostPath", matcher: match.toPathMatcher(pattern) };
|
|
61
|
+
}
|
|
62
|
+
// A host entry matches the hostname. A bare host (no wildcard) also
|
|
63
|
+
// permits its subdomains via an added `*.<host>` alternative.
|
|
64
|
+
const globs = pattern.includes("*") ? [pattern] : [pattern, `*.${pattern}`];
|
|
65
|
+
return { target: "hostname", matcher: match.toPathMatcher(...globs) };
|
|
66
|
+
}
|
|
67
|
+
/** The URL slices a compiled pattern is tested against. */
|
|
68
|
+
function urlTargets(url) {
|
|
69
|
+
try {
|
|
70
|
+
const u = new URL(url);
|
|
71
|
+
return {
|
|
72
|
+
hostname: u.hostname,
|
|
73
|
+
// Drop a trailing slash so `example.com/api` matches `example.com/api/`.
|
|
74
|
+
hostPath: `${u.hostname}${u.pathname}`.replace(/\/$/, ""),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Compile a normalized entry list into a {@link UrlAllowList}. An empty list
|
|
83
|
+
* yields a permit-all allow-list whose {@link UrlAllowList.allows} always
|
|
84
|
+
* returns `true`. A URL that can't be parsed is never permitted by a
|
|
85
|
+
* restricted list.
|
|
86
|
+
*/
|
|
87
|
+
export function toUrlAllowList(patterns) {
|
|
88
|
+
if (patterns.length === 0) {
|
|
89
|
+
return { patterns: [], restricted: false, allows: () => true };
|
|
90
|
+
}
|
|
91
|
+
const compiled = patterns.map(compilePattern);
|
|
92
|
+
return {
|
|
93
|
+
patterns,
|
|
94
|
+
restricted: true,
|
|
95
|
+
allows: (url) => {
|
|
96
|
+
const targets = urlTargets(url);
|
|
97
|
+
if (!targets)
|
|
98
|
+
return false;
|
|
99
|
+
return compiled.some((c) => c.matcher(targets[c.target]));
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Throw when `url` is not permitted by the allow-list. No-op when the
|
|
105
|
+
* allow-list is unrestricted. The single enforcement point for the
|
|
106
|
+
* `web_fetch` path.
|
|
107
|
+
*/
|
|
108
|
+
export function assertUrlAllowed(url, allow) {
|
|
109
|
+
if (!allow.allows(url)) {
|
|
110
|
+
throw ValidationError.invalidValue("url", url, `a URL permitted by the configured allow-list (${allow.patterns.join(", ")})`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxsb3dsaXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FsbG93bGlzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFFSCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLEtBQUssRUFBb0IsTUFBTSxpQkFBaUIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFZaEQsc0VBQXNFO0FBQ3RFLFNBQVMsV0FBVyxDQUFDLE9BQWU7SUFDbEMsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLDBCQUEwQixFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUM3RixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FBQyxPQUFlO0lBQ2pELE9BQU8sV0FBVyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ3JDLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsR0FBa0M7SUFDakUsT0FBTyxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0FBQ3BELENBQUM7QUFRRCx3RUFBd0U7QUFDeEUsU0FBUyxjQUFjLENBQUMsT0FBZTtJQUNyQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUMxQix3RUFBd0U7UUFDeEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztJQUN2RSxDQUFDO0lBQ0Qsb0VBQW9FO0lBQ3BFLDhEQUE4RDtJQUM5RCxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxLQUFLLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDNUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDO0FBQ3hFLENBQUM7QUFFRCwyREFBMkQ7QUFDM0QsU0FBUyxVQUFVLENBQUMsR0FBVztJQUM3QixJQUFJLENBQUM7UUFDSCxNQUFNLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QixPQUFPO1lBQ0wsUUFBUSxFQUFFLENBQUMsQ0FBQyxRQUFRO1lBQ3BCLHlFQUF5RTtZQUN6RSxRQUFRLEVBQUUsR0FBRyxDQUFDLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztTQUMxRCxDQUFDO0lBQ0osQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUFDLFFBQTJCO0lBQ3hELElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUMxQixPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNqRSxDQUFDO0lBQ0QsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUM5QyxPQUFPO1FBQ0wsUUFBUTtRQUNSLFVBQVUsRUFBRSxJQUFJO1FBQ2hCLE1BQU0sRUFBRSxDQUFDLEdBQVcsRUFBRSxFQUFFO1lBQ3RCLE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNoQyxJQUFJLENBQUMsT0FBTztnQkFBRSxPQUFPLEtBQUssQ0FBQztZQUMzQixPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDNUQsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxHQUFXLEVBQUUsS0FBbUI7SUFDL0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN2QixNQUFNLGVBQWUsQ0FBQyxZQUFZLENBQ2hDLEtBQUssRUFDTCxHQUFHLEVBQ0gsaURBQWlELEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQzlFLENBQUM7SUFDSixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVVJMIGFsbG93LWxpc3QgcG9saWN5IGZvciB0aGUgd2ViLXNlYXJjaCBhZGQtb24uXG4gKlxuICogQSBjb25maWd1cmVkIGFsbG93LWxpc3QgcmVzdHJpY3RzIHdoaWNoIFVSTHMgdGhlIHRvb2xzIHdpbGwgc3VyZmFjZSBvclxuICogZmV0Y2guIEVhY2ggZW50cnkgaXMgYSBnbG9iIGNvbXBpbGVkIGJ5IGBAZGJ4LXRvb2xzL3BhdGhgJ3NcbiAqIHtAbGluayBtYXRjaC50b1BhdGhNYXRjaGVyfSAodGhlIHNhbWUgYE1pbmltYXRjaGAtYmFja2VkIG1hdGNoZXIgdGhlXG4gKiBwYWNrYWdlJ3MgZmlsZSBzY2FubmluZyB1c2VzKS4gQmVjYXVzZSB0aGF0IG1hdGNoZXIgdHJlYXRzIGAvYCBhcyBhXG4gKiBwYXRoLXNlZ21lbnQgYm91bmRhcnksIGVudHJpZXMgYXJlIG1hdGNoZWQgYWdhaW5zdCB0aGUgcmlnaHQgc2xpY2Ugb2YgdGhlXG4gKiBVUkwgcmF0aGVyIHRoYW4gdGhlIHJhdyBgaHJlZmA6XG4gKlxuICogLSBBICoqaG9zdCoqIGVudHJ5IChubyBgL2AgYWZ0ZXIgdGhlIG9wdGlvbmFsIHNjaGVtZSwgZS5nLiBgZGF0YWJyaWNrcy5jb21gXG4gKiAgIG9yIGAqLmRhdGFicmlja3MuY29tYCkgaXMgdGVzdGVkIGFnYWluc3QgdGhlIFVSTCdzIGBob3N0bmFtZWAuIEEgYmFyZVxuICogICBob3N0IHdpdGggbm8gd2lsZGNhcmQgYWxzbyBtYXRjaGVzIGl0cyBzdWJkb21haW5zLCBzbyBgZGF0YWJyaWNrcy5jb21gXG4gKiAgIHBlcm1pdHMgYGRvY3MuZGF0YWJyaWNrcy5jb21gIC0gdGhlIGludHVpdGl2ZSByZWFkaW5nIG9mIGEgZG9tYWluXG4gKiAgIGFsbG93LWxpc3QuXG4gKiAtIEEgKipwYXRoKiogZW50cnkgKGNvbnRhaW5zIGEgYC9gLCBlLmcuIGBkb2NzLmV4YW1wbGUuY29tL2FwaS8qKmApIGlzXG4gKiAgIHRlc3RlZCBhZ2FpbnN0IGBob3N0ICsgcGF0aG5hbWVgIChzY2hlbWUgYW5kIHF1ZXJ5IHN0cmlwcGVkKSwgc28gcGF0aFxuICogICBnbG9icyB3b3JrIHdpdGhvdXQgZmlnaHRpbmcgdGhlIGBodHRwczovL2AgcHJlZml4LlxuICpcbiAqIEVuZm9yY2VtZW50IGlzIGFzeW1tZXRyaWMgYnkgZGVzaWduIChzZWUgdGhlIG1vZHVsZSdzIHR3byBjb25zdW1lcnMpOlxuICogYHdlYl9zZWFyY2hgIHJlc3VsdHMgYXJlIFNJTEVOVExZIGZpbHRlcmVkIHRvIHRoZSBwZXJtaXR0ZWQgc2V0LCB3aGlsZSBhblxuICogZXhwbGljaXQgYHdlYl9mZXRjaGAgb2YgYSBkaXNhbGxvd2VkIFVSTCBpcyByZWZ1c2VkIHdpdGggYW4gZXJyb3IgLSB0aGVcbiAqIHNlYXJjaCBuZXZlciBsZWFrcyBhIFVSTCB0aGUgY2FsbGVyIHRoZW4gY2FuJ3QgZmV0Y2gsIGJ1dCBhIGRpcmVjdCBmZXRjaFxuICogb2YgYSBibG9ja2VkIFVSTCBpcyBhIHZpc2libGUsIGNvcnJlY3RhYmxlIG1pc3Rha2UgcmF0aGVyIHRoYW4gYSBzaWxlbnRcbiAqIGVtcHR5LlxuICpcbiAqIEFuIGVtcHR5IC8gYWJzZW50IGFsbG93LWxpc3QgcGVybWl0cyBldmVyeXRoaW5nLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBtYXRjaCwgdHlwZSBQYXRoTWF0Y2hlciB9IGZyb20gXCJAZGJ4LXRvb2xzL3BhdGhcIjtcbmltcG9ydCB7IHN0cmluZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5cbi8qKiBBIGNvbXBpbGVkIFVSTCBhbGxvdy1saXN0LiBCdWlsZCBvbmUgd2l0aCB7QGxpbmsgdG9VcmxBbGxvd0xpc3R9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBVcmxBbGxvd0xpc3Qge1xuICAvKiogVGhlIG5vcm1hbGl6ZWQgZW50cmllcyBiYWNraW5nIHRoaXMgbGlzdCAoZm9yIGRpYWdub3N0aWNzKS4gKi9cbiAgcmVhZG9ubHkgcGF0dGVybnM6IHJlYWRvbmx5IHN0cmluZ1tdO1xuICAvKiogV2hldGhlciB0aGUgbGlzdCBhY3R1YWxseSByZXN0cmljdHMgYW55dGhpbmcgKGBmYWxzZWAgPT0gcGVybWl0IGFsbCkuICovXG4gIHJlYWRvbmx5IHJlc3RyaWN0ZWQ6IGJvb2xlYW47XG4gIC8qKiBXaGV0aGVyIGB1cmxgIGlzIHBlcm1pdHRlZC4gQW4gdW5yZXN0cmljdGVkIGxpc3QgcGVybWl0cyBldmVyeXRoaW5nLiAqL1xuICBhbGxvd3ModXJsOiBzdHJpbmcpOiBib29sZWFuO1xufVxuXG4vKiogU3RyaXAgYSBsZWFkaW5nIGBzY2hlbWU6Ly9gIChvciBiYXJlIGBzY2hlbWU6YCkgZnJvbSBhIHBhdHRlcm4uICovXG5mdW5jdGlvbiBzdHJpcFNjaGVtZShwYXR0ZXJuOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gcGF0dGVybi5yZXBsYWNlKC9eW2Etel1bYS16MC05Ky4tXSo6XFwvXFwvL2ksIFwiXCIpLnJlcGxhY2UoL15bYS16XVthLXowLTkrLi1dKjovaSwgXCJcIik7XG59XG5cbi8qKlxuICogTm9ybWFsaXplIG9uZSByYXcgYWxsb3ctbGlzdCBlbnRyeTogdHJpbSBpdCBhbmQgZHJvcCBhbnkgc2NoZW1lLiBUaGVcbiAqIHNjaGVtZSBpcyBpcnJlbGV2YW50IHRvIG1hdGNoaW5nICh3ZSBjb21wYXJlIGFnYWluc3QgaG9zdG5hbWUgLyBob3N0K3BhdGgpLFxuICogc28gYGh0dHBzOi8vZG9jcy5leGFtcGxlLmNvbS94YCBhbmQgYGRvY3MuZXhhbXBsZS5jb20veGAgYXJlIGVxdWl2YWxlbnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVVcmxQYXR0ZXJuKHBhdHRlcm46IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBzdHJpcFNjaGVtZShwYXR0ZXJuLnRyaW0oKSk7XG59XG5cbi8qKlxuICogUGFyc2UgYSByYXcgYWxsb3ctbGlzdCBmcm9tIGNvbmZpZyAoYHN0cmluZ1tdYCkgb3IgYW4gZW52IHZhciAoYSBDU1YgL1xuICogd2hpdGVzcGFjZS1zZXBhcmF0ZWQgc3RyaW5nKSBpbnRvIGEgbm9ybWFsaXplZCwgZGUtZHVwbGljYXRlZCBlbnRyeSBsaXN0LlxuICogRW50cmllcyBhcmUgdHJpbW1lZCBhbmQgc2NoZW1lLXN0cmlwcGVkOyBlbXB0aWVzIGFyZSBkcm9wcGVkLiBNaXJyb3JzIHRoZVxuICogZW1haWwgYWRkLW9uJ3MgYHBhcnNlQWxsb3dlZFNlbmRlcnNgIHNvIHRoZSB0d28gcG9saWNpZXMgcmVhZCB0aGVpciBjb25maWdcbiAqIGlkZW50aWNhbGx5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VBbGxvd2VkVXJscyhyYXc6IHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkKTogc3RyaW5nW10ge1xuICByZXR1cm4gc3RyaW5nLnBhcnNlTGlzdChyYXcsIG5vcm1hbGl6ZVVybFBhdHRlcm4pO1xufVxuXG4vKiogT25lIGNvbXBpbGVkIGVudHJ5OiB3aGljaCBVUkwgc2xpY2UgaXQgdGVzdHMsIGFuZCB0aGUgbWF0Y2hlciBmb3IgaXQuICovXG5pbnRlcmZhY2UgQ29tcGlsZWRQYXR0ZXJuIHtcbiAgdGFyZ2V0OiBcImhvc3RuYW1lXCIgfCBcImhvc3RQYXRoXCI7XG4gIG1hdGNoZXI6IFBhdGhNYXRjaGVyO1xufVxuXG4vKiogQ29tcGlsZSBhIHNpbmdsZSBub3JtYWxpemVkIGVudHJ5IGludG8gYSB7QGxpbmsgQ29tcGlsZWRQYXR0ZXJufS4gKi9cbmZ1bmN0aW9uIGNvbXBpbGVQYXR0ZXJuKHBhdHRlcm46IHN0cmluZyk6IENvbXBpbGVkUGF0dGVybiB7XG4gIGlmIChwYXR0ZXJuLmluY2x1ZGVzKFwiL1wiKSkge1xuICAgIC8vIEEgcGF0aCBlbnRyeSBtYXRjaGVzIGFnYWluc3QgYGhvc3QgKyBwYXRobmFtZWAgKG5vIHNjaGVtZSwgbm8gcXVlcnkpLlxuICAgIHJldHVybiB7IHRhcmdldDogXCJob3N0UGF0aFwiLCBtYXRjaGVyOiBtYXRjaC50b1BhdGhNYXRjaGVyKHBhdHRlcm4pIH07XG4gIH1cbiAgLy8gQSBob3N0IGVudHJ5IG1hdGNoZXMgdGhlIGhvc3RuYW1lLiBBIGJhcmUgaG9zdCAobm8gd2lsZGNhcmQpIGFsc29cbiAgLy8gcGVybWl0cyBpdHMgc3ViZG9tYWlucyB2aWEgYW4gYWRkZWQgYCouPGhvc3Q+YCBhbHRlcm5hdGl2ZS5cbiAgY29uc3QgZ2xvYnMgPSBwYXR0ZXJuLmluY2x1ZGVzKFwiKlwiKSA/IFtwYXR0ZXJuXSA6IFtwYXR0ZXJuLCBgKi4ke3BhdHRlcm59YF07XG4gIHJldHVybiB7IHRhcmdldDogXCJob3N0bmFtZVwiLCBtYXRjaGVyOiBtYXRjaC50b1BhdGhNYXRjaGVyKC4uLmdsb2JzKSB9O1xufVxuXG4vKiogVGhlIFVSTCBzbGljZXMgYSBjb21waWxlZCBwYXR0ZXJuIGlzIHRlc3RlZCBhZ2FpbnN0LiAqL1xuZnVuY3Rpb24gdXJsVGFyZ2V0cyh1cmw6IHN0cmluZyk6IHsgaG9zdG5hbWU6IHN0cmluZzsgaG9zdFBhdGg6IHN0cmluZyB9IHwgdW5kZWZpbmVkIHtcbiAgdHJ5IHtcbiAgICBjb25zdCB1ID0gbmV3IFVSTCh1cmwpO1xuICAgIHJldHVybiB7XG4gICAgICBob3N0bmFtZTogdS5ob3N0bmFtZSxcbiAgICAgIC8vIERyb3AgYSB0cmFpbGluZyBzbGFzaCBzbyBgZXhhbXBsZS5jb20vYXBpYCBtYXRjaGVzIGBleGFtcGxlLmNvbS9hcGkvYC5cbiAgICAgIGhvc3RQYXRoOiBgJHt1Lmhvc3RuYW1lfSR7dS5wYXRobmFtZX1gLnJlcGxhY2UoL1xcLyQvLCBcIlwiKSxcbiAgICB9O1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogQ29tcGlsZSBhIG5vcm1hbGl6ZWQgZW50cnkgbGlzdCBpbnRvIGEge0BsaW5rIFVybEFsbG93TGlzdH0uIEFuIGVtcHR5IGxpc3RcbiAqIHlpZWxkcyBhIHBlcm1pdC1hbGwgYWxsb3ctbGlzdCB3aG9zZSB7QGxpbmsgVXJsQWxsb3dMaXN0LmFsbG93c30gYWx3YXlzXG4gKiByZXR1cm5zIGB0cnVlYC4gQSBVUkwgdGhhdCBjYW4ndCBiZSBwYXJzZWQgaXMgbmV2ZXIgcGVybWl0dGVkIGJ5IGFcbiAqIHJlc3RyaWN0ZWQgbGlzdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvVXJsQWxsb3dMaXN0KHBhdHRlcm5zOiByZWFkb25seSBzdHJpbmdbXSk6IFVybEFsbG93TGlzdCB7XG4gIGlmIChwYXR0ZXJucy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4geyBwYXR0ZXJuczogW10sIHJlc3RyaWN0ZWQ6IGZhbHNlLCBhbGxvd3M6ICgpID0+IHRydWUgfTtcbiAgfVxuICBjb25zdCBjb21waWxlZCA9IHBhdHRlcm5zLm1hcChjb21waWxlUGF0dGVybik7XG4gIHJldHVybiB7XG4gICAgcGF0dGVybnMsXG4gICAgcmVzdHJpY3RlZDogdHJ1ZSxcbiAgICBhbGxvd3M6ICh1cmw6IHN0cmluZykgPT4ge1xuICAgICAgY29uc3QgdGFyZ2V0cyA9IHVybFRhcmdldHModXJsKTtcbiAgICAgIGlmICghdGFyZ2V0cykgcmV0dXJuIGZhbHNlO1xuICAgICAgcmV0dXJuIGNvbXBpbGVkLnNvbWUoKGMpID0+IGMubWF0Y2hlcih0YXJnZXRzW2MudGFyZ2V0XSkpO1xuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogVGhyb3cgd2hlbiBgdXJsYCBpcyBub3QgcGVybWl0dGVkIGJ5IHRoZSBhbGxvdy1saXN0LiBOby1vcCB3aGVuIHRoZVxuICogYWxsb3ctbGlzdCBpcyB1bnJlc3RyaWN0ZWQuIFRoZSBzaW5nbGUgZW5mb3JjZW1lbnQgcG9pbnQgZm9yIHRoZVxuICogYHdlYl9mZXRjaGAgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFzc2VydFVybEFsbG93ZWQodXJsOiBzdHJpbmcsIGFsbG93OiBVcmxBbGxvd0xpc3QpOiB2b2lkIHtcbiAgaWYgKCFhbGxvdy5hbGxvd3ModXJsKSkge1xuICAgIHRocm93IFZhbGlkYXRpb25FcnJvci5pbnZhbGlkVmFsdWUoXG4gICAgICBcInVybFwiLFxuICAgICAgdXJsLFxuICAgICAgYGEgVVJMIHBlcm1pdHRlZCBieSB0aGUgY29uZmlndXJlZCBhbGxvdy1saXN0ICgke2FsbG93LnBhdHRlcm5zLmpvaW4oXCIsIFwiKX0pYCxcbiAgICApO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the web-search plugin: the typed
|
|
3
|
+
* {@link WebSearchPluginConfig} (the plugin's slice of AppKit config), the
|
|
4
|
+
* JSON Schema the manifest publishes for it, and {@link resolveWebSearchConfig}
|
|
5
|
+
* which layers that config over environment defaults into the concrete
|
|
6
|
+
* {@link ResolvedWebSearchConfig} the runtime + tools read.
|
|
7
|
+
*
|
|
8
|
+
* `web_search` runs on the Databricks Model Serving native web-search tool
|
|
9
|
+
* (see `provider.ts` / `search.ts`), so the key knob is which web-search-
|
|
10
|
+
* capable model to use. It resolves independently of the calling agent's chat
|
|
11
|
+
* model: `model` (a name, loose name, or capability class) is fuzzy-matched
|
|
12
|
+
* against the workspace catalogue, and when nothing is pinned the
|
|
13
|
+
* {@link WebSearchPluginConfig.modelFallbacks} order (Gemini, then GPT, then a
|
|
14
|
+
* repo floor) picks the first web-search-capable endpoint that exists.
|
|
15
|
+
*
|
|
16
|
+
* Which endpoint id is used follows the standard precedence - explicit plugin
|
|
17
|
+
* config, then environment, then a default - with two environment sources:
|
|
18
|
+
*
|
|
19
|
+
* 1. `model` in plugin config;
|
|
20
|
+
* 2. `WEB_SEARCH_MODEL`, the dedicated override, so a deployment can point
|
|
21
|
+
* web search at a different endpoint than the agent's chat model;
|
|
22
|
+
* 3. `DATABRICKS_SERVING_ENDPOINT_NAME`, AppKit's standard name for a
|
|
23
|
+
* Model Serving binding, honored so the resource declared in the manifest
|
|
24
|
+
* wires this plugin up like any other. Because that binding is shared
|
|
25
|
+
* with whatever else the app serves, it is treated as a preference: an
|
|
26
|
+
* endpoint that cannot run the native web-search tool is skipped in
|
|
27
|
+
* favor of {@link WebSearchPluginConfig.modelFallbacks} rather than
|
|
28
|
+
* failing the call. A pin from (1) or (2) is explicit and DOES fail;
|
|
29
|
+
* 4. otherwise the fallback order, resolved against the live catalogue.
|
|
30
|
+
*
|
|
31
|
+
* Which model wins is decided lazily, at call time, against the live
|
|
32
|
+
* catalogue. Resolution here is eager about everything else and fails loudly
|
|
33
|
+
* on a contradiction: an unparseable `WEB_SEARCH_TOOLS`, an unknown
|
|
34
|
+
* {@link UrlPolicyMode}, or a URL policy that disagrees with the allow-list it
|
|
35
|
+
* was given.
|
|
36
|
+
*
|
|
37
|
+
* Env fallbacks: `WEB_SEARCH_MODEL`, `DATABRICKS_SERVING_ENDPOINT_NAME`,
|
|
38
|
+
* `WEB_SEARCH_MODEL_FALLBACKS`, `WEB_SEARCH_TOOLS` (JSON),
|
|
39
|
+
* `WEB_SEARCH_URL_POLICY`, `WEB_SEARCH_ALLOWED_URLS`,
|
|
40
|
+
* `WEB_SEARCH_MAX_CITATIONS`, `WEB_SEARCH_FETCH_MAX_LENGTH`,
|
|
41
|
+
* `WEB_SEARCH_TIMEOUT_MS`, `WEB_SEARCH_SCRAPE_FALLBACK`, `WEB_SEARCH_FUZZY`,
|
|
42
|
+
* `WEB_SEARCH_FUZZY_THRESHOLD`.
|
|
43
|
+
*
|
|
44
|
+
* @module
|
|
45
|
+
*/
|
|
46
|
+
import { type BasePluginConfig } from "@databricks/appkit";
|
|
47
|
+
import { type OneOrMany } from "@dbx-tools/shared-core";
|
|
48
|
+
import type { JSONSchema7 } from "json-schema";
|
|
49
|
+
import { type UrlAllowList } from "./allowlist.js";
|
|
50
|
+
/**
|
|
51
|
+
* A URL-pattern gate for per-tool approval. `true` gates every call; a
|
|
52
|
+
* pattern (or list of patterns, in the {@link OneOrMany} shape used across
|
|
53
|
+
* the repo) gates only calls whose URL matches. Patterns use the same glob
|
|
54
|
+
* syntax as the allow-list (see `allowlist.ts`). Omit / `false` for no
|
|
55
|
+
* approval. Normalized to an {@link ApprovalPolicy} before use.
|
|
56
|
+
*/
|
|
57
|
+
export type ApprovalGate = boolean | OneOrMany<string> | string;
|
|
58
|
+
/**
|
|
59
|
+
* The normalized form of an {@link ApprovalGate}: which calls pause for a
|
|
60
|
+
* human. `"none"` runs every call straight through, `"always"` gates all of
|
|
61
|
+
* them, and `"urls"` gates only calls whose URL matches one of `patterns`.
|
|
62
|
+
*/
|
|
63
|
+
export type ApprovalPolicy = {
|
|
64
|
+
readonly mode: "none";
|
|
65
|
+
} | {
|
|
66
|
+
readonly mode: "always";
|
|
67
|
+
} | {
|
|
68
|
+
readonly mode: "urls";
|
|
69
|
+
readonly patterns: readonly string[];
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Which URLs the tools may reach. `"allowlist"` permits only the configured
|
|
73
|
+
* entries; `"unrestricted"` names the permissive mode explicitly, so an
|
|
74
|
+
* unrestricted deployment is a stated choice visible in the boot log rather
|
|
75
|
+
* than an empty list nobody noticed.
|
|
76
|
+
*/
|
|
77
|
+
export type UrlPolicyMode = "unrestricted" | "allowlist";
|
|
78
|
+
/** Dedicated override for the web-search endpoint id. */
|
|
79
|
+
export declare const MODEL_ENV = "WEB_SEARCH_MODEL";
|
|
80
|
+
/** AppKit's standard environment name for a Model Serving endpoint binding. */
|
|
81
|
+
export declare const SERVING_ENDPOINT_ENV = "DATABRICKS_SERVING_ENDPOINT_NAME";
|
|
82
|
+
/** Where the pinned web-search endpoint id came from, or `"none"` when unpinned. */
|
|
83
|
+
export type ModelSource = "config" | typeof MODEL_ENV | typeof SERVING_ENDPOINT_ENV | "none";
|
|
84
|
+
/**
|
|
85
|
+
* Default web-search model preference, tried in order when no model is
|
|
86
|
+
* pinned. Gemini first, then GPT - both support the native web-search tool;
|
|
87
|
+
* a workspace typically has at least one. Each is fuzzy-matched against the
|
|
88
|
+
* live catalogue, so a close variant (e.g. `databricks-gemini-3-1-pro`) is
|
|
89
|
+
* picked when the exact id isn't present.
|
|
90
|
+
*/
|
|
91
|
+
export declare const DEFAULT_MODEL_FALLBACKS: readonly string[];
|
|
92
|
+
/** Default cap on the number of citations returned from a single search. */
|
|
93
|
+
export declare const DEFAULT_MAX_CITATIONS = 10;
|
|
94
|
+
/** Default cap on characters returned from a single `web_fetch`. */
|
|
95
|
+
export declare const DEFAULT_FETCH_MAX_LENGTH = 50000;
|
|
96
|
+
/** Default per-request network timeout (ms) for search + fetch. */
|
|
97
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
98
|
+
/** AppKit config accepted by the web-search plugin. */
|
|
99
|
+
export interface WebSearchPluginConfig extends BasePluginConfig {
|
|
100
|
+
/**
|
|
101
|
+
* The web-search model to use by default: a Databricks serving endpoint
|
|
102
|
+
* name (`"databricks-gemini-3-pro"`), a loose name (`"gemini"`, `"gpt"`),
|
|
103
|
+
* or a capability class. Fuzzy-matched against the live catalogue. Falls
|
|
104
|
+
* back to `WEB_SEARCH_MODEL`, then `DATABRICKS_SERVING_ENDPOINT_NAME`, then
|
|
105
|
+
* the {@link modelFallbacks} order. Chosen independently of the calling
|
|
106
|
+
* agent's chat model.
|
|
107
|
+
*/
|
|
108
|
+
model?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Priority-ordered web-search model candidates tried when {@link model} is
|
|
111
|
+
* unset, each fuzzy-matched and checked for web-search support. Falls back
|
|
112
|
+
* to `WEB_SEARCH_MODEL_FALLBACKS` (comma/space-separated), then
|
|
113
|
+
* {@link DEFAULT_MODEL_FALLBACKS} (Gemini, then GPT).
|
|
114
|
+
*/
|
|
115
|
+
modelFallbacks?: string | string[];
|
|
116
|
+
/**
|
|
117
|
+
* Provider -> tool-spec override map, merged over the built-in
|
|
118
|
+
* {@link WEB_SEARCH_PROVIDERS} defaults. Keyed by provider family
|
|
119
|
+
* (`"openai"`, `"gemini"`); each value may override the `tool` entry
|
|
120
|
+
* and/or the `api` surface. Use to change the tool shape as the platform
|
|
121
|
+
* evolves without a code change. Falls back to `WEB_SEARCH_TOOLS` parsed as
|
|
122
|
+
* JSON. This is the `WEB_SEARCH_TOOLS` setting.
|
|
123
|
+
*/
|
|
124
|
+
webSearchTools?: Record<string, unknown>;
|
|
125
|
+
/**
|
|
126
|
+
* Enable fuzzy matching of loose model names against the catalogue.
|
|
127
|
+
* Defaults to `true`; falls back to `WEB_SEARCH_FUZZY`.
|
|
128
|
+
*/
|
|
129
|
+
modelFuzzyMatch?: boolean;
|
|
130
|
+
/** Fuse.js fuzzy threshold. Falls back to `WEB_SEARCH_FUZZY_THRESHOLD`, then the shared default. */
|
|
131
|
+
modelFuzzyThreshold?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Hard cap on the number of citations a single search returns. Falls back
|
|
134
|
+
* to `WEB_SEARCH_MAX_CITATIONS`, then {@link DEFAULT_MAX_CITATIONS}.
|
|
135
|
+
*/
|
|
136
|
+
maxCitations?: number;
|
|
137
|
+
/**
|
|
138
|
+
* Hard cap on the character length of a single `web_fetch` result. Falls
|
|
139
|
+
* back to `WEB_SEARCH_FETCH_MAX_LENGTH`, then {@link DEFAULT_FETCH_MAX_LENGTH}.
|
|
140
|
+
*/
|
|
141
|
+
fetchMaxLength?: number;
|
|
142
|
+
/**
|
|
143
|
+
* Per-request network timeout in ms for search + fetch. Falls back to
|
|
144
|
+
* `WEB_SEARCH_TIMEOUT_MS`, then {@link DEFAULT_TIMEOUT_MS}.
|
|
145
|
+
*/
|
|
146
|
+
timeoutMs?: number;
|
|
147
|
+
/**
|
|
148
|
+
* Fall back to a DuckDuckGo scrape when the workspace has NO deployed
|
|
149
|
+
* web-search-capable model (no GPT / Gemini serving endpoint). The native
|
|
150
|
+
* Databricks tool is always preferred; this only kicks in when there is no
|
|
151
|
+
* native option, so the tool still returns results instead of erroring.
|
|
152
|
+
* Defaults to `true`; set `false` (or `WEB_SEARCH_SCRAPE_FALLBACK=0`) to
|
|
153
|
+
* require a native model and error otherwise.
|
|
154
|
+
*/
|
|
155
|
+
scrapeFallback?: boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Which URLs the tools may reach ({@link UrlPolicyMode}). Falls back to
|
|
158
|
+
* `WEB_SEARCH_URL_POLICY`, then to `"allowlist"` when {@link allowedUrls}
|
|
159
|
+
* has entries and `"unrestricted"` when it does not. Naming the mode
|
|
160
|
+
* explicitly is the way to state that an open deployment is intended;
|
|
161
|
+
* `"allowlist"` with no entries, or `"unrestricted"` alongside entries, is
|
|
162
|
+
* a contradiction and fails at resolution.
|
|
163
|
+
*/
|
|
164
|
+
urlPolicy?: UrlPolicyMode;
|
|
165
|
+
/**
|
|
166
|
+
* Optional URL allow-list. Each entry is a glob (or bare host) tested
|
|
167
|
+
* against a URL's full `href`. When set, `web_search` silently filters
|
|
168
|
+
* citations to the permitted set and `web_fetch` refuses a disallowed URL.
|
|
169
|
+
* Accepts a `string[]` or a comma-/whitespace-separated string; falls back
|
|
170
|
+
* to `WEB_SEARCH_ALLOWED_URLS`. Omit (or leave empty) for no restriction.
|
|
171
|
+
* See `allowlist.ts`.
|
|
172
|
+
*/
|
|
173
|
+
allowedUrls?: string | string[];
|
|
174
|
+
/**
|
|
175
|
+
* Approval gate applied to BOTH tools (per-tool overrides via
|
|
176
|
+
* {@link WebSearchToolOptions.approval} win). `true` gates every call;
|
|
177
|
+
* a URL-pattern (or list) gates only matching calls; an
|
|
178
|
+
* {@link ApprovalPolicy} states the mode directly. Omit for no approval.
|
|
179
|
+
*/
|
|
180
|
+
approval?: ApprovalGate | ApprovalPolicy;
|
|
181
|
+
}
|
|
182
|
+
/** Concrete, validated config the runtime + tools read. */
|
|
183
|
+
export interface ResolvedWebSearchConfig {
|
|
184
|
+
/** Pinned web-search model, when configured (else undefined - use fallbacks). */
|
|
185
|
+
model?: string;
|
|
186
|
+
/** Where {@link model} came from, which decides whether an unsupported pin is fatal. */
|
|
187
|
+
modelSource: ModelSource;
|
|
188
|
+
/** Ordered fallback model candidates (Gemini, then GPT, then a floor). */
|
|
189
|
+
modelFallbacks: readonly string[];
|
|
190
|
+
/** Provider -> tool-spec override map, merged over the built-in defaults. */
|
|
191
|
+
webSearchTools: Record<string, unknown>;
|
|
192
|
+
/** Whether to fuzzy-match loose model names. */
|
|
193
|
+
fuzzy: boolean;
|
|
194
|
+
/** Fuse.js fuzzy threshold. */
|
|
195
|
+
fuzzyThreshold: number;
|
|
196
|
+
maxCitations: number;
|
|
197
|
+
fetchMaxLength: number;
|
|
198
|
+
timeoutMs: number;
|
|
199
|
+
/** Whether to scrape-fallback when no native web-search model is deployed. */
|
|
200
|
+
scrapeFallback: boolean;
|
|
201
|
+
/** The named URL policy in force. */
|
|
202
|
+
urlPolicy: UrlPolicyMode;
|
|
203
|
+
/** Compiled allow-list (permit-all under the `unrestricted` policy). */
|
|
204
|
+
allowList: UrlAllowList;
|
|
205
|
+
/** Default per-tool approval policy. */
|
|
206
|
+
approval: ApprovalPolicy;
|
|
207
|
+
}
|
|
208
|
+
/** JSON Schema published on the manifest's `config.schema`. */
|
|
209
|
+
export declare const WEB_SEARCH_CONFIG_SCHEMA: JSONSchema7;
|
|
210
|
+
/**
|
|
211
|
+
* Normalize any accepted approval spelling into an {@link ApprovalPolicy}.
|
|
212
|
+
* A pattern gate with no usable patterns collapses to `"none"` rather than
|
|
213
|
+
* gating everything, so a blank env var can never wedge the tools behind an
|
|
214
|
+
* approval nobody configured.
|
|
215
|
+
*/
|
|
216
|
+
export declare function toApprovalPolicy(gate: ApprovalGate | ApprovalPolicy | undefined): ApprovalPolicy;
|
|
217
|
+
/**
|
|
218
|
+
* Resolve plugin config over environment defaults into the concrete
|
|
219
|
+
* {@link ResolvedWebSearchConfig}. Which model is used stays lazy - it is
|
|
220
|
+
* picked at call time against the live catalogue - but everything else is
|
|
221
|
+
* settled here, and a contradiction (unparseable `WEB_SEARCH_TOOLS`, an
|
|
222
|
+
* unknown URL policy, a policy that disagrees with its allow-list) throws a
|
|
223
|
+
* {@link ConfigurationError} naming the field and the environment variable.
|
|
224
|
+
*/
|
|
225
|
+
export declare function resolveWebSearchConfig(config?: WebSearchPluginConfig): ResolvedWebSearchConfig;
|
|
226
|
+
/**
|
|
227
|
+
* Resolve an approval gate against a set of candidate URLs into a concrete
|
|
228
|
+
* boolean: `"none"` / `"always"` pass straight through; a `"urls"` policy
|
|
229
|
+
* gates when ANY candidate matches. Empty candidates with a pattern gate
|
|
230
|
+
* never match (nothing to approve). Reuses the allow-list matcher so approval
|
|
231
|
+
* globs read exactly like allow-list globs.
|
|
232
|
+
*/
|
|
233
|
+
export declare function approvalMatches(gate: ApprovalGate | ApprovalPolicy, urls: readonly string[]): boolean;
|