优化渲染结构
This commit is contained in:
parent
4c0566b470
commit
68f45fedf7
@ -8,6 +8,9 @@
|
|||||||
- 修复 bug:流式传输进行 function calling 时,多工具的索引串流导致的 JSON Schema 反序列化失败
|
- 修复 bug:流式传输进行 function calling 时,多工具的索引串流导致的 JSON Schema 反序列化失败
|
||||||
- 修复 bug:大模型返回大量重复错误信息
|
- 修复 bug:大模型返回大量重复错误信息
|
||||||
- 新特性:支持一次对话同时调用多个工具
|
- 新特性:支持一次对话同时调用多个工具
|
||||||
|
- UI:优化代码高亮的滚动条
|
||||||
|
- 新特性:resources/list 协议的内容点击就会直接渲染,无需二次发送
|
||||||
|
- 新特性:resources prompts tools 的结果的 json 模式支持高亮
|
||||||
|
|
||||||
## [main] 0.0.7
|
## [main] 0.0.7
|
||||||
- 优化页面布局,使得调试窗口可以显示更多内容
|
- 优化页面布局,使得调试窗口可以显示更多内容
|
||||||
|
22
renderer/src/components/json-render/index.vue
Normal file
22
renderer/src/components/json-render/index.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<el-scrollbar width="100%">
|
||||||
|
<div v-html="renderJson(json)">
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, defineProps, PropType } from 'vue';
|
||||||
|
import { renderJson } from '../main-panel/chat/markdown/markdown';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
json: {
|
||||||
|
type: Object as PropType<string | object | undefined>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<el-dialog v-model="showChooseResource" :title="t('resources')" width="400px">
|
<el-dialog v-model="showChooseResource" :title="t('resources')" width="400px">
|
||||||
<div class="resource-template-container-scrollbar" v-if="!selectResource">
|
<div class="resource-template-container-scrollbar" v-if="!selectResource">
|
||||||
<ResourceList :tab-id="-1" @resource-selected="resource => selectResource = resource" />
|
<ResourceList :tab-id="-1" @resource-selected="resource => handleResourceSelected(resource)" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<ResourceReader :tab-id="-1" :current-resource-name="selectResource!.name"
|
<ResourceReader :tab-id="-1" :current-resource-name="selectResource!.name"
|
||||||
@ -25,13 +25,14 @@
|
|||||||
import { createApp, inject, ref } from 'vue';
|
import { createApp, inject, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { ChatStorage, EditorContext } from '../chat';
|
import { ChatStorage, EditorContext } from '../chat';
|
||||||
import { ResourcesReadResponse, ResourceTemplate } from '@/hook/type';
|
import { Resources, ResourcesReadResponse, ResourceTemplate } from '@/hook/type';
|
||||||
|
|
||||||
import ResourceList from '@/components/main-panel/resource/resource-list.vue';
|
import ResourceList from '@/components/main-panel/resource/resource-list.vue';
|
||||||
import ResourceReader from '@/components/main-panel/resource/resouce-reader.vue';
|
import ResourceReader from '@/components/main-panel/resource/resouce-reader.vue';
|
||||||
import { ElMessage, ElTooltip, ElProgress, ElPopover } from 'element-plus';
|
import { ElMessage, ElTooltip, ElProgress, ElPopover } from 'element-plus';
|
||||||
|
|
||||||
import ResourceChatItem from '../resource-chat-item.vue';
|
import ResourceChatItem from '../resource-chat-item.vue';
|
||||||
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@ -57,6 +58,15 @@ function saveCursorPosition() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleResourceSelected(resource: Resources) {
|
||||||
|
selectResource.value = undefined;
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
const { code, msg } = await bridge.commandRequest('resources/read', { resourceUri: resource.uri });
|
||||||
|
if (msg) {
|
||||||
|
await whenGetResourceResponse(msg as ResourcesReadResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function whenGetResourceResponse(msg: ResourcesReadResponse) {
|
async function whenGetResourceResponse(msg: ResourcesReadResponse) {
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
return;
|
return;
|
||||||
|
@ -10,33 +10,49 @@ function escapeHtml(unsafe: string) {
|
|||||||
.replace(/'/g, "'");
|
.replace(/'/g, "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出默认的 highlight 函数
|
interface HighlightOption {
|
||||||
export default function highlight(str: string, lang: string) {
|
needTools?: boolean
|
||||||
// 创建代码块容器
|
|
||||||
let container = `<div class="openmcp-code-block">`;
|
|
||||||
|
|
||||||
// 添加复制按钮(右上角)
|
|
||||||
container += `
|
|
||||||
<div class="code-header">
|
|
||||||
<div class="code-language">${lang || ''}</div>
|
|
||||||
<button class="copy-button" onclick="copyCode(this)">复制</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
if (lang && Prism.languages[lang]) {
|
|
||||||
// 使用 Prism 高亮代码
|
|
||||||
const highlightedCode = Prism.highlight(str, Prism.languages[lang], lang);
|
|
||||||
// 添加代码区域
|
|
||||||
container += `<pre class="language-${lang}"><code class="language-${lang}">${highlightedCode}</code></pre>`;
|
|
||||||
} else {
|
|
||||||
// 普通代码块
|
|
||||||
container += `<pre class="language-none"><code>${escapeHtml(str)}</code></pre>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
container += `</div>`;
|
|
||||||
return container;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出默认的 highlight 函数
|
||||||
|
export default function highlight(option: HighlightOption = {}) {
|
||||||
|
const {
|
||||||
|
needTools = true
|
||||||
|
} = option;
|
||||||
|
|
||||||
|
return (str: string, lang: string) => {
|
||||||
|
|
||||||
|
if (needTools) {
|
||||||
|
// 创建代码块容器
|
||||||
|
let container = `<div class="openmcp-code-block">`;
|
||||||
|
|
||||||
|
// 添加复制按钮(右上角)
|
||||||
|
container += `
|
||||||
|
<div class="code-header">
|
||||||
|
<div class="code-language">${lang || ''}</div>
|
||||||
|
<button class="copy-button" onclick="copyCode(this)">复制</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (lang && Prism.languages[lang]) {
|
||||||
|
// 使用 Prism 高亮代码
|
||||||
|
const highlightedCode = Prism.highlight(str, Prism.languages[lang], lang);
|
||||||
|
// 添加代码区域
|
||||||
|
container += `<pre class="language-${lang}"><code class="language-${lang}">${highlightedCode}</code></pre>`;
|
||||||
|
} else {
|
||||||
|
// 普通代码块
|
||||||
|
container += `<pre class="language-none"><code>${escapeHtml(str)}</code></pre>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
container += `</div>`;
|
||||||
|
return container;
|
||||||
|
} else {
|
||||||
|
return Prism.highlight(str, Prism.languages[lang], lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 全局复制函数
|
// 全局复制函数
|
||||||
(window as any).copyCode = function (button: HTMLElement) {
|
(window as any).copyCode = function (button: HTMLElement) {
|
||||||
const codeBlock = button.closest('.openmcp-code-block');
|
const codeBlock = button.closest('.openmcp-code-block');
|
||||||
|
@ -3,7 +3,7 @@ import MarkdownKatex from './markdown-katex';
|
|||||||
import MarkdownHighlight from './markdown-highlight';
|
import MarkdownHighlight from './markdown-highlight';
|
||||||
|
|
||||||
const md = new MarkdownIt({
|
const md = new MarkdownIt({
|
||||||
highlight: MarkdownHighlight,
|
highlight: MarkdownHighlight({ needTools: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
md.use(MarkdownKatex, {
|
md.use(MarkdownKatex, {
|
||||||
@ -18,6 +18,35 @@ export const markdownToHtml = (markdown: string) => {
|
|||||||
return md.render(markdown);
|
return md.render(markdown);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pureHighLightMd = new MarkdownIt({
|
||||||
|
highlight: MarkdownHighlight({ needTools: false }),
|
||||||
|
});
|
||||||
|
|
||||||
export const copyToClipboard = (text: string) => {
|
export const copyToClipboard = (text: string) => {
|
||||||
return navigator.clipboard.writeText(text);
|
return navigator.clipboard.writeText(text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tryParseJson = (text: string) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(text);
|
||||||
|
} catch (error) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const prettifyObj = (obj: object | string) => {
|
||||||
|
const rawObj = typeof obj === 'string' ? tryParseJson(obj) : obj;
|
||||||
|
return JSON.stringify(rawObj, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const renderJson = (obj: object | string | undefined) => {
|
||||||
|
if (!obj) {
|
||||||
|
return '<span>Invalid JSON</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonString = prettifyObj(obj);
|
||||||
|
const md = "```json\n" + jsonString + "\n```";
|
||||||
|
const html = pureHighLightMd.render(md);
|
||||||
|
return html;
|
||||||
|
}
|
@ -36,7 +36,6 @@
|
|||||||
max-height: inherit;
|
max-height: inherit;
|
||||||
height: inherit;
|
height: inherit;
|
||||||
display: block;
|
display: block;
|
||||||
overflow: auto;
|
|
||||||
background-color: unset !important;
|
background-color: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +250,6 @@
|
|||||||
max-height: inherit;
|
max-height: inherit;
|
||||||
height: inherit;
|
height: inherit;
|
||||||
display: block;
|
display: block;
|
||||||
overflow: auto;
|
|
||||||
background-color: unset !important;
|
background-color: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-scrollbar width="100%">
|
<el-scrollbar width="100%" max-height="300px">
|
||||||
<div v-if="props.item.type === 'text'" class="tool-text">
|
<div v-if="props.item.type === 'text'" class="tool-text">
|
||||||
{{ props.item.text }}
|
{{ props.item.text }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,8 +7,11 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-text tool_calls" :class="[currentMessageLevel]">
|
<div class="message-text tool_calls" :class="[currentMessageLevel]">
|
||||||
|
|
||||||
|
<!-- 工具的消息 -->
|
||||||
<div v-if="props.message.content" v-html="markdownToHtml(props.message.content)"></div>
|
<div v-if="props.message.content" v-html="markdownToHtml(props.message.content)"></div>
|
||||||
|
|
||||||
|
<!-- 工具的调用 -->
|
||||||
<el-collapse v-model="activeNames" v-if="props.message.tool_calls">
|
<el-collapse v-model="activeNames" v-if="props.message.tool_calls">
|
||||||
<el-collapse-item name="tool">
|
<el-collapse-item name="tool">
|
||||||
<template #title>
|
<template #title>
|
||||||
@ -43,12 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tool-arguments">
|
<div class="tool-arguments">
|
||||||
<el-scrollbar width="100%">
|
<json-render :json="props.message.tool_calls[toolIndex].function.arguments"/>
|
||||||
<div class="inner">
|
|
||||||
<div v-html="jsonResultToHtml(props.message.tool_calls[toolIndex].function.arguments)">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-scrollbar>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 工具调用结果 -->
|
<!-- 工具调用结果 -->
|
||||||
@ -79,9 +77,7 @@
|
|||||||
<div class="tool-result" v-if="isValid(toolResult)">
|
<div class="tool-result" v-if="isValid(toolResult)">
|
||||||
<!-- 展示 JSON -->
|
<!-- 展示 JSON -->
|
||||||
<div v-if="props.message.showJson!.value" class="tool-result-content">
|
<div v-if="props.message.showJson!.value" class="tool-result-content">
|
||||||
<div class="inner">
|
<json-render :json="props.message.toolResults[toolIndex]"/>
|
||||||
<div v-html="toHtml(props.message.toolResults[toolIndex])"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 展示富文本 -->
|
<!-- 展示富文本 -->
|
||||||
@ -120,6 +116,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -134,9 +131,10 @@ import { IToolRenderMessage, MessageState } from '../chat-box/chat';
|
|||||||
import { ToolCallContent } from '@/hook/type';
|
import { ToolCallContent } from '@/hook/type';
|
||||||
|
|
||||||
import ToolcallResultItem from './toolcall-result-item.vue';
|
import ToolcallResultItem from './toolcall-result-item.vue';
|
||||||
|
import JsonRender from '@/components/json-render/index.vue';
|
||||||
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
message: {
|
message: {
|
||||||
type: Object as PropType<IToolRenderMessage>,
|
type: Object as PropType<IToolRenderMessage>,
|
||||||
@ -149,7 +147,6 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const hasOcr = computed(() => {
|
const hasOcr = computed(() => {
|
||||||
|
|
||||||
if (props.message.role === 'assistant/tool_calls') {
|
if (props.message.role === 'assistant/tool_calls') {
|
||||||
for (const toolResult of props.message.toolResults) {
|
for (const toolResult of props.message.toolResults) {
|
||||||
for (const item of toolResult) {
|
for (const item of toolResult) {
|
||||||
@ -198,26 +195,6 @@ function collposePanel() {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 将工具调用结果转换成 html
|
|
||||||
* @param toolResult
|
|
||||||
*/
|
|
||||||
const toHtml = (toolResult: ToolCallContent[]) => {
|
|
||||||
const formattedJson = JSON.stringify(toolResult, null, 2);
|
|
||||||
const html = markdownToHtml('```json\n' + formattedJson + '\n```');
|
|
||||||
return html;
|
|
||||||
};
|
|
||||||
|
|
||||||
const jsonResultToHtml = (jsonResult: string) => {
|
|
||||||
try {
|
|
||||||
const formattedJson = JSON.stringify(JSON.parse(jsonResult), null, 2);
|
|
||||||
const html = markdownToHtml('```json\n' + formattedJson + '\n```');
|
|
||||||
return html;
|
|
||||||
} catch (error) {
|
|
||||||
const html = markdownToHtml('```json\n' + jsonResult + '\n```');
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function gotoIssue() {
|
function gotoIssue() {
|
||||||
window.open('https://github.com/LSTM-Kirigaya/openmcp-client/issues', '_blank');
|
window.open('https://github.com/LSTM-Kirigaya/openmcp-client/issues', '_blank');
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ formattedJson }}
|
<json-render :json="tabStorage.lastPromptGetResponse"/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@ -36,6 +36,7 @@ import { defineComponent, defineProps, computed, ref } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { tabs } from '../panel';
|
import { tabs } from '../panel';
|
||||||
import { PromptStorage } from './prompts';
|
import { PromptStorage } from './prompts';
|
||||||
|
import JsonRender from '@/components/json-render/index.vue';
|
||||||
|
|
||||||
defineComponent({ name: 'prompt-logger' });
|
defineComponent({ name: 'prompt-logger' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -52,13 +53,6 @@ const tabStorage = tab.storage as PromptStorage;
|
|||||||
|
|
||||||
const showRawJson = ref(false);
|
const showRawJson = ref(false);
|
||||||
|
|
||||||
const formattedJson = computed(() => {
|
|
||||||
try {
|
|
||||||
return JSON.stringify(tabStorage.lastPromptGetResponse, null, 2);
|
|
||||||
} catch {
|
|
||||||
return 'Invalid JSON';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<el-switch v-else-if="param.type === 'boolean'" v-model="tabStorage.formData[param.name]" />
|
<el-switch v-else-if="param.type === 'boolean'" v-model="tabStorage.formData[param.name]" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item v-if="tabStorage.currentType === 'template'">
|
||||||
<el-button type="primary" :loading="loading" @click="handleSubmit">
|
<el-button type="primary" :loading="loading" @click="handleSubmit">
|
||||||
{{ t('read-resource') }}
|
{{ t('read-resource') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -24,6 +24,11 @@
|
|||||||
{{ t('reset') }}
|
{{ t('reset') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item v-else>
|
||||||
|
<el-button @click="handleSubmit">
|
||||||
|
{{ t("refresh") }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -142,9 +147,7 @@ function getUri() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const currentResourceName = props.tabId >= 0 ? tabStorage.currentResourceName : props.currentResourceName;
|
const currentResourceName = props.tabId >= 0 ? tabStorage.currentResourceName : props.currentResourceName;
|
||||||
|
|
||||||
const targetResource = resourcesManager.resources.find(resources => resources.name === currentResourceName);
|
const targetResource = resourcesManager.resources.find(resources => resources.name === currentResourceName);
|
||||||
|
|
||||||
return targetResource?.uri;
|
return targetResource?.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,9 +157,7 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
const { code, msg } = await bridge.commandRequest('resources/read', { resourceUri: uri });
|
const { code, msg } = await bridge.commandRequest('resources/read', { resourceUri: uri });
|
||||||
|
|
||||||
tabStorage.lastResourceReadResponse = msg;
|
tabStorage.lastResourceReadResponse = msg;
|
||||||
|
|
||||||
emits('resource-get-response', msg);
|
emits('resource-get-response', msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +75,18 @@ function reloadResources(option: { first: boolean }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClick(resource: Resources) {
|
async function handleClick(resource: Resources) {
|
||||||
tabStorage.currentType = 'resource';
|
tabStorage.currentType = 'resource';
|
||||||
tabStorage.currentResourceName = resource.name;
|
tabStorage.currentResourceName = resource.name;
|
||||||
tabStorage.lastResourceReadResponse = undefined;
|
tabStorage.lastResourceReadResponse = undefined;
|
||||||
|
|
||||||
emits('resource-selected', resource);
|
emits('resource-selected', resource);
|
||||||
|
|
||||||
|
// 更新资源
|
||||||
|
if (props.tabId >= 0) {
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
const { code, msg } = await bridge.commandRequest('resources/read', { resourceUri: resource.uri });
|
||||||
|
tabStorage.lastResourceReadResponse = msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let commandCancel: (() => void);
|
let commandCancel: (() => void);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ formattedJson }}
|
<json-render :json="tabStorage.lastResourceReadResponse"/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@ -50,6 +50,7 @@ import { useI18n } from 'vue-i18n';
|
|||||||
import { tabs } from '../panel';
|
import { tabs } from '../panel';
|
||||||
import { ResourceStorage } from './resources';
|
import { ResourceStorage } from './resources';
|
||||||
import { getImageBlobUrlByBase64 } from '@/hook/util';
|
import { getImageBlobUrlByBase64 } from '@/hook/util';
|
||||||
|
import JsonRender from '@/components/json-render/index.vue';
|
||||||
|
|
||||||
defineComponent({ name: 'resource-logger' });
|
defineComponent({ name: 'resource-logger' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<!-- 展示 json -->
|
<!-- 展示 json -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ formattedJson }}
|
<json-render :json="tabStorage.lastToolCallResponse"/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ import { defineComponent, defineProps, computed, ref } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { tabs } from '../panel';
|
import { tabs } from '../panel';
|
||||||
import { ToolStorage } from './tools';
|
import { ToolStorage } from './tools';
|
||||||
import { useMessageBridge } from '@/api/message-bridge';
|
import JsonRender from '@/components/json-render/index.vue';
|
||||||
|
|
||||||
defineComponent({ name: 'tool-logger' });
|
defineComponent({ name: 'tool-logger' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -57,17 +57,6 @@ const tabStorage = tab.storage as ToolStorage;
|
|||||||
|
|
||||||
const showRawJson = ref(false);
|
const showRawJson = ref(false);
|
||||||
|
|
||||||
const formattedJson = computed(() => {
|
|
||||||
try {
|
|
||||||
if (typeof tabStorage.lastToolCallResponse === 'string') {
|
|
||||||
return tabStorage.lastToolCallResponse;
|
|
||||||
}
|
|
||||||
return JSON.stringify(tabStorage.lastToolCallResponse, null, 2);
|
|
||||||
} catch {
|
|
||||||
return 'Invalid JSON';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -31,6 +31,7 @@ export interface McpOptions {
|
|||||||
// SSE 特定选项
|
// SSE 特定选项
|
||||||
url?: string;
|
url?: string;
|
||||||
cwd?: string;
|
cwd?: string;
|
||||||
|
env?: Record<string, string>;
|
||||||
// 通用客户端选项
|
// 通用客户端选项
|
||||||
clientName?: string;
|
clientName?: string;
|
||||||
clientVersion?: string;
|
clientVersion?: string;
|
||||||
|
@ -42,7 +42,8 @@ export class McpClient {
|
|||||||
command: this.options.command || '',
|
command: this.options.command || '',
|
||||||
args: this.options.args || [],
|
args: this.options.args || [],
|
||||||
cwd: this.options.cwd || process.cwd(),
|
cwd: this.options.cwd || process.cwd(),
|
||||||
stderr: 'pipe'
|
stderr: 'pipe',
|
||||||
|
env: this.options.env,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -119,8 +120,8 @@ export class McpClient {
|
|||||||
|
|
||||||
// 调用工具
|
// 调用工具
|
||||||
public async callTool(options: { name: string; arguments: Record<string, any>, callToolOption?: any }) {
|
public async callTool(options: { name: string; arguments: Record<string, any>, callToolOption?: any }) {
|
||||||
|
|
||||||
const { callToolOption, ...methodArgs } = options;
|
const { callToolOption, ...methodArgs } = options;
|
||||||
|
console.log('callToolOption', callToolOption);
|
||||||
return await this.client.callTool(methodArgs, undefined, callToolOption);
|
return await this.client.callTool(methodArgs, undefined, callToolOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user