agent-Specialization/static/src/components/chat/actions/ToolAction.vue

87 lines
3.6 KiB
Vue

<template>
<div
class="collapsible-block tool-block"
:class="{
expanded,
processing: action.tool.status === 'preparing' || action.tool.status === 'running',
completed: action.tool.status === 'completed'
}"
>
<div class="collapsible-header" @click="$emit('toggle')">
<div class="arrow"></div>
<div class="status-icon">
<span
class="tool-icon icon icon-md"
:class="getToolAnimationClass(action.tool)"
:style="iconStyle(getToolIcon(action.tool))"
aria-hidden="true"
></span>
</div>
<span class="status-text">{{ getToolStatusText(action.tool) }}</span>
<span class="tool-desc">{{ getToolDescription(action.tool) }}</span>
</div>
<div
class="collapsible-content"
:ref="el => registerCollapseContent && registerCollapseContent(collapseKey || action.tool.id || action.id || 'tool', el)"
>
<div class="content-inner">
<div v-if="action.tool.name === 'web_search' && action.tool.result">
<div class="search-meta">
<div><strong>搜索内容:</strong>{{ action.tool.result.query || action.tool.arguments.query }}</div>
<div><strong>主题:</strong>{{ formatSearchTopic(action.tool.result.filters || {}) }}</div>
<div><strong>时间范围:</strong>{{ formatSearchTime(action.tool.result.filters || {}) }}</div>
<div><strong>结果数量:</strong>{{ action.tool.result.total_results }}</div>
</div>
<div v-if="action.tool.result.results && action.tool.result.results.length" class="search-result-list">
<div v-for="item in action.tool.result.results" :key="item.url || item.index" class="search-result-item">
<div class="search-result-title">{{ item.title || '无标题' }}</div>
<div class="search-result-url">
<a v-if="item.url" :href="item.url" target="_blank">{{ item.url }}</a><span v-else>无可用链接</span>
</div>
</div>
</div>
<div v-else class="search-empty">未返回详细的搜索结果。</div>
</div>
<div v-else-if="action.tool.name === 'run_python' && action.tool.result">
<div class="code-block">
<div class="code-label">代码:</div>
<pre><code class="language-python">{{ action.tool.result.code || action.tool.arguments.code }}</code></pre>
</div>
<div v-if="action.tool.result.output" class="output-block">
<div class="output-label">输出:</div>
<pre>{{ action.tool.result.output }}</pre>
</div>
</div>
<div v-else>
<pre>{{ JSON.stringify(action.tool.result || action.tool.arguments, null, 2) }}</pre>
</div>
</div>
</div>
<div
v-if="action.tool.status === 'preparing' || action.tool.status === 'running'"
class="progress-indicator"
></div>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: 'ToolAction' });
defineProps<{
action: any;
expanded: boolean;
iconStyle: (key: string) => Record<string, string>;
getToolAnimationClass: (tool: any) => Record<string, unknown>;
getToolIcon: (tool: any) => string;
getToolStatusText: (tool: any) => string;
getToolDescription: (tool: any) => string;
formatSearchTopic: (filters: Record<string, any>) => string;
formatSearchTime: (filters: Record<string, any>) => string;
streamingMessage: boolean;
registerCollapseContent?: (key: string, el: Element | null) => void;
collapseKey?: string;
}>();
defineEmits<{ (event: 'toggle'): void }>();
</script>