105 lines
2.6 KiB
Vue
105 lines
2.6 KiB
Vue
|
|
<template>
|
|||
|
|
<a-modal
|
|||
|
|
:open="open"
|
|||
|
|
:title="subagentName || '子智能体'"
|
|||
|
|
:footer="null"
|
|||
|
|
:width="800"
|
|||
|
|
:destroyOnClose="true"
|
|||
|
|
@cancel="$emit('update:open', false)"
|
|||
|
|
>
|
|||
|
|
<div class="subagent-thread-modal-body">
|
|||
|
|
<div v-if="loading" class="subagent-thread-modal-state">正在加载子智能体消息...</div>
|
|||
|
|
<div v-else-if="error" class="subagent-thread-modal-state is-error">{{ error }}</div>
|
|||
|
|
<ThreadMessageList v-else :messages="messages" />
|
|||
|
|
</div>
|
|||
|
|
</a-modal>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { ref, watch } from 'vue'
|
|||
|
|
import { agentApi } from '@/apis'
|
|||
|
|
import { MessageProcessor } from '@/utils/messageProcessor'
|
|||
|
|
import ThreadMessageList from '@/components/ThreadMessageList.vue'
|
|||
|
|
|
|||
|
|
const props = defineProps({
|
|||
|
|
open: {
|
|||
|
|
type: Boolean,
|
|||
|
|
default: false
|
|||
|
|
},
|
|||
|
|
childThreadId: {
|
|||
|
|
type: String,
|
|||
|
|
default: ''
|
|||
|
|
},
|
|||
|
|
subagentName: {
|
|||
|
|
type: String,
|
|||
|
|
default: ''
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
defineEmits(['update:open'])
|
|||
|
|
|
|||
|
|
const loading = ref(false)
|
|||
|
|
const error = ref('')
|
|||
|
|
const messages = ref([])
|
|||
|
|
|
|||
|
|
// LangChain 内容块数组 → 纯文本(仅保留 text 块)
|
|||
|
|
const flattenContent = (content) => {
|
|||
|
|
if (typeof content === 'string') return content
|
|||
|
|
if (Array.isArray(content)) {
|
|||
|
|
return content
|
|||
|
|
.filter((block) => block && block.type === 'text')
|
|||
|
|
.map((block) => block.text || '')
|
|||
|
|
.join('')
|
|||
|
|
}
|
|||
|
|
return content ?? ''
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const loadHistory = async (threadId) => {
|
|||
|
|
if (!threadId) return
|
|||
|
|
loading.value = true
|
|||
|
|
error.value = ''
|
|||
|
|
messages.value = []
|
|||
|
|
try {
|
|||
|
|
// 子智能体消息存于 LangGraph checkpoint,需走 state 接口并把 tool 结果嵌入 AI 消息。
|
|||
|
|
const response = await agentApi.getAgentState(threadId, { includeMessages: true })
|
|||
|
|
// checkpoint 的 content 可能是 LangChain 内容块数组,扁平成文本供 MarkdownPreview 渲染。
|
|||
|
|
const normalized = (response.messages || []).map((msg) => ({
|
|||
|
|
...msg,
|
|||
|
|
content: flattenContent(msg.content)
|
|||
|
|
}))
|
|||
|
|
messages.value = MessageProcessor.convertToolResultToMessages(normalized)
|
|||
|
|
} catch (e) {
|
|||
|
|
error.value = '加载子智能体消息失败'
|
|||
|
|
console.error('Failed to load subagent thread messages:', e)
|
|||
|
|
} finally {
|
|||
|
|
loading.value = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
watch(
|
|||
|
|
() => [props.open, props.childThreadId],
|
|||
|
|
([isOpen, threadId]) => {
|
|||
|
|
if (isOpen && threadId) loadHistory(threadId)
|
|||
|
|
},
|
|||
|
|
{ immediate: true }
|
|||
|
|
)
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="less" scoped>
|
|||
|
|
.subagent-thread-modal-body {
|
|||
|
|
max-height: 70vh;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.subagent-thread-modal-state {
|
|||
|
|
padding: 32px 0;
|
|||
|
|
text-align: center;
|
|||
|
|
color: var(--gray-500);
|
|||
|
|
font-size: 13px;
|
|||
|
|
|
|||
|
|
&.is-error {
|
|||
|
|
color: var(--color-error-600);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|