@assistant-ui/react-langchain 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ ## `@assistant-ui/react-langchain`
2
+
3
+ Adapter that wraps [`useStream`](https://docs.langchain.com/oss/javascript/langgraph-sdk/react-stream) from `@langchain/react` and exposes it as an assistant-ui runtime, with hooks for reading interrupts, submitting raw state updates, and reading arbitrary LangGraph custom state keys.
4
+
5
+ > assistant-ui also ships [`@assistant-ui/react-langgraph`](https://www.npmjs.com/package/@assistant-ui/react-langgraph), which integrates with `@langchain/langgraph-sdk` directly and has a broader feature set (subgraph events, UI messages, message metadata, cancellation). The two packages are independent adapters targeting different upstream libraries — pick whichever matches your upstream choice. See the [comparison](https://www.assistant-ui.com/docs/runtimes/langchain/comparison).
6
+
7
+ ## Features
8
+
9
+ - Bridges LangChain's `useStream` to an assistant-ui `AssistantRuntime`
10
+ - Tool invocations flow through assistant-ui's `useToolInvocations`
11
+ - `useLangChainInterruptState` — read the current LangGraph interrupt
12
+ - `useLangChainSubmit` — submit raw state updates (e.g. resume commands)
13
+ - `useLangChainState<T>(key)` — read custom state keys like `todos` / `files` reactively
14
+ - Optional assistant-cloud thread persistence
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @assistant-ui/react @assistant-ui/react-langchain @langchain/react
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Basic setup
25
+
26
+ ```tsx
27
+ import { useStreamRuntime } from "@assistant-ui/react-langchain";
28
+ import { AssistantRuntimeProvider, Thread } from "@assistant-ui/react";
29
+
30
+ function App() {
31
+ const runtime = useStreamRuntime({
32
+ assistantId: "agent",
33
+ apiUrl: "http://localhost:2024",
34
+ });
35
+
36
+ return (
37
+ <AssistantRuntimeProvider runtime={runtime}>
38
+ <Thread />
39
+ </AssistantRuntimeProvider>
40
+ );
41
+ }
42
+ ```
43
+
44
+ `useStreamRuntime` accepts every option `useStream` from `@langchain/react` does, plus:
45
+
46
+ - `cloud` — an `AssistantCloud` instance for persisting threads
47
+ - `adapters` — `{ attachments, speech, feedback }`
48
+ - `messagesKey` — the state key that holds messages (default `"messages"`)
49
+
50
+ ### Reading custom state keys
51
+
52
+ LangGraph agents often expose structured state beyond messages (plans, todos, scratch files, generative-UI artifacts). Read them directly with `useLangChainState` — mirrors `useStream().values[key]` upstream and updates when the stream emits new state.
53
+
54
+ ```tsx
55
+ import { useLangChainState } from "@assistant-ui/react-langchain";
56
+
57
+ type Todo = { id: string; title: string; done: boolean };
58
+
59
+ function TodoList() {
60
+ const todos = useLangChainState<Todo[]>("todos", []);
61
+
62
+ return (
63
+ <ul>
64
+ {todos.map((t) => (
65
+ <li key={t.id}>{t.title}</li>
66
+ ))}
67
+ </ul>
68
+ );
69
+ }
70
+ ```
71
+
72
+ Signatures:
73
+
74
+ ```ts
75
+ useLangChainState<T>(key: string): T | undefined;
76
+ useLangChainState<T>(key: string, defaultValue: T): T;
77
+ ```
78
+
79
+ ### Interrupts
80
+
81
+ ```tsx
82
+ import {
83
+ useLangChainInterruptState,
84
+ useLangChainSubmit,
85
+ } from "@assistant-ui/react-langchain";
86
+ import { Command } from "@langchain/langgraph-sdk";
87
+
88
+ function InterruptPrompt() {
89
+ const interrupt = useLangChainInterruptState();
90
+ const submit = useLangChainSubmit();
91
+
92
+ if (!interrupt) return null;
93
+
94
+ return (
95
+ <div>
96
+ <pre>{JSON.stringify(interrupt.value, null, 2)}</pre>
97
+ <button onClick={() => submit(null, { command: new Command({ resume: "yes" }) })}>
98
+ Approve
99
+ </button>
100
+ </div>
101
+ );
102
+ }
103
+ ```
104
+
105
+ ### Message conversion
106
+
107
+ The adapter ships `convertLangChainBaseMessage` for cases where you want to reuse the internal converter directly (e.g. when building a custom `ExternalStoreAdapter`).
108
+
109
+ ```ts
110
+ import { convertLangChainBaseMessage } from "@assistant-ui/react-langchain";
111
+ ```
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { useStreamRuntime, useLangChainInterruptState, useLangChainSubmit, } from "./useStreamRuntime.js";
1
+ export { useStreamRuntime, useLangChainInterruptState, useLangChainState, useLangChainSubmit, } from "./useStreamRuntime.js";
2
2
  export type { UseStreamRuntimeOptions } from "./useStreamRuntime.js";
3
3
  export { convertLangChainBaseMessage } from "./convertMessages.js";
4
4
  export type { LangChainBaseMessage, LangChainContentBlock, LangChainToolCall, } from "./types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,kBAAkB,GACnB,8BAA2B;AAC5B,YAAY,EAAE,uBAAuB,EAAE,8BAA2B;AAElE,OAAO,EAAE,2BAA2B,EAAE,6BAA0B;AAEhE,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,mBAAgB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,GACnB,8BAA2B;AAC5B,YAAY,EAAE,uBAAuB,EAAE,8BAA2B;AAElE,OAAO,EAAE,2BAA2B,EAAE,6BAA0B;AAEhE,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,mBAAgB"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { useStreamRuntime, useLangChainInterruptState, useLangChainSubmit, } from "./useStreamRuntime.js";
1
+ export { useStreamRuntime, useLangChainInterruptState, useLangChainState, useLangChainSubmit, } from "./useStreamRuntime.js";
2
2
  export { convertLangChainBaseMessage } from "./convertMessages.js";
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,kBAAkB,GACnB,8BAA2B;AAG5B,OAAO,EAAE,2BAA2B,EAAE,6BAA0B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,GACnB,8BAA2B;AAG5B,OAAO,EAAE,2BAA2B,EAAE,6BAA0B"}
@@ -48,4 +48,17 @@ export declare const useLangChainInterruptState: () => {
48
48
  * commands.
49
49
  */
50
50
  export declare const useLangChainSubmit: () => (values: Record<string, unknown> | null | undefined, options?: Record<string, unknown>) => Promise<void>;
51
+ /**
52
+ * Read a custom LangGraph state key from the current thread. Mirrors
53
+ * `useStream().values[key]` from `@langchain/react` and updates when the
54
+ * stream emits new state.
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * const todos = useLangChainState<Todo[]>("todos");
59
+ * const files = useLangChainState<Record<string, string>>("files", {});
60
+ * ```
61
+ */
62
+ export declare function useLangChainState<T>(key: string): T | undefined;
63
+ export declare function useLangChainState<T>(key: string, defaultValue: T): T;
51
64
  //# sourceMappingURL=useStreamRuntime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStreamRuntime.d.ts","sourceRoot":"","sources":["../src/useStreamRuntime.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AA4BpE,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,GAAG;IACvD,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,EACL;QACE,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;QAC5C,MAAM,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;QAC5C,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;KACxC,GACD,SAAS,CAAC;IACd,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,CAAC;AAoKF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gBAAgB,GAAI,uBAG9B,uBAAuB,kDAYzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;YA/OhB,OAAO;aAqP7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,SAG3B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EAClD,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAMpC,CAAC"}
1
+ {"version":3,"file":"useStreamRuntime.d.ts","sourceRoot":"","sources":["../src/useStreamRuntime.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AA6BpE,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,GAAG;IACvD,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,EACL;QACE,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;QAC5C,MAAM,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;QAC5C,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;KACxC,GACD,SAAS,CAAC;IACd,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,CAAC;AA8KF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gBAAgB,GAAI,uBAG9B,uBAAuB,kDAazB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;YA3PhB,OAAO;aAiQ7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,SAG3B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EAClD,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAMpC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;AACjE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC"}
@@ -51,26 +51,33 @@ const getMessageContent = (msg) => {
51
51
  return content;
52
52
  };
53
53
  const useStreamThreadRuntime = ({ adapters, messagesKey = "messages", ...streamOptions }) => {
54
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
54
55
  const externalId = useAuiState((s) => s.threadListItem.externalId);
56
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
55
57
  const stream = useStream({
56
58
  ...streamOptions,
57
59
  threadId: externalId,
58
60
  });
61
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
59
62
  const [toolStatuses, setToolStatuses] = useState({});
60
63
  const hasExecutingTools = Object.values(toolStatuses).some((s) => s?.type === "executing");
61
64
  const effectiveIsRunning = stream.isLoading || hasExecutingTools;
65
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
62
66
  const threadMessages = useExternalMessageConverter({
63
67
  callback: convertLangChainBaseMessage,
64
68
  messages: stream.messages,
65
69
  isRunning: effectiveIsRunning,
66
70
  });
71
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
67
72
  const [runtimeRef] = useState(() => ({
68
73
  get current() {
69
74
  return runtime;
70
75
  },
71
76
  }));
77
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
72
78
  const streamRef = useRef(stream);
73
79
  streamRef.current = stream;
80
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
74
81
  const toolInvocations = useToolInvocations({
75
82
  state: {
76
83
  messages: threadMessages,
@@ -94,12 +101,15 @@ const useStreamThreadRuntime = ({ adapters, messagesKey = "messages", ...streamO
94
101
  },
95
102
  setToolStatuses,
96
103
  });
104
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
97
105
  const extras = useMemo(() => ({
98
106
  [symbolLangChainRuntimeExtras]: true,
99
107
  interrupt: stream.interrupt,
100
108
  interrupts: stream.interrupts,
101
109
  submit: stream.submit,
102
- }), [stream.interrupt, stream.interrupts, stream.submit]);
110
+ values: stream.values,
111
+ }), [stream.interrupt, stream.interrupts, stream.submit, stream.values]);
112
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
103
113
  const runtime = useExternalStoreRuntime({
104
114
  isRunning: effectiveIsRunning,
105
115
  messages: threadMessages,
@@ -163,6 +173,7 @@ export const useStreamRuntime = ({ cloud, ...options }) => {
163
173
  const cloudAdapter = useCloudThreadListAdapter({ cloud });
164
174
  return useRemoteThreadListRuntime({
165
175
  runtimeHook: function RuntimeHook() {
176
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
166
177
  return useStreamThreadRuntime(optionsRef.current);
167
178
  },
168
179
  adapter: cloudAdapter,
@@ -193,4 +204,13 @@ export const useLangChainSubmit = () => {
193
204
  return submit(values, options);
194
205
  };
195
206
  };
207
+ export function useLangChainState(key, defaultValue) {
208
+ return useAuiState((s) => {
209
+ const extras = s.thread.extras;
210
+ if (!extras)
211
+ return defaultValue;
212
+ const value = asLangChainRuntimeExtras(extras).values[key];
213
+ return value !== undefined ? value : defaultValue;
214
+ });
215
+ }
196
216
  //# sourceMappingURL=useStreamRuntime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStreamRuntime.js","sourceRoot":"","sources":["../src/useStreamRuntime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useStreamRuntime.js","sourceRoot":"","sources":["../src/useStreamRuntime.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-langchain",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "LangChain useStream adapter for assistant-ui",
5
5
  "keywords": [
6
6
  "langchain",
@@ -29,10 +29,10 @@
29
29
  ],
30
30
  "sideEffects": false,
31
31
  "dependencies": {
32
- "@assistant-ui/core": "^0.1.14",
33
- "@assistant-ui/store": "^0.2.7",
32
+ "@assistant-ui/core": "^0.1.15",
33
+ "@assistant-ui/store": "^0.2.8",
34
34
  "assistant-cloud": "*",
35
- "assistant-stream": "^0.3.11"
35
+ "assistant-stream": "^0.3.12"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@langchain/react": "^0.3.3",
@@ -45,12 +45,15 @@
45
45
  }
46
46
  },
47
47
  "devDependencies": {
48
- "@langchain/core": "^1.1.39",
49
- "@langchain/langgraph-sdk": "^1.8.8",
48
+ "@langchain/core": "^1.1.40",
49
+ "@langchain/langgraph-sdk": "^1.8.9",
50
50
  "@langchain/react": "^0.3.3",
51
+ "@testing-library/react": "^16.3.2",
51
52
  "@types/react": "^19.2.14",
53
+ "jsdom": "^29.0.2",
52
54
  "react": "^19.2.5",
53
- "@assistant-ui/x-buildutils": "0.0.5"
55
+ "vitest": "^4.1.5",
56
+ "@assistant-ui/x-buildutils": "0.0.6"
54
57
  },
55
58
  "publishConfig": {
56
59
  "access": "public",
@@ -66,6 +69,8 @@
66
69
  "url": "https://github.com/assistant-ui/assistant-ui/issues"
67
70
  },
68
71
  "scripts": {
69
- "build": "aui-build"
72
+ "build": "aui-build",
73
+ "test": "vitest run",
74
+ "test:watch": "vitest"
70
75
  }
71
76
  }
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export {
2
2
  useStreamRuntime,
3
3
  useLangChainInterruptState,
4
+ useLangChainState,
4
5
  useLangChainSubmit,
5
6
  } from "./useStreamRuntime";
6
7
  export type { UseStreamRuntimeOptions } from "./useStreamRuntime";
@@ -0,0 +1,92 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { renderHook } from "@testing-library/react";
5
+
6
+ type Selector = (state: unknown) => unknown;
7
+ const { mockUseAuiState } = vi.hoisted(() => ({
8
+ mockUseAuiState: vi.fn(),
9
+ }));
10
+
11
+ vi.mock(import("@assistant-ui/store"), async (importOriginal) => {
12
+ const actual = await importOriginal();
13
+ return {
14
+ ...actual,
15
+ useAuiState: ((selector: Selector) =>
16
+ mockUseAuiState(selector)) as typeof actual.useAuiState,
17
+ useAui: (() => ({})) as unknown as typeof actual.useAui,
18
+ };
19
+ });
20
+
21
+ import { useLangChainState } from "./useStreamRuntime";
22
+
23
+ // The real guard symbol in useStreamRuntime is module-private. To stand in for
24
+ // runtime-produced extras, we use a Proxy whose `has` trap claims any symbol
25
+ // with the description "langchain-runtime-extras" is present.
26
+ const makeExtras = (values: Record<string, unknown>) =>
27
+ new Proxy(
28
+ { values },
29
+ {
30
+ has: (target, key) =>
31
+ (typeof key === "symbol" &&
32
+ key.description === "langchain-runtime-extras") ||
33
+ Reflect.has(target, key),
34
+ },
35
+ );
36
+
37
+ const runSelectorAgainst = (extras: unknown) => {
38
+ mockUseAuiState.mockImplementationOnce((selector: Selector) =>
39
+ selector({ thread: { extras } }),
40
+ );
41
+ };
42
+
43
+ describe("useLangChainState", () => {
44
+ it("returns undefined when extras are absent", () => {
45
+ runSelectorAgainst(undefined);
46
+ const { result } = renderHook(() => useLangChainState<number>("count"));
47
+ expect(result.current).toBeUndefined();
48
+ });
49
+
50
+ it("returns defaultValue when extras are absent", () => {
51
+ runSelectorAgainst(undefined);
52
+ const { result } = renderHook(() => useLangChainState<number>("count", 42));
53
+ expect(result.current).toBe(42);
54
+ });
55
+
56
+ it("reads the value for the given key from extras.values", () => {
57
+ runSelectorAgainst(makeExtras({ todos: [{ id: "a" }], count: 7 }));
58
+ const { result } = renderHook(() =>
59
+ useLangChainState<Array<{ id: string }>>("todos"),
60
+ );
61
+ expect(result.current).toEqual([{ id: "a" }]);
62
+ });
63
+
64
+ it("falls back to defaultValue when the key is missing from values", () => {
65
+ runSelectorAgainst(makeExtras({ unrelated: "x" }));
66
+ const { result } = renderHook(() => useLangChainState<number>("count", 99));
67
+ expect(result.current).toBe(99);
68
+ });
69
+
70
+ it("returns undefined when the key is missing and no default is given", () => {
71
+ runSelectorAgainst(makeExtras({ unrelated: "x" }));
72
+ const { result } = renderHook(() => useLangChainState<number>("count"));
73
+ expect(result.current).toBeUndefined();
74
+ });
75
+
76
+ it("returns the stored value (not default) when both are present", () => {
77
+ runSelectorAgainst(makeExtras({ count: 0 }));
78
+ const { result } = renderHook(() => useLangChainState<number>("count", 99));
79
+ // 0 is a valid value; must be preserved over the default.
80
+ expect(result.current).toBe(0);
81
+ });
82
+
83
+ it("preserves explicit null over defaultValue", () => {
84
+ runSelectorAgainst(makeExtras({ flag: null }));
85
+ const { result } = renderHook(() =>
86
+ useLangChainState<string | null>("flag", "default"),
87
+ );
88
+ // LangGraph treats null as an explicit "cleared" value distinct
89
+ // from a missing key; the hook must not conflate them.
90
+ expect(result.current).toBeNull();
91
+ });
92
+ });
@@ -31,6 +31,7 @@ type LangChainRuntimeExtras = {
31
31
  values: Record<string, unknown> | null | undefined,
32
32
  options?: Record<string, unknown>,
33
33
  ) => Promise<void>;
34
+ values: Record<string, unknown>;
34
35
  };
35
36
 
36
37
  const asLangChainRuntimeExtras = (extras: unknown): LangChainRuntimeExtras => {
@@ -110,15 +111,18 @@ const useStreamThreadRuntime = ({
110
111
  messagesKey = "messages",
111
112
  ...streamOptions
112
113
  }: Omit<UseStreamRuntimeOptions, "cloud">) => {
114
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
113
115
  const externalId = useAuiState((s) => s.threadListItem.externalId) as
114
116
  | string
115
117
  | null;
116
118
 
119
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
117
120
  const stream = useStream({
118
121
  ...streamOptions,
119
122
  threadId: externalId,
120
123
  });
121
124
 
125
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
122
126
  const [toolStatuses, setToolStatuses] = useState<
123
127
  Record<string, ToolExecutionStatus>
124
128
  >({});
@@ -127,21 +131,25 @@ const useStreamThreadRuntime = ({
127
131
  );
128
132
  const effectiveIsRunning = stream.isLoading || hasExecutingTools;
129
133
 
134
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
130
135
  const threadMessages = useExternalMessageConverter({
131
136
  callback: convertLangChainBaseMessage,
132
137
  messages: stream.messages as LangChainBaseMessage[],
133
138
  isRunning: effectiveIsRunning,
134
139
  });
135
140
 
141
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
136
142
  const [runtimeRef] = useState(() => ({
137
143
  get current() {
138
144
  return runtime;
139
145
  },
140
146
  }));
141
147
 
148
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
142
149
  const streamRef = useRef(stream);
143
150
  streamRef.current = stream;
144
151
 
152
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
145
153
  const toolInvocations = useToolInvocations({
146
154
  state: {
147
155
  messages: threadMessages,
@@ -169,16 +177,19 @@ const useStreamThreadRuntime = ({
169
177
  setToolStatuses,
170
178
  });
171
179
 
180
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
172
181
  const extras = useMemo(
173
182
  (): LangChainRuntimeExtras => ({
174
183
  [symbolLangChainRuntimeExtras]: true,
175
184
  interrupt: stream.interrupt,
176
185
  interrupts: stream.interrupts,
177
186
  submit: stream.submit,
187
+ values: stream.values,
178
188
  }),
179
- [stream.interrupt, stream.interrupts, stream.submit],
189
+ [stream.interrupt, stream.interrupts, stream.submit, stream.values],
180
190
  );
181
191
 
192
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
182
193
  const runtime = useExternalStoreRuntime({
183
194
  isRunning: effectiveIsRunning,
184
195
  messages: threadMessages,
@@ -254,6 +265,7 @@ export const useStreamRuntime = ({
254
265
  const cloudAdapter = useCloudThreadListAdapter({ cloud });
255
266
  return useRemoteThreadListRuntime({
256
267
  runtimeHook: function RuntimeHook() {
268
+ // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
257
269
  return useStreamThreadRuntime(optionsRef.current);
258
270
  },
259
271
  adapter: cloudAdapter,
@@ -288,3 +300,28 @@ export const useLangChainSubmit = () => {
288
300
  return submit(values, options);
289
301
  };
290
302
  };
303
+
304
+ /**
305
+ * Read a custom LangGraph state key from the current thread. Mirrors
306
+ * `useStream().values[key]` from `@langchain/react` and updates when the
307
+ * stream emits new state.
308
+ *
309
+ * @example
310
+ * ```tsx
311
+ * const todos = useLangChainState<Todo[]>("todos");
312
+ * const files = useLangChainState<Record<string, string>>("files", {});
313
+ * ```
314
+ */
315
+ export function useLangChainState<T>(key: string): T | undefined;
316
+ export function useLangChainState<T>(key: string, defaultValue: T): T;
317
+ export function useLangChainState<T>(
318
+ key: string,
319
+ defaultValue?: T,
320
+ ): T | undefined {
321
+ return useAuiState((s) => {
322
+ const extras = s.thread.extras;
323
+ if (!extras) return defaultValue;
324
+ const value = asLangChainRuntimeExtras(extras).values[key] as T | undefined;
325
+ return value !== undefined ? value : defaultValue;
326
+ });
327
+ }