UNPKG

@langchain/langgraph-sdk

Version:

Client library for interacting with the LangGraph API

1 lines • 10.8 kB
{"version":3,"file":"stream.custom.cjs","names":["BytesLineDecoder","SSEDecoder","IterableReadableStream","MessageTupleManager","StreamManager","useControllableThreadId","getToolCallsWithResults"],"sources":["../../src/react/stream.custom.tsx"],"sourcesContent":["/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */\n\n\"use client\";\n\nimport { useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport { EventStreamEvent, StreamManager } from \"../ui/manager.js\";\nimport type {\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetToolCallsType,\n RunCallbackMeta,\n GetConfigurableType,\n UseStreamTransport,\n UseStreamCustomOptions,\n CustomSubmitOptions,\n} from \"../ui/types.js\";\nimport type { UseStreamCustom } from \"./types.js\";\nimport { type Message } from \"../types.messages.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport { MessageTupleManager } from \"../ui/messages.js\";\nimport { Interrupt } from \"../schema.js\";\nimport { BytesLineDecoder, SSEDecoder } from \"../utils/sse.js\";\nimport { IterableReadableStream } from \"../utils/stream.js\";\nimport { useControllableThreadId } from \"./thread.js\";\nimport { Command } from \"../types.js\";\nimport type { BagTemplate } from \"../types.template.js\";\n\ninterface FetchStreamTransportOptions {\n /**\n * The URL of the API to use.\n */\n apiUrl: string;\n\n /**\n * Default headers to send with requests.\n */\n defaultHeaders?: HeadersInit;\n\n /**\n * Specify a custom fetch implementation.\n */\n fetch?: typeof fetch | ((...args: any[]) => any); // eslint-disable-line @typescript-eslint/no-explicit-any\n\n /**\n * Callback that is called before the request is made.\n */\n onRequest?: (\n url: string,\n init: RequestInit\n ) => Promise<RequestInit> | RequestInit;\n}\n\nexport class FetchStreamTransport<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate\n> implements UseStreamTransport<StateType, Bag>\n{\n constructor(private readonly options: FetchStreamTransportOptions) {}\n\n async stream(payload: {\n input: GetUpdateType<Bag, StateType> | null | undefined;\n context: GetConfigurableType<Bag> | undefined;\n command: Command | undefined;\n signal: AbortSignal;\n }): Promise<AsyncGenerator<{ id?: string; event: string; data: unknown }>> {\n const { signal, ...body } = payload;\n\n let requestInit: RequestInit = {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.options.defaultHeaders,\n },\n body: JSON.stringify(body),\n signal,\n };\n\n if (this.options.onRequest) {\n requestInit = await this.options.onRequest(\n this.options.apiUrl,\n requestInit\n );\n }\n const fetchFn = this.options.fetch ?? fetch;\n\n const response = await fetchFn(this.options.apiUrl, requestInit);\n if (!response.ok) {\n throw new Error(`Failed to stream: ${response.statusText}`);\n }\n\n const stream = (\n response.body || new ReadableStream({ start: (ctrl) => ctrl.close() })\n )\n .pipeThrough(BytesLineDecoder())\n .pipeThrough(SSEDecoder());\n\n return IterableReadableStream.fromReadableStream(stream);\n }\n}\n\nexport function useStreamCustom<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate\n>(\n options: UseStreamCustomOptions<StateType, Bag>\n): UseStreamCustom<StateType, Bag> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n type InterruptType = GetInterruptType<Bag>;\n type ConfigurableType = GetConfigurableType<Bag>;\n type ToolCallType = GetToolCallsType<StateType>;\n\n const [messageManager] = useState(() => new MessageTupleManager());\n const [stream] = useState(\n () =>\n new StreamManager<StateType, Bag>(messageManager, {\n throttle: options.throttle ?? false,\n })\n );\n\n useSyncExternalStore(\n stream.subscribe,\n stream.getSnapshot,\n stream.getSnapshot\n );\n\n const [threadId, onThreadId] = useControllableThreadId(options);\n const threadIdRef = useRef<string | null>(threadId);\n\n // Cancel the stream if thread ID has changed\n useEffect(() => {\n if (threadIdRef.current !== threadId) {\n threadIdRef.current = threadId;\n stream.clear();\n }\n }, [threadId, stream]);\n\n const getMessages = (value: StateType): Message[] => {\n const messagesKey = options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n const setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n const historyValues = options.initialValues ?? ({} as StateType);\n\n const stop = () => stream.stop(historyValues, { onStop: options.onStop });\n\n const submit = async (\n values: UpdateType | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, ConfigurableType>\n ) => {\n let callbackMeta: RunCallbackMeta | undefined;\n let usableThreadId = threadId;\n\n stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...historyValues };\n });\n\n await stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n // generate random thread id\n usableThreadId = crypto.randomUUID();\n threadIdRef.current = usableThreadId;\n onThreadId(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages,\n setMessages,\n\n initialValues: {} as StateType,\n callbacks: options,\n\n onSuccess: () => undefined,\n onError(error) {\n options.onError?.(error, callbackMeta);\n },\n }\n );\n };\n\n return {\n get values() {\n return stream.values ?? ({} as StateType);\n },\n\n error: stream.error,\n isLoading: stream.isLoading,\n\n stop,\n submit,\n\n get interrupt(): Interrupt<InterruptType> | undefined {\n if (\n stream.values != null &&\n \"__interrupt__\" in stream.values &&\n Array.isArray(stream.values.__interrupt__)\n ) {\n const valueInterrupts = stream.values.__interrupt__;\n if (valueInterrupts.length === 0) return { when: \"breakpoint\" };\n if (valueInterrupts.length === 1) return valueInterrupts[0];\n\n // TODO: fix the typing of interrupts if multiple interrupts are returned\n return valueInterrupts as Interrupt<InterruptType>;\n }\n\n return undefined;\n },\n\n get messages(): Message<ToolCallType>[] {\n if (!stream.values) return [];\n return getMessages(stream.values);\n },\n\n get toolCalls() {\n if (!stream.values) return [];\n const msgs = getMessages(stream.values);\n return getToolCallsWithResults<ToolCallType>(msgs);\n },\n\n getToolCalls(message) {\n if (!stream.values) return [];\n const msgs = getMessages(stream.values);\n const allToolCalls = getToolCallsWithResults<ToolCallType>(msgs);\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;AAqDA,IAAa,uBAAb,MAIA;CACE,YAAY,AAAiB,SAAsC;EAAtC;;CAE7B,MAAM,OAAO,SAK8D;EACzE,MAAM,EAAE,QAAQ,GAAG,SAAS;EAE5B,IAAI,cAA2B;GAC7B,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,GAAG,KAAK,QAAQ;IACjB;GACD,MAAM,KAAK,UAAU,KAAK;GAC1B;GACD;AAED,MAAI,KAAK,QAAQ,UACf,eAAc,MAAM,KAAK,QAAQ,UAC/B,KAAK,QAAQ,QACb,YACD;EAIH,MAAM,WAAW,OAFD,KAAK,QAAQ,SAAS,OAEP,KAAK,QAAQ,QAAQ,YAAY;AAChE,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,qBAAqB,SAAS,aAAa;EAG7D,MAAM,UACJ,SAAS,QAAQ,IAAI,eAAe,EAAE,QAAQ,SAAS,KAAK,OAAO,EAAE,CAAC,EAErE,YAAYA,8BAAkB,CAAC,CAC/B,YAAYC,wBAAY,CAAC;AAE5B,SAAOC,sCAAuB,mBAAmB,OAAO;;;AAI5D,SAAgB,gBAId,SACiC;CAOjC,MAAM,CAAC,4CAAiC,IAAIC,sCAAqB,CAAC;CAClE,MAAM,CAAC,oCAEH,IAAIC,8BAA8B,gBAAgB,EAChD,UAAU,QAAQ,YAAY,OAC/B,CAAC,CACL;AAED,iCACE,OAAO,WACP,OAAO,aACP,OAAO,YACR;CAED,MAAM,CAAC,UAAU,cAAcC,uCAAwB,QAAQ;CAC/D,MAAM,gCAAoC,SAAS;AAGnD,4BAAgB;AACd,MAAI,YAAY,YAAY,UAAU;AACpC,eAAY,UAAU;AACtB,UAAO,OAAO;;IAEf,CAAC,UAAU,OAAO,CAAC;CAEtB,MAAM,eAAe,UAAgC;EACnD,MAAM,cAAc,QAAQ,eAAe;AAC3C,SAAO,MAAM,QAAQ,MAAM,aAAa,GACnC,MAAM,eACP,EAAE;;CAGR,MAAM,eAAe,SAAoB,aAAmC;EAC1E,MAAM,cAAc,QAAQ,eAAe;AAC3C,SAAO;GAAE,GAAG;IAAU,cAAc;GAAU;;CAGhD,MAAM,gBAAgB,QAAQ,iBAAkB,EAAE;CAElD,MAAM,aAAa,OAAO,KAAK,eAAe,EAAE,QAAQ,QAAQ,QAAQ,CAAC;CAEzE,MAAM,SAAS,OACb,QACA,kBACG;EACH,IAAI;EACJ,IAAI,iBAAiB;AAErB,SAAO,sBAAsB;AAC3B,OAAI,eAAe,oBAAoB,KACrC,QAAO;IACL,GAAG;IACH,GAAI,OAAO,cAAc,qBAAqB,aAC1C,cAAc,iBAAiB,cAAc,GAC7C,cAAc;IACnB;AAGH,UAAO,EAAE,GAAG,eAAe;IAC3B;AAEF,QAAM,OAAO,MACX,OAAO,WAAwB;AAC7B,OAAI,CAAC,gBAAgB;AAEnB,qBAAiB,OAAO,YAAY;AACpC,gBAAY,UAAU;AACtB,eAAW,eAAe;;AAG5B,OAAI,CAAC,eACH,OAAM,IAAI,MAAM,oCAAoC;AAGtD,UAAO,QAAQ,UAAU,OAAO;IAC9B,OAAO;IACP,SAAS,eAAe;IACxB,SAAS,eAAe;IACxB;IACA,QAAQ;KACN,GAAG,eAAe;KAClB,cAAc;MACZ,WAAW;MACX,GAAG,eAAe,QAAQ;MAC3B;KACF;IACF,CAAC;KAIJ;GACE;GACA;GAEA,eAAe,EAAE;GACjB,WAAW;GAEX,iBAAiB;GACjB,QAAQ,OAAO;AACb,YAAQ,UAAU,OAAO,aAAa;;GAEzC,CACF;;AAGH,QAAO;EACL,IAAI,SAAS;AACX,UAAO,OAAO,UAAW,EAAE;;EAG7B,OAAO,OAAO;EACd,WAAW,OAAO;EAElB;EACA;EAEA,IAAI,YAAkD;AACpD,OACE,OAAO,UAAU,QACjB,mBAAmB,OAAO,UAC1B,MAAM,QAAQ,OAAO,OAAO,cAAc,EAC1C;IACA,MAAM,kBAAkB,OAAO,OAAO;AACtC,QAAI,gBAAgB,WAAW,EAAG,QAAO,EAAE,MAAM,cAAc;AAC/D,QAAI,gBAAgB,WAAW,EAAG,QAAO,gBAAgB;AAGzD,WAAO;;;EAMX,IAAI,WAAoC;AACtC,OAAI,CAAC,OAAO,OAAQ,QAAO,EAAE;AAC7B,UAAO,YAAY,OAAO,OAAO;;EAGnC,IAAI,YAAY;AACd,OAAI,CAAC,OAAO,OAAQ,QAAO,EAAE;AAE7B,UAAOC,sCADM,YAAY,OAAO,OAAO,CACW;;EAGpD,aAAa,SAAS;AACpB,OAAI,CAAC,OAAO,OAAQ,QAAO,EAAE;AAG7B,UADqBA,sCADR,YAAY,OAAO,OAAO,CACyB,CAC5C,QAAQ,OAAO,GAAG,UAAU,OAAO,QAAQ,GAAG;;EAErE"}