Skip to content

Commit ca36bfe

Browse files
authored
Merge pull request #96 from langchain-ai/brace/fix-interrupt-no-msgs
fix: Rendering interrupts when there are no ai/tool messages
2 parents ef59d29 + ec294c5 commit ca36bfe

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

src/components/thread/index.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ export function Thread() {
200200
};
201201

202202
const chatStarted = !!threadId || !!messages.length;
203+
const hasNoAIOrToolMessages = !messages.find(
204+
(m) => m.type === "ai" || m.type === "tool",
205+
);
203206

204207
return (
205208
<div className="flex w-full h-screen overflow-hidden">
@@ -350,6 +353,16 @@ export function Thread() {
350353
/>
351354
),
352355
)}
356+
{/* Special rendering case where there are no AI/tool messages, but there is an interrupt.
357+
We need to render it outside of the messages list, since there are no messages to render */}
358+
{hasNoAIOrToolMessages && !!stream.interrupt && (
359+
<AssistantMessage
360+
key="interrupt-msg"
361+
message={undefined}
362+
isLoading={isLoading}
363+
handleRegenerate={handleRegenerate}
364+
/>
365+
)}
353366
{isLoading && !firstTokenReceived && (
354367
<AssistantMessageLoading />
355368
)}

src/components/thread/messages/ai.tsx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,33 @@ export function AssistantMessage({
7070
isLoading,
7171
handleRegenerate,
7272
}: {
73-
message: Message;
73+
message: Message | undefined;
7474
isLoading: boolean;
7575
handleRegenerate: (parentCheckpoint: Checkpoint | null | undefined) => void;
7676
}) {
77-
const contentString = getContentString(message.content);
77+
const content = message?.content ?? [];
78+
const contentString = getContentString(content);
7879
const [hideToolCalls] = useQueryState(
7980
"hideToolCalls",
8081
parseAsBoolean.withDefault(false),
8182
);
8283

8384
const thread = useStreamContext();
8485
const isLastMessage =
85-
thread.messages[thread.messages.length - 1].id === message.id;
86-
const meta = thread.getMessagesMetadata(message);
87-
const interrupt = thread.interrupt;
86+
thread.messages[thread.messages.length - 1].id === message?.id;
87+
const hasNoAIOrToolMessages = !thread.messages.find(
88+
(m) => m.type === "ai" || m.type === "tool",
89+
);
90+
const meta = message ? thread.getMessagesMetadata(message) : undefined;
91+
const threadInterrupt = thread.interrupt;
92+
8893
const parentCheckpoint = meta?.firstSeenState?.parent_checkpoint;
89-
const anthropicStreamedToolCalls = Array.isArray(message.content)
90-
? parseAnthropicStreamedToolCalls(message.content)
94+
const anthropicStreamedToolCalls = Array.isArray(content)
95+
? parseAnthropicStreamedToolCalls(content)
9196
: undefined;
9297

9398
const hasToolCalls =
99+
message &&
94100
"tool_calls" in message &&
95101
message.tool_calls &&
96102
message.tool_calls.length > 0;
@@ -100,7 +106,7 @@ export function AssistantMessage({
100106
(tc) => tc.args && Object.keys(tc.args).length > 0,
101107
);
102108
const hasAnthropicToolCalls = !!anthropicStreamedToolCalls?.length;
103-
const isToolResult = message.type === "tool";
109+
const isToolResult = message?.type === "tool";
104110

105111
if (isToolResult && hideToolCalls) {
106112
return null;
@@ -130,14 +136,15 @@ export function AssistantMessage({
130136
</>
131137
)}
132138

133-
<CustomComponent message={message} thread={thread} />
134-
{isAgentInboxInterruptSchema(interrupt?.value) && isLastMessage && (
135-
<ThreadView interrupt={interrupt.value} />
136-
)}
137-
{interrupt?.value &&
138-
!isAgentInboxInterruptSchema(interrupt.value) &&
139+
{message && <CustomComponent message={message} thread={thread} />}
140+
{isAgentInboxInterruptSchema(threadInterrupt?.value) &&
141+
(isLastMessage || hasNoAIOrToolMessages) && (
142+
<ThreadView interrupt={threadInterrupt.value} />
143+
)}
144+
{threadInterrupt?.value &&
145+
!isAgentInboxInterruptSchema(threadInterrupt.value) &&
139146
isLastMessage ? (
140-
<GenericInterruptView interrupt={interrupt.value} />
147+
<GenericInterruptView interrupt={threadInterrupt.value} />
141148
) : null}
142149
<div
143150
className={cn(

0 commit comments

Comments
 (0)