From f83d18188f0a3974d6a6daec271dae6072d9a536 Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Thu, 20 Feb 2025 02:39:11 +0100 Subject: [PATCH 1/2] feat(react): add interrupts, clean up generic types --- libs/sdk-js/src/react/stream.tsx | 94 ++++++++++++++++++++++++++------ libs/sdk-js/src/schema.ts | 4 +- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/libs/sdk-js/src/react/stream.tsx b/libs/sdk-js/src/react/stream.tsx index 49f2cba1a..a8685a19a 100644 --- a/libs/sdk-js/src/react/stream.tsx +++ b/libs/sdk-js/src/react/stream.tsx @@ -9,7 +9,13 @@ import type { OnCompletionBehavior, } from "../types.js"; import type { Message } from "../types.messages.js"; -import type { Checkpoint, Config, Metadata, ThreadState } from "../schema.js"; +import type { + Checkpoint, + Config, + Interrupt, + Metadata, + ThreadState, +} from "../schema.js"; import type { CustomStreamEvent, DebugStreamEvent, @@ -342,10 +348,41 @@ const useControllableThreadId = (options?: { return [options.threadId, onThreadId]; }; +type BagTemplate = { + ConfigurableType?: Record; + InterruptType?: unknown; + CustomEventType?: unknown; + UpdateType?: unknown; +}; + +type GetUpdateType< + Bag extends BagTemplate, + StateType extends Record, +> = Bag extends { UpdateType: unknown } + ? Bag["UpdateType"] + : Partial; + +type GetConfigurableType = Bag extends { + ConfigurableType: Record; +} + ? Bag["ConfigurableType"] + : Record; + +type GetInterruptType = Bag extends { + InterruptType: unknown; +} + ? Bag["InterruptType"] + : unknown; + +type GetCustomEventType = Bag extends { + CustomEventType: unknown; +} + ? Bag["CustomEventType"] + : unknown; + interface UseStreamOptions< StateType extends Record = Record, - UpdateType extends Record = Partial, - CustomType = unknown, + Bag extends BagTemplate = BagTemplate, > { /** * The ID of the assistant to use. @@ -383,12 +420,16 @@ interface UseStreamOptions< /** * Callback that is called when an update event is received. */ - onUpdateEvent?: (data: UpdatesStreamEvent["data"]) => void; + onUpdateEvent?: ( + data: UpdatesStreamEvent>["data"], + ) => void; /** * Callback that is called when a custom event is received. */ - onCustomEvent?: (data: CustomStreamEvent["data"]) => void; + onCustomEvent?: ( + data: CustomStreamEvent>["data"], + ) => void; /** * Callback that is called when a metadata event is received. @@ -408,8 +449,7 @@ interface UseStreamOptions< interface UseStream< StateType extends Record = Record, - UpdateType extends Record = Partial, - ConfigurableType extends Record = Record, + Bag extends BagTemplate = BagTemplate, > { /** * The current values of the thread. @@ -435,8 +475,8 @@ interface UseStream< * Create and stream a run to the thread. */ submit: ( - values: UpdateType, - options?: SubmitOptions, + values: GetUpdateType | null | undefined, + options?: SubmitOptions>, ) => void; /** @@ -460,6 +500,11 @@ interface UseStream< */ experimental_branchTree: Sequence; + /** + * Get the interrupt value for the stream if interrupted. + */ + interrupt: Interrupt> | undefined; + /** * Messages inferred from the thread. * Will automatically update with incoming message chunks. @@ -505,12 +550,18 @@ interface SubmitOptions< export function useStream< StateType extends Record = Record, - UpdateType extends Record = Partial, - ConfigurableType extends Record = Record, - CustomType = unknown, ->( - options: UseStreamOptions, -): UseStream { + Bag extends { + ConfigurableType?: Record; + InterruptType?: unknown; + CustomEventType?: unknown; + UpdateType?: unknown; + } = BagTemplate, +>(options: UseStreamOptions): UseStream { + type UpdateType = GetUpdateType; + type CustomType = GetCustomEventType; + type InterruptType = GetInterruptType; + type ConfigurableType = GetConfigurableType; + type EventStreamEvent = | ValuesStreamEvent | UpdatesStreamEvent @@ -656,7 +707,7 @@ export function useStream< }, []); const submit = async ( - values: UpdateType | undefined, + values: UpdateType | null | undefined, submitOptions?: SubmitOptions, ) => { try { @@ -815,6 +866,17 @@ export function useStream< history: flatHistory, experimental_branchTree: rootSequence, + get interrupt() { + // Don't show the interrupt if the stream is loading + if (isLoading) return undefined; + + const interrupts = threadHead?.tasks?.at(-1)?.interrupts; + if (interrupts == null || interrupts.length === 0) return undefined; + + // Return only the current interrupt + return interrupts.at(-1) as Interrupt | undefined; + }, + get messages() { trackStreamMode("messages-tuple"); return getMessages(values); diff --git a/libs/sdk-js/src/schema.ts b/libs/sdk-js/src/schema.ts index b737d6a72..1a549dfc4 100644 --- a/libs/sdk-js/src/schema.ts +++ b/libs/sdk-js/src/schema.ts @@ -141,8 +141,8 @@ export interface AssistantGraph { /** * An interrupt thrown inside a thread. */ -export interface Interrupt { - value: unknown; +export interface Interrupt { + value: TValue; when: "during"; resumable: boolean; ns?: string[]; From a69ea47ac2eff4be3cc9a3063511e241112957be Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Thu, 20 Feb 2025 02:40:51 +0100 Subject: [PATCH 2/2] Bump to 0.0.44 --- libs/sdk-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/sdk-js/package.json b/libs/sdk-js/package.json index 89b5444f4..7cbae0cae 100644 --- a/libs/sdk-js/package.json +++ b/libs/sdk-js/package.json @@ -1,6 +1,6 @@ { "name": "@langchain/langgraph-sdk", - "version": "0.0.43", + "version": "0.0.44", "description": "Client library for interacting with the LangGraph API", "type": "module", "packageManager": "yarn@1.22.19",