mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 10:40:07 +08:00
feat: support preview of MCP call results (#5236)
This commit is contained in:
parent
5a44f6aca8
commit
62b6584d65
@ -562,7 +562,9 @@
|
||||
"tools": {
|
||||
"completed": "Completed",
|
||||
"invoking": "Invoking",
|
||||
"error": "Error occurred"
|
||||
"error": "Error occurred",
|
||||
"raw": "Raw",
|
||||
"preview": "Preview"
|
||||
},
|
||||
"topic.added": "New topic added",
|
||||
"upgrade.success.button": "Restart",
|
||||
|
||||
@ -561,7 +561,9 @@
|
||||
"tools": {
|
||||
"completed": "完了",
|
||||
"invoking": "呼び出し中",
|
||||
"error": "エラーが発生しました"
|
||||
"error": "エラーが発生しました",
|
||||
"raw": "生データ",
|
||||
"preview": "プレビュー"
|
||||
},
|
||||
"topic.added": "新しいトピックが追加されました",
|
||||
"upgrade.success.button": "再起動",
|
||||
|
||||
@ -562,7 +562,9 @@
|
||||
"tools": {
|
||||
"completed": "Завершено",
|
||||
"invoking": "Вызов",
|
||||
"error": "Произошла ошибка"
|
||||
"error": "Произошла ошибка",
|
||||
"raw": "Исходный",
|
||||
"preview": "Предпросмотр"
|
||||
},
|
||||
"topic.added": "Новый топик добавлен",
|
||||
"upgrade.success.button": "Перезапустить",
|
||||
|
||||
@ -562,7 +562,9 @@
|
||||
"tools": {
|
||||
"completed": "已完成",
|
||||
"invoking": "调用中",
|
||||
"error": "发生错误"
|
||||
"error": "发生错误",
|
||||
"raw": "原始",
|
||||
"preview": "预览"
|
||||
},
|
||||
"topic.added": "话题添加成功",
|
||||
"upgrade.success.button": "重启",
|
||||
|
||||
@ -562,7 +562,9 @@
|
||||
"tools": {
|
||||
"completed": "已完成",
|
||||
"invoking": "調用中",
|
||||
"error": "發生錯誤"
|
||||
"error": "發生錯誤",
|
||||
"raw": "原始碼",
|
||||
"preview": "預覽"
|
||||
},
|
||||
"topic.added": "新話題已新增",
|
||||
"upgrade.success.button": "重新啟動",
|
||||
|
||||
@ -503,7 +503,9 @@
|
||||
"switch.disabled": "Παρακαλείστε να περιμένετε τη λήξη της τρέχουσας απάντησης",
|
||||
"tools": {
|
||||
"completed": "Ολοκληρώθηκε",
|
||||
"invoking": "κλήση σε εξέλιξη"
|
||||
"invoking": "κλήση σε εξέλιξη",
|
||||
"raw": "Ακατέργαστο",
|
||||
"preview": "Προεπισκόπηση"
|
||||
},
|
||||
"topic.added": "Η θεματική προστέθηκε επιτυχώς",
|
||||
"upgrade.success.button": "Επανεκκίνηση",
|
||||
|
||||
@ -503,7 +503,9 @@
|
||||
"switch.disabled": "Espere a que se complete la respuesta actual antes de realizar la operación",
|
||||
"tools": {
|
||||
"completed": "Completado",
|
||||
"invoking": "En llamada"
|
||||
"invoking": "En llamada",
|
||||
"raw": "Crudo",
|
||||
"preview": "Vista previa"
|
||||
},
|
||||
"topic.added": "Tema agregado con éxito",
|
||||
"upgrade.success.button": "Reiniciar",
|
||||
|
||||
@ -503,7 +503,9 @@
|
||||
"switch.disabled": "Veuillez attendre la fin de la réponse actuelle avant de procéder",
|
||||
"tools": {
|
||||
"completed": "Terminé",
|
||||
"invoking": "En cours d'exécution"
|
||||
"invoking": "En cours d'exécution",
|
||||
"raw": "Brut",
|
||||
"preview": "Aperçu"
|
||||
},
|
||||
"topic.added": "Thème ajouté avec succès",
|
||||
"upgrade.success.button": "Redémarrer",
|
||||
|
||||
@ -503,7 +503,9 @@
|
||||
"switch.disabled": "Aguarde a conclusão da resposta atual antes de operar",
|
||||
"tools": {
|
||||
"completed": "Completo",
|
||||
"invoking": "Em execução"
|
||||
"invoking": "Em execução",
|
||||
"raw": "Bruto",
|
||||
"preview": "Pré-visualização"
|
||||
},
|
||||
"topic.added": "Tópico adicionado com sucesso",
|
||||
"upgrade.success.button": "Reiniciar",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { CheckOutlined, ExpandOutlined, LoadingOutlined, WarningOutlined } from '@ant-design/icons'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { Message } from '@renderer/types'
|
||||
import { Collapse, message as antdMessage, Modal, Tooltip } from 'antd'
|
||||
import { Collapse, message as antdMessage, Modal, Tabs, Tooltip } from 'antd'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { FC, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -116,6 +116,24 @@ const MessageTools: FC<Props> = ({ message }) => {
|
||||
return items
|
||||
}
|
||||
|
||||
const renderPreview = (content: string) => {
|
||||
if (!content) return null
|
||||
|
||||
try {
|
||||
const parsedResult = JSON.parse(content)
|
||||
switch (parsedResult.content[0]?.type) {
|
||||
case 'text':
|
||||
return <PreviewBlock>{parsedResult.content[0].text}</PreviewBlock>
|
||||
// TODO: support other types
|
||||
default:
|
||||
return <PreviewBlock>{content}</PreviewBlock>
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('failed to render the preview of mcp results:', e)
|
||||
return <PreviewBlock>{content}</PreviewBlock>
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<CollapseContainer
|
||||
@ -139,18 +157,42 @@ const MessageTools: FC<Props> = ({ message }) => {
|
||||
styles={{ body: { maxHeight: '80vh', overflow: 'auto' } }}>
|
||||
{expandedResponse && (
|
||||
<ExpandedResponseContainer style={{ fontFamily, fontSize }}>
|
||||
<ActionButton
|
||||
className="copy-expanded-button"
|
||||
onClick={() => {
|
||||
if (expandedResponse) {
|
||||
navigator.clipboard.writeText(expandedResponse.content)
|
||||
antdMessage.success({ content: t('message.copied'), key: 'copy-expanded' })
|
||||
{/* mode swtich tabs */}
|
||||
<Tabs
|
||||
tabBarExtraContent={
|
||||
<ActionButton
|
||||
className="copy-expanded-button"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
typeof expandedResponse.content === 'string'
|
||||
? expandedResponse.content
|
||||
: JSON.stringify(expandedResponse.content, null, 2)
|
||||
)
|
||||
antdMessage.success({ content: t('message.copied'), key: 'copy-expanded' })
|
||||
}}
|
||||
aria-label={t('common.copy')}>
|
||||
<i className="iconfont icon-copy"></i>
|
||||
</ActionButton>
|
||||
}
|
||||
items={[
|
||||
{
|
||||
key: 'preview',
|
||||
label: t('message.tools.preview'),
|
||||
children: renderPreview(expandedResponse.content)
|
||||
},
|
||||
{
|
||||
key: 'raw',
|
||||
label: t('message.tools.raw'),
|
||||
children: (
|
||||
<CodeBlock>
|
||||
{typeof expandedResponse.content === 'string'
|
||||
? expandedResponse.content
|
||||
: JSON.stringify(expandedResponse.content, null, 2)}
|
||||
</CodeBlock>
|
||||
)
|
||||
}
|
||||
}}
|
||||
aria-label={t('common.copy')}>
|
||||
<i className="iconfont icon-copy"></i>
|
||||
</ActionButton>
|
||||
<CodeBlock>{expandedResponse.content}</CodeBlock>
|
||||
]}
|
||||
/>
|
||||
</ExpandedResponseContainer>
|
||||
)}
|
||||
</Modal>
|
||||
@ -267,6 +309,14 @@ const ToolResponseContainer = styled.div`
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const PreviewBlock = styled.div`
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
color: var(--color-text);
|
||||
user-select: text;
|
||||
`
|
||||
|
||||
const CodeBlock = styled.pre`
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user