Skip to content

Commit edeacfb

Browse files
committed
disable if not all are present
1 parent 7a7c584 commit edeacfb

File tree

4 files changed

+53
-4
lines changed

4 files changed

+53
-4
lines changed

frontend/app/components/Primitives.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ const MyThreadScrollToBottom: FC = () => {
9797

9898
interface MyComposerProps {
9999
messages: BaseMessage[];
100+
submitDisabled: boolean;
100101
}
101102

102103
const MyComposer: FC<MyComposerProps> = (props: MyComposerProps) => {
@@ -117,7 +118,7 @@ const MyComposer: FC<MyComposerProps> = (props: MyComposerProps) => {
117118
className="placeholder:text-gray-400 text-gray-100 max-h-40 flex-1 resize-none border-none bg-transparent px-2 py-2 text-sm outline-none focus:ring-0 disabled:cursor-not-allowed"
118119
/>
119120
<div className="flex-shrink-0">
120-
<ThreadPrimitive.If running={false}>
121+
<ThreadPrimitive.If running={false} disabled={props.submitDisabled}>
121122
<ComposerPrimitive.Send asChild>
122123
<TooltipIconButton
123124
tooltip="Send"

frontend/app/hooks/useGraph.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { v4 as uuidv4 } from "uuid";
66

77
import { Client } from "@langchain/langgraph-sdk";
88
import { getCookie, setCookie } from "../utils/cookies";
9-
import { ThreadActual } from "./useThreads";
9+
import { ThreadActual, useThreads } from "./useThreads";
1010

1111
export const createClient = () => {
1212
const apiUrl = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:3000/api";
@@ -53,20 +53,41 @@ export interface GraphInput {
5353

5454
export function useGraph(userId: string | undefined) {
5555
const { toast } = useToast();
56+
const { getThreadById } = useThreads(userId);
5657
const [messages, setMessages] = useState<BaseMessage[]>([]);
5758
const [assistantId, setAssistantId] = useState<string>();
5859
const [threadId, setThreadId] = useState<string>();
5960

6061
useEffect(() => {
6162
if (threadId || typeof window === "undefined" || !userId) return;
62-
createThread(userId);
63+
searchOrCreateThread(userId);
6364
}, [userId]);
6465

6566
useEffect(() => {
6667
if (assistantId || typeof window === "undefined") return;
6768
getOrCreateAssistant();
6869
}, []);
6970

71+
const searchOrCreateThread = async (id: string) => {
72+
const threadIdCookie = getCookie("clc_py_thread_id");
73+
if (!threadIdCookie) {
74+
await createThread(id);
75+
return;
76+
}
77+
// Thread ID is in cookies.
78+
79+
const thread = await getThreadById(threadIdCookie);
80+
if (!thread.values) {
81+
// No values = no activity. Can keep.
82+
setThreadId(threadIdCookie);
83+
return;
84+
} else {
85+
// Current thread has activity. Create a new thread.
86+
await createThread(id);
87+
return;
88+
}
89+
};
90+
7091
const createThread = async (id: string) => {
7192
setMessages([]);
7293
const client = createClient();
@@ -81,6 +102,7 @@ export function useGraph(userId: string | undefined) {
81102
throw new Error("Thread creation failed.");
82103
}
83104
setThreadId(thread.thread_id);
105+
setCookie("clc_py_thread_id", thread.thread_id);
84106
} catch (e) {
85107
console.error("Error creating thread", e);
86108
toast({

frontend/app/hooks/useThreads.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ export function useThreads(userId: string | undefined) {
4343
}
4444
};
4545

46+
const getThreadById = async (id: string) => {
47+
const client = createClient();
48+
return (await client.threads.get(id)) as Awaited<ThreadActual>;
49+
};
50+
4651
return {
4752
userThreads,
53+
getThreadById,
4854
};
4955
}

frontend/app/new/page.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ import { useGraph } from "../hooks/useGraph";
1919
import { ThreadHistory } from "../components/ThreadHistory";
2020
import { useUser } from "../hooks/useUser";
2121
import { useThreads } from "../hooks/useThreads";
22+
import { useToast } from "../hooks/use-toast";
2223

2324
export default function ContentComposerChatInterface(): React.ReactElement {
25+
const { toast } = useToast();
2426
const { userId } = useUser();
2527
const {
2628
messages,
@@ -34,7 +36,25 @@ export default function ContentComposerChatInterface(): React.ReactElement {
3436
const { userThreads } = useThreads(userId);
3537
const [isRunning, setIsRunning] = useState(false);
3638

39+
const isSubmitDisabled = !userId || !assistantId || !currentThread;
40+
3741
async function onNew(message: AppendMessage): Promise<void> {
42+
if (isSubmitDisabled) {
43+
let description = "";
44+
if (!userId) {
45+
description = "Unable to find user ID. Please try again later.";
46+
} else if (!assistantId) {
47+
description = "Unable to find assistant ID. Please try again later.";
48+
} else if (!currentThread) {
49+
description =
50+
"Unable to find current thread ID. Please try again later.";
51+
}
52+
toast({
53+
title: "Failed to send message",
54+
description,
55+
});
56+
return;
57+
}
3858
if (message.content[0]?.type !== "text") {
3959
throw new Error("Only text messages are supported");
4060
}
@@ -83,7 +103,7 @@ export default function ContentComposerChatInterface(): React.ReactElement {
83103
</div>
84104
<div className="w-full h-full overflow-hidden">
85105
<AssistantRuntimeProvider runtime={runtime}>
86-
<MyThread messages={messages} />
106+
<MyThread submitDisabled={isSubmitDisabled} messages={messages} />
87107
</AssistantRuntimeProvider>
88108
</div>
89109
<Toaster />

0 commit comments

Comments
 (0)