langgraph-ui-components 0.0.25 → 0.0.27
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 +412 -51
- package/dist/_virtual/index.cjs6.js +1 -1
- package/dist/_virtual/index.cjs8.js +1 -1
- package/dist/_virtual/index.es6.js +2 -2
- package/dist/_virtual/index.es8.js +2 -2
- package/dist/assets/langgraph-ui-components.css +1 -1
- package/dist/components/ChatBody.cjs.js +2 -2
- package/dist/components/ChatBody.cjs.js.map +1 -1
- package/dist/components/ChatBody.d.ts.map +1 -1
- package/dist/components/ChatBody.es.js +137 -98
- package/dist/components/ChatBody.es.js.map +1 -1
- package/dist/components/messages/AgentMessage.cjs.js +3 -1
- package/dist/components/messages/AgentMessage.cjs.js.map +1 -1
- package/dist/components/messages/AgentMessage.d.ts +3 -1
- package/dist/components/messages/AgentMessage.d.ts.map +1 -1
- package/dist/components/messages/AgentMessage.es.js +197 -112
- package/dist/components/messages/AgentMessage.es.js.map +1 -1
- package/dist/entries/components.cjs.js +1 -1
- package/dist/entries/components.d.ts.map +1 -1
- package/dist/entries/components.es.js +4 -5
- package/dist/entries/components.es.js.map +1 -1
- package/dist/entries/hooks.cjs.js +1 -1
- package/dist/entries/hooks.d.ts.map +1 -1
- package/dist/entries/hooks.es.js +5 -6
- package/dist/entries/hooks.es.js.map +1 -1
- package/dist/entries/providers.cjs.js +1 -1
- package/dist/entries/providers.d.ts +1 -1
- package/dist/entries/providers.d.ts.map +1 -1
- package/dist/entries/providers.es.js +18 -19
- package/dist/entries/providers.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +28 -29
- package/dist/index.es.js.map +1 -1
- package/dist/node_modules/.pnpm/eventemitter3@4.0.7/node_modules/eventemitter3/index.cjs.js +1 -1
- package/dist/node_modules/.pnpm/eventemitter3@4.0.7/node_modules/eventemitter3/index.es.js +1 -1
- package/dist/node_modules/.pnpm/p-timeout@3.2.0/node_modules/p-timeout/index.cjs.js +1 -1
- package/dist/node_modules/.pnpm/p-timeout@3.2.0/node_modules/p-timeout/index.es.js +1 -1
- package/dist/node_modules/.pnpm/react-syntax-highlighter@16.1.0_react@19.2.3/node_modules/react-syntax-highlighter/dist/cjs/styles/prism/index.cjs.js +1 -1
- package/dist/node_modules/.pnpm/react-syntax-highlighter@16.1.0_react@19.2.3/node_modules/react-syntax-highlighter/dist/cjs/styles/prism/index.es.js +1 -1
- package/dist/providers/ChatProvider.cjs.js +1 -1
- package/dist/providers/ChatProvider.cjs.js.map +1 -1
- package/dist/providers/ChatProvider.d.ts +17 -1
- package/dist/providers/ChatProvider.d.ts.map +1 -1
- package/dist/providers/ChatProvider.es.js +18 -17
- package/dist/providers/ChatProvider.es.js.map +1 -1
- package/dist/providers/ChatRuntime.es.js +4 -4
- package/dist/providers/CustomComponentProvider.cjs.js +1 -1
- package/dist/providers/CustomComponentProvider.cjs.js.map +1 -1
- package/dist/providers/CustomComponentProvider.d.ts +11 -0
- package/dist/providers/CustomComponentProvider.d.ts.map +1 -1
- package/dist/providers/CustomComponentProvider.es.js +51 -35
- package/dist/providers/CustomComponentProvider.es.js.map +1 -1
- package/dist/providers/Stream.cjs.js +1 -1
- package/dist/providers/Stream.cjs.js.map +1 -1
- package/dist/providers/Stream.d.ts.map +1 -1
- package/dist/providers/Stream.es.js +113 -94
- package/dist/providers/Stream.es.js.map +1 -1
- package/dist/providers/Thread.cjs.js +1 -1
- package/dist/providers/Thread.cjs.js.map +1 -1
- package/dist/providers/Thread.d.ts +2 -1
- package/dist/providers/Thread.d.ts.map +1 -1
- package/dist/providers/Thread.es.js +19 -19
- package/dist/providers/Thread.es.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/ChatBody.tsx +88 -28
- package/src/components/messages/AgentMessage.tsx +281 -81
- package/src/entries/components.ts +0 -2
- package/src/entries/hooks.ts +0 -2
- package/src/entries/providers.ts +1 -3
- package/src/index.css +2 -2
- package/src/index.ts +1 -3
- package/src/providers/ChatProvider.tsx +18 -1
- package/src/providers/CustomComponentProvider.tsx +41 -0
- package/src/providers/Stream.tsx +34 -15
- package/src/providers/Thread.tsx +2 -2
- package/dist/components/ToolCallFunctions.cjs.js +0 -2
- package/dist/components/ToolCallFunctions.cjs.js.map +0 -1
- package/dist/components/ToolCallFunctions.es.js +0 -75
- package/dist/components/ToolCallFunctions.es.js.map +0 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ A React component library for building AI chat interfaces with LangChain/LangGra
|
|
|
12
12
|
- 🧩 **Provider-based architecture** - Flexible state management with React Context
|
|
13
13
|
- 📝 **TypeScript** - Full type definitions included
|
|
14
14
|
- 🎨 **Tailwind CSS** - Pre-built styles, easy to customize
|
|
15
|
+
- 🛑 **Human-in-the-Loop (HITL)** - Built-in interrupt handling for agent approval flows
|
|
15
16
|
|
|
16
17
|
## Installation
|
|
17
18
|
|
|
@@ -136,8 +137,10 @@ import { Chat } from 'langgraph-ui-components/components';
|
|
|
136
137
|
|
|
137
138
|
**Props:**
|
|
138
139
|
- `enableToolCallIndicator?: boolean` - Show visual indicators when AI tools are being executed. Default: `false`
|
|
139
|
-
- `callThisOnSubmit?: () => Promise<
|
|
140
|
+
- `callThisOnSubmit?: () => Promise<CallThisOnSubmitResponse | void>` - Custom callback executed before message submission, useful for uploading files to external storage. Return `{ files, contextValues }` to attach files or inject context into the message.
|
|
140
141
|
- `handleFileSelect?: (event: React.ChangeEvent<HTMLInputElement>) => void` - Custom file selection handler to override default behavior
|
|
142
|
+
- `inputFileAccept?: string` - File types accepted by the file input (e.g. `"image/*,.pdf"`)
|
|
143
|
+
- `chatBodyProps?: chatBodyProps` - Customize agent name, avatar, and font size (see [chatBodyProps](#chatbodyprops))
|
|
141
144
|
|
|
142
145
|
### Sidebar Component
|
|
143
146
|
|
|
@@ -164,27 +167,36 @@ import { Sidebar } from 'langgraph-ui-components/components';
|
|
|
164
167
|
- `leftPanelContent?: React.ReactNode` - Custom content to display in the left expansion panel
|
|
165
168
|
- `leftPanelOpen?: boolean` - External control for left panel open state
|
|
166
169
|
- `setLeftPanelOpen?: (open: boolean) => void` - External setter for left panel open state
|
|
170
|
+
- `leftPanelInitialWidth?: number` - Initial width of the left panel in pixels
|
|
171
|
+
- `leftPanelClassName?: string` - CSS class name for the left panel container
|
|
172
|
+
- `banner?: React.ReactNode` - Optional banner rendered above the chat messages (e.g. an alert or notice)
|
|
173
|
+
- `filePreview?: (files: FileInfo[], setFileInput) => React.ReactNode` - Custom file preview renderer for selected files before submission
|
|
174
|
+
- `inputFileAccept?: string` - File types accepted by the file input (e.g. `"image/*,.pdf"`)
|
|
175
|
+
- `s3_upload?: boolean` - Enable S3 upload mode for file attachments
|
|
167
176
|
|
|
168
177
|
## Exported Providers
|
|
169
178
|
|
|
170
|
-
- `ChatProvider` - Core chat state management
|
|
179
|
+
- `ChatProvider` - Core chat state management. Props: `apiUrl`, `assistantId`, `identity?`, `initialMode?` (`"single"` | `"multi"`, default `"single"`), `customComponents?`, `suspenseFallback?`
|
|
171
180
|
- `ChatRuntimeProvider` - Runtime configuration
|
|
172
|
-
- `ThreadProvider` - Conversation thread management
|
|
181
|
+
- `ThreadProvider` - Conversation thread management. Props: `initialMode?` (`"single"` | `"multi"`, default `"single"`)
|
|
173
182
|
- `StreamProvider` - AI streaming responses
|
|
174
183
|
- `FileProvider` - File upload handling
|
|
175
184
|
- `CustomComponentProvider` - Custom component rendering
|
|
176
185
|
|
|
177
186
|
## Exported Hooks
|
|
178
187
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
All from `langgraph-ui-components/providers` unless noted:
|
|
189
|
+
|
|
190
|
+
| Hook | Description |
|
|
191
|
+
|------|-------------|
|
|
192
|
+
| `useStreamContext()` | Messages, loading state, sendMessage, stop, interrupt — [details](#usestreamcontext) |
|
|
193
|
+
| `useThread()` | Thread ID, thread list, deleteThread, updateThread, mode — [details](#usethread) |
|
|
194
|
+
| `useChatRuntime()` | apiUrl, assistantId, setAssistantId, identity — [details](#usechatruntime) |
|
|
195
|
+
| `useFileProvider()` | `fileInput: FileInfo[]` and `setFileInput` |
|
|
196
|
+
| `useCustomComponents()` | Register generative UI and interrupt components — [details](#custom-components) |
|
|
197
|
+
| `useChatSuggestions()` | Opt-in chat suggestions — [details](#usechatsuggestions-hook) |
|
|
198
|
+
| `useTools()` *(hooks)* | Sidebar tool buttons — [details](#usetools) |
|
|
199
|
+
| `useModels()` *(hooks)* | Model list and selection — [details](#usemodels) |
|
|
188
200
|
|
|
189
201
|
## useChatSuggestions Hook
|
|
190
202
|
|
|
@@ -200,7 +212,7 @@ The `useChatSuggestions` hook enables intelligent, opt-in chat suggestions for y
|
|
|
200
212
|
### Basic Usage
|
|
201
213
|
|
|
202
214
|
```tsx
|
|
203
|
-
import { useChatSuggestions } from 'langgraph-ui-components/
|
|
215
|
+
import { useChatSuggestions } from 'langgraph-ui-components/providers';
|
|
204
216
|
|
|
205
217
|
function MyComponent() {
|
|
206
218
|
// Simply call the hook - it registers configuration internally
|
|
@@ -261,41 +273,246 @@ function ChatInterface() {
|
|
|
261
273
|
|
|
262
274
|
When dependencies change, suggestions are regenerated to match the new context.
|
|
263
275
|
|
|
264
|
-
##
|
|
276
|
+
## useStreamContext
|
|
265
277
|
|
|
266
|
-
|
|
278
|
+
Access the full streaming state and control functions from anywhere inside the provider tree.
|
|
267
279
|
|
|
268
|
-
|
|
280
|
+
```tsx
|
|
281
|
+
import { useStreamContext } from 'langgraph-ui-components/providers';
|
|
282
|
+
|
|
283
|
+
const {
|
|
284
|
+
messages, // Message[] — all messages in the conversation
|
|
285
|
+
isLoading, // boolean — true while agent is streaming
|
|
286
|
+
interrupt, // interrupt payload when agent pauses for human input
|
|
287
|
+
sendMessage, // send a message programmatically
|
|
288
|
+
submitMessage, // low-level submit with stream control options
|
|
289
|
+
regenerateMessage, // regenerate an AI response by message ID
|
|
290
|
+
fetchCatalog, // fetch available agents from /agents/catalog
|
|
291
|
+
stop, // cancel the current stream
|
|
292
|
+
} = useStreamContext();
|
|
293
|
+
```
|
|
269
294
|
|
|
270
|
-
|
|
271
|
-
- `options` (optional object):
|
|
272
|
-
- `type` (Message["type"], optional): The message type to use when sending a string message. Defaults to "human" for user messages. Use "system" for agent-only messages.
|
|
273
|
-
- `config` (any, optional): Additional configuration to pass to the agent.
|
|
295
|
+
### sendMessage
|
|
274
296
|
|
|
275
|
-
|
|
297
|
+
Send a message programmatically. The message is appended to the conversation and submitted to the agent.
|
|
276
298
|
|
|
277
299
|
```tsx
|
|
278
|
-
|
|
300
|
+
// Simple string
|
|
301
|
+
await sendMessage("Hello!");
|
|
302
|
+
|
|
303
|
+
// With options
|
|
304
|
+
await sendMessage("Hello!", {
|
|
305
|
+
type: "human", // message type, defaults to "human"
|
|
306
|
+
hidden: true, // hide from UI (useful for system-level triggers)
|
|
307
|
+
id: "custom-id", // custom message ID instead of auto-generated UUID
|
|
308
|
+
context: { key: "val" }, // extra context merged with identity
|
|
309
|
+
additional_kwargs: {}, // custom metadata attached to the message
|
|
310
|
+
});
|
|
311
|
+
```
|
|
279
312
|
|
|
280
|
-
|
|
281
|
-
|
|
313
|
+
| Option | Type | Description |
|
|
314
|
+
|--------|------|-------------|
|
|
315
|
+
| `type` | `Message["type"]` | Message type (`"human"`, `"system"`, etc.). Default: `"human"` |
|
|
316
|
+
| `hidden` | `boolean` | If `true`, message is not shown in the chat UI |
|
|
317
|
+
| `id` | `string` | Custom message ID (auto-generated UUID if omitted) |
|
|
318
|
+
| `name` | `string` | Required for function/tool messages |
|
|
319
|
+
| `tool_call_id` | `string` | ID linking this message to a tool call |
|
|
320
|
+
| `tool_calls` | `ToolCall[]` | Tool calls to attach to the message |
|
|
321
|
+
| `additional_kwargs` | `Record<string, unknown>` | Custom metadata on the message |
|
|
322
|
+
| `ui` | `UIMessage[]` | UI components to display alongside the message |
|
|
323
|
+
| `context` | `Record<string, unknown>` | Context values merged with identity for this message |
|
|
282
324
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
325
|
+
### submitMessage
|
|
326
|
+
|
|
327
|
+
Low-level submit with full control over streaming behavior. Use this when you need non-default stream modes.
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
await submitMessage(messageObject, {
|
|
331
|
+
streamMode: ["values", "updates"], // which stream modes to use
|
|
332
|
+
streamSubgraphs: true, // include subgraph updates
|
|
333
|
+
streamResumable: true, // allow stream resumption
|
|
334
|
+
contextValues: { user_role: "admin" }, // extra context for this call
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### regenerateMessage
|
|
339
|
+
|
|
340
|
+
Regenerate an AI response. Resumes from the checkpoint before the given message ID.
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
await regenerateMessage(messageId);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### fetchCatalog
|
|
347
|
+
|
|
348
|
+
Fetch the list of available agents from your API's `/agents/catalog` endpoint.
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
const catalog = await fetchCatalog();
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### stop
|
|
355
|
+
|
|
356
|
+
Cancel the currently active stream.
|
|
357
|
+
|
|
358
|
+
```tsx
|
|
359
|
+
const { stop, isLoading } = useStreamContext();
|
|
360
|
+
|
|
361
|
+
<button onClick={stop} disabled={!isLoading}>Stop</button>
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## useThread
|
|
365
|
+
|
|
366
|
+
Access and manage conversation threads.
|
|
367
|
+
|
|
368
|
+
```tsx
|
|
369
|
+
import { useThread } from 'langgraph-ui-components/providers';
|
|
370
|
+
|
|
371
|
+
const {
|
|
372
|
+
threadId, // string | null — current thread ID
|
|
373
|
+
setThreadId, // switch to a different thread
|
|
374
|
+
threads, // Thread[] — list of all threads
|
|
375
|
+
getThreads, // fetch threads from API
|
|
376
|
+
setThreads, // directly update thread list
|
|
377
|
+
configuration, // ThreadConfiguration — config passed to LangGraph on each call
|
|
378
|
+
setConfiguration, // update thread configuration
|
|
379
|
+
mode, // "single" | "multi"
|
|
380
|
+
setMode, // switch between single and multi-thread modes
|
|
381
|
+
threadsLoading, // boolean — true while fetching thread list
|
|
382
|
+
deleteThread, // delete a thread by ID
|
|
383
|
+
updateThread, // update thread metadata
|
|
384
|
+
} = useThread();
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### deleteThread
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
await deleteThread(threadId);
|
|
391
|
+
// Removes thread from list and clears current threadId if it was the active one
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### updateThread
|
|
395
|
+
|
|
396
|
+
```tsx
|
|
397
|
+
await updateThread(threadId, { title: "My conversation" });
|
|
398
|
+
// Updates metadata on the thread and refreshes the thread list
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Thread Configuration
|
|
402
|
+
|
|
403
|
+
`configuration` is a free-form object passed to the LangGraph API on every stream call. Use it to send per-thread settings your agent reads from `config.configurable`:
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
const { setConfiguration } = useThread();
|
|
407
|
+
|
|
408
|
+
setConfiguration({
|
|
409
|
+
temperature: 0.7,
|
|
410
|
+
system_prompt: "You are a helpful assistant.",
|
|
411
|
+
});
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### URL-based Thread Loading
|
|
415
|
+
|
|
416
|
+
Append `?thread=<threadId>` to the page URL to automatically load a specific thread on mount:
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
https://yourapp.com/chat?thread=abc123
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## useChatRuntime
|
|
423
|
+
|
|
424
|
+
Access and update the core runtime configuration.
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
import { useChatRuntime } from 'langgraph-ui-components/providers';
|
|
428
|
+
|
|
429
|
+
const {
|
|
430
|
+
apiUrl, // string — base API URL
|
|
431
|
+
assistantId, // string — current assistant/graph ID
|
|
432
|
+
setAssistantId, // switch to a different assistant at runtime
|
|
433
|
+
identity, // ChatIdentity | null | undefined
|
|
434
|
+
} = useChatRuntime();
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
`setAssistantId` is useful when your app lets users pick which agent to talk to:
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
const { setAssistantId } = useChatRuntime();
|
|
441
|
+
|
|
442
|
+
<button onClick={() => setAssistantId("support_agent")}>Switch to Support</button>
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## useTools
|
|
446
|
+
|
|
447
|
+
Manage the sidebar tool buttons (the icon strip on the left panel).
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
import { useTools } from 'langgraph-ui-components/hooks';
|
|
451
|
+
|
|
452
|
+
const {
|
|
453
|
+
tool, // CustomTool[] — built-in tools (Search, Chat)
|
|
454
|
+
addTool, // add a custom tool button
|
|
455
|
+
userDefinedTools, // CustomTool[] — tools added via addTool
|
|
456
|
+
setUserDefinedTools, // directly replace user-defined tools
|
|
457
|
+
} = useTools();
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Adding a Custom Tool
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
import { useTools } from 'langgraph-ui-components/hooks';
|
|
464
|
+
import { Download } from 'lucide-react';
|
|
465
|
+
|
|
466
|
+
function MyApp() {
|
|
467
|
+
const { addTool } = useTools();
|
|
286
468
|
|
|
287
|
-
|
|
469
|
+
useEffect(() => {
|
|
470
|
+
addTool({
|
|
471
|
+
label: "Export",
|
|
472
|
+
icon: <Download />,
|
|
473
|
+
alt: "Export conversation", // tooltip text
|
|
474
|
+
onClick: () => handleExport(),
|
|
475
|
+
});
|
|
476
|
+
}, []);
|
|
288
477
|
}
|
|
289
478
|
```
|
|
290
479
|
|
|
291
|
-
|
|
480
|
+
### CustomTool Type
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
type CustomTool = {
|
|
484
|
+
label: string; // display name
|
|
485
|
+
icon: React.ReactElement; // icon component (e.g. from lucide-react)
|
|
486
|
+
alt?: string; // tooltip text
|
|
487
|
+
onClick: () => void; // click handler
|
|
488
|
+
};
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## useModels
|
|
292
492
|
|
|
293
|
-
|
|
493
|
+
Fetch and manage model selection. Calls `GET /agents/models` on mount and persists the selection to `localStorage`.
|
|
494
|
+
|
|
495
|
+
```tsx
|
|
496
|
+
import { useModels } from 'langgraph-ui-components/hooks';
|
|
497
|
+
|
|
498
|
+
const {
|
|
499
|
+
models, // ModelOption[] — available models
|
|
500
|
+
selectedModel, // string — currently selected model ID
|
|
501
|
+
setSelectedModel, // update selection (also persists to localStorage)
|
|
502
|
+
loading, // boolean — true while fetching
|
|
503
|
+
} = useModels();
|
|
504
|
+
```
|
|
294
505
|
|
|
295
506
|
```tsx
|
|
296
|
-
|
|
507
|
+
// ModelOption type
|
|
508
|
+
type ModelOption = {
|
|
509
|
+
id: string;
|
|
510
|
+
name: string;
|
|
511
|
+
};
|
|
297
512
|
```
|
|
298
513
|
|
|
514
|
+
Models with "embed" or "rerank" in their ID are automatically filtered out. Selection persists under the localStorage key `"agent-chat:selected-model"` and is safe for SSR environments.
|
|
515
|
+
|
|
299
516
|
## Custom Components
|
|
300
517
|
|
|
301
518
|
You can inject custom React components into chat messages using the `CustomComponentProvider`. Components are registered by name and can be referenced in message content.
|
|
@@ -327,7 +544,7 @@ function App() {
|
|
|
327
544
|
Use the `registerComponent` method from the `useCustomComponents` hook:
|
|
328
545
|
|
|
329
546
|
```tsx
|
|
330
|
-
import { useCustomComponents } from 'langgraph-ui-components/
|
|
547
|
+
import { useCustomComponents } from 'langgraph-ui-components/providers';
|
|
331
548
|
|
|
332
549
|
function RegisterComponent() {
|
|
333
550
|
const { registerComponent } = useCustomComponents();
|
|
@@ -345,28 +562,172 @@ function RegisterComponent() {
|
|
|
345
562
|
- `registerComponents(components)`: Register multiple components at once.
|
|
346
563
|
- `unregisterComponent(name)`: Remove a registered component.
|
|
347
564
|
|
|
565
|
+
## Human-in-the-Loop (HITL) Interrupts
|
|
566
|
+
|
|
567
|
+
LangGraph agents can pause mid-execution and ask a human to review or approve an action before continuing. This library has built-in support for rendering these interrupt requests with custom UI.
|
|
568
|
+
|
|
569
|
+
### How It Works
|
|
570
|
+
|
|
571
|
+
1. Your agent raises an interrupt with an `actionRequests` payload
|
|
572
|
+
2. The library detects `stream.interrupt` and looks up a registered interrupt component by **tool name**
|
|
573
|
+
3. Your component receives the interrupt data and action callbacks
|
|
574
|
+
4. Calling one of the action callbacks resumes the agent
|
|
575
|
+
|
|
576
|
+
### Agent-side Interrupt Format
|
|
577
|
+
|
|
578
|
+
Your LangGraph agent should raise an interrupt with this shape:
|
|
579
|
+
|
|
580
|
+
```python
|
|
581
|
+
from langgraph.types import interrupt
|
|
582
|
+
|
|
583
|
+
interrupt({
|
|
584
|
+
"actionRequests": [
|
|
585
|
+
{
|
|
586
|
+
"name": "send_email", # must match the name you register
|
|
587
|
+
"args": {"to": "user@example.com", "subject": "Hello"},
|
|
588
|
+
"description": "Send a welcome email" # optional
|
|
589
|
+
}
|
|
590
|
+
],
|
|
591
|
+
"reviewConfigs": [
|
|
592
|
+
{
|
|
593
|
+
"actionName": "send_email",
|
|
594
|
+
"allowedDecisions": ["approve", "reject", "edit"]
|
|
595
|
+
}
|
|
596
|
+
]
|
|
597
|
+
})
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Registering an Interrupt Component
|
|
601
|
+
|
|
602
|
+
Use `registerInterruptComponent` from `useCustomComponents()` to register a component for a specific tool name:
|
|
603
|
+
|
|
604
|
+
```tsx
|
|
605
|
+
import { useCustomComponents } from 'langgraph-ui-components/providers';
|
|
606
|
+
import type { InterruptComponentProps } from 'langgraph-ui-components/providers';
|
|
607
|
+
import { useEffect } from 'react';
|
|
608
|
+
|
|
609
|
+
function SendEmailInterrupt({ interrupt, actions }: InterruptComponentProps) {
|
|
610
|
+
const request = interrupt.actionRequests[0];
|
|
611
|
+
|
|
612
|
+
return (
|
|
613
|
+
<div className="border rounded p-4">
|
|
614
|
+
<h3>Approve Action: {request.name}</h3>
|
|
615
|
+
<pre>{JSON.stringify(request.args, null, 2)}</pre>
|
|
616
|
+
<div className="flex gap-2 mt-3">
|
|
617
|
+
<button onClick={() => actions.approve()}>Approve</button>
|
|
618
|
+
<button onClick={() => actions.reject("Not needed")}>Reject</button>
|
|
619
|
+
<button onClick={() => actions.edit({ subject: "Updated subject" })}>
|
|
620
|
+
Edit & Approve
|
|
621
|
+
</button>
|
|
622
|
+
</div>
|
|
623
|
+
</div>
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function App() {
|
|
628
|
+
const { registerInterruptComponent } = useCustomComponents();
|
|
629
|
+
|
|
630
|
+
useEffect(() => {
|
|
631
|
+
// Register for the tool name that matches your agent's interrupt
|
|
632
|
+
registerInterruptComponent('send_email', SendEmailInterrupt);
|
|
633
|
+
}, [registerInterruptComponent]);
|
|
634
|
+
|
|
635
|
+
return <Sidebar />;
|
|
636
|
+
}
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
Or register via `ChatProvider`'s `customComponents` if you prefer props-based setup (note: this is for generative UI components — for interrupts, use `registerInterruptComponent` as above).
|
|
640
|
+
|
|
641
|
+
### `InterruptComponentProps`
|
|
642
|
+
|
|
643
|
+
```typescript
|
|
644
|
+
interface InterruptComponentProps {
|
|
645
|
+
interrupt: {
|
|
646
|
+
actionRequests: Array<{
|
|
647
|
+
name: string;
|
|
648
|
+
args: Record<string, unknown>;
|
|
649
|
+
description?: string;
|
|
650
|
+
}>;
|
|
651
|
+
reviewConfigs: Array<{
|
|
652
|
+
actionName: string;
|
|
653
|
+
allowedDecisions: string[];
|
|
654
|
+
argsSchema?: Record<string, unknown>;
|
|
655
|
+
}>;
|
|
656
|
+
};
|
|
657
|
+
actions: {
|
|
658
|
+
/** Resume the agent with approval */
|
|
659
|
+
approve: () => void;
|
|
660
|
+
/** Resume the agent with rejection */
|
|
661
|
+
reject: (reason?: string) => void;
|
|
662
|
+
/** Resume the agent with edited arguments */
|
|
663
|
+
edit: (editedArgs: Record<string, unknown>) => void;
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
### `useCustomComponents` — Interrupt Methods
|
|
669
|
+
|
|
670
|
+
- `registerInterruptComponent(toolName, component)` — Register a component to render when the agent interrupts for the given tool name
|
|
671
|
+
- `unregisterInterruptComponent(toolName)` — Remove a registered interrupt component
|
|
672
|
+
|
|
673
|
+
### Accessing Interrupt State Directly
|
|
674
|
+
|
|
675
|
+
You can also access the raw interrupt from the stream context if you need to build custom logic:
|
|
676
|
+
|
|
677
|
+
```tsx
|
|
678
|
+
import { useStreamContext } from 'langgraph-ui-components/providers';
|
|
679
|
+
|
|
680
|
+
function MyComponent() {
|
|
681
|
+
const { interrupt, isLoading } = useStreamContext();
|
|
682
|
+
|
|
683
|
+
if (!isLoading && interrupt) {
|
|
684
|
+
console.log('Agent paused:', interrupt.value);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
## chatBodyProps
|
|
690
|
+
|
|
691
|
+
The `chatBodyProps` prop on both `Chat` and `Sidebar` customizes how agent messages are displayed:
|
|
692
|
+
|
|
693
|
+
```tsx
|
|
694
|
+
<Sidebar
|
|
695
|
+
chatBodyProps={{
|
|
696
|
+
agentName: "Aria",
|
|
697
|
+
agentAvatarUrl: "https://example.com/avatar.png",
|
|
698
|
+
fontSize: "15px",
|
|
699
|
+
}}
|
|
700
|
+
/>
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
**Props:**
|
|
704
|
+
- `agentName?: string` — Display name shown above agent messages. Default: `"Agent"`
|
|
705
|
+
- `agentAvatarUrl?: string` — URL for the agent avatar image
|
|
706
|
+
- `fontSize?: string` — Font size for message text (e.g. `"14px"`, `"1rem"`)
|
|
707
|
+
|
|
348
708
|
## Types
|
|
349
709
|
|
|
350
710
|
Full TypeScript definitions available for:
|
|
351
|
-
- `ChatIdentity`
|
|
352
|
-
- `ChatRuntimeContextValue`
|
|
353
|
-
- `FileInfo`
|
|
354
|
-
- `SuggestionsOptions`
|
|
355
|
-
- `SuggestionConfig`
|
|
356
|
-
- `ThreadMode`
|
|
357
|
-
- `ThreadConfiguration`
|
|
358
|
-
- `ThreadContextType`
|
|
359
|
-
- `StateType`
|
|
360
|
-
- `CustomComponentContextValue`
|
|
361
|
-
- `
|
|
362
|
-
- `
|
|
363
|
-
- `
|
|
364
|
-
- `
|
|
365
|
-
- `
|
|
366
|
-
- `
|
|
367
|
-
- `
|
|
368
|
-
- `
|
|
369
|
-
- `
|
|
711
|
+
- `ChatIdentity` — user/org identity + auth token
|
|
712
|
+
- `ChatRuntimeContextValue` — `useChatRuntime()` return type
|
|
713
|
+
- `FileInfo` — `{ fileName, fileType, file?, fileData?, metadata? }`
|
|
714
|
+
- `SuggestionsOptions` — options for `useChatSuggestions`
|
|
715
|
+
- `SuggestionConfig` — internal suggestion config shape
|
|
716
|
+
- `ThreadMode` — `"single" | "multi"`
|
|
717
|
+
- `ThreadConfiguration` — `Record<string, unknown>` passed to LangGraph config
|
|
718
|
+
- `ThreadContextType` — `useThread()` return type
|
|
719
|
+
- `StateType` — `{ messages, ui?, suggestions? }`
|
|
720
|
+
- `CustomComponentContextValue` — `useCustomComponents()` return type
|
|
721
|
+
- `InterruptComponentProps` — props for HITL interrupt components
|
|
722
|
+
- `CustomTool` — `{ label, icon, alt?, onClick }`
|
|
723
|
+
- `ModelOption` — `{ id, name }`
|
|
724
|
+
- `ChatProps` — base props shared by Chat and Sidebar
|
|
725
|
+
- `ChatSidebarProps` — Sidebar-specific props (extends ChatProps)
|
|
726
|
+
- `ChatUIProps` — Chat-specific props (extends ChatProps)
|
|
727
|
+
- `CallThisOnSubmitResponse` — `{ files?, contextValues? }`
|
|
728
|
+
- `chatBodyProps` — `{ agentName?, agentAvatarUrl?, fontSize? }`
|
|
729
|
+
- `headerProps` — `{ title?, logoUrl? }`
|
|
730
|
+
- `textToSpeechVoice` — `{ apiUrl, apiKey, model }`
|
|
370
731
|
|
|
371
732
|
## Keywords
|
|
372
733
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var e={
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var e={};exports.__exports=e;
|
|
2
2
|
//# sourceMappingURL=index.cjs6.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var e={};exports.
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var e={exports:{}};exports.__module=e;
|
|
2
2
|
//# sourceMappingURL=index.cjs8.js.map
|