show tool message in chat
This commit is contained in:
@@ -46,7 +46,7 @@ type EditableAgent = {
|
|||||||
|
|
||||||
type AgentChatMessage = {
|
type AgentChatMessage = {
|
||||||
id: string;
|
id: string;
|
||||||
role: "user" | "assistant";
|
role: "user" | "assistant" | "tool";
|
||||||
content: string;
|
content: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -452,6 +452,28 @@ function createConversationId(): string {
|
|||||||
return `conv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
return `conv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapConversationMessageToAgentChatMessage(
|
||||||
|
message: ConversationMessageItem
|
||||||
|
): AgentChatMessage | null {
|
||||||
|
const type = (message.message_type || "").toLowerCase();
|
||||||
|
let role: AgentChatMessage["role"] | null = null;
|
||||||
|
if (type === "human" || type === "user") {
|
||||||
|
role = "user";
|
||||||
|
} else if (type === "ai" || type === "assistant") {
|
||||||
|
role = "assistant";
|
||||||
|
} else if (type === "tool") {
|
||||||
|
role = "tool";
|
||||||
|
}
|
||||||
|
if (!role) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: `${message.sequence_number}-${message.created_at}-${role}`,
|
||||||
|
role,
|
||||||
|
content: message.content || "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeDeepAgentActBackend(value: unknown): DeepAgentActBackend {
|
function normalizeDeepAgentActBackend(value: unknown): DeepAgentActBackend {
|
||||||
if (value === "local_shell" || value === "localshell") {
|
if (value === "local_shell" || value === "localshell") {
|
||||||
return "local_shell";
|
return "local_shell";
|
||||||
@@ -1227,6 +1249,7 @@ export default function App() {
|
|||||||
|
|
||||||
async function sendAgentChatMessage(): Promise<void> {
|
async function sendAgentChatMessage(): Promise<void> {
|
||||||
const pipelineId = (chatPipelineId || "").trim();
|
const pipelineId = (chatPipelineId || "").trim();
|
||||||
|
const conversationId = chatConversationId;
|
||||||
const message = chatInput.trim();
|
const message = chatInput.trim();
|
||||||
if (!pipelineId || !message || chatSending) {
|
if (!pipelineId || !message || chatSending) {
|
||||||
return;
|
return;
|
||||||
@@ -1256,7 +1279,7 @@ export default function App() {
|
|||||||
try {
|
try {
|
||||||
await streamAgentChatResponse({
|
await streamAgentChatResponse({
|
||||||
appId: pipelineId,
|
appId: pipelineId,
|
||||||
sessionId: chatConversationId,
|
sessionId: conversationId,
|
||||||
apiKey: authKey,
|
apiKey: authKey,
|
||||||
message,
|
message,
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
@@ -1273,6 +1296,34 @@ export default function App() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// Some runtimes namespace thread ids as "<pipeline_id>:<session_id>" when persisting.
|
||||||
|
// Try both IDs and fail soft so a successful streamed reply never turns into a UI error.
|
||||||
|
const candidateConversationIds = [
|
||||||
|
conversationId,
|
||||||
|
`${pipelineId}:${conversationId}`,
|
||||||
|
];
|
||||||
|
let reloaded = false;
|
||||||
|
for (const candidateId of candidateConversationIds) {
|
||||||
|
try {
|
||||||
|
const storedMessages = await getPipelineConversationMessages(
|
||||||
|
pipelineId,
|
||||||
|
candidateId
|
||||||
|
);
|
||||||
|
const normalizedMessages = storedMessages
|
||||||
|
.map(mapConversationMessageToAgentChatMessage)
|
||||||
|
.filter((item): item is AgentChatMessage => item !== null);
|
||||||
|
if (normalizedMessages.length > 0) {
|
||||||
|
setChatMessages(normalizedMessages);
|
||||||
|
reloaded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore refresh failures; keep streamed content visible.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!reloaded) {
|
||||||
|
// Keep existing streamed messages without surfacing a false error state.
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if ((error as Error).message === "Request cancelled") {
|
if ((error as Error).message === "Request cancelled") {
|
||||||
setChatMessages((prev) =>
|
setChatMessages((prev) =>
|
||||||
@@ -1907,9 +1958,15 @@ export default function App() {
|
|||||||
chatMessages.map((message) => (
|
chatMessages.map((message) => (
|
||||||
<article
|
<article
|
||||||
key={message.id}
|
key={message.id}
|
||||||
className={`chat-modal-message ${message.role === "assistant" ? "assistant" : "user"}`}
|
className={`chat-modal-message ${message.role}`}
|
||||||
>
|
>
|
||||||
<strong>{message.role === "assistant" ? "Agent" : "You"}</strong>
|
<strong>
|
||||||
|
{message.role === "assistant"
|
||||||
|
? "Agent"
|
||||||
|
: message.role === "tool"
|
||||||
|
? "Tool"
|
||||||
|
: "You"}
|
||||||
|
</strong>
|
||||||
<div className="chat-message-content">
|
<div className="chat-message-content">
|
||||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>
|
<ReactMarkdown remarkPlugins={[remarkGfm]}>
|
||||||
{message.content || (chatSending && message.role === "assistant" ? "..." : "")}
|
{message.content || (chatSending && message.role === "assistant" ? "..." : "")}
|
||||||
|
|||||||
@@ -611,6 +611,10 @@ button:disabled {
|
|||||||
border-left: 3px solid #26a269;
|
border-left: 3px solid #26a269;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-modal-message.tool {
|
||||||
|
border-left: 3px solid #8e6bd8;
|
||||||
|
}
|
||||||
|
|
||||||
.chat-modal-message p {
|
.chat-modal-message p {
|
||||||
margin: 6px 0 0 0;
|
margin: 6px 0 0 0;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user