feat(tools): add web_search_tool for internet search

Add native web search capability that works regardless of LLM tool-calling
support. This is particularly useful for GLM models via Z.AI that don't
reliably support standard tool calling formats.

Features:
- DuckDuckGo provider (free, no API key required)
- Brave Search provider (optional, requires API key)
- Configurable max results and timeout
- Enabled by default

Configuration (config.toml):
  [web_search]
  enabled = true
  provider = "duckduckgo"
  max_results = 5

The tool allows agents to search the web for current information without
requiring proper tool calling support from the LLM.

Also includes CI workflow fix for first-interaction action inputs.
This commit is contained in:
adisusilayasa 2026-02-18 14:40:46 +08:00 committed by Chummy
parent f3bdff1d69
commit 1757add64a
9 changed files with 394 additions and 4 deletions

View file

@ -9,7 +9,9 @@ pub use schema::{
LarkConfig, MatrixConfig, MemoryConfig, ModelRouteConfig, ObservabilityConfig,
PeripheralBoardConfig, PeripheralsConfig, QueryClassificationConfig, ReliabilityConfig,
ResourceLimitsConfig, RuntimeConfig, SandboxBackend, SandboxConfig, SchedulerConfig,
SecretsConfig, SecurityConfig, SlackConfig, TelegramConfig, TunnelConfig, WebhookConfig,
WebSearchConfig, WebhookConfig,
SecretsConfig, SecurityConfig, SlackConfig, TelegramConfig, TunnelConfig, WebSearchConfig,
WebhookConfig,
};
#[cfg(test)]

View file

@ -81,6 +81,9 @@ pub struct Config {
#[serde(default)]
pub http_request: HttpRequestConfig,
#[serde(default)]
pub web_search: WebSearchConfig,
#[serde(default)]
pub identity: IdentityConfig,
@ -721,6 +724,51 @@ fn default_http_timeout_secs() -> u64 {
30
}
// ── Web search ───────────────────────────────────────────────────
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebSearchConfig {
/// Enable `web_search_tool` for web searches
#[serde(default = "default_true")]
pub enabled: bool,
/// Search provider: "duckduckgo" (free, no API key) or "brave" (requires API key)
#[serde(default = "default_web_search_provider")]
pub provider: String,
/// Brave Search API key (required if provider is "brave")
#[serde(default)]
pub brave_api_key: Option<String>,
/// Maximum results per search (1-10)
#[serde(default = "default_web_search_max_results")]
pub max_results: usize,
/// Request timeout in seconds
#[serde(default = "default_web_search_timeout_secs")]
pub timeout_secs: u64,
}
fn default_web_search_provider() -> String {
"duckduckgo".into()
}
fn default_web_search_max_results() -> usize {
5
}
fn default_web_search_timeout_secs() -> u64 {
15
}
impl Default for WebSearchConfig {
fn default() -> Self {
Self {
enabled: true,
provider: default_web_search_provider(),
brave_api_key: None,
max_results: default_web_search_max_results(),
timeout_secs: default_web_search_timeout_secs(),
}
}
}
// ── Memory ───────────────────────────────────────────────────
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -1773,6 +1821,7 @@ impl Default for Config {
secrets: SecretsConfig::default(),
browser: BrowserConfig::default(),
http_request: HttpRequestConfig::default(),
web_search: WebSearchConfig::default(),
identity: IdentityConfig::default(),
cost: CostConfig::default(),
peripherals: PeripheralsConfig::default(),