优化智能体体验

This commit is contained in:
Wenjie Zhang 2025-04-05 02:23:32 +08:00
parent 42384236f8
commit f5a7a3eec9
4 changed files with 127 additions and 40 deletions

View File

@ -174,21 +174,25 @@ def chat_agent(agent_name: str,
def stream_messages(): def stream_messages():
content = "" content = ""
yield make_chunk(status="init", meta=meta) yield make_chunk(status="init", meta=meta)
for msg, metadata in agent.stream_messages(messages, config_schema=runnable_config): try:
if isinstance(msg, AIMessageChunk) and msg.content != "<tool_call>": for msg, metadata in agent.stream_messages(messages, config_schema=runnable_config):
content += msg.content if isinstance(msg, AIMessageChunk) and msg.content != "<tool_call>":
yield make_chunk(content=msg.content, content += msg.content
msg=msg.model_dump(), yield make_chunk(content=msg.content,
metadata=metadata, msg=msg.model_dump(),
status="loading") metadata=metadata,
else: status="loading")
yield make_chunk(msg=msg.model_dump(), else:
metadata=metadata, yield make_chunk(msg=msg.model_dump(),
status="loading") metadata=metadata,
status="loading")
yield make_chunk(status="finished", yield make_chunk(status="finished",
history=history_manager.update_ai(content), history=history_manager.update_ai(content),
meta=meta) meta=meta)
except Exception as e:
logger.error(f"Error streaming messages: {e}")
yield make_chunk(message=f"Error streaming messages: {e}", status="error")
return StreamingResponse(stream_messages(), media_type='application/json') return StreamingResponse(stream_messages(), media_type='application/json')

View File

@ -444,6 +444,8 @@ const handleStreamResponse = async (response) => {
await handleInit(value); await handleInit(value);
} else if (value.status === 'finished') { } else if (value.status === 'finished') {
await handleFinished(value); await handleFinished(value);
} else if (value.status === 'error') {
await handleError(value);
} else { } else {
await handleMessageById(value); await handleMessageById(value);
} }
@ -552,7 +554,7 @@ const handleFinished = async (data) => {
const handleMessageById = async (data) => { const handleMessageById = async (data) => {
const msgId = data.msg.id; const msgId = data.msg.id;
const msgType = data.msg.type; const msgType = data.msg.type;
// console.log("data", data); console.log("data", data);
// //
const existingMsgIndex = messageMap.value.get(msgId); const existingMsgIndex = messageMap.value.get(msgId);
@ -678,11 +680,26 @@ const updateExistingMessage = async (data, existingMsgIndex) => {
} }
} }
// errorerror
if (data.status === 'error') {
msgInstance.status = 'error';
msgInstance.message = data.message;
}
// //
await nextTick(); await nextTick();
await scrollToBottom(); await scrollToBottom();
}; };
const handleError = async (data) => {
console.error('处理错误状态:', data);
const lastMsg = messages.value[messages.value.length - 1];
if (lastMsg) {
lastMsg.status = 'error';
lastMsg.message = data.message;
}
isProcessing.value = false;
};
const appendToolMessageToExistingAssistant = async (data) => { const appendToolMessageToExistingAssistant = async (data) => {
// console.log("appendToolMessageToExistingAssistant", data); // console.log("appendToolMessageToExistingAssistant", data);

View File

@ -42,7 +42,7 @@
<!-- 添加令牌弹窗 --> <!-- 添加令牌弹窗 -->
<a-modal <a-modal
v-model:visible="addTokenModalVisible" v-model:open="addTokenModalVisible"
title="添加访问令牌" title="添加访问令牌"
ok-text="创建" ok-text="创建"
cancel-text="取消" cancel-text="取消"

View File

@ -27,6 +27,34 @@
{{ agents[selectedAgentId]?.description }} {{ agents[selectedAgentId]?.description }}
</p> </p>
<!-- 添加配置按钮 -->
<div class="agent-action-buttons">
<a-button
class="action-button"
@click="openConfigModal"
>
<template #icon><SettingOutlined /></template>
智能体配置
</a-button>
<a-button
class="action-button"
@click="openTokenModal"
>
<template #icon><KeyOutlined /></template>
访问令牌
</a-button>
<a-button
class="action-button"
@click="goToAgentPage"
v-if="selectedAgentId"
>
<template #icon><LinkOutlined /></template>
打开独立页面
</a-button>
</div>
<!-- 添加requirements显示部分 --> <!-- 添加requirements显示部分 -->
<div v-if="agents[selectedAgentId]?.requirements && agents[selectedAgentId]?.requirements.length > 0" class="info-section"> <div v-if="agents[selectedAgentId]?.requirements && agents[selectedAgentId]?.requirements.length > 0" class="info-section">
<h3>所需环境变量:</h3> <h3>所需环境变量:</h3>
@ -62,12 +90,12 @@
<img src="@/assets/icons/sidebar_left.svg" class="iconfont icon-20" alt="设置" /> <img src="@/assets/icons/sidebar_left.svg" class="iconfont icon-20" alt="设置" />
</div> </div>
</template> </template>
<template #header-right> <!-- <template #header-right>
<div class="toggle-sidebar nav-btn" @click="toggleConfigSidebar()"> <div class="toggle-sidebar nav-btn" @click="toggleConfigSidebar()">
<SettingOutlined class="iconfont icon-20" /> <SettingOutlined class="iconfont icon-20" />
<span class="text">配置</span> <span class="text">配置</span>
</div> </div>
</template> </template> -->
</AgentChatComponent> </AgentChatComponent>
</div> </div>
@ -80,33 +108,18 @@
</div> </div>
</h2> </h2>
<div v-if="selectedAgentId" class="config-form"> <div v-if="selectedAgentId" class="config-form">
<!-- 打开配置弹窗的按钮 --> <!-- 已将按钮移至左侧边栏 -->
<a-button
type="primary"
block
@click="openConfigModal"
>
打开智能体配置
</a-button>
<!-- 添加令牌管理按钮 -->
<a-button
style="margin-top: 16px;"
type="primary"
block
@click="openTokenModal"
>
访问令牌管理
</a-button>
</div> </div>
<div v-else class="no-agent-selected"> <div v-else class="no-agent-selected">
请先选择一个智能体 请先选择一个智能体
</div> </div>
<p>你好智能体</p>
</div> </div>
<!-- 配置弹窗 --> <!-- 配置弹窗 -->
<a-modal <a-modal
v-model:visible="state.configModalVisible" v-model:open="state.configModalVisible"
title="智能体配置" title="智能体配置"
width="650px" width="650px"
:footer="null" :footer="null"
@ -162,7 +175,7 @@
<!-- 令牌管理弹窗 --> <!-- 令牌管理弹窗 -->
<a-modal <a-modal
v-model:visible="state.tokenModalVisible" v-model:open="state.tokenModalVisible"
title="访问令牌管理" title="访问令牌管理"
width="650px" width="650px"
:footer="null" :footer="null"
@ -175,17 +188,23 @@
<script setup> <script setup>
import { ref, onMounted, reactive, watch, computed, h } from 'vue'; import { ref, onMounted, reactive, watch, computed, h } from 'vue';
import { useRouter } from 'vue-router';
import { import {
RobotOutlined, RobotOutlined,
MenuFoldOutlined, MenuFoldOutlined,
MenuUnfoldOutlined, MenuUnfoldOutlined,
CloseOutlined, CloseOutlined,
SettingOutlined SettingOutlined,
KeyOutlined,
LinkOutlined
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import AgentChatComponent from '@/components/AgentChatComponent.vue'; import AgentChatComponent from '@/components/AgentChatComponent.vue';
import TokenManagerComponent from '@/components/TokenManagerComponent.vue'; import TokenManagerComponent from '@/components/TokenManagerComponent.vue';
//
const router = useRouter();
// //
const agents = ref({}); const agents = ref({});
const selectedAgentId = ref(null); const selectedAgentId = ref(null);
@ -323,7 +342,7 @@ const fetchAgents = async () => {
acc[agent.name] = agent; acc[agent.name] = agent;
return acc; return acc;
}, {}); }, {});
console.log("agents", agents.value); // console.log("agents", agents.value);
// //
if (selectedAgentId.value) { if (selectedAgentId.value) {
@ -392,6 +411,13 @@ const getPlaceholder = (key, value) => {
// //
return `(默认: ${value.default}` ; return `(默认: ${value.default}` ;
}; };
//
const goToAgentPage = () => {
if (selectedAgentId.value) {
window.open(`/agent/${selectedAgentId.value}`, '_blank');
}
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@ -531,6 +557,22 @@ const getPlaceholder = (key, value) => {
.agent-info { .agent-info {
padding: 16px; padding: 16px;
min-width: calc(var(--agent-sidebar-width) - 16px); min-width: calc(var(--agent-sidebar-width) - 16px);
overflow-y: auto;
max-height: calc(100vh - 60px); /* 减去标题栏的高度 */
scrollbar-width: thin;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: var(--main-light-4);
border-radius: 4px;
}
} }
.agent-name { .agent-name {
@ -623,6 +665,30 @@ const getPlaceholder = (key, value) => {
gap: 10px; gap: 10px;
} }
} }
//
.agent-action-buttons {
margin-top: 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
.action-button {
background-color: white;
border: 1px solid var(--main-light-3);
text-align: left;
height: auto;
padding: 8px 12px;
&:hover {
background-color: var(--main-light-4);
}
.anticon {
margin-right: 8px;
}
}
</style> </style>