Merge pull request #96 from langchain-ai/brace/fix-interrupt-no-msgs
fix: Rendering interrupts when there are no ai/tool messages
This commit is contained in:
@@ -200,6 +200,9 @@ export function Thread() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const chatStarted = !!threadId || !!messages.length;
|
const chatStarted = !!threadId || !!messages.length;
|
||||||
|
const hasNoAIOrToolMessages = !messages.find(
|
||||||
|
(m) => m.type === "ai" || m.type === "tool",
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full h-screen overflow-hidden">
|
<div className="flex w-full h-screen overflow-hidden">
|
||||||
@@ -350,6 +353,16 @@ export function Thread() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
|
{/* Special rendering case where there are no AI/tool messages, but there is an interrupt.
|
||||||
|
We need to render it outside of the messages list, since there are no messages to render */}
|
||||||
|
{hasNoAIOrToolMessages && !!stream.interrupt && (
|
||||||
|
<AssistantMessage
|
||||||
|
key="interrupt-msg"
|
||||||
|
message={undefined}
|
||||||
|
isLoading={isLoading}
|
||||||
|
handleRegenerate={handleRegenerate}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{isLoading && !firstTokenReceived && (
|
{isLoading && !firstTokenReceived && (
|
||||||
<AssistantMessageLoading />
|
<AssistantMessageLoading />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -70,11 +70,12 @@ export function AssistantMessage({
|
|||||||
isLoading,
|
isLoading,
|
||||||
handleRegenerate,
|
handleRegenerate,
|
||||||
}: {
|
}: {
|
||||||
message: Message;
|
message: Message | undefined;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
handleRegenerate: (parentCheckpoint: Checkpoint | null | undefined) => void;
|
handleRegenerate: (parentCheckpoint: Checkpoint | null | undefined) => void;
|
||||||
}) {
|
}) {
|
||||||
const contentString = getContentString(message.content);
|
const content = message?.content ?? [];
|
||||||
|
const contentString = getContentString(content);
|
||||||
const [hideToolCalls] = useQueryState(
|
const [hideToolCalls] = useQueryState(
|
||||||
"hideToolCalls",
|
"hideToolCalls",
|
||||||
parseAsBoolean.withDefault(false),
|
parseAsBoolean.withDefault(false),
|
||||||
@@ -82,15 +83,20 @@ export function AssistantMessage({
|
|||||||
|
|
||||||
const thread = useStreamContext();
|
const thread = useStreamContext();
|
||||||
const isLastMessage =
|
const isLastMessage =
|
||||||
thread.messages[thread.messages.length - 1].id === message.id;
|
thread.messages[thread.messages.length - 1].id === message?.id;
|
||||||
const meta = thread.getMessagesMetadata(message);
|
const hasNoAIOrToolMessages = !thread.messages.find(
|
||||||
const interrupt = thread.interrupt;
|
(m) => m.type === "ai" || m.type === "tool",
|
||||||
|
);
|
||||||
|
const meta = message ? thread.getMessagesMetadata(message) : undefined;
|
||||||
|
const threadInterrupt = thread.interrupt;
|
||||||
|
|
||||||
const parentCheckpoint = meta?.firstSeenState?.parent_checkpoint;
|
const parentCheckpoint = meta?.firstSeenState?.parent_checkpoint;
|
||||||
const anthropicStreamedToolCalls = Array.isArray(message.content)
|
const anthropicStreamedToolCalls = Array.isArray(content)
|
||||||
? parseAnthropicStreamedToolCalls(message.content)
|
? parseAnthropicStreamedToolCalls(content)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const hasToolCalls =
|
const hasToolCalls =
|
||||||
|
message &&
|
||||||
"tool_calls" in message &&
|
"tool_calls" in message &&
|
||||||
message.tool_calls &&
|
message.tool_calls &&
|
||||||
message.tool_calls.length > 0;
|
message.tool_calls.length > 0;
|
||||||
@@ -100,7 +106,7 @@ export function AssistantMessage({
|
|||||||
(tc) => tc.args && Object.keys(tc.args).length > 0,
|
(tc) => tc.args && Object.keys(tc.args).length > 0,
|
||||||
);
|
);
|
||||||
const hasAnthropicToolCalls = !!anthropicStreamedToolCalls?.length;
|
const hasAnthropicToolCalls = !!anthropicStreamedToolCalls?.length;
|
||||||
const isToolResult = message.type === "tool";
|
const isToolResult = message?.type === "tool";
|
||||||
|
|
||||||
if (isToolResult && hideToolCalls) {
|
if (isToolResult && hideToolCalls) {
|
||||||
return null;
|
return null;
|
||||||
@@ -130,14 +136,15 @@ export function AssistantMessage({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<CustomComponent message={message} thread={thread} />
|
{message && <CustomComponent message={message} thread={thread} />}
|
||||||
{isAgentInboxInterruptSchema(interrupt?.value) && isLastMessage && (
|
{isAgentInboxInterruptSchema(threadInterrupt?.value) &&
|
||||||
<ThreadView interrupt={interrupt.value} />
|
(isLastMessage || hasNoAIOrToolMessages) && (
|
||||||
)}
|
<ThreadView interrupt={threadInterrupt.value} />
|
||||||
{interrupt?.value &&
|
)}
|
||||||
!isAgentInboxInterruptSchema(interrupt.value) &&
|
{threadInterrupt?.value &&
|
||||||
|
!isAgentInboxInterruptSchema(threadInterrupt.value) &&
|
||||||
isLastMessage ? (
|
isLastMessage ? (
|
||||||
<GenericInterruptView interrupt={interrupt.value} />
|
<GenericInterruptView interrupt={threadInterrupt.value} />
|
||||||
) : null}
|
) : null}
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
Reference in New Issue
Block a user