support self-check
This commit is contained in:
parent
25f74b8f1e
commit
13673d798b
@ -5,13 +5,28 @@
|
|||||||
<span class="item-status" :class="props.dataView.status">{{ props.dataView.status }}</span>
|
<span class="item-status" :class="props.dataView.status">{{ props.dataView.status }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-desc">{{ props.dataView.tool.description }}</div>
|
<div class="item-desc">{{ props.dataView.tool.description }}</div>
|
||||||
<div class="item-schema">
|
|
||||||
<span class="item-label">Input Schema:</span>
|
<div v-if="props.dataView.function !== undefined" class="item-result">
|
||||||
<pre class="item-json">{{ formatJson(props.dataView.tool.inputSchema) }}</pre>
|
<span class="item-label">Function</span>
|
||||||
|
<pre class="item-json">{{ props.dataView.function.name }}</pre>
|
||||||
|
<span class="item-label">Arguments</span>
|
||||||
|
<pre class="item-json">{{ formatJson(props.dataView.function.arguments) }}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="props.dataView.result !== undefined" class="item-result">
|
<div v-if="props.dataView.result !== undefined" class="item-result">
|
||||||
<span class="item-label">Result:</span>
|
<span class="item-label">Result</span>
|
||||||
<pre class="item-json">{{ formatJson(props.dataView.result) }}</pre>
|
<template v-if="Array.isArray(props.dataView.result)">
|
||||||
|
<div
|
||||||
|
v-for="(item, idx) in props.dataView.result"
|
||||||
|
:key="idx"
|
||||||
|
class="result-block"
|
||||||
|
>
|
||||||
|
<pre class="item-json" v-if="typeof item === 'object' && item.text !== undefined">{{ item.text }}</pre>
|
||||||
|
<pre class="item-json" v-else>{{ formatJson(item) }}</pre>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<pre class="item-json" v-else-if="typeof props.dataView.result === 'string'">{{ props.dataView.result }}</pre>
|
||||||
|
<pre class="item-json" v-else>{{ formatJson(props.dataView.result) }}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="diagram-item-record">
|
<div v-else class="diagram-item-record">
|
||||||
@ -48,8 +63,7 @@ function formatJson(obj: any) {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #222;
|
max-width: 300px;
|
||||||
max-width: 420px;
|
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,4 +118,10 @@ function formatJson(obj: any) {
|
|||||||
.item-result {
|
.item-result {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-block {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
border-radius: .5em;
|
||||||
|
background-color: rgba(245, 108, 108, 0.3);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -1,11 +1,12 @@
|
|||||||
import type { ElkNode } from 'elkjs/lib/elk-api';
|
import type { ElkNode } from 'elkjs/lib/elk-api';
|
||||||
import { TaskLoop } from '../../chat/core/task-loop';
|
import { MessageState, TaskLoop } from '../../chat/core/task-loop';
|
||||||
import type { Reactive } from 'vue';
|
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 { ElMessage } from 'element-plus';
|
||||||
import type { ToolItem } from '@/hook/type';
|
import type { ToolItem } from '@/hook/type';
|
||||||
|
|
||||||
import I18n from '@/i18n';
|
import I18n from '@/i18n';
|
||||||
|
import type { ChatCompletionChunk } from 'openai/resources/index.mjs';
|
||||||
|
|
||||||
const { t } = I18n.global;
|
const { t } = I18n.global;
|
||||||
|
|
||||||
@ -13,11 +14,14 @@ export interface Edge {
|
|||||||
id: string;
|
id: string;
|
||||||
sources: string[];
|
sources: string[];
|
||||||
targets: string[];
|
targets: string[];
|
||||||
section?: any; // { startPoint: { x, y }, endPoint: { x,
|
sections?: any; // { startPoint: { x, y }, endPoint: { x,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Node = ElkNode & {
|
export type Node = ElkNode & {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface DiagramState {
|
export interface DiagramState {
|
||||||
@ -36,7 +40,8 @@ export interface CanConnectResult {
|
|||||||
export interface NodeDataView {
|
export interface NodeDataView {
|
||||||
tool: ToolItem;
|
tool: ToolItem;
|
||||||
status: 'default' | 'running' | 'waiting' | 'success' | 'error';
|
status: 'default' | 'running' | 'waiting' | 'success' | 'error';
|
||||||
result: any;
|
function?: ChatCompletionChunk.Choice.Delta.ToolCall.Function;
|
||||||
|
result?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DiagramContext {
|
export interface DiagramContext {
|
||||||
@ -191,7 +196,7 @@ export async function makeNodeTest(
|
|||||||
let aiMockJson: any = undefined;
|
let aiMockJson: any = undefined;
|
||||||
|
|
||||||
loop.registerOnToolCall(toolCall => {
|
loop.registerOnToolCall(toolCall => {
|
||||||
console.log(toolCall);
|
dataView.function = toolCall.function;
|
||||||
|
|
||||||
if (toolCall.function?.name === dataView.tool?.name) {
|
if (toolCall.function?.name === dataView.tool?.name) {
|
||||||
try {
|
try {
|
||||||
@ -202,19 +207,34 @@ export async function makeNodeTest(
|
|||||||
dataView.status = 'error';
|
dataView.status = 'error';
|
||||||
dataView.result = t('ai-gen-error-json');
|
dataView.result = t('ai-gen-error-json');
|
||||||
context.render();
|
context.render();
|
||||||
|
loop.abort();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ElMessage.error('AI 调用了未知的工具');
|
// ElMessage.error('AI 调用了未知的工具');
|
||||||
dataView.status = 'error';
|
dataView.status = 'error';
|
||||||
dataView.result = t('ai-invoke-unknown-tool') + ' ' + toolCall.function?.name;
|
dataView.result = t('ai-invoke-unknown-tool') + ' ' + toolCall.function?.name;
|
||||||
context.render();
|
context.render();
|
||||||
}
|
|
||||||
loop.abort();
|
loop.abort();
|
||||||
|
}
|
||||||
return toolCall;
|
return toolCall;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
loop.registerOnToolCalled(toolCalled => {
|
||||||
|
if (toolCalled.state === MessageState.Success) {
|
||||||
|
dataView.status = 'success';
|
||||||
|
dataView.result = toolCalled.content;
|
||||||
|
} else {
|
||||||
|
dataView.status = 'error';
|
||||||
|
dataView.result = toolCalled.content;
|
||||||
|
}
|
||||||
|
loop.abort();
|
||||||
|
return toolCalled;
|
||||||
|
})
|
||||||
|
|
||||||
loop.registerOnError(error => {
|
loop.registerOnError(error => {
|
||||||
ElMessage.error(error + '');
|
dataView.status = 'error';
|
||||||
|
dataView.result = error;
|
||||||
|
context.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
await loop.start(chatStorage, usePrompt);
|
await loop.start(chatStorage, usePrompt);
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
:style="getNodePopupStyle(node)"
|
:style="getNodePopupStyle(node)"
|
||||||
class="node-popup"
|
class="node-popup"
|
||||||
>
|
>
|
||||||
|
<el-scrollbar height="100%" width="100%">
|
||||||
<DiagramItemRecord :data-view="state.dataView.get(node.id)"/>
|
<DiagramItemRecord :data-view="state.dataView.get(node.id)"/>
|
||||||
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
@ -29,16 +31,25 @@ import { ElMessage } from 'element-plus';
|
|||||||
|
|
||||||
import DiagramItemRecord from './diagram-item-record.vue';
|
import DiagramItemRecord from './diagram-item-record.vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import type { ToolStorage } from '../tools';
|
||||||
|
import { tabs } from '../../panel';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
tabId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const svgContainer = ref<HTMLDivElement | null>(null);
|
const svgContainer = ref<HTMLDivElement | null>(null);
|
||||||
let prevNodes: any[] = [];
|
let prevNodes: any[] = [];
|
||||||
let prevEdges: any[] = [];
|
let prevEdges: any[] = [];
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
nodes: [] as any[],
|
nodes: [] as Node[],
|
||||||
edges: [] as any[],
|
edges: [] as Edge[],
|
||||||
selectedNodeId: null as string | null,
|
selectedNodeId: null as string | null,
|
||||||
draggingNodeId: null as string | null,
|
draggingNodeId: null as string | null,
|
||||||
hoverNodeId: null as string | null,
|
hoverNodeId: null as string | null,
|
||||||
@ -46,6 +57,29 @@ const state = reactive({
|
|||||||
dataView: new Map<string, NodeDataView>
|
dataView: new Map<string, NodeDataView>
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tab = tabs.content[props.tabId];
|
||||||
|
const tabStorage = tab.storage as ToolStorage;
|
||||||
|
const autoDetectDiagram = tabStorage.autoDetectDiagram;
|
||||||
|
|
||||||
|
if (autoDetectDiagram) {
|
||||||
|
// 将 tabStorage.autoDetectDiagram 中的 dataView 保存到 state 中
|
||||||
|
autoDetectDiagram.views?.forEach(item => {
|
||||||
|
state.dataView.set(item.tool.name, {
|
||||||
|
tool: item.tool,
|
||||||
|
status: item.status || 'waiting',
|
||||||
|
result: item.result || null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
tabStorage.autoDetectDiagram = {
|
||||||
|
edges: [],
|
||||||
|
views: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(tabStorage.autoDetectDiagram!.views);
|
||||||
|
console.log(state.dataView);
|
||||||
|
|
||||||
|
|
||||||
let cancelHoverHandler: NodeJS.Timeout | undefined = undefined;
|
let cancelHoverHandler: NodeJS.Timeout | undefined = undefined;
|
||||||
|
|
||||||
@ -88,17 +122,26 @@ const recomputeLayout = async () => {
|
|||||||
children: state.nodes,
|
children: state.nodes,
|
||||||
edges: state.edges
|
edges: state.edges
|
||||||
};
|
};
|
||||||
const layout = await elk.layout(elkGraph) as Node;
|
const layout = await elk.layout(elkGraph) as unknown as Node;
|
||||||
|
|
||||||
state.nodes.forEach((n, i) => {
|
state.nodes.forEach((n, i) => {
|
||||||
const ln = layout.children?.find(c => c.id === n.id);
|
const ln = layout.children?.find(c => c.id === n.id);
|
||||||
if (ln) {
|
if (ln) {
|
||||||
n.x = ln.x;
|
n.x = ln.x;
|
||||||
n.y = ln.y;
|
n.y = ln.y;
|
||||||
n.width = ln.width;
|
n.width = ln.width || 200; // 默认宽度
|
||||||
n.height = ln.height;
|
n.height = ln.height || 64; // 默认高度
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
state.edges = layout.edges || [];
|
state.edges = layout.edges || [];
|
||||||
|
|
||||||
|
// 保存拓扑信息到 tabStorage
|
||||||
|
tabStorage.autoDetectDiagram!.edges = state.edges.map(edge => ({
|
||||||
|
id: edge.id,
|
||||||
|
sources: edge.sources || [],
|
||||||
|
targets: edge.targets || []
|
||||||
|
}));
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,6 +152,19 @@ const drawDiagram = async () => {
|
|||||||
const nodes = [] as Node[];
|
const nodes = [] as Node[];
|
||||||
const edges = [] as Edge[];
|
const edges = [] as Edge[];
|
||||||
|
|
||||||
|
// 如果保存了 edges 信息,则需要进行同步
|
||||||
|
const reservedEdges = autoDetectDiagram?.edges;
|
||||||
|
if (reservedEdges) {
|
||||||
|
for (const edge of reservedEdges) {
|
||||||
|
if (edge.sources && edge.targets && edge.sources.length > 0 && edge.targets.length > 0) {
|
||||||
|
edges.push({
|
||||||
|
id: edge.id,
|
||||||
|
sources: edge.sources || [],
|
||||||
|
targets: edge.targets || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (let i = 0; i < tools.length - 1; ++i) {
|
for (let i = 0; i < tools.length - 1; ++i) {
|
||||||
const prev = tools[i];
|
const prev = tools[i];
|
||||||
const next = tools[i + 1];
|
const next = tools[i + 1];
|
||||||
@ -118,6 +174,7 @@ const drawDiagram = async () => {
|
|||||||
targets: [next.name]
|
targets: [next.name]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const tool of tools) {
|
for (const tool of tools) {
|
||||||
nodes.push({
|
nodes.push({
|
||||||
@ -127,12 +184,14 @@ const drawDiagram = async () => {
|
|||||||
labels: [{ text: tool.name || 'Tool' }]
|
labels: [{ text: tool.name || 'Tool' }]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!state.dataView.has(tool.name)) {
|
||||||
|
// 如果 dataView 中没有该工具,则初始化
|
||||||
state.dataView.set(tool.name, {
|
state.dataView.set(tool.name, {
|
||||||
tool,
|
tool,
|
||||||
status: 'waiting',
|
status: 'waiting'
|
||||||
result: null
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
state.edges = edges;
|
state.edges = edges;
|
||||||
state.nodes = nodes;
|
state.nodes = nodes;
|
||||||
@ -291,10 +350,8 @@ function renderSvg() {
|
|||||||
if (state.selectedNodeId) {
|
if (state.selectedNodeId) {
|
||||||
|
|
||||||
const { canConnect, reason } = invalidConnectionDetector(state, d);
|
const { canConnect, reason } = invalidConnectionDetector(state, d);
|
||||||
|
|
||||||
console.log(reason);
|
console.log(reason);
|
||||||
|
|
||||||
|
|
||||||
if (reason) {
|
if (reason) {
|
||||||
ElMessage.warning(reason);
|
ElMessage.warning(reason);
|
||||||
}
|
}
|
||||||
@ -340,8 +397,8 @@ function renderSvg() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
nodeGroupEnter.append('rect')
|
nodeGroupEnter.append('rect')
|
||||||
.attr('width', d => d.width)
|
.attr('width', (d: any) => d.width)
|
||||||
.attr('height', d => d.height)
|
.attr('height', (d: any) => d.height)
|
||||||
.attr('rx', 16)
|
.attr('rx', 16)
|
||||||
.attr('fill', 'var(--main-light-color-20)')
|
.attr('fill', 'var(--main-light-color-20)')
|
||||||
.attr('stroke', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-light-color-10)')
|
.attr('stroke', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-light-color-10)')
|
||||||
@ -454,7 +511,6 @@ function renderSvg() {
|
|||||||
nodeGroup.select('rect')
|
nodeGroup.select('rect')
|
||||||
.transition()
|
.transition()
|
||||||
.duration(400)
|
.duration(400)
|
||||||
.attr('stroke-width', d => state.selectedNodeId === d.id ? 2 : 1)
|
|
||||||
.attr('stroke', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-light-color-10)');
|
.attr('stroke', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-light-color-10)');
|
||||||
|
|
||||||
// 边高亮
|
// 边高亮
|
||||||
@ -530,12 +586,33 @@ onMounted(() => {
|
|||||||
function getNodePopupStyle(node: any): any {
|
function getNodePopupStyle(node: any): any {
|
||||||
// 节点的 svg 坐标转为容器内绝对定位
|
// 节点的 svg 坐标转为容器内绝对定位
|
||||||
// 注意:这里假设 offsetX、node.x、node.y 已经是最新的
|
// 注意:这里假设 offsetX、node.x、node.y 已经是最新的
|
||||||
const left = (node.x || 0) + (node.width || 160) + 120; // 节点右侧
|
const marginX = 50;
|
||||||
const top = (node.y || 0) + 30;
|
const marginY = 80;
|
||||||
|
const popupWidth = 300;
|
||||||
|
const popupHeight = 500;
|
||||||
|
|
||||||
|
let left = (node.x || 0) + (node.width || 160) + 100;
|
||||||
|
let top = (node.y || 0) + 30;
|
||||||
|
|
||||||
|
// 获取容器宽高
|
||||||
|
const container = svgContainer.value;
|
||||||
|
let containerWidth = 1200, containerHeight = 800; // 默认值
|
||||||
|
if (container) {
|
||||||
|
const rect = container.getBoundingClientRect();
|
||||||
|
containerWidth = rect.width;
|
||||||
|
containerHeight = rect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 限制 left 和 top 不超出容器
|
||||||
|
left = Math.max(marginX, Math.min(left, containerWidth - popupWidth - marginX));
|
||||||
|
top = Math.max(marginY, Math.min(top, containerHeight - popupHeight - marginY));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: `${left}px`,
|
left: `${left}px`,
|
||||||
top: `${top}px`,
|
top: `${top}px`,
|
||||||
|
width: `${popupWidth}px`,
|
||||||
|
height: `${popupHeight}px`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -556,7 +633,6 @@ function getNodePopupStyle(node: any): any {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
border: 1px solid var(--main-color);
|
border: 1px solid var(--main-color);
|
||||||
width: 240px;
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
@ -17,12 +17,10 @@
|
|||||||
placeholder="请输入 prompt" />
|
placeholder="请输入 prompt" />
|
||||||
<div style="display: flex; align-items: center; margin-bottom: 8px;">
|
<div style="display: flex; align-items: center; margin-bottom: 8px;">
|
||||||
<el-switch v-model="enableXmlWrapper" style="margin-right: 8px;" />
|
<el-switch v-model="enableXmlWrapper" style="margin-right: 8px;" />
|
||||||
<span
|
<span :style="{
|
||||||
:style="{
|
opacity: enableXmlWrapper ? 1 : 0.7,
|
||||||
opacity: enableXmlWrapper? 1 : 0.7,
|
|
||||||
color: enableXmlWrapper ? 'var(--main-color)' : undefined
|
color: enableXmlWrapper ? 'var(--main-color)' : undefined
|
||||||
}"
|
}">XML</span>
|
||||||
>XML</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align: right;">
|
<div style="text-align: right;">
|
||||||
<el-button size="small" @click="testFormVisible = false">{{ t("cancel") }}</el-button>
|
<el-button size="small" @click="testFormVisible = false">{{ t("cancel") }}</el-button>
|
||||||
@ -34,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-scrollbar height="80vh">
|
<el-scrollbar height="80vh">
|
||||||
<Diagram />
|
<Diagram :tab-id="props.tabId" />
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
<transition name="main-fade" mode="out-in">
|
<transition name="main-fade" mode="out-in">
|
||||||
<div class="caption" v-show="showCaption">
|
<div class="caption" v-show="showCaption">
|
||||||
@ -49,10 +47,10 @@ import { nextTick, provide, ref } from 'vue';
|
|||||||
import Diagram from './diagram.vue';
|
import Diagram from './diagram.vue';
|
||||||
import { makeNodeTest, topoSortParallel, type DiagramContext, type DiagramState } from './diagram';
|
import { makeNodeTest, topoSortParallel, type DiagramContext, type DiagramState } from './diagram';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { tabs } from '../../panel';
|
|
||||||
import type { ToolStorage } from '../tools';
|
|
||||||
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import type { ToolStorage } from '../tools';
|
||||||
|
import { tabs } from '../../panel';
|
||||||
|
|
||||||
const showDiagram = ref(true);
|
const showDiagram = ref(true);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -67,14 +65,6 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const tab = tabs.content[props.tabId];
|
|
||||||
const tabStorage = tab.storage as ToolStorage;
|
|
||||||
|
|
||||||
if (!tabStorage.formData) {
|
|
||||||
tabStorage.formData = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCaption(text: string) {
|
function setCaption(text: string) {
|
||||||
caption.value = text;
|
caption.value = text;
|
||||||
if (caption.value) {
|
if (caption.value) {
|
||||||
@ -89,14 +79,27 @@ function setCaption(text: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const context: DiagramContext = {
|
const context: DiagramContext = {
|
||||||
reset: () => {},
|
reset: () => { },
|
||||||
render: () => {},
|
render: () => { },
|
||||||
state: undefined,
|
state: undefined,
|
||||||
setCaption
|
setCaption
|
||||||
};
|
};
|
||||||
|
|
||||||
provide('context', context);
|
provide('context', context);
|
||||||
|
|
||||||
|
const tab = tabs.content[props.tabId];
|
||||||
|
const tabStorage = tab.storage as ToolStorage;
|
||||||
|
const autoDetectDiagram = tabStorage.autoDetectDiagram;
|
||||||
|
|
||||||
|
if (autoDetectDiagram) {
|
||||||
|
// ...
|
||||||
|
} else {
|
||||||
|
tabStorage.autoDetectDiagram = {
|
||||||
|
edges: [],
|
||||||
|
views: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 新增:自检参数表单相关
|
// 新增:自检参数表单相关
|
||||||
const testFormVisible = ref(false);
|
const testFormVisible = ref(false);
|
||||||
const enableXmlWrapper = ref(false);
|
const enableXmlWrapper = ref(false);
|
||||||
@ -106,21 +109,31 @@ async function onTestConfirm() {
|
|||||||
testFormVisible.value = false;
|
testFormVisible.value = false;
|
||||||
// 这里可以将 enableXmlWrapper.value 和 testPrompt.value 传递给自检逻辑
|
// 这里可以将 enableXmlWrapper.value 和 testPrompt.value 传递给自检逻辑
|
||||||
const state = context.state;
|
const state = context.state;
|
||||||
|
|
||||||
|
|
||||||
|
tabStorage.autoDetectDiagram!.views = [];
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
const dispatches = topoSortParallel(state);
|
const dispatches = topoSortParallel(state);
|
||||||
for (const nodeIds of dispatches) {
|
for (const nodeIds of dispatches) {
|
||||||
await Promise.all(
|
for (const id of nodeIds) {
|
||||||
nodeIds.map(id => {
|
const view = state.dataView.get(id);
|
||||||
const node = state.dataView.get(id);
|
if (view) {
|
||||||
if (node) {
|
await makeNodeTest(view, enableXmlWrapper.value, testPrompt.value, context)
|
||||||
return makeNodeTest(node, enableXmlWrapper.value, testPrompt.value, context)
|
tabStorage.autoDetectDiagram!.views!.push({
|
||||||
|
tool: view.tool,
|
||||||
|
status: view.status,
|
||||||
|
function: view.function,
|
||||||
|
result: view.result
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error('error');
|
ElMessage.error('error');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import type { ToolCallResponse } from '@/hook/type';
|
import type { ToolCallResponse } from '@/hook/type';
|
||||||
|
import type { Edge, Node, NodeDataView } from './auto-detector/diagram';
|
||||||
|
|
||||||
export interface ToolStorage {
|
export interface ToolStorage {
|
||||||
activeNames: any[];
|
activeNames: any[];
|
||||||
currentToolName: string;
|
currentToolName: string;
|
||||||
lastToolCallResponse?: ToolCallResponse | string;
|
lastToolCallResponse?: ToolCallResponse | string;
|
||||||
formData: Record<string, any>;
|
formData: Record<string, any>;
|
||||||
|
autoDetectDiagram?: {
|
||||||
|
edges?: Edge[];
|
||||||
|
views?: NodeDataView[];
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user