feat: add web tools

This commit is contained in:
Peter Steinberger
2026-01-15 04:07:29 +00:00
parent 31d3aef8d6
commit f275cc180b
18 changed files with 736 additions and 165 deletions

View File

@@ -105,6 +105,17 @@ const FIELD_LABELS: Record<string, string> = {
"agents.list[].tools.byProvider": "Agent Tool Policy by Provider",
"tools.exec.applyPatch.enabled": "Enable apply_patch",
"tools.exec.applyPatch.allowModels": "apply_patch Model Allowlist",
"tools.web.search.enabled": "Enable Web Search Tool",
"tools.web.search.provider": "Web Search Provider",
"tools.web.search.apiKey": "Brave Search API Key",
"tools.web.search.maxResults": "Web Search Max Results",
"tools.web.search.timeoutSeconds": "Web Search Timeout (sec)",
"tools.web.search.cacheTtlMinutes": "Web Search Cache TTL (min)",
"tools.web.fetch.enabled": "Enable Web Fetch Tool",
"tools.web.fetch.maxChars": "Web Fetch Max Chars",
"tools.web.fetch.timeoutSeconds": "Web Fetch Timeout (sec)",
"tools.web.fetch.cacheTtlMinutes": "Web Fetch Cache TTL (min)",
"tools.web.fetch.userAgent": "Web Fetch User-Agent",
"gateway.controlUi.basePath": "Control UI Base Path",
"gateway.http.endpoints.chatCompletions.enabled": "OpenAI Chat Completions Endpoint",
"gateway.reload.mode": "Config Reload Mode",
@@ -219,6 +230,17 @@ const FIELD_HELP: Record<string, string> = {
"Experimental. Enables apply_patch for OpenAI models when allowed by tool policy.",
"tools.exec.applyPatch.allowModels":
'Optional allowlist of model ids (e.g. "gpt-5.2" or "openai/gpt-5.2").',
"tools.web.search.enabled": "Enable the web_search tool (requires Brave API key).",
"tools.web.search.provider": 'Search provider (only "brave" supported today).',
"tools.web.search.apiKey": "Brave Search API key (fallback: BRAVE_API_KEY env var).",
"tools.web.search.maxResults": "Default number of results to return (1-10).",
"tools.web.search.timeoutSeconds": "Timeout in seconds for web_search requests.",
"tools.web.search.cacheTtlMinutes": "Cache TTL in minutes for web_search results.",
"tools.web.fetch.enabled": "Enable the web_fetch tool (lightweight HTTP fetch).",
"tools.web.fetch.maxChars": "Max characters returned by web_fetch (truncated).",
"tools.web.fetch.timeoutSeconds": "Timeout in seconds for web_fetch requests.",
"tools.web.fetch.cacheTtlMinutes": "Cache TTL in minutes for web_fetch results.",
"tools.web.fetch.userAgent": "Override User-Agent header for web_fetch requests.",
"channels.slack.allowBots":
"Allow bot-authored messages to trigger Slack replies (default: false).",
"auth.profiles": "Named auth profiles (provider + mode + optional email).",

View File

@@ -73,6 +73,34 @@ export type ToolsConfig = {
profile?: ToolProfileId;
allow?: string[];
deny?: string[];
web?: {
search?: {
/** Enable web search tool (default: true when API key is present). */
enabled?: boolean;
/** Search provider (currently "brave"). */
provider?: "brave";
/** Brave Search API key (optional; defaults to BRAVE_API_KEY env var). */
apiKey?: string;
/** Default search results count (1-10). */
maxResults?: number;
/** Timeout in seconds for search requests. */
timeoutSeconds?: number;
/** Cache TTL in minutes for search results. */
cacheTtlMinutes?: number;
};
fetch?: {
/** Enable web fetch tool (default: false). */
enabled?: boolean;
/** Max characters to return from fetched content. */
maxChars?: number;
/** Timeout in seconds for fetch requests. */
timeoutSeconds?: number;
/** Cache TTL in minutes for fetched content. */
cacheTtlMinutes?: number;
/** Override User-Agent header for fetch requests. */
userAgent?: string;
};
};
audio?: {
transcription?: {
/** CLI args (template-enabled). */

View File

@@ -114,6 +114,34 @@ export const ToolPolicySchema = z
})
.optional();
export const ToolsWebSearchSchema = z
.object({
enabled: z.boolean().optional(),
provider: z.union([z.literal("brave")]).optional(),
apiKey: z.string().optional(),
maxResults: z.number().int().positive().optional(),
timeoutSeconds: z.number().int().positive().optional(),
cacheTtlMinutes: z.number().nonnegative().optional(),
})
.optional();
export const ToolsWebFetchSchema = z
.object({
enabled: z.boolean().optional(),
maxChars: z.number().int().positive().optional(),
timeoutSeconds: z.number().int().positive().optional(),
cacheTtlMinutes: z.number().nonnegative().optional(),
userAgent: z.string().optional(),
})
.optional();
export const ToolsWebSchema = z
.object({
search: ToolsWebSearchSchema,
fetch: ToolsWebFetchSchema,
})
.optional();
export const ToolProfileSchema = z
.union([z.literal("minimal"), z.literal("coding"), z.literal("messaging"), z.literal("full")])
.optional();
@@ -245,6 +273,7 @@ export const ToolsSchema = z
profile: ToolProfileSchema,
allow: z.array(z.string()).optional(),
deny: z.array(z.string()).optional(),
web: ToolsWebSchema,
audio: z
.object({
transcription: ToolsAudioTranscriptionSchema,