fix(gui): 修复对话无skill时无法聊天、空对话列表、输入框清空、监控数据
- portal.py: 移除 all_skills 空检查,无 skill 时 fallback 到直接 LLM 对话 - portal.py: general 路径 agent 为 None 时也 fallback 到直接对话 - ChatView.vue: onMounted 自动创建默认对话 - ChatInput.vue: nextTick 清空输入框 - evolution_dashboard.py: usage API 从 LLMGateway.UsageTracker 读取真实数据 - DashboardOverview.vue: 活跃 agent 从 capabilities API 获取
This commit is contained in:
parent
d02a6d5200
commit
905c1f6b18
|
|
@ -33,7 +33,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, nextTick, type Component } from 'vue'
|
||||
import { ref, computed, type Component } from 'vue'
|
||||
import { Input as AInput, Button as AButton } from 'ant-design-vue'
|
||||
import { SendOutlined } from '@ant-design/icons-vue'
|
||||
import ContextPill from './ContextPill.vue'
|
||||
|
|
@ -71,10 +71,7 @@ function handleSend(): void {
|
|||
const message = inputText.value.trim()
|
||||
if (!message) return
|
||||
emit('send', message)
|
||||
// Use nextTick to ensure Ant Design Vue's v-model syncs properly
|
||||
nextTick(() => {
|
||||
inputText.value = ''
|
||||
})
|
||||
inputText.value = ''
|
||||
}
|
||||
|
||||
function handlePressEnter(event: KeyboardEvent): void {
|
||||
|
|
|
|||
|
|
@ -134,11 +134,14 @@ onMounted(async () => {
|
|||
activeAgentCount.value = taskTypes.size
|
||||
}
|
||||
|
||||
// Also fetch active agents from capabilities API
|
||||
// Use capabilities API as primary source when available, fall back to task-type count
|
||||
try {
|
||||
const caps = await apiClient.getCapabilities()
|
||||
if (caps?.capabilities?.length) {
|
||||
activeAgentCount.value = caps.capabilities.length
|
||||
// Use capabilities count only if no experience-based count yet
|
||||
if (activeAgentCount.value === 0) {
|
||||
activeAgentCount.value = caps.capabilities.length
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// capabilities may not be available
|
||||
|
|
|
|||
|
|
@ -66,11 +66,13 @@ const ATypographyText = ATypography.Text
|
|||
const chatStore = useChatStore()
|
||||
const messagesContainer = ref<HTMLElement | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
chatStore.loadConversations()
|
||||
onMounted(async () => {
|
||||
await chatStore.loadConversations()
|
||||
chatStore.connectWebSocket()
|
||||
// Auto-create a default conversation so user can start chatting immediately
|
||||
if (!chatStore.currentConversationId) {
|
||||
// Auto-select or create a conversation so user can start chatting immediately
|
||||
if (chatStore.conversations.length > 0 && !chatStore.currentConversationId) {
|
||||
chatStore.selectConversation(chatStore.conversations[0].id)
|
||||
} else if (chatStore.conversations.length === 0) {
|
||||
chatStore.createConversation()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -456,15 +456,17 @@ async def get_usage(
|
|||
"""获取 LLM 用量统计"""
|
||||
now = datetime.now(timezone.utc)
|
||||
if period == "today":
|
||||
days = 1
|
||||
start_time = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
elif period == "30d":
|
||||
days = 30
|
||||
start_time = now - timedelta(days=30)
|
||||
else:
|
||||
days = 7
|
||||
start_time = now - timedelta(days=7)
|
||||
|
||||
total_tokens = 0
|
||||
total_requests = 0
|
||||
total_errors = 0
|
||||
total_latency = 0.0
|
||||
usage_records: list[dict] = []
|
||||
|
||||
|
|
@ -482,17 +484,18 @@ async def get_usage(
|
|||
for r in summary.records:
|
||||
date_key = r.timestamp.strftime("%Y-%m-%d")
|
||||
if date_key not in daily:
|
||||
daily[date_key] = {"tokens": 0, "requests": 0, "latency": 0.0, "model": r.model}
|
||||
daily[date_key] = {"tokens": 0, "requests": 0, "latency": 0.0, "models": set()}
|
||||
daily[date_key]["tokens"] += r.total_tokens
|
||||
daily[date_key]["requests"] += 1
|
||||
daily[date_key]["latency"] += r.latency_ms
|
||||
daily[date_key]["models"].add(r.model)
|
||||
|
||||
for date_key in sorted(daily):
|
||||
d = daily[date_key]
|
||||
usage_records.append({
|
||||
"date": date_key,
|
||||
"provider": "llm",
|
||||
"model": d["model"],
|
||||
"model": ", ".join(sorted(d["models"])),
|
||||
"tokens": d["tokens"],
|
||||
"requests": d["requests"],
|
||||
"errors": 0,
|
||||
|
|
@ -502,12 +505,6 @@ async def get_usage(
|
|||
logger.error(f"Failed to get usage from LLMGateway: {e}")
|
||||
|
||||
# Fill in missing dates with zero
|
||||
if period == "today":
|
||||
days = 1
|
||||
elif period == "30d":
|
||||
days = 30
|
||||
else:
|
||||
days = 7
|
||||
existing_dates = {r["date"] for r in usage_records}
|
||||
for i in range(days - 1, -1, -1):
|
||||
date = (now - timedelta(days=i)).strftime("%Y-%m-%d")
|
||||
|
|
|
|||
|
|
@ -529,11 +529,6 @@ async def portal_websocket(websocket: WebSocket):
|
|||
cost_aware_router = websocket.app.state.cost_aware_router
|
||||
|
||||
all_skills = skill_registry.list_skills()
|
||||
if not all_skills:
|
||||
await websocket.send_json(
|
||||
{"type": "error", "data": {"message": "No skills available"}}
|
||||
)
|
||||
continue
|
||||
|
||||
# Get default tools for CostAwareRouter routing (only if default skill exists)
|
||||
default_tools = []
|
||||
|
|
@ -599,6 +594,27 @@ async def portal_websocket(websocket: WebSocket):
|
|||
agent_name = routing_result.agent_name or "default"
|
||||
agent = pool.get_agent(agent_name)
|
||||
if agent is None:
|
||||
if not all_skills:
|
||||
# No skills registered — fallback to direct chat
|
||||
chat_messages = [{"role": "user", "content": message_text}]
|
||||
try:
|
||||
history = _conversation_store.get_history(conv.id, limit=20)
|
||||
for hist_msg in history[:-1]:
|
||||
if hist_msg.role in ("user", "assistant"):
|
||||
chat_messages.insert(0, {"role": hist_msg.role, "content": hist_msg.content})
|
||||
except Exception:
|
||||
pass
|
||||
response = await llm_gateway.chat(
|
||||
messages=chat_messages,
|
||||
model="default",
|
||||
agent_name="default",
|
||||
task_type="chat",
|
||||
)
|
||||
await websocket.send_json({
|
||||
"type": "result",
|
||||
"data": {"status": "completed", "content": response.content},
|
||||
})
|
||||
continue
|
||||
agent = await pool.create_agent_from_skill(agent_name)
|
||||
|
||||
# Execute via ReAct stream
|
||||
|
|
@ -664,7 +680,7 @@ async def portal_websocket(websocket: WebSocket):
|
|||
)
|
||||
|
||||
except WebSocketDisconnect:
|
||||
logger.debug(f"Portal WebSocket disconnected for conversation {conv.id}")
|
||||
logger.debug(f"Portal WebSocket disconnected for conversation {conv.id if conv else 'N/A'}")
|
||||
except Exception as e:
|
||||
logger.error(f"Portal WebSocket error: {e}")
|
||||
try:
|
||||
|
|
|
|||
Loading…
Reference in New Issue