Skip to content

Commit 9062baf

Browse files
authored
Merge pull request #25 from langchain-ai/vic/fix-react-warning-and-default-interrupts
feat: default interrupt handling, maintain gen ui interrupt support, and add general gen ui support
2 parents b273c4a + 2e9c0f2 commit 9062baf

File tree

12 files changed

+1810
-3511
lines changed

12 files changed

+1810
-3511
lines changed

MIGRATION_ANALYSIS.md

Lines changed: 0 additions & 1430 deletions
This file was deleted.

src/app/components/ChatInterface.tsx

Lines changed: 428 additions & 611 deletions
Large diffs are not rendered by default.

src/app/components/ChatMessage.tsx

Lines changed: 30 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,47 @@
11
"use client";
22

33
import React, { useMemo, useState, useCallback } from "react";
4-
import { RotateCcw } from "lucide-react";
54
import { SubAgentIndicator } from "@/app/components/SubAgentIndicator";
65
import { ToolCallBox } from "@/app/components/ToolCallBox";
76
import { MarkdownContent } from "@/app/components/MarkdownContent";
8-
import type { SubAgent, ToolCall } from "@/app/types/types";
9-
import { Interrupt, Message } from "@langchain/langgraph-sdk";
7+
import type {
8+
SubAgent,
9+
ToolCall,
10+
ActionRequest,
11+
ReviewConfig,
12+
} from "@/app/types/types";
13+
import { Message } from "@langchain/langgraph-sdk";
1014
import {
1115
extractSubAgentContent,
1216
extractStringFromMessageContent,
13-
getInterruptTitle,
1417
} from "@/app/utils/utils";
1518
import { cn } from "@/lib/utils";
1619

1720
interface ChatMessageProps {
1821
message: Message;
1922
toolCalls: ToolCall[];
20-
onRestartFromAIMessage: (message: Message) => void;
21-
onRestartFromSubTask: (toolCallId: string) => void;
22-
debugMode?: boolean;
23-
isLastMessage?: boolean;
2423
isLoading?: boolean;
25-
interrupt?: Interrupt;
24+
actionRequestsMap?: Map<string, ActionRequest>;
25+
reviewConfigsMap?: Map<string, ReviewConfig>;
2626
ui?: any[];
2727
stream?: any;
28+
onResumeInterrupt?: (value: any) => void;
29+
graphId?: string;
2830
}
2931

3032
export const ChatMessage = React.memo<ChatMessageProps>(
3133
({
3234
message,
3335
toolCalls,
34-
onRestartFromAIMessage,
35-
onRestartFromSubTask,
36-
debugMode,
37-
isLastMessage,
3836
isLoading,
39-
interrupt,
37+
actionRequestsMap,
38+
reviewConfigsMap,
4039
ui,
4140
stream,
41+
onResumeInterrupt,
42+
graphId,
4243
}) => {
4344
const isUser = message.type === "human";
44-
const isAIMessage = message.type === "ai";
4545
const messageContent = extractStringFromMessageContent(message);
4646
const hasContent = messageContent && messageContent.trim() !== "";
4747
const hasToolCalls = toolCalls.length > 0;
@@ -56,10 +56,13 @@ export const ChatMessage = React.memo<ChatMessageProps>(
5656
);
5757
})
5858
.map((toolCall: ToolCall) => {
59+
const subagentType = (toolCall.args as Record<string, unknown>)[
60+
"subagent_type"
61+
] as string;
5962
return {
6063
id: toolCall.id,
6164
name: toolCall.name,
62-
subAgentName: String(toolCall.args["subagent_type"] || ""),
65+
subAgentName: subagentType,
6366
input: toolCall.args,
6467
output: toolCall.result ? { result: toolCall.result } : undefined,
6568
status: toolCall.status,
@@ -81,8 +84,6 @@ export const ChatMessage = React.memo<ChatMessageProps>(
8184
}));
8285
}, []);
8386

84-
const interruptTitle = interrupt ? getInterruptTitle(interrupt) : "";
85-
8687
return (
8788
<div
8889
className={cn(
@@ -96,7 +97,7 @@ export const ChatMessage = React.memo<ChatMessageProps>(
9697
isUser ? "max-w-[70%]" : "w-full"
9798
)}
9899
>
99-
{(hasContent || debugMode) && (
100+
{hasContent && (
100101
<div className={cn("relative flex items-end gap-0")}>
101102
<div
102103
className={cn(
@@ -117,40 +118,30 @@ export const ChatMessage = React.memo<ChatMessageProps>(
117118
</p>
118119
) : hasContent ? (
119120
<MarkdownContent content={messageContent} />
120-
) : debugMode ? (
121-
<p className="m-0 whitespace-nowrap text-xs italic">
122-
Empty Message
123-
</p>
124121
) : null}
125122
</div>
126-
{debugMode && isAIMessage && !(isLastMessage && isLoading) && (
127-
<button
128-
onClick={() => onRestartFromAIMessage(message)}
129-
className="absolute bottom-1 right-1 -scale-x-100 rounded-full bg-black/10 p-1 transition-colors duration-200 hover:bg-black/20"
130-
>
131-
<RotateCcw className="h-3 w-3 text-gray-600" />
132-
</button>
133-
)}
134123
</div>
135124
)}
136125
{hasToolCalls && (
137126
<div className="mt-4 flex w-full flex-col">
138-
{toolCalls.map((toolCall: ToolCall, idx, arr) => {
127+
{toolCalls.map((toolCall: ToolCall) => {
139128
if (toolCall.name === "task") return null;
140-
const uiComponent = ui?.find(
129+
const toolCallGenUiComponent = ui?.find(
141130
(u) => u.metadata?.tool_call_id === toolCall.id
142131
);
143-
const isInterrupted =
144-
idx === arr.length - 1 &&
145-
toolCall.name === interruptTitle &&
146-
isLastMessage;
132+
const actionRequest = actionRequestsMap?.get(toolCall.name);
133+
const reviewConfig = reviewConfigsMap?.get(toolCall.name);
147134
return (
148135
<ToolCallBox
149136
key={toolCall.id}
150137
toolCall={toolCall}
151-
uiComponent={uiComponent}
138+
uiComponent={toolCallGenUiComponent}
152139
stream={stream}
153-
isInterrupted={isInterrupted}
140+
graphId={graphId}
141+
actionRequest={actionRequest}
142+
reviewConfig={reviewConfig}
143+
onResume={onResumeInterrupt}
144+
isLoading={isLoading}
154145
/>
155146
);
156147
})}
@@ -171,16 +162,6 @@ export const ChatMessage = React.memo<ChatMessageProps>(
171162
isExpanded={isSubAgentExpanded(subAgent.id)}
172163
/>
173164
</div>
174-
<div className="relative h-full min-h-[40px] w-[72px] flex-shrink-0">
175-
{debugMode && subAgent.status === "completed" && (
176-
<button
177-
onClick={() => onRestartFromSubTask(subAgent.id)}
178-
className="absolute bottom-1 right-1 -scale-x-100 rounded-full bg-black/10 p-1 transition-colors duration-200 hover:bg-black/20"
179-
>
180-
<RotateCcw className="h-3 w-3 text-gray-600" />
181-
</button>
182-
)}
183-
</div>
184165
</div>
185166
{isSubAgentExpanded(subAgent.id) && (
186167
<div className="w-full max-w-full">

0 commit comments

Comments
 (0)