-
@@ -66,19 +84,21 @@
@@ -130,7 +151,7 @@ const isValidJSON = (str: string) => {
.tool-call-header {
display: flex;
align-items: center;
- margin-bottom: 5px;
+ margin-top: 10px;
}
.tool-name {
@@ -143,6 +164,10 @@ const isValidJSON = (str: string) => {
height: 26px;
}
+.tool-name.error {
+ color: var(--el-color-error);
+}
+
.tool-type {
font-size: 0.8em;
color: var(--el-text-color-secondary);
@@ -155,6 +180,10 @@ const isValidJSON = (str: string) => {
height: 22px;
}
+.response-item {
+ margin-bottom: 10px;
+}
+
.tool-arguments {
margin: 0;
padding: 8px;
@@ -170,6 +199,10 @@ const isValidJSON = (str: string) => {
border-radius: 4px;
}
+.tool-result.error {
+ background-color: rgba(245, 108, 108, 0.5);
+}
+
.tool-text {
white-space: pre-wrap;
line-height: 1.6;
diff --git a/renderer/src/components/main-panel/chat/task-loop.ts b/renderer/src/components/main-panel/chat/task-loop.ts
index 4f44d22..2c15f61 100644
--- a/renderer/src/components/main-panel/chat/task-loop.ts
+++ b/renderer/src/components/main-panel/chat/task-loop.ts
@@ -1,6 +1,6 @@
/* eslint-disable */
import { Ref } from "vue";
-import { ToolCall, ChatStorage, getToolSchema } from "./chat";
+import { ToolCall, ChatStorage, getToolSchema, MessageState } from "./chat";
import { useMessageBridge } from "@/api/message-bridge";
import type { OpenAI } from 'openai';
import { callTool } from "../tool/tools";
@@ -12,6 +12,11 @@ interface TaskLoopOptions {
maxEpochs: number;
}
+interface IErrorMssage {
+ state: MessageState,
+ msg: string
+}
+
/**
* @description 对任务循环进行的抽象封装
*/
@@ -23,7 +28,7 @@ export class TaskLoop {
constructor(
private readonly streamingContent: Ref
,
private readonly streamingToolCalls: Ref,
- private onError: (msg: string) => void = (msg) => {},
+ private onError: (error: IErrorMssage) => void = (msg) => {},
private onChunk: (chunk: ChatCompletionChunk) => void = (chunk) => {},
private onDone: () => void = () => {},
private onEpoch: () => void = () => {},
@@ -42,15 +47,33 @@ export class TaskLoop {
if (!toolResponse.isError) {
const content = JSON.stringify(toolResponse.content);
- return content;
+ return {
+ content,
+ state: MessageState.Success,
+
+ };
} else {
- this.onError(`工具调用失败: ${toolResponse.content}`);
- console.error(toolResponse.content);
+ this.onError({
+ state: MessageState.ToolCall,
+ msg: `工具调用失败: ${toolResponse.content}`
+ });
+ console.error(toolResponse.content);
+ return {
+ content: toolResponse.content.toString(),
+ state: MessageState.ToolCall
+ }
}
} catch (error) {
- this.onError(`工具调用失败: ${(error as Error).message}`);
+ this.onError({
+ state: MessageState.ToolCall,
+ msg: `工具调用失败: ${(error as Error).message}`
+ });
console.error(error);
+ return {
+ content: (error as Error).message,
+ state: MessageState.ToolCall
+ }
}
}
@@ -107,7 +130,10 @@ export class TaskLoop {
return new Promise((resolve, reject) => {
const chunkHandler = this.bridge.addCommandListener('llm/chat/completions/chunk', data => {
if (data.code !== 200) {
- this.onError(data.msg || '请求模型服务时发生错误');
+ this.onError({
+ state: MessageState.ReceiveChunkError,
+ msg: data.msg || '请求模型服务时发生错误'
+ });
resolve();
return;
}
@@ -182,7 +208,7 @@ export class TaskLoop {
this.streamingToolCalls.value = [];
}
- public registerOnError(handler: (msg: string) => void) {
+ public registerOnError(handler: (msg: IErrorMssage) => void) {
this.onError = handler;
}
@@ -208,6 +234,7 @@ export class TaskLoop {
content: userMessage,
extraInfo: {
created: Date.now(),
+ state: MessageState.Success,
serverName: llms[llmManager.currentModelIndex].id || 'unknown'
}
});
@@ -238,6 +265,7 @@ export class TaskLoop {
tool_calls: this.streamingToolCalls.value,
extraInfo: {
created: Date.now(),
+ state: MessageState.Success,
serverName: llms[llmManager.currentModelIndex].id || 'unknown'
}
});
@@ -249,9 +277,10 @@ export class TaskLoop {
tabStorage.messages.push({
role: 'tool',
tool_call_id: toolCall.id || toolCall.function.name,
- content: toolCallResult,
+ content: toolCallResult.content,
extraInfo: {
created: Date.now(),
+ state: toolCallResult.state,
serverName: llms[llmManager.currentModelIndex].id || 'unknown',
usage: this.completionUsage
}
@@ -264,6 +293,7 @@ export class TaskLoop {
content: this.streamingContent.value,
extraInfo: {
created: Date.now(),
+ state: MessageState.Success,
serverName: llms[llmManager.currentModelIndex].id || 'unknown',
usage: this.completionUsage
}
diff --git a/renderer/src/components/main-panel/chat/usage.ts b/renderer/src/components/main-panel/chat/usage.ts
index 5a560f0..8552c8f 100644
--- a/renderer/src/components/main-panel/chat/usage.ts
+++ b/renderer/src/components/main-panel/chat/usage.ts
@@ -20,7 +20,7 @@ export function makeUsageStatistic(extraInfo: IExtraInfo): UsageStatistic | unde
input: usage.prompt_tokens,
output: usage.completion_tokens,
total: usage.prompt_tokens + usage.completion_tokens,
- cacheHitRatio: Math.ceil(usage.prompt_tokens_details?.cached_tokens || 0 / usage.prompt_tokens * 1000) / 10,
+ cacheHitRatio: Math.ceil((usage.prompt_tokens_details?.cached_tokens || 0) / usage.prompt_tokens * 1000) / 10,
}
case 'openai':
diff --git a/renderer/src/components/main-panel/tool/tool-executor.vue b/renderer/src/components/main-panel/tool/tool-executor.vue
index d49dd95..e685212 100644
--- a/renderer/src/components/main-panel/tool/tool-executor.vue
+++ b/renderer/src/components/main-panel/tool/tool-executor.vue
@@ -16,7 +16,7 @@
v-if="property.type === 'string'"
v-model="tabStorage.formData[name]"
type="text"
- :placeholder="t('enter') + ' ' + (property.title || name)"
+ :placeholder="property.description || t('enter') + ' ' + (property.title || name)"
@keydown.enter.prevent="handleExecute"
/>
@@ -24,14 +24,23 @@
v-else-if="property.type === 'number' || property.type === 'integer'"
v-model="tabStorage.formData[name]"
controls-position="right"
- :placeholder="t('enter') + ' ' + (property.title || name)"
+ :placeholder="property.description || t('enter') + ' ' + (property.title || name)"
@keydown.enter.prevent="handleExecute"
/>
+
+
+
@@ -53,9 +62,10 @@ import { useI18n } from 'vue-i18n';
import type { FormInstance, FormRules } from 'element-plus';
import { tabs } from '../panel';
import { callTool, toolsManager, ToolStorage } from './tools';
-import { pinkLog } from '@/views/setting/util';
import { getDefaultValue, normaliseJavascriptType } from '@/hook/mcp';
+import KInputObject from '@/components/k-input-object/index.vue';
+
defineComponent({ name: 'tool-executor' });
const { t } = useI18n();
@@ -74,6 +84,9 @@ if (!tabStorage.formData) {
tabStorage.formData = {};
}
+console.log(tabStorage.formData);
+
+
const formRef = ref();
const loading = ref(false);
@@ -81,6 +94,7 @@ const currentTool = computed(() => {
return toolsManager.tools.find(tool => tool.name === tabStorage.currentToolName);
});
+
const formRules = computed(() => {
const rules: FormRules = {};
if (!currentTool.value?.inputSchema?.properties) return rules;
@@ -108,11 +122,13 @@ const initFormData = () => {
if (!currentTool.value?.inputSchema?.properties) return;
- const newSchemaDataForm: Record = {};
+ const newSchemaDataForm: Record = {};
+
+ console.log(currentTool.value.inputSchema.properties);
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
newSchemaDataForm[name] = getDefaultValue(property);
- const originType = normaliseJavascriptType(typeof tabStorage.formData[name]);
+ const originType = normaliseJavascriptType(typeof tabStorage.formData[name]);
if (tabStorage.formData[name] !== undefined && originType === property.type) {
newSchemaDataForm[name] = tabStorage.formData[name];
@@ -145,4 +161,21 @@ watch(() => tabStorage.currentToolName, () => {
border-radius: .5em;
margin-bottom: 15px;
}
+
+.tool-executor-container {
+
+}
+
+.tool-executor-container .el-switch .el-switch__action {
+ background-color: var(--main-color);
+}
+
+.tool-executor-container .el-switch.is-checked .el-switch__action {
+ background-color: var(--sidebar);
+}
+
+.tool-executor-container .el-switch__core {
+ border: 1px solid var(--main-color) !important;
+}
+
\ No newline at end of file
diff --git a/renderer/src/components/main-panel/tool/tools.ts b/renderer/src/components/main-panel/tool/tools.ts
index 8e62fdd..fdcff66 100644
--- a/renderer/src/components/main-panel/tool/tools.ts
+++ b/renderer/src/components/main-panel/tool/tools.ts
@@ -12,7 +12,7 @@ export const toolsManager = reactive<{
export interface ToolStorage {
currentToolName: string;
lastToolCallResponse?: ToolCallResponse;
- formData: Record;
+ formData: Record;
}
const bridge = useMessageBridge();
diff --git a/renderer/src/hook/mcp.ts b/renderer/src/hook/mcp.ts
index 9e19f78..13a7b2c 100644
--- a/renderer/src/hook/mcp.ts
+++ b/renderer/src/hook/mcp.ts
@@ -1,14 +1,14 @@
-import { SchemaProperty } from "./type";
-
interface TypeAble {
type: string;
}
-export function getDefaultValue(property: TypeAble) {
+export function getDefaultValue(property: TypeAble) {
if (property.type === 'number' || property.type === 'integer') {
return 0;
} else if (property.type === 'boolean') {
return false;
+ } else if (property.type === 'object') {
+ return {};
} else {
return '';
}
@@ -19,7 +19,7 @@ export function normaliseJavascriptType(type: string) {
case 'integer':
return 'number';
case 'number':
- return 'integer';
+ return 'number';
case 'boolean':
return 'boolean';
case 'string':
diff --git a/renderer/src/hook/type.ts b/renderer/src/hook/type.ts
index d0af559..b64d3fe 100644
--- a/renderer/src/hook/type.ts
+++ b/renderer/src/hook/type.ts
@@ -2,6 +2,7 @@
export interface SchemaProperty {
title: string;
type: string;
+ description?: string;
}
export interface InputSchema {
diff --git a/renderer/src/i18n/ar.json b/renderer/src/i18n/ar.json
index bf13512..85d6e35 100644
--- a/renderer/src/i18n/ar.json
+++ b/renderer/src/i18n/ar.json
@@ -144,5 +144,6 @@
"single-dialog": "محادثة من جولة واحدة",
"multi-dialog": "محادثة متعددة الجولات",
"press-and-run": "اكتب سؤالاً لبدء الاختبار",
- "connect-sigature": "توقيع الاتصال"
+ "connect-sigature": "توقيع الاتصال",
+ "finish-refresh": "تم التحديث"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/de.json b/renderer/src/i18n/de.json
index f279f5b..4f8ef60 100644
--- a/renderer/src/i18n/de.json
+++ b/renderer/src/i18n/de.json
@@ -144,5 +144,6 @@
"single-dialog": "Einzelrunden-Dialog",
"multi-dialog": "Mehrrundengespräch",
"press-and-run": "Geben Sie eine Frage ein, um den Test zu starten",
- "connect-sigature": "Verbindungssignatur"
+ "connect-sigature": "Verbindungssignatur",
+ "finish-refresh": "Aktualisierung abgeschlossen"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/en.json b/renderer/src/i18n/en.json
index e1db33b..be37a10 100644
--- a/renderer/src/i18n/en.json
+++ b/renderer/src/i18n/en.json
@@ -144,5 +144,6 @@
"single-dialog": "Single-round dialogue",
"multi-dialog": "Multi-turn conversation",
"press-and-run": "Type a question to start the test",
- "connect-sigature": "Connection signature"
+ "connect-sigature": "Connection signature",
+ "finish-refresh": "Refresh completed"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/fr.json b/renderer/src/i18n/fr.json
index 75005fc..84fd9b9 100644
--- a/renderer/src/i18n/fr.json
+++ b/renderer/src/i18n/fr.json
@@ -144,5 +144,6 @@
"single-dialog": "Dialogue en un tour",
"multi-dialog": "Conversation multi-tours",
"press-and-run": "Tapez une question pour commencer le test",
- "connect-sigature": "Signature de connexion"
+ "connect-sigature": "Signature de connexion",
+ "finish-refresh": "Actualisation terminée"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/ja.json b/renderer/src/i18n/ja.json
index 1309121..dae39a5 100644
--- a/renderer/src/i18n/ja.json
+++ b/renderer/src/i18n/ja.json
@@ -144,5 +144,6 @@
"single-dialog": "単一ラウンドの対話",
"multi-dialog": "マルチターン会話",
"press-and-run": "テストを開始するには質問を入力してください",
- "connect-sigature": "接続署名"
+ "connect-sigature": "接続署名",
+ "finish-refresh": "更新が完了しました"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/ko.json b/renderer/src/i18n/ko.json
index b755e59..dbb3937 100644
--- a/renderer/src/i18n/ko.json
+++ b/renderer/src/i18n/ko.json
@@ -144,5 +144,6 @@
"single-dialog": "단일 라운드 대화",
"multi-dialog": "다중 턴 대화",
"press-and-run": "테스트를 시작하려면 질문을 입력하세요",
- "connect-sigature": "연결 서명"
+ "connect-sigature": "연결 서명",
+ "finish-refresh": "새로 고침 완료"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/ru.json b/renderer/src/i18n/ru.json
index 5e8d9dd..70edc40 100644
--- a/renderer/src/i18n/ru.json
+++ b/renderer/src/i18n/ru.json
@@ -144,5 +144,6 @@
"single-dialog": "Однораундовый диалог",
"multi-dialog": "Многораундовый разговор",
"press-and-run": "Введите вопрос, чтобы начать тест",
- "connect-sigature": "Подпись соединения"
+ "connect-sigature": "Подпись соединения",
+ "finish-refresh": "Обновление завершено"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/zh-cn.json b/renderer/src/i18n/zh-cn.json
index e11f387..c54e781 100644
--- a/renderer/src/i18n/zh-cn.json
+++ b/renderer/src/i18n/zh-cn.json
@@ -144,5 +144,6 @@
"single-dialog": "单轮对话",
"multi-dialog": "多轮对话",
"press-and-run": "键入问题以开始测试",
- "connect-sigature": "连接签名"
+ "connect-sigature": "连接签名",
+ "finish-refresh": "完成刷新"
}
\ No newline at end of file
diff --git a/renderer/src/i18n/zh-tw.json b/renderer/src/i18n/zh-tw.json
index 223e2ed..d594731 100644
--- a/renderer/src/i18n/zh-tw.json
+++ b/renderer/src/i18n/zh-tw.json
@@ -144,5 +144,6 @@
"single-dialog": "單輪對話",
"multi-dialog": "多輪對話",
"press-and-run": "輸入問題以開始測試",
- "connect-sigature": "連接簽名"
+ "connect-sigature": "連接簽名",
+ "finish-refresh": "刷新完成"
}
\ No newline at end of file
diff --git a/renderer/src/views/connect/connection-log.vue b/renderer/src/views/connect/connection-log.vue
index a49bbd0..0dceaf3 100644
--- a/renderer/src/views/connect/connection-log.vue
+++ b/renderer/src/views/connect/connection-log.vue
@@ -1,7 +1,7 @@
{{ t('log') }}
-
+
{{ log.message }}
@@ -24,7 +24,7 @@ const { t } = useI18n();