diff --git a/locales/en/plugin__lightspeed-console-plugin.json b/locales/en/plugin__lightspeed-console-plugin.json
index 583d51d0..c7526454 100644
--- a/locales/en/plugin__lightspeed-console-plugin.json
+++ b/locales/en/plugin__lightspeed-console-plugin.json
@@ -17,6 +17,7 @@
"Configure events attachment": "Configure events attachment",
"Configure log attachment": "Configure log attachment",
"Confirm chat deletion": "Confirm chat deletion",
+ "Content": "Content",
"Conversation history has been truncated to fit within context window.": "Conversation history has been truncated to fit within context window.",
"Copied": "Copied",
"Copy conversation": "Copy conversation",
@@ -59,6 +60,7 @@
"Large prompt": "Large prompt",
"Leave": "Leave",
"Logs": "Logs",
+ "MCP server": "MCP server",
"Minimize": "Minimize",
"Most recent {{lines}} lines": "Most recent {{lines}} lines",
"Most recent {{numEvents}} events": "Most recent {{numEvents}} events",
@@ -80,13 +82,16 @@
"Revert to original": "Revert to original",
"Save": "Save",
"Send a message...": "Send a message...",
+ "Status": "Status",
"Stay": "Stay",
+ "Structured content": "Structured content",
"Submit": "Submit",
"The following output was generated when running <2>{{name}}2> with arguments <5>{{argsFormatted}}5>.": "The following output was generated when running <2>{{name}}2> with arguments <5>{{argsFormatted}}5>.",
"The following output was generated when running <2>{{name}}2> with no arguments.": "The following output was generated when running <2>{{name}}2> with no arguments.",
"The OpenShift Lightspeed service is not yet ready to receive requests. If this message persists, please check the OLSConfig.": "The OpenShift Lightspeed service is not yet ready to receive requests. If this message persists, please check the OLSConfig.",
"Tool output": "Tool output",
"Total size of attachments exceeds {{max}} characters.": "Total size of attachments exceeds {{max}} characters.",
+ "UI resource": "UI resource",
"Upload from computer": "Upload from computer",
"Uploaded file is not valid YAML": "Uploaded file is not valid YAML",
"Uploaded file is too large. Max size is {{max}} MB.": "Uploaded file is too large. Max size is {{max}} MB.",
diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx
index 6781d7fe..3e534b5d 100644
--- a/src/components/Prompt.tsx
+++ b/src/components/Prompt.tsx
@@ -573,8 +573,23 @@ const Prompt: React.FC = ({ scrollIntoView }) => {
const { args, id, name: toolName } = json.data;
dispatch(chatHistoryUpdateTool(chatEntryID, id, { name: toolName, args }));
} else if (json.event === 'tool_result') {
- const { content, id, status } = json.data;
- dispatch(chatHistoryUpdateTool(chatEntryID, id, { content, status }));
+ const {
+ content,
+ id,
+ status,
+ ui_resource_uri: uiResourceUri,
+ server_name: serverName,
+ structured_content: structuredContent,
+ } = json.data;
+ dispatch(
+ chatHistoryUpdateTool(chatEntryID, id, {
+ content,
+ status,
+ ...(uiResourceUri && { uiResourceUri }),
+ ...(serverName && { serverName }),
+ ...(structuredContent && { structuredContent }),
+ }),
+ );
} else if (json.event === 'error') {
dispatch(
chatHistoryUpdateByID(chatEntryID, {
diff --git a/src/components/ResponseToolModal.tsx b/src/components/ResponseToolModal.tsx
index 0aa6db71..de8d102c 100644
--- a/src/components/ResponseToolModal.tsx
+++ b/src/components/ResponseToolModal.tsx
@@ -2,7 +2,19 @@ import { Map as ImmutableMap } from 'immutable';
import * as React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
-import { Alert, CodeBlock, CodeBlockAction, CodeBlockCode, Icon } from '@patternfly/react-core';
+import {
+ Alert,
+ CodeBlock,
+ CodeBlockAction,
+ CodeBlockCode,
+ DescriptionList,
+ DescriptionListDescription,
+ DescriptionListGroup,
+ DescriptionListTerm,
+ Icon,
+ Label,
+ Title,
+} from '@patternfly/react-core';
import { InfoCircleIcon } from '@patternfly/react-icons';
import { openToolClear } from '../redux-actions';
@@ -32,12 +44,26 @@ const ToolModal: React.FC = () => {
if (!tool) {
return null;
}
- const { args, content, name, status } = tool.toJS();
- const argsFormatted = Object.entries(args)
+ const { args, content, name, serverName, status, structuredContent, uiResourceUri } =
+ tool.toJS() as {
+ args: Record;
+ content: string;
+ name: string;
+ serverName?: string;
+ status: string;
+ structuredContent?: Record;
+ uiResourceUri?: string;
+ };
+
+ const argsFormatted = Object.entries(args ?? {})
.map(([key, value]) => `${key}=${value}`)
.join(', ');
+ const structuredContentFormatted = structuredContent
+ ? JSON.stringify(structuredContent, null, 2)
+ : undefined;
+
return (
{
)}
+
+
+
+ {t('Status')}
+
+
+
+
+ {serverName && (
+
+ {t('MCP server')}
+ {serverName}
+
+ )}
+ {uiResourceUri && (
+
+ {t('UI resource')}
+
+ {uiResourceUri}
+
+
+ )}
+
+
{content ? (
-
-
-
-
-
- >
- }
- className="ols-plugin__code-block ols-plugin__code-block--attachment"
- >
- {content}
-
+ <>
+
+ {t('Content')}
+
+
+
+
+
+
+ >
+ }
+ className="ols-plugin__code-block ols-plugin__code-block--attachment"
+ >
+ {content}
+
+ >
) : (
{
variant="info"
/>
)}
+
+ {structuredContentFormatted && (
+ <>
+
+ {t('Structured content')}
+
+
+
+
+
+
+ >
+ }
+ className="ols-plugin__code-block ols-plugin__code-block--attachment"
+ >
+
+ {structuredContentFormatted}
+
+
+ >
+ )}
);
};
diff --git a/src/components/ResponseTools.tsx b/src/components/ResponseTools.tsx
index a787af8e..0bf56df5 100644
--- a/src/components/ResponseTools.tsx
+++ b/src/components/ResponseTools.tsx
@@ -2,7 +2,7 @@ import { Map as ImmutableMap } from 'immutable';
import * as React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Label, LabelGroup } from '@patternfly/react-core';
-import { CodeIcon, InfoCircleIcon } from '@patternfly/react-icons';
+import { CodeIcon, ExternalLinkAltIcon, InfoCircleIcon } from '@patternfly/react-icons';
import { openToolSet } from '../redux-actions';
import { State } from '../redux-reducers';
@@ -23,16 +23,25 @@ const ToolLabel: React.FC = ({ entryIndex, toolID }) => {
dispatch(openToolSet(entryIndex, toolID));
}, [dispatch, entryIndex, toolID]);
- const isError = tool.get('status') === 'error';
+ const status = tool.get('status') as string | undefined;
+ const isError = status === 'error';
+ const isTruncated = status === 'truncated';
+ const hasUI = !!tool.get('uiResourceUri');
+
+ const color = isError ? 'red' : isTruncated ? 'yellow' : hasUI ? 'blue' : undefined;
+ const icon = isError ? (
+
+ ) : isTruncated ? (
+
+ ) : hasUI ? (
+
+ ) : (
+
+ );
return (
- : }
- onClick={onClick}
- textMaxWidth="16ch"
- >
- {tool.get('name')}
+
);
};
diff --git a/src/components/general-page.css b/src/components/general-page.css
index 6de49de7..f6d3b1bc 100644
--- a/src/components/general-page.css
+++ b/src/components/general-page.css
@@ -124,3 +124,13 @@
max-width: 30rem;
text-align: center;
}
+
+.ols-plugin__tool-metadata {
+ margin-bottom: var(--pf-t--global--spacer--md);
+ margin-top: var(--pf-t--global--spacer--md);
+}
+
+.ols-plugin__tool-section-title {
+ margin-bottom: var(--pf-t--global--spacer--sm);
+ margin-top: var(--pf-t--global--spacer--md);
+}
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
index 3008eaba..ad9fd387 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -30,7 +30,11 @@ export type Tool = {
args: { [key: string]: Array };
content: string;
name: string;
- status: 'error' | 'success';
+ status: 'error' | 'success' | 'truncated';
+ // MCP app fields (optional - present when tool provides UI)
+ uiResourceUri?: string;
+ serverName?: string;
+ structuredContent?: Record;
};
type ChatEntryUser = {