feat: 全新智能体功能
- 基于先进智能体框架,增加智能体编排功能 - 增加智能体聊天,并对接持久化
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
<script setup lang="ts">
|
||||
import type {ChatTimelineMessageItem, ChatTimelineToolApprovalPayload,} from '@easyflow/common-ui';
|
||||
import {ChatTimeline} from '@easyflow/common-ui';
|
||||
|
||||
import type {AgentInfo, AgentKnowledgeBinding, AgentToolBinding,} from '../types';
|
||||
|
||||
import {onMounted, ref, watch} from 'vue';
|
||||
import {BrushCleaning} from '@easyflow/icons';
|
||||
|
||||
import {ElButton, ElMessage} from 'element-plus';
|
||||
|
||||
import AiChatPanel from '#/components/ai-chat/AiChatPanel.vue';
|
||||
|
||||
import {approveAgentRun, rejectAgentRun} from '../api';
|
||||
import {useAgentTryoutStream} from '../composables/useAgentTryoutStream';
|
||||
|
||||
const props = defineProps<{
|
||||
agent: AgentInfo;
|
||||
knowledgeBindings: AgentKnowledgeBinding[];
|
||||
toolBindings: AgentToolBinding[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{ close: [] }>();
|
||||
|
||||
const {
|
||||
loading,
|
||||
clearDraftSession,
|
||||
markToolApproving,
|
||||
markToolRejected,
|
||||
copyMessageText,
|
||||
selectVariant,
|
||||
syncDraftContext,
|
||||
timelineItems,
|
||||
sendDraft,
|
||||
stop,
|
||||
} = useAgentTryoutStream();
|
||||
const approvalLoading = ref(false);
|
||||
|
||||
function getDraftContext() {
|
||||
return {
|
||||
agent: props.agent,
|
||||
toolBindings: props.toolBindings,
|
||||
knowledgeBindings: props.knowledgeBindings,
|
||||
};
|
||||
}
|
||||
|
||||
function syncCurrentDraftContext(restore = false) {
|
||||
syncDraftContext(getDraftContext(), restore);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
syncCurrentDraftContext(true);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => [props.agent.id, props.agent.localId],
|
||||
() => {
|
||||
syncCurrentDraftContext(true);
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => [props.agent, props.knowledgeBindings, props.toolBindings],
|
||||
() => {
|
||||
syncCurrentDraftContext();
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
async function handleSend(prompt: string) {
|
||||
await sendDraft({
|
||||
...getDraftContext(),
|
||||
prompt,
|
||||
});
|
||||
}
|
||||
|
||||
function canCopyMessage(item: ChatTimelineMessageItem) {
|
||||
if (item.role === 'user') {
|
||||
return Boolean(copyMessageText(item).trim());
|
||||
}
|
||||
return Boolean(
|
||||
item.roundId && item.roundCompleted && copyMessageText(item).trim(),
|
||||
);
|
||||
}
|
||||
|
||||
function canRegenerateMessage(item: ChatTimelineMessageItem) {
|
||||
return (
|
||||
item.role === 'assistant' &&
|
||||
Boolean(item.roundId) &&
|
||||
Boolean(item.roundCompleted)
|
||||
);
|
||||
}
|
||||
|
||||
async function handleCopyMessage(item: ChatTimelineMessageItem) {
|
||||
const text = copyMessageText(item).trim();
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
ElMessage.success('已复制');
|
||||
} catch {
|
||||
ElMessage.error('复制失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRegenerateMessage(item: ChatTimelineMessageItem) {
|
||||
void item;
|
||||
}
|
||||
|
||||
function handleSelectPreviousVariant(item: ChatTimelineMessageItem) {
|
||||
selectVariant(item, 'previous');
|
||||
}
|
||||
|
||||
function handleSelectNextVariant(item: ChatTimelineMessageItem) {
|
||||
selectVariant(item, 'next');
|
||||
}
|
||||
|
||||
async function handleClearSession() {
|
||||
try {
|
||||
await clearDraftSession();
|
||||
ElMessage.success('已清理会话');
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '清理会话失败');
|
||||
}
|
||||
}
|
||||
|
||||
function handleStop() {
|
||||
if (!loading.value) {
|
||||
return;
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
async function handleApprove(payload: ChatTimelineToolApprovalPayload) {
|
||||
approvalLoading.value = true;
|
||||
markToolApproving(payload);
|
||||
try {
|
||||
const res = await approveAgentRun(payload.requestId, payload.resumeToken);
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success('已批准');
|
||||
}
|
||||
} catch (error) {
|
||||
markToolRejected({
|
||||
...payload,
|
||||
reason: error instanceof Error ? error.message : '批准失败',
|
||||
});
|
||||
throw error;
|
||||
} finally {
|
||||
approvalLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleReject(payload: ChatTimelineToolApprovalPayload) {
|
||||
approvalLoading.value = true;
|
||||
markToolRejected({
|
||||
...payload,
|
||||
reason: '用户拒绝执行',
|
||||
});
|
||||
try {
|
||||
await rejectAgentRun(
|
||||
payload.requestId,
|
||||
payload.resumeToken,
|
||||
'用户拒绝执行',
|
||||
);
|
||||
} finally {
|
||||
approvalLoading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AiChatPanel
|
||||
:title="agent.name || '草稿试运行'"
|
||||
empty-text="输入问题试运行当前智能体"
|
||||
closable
|
||||
:messages="[]"
|
||||
:loading="loading"
|
||||
:approval-loading="approvalLoading"
|
||||
@send="handleSend"
|
||||
@stop="handleStop"
|
||||
@approve="handleApprove"
|
||||
@reject="handleReject"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<template #headerActions>
|
||||
<ElButton
|
||||
:icon="BrushCleaning"
|
||||
circle
|
||||
text
|
||||
:disabled="approvalLoading"
|
||||
aria-label="清理会话"
|
||||
title="清理会话"
|
||||
@click="handleClearSession"
|
||||
/>
|
||||
</template>
|
||||
<ChatTimeline
|
||||
:items="timelineItems"
|
||||
empty-text="输入问题试运行当前智能体"
|
||||
:approval-loading="approvalLoading"
|
||||
:copyable="canCopyMessage"
|
||||
:regenerable="canRegenerateMessage"
|
||||
:regenerate-disabled="true"
|
||||
@approve="handleApprove"
|
||||
@copy-message="handleCopyMessage"
|
||||
@regenerate-message="handleRegenerateMessage"
|
||||
@reject="handleReject"
|
||||
@select-next-variant="handleSelectNextVariant"
|
||||
@select-previous-variant="handleSelectPreviousVariant"
|
||||
/>
|
||||
</AiChatPanel>
|
||||
</template>
|
||||
Reference in New Issue
Block a user