修复只有空页面时,标签页恢复报错的 bug

This commit is contained in:
锦恢 2025-04-21 19:43:29 +08:00
parent 36744f2a71
commit 8105bfde85
14 changed files with 181 additions and 39 deletions

View File

@ -41,7 +41,8 @@
| `all` | 完成最基本的各类基础设施 | `完整版本` | 100% | `Done` | | `all` | 完成最基本的各类基础设施 | `完整版本` | 100% | `Done` |
| `render` | chat 模式下支持进行成本分析 | `迭代版本` | 100% | `Done` | | `render` | chat 模式下支持进行成本分析 | `迭代版本` | 100% | `Done` |
| `ext` | 支持基本的 MCP 项目管理 | `MVP` | 0% | `P0` | | `ext` | 支持基本的 MCP 项目管理 | `MVP` | 0% | `P0` |
| `service` | 支持自定义大模型接入 | `MVP` | 80% | `P0` | | `service` | 支持自定义支持 openai 接口协议的大模型接入 | `完整版本` | 100% | `Done` |
| `service` | 支持自定义接口协议的大模型接入 | `MVP` | 0% | `P1` |
| `all` | 支持同时调试多个 MCP Server | `MVP` | 0% | `P1` | | `all` | 支持同时调试多个 MCP Server | `MVP` | 0% | `P1` |
| `all` | 支持通过大模型进行在线验证 | `迭代版本` | 100% | `Done` | | `all` | 支持通过大模型进行在线验证 | `迭代版本` | 100% | `Done` |
| `all` | 支持 completion/complete 协议字段 | `MVP` | 0% | `P1` | | `all` | 支持 completion/complete 协议字段 | `MVP` | 0% | `P1` |

View File

