open-swe/apps/web/src/components/v2/actions-renderer.tsx

75 lines
2.2 KiB
TypeScript
Raw Normal View History

import { isHumanMessageSDK } from "@/lib/langchain-messages";
import { UseStream, useStream } from "@langchain/langgraph-sdk/react";
import { AssistantMessage } from "../thread/messages/ai";
import { Dispatch, SetStateAction, useEffect, useRef } from "react";
import { ManagerGraphState } from "@open-swe/shared/open-swe/manager/types";
import { PlannerGraphState } from "@open-swe/shared/open-swe/planner/types";
import { GraphState } from "@open-swe/shared/open-swe/types";
interface ActionsRendererProps {
graphId: string;
threadId: string;
runId?: string;
setProgrammerSession?: (
session: ManagerGraphState["programmerSession"],
) => void;
programmerSession?: ManagerGraphState["programmerSession"];
setSelectedTab?: Dispatch<SetStateAction<"planner" | "programmer">>;
}
export function ActionsRenderer<State extends PlannerGraphState | GraphState>({
graphId,
threadId,
runId,
setProgrammerSession,
programmerSession,
setSelectedTab,
}: ActionsRendererProps) {
const stream = useStream<State>({
apiUrl: process.env.NEXT_PUBLIC_API_URL,
assistantId: graphId,
reconnectOnMount: true,
threadId,
});
const streamJoined = useRef(false);
useEffect(() => {
if (!streamJoined.current && runId) {
streamJoined.current = true;
stream.joinStream(runId).catch(console.error);
}
}, [runId]);
const nonHumanMessages = stream.messages?.filter(
(m) => !isHumanMessageSDK(m),
);
// TODO: Need a better way to handle this. Not great like this...
useEffect(() => {
if (
"programmerSession" in stream.values &&
stream.values.programmerSession &&
(stream.values.programmerSession.runId !== programmerSession?.runId ||
stream.values.programmerSession.threadId !==
programmerSession?.threadId)
) {
setProgrammerSession?.(stream.values.programmerSession);
setSelectedTab?.("programmer");
}
}, [stream.values]);
return (
<div className="flex w-full flex-col gap-2">
{nonHumanMessages?.map((m) => (
<AssistantMessage
key={m.id}
thread={stream as UseStream<Record<string, unknown>>}
message={m}
isLoading={false}
handleRegenerate={() => {}}
/>
))}
</div>
);
}