diff --git a/src/agentkit/chat/skill_routing.py b/src/agentkit/chat/skill_routing.py index e4df932..241092c 100644 --- a/src/agentkit/chat/skill_routing.py +++ b/src/agentkit/chat/skill_routing.py @@ -210,9 +210,31 @@ async def resolve_skill_routing( result.model = default_model result.agent_name = default_agent_name + # Append available tools to system prompt so LLM knows what it can call + if result.tools: + tools_desc = _build_tools_description(result.tools) + if result.system_prompt: + result.system_prompt += f"\n\n## Available Tools\n{tools_desc}" + else: + result.system_prompt = f"## Available Tools\n{tools_desc}" + return result +def _build_tools_description(tools: list) -> str: + """Build a text description of tools for the system prompt.""" + lines = [] + for tool in tools: + desc = getattr(tool, 'description', '') + lines.append(f"- **{tool.name}**: {desc}") + schema = getattr(tool, 'input_schema', None) + if schema and "properties" in schema: + params = list(schema["properties"].keys()) + if params: + lines[-1] += f" (parameters: {', '.join(params)})" + return "\n".join(lines) + + # --------------------------------------------------------------------------- # CostAwareRouter - 三层成本感知路由 # --------------------------------------------------------------------------- diff --git a/src/agentkit/server/static/index.html b/src/agentkit/server/static/index.html index 0267cd5..bd5c30d 100644 --- a/src/agentkit/server/static/index.html +++ b/src/agentkit/server/static/index.html @@ -164,6 +164,14 @@ html,body{height:100%;font-family:var(--font);background:var(--bg);color:var(--t @keyframes fadeIn{from{opacity:0}to{opacity:1}} @keyframes slideInRight{from{opacity:0;transform:translateX(12px)}to{opacity:1;transform:translateX(0)}} +/* ── Loading indicator ───────────────────────────────────────── */ +.loading-msg{display:flex;flex-direction:column;max-width:72%;align-self:flex-start;animation:msgIn .35s cubic-bezier(.16,1,.3,1)} +.loading-msg .loading-bubble{padding:8px 20px;background:var(--surface);border:1px solid var(--border-light);border-radius:var(--radius-lg) var(--radius-lg) var(--radius-lg) var(--radius-sm);display:inline-flex;align-items:center;gap:6px;box-shadow:var(--shadow-xs)} +.loading-msg .loading-dot{width:8px;height:8px;border-radius:50%;background:var(--text3);animation:loadingDot 1.4s infinite ease-in-out} +.loading-msg .loading-dot:nth-child(2){animation-delay:.2s} +.loading-msg .loading-dot:nth-child(3){animation-delay:.4s} +@keyframes loadingDot{0%,80%,100%{transform:scale(.4);opacity:.3}40%{transform:scale(1);opacity:1}} + /* ── Mobile ──────────────────────────────────────────────────── */ @media(max-width:768px){ .sidebar{position:fixed;left:-100%;z-index:10;transition:left .3s cubic-bezier(.16,1,.3,1);width:85vw;max-width:320px;box-shadow:var(--shadow-lg)} @@ -262,6 +270,7 @@ let activeSessionId = null; let ws = null; let isStreaming = false; let currentAgentBubble = null; +let loadingEl = null; let skills = []; const API = '/api/v1/chat'; const SKILLS_API = '/api/v1/skills'; @@ -380,7 +389,12 @@ function handleWsMessage(msg) { case 'connected': setConnStatus('已连接', true); break; + case 'routing': + removeLoading(); + appendStep(`路由: ${msg.skill || 'default'} (${msg.method}, ${Math.round((msg.confidence || 0) * 100)}%)`); + break; case 'token': + removeLoading(); if (!currentAgentBubble) { currentAgentBubble = appendMessage('agent', ''); isStreaming = true; @@ -390,6 +404,7 @@ function handleWsMessage(msg) { scrollToBottom(); break; case 'final_answer': + removeLoading(); if (currentAgentBubble) { const current = currentAgentBubble.textContent || ''; const final = msg.content || ''; @@ -405,16 +420,19 @@ function handleWsMessage(msg) { scrollToBottom(); break; case 'step': + removeLoading(); if (msg.data?.event_type === 'tool_call') { appendStep(`使用工具: ${msg.data?.data?.tool_name || 'tool'}`); } break; case 'skill_match': + removeLoading(); if (msg.data?.skill) { appendStep(`技能: ${msg.data.skill} (${msg.data.method}, ${Math.round((msg.data.confidence || 0) * 100)}%)`); } break; case 'error': + removeLoading(); appendMessage('agent', `[错误] ${msg.data?.message || '未知错误'}`); currentAgentBubble = null; isStreaming = false; @@ -423,6 +441,27 @@ function handleWsMessage(msg) { } } +// ── Loading indicator ────────────────────────────────────────── +function showLoading() { + if (loadingEl) return; + hideWelcome(); + const container = document.getElementById('messages'); + const div = document.createElement('div'); + div.className = 'loading-msg'; + div.id = 'loadingIndicator'; + div.innerHTML = '