@dremio/js-sdk 0.45.2 → 0.45.4

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.
Files changed (2) hide show
  1. package/README.md +208 -9
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -360,6 +360,43 @@ const history = await conversation.history();
360
360
  console.log(`Conversation has ${history.length} events`);
361
361
  ```
362
362
 
363
+ #### Stop a Run
364
+
365
+ Stop the currently active run for a conversation:
366
+
367
+ ```typescript
368
+ await conversation.stopRun(runId);
369
+ ```
370
+
371
+ Note: Only one run can be active per conversation at a time.
372
+
373
+ #### Clone a Conversation
374
+
375
+ Create a copy of the conversation instance:
376
+
377
+ ```typescript
378
+ const conversationCopy = conversation.clone();
379
+ ```
380
+
381
+ #### Serialize Conversation
382
+
383
+ Convert the conversation to a plain JSON object:
384
+
385
+ ```typescript
386
+ const json = conversation.toJSON();
387
+ console.log(json);
388
+ // {
389
+ // id: "...",
390
+ // title: "...",
391
+ // createdAt: Temporal.Instant,
392
+ // modifiedAt: Temporal.Instant,
393
+ // currentRunId: "..." | null,
394
+ // modelName: "..." | null,
395
+ // modelProviderId: "..." | null,
396
+ // tag: "..."
397
+ // }
398
+ ```
399
+
363
400
  ### Working with Chat Events
364
401
 
365
402
  The state of a conversation is represented as a stream of `ChatEvent` objects. These events include user messages, tool call requests and results, and Agent replies. While the event stream enables incremental UI updates, it contains implicit relationships that need to be made explicit for easier consumption.
@@ -371,16 +408,36 @@ The state of a conversation is represented as a stream of `ChatEvent` objects. T
371
408
  - `toolRequest` - A request to execute a tool (tool calls can run in parallel)
372
409
  - `toolResponse` - The result of a tool execution
373
410
  - `error` - An error message
411
+ - `conversationUpdate` - Updates to conversation metadata (title, summary)
412
+ - `endOfStream` - Marks the end of a run's event stream
374
413
 
375
414
  #### Building a Conversation Snapshot
376
415
 
377
- The `AgentConversation.reduceChatEvents()` method transforms a stream of chat events into a structured snapshot that makes implicit relationships explicit:
416
+ The `AgentConversation.reduceChatEvents()` method is a pure reducer function that transforms a stream of chat events into a structured snapshot that makes implicit relationships explicit.
417
+
418
+ **Function Signature:**
419
+
420
+ ```typescript
421
+ function reduceChatEvents(
422
+ state: ConversationExchange[],
423
+ chatEvents: ChatEvent[],
424
+ ): ConversationExchange[];
425
+ ```
426
+
427
+ **What it does:**
378
428
 
379
429
  - **Groups events by exchange** - Each user-agent interaction (identified by `runId`) becomes a separate exchange
380
430
  - **Pairs tool calls** - Tool requests and responses are matched by `callId` and combined into a single object
381
- - **Derives tool state** - Automatically determines if a tool call is `pending`, `success`, or `error`
382
- - **Handles duplicates** - Efficiently filters duplicate events when merging history and live streams
383
- - **Preserves order** - Maintains insertion order for messages and tool calls
431
+ - **Derives tool state** - Automatically determines if a tool call is `pending`, `success`, `error`, or `canceled`
432
+ - `pending` - Tool request received but no response yet
433
+ - `success` - Tool response received without error
434
+ - `error` - Tool response received with error message
435
+ - `canceled` - End of stream reached without receiving a response
436
+ - **Handles duplicates** - Efficiently filters duplicate events when merging history and live streams (events with the same `id` are deduplicated)
437
+ - **Preserves order** - Maintains insertion order for messages and tool calls using `Map` data structures
438
+ - **Immutable updates** - Uses structural sharing to efficiently create new snapshots without mutating the original state
439
+
440
+ **Basic Usage:**
384
441
 
385
442
  ```typescript
386
443
  import { AgentConversation } from "@dremio/js-sdk/enterprise/ai";
@@ -404,12 +461,110 @@ type ConversationExchange = {
404
461
  submittedUserMessage?: UserChatMessage;
405
462
  };
406
463
 
464
+ type ConversationExchangeMessage =
465
+ | ChatEventWithChunkType<"error">
466
+ | ChatEventWithChunkType<"model">
467
+ | ChatEventWithChunkType<"userMessage">;
468
+
407
469
  type AgentToolCall = {
408
470
  id: string;
409
- state: "error" | "pending" | "success";
471
+ state: "canceled" | "error" | "pending" | "success";
410
472
  request: ChatEventWithChunkType<"toolRequest"> | undefined;
411
473
  result: ChatEventWithChunkType<"toolResponse"> | undefined;
412
474
  };
