mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
feat: Add Anthropic web search and web fetch tools support
Implements comprehensive support for Anthropic's web search (web_search_20250305) and web fetch (web_fetch_20250910) tools. - Add llmVndAntWebSearch and llmVndAntWebFetch parameters with ['auto', 'off'] options - Enable tools for Claude 4.5, 4.1, 4, 3.7, 3.5 Sonnet/Haiku/Opus models (including thinking variants) - Inject web_search_20250305 and web_fetch_20250910 tools based on parameter values - Configure web search with max_uses=5 for progressive searches - Configure web fetch with max_uses=5 and citations enabled - Add dynamic beta header injection for web fetch (web-fetch-2025-09-10) - Add UI controls in model settings for easy parameter configuration Parser already supports web_search_tool_result and web_fetch_tool_result blocks (no changes needed). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Enrico Ros <enricoros@users.noreply.github.com>
This commit is contained in:
@@ -88,6 +88,22 @@ export const DModelParameterRegistry = {
|
||||
} as const,
|
||||
} as const,
|
||||
|
||||
llmVndAntWebSearch: {
|
||||
label: 'Web Search',
|
||||
type: 'enum' as const,
|
||||
description: 'Enable web search for real-time information',
|
||||
values: ['auto', 'off'] as const,
|
||||
// No initialValue - undefined means off (same as 'off')
|
||||
} as const,
|
||||
|
||||
llmVndAntWebFetch: {
|
||||
label: 'Web Fetch',
|
||||
type: 'enum' as const,
|
||||
description: 'Enable fetching content from web pages and PDFs',
|
||||
values: ['auto', 'off'] as const,
|
||||
// No initialValue - undefined means off (same as 'off')
|
||||
} as const,
|
||||
|
||||
llmVndGeminiAspectRatio: {
|
||||
label: 'Aspect Ratio',
|
||||
type: 'enum' as const,
|
||||
|
||||
@@ -406,6 +406,8 @@ export namespace AixWire_API {
|
||||
topP: z.number().min(0).max(1).optional(),
|
||||
forceNoStream: z.boolean().optional(),
|
||||
vndAntThinkingBudget: z.number().nullable().optional(),
|
||||
vndAntWebSearch: z.enum(['auto', 'off']).optional(),
|
||||
vndAntWebFetch: z.enum(['auto', 'off']).optional(),
|
||||
vndGeminiAspectRatio: z.enum(['1:1', '2:3', '3:2', '3:4', '4:3', '9:16', '16:9', '21:9']).optional(),
|
||||
vndGeminiGoogleSearch: z.enum(['unfiltered', '1d', '1w', '1m', '6m', '1y']).optional(),
|
||||
vndGeminiShowThoughts: z.boolean().optional(),
|
||||
|
||||
@@ -141,12 +141,38 @@ export function aixToAnthropicMessageCreate(model: AixAPI_Model, _chatGenerate:
|
||||
// --- Tools ---
|
||||
|
||||
// Allow/deny auto-adding hosted tools when custom tools are present
|
||||
// const hasCustomTools = chatGenerate.tools?.some(t => t.type === 'function_call');
|
||||
// const hasRestrictivePolicy = chatGenerate.toolsPolicy?.type === 'any' || chatGenerate.toolsPolicy?.type === 'function_call';
|
||||
// const skipHostedToolsDueToCustomTools = hasCustomTools && hasRestrictivePolicy;
|
||||
const hasCustomTools = chatGenerate.tools?.some(t => t.type === 'function_call');
|
||||
const hasRestrictivePolicy = chatGenerate.toolsPolicy?.type === 'any' || chatGenerate.toolsPolicy?.type === 'function_call';
|
||||
const skipHostedToolsDueToCustomTools = hasCustomTools && hasRestrictivePolicy;
|
||||
|
||||
// Hosted tools
|
||||
// ...
|
||||
if (!skipHostedToolsDueToCustomTools) {
|
||||
const hostedTools: NonNullable<TRequest['tools']> = [];
|
||||
|
||||
// Web Search Tool
|
||||
if (model.vndAntWebSearch === 'auto') {
|
||||
hostedTools.push({
|
||||
type: 'web_search_20250305',
|
||||
name: 'web_search',
|
||||
max_uses: 5, // Allow up to 5 progressive searches
|
||||
});
|
||||
}
|
||||
|
||||
// Web Fetch Tool
|
||||
if (model.vndAntWebFetch === 'auto') {
|
||||
hostedTools.push({
|
||||
type: 'web_fetch_20250910',
|
||||
name: 'web_fetch',
|
||||
max_uses: 5, // Allow up to 5 fetches
|
||||
citations: { enabled: true }, // Enable citations
|
||||
});
|
||||
}
|
||||
|
||||
// Merge hosted tools with custom tools
|
||||
if (hostedTools.length > 0) {
|
||||
payload.tools = payload.tools ? [...payload.tools, ...hostedTools] : hostedTools;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Preemptive error detection with server-side payload validation before sending it upstream
|
||||
|
||||
@@ -36,15 +36,28 @@ export function createChatGenerateDispatch(access: AixAPI_Access, model: AixAPI_
|
||||
} {
|
||||
|
||||
switch (access.dialect) {
|
||||
case 'anthropic':
|
||||
case 'anthropic': {
|
||||
const anthropicRequest = anthropicAccess(access, model.id, '/v1/messages');
|
||||
|
||||
// Add web fetch beta header if enabled
|
||||
if (model.vndAntWebFetch === 'auto') {
|
||||
const currentBeta = anthropicRequest.headers['anthropic-beta'] as string || '';
|
||||
const betaFeatures = currentBeta ? currentBeta.split(',') : [];
|
||||
if (!betaFeatures.includes('web-fetch-2025-09-10')) {
|
||||
betaFeatures.push('web-fetch-2025-09-10');
|
||||
anthropicRequest.headers['anthropic-beta'] = betaFeatures.join(',');
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
request: {
|
||||
...anthropicAccess(access, model.id, '/v1/messages'),
|
||||
...anthropicRequest,
|
||||
body: aixToAnthropicMessageCreate(model, chatGenerate, streaming),
|
||||
},
|
||||
demuxerFormat: streaming ? 'fast-sse' : null,
|
||||
chatGenerateParse: streaming ? createAnthropicMessageParser() : createAnthropicMessageParserNS(),
|
||||
};
|
||||
}
|
||||
|
||||
case 'gemini':
|
||||
/**
|
||||
|
||||
@@ -80,6 +80,18 @@ const _xaiSearchModeOptions = [
|
||||
{ value: 'off', label: 'Off', description: 'Never perform a search' },
|
||||
] as const;
|
||||
|
||||
const _antWebSearchOptions = [
|
||||
{ value: 'auto', label: 'On', description: 'Enable web search for real-time information' },
|
||||
{ value: 'off', label: 'Off', description: 'Disabled (default)' },
|
||||
{ value: _UNSPECIFIED, label: 'Off', description: 'Disabled (default)' },
|
||||
] as const;
|
||||
|
||||
const _antWebFetchOptions = [
|
||||
{ value: 'auto', label: 'On', description: 'Enable fetching web content and PDFs' },
|
||||
{ value: 'off', label: 'Off', description: 'Disabled (default)' },
|
||||
{ value: _UNSPECIFIED, label: 'Off', description: 'Disabled (default)' },
|
||||
] as const;
|
||||
|
||||
const _imageGenerationOptions = [
|
||||
{ value: _UNSPECIFIED, label: 'Off', description: 'Default (disabled)' },
|
||||
{ value: 'mq', label: 'Standard', description: 'Quick gen' },
|
||||
@@ -132,6 +144,8 @@ export function LLMParametersEditor(props: {
|
||||
llmTemperature = FALLBACK_LLM_PARAM_TEMPERATURE, // fallback for undefined, result is number | null
|
||||
llmForceNoStream,
|
||||
llmVndAntThinkingBudget,
|
||||
llmVndAntWebSearch,
|
||||
llmVndAntWebFetch,
|
||||
llmVndGeminiAspectRatio,
|
||||
llmVndGeminiGoogleSearch,
|
||||
llmVndGeminiShowThoughts,
|
||||
@@ -252,6 +266,32 @@ export function LLMParametersEditor(props: {
|
||||
/>
|
||||
)}
|
||||
|
||||
{showParam('llmVndAntWebSearch') && (
|
||||
<FormSelectControl
|
||||
title='Web Search'
|
||||
tooltip='Enable web search for real-time information retrieval'
|
||||
value={llmVndAntWebSearch ?? _UNSPECIFIED}
|
||||
onChange={(value) => {
|
||||
if (value === _UNSPECIFIED || !value || value === 'off') onRemoveParameter('llmVndAntWebSearch');
|
||||
else onChangeParameter({ llmVndAntWebSearch: value });
|
||||
}}
|
||||
options={_antWebSearchOptions}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showParam('llmVndAntWebFetch') && (
|
||||
<FormSelectControl
|
||||
title='Web Fetch'
|
||||
tooltip='Enable fetching full content from web pages and PDF documents'
|
||||
value={llmVndAntWebFetch ?? _UNSPECIFIED}
|
||||
onChange={(value) => {
|
||||
if (value === _UNSPECIFIED || !value || value === 'off') onRemoveParameter('llmVndAntWebFetch');
|
||||
else onChangeParameter({ llmVndAntWebFetch: value });
|
||||
}}
|
||||
options={_antWebFetchOptions}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showParam('llmVndGeminiAspectRatio') && (
|
||||
<FormSelectControl
|
||||
title='Aspect Ratio'
|
||||
|
||||
@@ -10,7 +10,11 @@ export const hardcodedAnthropicVariants: { [modelId: string]: Partial<ModelDescr
|
||||
idVariant: 'thinking',
|
||||
label: 'Claude Sonnet 4.5 (Thinking)',
|
||||
description: 'Claude Sonnet 4.5 with extended thinking mode enabled for complex reasoning',
|
||||
parameterSpecs: [{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false }],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false },
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
maxCompletionTokens: 64000,
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching, LLM_IF_OAI_Reasoning],
|
||||
benchmark: { cbaElo: 1451 + 1 }, // FALLBACK-UNTIL-AVAILABLE: claude-opus-4-1-20250805-thinking-16k + 1
|
||||
@@ -20,7 +24,11 @@ export const hardcodedAnthropicVariants: { [modelId: string]: Partial<ModelDescr
|
||||
idVariant: 'thinking',
|
||||
label: 'Claude Haiku 4.5 (Thinking)',
|
||||
description: 'Claude Haiku 4.5 with extended thinking mode - first Haiku model with reasoning capabilities',
|
||||
parameterSpecs: [{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false }],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false },
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
maxCompletionTokens: 64000,
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching, LLM_IF_OAI_Reasoning],
|
||||
},
|
||||
@@ -30,7 +38,11 @@ export const hardcodedAnthropicVariants: { [modelId: string]: Partial<ModelDescr
|
||||
idVariant: 'thinking',
|
||||
label: 'Claude Opus 4.1 (Thinking)',
|
||||
description: 'Claude Opus 4.1 with extended thinking mode enabled for complex reasoning',
|
||||
parameterSpecs: [{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false }],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false },
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
maxCompletionTokens: 32000,
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching, LLM_IF_OAI_Reasoning],
|
||||
benchmark: { cbaElo: 1451 }, // claude-opus-4-1-20250805-thinking-16k
|
||||
@@ -42,7 +54,11 @@ export const hardcodedAnthropicVariants: { [modelId: string]: Partial<ModelDescr
|
||||
idVariant: 'thinking',
|
||||
label: 'Claude Opus 4 (Thinking)',
|
||||
description: 'Claude Opus 4 with extended thinking mode enabled for complex reasoning',
|
||||
parameterSpecs: [{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false }],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false },
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
maxCompletionTokens: 32000,
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching, LLM_IF_OAI_Reasoning],
|
||||
benchmark: { cbaElo: 1420 }, // claude-opus-4-20250514-thinking-16k
|
||||
@@ -52,7 +68,11 @@ export const hardcodedAnthropicVariants: { [modelId: string]: Partial<ModelDescr
|
||||
idVariant: 'thinking',
|
||||
label: 'Claude Sonnet 4 (Thinking)',
|
||||
description: 'Claude Sonnet 4 with extended thinking mode enabled for complex reasoning',
|
||||
parameterSpecs: [{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false }],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false },
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
maxCompletionTokens: 64000,
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching, LLM_IF_OAI_Reasoning],
|
||||
benchmark: { cbaElo: 1400 }, // claude-sonnet-4-20250514-thinking-32k
|
||||
@@ -63,7 +83,11 @@ export const hardcodedAnthropicVariants: { [modelId: string]: Partial<ModelDescr
|
||||
idVariant: 'thinking',
|
||||
label: 'Claude Sonnet 3.7 (Thinking)',
|
||||
description: 'Claude 3.7 with extended thinking mode enabled for complex reasoning',
|
||||
parameterSpecs: [{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false }],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntThinkingBudget', required: true, hidden: false },
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
maxCompletionTokens: 64000,
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching, LLM_IF_OAI_Reasoning],
|
||||
benchmark: { cbaElo: 1385 }, // claude-3-7-sonnet-20250219-thinking-32k
|
||||
@@ -83,6 +107,10 @@ export const hardcodedAnthropicModels: (ModelDescriptionSchema & { isLegacy?: bo
|
||||
maxCompletionTokens: 64000,
|
||||
trainingDataCutoff: 'Jul 2025',
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
// Note: Tiered pricing - ≤200K: $3/$15, >200K: $6/$22.50. Using lower tier as base.
|
||||
chatPrice: { input: 3, output: 15, cache: { cType: 'ant-bp', read: 0.30, write: 3.75, duration: 300 } },
|
||||
benchmark: { cbaElo: 1438 + 1 }, // FALLBACK-UNTIL-AVAILABLE: claude-opus-4-1-20250805 + 1
|
||||
@@ -95,6 +123,10 @@ export const hardcodedAnthropicModels: (ModelDescriptionSchema & { isLegacy?: bo
|
||||
maxCompletionTokens: 64000,
|
||||
trainingDataCutoff: 'Jul 2025',
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
chatPrice: { input: 1, output: 5, cache: { cType: 'ant-bp', read: 0.10, write: 1.25, duration: 300 } },
|
||||
},
|
||||
|
||||
@@ -107,6 +139,10 @@ export const hardcodedAnthropicModels: (ModelDescriptionSchema & { isLegacy?: bo
|
||||
maxCompletionTokens: 32000,
|
||||
trainingDataCutoff: 'Mar 2025',
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
chatPrice: { input: 15, output: 75, cache: { cType: 'ant-bp', read: 1.50, write: 18.75, duration: 300 } },
|
||||
benchmark: { cbaElo: 1438 }, // claude-opus-4-1-20250805
|
||||
},
|
||||
@@ -121,6 +157,10 @@ export const hardcodedAnthropicModels: (ModelDescriptionSchema & { isLegacy?: bo
|
||||
maxCompletionTokens: 32000,
|
||||
trainingDataCutoff: 'Mar 2025',
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
chatPrice: { input: 15, output: 75, cache: { cType: 'ant-bp', read: 1.50, write: 18.75, duration: 300 } },
|
||||
benchmark: { cbaElo: 1411 }, // claude-opus-4-20250514
|
||||
},
|
||||
@@ -132,6 +172,10 @@ export const hardcodedAnthropicModels: (ModelDescriptionSchema & { isLegacy?: bo
|
||||
maxCompletionTokens: 64000,
|
||||
trainingDataCutoff: 'Mar 2025',
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
chatPrice: { input: 3, output: 15, cache: { cType: 'ant-bp', read: 0.30, write: 3.75, duration: 300 } },
|
||||
benchmark: { cbaElo: 1386 }, // claude-sonnet-4-20250514
|
||||
},
|
||||
@@ -145,6 +189,10 @@ export const hardcodedAnthropicModels: (ModelDescriptionSchema & { isLegacy?: bo
|
||||
maxCompletionTokens: 64000,
|
||||
trainingDataCutoff: 'Nov 2024',
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
chatPrice: { input: 3, output: 15, cache: { cType: 'ant-bp', read: 0.30, write: 3.75, duration: 300 } },
|
||||
benchmark: { cbaElo: 1369 }, // claude-3-7-sonnet-20250219
|
||||
},
|
||||
@@ -184,6 +232,10 @@ export const hardcodedAnthropicModels: (ModelDescriptionSchema & { isLegacy?: bo
|
||||
maxCompletionTokens: 8192,
|
||||
trainingDataCutoff: 'Jul 2024',
|
||||
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_ANT_PromptCaching],
|
||||
parameterSpecs: [
|
||||
{ paramId: 'llmVndAntWebSearch' },
|
||||
{ paramId: 'llmVndAntWebFetch' },
|
||||
],
|
||||
chatPrice: { input: 0.80, output: 4.00, cache: { cType: 'ant-bp', read: 0.08, write: 1.00, duration: 300 } },
|
||||
benchmark: { cbaElo: 1319, cbaMmlu: 75.2 }, // claude-3-5-haiku-20241022
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user