# DESIGN-0.13.1 — Web Search + URL Fetch + Tool Toggle ## Overview Built-in `web_search` and `url_fetch` tools using the existing tool framework (v0.11.0), plus a chat-bar tools toggle menu so users can enable/disable tool categories per-session. Depends on: tool framework (v0.11.0), admin panel (v0.13.0). ## Tools ### `web_search` **Provider abstraction** — same pattern as providers. Default: DuckDuckGo. Admin adds SearXNG instances or other search APIs. **Model:** `searchResult[]` — title, url, snippet. ```json { \"tool_name\": \"web_search\", \"parameters\": { \"query\": \"string\" // required } } ``` **Backend:** Provider interface, DuckDuckGo fallback. Results deduped by URL. Max 10 results (configurable). Results cached in-memory 1h (channel-scoped). ### `url_fetch` **Model:** `webPage` — title, url, content (HTML or text). ```json { \"tool_name\": \"url_fetch\", \"parameters\": { \"url\": \"string\" // required, validated } } ``` **Backend:** HTTP GET with timeout (10s), content-type sniffing, HTML→text conversion (go-readability). Max 100KB extracted text. Cached 1h. ## Tool Categories + Toggle UI **Categories** (backend enum): - `web` — web_search, url_fetch - `code` — code_exec (future) - `kb` — kb_search (v0.14.0) - `memory` — memory_recall (v0.18.0) **Per-chat persistence:** `channel.settings.tools[]` array of enabled categories. Default: all. **Chat bar UI:** Toggle icon → dropdown with checkboxes per category. Syncs to API on change (`PATCH /channels/:id {tools: [...]}`). **Admin global default:** `global_settings.default_tools[]`. ## Backend Changes ### 1. `server/tools/search.go` — New file ```go // web_search + url_fetch providers + caching ``` ### 2. `server/tools/registry.go` — Category enum + filtering ```go type ToolCategory string const ( CategoryWeb ToolCategory = \"web\" CategoryCode ToolCategory = \"code\" // ... ) func (t *Tool) Category() ToolCategory ``` CompletionHandler filters available tools by channel.settings.tools. ### 3. `server/handlers/channels.go` — PATCH tools[] ```go case \"tools\": if tools, ok := data.([]string); ok { ch.Tools = tools } ``` ### 4. `server/config/config.go` — Global defaults ```go DefaultTools []string `json:\"default_tools\"` ``` ### 5. `VERSION` ``` 0.13.1 ``` ## Frontend Changes ### `src/js/chat-ui.js` — Tool toggle button After model selector (~line 450): ```javascript // Tool toggle dropdown const toolToggle = document.createElement('div'); toolToggle.className = 'tool-toggle'; toolToggle.innerHTML = `
`; chatBar.appendChild(toolToggle); ``` ### Event handler ```javascript ChatUI.toggleTools = function() { const menu = document.querySelector('.tool-menu'); menu.style.display = menu.style.display === 'none' ? 'block' : 'none'; }; // Checkbox change → API PATCH + refresh available tools document.querySelectorAll('[data-cat]').forEach(cb => { cb.addEventListener('change', async function() { const tools = Array.from(document.querySelectorAll('[data-cat]:checked')) .map(cb => cb.dataset.cat); await API.updateChannel(channelId, { tools }); ChatUI.refreshTools(); // filter tool_calls display }); }); ``` ## Testing Checklist 1. **Tools register** — logs show `🔧 Registered tool: web_search` 2. **web_search works** — DuckDuckGo fallback, results in tool_calls 3. **Admin search provider** — add SearXNG, verify switch 4. **url_fetch** — valid URL → content extracted 5. **Toggle UI** — checkbox → tools filtered from completion 6. **Persistence** — reload chat → toggles restored 7. **Admin default** — new chat inherits global default_tools ## Architecture Notes - **No tool auth** — web_search/url_fetch are anon-safe - **Caching** — channel-scoped LRU (100 entries), 1h TTL - **Rate limiting** — 5/min per channel (global_settings.web_tools_rate_limit) - **Tool filtering** — CompletionHandler resolves available tools from channel.tools + global default_tools intersection with registered tools' categories - **Provider symmetry** — search providers mirror LLM providers (health, priority)