diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index f20a56b9c..029e163a8 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -1019,6 +1019,15 @@ func (al *AgentLoop) runLLMIteration( // Build tool definitions providerToolDefs := agent.Tools.ToProviderDefs() + // Determine whether the provider's native web search should replace + // the client-side web_search tool for this request. + useNativeSearch := al.cfg.Tools.Web.PreferNative && + isNativeSearchProvider(agent.Provider) + + if useNativeSearch { + providerToolDefs = filterClientWebSearch(providerToolDefs) + } + // Log LLM request details logger.DebugCF("agent", "LLM request", map[string]any{ @@ -1027,6 +1036,7 @@ func (al *AgentLoop) runLLMIteration( "model": activeModel, "messages_count": len(messages), "tools_count": len(providerToolDefs), + "native_search": useNativeSearch, "max_tokens": agent.MaxTokens, "temperature": agent.Temperature, "system_prompt_len": len(messages[0].Content), @@ -1049,6 +1059,9 @@ func (al *AgentLoop) runLLMIteration( "temperature": agent.Temperature, "prompt_cache_key": agent.ID, } + if useNativeSearch { + llmOpts["native_search"] = true + } // parseThinkingLevel guarantees ThinkingOff for empty/unknown values, // so checking != ThinkingOff is sufficient. if agent.ThinkingLevel != ThinkingOff { @@ -1958,6 +1971,28 @@ func extractParentPeer(msg bus.InboundMessage) *routing.RoutePeer { return &routing.RoutePeer{Kind: parentKind, ID: parentID} } +// isNativeSearchProvider reports whether the given LLM provider implements +// NativeSearchCapable and returns true for SupportsNativeSearch. +func isNativeSearchProvider(p providers.LLMProvider) bool { + if ns, ok := p.(providers.NativeSearchCapable); ok { + return ns.SupportsNativeSearch() + } + return false +} + +// filterClientWebSearch returns a copy of tools with the client-side +// web_search tool removed. Used when native provider search is preferred. +func filterClientWebSearch(tools []providers.ToolDefinition) []providers.ToolDefinition { + result := make([]providers.ToolDefinition, 0, len(tools)) + for _, t := range tools { + if strings.EqualFold(t.Function.Name, "web_search") { + continue + } + result = append(result, t) + } + return result +} + // Helper to extract provider from registry for cleanup func extractProvider(registry *AgentRegistry) (providers.LLMProvider, bool) { if registry == nil {