feat: 增加智能体对话体验配置

- 支持欢迎语、猜你想问和输入提示的编辑、草稿预览与发布态展示

- 补充配置校验、发布快照持久化和发布后回显修复
This commit is contained in:
2026-07-14 21:21:57 +08:00
parent ce8b4fb420
commit 705e0faab6
18 changed files with 1351 additions and 160 deletions

View File

@@ -1,18 +1,28 @@
<script setup lang="ts">
import type {ChatTimelineMessageItem, ChatTimelineToolApprovalPayload,} from '@easyflow/common-ui';
import {ChatTimeline} from '@easyflow/common-ui';
import type {
ChatTimelineMessageItem,
ChatTimelineToolApprovalPayload,
} from '@easyflow/common-ui';
import type {AgentInfo, AgentKnowledgeBinding, AgentToolBinding,} from '../types';
import type {
AgentInfo,
AgentKnowledgeBinding,
AgentToolBinding,
} from '../types';
import {onMounted, ref, watch} from 'vue';
import {BrushCleaning} from '@easyflow/icons';
import { computed, onMounted, ref, watch } from 'vue';
import {ElButton, ElMessage} from 'element-plus';
import { ChatTimeline } from '@easyflow/common-ui';
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';
import { approveAgentRun, rejectAgentRun } from '../api';
import { useAgentTryoutStream } from '../composables/useAgentTryoutStream';
import { resolveInteractionDisplay } from '../interaction-config';
import AgentWelcomeState from './AgentWelcomeState.vue';
const props = defineProps<{
agent: AgentInfo;
@@ -35,6 +45,9 @@ const {
stop,
} = useAgentTryoutStream();
const approvalLoading = ref(false);
const interactionDisplay = computed(() =>
resolveInteractionDisplay(props.agent),
);
function getDraftContext() {
return {
@@ -68,12 +81,17 @@ watch(
);
async function handleSend(prompt: string) {
if (loading.value || approvalLoading.value) return;
await sendDraft({
...getDraftContext(),
prompt,
});
}
function handleSuggestedQuestion(question: string) {
void handleSend(question);
}
function canCopyMessage(item: ChatTimelineMessageItem) {
if (item.role === 'user') {
return Boolean(copyMessageText(item).trim());
@@ -176,6 +194,7 @@ async function handleReject(payload: ChatTimelineToolApprovalPayload) {
closable
:messages="[]"
:loading="loading"
:placeholder="interactionDisplay.inputPlaceholder"
:approval-loading="approvalLoading"
@send="handleSend"
@stop="handleStop"
@@ -194,19 +213,47 @@ async function handleReject(payload: ChatTimelineToolApprovalPayload) {
@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"
/>
<div class="agent-tryout__conversation">
<AgentWelcomeState
v-if="timelineItems.length === 0"
:agent-name="agent.name || '智能体'"
:avatar="agent.avatar"
:disabled="loading || approvalLoading"
:suggested-questions="interactionDisplay.suggestedQuestions"
:welcome-message="interactionDisplay.welcomeMessage"
@select-question="handleSuggestedQuestion"
/>
<ChatTimeline
v-else
: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"
/>
</div>
</AiChatPanel>
</template>
<style scoped>
.agent-tryout__conversation {
display: flex;
flex: 1;
min-height: 0;
padding: 0 var(--space-4);
overflow: auto;
overscroll-behavior: contain;
}
.agent-tryout__conversation :deep(.chat-timeline) {
width: 100%;
min-height: 0;
}
</style>