Merge pull request #48 from langchain-ai/brace/better-error-handling
feat: Error if graph can not connect
This commit is contained in:
@@ -15,7 +15,9 @@ First, clone the repository, or run the [`npx` command](https://www.npmjs.com/pa
|
|||||||
```bash
|
```bash
|
||||||
npx create-agent-chat-app
|
npx create-agent-chat-app
|
||||||
```
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/langchain-ai/agent-chat-ui.git
|
git clone https://github.com/langchain-ai/agent-chat-ui.git
|
||||||
|
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ export function InboxItemInput({
|
|||||||
(Array.isArray(change) && !Array.isArray(key)) ||
|
(Array.isArray(change) && !Array.isArray(key)) ||
|
||||||
(!Array.isArray(change) && Array.isArray(key))
|
(!Array.isArray(change) && Array.isArray(key))
|
||||||
) {
|
) {
|
||||||
toast("Error", {
|
toast.error("Error", {
|
||||||
description: "Something went wrong",
|
description: "Something went wrong",
|
||||||
richColors: true,
|
richColors: true,
|
||||||
closeButton: true,
|
closeButton: true,
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export function ThreadActionsView({
|
|||||||
|
|
||||||
const handleOpenInStudio = () => {
|
const handleOpenInStudio = () => {
|
||||||
if (!apiUrl) {
|
if (!apiUrl) {
|
||||||
toast("Error", {
|
toast.error("Error", {
|
||||||
description: "Please set the LangGraph deployment URL in settings.",
|
description: "Please set the LangGraph deployment URL in settings.",
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
richColors: true,
|
richColors: true,
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export default function useInterruptedActions({
|
|||||||
) => {
|
) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!humanResponse) {
|
if (!humanResponse) {
|
||||||
toast("Error", {
|
toast.error("Error", {
|
||||||
description: "Please enter a response.",
|
description: "Please enter a response.",
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
richColors: true,
|
richColors: true,
|
||||||
@@ -159,7 +159,7 @@ export default function useInterruptedActions({
|
|||||||
(r) => r.type === selectedSubmitType,
|
(r) => r.type === selectedSubmitType,
|
||||||
);
|
);
|
||||||
if (!input) {
|
if (!input) {
|
||||||
toast("Error", {
|
toast.error("Error", {
|
||||||
description: "No response found.",
|
description: "No response found.",
|
||||||
richColors: true,
|
richColors: true,
|
||||||
closeButton: true,
|
closeButton: true,
|
||||||
@@ -189,7 +189,7 @@ export default function useInterruptedActions({
|
|||||||
console.error("Error sending human response", e);
|
console.error("Error sending human response", e);
|
||||||
|
|
||||||
if ("message" in e && e.message.includes("Invalid assistant ID")) {
|
if ("message" in e && e.message.includes("Invalid assistant ID")) {
|
||||||
toast("Error: Invalid assistant ID", {
|
toast.error("Error: Invalid assistant ID", {
|
||||||
description:
|
description:
|
||||||
"The provided assistant ID was not found in this graph. Please update the assistant ID in the settings and try again.",
|
"The provided assistant ID was not found in this graph. Please update the assistant ID in the settings and try again.",
|
||||||
richColors: true,
|
richColors: true,
|
||||||
@@ -197,7 +197,7 @@ export default function useInterruptedActions({
|
|||||||
duration: 5000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast("Error", {
|
toast.error("Error", {
|
||||||
description: "Failed to submit response.",
|
description: "Failed to submit response.",
|
||||||
richColors: true,
|
richColors: true,
|
||||||
closeButton: true,
|
closeButton: true,
|
||||||
@@ -234,7 +234,7 @@ export default function useInterruptedActions({
|
|||||||
|
|
||||||
const ignoreResponse = humanResponse.find((r) => r.type === "ignore");
|
const ignoreResponse = humanResponse.find((r) => r.type === "ignore");
|
||||||
if (!ignoreResponse) {
|
if (!ignoreResponse) {
|
||||||
toast("Error", {
|
toast.error("Error", {
|
||||||
description: "The selected thread does not support ignoring.",
|
description: "The selected thread does not support ignoring.",
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
@@ -284,7 +284,7 @@ export default function useInterruptedActions({
|
|||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error marking thread as resolved", e);
|
console.error("Error marking thread as resolved", e);
|
||||||
toast("Error", {
|
toast.error("Error", {
|
||||||
description: "Failed to mark thread as resolved.",
|
description: "Failed to mark thread as resolved.",
|
||||||
richColors: true,
|
richColors: true,
|
||||||
closeButton: true,
|
closeButton: true,
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import React, { createContext, useContext, ReactNode, useState } from "react";
|
import React, {
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
ReactNode,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
} from "react";
|
||||||
import { useStream } from "@langchain/langgraph-sdk/react";
|
import { useStream } from "@langchain/langgraph-sdk/react";
|
||||||
import { type Message } from "@langchain/langgraph-sdk";
|
import { type Message } from "@langchain/langgraph-sdk";
|
||||||
import {
|
import {
|
||||||
@@ -15,6 +21,7 @@ import { ArrowRight } from "lucide-react";
|
|||||||
import { PasswordInput } from "@/components/ui/password-input";
|
import { PasswordInput } from "@/components/ui/password-input";
|
||||||
import { getApiKey } from "@/lib/api-key";
|
import { getApiKey } from "@/lib/api-key";
|
||||||
import { useThreads } from "./Thread";
|
import { useThreads } from "./Thread";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
export type StateType = { messages: Message[]; ui?: UIMessage[] };
|
export type StateType = { messages: Message[]; ui?: UIMessage[] };
|
||||||
|
|
||||||
@@ -36,6 +43,26 @@ async function sleep(ms = 4000) {
|
|||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function checkGraphStatus(
|
||||||
|
apiUrl: string,
|
||||||
|
apiKey: string | null,
|
||||||
|
): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${apiUrl}/ok`, {
|
||||||
|
...(apiKey && {
|
||||||
|
headers: {
|
||||||
|
"X-Api-Key": apiKey,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.ok;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const StreamSession = ({
|
const StreamSession = ({
|
||||||
children,
|
children,
|
||||||
apiKey,
|
apiKey,
|
||||||
@@ -68,6 +95,24 @@ const StreamSession = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
checkGraphStatus(apiUrl, apiKey).then((ok) => {
|
||||||
|
if (!ok) {
|
||||||
|
toast.error("Failed to connect to LangGraph server", {
|
||||||
|
description: () => (
|
||||||
|
<p>
|
||||||
|
Please ensure your graph is running at <code>{apiUrl}</code> and
|
||||||
|
your API key is correctly set (if connecting to a deployed graph).
|
||||||
|
</p>
|
||||||
|
),
|
||||||
|
duration: 10000,
|
||||||
|
richColors: true,
|
||||||
|
closeButton: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [apiKey, apiUrl]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StreamContext.Provider value={streamValue}>
|
<StreamContext.Provider value={streamValue}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
Reference in New Issue
Block a user