From 11af96265a4aadc7f96465c263975fbebc2fa696 Mon Sep 17 00:00:00 2001 From: JAE Date: Fri, 27 Mar 2026 04:44:28 +0000 Subject: [PATCH] fix: register tools via setTools(), add Tools/Code capability badges - Fix 'Tool browser not found': createTools callback was silently ignored by Agent constructor. Now uses agent.setTools() after instantiation. - Add Wrench (Tools) and Code icons + filter buttons to ModelSelector alongside existing Brain (Reasoning) and Image (Vision). - Add refreshSidebar() call in createAgent for session list updates. --- packages/web-ui/example/src/main.ts | 25 ++++++------ packages/web-ui/src/dialogs/ModelSelector.ts | 42 ++++++++++++++++++-- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/web-ui/example/src/main.ts b/packages/web-ui/example/src/main.ts index 56a3217..323b6af 100644 --- a/packages/web-ui/example/src/main.ts +++ b/packages/web-ui/example/src/main.ts @@ -405,20 +405,18 @@ Persist information across sessions. Use to save important context, user prefere } renderApp(); }, - createTools: async (runtimeProvidersFactory: any) => { - const replTool = createJavaScriptReplTool(); - replTool.runtimeProvidersFactory = runtimeProvidersFactory; - return [ - replTool, - createWebSearchTool(), - createBashTool(), - createBrowserTool(), - createImageGenTool(), - createTTSTool(), - ...createMemoryTools(), - ]; - }, }); + // Register tools with the agent + const replTool = createJavaScriptReplTool(); + agent.setTools([ + replTool, + createWebSearchTool(), + createBashTool(), + createBrowserTool(), + createImageGenTool(), + createTTSTool(), + ...createMemoryTools(), + ]); costTracker.bindAgent(agent); chatPanel?.setAgent(agent); // Hook: live model badge + immediate empty state hide @@ -438,6 +436,7 @@ Persist information across sessions. Use to save important context, user prefere } }); if (!currentSessionId) currentSessionId = crypto.randomUUID(); + await refreshSidebar(); }; const loadSession = async (sessionId: string): Promise => { diff --git a/packages/web-ui/src/dialogs/ModelSelector.ts b/packages/web-ui/src/dialogs/ModelSelector.ts index ade5c8f..11b2266 100644 --- a/packages/web-ui/src/dialogs/ModelSelector.ts +++ b/packages/web-ui/src/dialogs/ModelSelector.ts @@ -7,7 +7,7 @@ import { DialogBase } from "@mariozechner/mini-lit/dist/DialogBase.js"; import { html, type PropertyValues, type TemplateResult } from "lit"; import { customElement, state } from "lit/decorators.js"; import { createRef, ref } from "lit/directives/ref.js"; -import { Brain, Image as ImageIcon } from "lucide"; +import { Brain, Code, Globe, Image as ImageIcon, Wrench } from "lucide"; import { Input } from "../components/Input.js"; import { getAppStorage } from "../storage/app-storage.js"; import type { AutoDiscoveryProviderType } from "../storage/stores/custom-providers-store.js"; @@ -52,6 +52,8 @@ export class ModelSelector extends DialogBase { @state() searchQuery = ""; @state() filterThinking = false; @state() filterVision = false; + @state() filterTools = false; + @state() filterCode = false; @state() private filterProvider = ""; @state() customProvidersLoading = false; @state() selectedIndex = 0; @@ -246,6 +248,12 @@ export class ModelSelector extends DialogBase { if (this.filterVision) { filteredModels = filteredModels.filter(({ model }) => model.input.includes("image")); } + if (this.filterTools) { + filteredModels = filteredModels.filter(({ model }) => (model as any).tags?.includes("tools")); + } + if (this.filterCode) { + filteredModels = filteredModels.filter(({ model }) => (model as any).tags?.includes("code") || (model as any).tags?.includes("optimized-for-code")); + } if (this.filterProvider) { filteredModels = filteredModels.filter(({ provider }) => provider === this.filterProvider); } @@ -378,6 +386,32 @@ export class ModelSelector extends DialogBase { className: "rounded-full", children: html`${icon(ImageIcon, "sm")} ${i18n("Vision")}`, })} + ${Button({ + variant: this.filterTools ? "default" : "secondary", + size: "sm", + onClick: () => { + this.filterTools = !this.filterTools; + this.selectedIndex = 0; + if (this.scrollContainerRef.value) { + this.scrollContainerRef.value.scrollTop = 0; + } + }, + className: "rounded-full", + children: html`${icon(Wrench, "sm")} Tools`, + })} + ${Button({ + variant: this.filterCode ? "default" : "secondary", + size: "sm", + onClick: () => { + this.filterCode = !this.filterCode; + this.selectedIndex = 0; + if (this.scrollContainerRef.value) { + this.scrollContainerRef.value.scrollTop = 0; + } + }, + className: "rounded-full", + children: html`${icon(Code, "sm")} Code`, + })} ${this.renderProviderTabs()} @@ -411,8 +445,10 @@ export class ModelSelector extends DialogBase {
- ${icon(Brain, "sm")} - ${icon(ImageIcon, "sm")} + ${icon(Brain, "sm")} + ${icon(ImageIcon, "sm")} + ${icon(Wrench, "sm")} + ${icon(Code, "sm")} ${this.formatTokens(model.contextWindow)}K/${this.formatTokens(model.maxTokens)}K
${formatModelCost(model.cost)}