87 lines
3.6 KiB
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>
|