From d395a1c5cde2bf2420c36e4b94f231a4514c6233 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 3 Nov 2025 21:06:22 +0000
Subject: [PATCH 1/5] Initial plan
From a38ffe135be47da73d4649a64007ad8e6cfd82ed Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 3 Nov 2025 21:14:24 +0000
Subject: [PATCH 2/5] Add tool descriptions and input schemas to backend API
and frontend UI
Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com>
---
backend/routes/config_routes.py | 25 +++++++
frontend/src/components/ToolsPanel.jsx | 94 ++++++++++++++++++++++----
2 files changed, 107 insertions(+), 12 deletions(-)
diff --git a/backend/routes/config_routes.py b/backend/routes/config_routes.py
index 749c965..e8fec61 100644
--- a/backend/routes/config_routes.py
+++ b/backend/routes/config_routes.py
@@ -126,6 +126,20 @@ async def get_config(
tools_info.append({
'server': 'canvas',
'tools': ['canvas'],
+ 'tools_detailed': [{
+ 'name': 'canvas',
+ 'description': 'Display final rendered content in a visual canvas panel. Use this for: 1) Complete code (not code discussions), 2) Final reports/documents (not report discussions), 3) Data visualizations, 4) Any polished content that should be viewed separately from the conversation.',
+ 'inputSchema': {
+ 'type': 'object',
+ 'properties': {
+ 'content': {
+ 'type': 'string',
+ 'description': 'The content to display in the canvas. Can be markdown, code, or plain text.'
+ }
+ },
+ 'required': ['content']
+ }
+ }],
'tool_count': 1,
'description': 'Canvas for showing final rendered content: complete code, reports, and polished documents. Use this to finalize your work. Most code and reports will be shown here.',
'is_exclusive': False,
@@ -140,9 +154,20 @@ async def get_config(
# Only include servers that have tools and user has access to
if server_tools: # Only show servers with actual tools
+ # Build detailed tool information including descriptions and input schemas
+ tools_detailed = []
+ for tool in server_tools:
+ tool_detail = {
+ 'name': tool.name,
+ 'description': tool.description or '',
+ 'inputSchema': getattr(tool, 'inputSchema', {}) or {}
+ }
+ tools_detailed.append(tool_detail)
+
tools_info.append({
'server': server_name,
'tools': [tool.name for tool in server_tools],
+ 'tools_detailed': tools_detailed,
'tool_count': len(server_tools),
'description': server_config.get('description', f'{server_name} tools'),
'is_exclusive': server_config.get('is_exclusive', False),
diff --git a/frontend/src/components/ToolsPanel.jsx b/frontend/src/components/ToolsPanel.jsx
index f4b7725..a37ee05 100644
--- a/frontend/src/components/ToolsPanel.jsx
+++ b/frontend/src/components/ToolsPanel.jsx
@@ -1,4 +1,4 @@
-import { X, Trash2, Search, Plus, Wrench, ChevronDown, ChevronUp, Shield } from 'lucide-react'
+import { X, Trash2, Search, Plus, Wrench, ChevronDown, ChevronUp, Shield, Info } from 'lucide-react'
import { useNavigate } from 'react-router-dom'
import { useState, useEffect } from 'react'
import { useChat } from '../contexts/ChatContext'
@@ -7,6 +7,7 @@ import { useMarketplace } from '../contexts/MarketplaceContext'
const ToolsPanel = ({ isOpen, onClose }) => {
const [searchTerm, setSearchTerm] = useState('')
const [expandedServers, setExpandedServers] = useState(new Set())
+ const [expandedTools, setExpandedTools] = useState(new Set())
const navigate = useNavigate()
const {
selectedTools,
@@ -58,6 +59,7 @@ const ToolsPanel = ({ isOpen, onClose }) => {
is_exclusive: toolServer.is_exclusive,
compliance_level: toolServer.compliance_level,
tools: toolServer.tools || [],
+ tools_detailed: toolServer.tools_detailed || [],
tool_count: toolServer.tool_count || 0,
prompts: [],
prompt_count: 0
@@ -73,6 +75,7 @@ const ToolsPanel = ({ isOpen, onClose }) => {
description: promptServer.description,
is_exclusive: false,
tools: [],
+ tools_detailed: [],
tool_count: 0,
prompts: promptServer.prompts || [],
prompt_count: promptServer.prompt_count || 0
@@ -295,6 +298,43 @@ const ToolsPanel = ({ isOpen, onClose }) => {
setExpandedServers(newExpanded)
}
+ const toggleToolExpansion = (toolKey) => {
+ const newExpanded = new Set(expandedTools)
+ if (newExpanded.has(toolKey)) {
+ newExpanded.delete(toolKey)
+ } else {
+ newExpanded.add(toolKey)
+ }
+ setExpandedTools(newExpanded)
+ }
+
+ // Helper to render input schema parameters
+ const renderInputSchema = (schema) => {
+ if (!schema || !schema.properties) {
+ return
No input parameters
+ }
+
+ const properties = schema.properties
+ const required = schema.required || []
+
+ return (
+
+ {Object.entries(properties).map(([paramName, paramDef]) => (
+
+
{paramName}
+ {required.includes(paramName) && (
+
*
+ )}
+
({paramDef.type || 'any'})
+ {paramDef.description && (
+
{paramDef.description}
+ )}
+
+ ))}
+
+ )
+ }
+
// (Legacy isServerSelected removed; new implementation above.)
if (!isOpen) return null
@@ -468,20 +508,50 @@ const ToolsPanel = ({ isOpen, onClose }) => {
{server.tools.map(tool => {
const toolKey = `${server.server}_${tool}`
const isSelected = selectedTools.has(toolKey)
+ const isToolExpanded = expandedTools.has(toolKey)
+ // Find detailed tool info
+ const toolDetail = server.tools_detailed?.find(t => t.name === tool)
+
return (
-