@ -59,11 +59,12 @@ class MessageBridge {
}; };
this.ws.onmessage = (event) => { this.ws.onmessage = (event) => {
try { try {
const message = JSON.parse(event.data) as VSCodeMessage; const message = JSON.parse(event.data) as VSCodeMessage;
this.dispatchMessage(message); this.dispatchMessage(message);
} catch (err) { } catch (err) {
console.error('Message parse error:', err); console.error('Message parse error:', err);
console.log(event);
} }
}; };

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="chat-settings"> <div class="chat-settings">
<el-tooltip content="选择模型" placement="top"> <el-tooltip :content="t('choose-model')" placement="top">
<div class="setting-button" @click="showModelDialog = true"> <div class="setting-button" @click="showModelDialog = true">
<span class="iconfont icon-model"> <span class="iconfont icon-model">
{{ currentServerName }}/{{ currentModelName }} {{ currentServerName }}/{{ currentModelName }}
@ -8,35 +8,35 @@
</div> </div>
</el-tooltip> </el-tooltip>
<el-tooltip content="系统提示词" placement="top"> <el-tooltip :content="t('system-prompt')" placement="top">
<div class="setting-button" :class="{ 'active': hasSystemPrompt }" size="small" <div class="setting-button" :class="{ 'active': hasSystemPrompt }" size="small"
@click="showSystemPromptDialog = true"> @click="showSystemPromptDialog = true">
<span class="iconfont icon-robot"></span> <span class="iconfont icon-robot"></span>
</div> </div>
</el-tooltip> </el-tooltip>
<el-tooltip content="工具使用" placement="top"> <el-tooltip :content="t('tool-use')" placement="top">
<div class="setting-button" :class="{ 'active': toolActive }" size="small" <div class="setting-button" :class="{ 'active': toolActive }" size="small"
@click="toggleTools"> @click="toggleTools">
<span class="iconfont icon-tool"></span> <span class="iconfont icon-tool"></span>
</div> </div>
</el-tooltip> </el-tooltip>
<el-tooltip content="网络搜索" placement="top"> <el-tooltip :content="t('websearch')" placement="top">
<div class="setting-button" :class="{ 'active': tabStorage.settings.enableWebSearch }" size="small" <div class="setting-button" :class="{ 'active': tabStorage.settings.enableWebSearch }" size="small"
@click="toggleWebSearch"> @click="toggleWebSearch">
<span class="iconfont icon-web"></span> <span class="iconfont icon-web"></span>
</div> </div>
</el-tooltip> </el-tooltip>
<el-tooltip content="温度参数" placement="top"> <el-tooltip :content="t('temperature-parameter')" placement="top">
<div class="setting-button" @click="showTemperatureSlider = true"> <div class="setting-button" @click="showTemperatureSlider = true">
<span class="iconfont icon-temperature"></span> <span class="iconfont icon-temperature"></span>
<span class="value-badge">{{ tabStorage.settings.temperature.toFixed(1) }}</span> <span class="value-badge">{{ tabStorage.settings.temperature.toFixed(1) }}</span>
</div> </div>
</el-tooltip> </el-tooltip>
<el-tooltip content="上下文长度" placement="top"> <el-tooltip :content="t('context-length')" placement="top">
<div class="setting-button" @click="showContextLengthDialog = true"> <div class="setting-button" @click="showContextLengthDialog = true">
<span class="iconfont icon-length"></span> <span class="iconfont icon-length"></span>
<span class="value-badge">{{ tabStorage.settings.contextLength }}</span> <span class="value-badge">{{ tabStorage.settings.contextLength }}</span>
@ -44,55 +44,56 @@
</el-tooltip> </el-tooltip>
<!-- 模型选择对话框 --> <!-- 模型选择对话框 -->
<el-dialog v-model="showModelDialog" title="选择模型" width="400px"> <el-dialog v-model="showModelDialog" :title="t('choose-model')" width="400px">
<el-radio-group v-model="selectedModelIndex" @change="onRadioGroupChange"> <el-radio-group v-model="selectedModelIndex" @change="onRadioGroupChange">
<el-radio v-for="(model, index) in availableModels" :key="index" :label="index"> <el-radio v-for="(model, index) in availableModels" :key="index" :label="index">
{{ model }} {{ model }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
<template #footer> <template #footer>
<el-button @click="showModelDialog = false">取消</el-button> <el-button @click="showModelDialog = false">{{ t("cancel") }}</el-button>
<el-button type="primary" @click="confirmModelChange">确认</el-button> <el-button type="primary" @click="confirmModelChange">{{ t("confirm") }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<!-- System Prompt对话框 --> <!-- System Prompt对话框 -->
<el-dialog v-model="showSystemPromptDialog" title="系统提示词" width="600px"> <el-dialog v-model="showSystemPromptDialog" :title="t('system-prompt')" width="600px">
<el-input v-model="tabStorage.settings.systemPrompt" type="textarea" :rows="8" <el-input v-model="tabStorage.settings.systemPrompt" type="textarea" :rows="8"
placeholder="输入系统提示词(例如:你是一个专业的前端开发助手,用中文回答)" clearable /> :placeholder="t('system-prompt.placeholder')"
clearable
/>
<template #footer> <template #footer>
<el-button @click="showSystemPromptDialog = false">关闭</el-button> <el-button @click="showSystemPromptDialog = false">{{ t("cancel") }}</el-button>
<el-button type="primary" @click="showSystemPromptDialog = false">保存</el-button> <el-button type="primary" @click="showSystemPromptDialog = false">{{ t("save") }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<!-- 温度参数滑块 --> <!-- 温度参数滑块 -->
<el-dialog v-model="showTemperatureSlider" title="设置温度参数" width="400px"> <el-dialog v-model="showTemperatureSlider" :title="t('temperature-parameter')" width="400px">
<div class="slider-container"> <div class="slider-container">
<el-slider v-model="tabStorage.settings.temperature" :min="0" :max="2" :step="0.1" /> <el-slider v-model="tabStorage.settings.temperature" :min="0" :max="2" :step="0.1" />
<div class="slider-tips"> <div class="slider-tips">
<span>精确(0)</span> <span> {{ t('precise') }}(0)</span>
<span>平衡(1)</span> <span>{{ t('moderate') }}(1)</span>
<span>创意(2)</span> <span>{{ t('creative') }}(2)</span>
</div> </div>
</div> </div>
<template #footer> <template #footer>
<el-button @click="showTemperatureSlider = false">关闭</el-button> <el-button @click="showTemperatureSlider = false">{{ t("cancel") }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<!-- 上下文长度设置 - 改为滑块形式 --> <!-- 上下文长度设置 - 改为滑块形式 -->
<el-dialog v-model="showContextLengthDialog" title="设置上下文长度" width="400px"> <el-dialog v-model="showContextLengthDialog" :title="t('context-length') + ' ' + tabStorage.settings.contextLength" width="400px">
<div class="slider-container"> <div class="slider-container">
<el-slider v-model="tabStorage.settings.contextLength" :min="0" :max="99" :step="1" /> <el-slider v-model="tabStorage.settings.contextLength" :min="1" :max="99" :step="1" />
<div class="slider-tips"> <div class="slider-tips">
<span>0: 无上下文</span> <span> 1: {{ t('single-dialog') }}</span>
<span>10: 默认</span> <span> >1: {{ t('multi-dialog') }}</span>
<span>99: 最大</span>
</div> </div>
</div> </div>
<template #footer> <template #footer>
<el-button @click="showContextLengthDialog = false">关闭</el-button> <el-button @click="showContextLengthDialog = false">{{ t("cancel") }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
@ -116,7 +117,7 @@
<template #footer> <template #footer>
<el-button type="primary" @click="enableAllTools">激活所有工具</el-button> <el-button type="primary" @click="enableAllTools">激活所有工具</el-button>
<el-button type="danger" @click="disableAllTools">禁用所有工具</el-button> <el-button type="danger" @click="disableAllTools">禁用所有工具</el-button>
<el-button type="primary" @click="showToolsDialog = false">关闭</el-button> <el-button type="primary" @click="showToolsDialog = false">{{ t("cancel") }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
@ -132,6 +133,10 @@ import { CasualRestAPI, ToolItem, ToolsListResponse } from '@/hook/type';
import { markdownToHtml } from './markdown'; import { markdownToHtml } from './markdown';
import { saveSetting } from '@/hook/setting'; import { saveSetting } from '@/hook/setting';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({ const props = defineProps({
tabId: { tabId: {
type: Number, type: Number,

View File

@ -29,7 +29,7 @@ export function loadPanels() {
console.log(data.msg); console.log(data.msg);
} else { } else {
const persistTab = data.msg as SaveTab; const persistTab = data.msg as SaveTab;
pinkLog('tabs 加载成功'); pinkLog('tabs 加载成功');
@ -44,12 +44,15 @@ export function loadPanels() {
tabs.content = []; tabs.content = [];
for (const tab of persistTab.tabs || []) { for (const tab of persistTab.tabs || []) {
const component = tab.componentIndex >= 0? debugModes[tab.componentIndex] : undefined;
tabs.content.push({ tabs.content.push({
name: tab.name, name: tab.name,
icon: tab.icon, icon: tab.icon,
type: tab.type, type: tab.type,
componentIndex: tab.componentIndex, componentIndex: tab.componentIndex,
component: markRaw(debugModes[tab.componentIndex]), component: component,
storage: tab.storage storage: tab.storage
}); });
} }

View File

@ -130,5 +130,17 @@
"edit": "تعديل", "edit": "تعديل",
"delete": "حذف", "delete": "حذف",
"test": "اختبار", "test": "اختبار",
"add-new-server": "إضافة خدمة" "add-new-server": "إضافة خدمة",
"choose-model": "اختر النموذج",
"system-prompt": "كلمات توجيه النظام",
"tool-use": "استخدام الأداة",
"websearch": "بحث على الإنترنت",
"temperature-parameter": "معامل درجة الحرارة",
"context-length": "طول السياق",
"system-prompt.placeholder": "أدخل كلمة تلميح النظام (مثال: أنت مساعد محترف في تطوير الواجهات الأمامية، أجب باللغة العربية)",
"precise": "دقيق",
"moderate": "توازن",
"creative": "إبداع",
"single-dialog": "محادثة من جولة واحدة",
"multi-dialog": "محادثة متعددة الجولات"
} }

View File

@ -130,5 +130,17 @@
"edit": "Bearbeiten", "edit": "Bearbeiten",
"delete": "Löschen", "delete": "Löschen",
"test": "Test", "test": "Test",
"add-new-server": "Dienst hinzufügen" "add-new-server": "Dienst hinzufügen",
"choose-model": "Modell auswählen",
"system-prompt": "Systemaufforderung",
"tool-use": "Werkzeugnutzung",
"websearch": "Internetsuche",
"temperature-parameter": "Temperaturparameter",
"context-length": "Kontextlänge",
"system-prompt.placeholder": "Geben Sie den System-Prompt ein (z. B.: Sie sind ein professioneller Frontend-Entwicklungsassistent, antworten Sie auf Deutsch)",
"precise": "Präzise",
"moderate": "Gleichgewicht",
"creative": "Kreativität",
"single-dialog": "Einzelrunden-Dialog",
"multi-dialog": "Mehrrundengespräch"
} }

View File

@ -130,5 +130,17 @@
"edit": "Edit", "edit": "Edit",
"delete": "Delete", "delete": "Delete",
"test": "Test", "test": "Test",
"add-new-server": "Add service" "add-new-server": "Add service",
"choose-model": "Select model",
"system-prompt": "System prompt",
"tool-use": "Tool usage",
"websearch": "Web search",
"temperature-parameter": "Temperature parameter",
"context-length": "Context length",
"system-prompt.placeholder": "Enter the system prompt (e.g.: You are a professional front-end development assistant, answer in English)",
"precise": "Precise",
"moderate": "Balance",
"creative": "Creativity",
"single-dialog": "Single-round dialogue",
"multi-dialog": "Multi-turn conversation"
} }

View File

@ -130,5 +130,17 @@
"edit": "Modifier", "edit": "Modifier",
"delete": "Supprimer", "delete": "Supprimer",
"test": "Test", "test": "Test",
"add-new-server": "Ajouter un service" "add-new-server": "Ajouter un service",
"choose-model": "Sélectionner le modèle",
"system-prompt": "Invite système",
"tool-use": "Utilisation d'outils",
"websearch": "Recherche sur Internet",
"temperature-parameter": "Paramètre de température",
"context-length": "Longueur du contexte",
"system-prompt.placeholder": "Entrez l'invite système (par exemple : Vous êtes un assistant professionnel de développement front-end, répondez en français)",
"precise": "Précis",
"moderate": "Équilibre",
"creative": "Créativité",
"single-dialog": "Dialogue en un tour",
"multi-dialog": "Conversation multi-tours"
} }

View File

@ -130,5 +130,17 @@
"edit": "編集", "edit": "編集",
"delete": "削除", "delete": "削除",
"test": "テスト", "test": "テスト",
"add-new-server": "サービスを追加" "add-new-server": "サービスを追加",
"choose-model": "モデルを選択",
"system-prompt": "システムプロンプト",
"tool-use": "ツールの使用",
"websearch": "ウェブ検索",
"temperature-parameter": "温度パラメータ",
"context-length": "コンテキストの長さ",
"system-prompt.placeholder": "システムプロンプトを入力してください(例:あなたはプロのフロントエンド開発アシスタントで、日本語で答えます)",
"precise": "精密",
"moderate": "バランス",
"creative": "創造性",
"single-dialog": "単一ラウンドの対話",
"multi-dialog": "マルチターン会話"
} }

View File

@ -130,5 +130,17 @@
"edit": "편집", "edit": "편집",
"delete": "삭제", "delete": "삭제",
"test": "테스트", "test": "테스트",
"add-new-server": "서비스 추가" "add-new-server": "서비스 추가",
"choose-model": "모델 선택",
"system-prompt": "시스템 프롬프트",
"tool-use": "도구 사용",
"websearch": "웹 검색",
"temperature-parameter": "온도 매개변수",
"context-length": "컨텍스트 길이",
"system-prompt.placeholder": "시스템 프롬프트를 입력하세요 (예: 당신은 전문 프론트엔드 개발 어시스턴트이며, 한국어로 답변합니다)",
"precise": "정확한",
"moderate": "균형",
"creative": "창의성",
"single-dialog": "단일 라운드 대화",
"multi-dialog": "다중 턴 대화"
} }

View File

@ -130,5 +130,17 @@
"edit": "Редактировать", "edit": "Редактировать",
"delete": "Удалить", "delete": "Удалить",
"test": "Тест", "test": "Тест",
"add-new-server": "Добавить услугу" "add-new-server": "Добавить услугу",
"choose-model": "Выбрать модель",
"system-prompt": "Системная подсказка",
"tool-use": "Использование инструмента",
"websearch": "Поиск в Интернете",
"temperature-parameter": "Температурный параметр",
"context-length": "Длина контекста",
"system-prompt.placeholder": "Введите системный запрос (например: Вы профессиональный помощник по фронтенд-разработке, отвечайте на русском)",
"precise": "Точный",
"moderate": "Баланс",
"creative": "Творчество",
"single-dialog": "Однораундовый диалог",
"multi-dialog": "Многораундовый разговор"
} }