475
+
476
+ // ChatEvent is the base type for all events in the stream
477
+ type ChatEvent = {
478
+ id: string;
479
+ conversationId: string;
480
+ runId: string;
481
+ createdAt: Temporal.Instant;
482
+ modelName: string;
483
+ modelProviderId: string;
484
+ role: "agent" | "user";
485
+ content:
486
+ | { chunkType: "conversationUpdate"; title?: string; summary?: string }
487
+ | { chunkType: "endOfStream" }
488
+ | { chunkType: "error"; message: string }
489
+ | { chunkType: "model"; name: string; result: Record<string, unknown> }
490
+ | {
491
+ chunkType: "toolRequest";
492
+ callId: string;
493
+ name: string;
494
+ arguments: Record<string, unknown>;
495
+ commentary?: string;
496
+ summarizedTitle?: string;
497
+ }
498
+ | {
499
+ chunkType: "toolResponse";
500
+ callId: string;
501
+ name: string;
502
+ result: Record<string, unknown>;
503
+ commentary?: string;
504
+ }
505
+ | { chunkType: "userMessage"; text: string };
506
+ };
507
+
508
+ // ChatEventWithChunkType is a helper type to extract events by their chunk type
509
+ type ChatEventWithChunkType<T extends ChatEvent["content"]["chunkType"]> =
510
+ Extract<ChatEvent, { content: { chunkType: T } }>;
511
+ ```
512
+
513
+ #### UI Rendering and React Reconciliation
514
+
515
+ The conversation snapshot produced by the reducer (and automatically managed by the `AgentConversationMachine`) is designed specifically for modern declarative UIs like React, Vue, Svelte, or Ink.
516
+
517
+ **You do not need to manually track message IDs, buffer stream chunks, or manage parallel tool call states.**
518
+
519
+ The reducer performs highly optimized, **immutable updates** as new events arrive. Because the top-level references change only when the underlying data changes, you can directly map over the snapshot in your render function. It is safe to pass these objects into memoized components (e.g., `React.memo`) without writing complex deep-equality checks or manual diffing logic.
520
+
521
+ **React Example:**
522
+
523
+ ```typescript
524
+ import { createActor } from "xstate";
525
+ import { UserChatMessage } from "@dremio/js-sdk/enterprise/ai";
526
+
527
+ const actor = createActor(conversationMachine, {
528
+ input: { conversationId: null },
529
+ });
530
+
531
+ // Subscribe to state changes and update React state
532
+ actor.subscribe((snapshot) => {
533
+ setExchanges(snapshot.context.conversationSnapshot ?? []);
534
+ });
535
+
536
+ actor.start();
537
+
538
+ // In your render function - direct mapping, no manual diffing needed
539
+ return (
540
+ <div>
541
+ {exchanges.map((exchange) => (
542
+ <Exchange key={exchange.id} exchange={exchange} />
543
+ ))}
544
+ </div>
545
+ );
546
+ ```
547
+
548
+ **Why this works:**
549
+
550
+ - The reducer uses **structural sharing** via the `mutative` library, creating new object references only for changed data
551
+ - Unchanged exchanges and messages retain their original references, enabling efficient React reconciliation
552
+ - Maps preserve insertion order and provide O(1) lookups by ID
553
+ - Tool calls are automatically paired and their state is derived, eliminating manual tracking logic
554
+
555
+ **Vue/Svelte Example:**
556
+
557
+ ```typescript
558
+ // The same principle applies - just bind to the snapshot
559
+ actor.subscribe((snapshot) => {
560
+ conversationSnapshot = snapshot.context.conversationSnapshot ?? [];
561
+ });
562
+ ```
563
+
564
+ ```svelte
565
+ {#each conversationSnapshot as exchange (exchange.id)}
566
+ <Exchange {exchange} />
567
+ {/each}
413
568
  ```
414
569
 
415
570
  #### Incremental Updates
@@ -504,16 +659,60 @@ actor.send({
504
659
  - `uninitialized` - Initial state before conversation is created
505
660
  - `creating_conversation` - Creating a new conversation
506
661
  - `retrieving_history` - Fetching conversation history
662
+ - `retrieve_history_failed` - Error state when history retrieval fails
507
663
  - `idle` - Ready to accept new messages
508
664
  - `submitting_message` - Sending a user message
509
- - `streaming` - Receiving agent responses
510
- - `retrieve_history_failed` - Error state when history retrieval fails
665
+ - `submitting_message_failed` - Error state when message submission fails
666
+ - `streaming` - Receiving agent responses (with substates: `monitoring_replies`, `stopping`)
511
667
 
512
668
  #### Machine Events
513
669
 
514
- - `SUBMIT_USER_MESSAGE` - Send a new message
670
+ - `SUBMIT_USER_MESSAGE` - Send a new message with a `UserChatMessage`
671
+ - `RETRY_MESSAGE` - Retry sending the last failed message
515
672
  - `REFRESH_HISTORY` - Reload conversation history
516
- - `CANCEL_RUN` - Cancel the current run
673
+ - `STOP_RUN` - Stop the current run
674
+
675
+ #### Machine Context
676
+
677
+ The machine maintains the following context:
678
+
679
+ ```typescript
680
+ type ConversationMachineContext = {
681
+ conversationId: string | null;
682
+ conversationSnapshot?: ConversationExchange[];
683
+ currentRunId?: string | null;
684
+ lastError?: unknown;
685
+ messageAttempt?: UserChatMessage;
686
+ };
687
+ ```
688
+
689
+ #### Machine Emitted Events
690
+
691
+ The machine emits the following events that can be subscribed to:
692
+
693
+ ```typescript
694
+ type ConversationMachineEmitted =
695
+ | { type: "apiError"; error: HttpError }
696
+ | { type: "chatEventReceived"; chatEvent: ChatEvent }
697
+ | { type: "conversationCreated"; id: string };
698
+ ```
699
+
700
+ Subscribe to emitted events:
701
+
702
+ ```typescript
703
+ actor.subscribe((snapshot) => {
704
+ // Access emitted events through snapshot
705
+ console.log("State:", snapshot.value);
706
+ console.log("Context:", snapshot.context);
707
+ });
708
+
709
+ // Or use the system to listen for specific events
710
+ actor.system.subscribe((event) => {
711
+ if (event.type === "chatEventReceived") {
712
+ console.log("New chat event:", event.chatEvent);
713
+ }
714
+ });
715
+ ```
517
716
 
518
717
  ## Catalog
519
718
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dremio/js-sdk",
3
- "version": "0.45.2",
3
+ "version": "0.45.4",
4
4
  "description": "JavaScript library for the Dremio API",
5
5
  "keywords": [
6
6
  "dremio",