mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
feat(ui): localize tool call display via useToolLabel
This commit is contained in:
parent
4168e34961
commit
95dd500a16
@ -64,7 +64,7 @@
|
||||
<el-icon><WarningFilled /></el-icon>
|
||||
</span>
|
||||
<span class="approval-bar__label">{{ t('chat.approvalAllow') }}</span>
|
||||
<span class="approval-bar__tool">{{ pendingApproval.toolName }}</span>
|
||||
<span class="approval-bar__tool">{{ getToolLabel(pendingApproval.toolName) }}</span>
|
||||
<span class="approval-bar__label">{{ t('chat.approvalExecute') }}</span>
|
||||
</div>
|
||||
<div class="approval-bar__actions">
|
||||
@ -203,6 +203,7 @@
|
||||
import { ref, computed, nextTick, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { CloseBold, MagicStick, Microphone, Paperclip, Promotion, Select, Timer, WarningFilled } from '@element-plus/icons-vue'
|
||||
import { useToolLabel } from '@/composables/useToolLabel'
|
||||
import type { ChatAttachment, PendingApprovalMeta, StreamPhase, QueuedMessage } from '@/types'
|
||||
|
||||
interface Props {
|
||||
@ -272,6 +273,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const { getToolLabel } = useToolLabel()
|
||||
|
||||
// 内部状态
|
||||
const containerRef = ref<HTMLElement | null>(null)
|
||||
|
||||
@ -89,7 +89,7 @@
|
||||
<el-icon v-else-if="tc.success !== false" class="tc-icon--success"><Select /></el-icon>
|
||||
<el-icon v-else class="tc-icon--error"><CloseBold /></el-icon>
|
||||
</span>
|
||||
<span class="tool-call__name">{{ tc.name }}</span>
|
||||
<span class="tool-call__name">{{ getToolLabel(tc.name) }}</span>
|
||||
<span class="tool-call__args" v-if="tc.arguments">{{ truncateArgs(tc.arguments) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -108,13 +108,13 @@
|
||||
<div v-if="pendingApproval" class="approval-inline">
|
||||
<el-icon class="approval-inline__icon"><WarningFilled /></el-icon>
|
||||
<span v-if="pendingApproval.status === 'pending_approval'" class="approval-inline__text">
|
||||
{{ $t('chat.approvalWaiting') }} <code>{{ pendingApproval.toolName }}</code>
|
||||
{{ $t('chat.approvalWaiting') }} <code>{{ getToolLabel(pendingApproval.toolName) }}</code>
|
||||
</span>
|
||||
<span v-else-if="pendingApproval.status === 'approved'" class="approval-inline__text approval-inline--approved">
|
||||
{{ $t('chat.approved') }}: <code>{{ pendingApproval.toolName }}</code>
|
||||
{{ $t('chat.approved') }}: <code>{{ getToolLabel(pendingApproval.toolName) }}</code>
|
||||
</span>
|
||||
<span v-else class="approval-inline__text approval-inline--denied">
|
||||
{{ $t('chat.denied') }}: <code>{{ pendingApproval.toolName }}</code>
|
||||
{{ $t('chat.denied') }}: <code>{{ getToolLabel(pendingApproval.toolName) }}</code>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -279,6 +279,7 @@ import {
|
||||
} from '@element-plus/icons-vue'
|
||||
import { useMarkdownRenderer } from '@/composables/useMarkdownRenderer'
|
||||
import { useAuthenticatedAttachment } from '@/composables/useAuthenticatedAttachment'
|
||||
import { useToolLabel } from '@/composables/useToolLabel'
|
||||
import { http } from '@/api'
|
||||
import TypingCursor from './TypingCursor.vue'
|
||||
import BrowserTimeline from './BrowserTimeline.vue'
|
||||
@ -293,6 +294,7 @@ import type { ChatErrorInfo } from '@/types/chatError'
|
||||
|
||||
const { renderMarkdown } = useMarkdownRenderer()
|
||||
const { t } = useI18n()
|
||||
const { getToolLabel } = useToolLabel()
|
||||
const { blobUrls, loadAllImages, loadAllVideos, downloadFile, openImage, getDisplayUrl, revokeAll } = useAuthenticatedAttachment()
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { Loading, Select, CloseBold, ArrowDown, Document, Setting } from '@element-plus/icons-vue'
|
||||
import { useToolLabel } from '@/composables/useToolLabel'
|
||||
import type { MessageSegment } from '@/types'
|
||||
|
||||
const props = defineProps<{
|
||||
segment: MessageSegment
|
||||
}>()
|
||||
|
||||
const { getToolLabel } = useToolLabel()
|
||||
|
||||
const expanded = ref(props.segment.status === 'running')
|
||||
|
||||
// running → completed 时自动折叠
|
||||
@ -14,7 +17,7 @@ watch(() => props.segment.status, (val) => {
|
||||
if (val !== 'running') expanded.value = false
|
||||
})
|
||||
|
||||
const displayName = computed(() => (props.segment.toolName || '').replace(/_/g, ' '))
|
||||
const displayName = computed(() => getToolLabel(props.segment.toolName || ''))
|
||||
|
||||
const truncatedArgs = computed(() => {
|
||||
const args = props.segment.toolArgs || ''
|
||||
|
||||
43
mateclaw-ui/src/composables/useToolLabel.ts
Normal file
43
mateclaw-ui/src/composables/useToolLabel.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
/**
|
||||
* Title-case a raw camelCase / snake_case / kebab-case tool name.
|
||||
* Last-resort fallback for unknown tools; the i18n table is authoritative
|
||||
* for built-ins (see toolLabels in locale files).
|
||||
*
|
||||
* wiki_search_pages → "Wiki Search Pages"
|
||||
* delegateToAgent → "Delegate To Agent"
|
||||
* browser-use → "Browser Use"
|
||||
*/
|
||||
export function humanizeToolName(raw: string): string {
|
||||
if (!raw) return ''
|
||||
return raw
|
||||
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
.replace(/[-_]+/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
.replace(/\b\w/g, (c) => c.toUpperCase())
|
||||
}
|
||||
|
||||
type TFn = (key: string) => string
|
||||
type TeFn = (key: string) => boolean
|
||||
|
||||
/**
|
||||
* Pure resolver — callable outside Vue setup (pass t/te from a useI18n() instance).
|
||||
* Resolution: toolLabels.<rawName> in active locale → humanizeToolName(rawName).
|
||||
*/
|
||||
export function resolveToolLabel(raw: string, t: TFn, te: TeFn): string {
|
||||
if (!raw) return ''
|
||||
const key = `toolLabels.${raw}`
|
||||
return te(key) ? t(key) : humanizeToolName(raw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable — must be called inside a Vue setup context.
|
||||
*/
|
||||
export function useToolLabel() {
|
||||
const { t, te } = useI18n()
|
||||
return {
|
||||
getToolLabel: (raw: string) => resolveToolLabel(raw, t, te),
|
||||
}
|
||||
}
|
||||
@ -1865,4 +1865,79 @@ export default {
|
||||
skipped: 'Nothing to consolidate',
|
||||
},
|
||||
},
|
||||
// Tool display labels consumed by useToolLabel() — keys must mirror zh-CN.ts exactly.
|
||||
// Unknown tools (MCP / custom skills) fall back to humanizeToolName() and are not listed here.
|
||||
toolLabels: {
|
||||
// Delegation
|
||||
delegateToAgent: 'Delegate to Agent',
|
||||
delegateParallel: 'Parallel Delegation',
|
||||
listAvailableAgents: 'List Agents',
|
||||
|
||||
// Wiki
|
||||
wiki_search_pages: 'Search Knowledge Base',
|
||||
wiki_semantic_search: 'Semantic Search KB',
|
||||
wiki_read_page: 'Read KB Page',
|
||||
wiki_list_pages: 'List KB Pages',
|
||||
wiki_related_pages: 'Find Related Pages',
|
||||
wiki_trace_source: 'Trace Knowledge Source',
|
||||
wiki_create_page: 'Create KB Page',
|
||||
wiki_delete_page: 'Delete KB Page',
|
||||
wiki_enrich_page: 'Enrich KB Page',
|
||||
wiki_explain_relation: 'Explain Relation',
|
||||
|
||||
// Web search
|
||||
search: 'Web Search',
|
||||
|
||||
// Memory
|
||||
recall_structured: 'Recall Memory',
|
||||
remember_structured: 'Save Memory',
|
||||
forget_structured: 'Clear Memory',
|
||||
fact_probe: 'Probe Facts',
|
||||
fact_related: 'Query Related Facts',
|
||||
fact_list_contradictions: 'Check Contradictions',
|
||||
session_search: 'Search Sessions',
|
||||
read_workspace_memory_file: 'Read Memory File',
|
||||
write_workspace_memory_file: 'Write Memory File',
|
||||
edit_workspace_memory_file: 'Edit Memory File',
|
||||
list_workspace_memory_files: 'List Memory Files',
|
||||
|
||||
// Files & shell
|
||||
read_file: 'Read File',
|
||||
execute_shell_command: 'Execute Command',
|
||||
extract_document_text: 'Extract Document',
|
||||
extract_pdf_text: 'Extract PDF',
|
||||
extract_docx_text: 'Extract Document',
|
||||
detect_file_type: 'Detect File Type',
|
||||
readMateClawDoc: 'Read System Docs',
|
||||
|
||||
// Generative
|
||||
image_generate: 'Generate Image',
|
||||
video_generate: 'Generate Video',
|
||||
music_generate: 'Generate Music',
|
||||
|
||||
// Data
|
||||
query_datasource: 'Query Datasource',
|
||||
execute_sql: 'Execute SQL',
|
||||
|
||||
// Browser
|
||||
browser_use: 'Browser Action',
|
||||
|
||||
// Cron
|
||||
create_cron_job: 'Create Cron Job',
|
||||
list_cron_jobs: 'List Cron Jobs',
|
||||
toggle_cron_job: 'Toggle Cron Job',
|
||||
delete_cron_job: 'Delete Cron Job',
|
||||
|
||||
// Time
|
||||
getCurrentDateTime: 'Get Current Time',
|
||||
getCurrentTime: 'Get Current Time',
|
||||
getCurrentDate: 'Get Current Date',
|
||||
|
||||
// Skills
|
||||
skill_manage: 'Manage Skills',
|
||||
runSkillScript: 'Run Skill',
|
||||
listSkillFiles: 'List Skill Files',
|
||||
listAvailableSkills: 'List Skills',
|
||||
readSkillFile: 'Read Skill File',
|
||||
},
|
||||
} as const
|
||||
|
||||
@ -1875,4 +1875,79 @@ export default {
|
||||
skipped: '没有需要整合的内容',
|
||||
},
|
||||
},
|
||||
// Tool display labels consumed by useToolLabel() — keys must mirror en-US.ts exactly.
|
||||
// Unknown tools (MCP / custom skills) fall back to humanizeToolName() and are not listed here.
|
||||
toolLabels: {
|
||||
// Delegation
|
||||
delegateToAgent: '委派给智能体',
|
||||
delegateParallel: '并行委派',
|
||||
listAvailableAgents: '列出可用智能体',
|
||||
|
||||
// Wiki
|
||||
wiki_search_pages: '搜索知识库',
|
||||
wiki_semantic_search: '语义检索知识库',
|
||||
wiki_read_page: '读取知识库页面',
|
||||
wiki_list_pages: '列出知识库页面',
|
||||
wiki_related_pages: '查找相关页面',
|
||||
wiki_trace_source: '溯源知识库',
|
||||
wiki_create_page: '创建知识库页面',
|
||||
wiki_delete_page: '删除知识库页面',
|
||||
wiki_enrich_page: '丰富知识库页面',
|
||||
wiki_explain_relation: '解释关联关系',
|
||||
|
||||
// Web search
|
||||
search: '联网搜索',
|
||||
|
||||
// Memory
|
||||
recall_structured: '检索记忆',
|
||||
remember_structured: '保存记忆',
|
||||
forget_structured: '清除记忆',
|
||||
fact_probe: '探查事实',
|
||||
fact_related: '查询关联事实',
|
||||
fact_list_contradictions: '检查矛盾事实',
|
||||
session_search: '搜索会话',
|
||||
read_workspace_memory_file: '读取记忆文件',
|
||||
write_workspace_memory_file: '写入记忆文件',
|
||||
edit_workspace_memory_file: '编辑记忆文件',
|
||||
list_workspace_memory_files: '列出记忆文件',
|
||||
|
||||
// Files & shell
|
||||
read_file: '读取文件',
|
||||
execute_shell_command: '执行命令',
|
||||
extract_document_text: '提取文档内容',
|
||||
extract_pdf_text: '提取 PDF 内容',
|
||||
extract_docx_text: '提取文档内容',
|
||||
detect_file_type: '识别文件类型',
|
||||
readMateClawDoc: '查阅系统文档',
|
||||
|
||||
// Generative
|
||||
image_generate: '生成图片',
|
||||
video_generate: '生成视频',
|
||||
music_generate: '生成音乐',
|
||||
|
||||
// Data
|
||||
query_datasource: '查询数据源',
|
||||
execute_sql: '执行 SQL',
|
||||
|
||||
// Browser
|
||||
browser_use: '浏览器操作',
|
||||
|
||||
// Cron
|
||||
create_cron_job: '创建定时任务',
|
||||
list_cron_jobs: '查看定时任务',
|
||||
toggle_cron_job: '启停定时任务',
|
||||
delete_cron_job: '删除定时任务',
|
||||
|
||||
// Time
|
||||
getCurrentDateTime: '获取当前时间',
|
||||
getCurrentTime: '获取当前时间',
|
||||
getCurrentDate: '获取当前日期',
|
||||
|
||||
// Skills
|
||||
skill_manage: '管理技能',
|
||||
runSkillScript: '运行技能',
|
||||
listSkillFiles: '列出技能文件',
|
||||
listAvailableSkills: '列出可用技能',
|
||||
readSkillFile: '读取技能文件',
|
||||
},
|
||||
} as const
|
||||
|
||||
Loading…
Reference in New Issue
Block a user