View File

@ -130,5 +130,17 @@
"edit": "编辑", "edit": "编辑",
"delete": "删除", "delete": "删除",
"test": "测试", "test": "测试",
"add-new-server": "添加服务" "add-new-server": "添加服务",
"choose-model": "选择模型",
"system-prompt": "系统提示词",
"tool-use": "工具使用",
"websearch": "网络搜索",
"temperature-parameter": "温度参数",
"context-length": "上下文长度",
"system-prompt.placeholder": "输入系统提示词(例如:你是一个专业的前端开发助手,用中文回答)",
"precise": "精确",
"moderate": "平衡",
"creative": "创意",
"single-dialog": "单轮对话",
"multi-dialog": "多轮对话"
} }

View File

@ -130,5 +130,17 @@
"edit": "編輯", "edit": "編輯",
"delete": "刪除", "delete": "刪除",
"test": "測試", "test": "測試",
"add-new-server": "新增服務" "add-new-server": "新增服務",
"choose-model": "選擇模型",
"system-prompt": "系統提示詞",
"tool-use": "工具使用",
"websearch": "網路搜尋",
"temperature-parameter": "溫度參數",
"context-length": "上下文長度",
"system-prompt.placeholder": "輸入系統提示詞(例如:你是一個專業的前端開發助手,用中文回答)",
"precise": "精確",
"moderate": "平衡",
"creative": "創意",
"single-dialog": "單輪對話",
"multi-dialog": "多輪對話"
} }

View File

@ -1,4 +1,28 @@
{ {
"currentIndex": 0, "currentIndex": 0,
"tabs": [] "tabs": [
{
"name": "Interactive Test",
"icon": "icon-robot",
"type": "blank",
"componentIndex": 3,
"storage": {
"messages": [],
"settings": {
"modelIndex": 8,
"enableTools": [
{
"name": "image_crawler",
"description": "根据关键词从指定搜索引擎爬取图片",
"enabled": true
}
],
"enableWebSearch": false,
"temperature": 0.7,
"contextLength": 10,
"systemPrompt": ""
}
}
}
]
} }