diff --git a/renderer/src/components/main-panel/prompt/index.vue b/renderer/src/components/main-panel/prompt/index.vue index 1143cec..a3a79ac 100644 --- a/renderer/src/components/main-panel/prompt/index.vue +++ b/renderer/src/components/main-panel/prompt/index.vue @@ -4,7 +4,7 @@

- 提示词模块 + {{ t('prompt-module') }}

@@ -24,6 +24,9 @@ import { defineProps } from 'vue'; import PromptTemplates from './prompt-templates.vue'; import PromptReader from './prompt-reader.vue'; import PromptLogger from './prompt-logger.vue'; +import { useI18n } from 'vue-i18n'; + +const { t } = useI18n(); const props = defineProps({ tabId: { diff --git a/renderer/src/components/main-panel/tool/auto-detector/diagram-item-record.vue b/renderer/src/components/main-panel/tool/auto-detector/diagram-item-record.vue new file mode 100644 index 0000000..6f2b50e --- /dev/null +++ b/renderer/src/components/main-panel/tool/auto-detector/diagram-item-record.vue @@ -0,0 +1,107 @@ + + + + + \ No newline at end of file diff --git a/renderer/src/components/main-panel/tool/diagram.ts b/renderer/src/components/main-panel/tool/auto-detector/diagram.ts similarity index 90% rename from renderer/src/components/main-panel/tool/diagram.ts rename to renderer/src/components/main-panel/tool/auto-detector/diagram.ts index b5c6809..55b359d 100644 --- a/renderer/src/components/main-panel/tool/diagram.ts +++ b/renderer/src/components/main-panel/tool/auto-detector/diagram.ts @@ -1,10 +1,14 @@ import type { ElkNode } from 'elkjs/lib/elk-api'; -import { TaskLoop } from '../chat/core/task-loop'; +import { TaskLoop } from '../../chat/core/task-loop'; import type { Reactive } from 'vue'; -import type { ChatStorage } from '../chat/chat-box/chat'; +import type { ChatStorage } from '../../chat/chat-box/chat'; import { ElMessage } from 'element-plus'; import type { ToolItem } from '@/hook/type'; +import I18n from '@/i18n'; + +const { t } = I18n.global; + export interface Edge { id: string; sources: string[]; @@ -50,11 +54,11 @@ export function invalidConnectionDetector(state: DiagramState, d: Node): CanConn const to = d.id; if (!from) { - return { canConnect: false, reason: '未选择起始节点' }; + return { canConnect: false, reason: t('not-select-begin-node') }; } if (from === to) { - return { canConnect: false, reason: '不能连接到自身' }; + return { canConnect: false, reason: '' }; } // 建立邻接表 @@ -84,11 +88,11 @@ export function invalidConnectionDetector(state: DiagramState, d: Node): CanConn } if (hasPath(to, from, new Set())) { - return { canConnect: false, reason: '连接会形成环路' }; + return { canConnect: false, reason: t('can-make-loop') }; } if (hasPath(from, to, new Set())) { - return { canConnect: false, reason: '这是一个重复的连接' }; + return { canConnect: false, reason: t('this-is-repeat-connection') }; } return { @@ -196,13 +200,13 @@ export async function makeNodeTest( } catch (e) { // ElMessage.error('AI 生成的 JSON 解析错误'); dataView.status = 'error'; - dataView.result = 'AI 生成的 JSON 解析错误'; + dataView.result = t('ai-gen-error-json'); context.render(); } } else { // ElMessage.error('AI 调用了未知的工具'); dataView.status = 'error'; - dataView.result = 'AI 调用了未知的工具 ' + toolCall.function?.name; + dataView.result = t('ai-invoke-unknown-tool') + ' ' + toolCall.function?.name; context.render(); } loop.abort(); diff --git a/renderer/src/components/main-panel/tool/diagram.vue b/renderer/src/components/main-panel/tool/auto-detector/diagram.vue similarity index 92% rename from renderer/src/components/main-panel/tool/diagram.vue rename to renderer/src/components/main-panel/tool/auto-detector/diagram.vue index 21f997b..d48660f 100644 --- a/renderer/src/components/main-panel/tool/diagram.vue +++ b/renderer/src/components/main-panel/tool/auto-detector/diagram.vue @@ -2,16 +2,19 @@
- +
@@ -23,6 +26,12 @@ import { mcpClientAdapter } from '@/views/connect/core'; import { invalidConnectionDetector, type Edge, type Node, type NodeDataView } from './diagram'; import { ElMessage } from 'element-plus'; + +import DiagramItemRecord from './diagram-item-record.vue'; +import { useI18n } from 'vue-i18n'; + +const { t } = useI18n(); + const svgContainer = ref(null); let prevNodes: any[] = []; let prevEdges: any[] = []; @@ -37,6 +46,27 @@ const state = reactive({ dataView: new Map }); + +let cancelHoverHandler: NodeJS.Timeout | undefined = undefined; + +const setHoverItem = (id: string) => { + if (cancelHoverHandler) { + clearTimeout(cancelHoverHandler); + } + state.hoverNodeId = id; +} + +const clearHoverItem = () => { + cancelHoverHandler = setTimeout(() => { + if (cancelHoverHandler) { + clearTimeout(cancelHoverHandler); + } + if (state.hoverNodeId) { + state.hoverNodeId = null; + } + }, 300); +}; + const getAllTools = async () => { const items = []; for (const client of mcpClientAdapter.clients) { @@ -287,12 +317,12 @@ function renderSvg() { } else { state.selectedNodeId = d.id; renderSvg(); - context.setCaption('选择另一个节点以定义测试拓扑'); + context.setCaption(t('select-node-define-test-tomo')); } state.draggingNodeId = null; }) .on('mouseover', function (event, d) { - state.hoverNodeId = d.id; + setHoverItem(d.id); d3.select(this).select('rect') .transition() .duration(200) @@ -300,7 +330,7 @@ function renderSvg() { .attr('stroke-width', 2); }) .on('mouseout', function (event, d) { - state.hoverNodeId = null; + clearHoverItem(); if (state.selectedNodeId === d.id) return; d3.select(this).select('rect') .transition() @@ -436,7 +466,7 @@ function renderSvg() { .attr('stroke', 'var(--main-color)') .attr('stroke-width', 4.5); - context.setCaption('点击边以删除'); + context.setCaption(t('click-edge-to-delete')); }) .on('mouseout', function () { @@ -500,10 +530,8 @@ onMounted(() => { function getNodePopupStyle(node: any): any { // 节点的 svg 坐标转为容器内绝对定位 // 注意:这里假设 offsetX、node.x、node.y 已经是最新的 - console.log(node); - - const left = (node.x || 0) + (node.width || 160) - 120; // 节点右侧 - const top = (node.y || 0) + 30; // 节点顶部对齐 + const left = (node.x || 0) + (node.width || 160) + 120; // 节点右侧 + const top = (node.y || 0) + 30; return { position: 'absolute', left: `${left}px`, diff --git a/renderer/src/components/main-panel/tool/auto-detector.vue b/renderer/src/components/main-panel/tool/auto-detector/index.vue similarity index 86% rename from renderer/src/components/main-panel/tool/auto-detector.vue rename to renderer/src/components/main-panel/tool/auto-detector/index.vue index d751a97..5414f4c 100644 --- a/renderer/src/components/main-panel/tool/auto-detector.vue +++ b/renderer/src/components/main-panel/tool/auto-detector/index.vue @@ -17,7 +17,12 @@ placeholder="请输入 prompt" />
- enableXmlWrapper + XML
{{ t("cancel") }} @@ -44,6 +49,9 @@ import { nextTick, provide, ref } from 'vue'; import Diagram from './diagram.vue'; import { makeNodeTest, topoSortParallel, type DiagramContext, type DiagramState } from './diagram'; import { ElMessage } from 'element-plus'; +import { tabs } from '../../panel'; +import type { ToolStorage } from '../tools'; + import { useI18n } from 'vue-i18n'; const showDiagram = ref(true); @@ -52,6 +60,21 @@ const { t } = useI18n(); const caption = ref(''); const showCaption = ref(false); +const props = defineProps({ + tabId: { + type: Number, + required: true + } +}); + + +const tab = tabs.content[props.tabId]; +const tabStorage = tab.storage as ToolStorage; + +if (!tabStorage.formData) { + tabStorage.formData = {}; +} + function setCaption(text: string) { caption.value = text; if (caption.value) { diff --git a/renderer/src/components/main-panel/tool/index.vue b/renderer/src/components/main-panel/tool/index.vue index 9025e05..26266e7 100644 --- a/renderer/src/components/main-panel/tool/index.vue +++ b/renderer/src/components/main-panel/tool/index.vue @@ -1,11 +1,11 @@