@dremio/js-sdk 0.43.0 → 0.44.0

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 CHANGED
@@ -251,31 +251,23 @@ Represents a conversation with the Dremio AI Agent.
251
251
 
252
252
  #### Properties
253
253
 
254
- - `id: string` - Unique identifier for the conversation
255
- - `title: string` - The conversation title
256
254
  - `createdAt: Temporal.Instant` - When the conversation was created
257
- - `modifiedAt: Temporal.Instant` - When the conversation was last modified
255
+ - `currentRunId: string | null` - The ID of the currently active run, if any
256
+ - `id: string` - Unique identifier for the conversation
258
257
  - `modelName: string | null` - The AI model name last used for this conversation
259
258
  - `modelProviderId: string | null` - The AI model provider ID last used for this conversation
260
-
261
- #### `AgentConversation` implements the [`Observable` contract](https://github.com/WICG/observable) using `Symbol.observable`:
262
-
263
- ```typescript
264
- import { from } from "rxjs";
265
-
266
- from(conversation).subscribe((chatEvent) => {
267
- console.log(chatEvent);
268
- });
269
- ```
259
+ - `modifiedAt: Temporal.Instant` - When the conversation was last modified
260
+ - `tag: string` - Version tag for optimistic concurrency control
261
+ - `title: string` - The conversation title
270
262
 
271
263
  #### Create an `AgentConversation`
272
264
 
273
265
  ```typescript
266
+ import { UserChatMessage } from "@dremio/js-sdk/enterprise/ai";
267
+
274
268
  const conversation = await dremio.ai("PROJECT_ID").createConversation({
275
- message: new UserChatMessage(
276
- new UserChatMessageStringContent(
277
- "Can you help me visualize the data in the Citibike sample dataset?",
278
- ),
269
+ message: UserChatMessage.new(
270
+ "Can you help me visualize the data in the Citibike sample dataset?",
279
271
  ),
280
272
  });
281
273
  ```
@@ -291,7 +283,21 @@ const conversation = await dremio
291
283
  #### Update `AgentConversation`
292
284
 
293
285
  ```typescript
294
- const result = await conversation.update({ title: "New title" });
286
+ await conversation.update({ title: "New title" });
287
+ ```
288
+
289
+ The `update()` method supports optimistic concurrency control with conflict resolution:
290
+
291
+ ```typescript
292
+ await conversation.update(
293
+ { title: "New title" },
294
+ {
295
+ onConflict: async (local, remote, changes) => {
296
+ // Overwrite with local title
297
+ return { title: local.title };
298
+ },
299
+ },
300
+ );
295
301
  ```
296
302
 
297
303
  #### Delete `AgentConversation`
@@ -316,141 +322,199 @@ for await (const conversation of dremio
316
322
  To send a message to the Agent, use the `startRun()` method:
317
323
 
318
324
  ```typescript
319
- await conversation.startRun({
320
- message: new UserChatMessage(
321
- new UserChatMessageStringContent(
322
- "Please adjust the x-axis range to show only 2025-2026",
323
- ),
325
+ import { UserChatMessage } from "@dremio/js-sdk/enterprise/ai";
326
+
327
+ const runId = await conversation.startRun({
328
+ message: UserChatMessage.new(
329
+ "Please adjust the x-axis range to show only 2025-2026",
324
330
  ),
325
331
  });
326
332
  ```
327
333
 
328
- ### `AgentConversationSnapshotBuilder`
334
+ #### Stream Run Events
329
335
 
330
- Compiles a sequence of `ChatEvent`s into a structured view of the current conversation state.
336
+ Monitor chat events as they stream in from a run:
331
337
 
332
- #### Building a Snapshot
338
+ ```typescript
339
+ import { UserChatMessage } from "@dremio/js-sdk/enterprise/ai";
333
340
 
334
- Create a snapshot from existing conversation history:
341
+ const runId = await conversation.startRun({
342
+ message: UserChatMessage.new("What data is available to me in Dremio?"),
343
+ });
344
+
345
+ conversation.runEvents$(runId).subscribe((chatEvent) => {
346
+ console.log("Event:", chatEvent.content.chunkType);
347
+ if (chatEvent.content.chunkType === "model") {
348
+ console.log("Model response:", chatEvent.content.result);
349
+ }
350
+ });
351
+ ```
352
+
353
+ #### Retrieve Conversation History
354
+
355
+ Get the full history of chat events for a conversation:
335
356
 
336
357
  ```typescript
337
- const conversation = (
338
- await dremio.ai("PROJECT_ID").retrieveConversation("CONVERSATION_ID")
339
- ).unwrap();
358
+ const history = await conversation.history();
340
359
 
341
- const conversationSnapshot = AgentConversationSnapshotBuilder.fromChatEvents(
342
- conversation.id,
343
- (await conversation.history()).unwrap(),
344
- );
360
+ console.log(`Conversation has ${history.length} events`);
345
361
  ```
346
362
 
347
- #### Adding Events in Real-Time
363
+ ### Working with Chat Events
364
+
365
+ 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.
348
366
 
349
- Monitor chat events as they stream in and add them to the snapshot:
367
+ #### Chat Event Types
368
+
369
+ - `userMessage` - A message from the user
370
+ - `model` - A response from the AI model
371
+ - `toolRequest` - A request to execute a tool (tool calls can run in parallel)
372
+ - `toolResponse` - The result of a tool execution
373
+ - `error` - An error message
374
+
375
+ #### Building a Conversation Snapshot
376
+
377
+ The `AgentConversation.reduceChatEvents()` method transforms a stream of chat events into a structured snapshot that makes implicit relationships explicit:
378
+
379
+ - **Groups events by exchange** - Each user-agent interaction (identified by `runId`) becomes a separate exchange
380
+ - **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
350
384
 
351
385
  ```typescript
352
- const runId = await conversation
353
- .startRun({
354
- message: new UserChatMessage(
355
- new UserChatMessageStringContent(
356
- "What data is available to me in Dremio?",
357
- ),
358
- ),
359
- })
360
- .then((res) => res.unwrap());
386
+ import { AgentConversation } from "@dremio/js-sdk/enterprise/ai";
387
+
388
+ const conversation = await dremio
389
+ .ai("PROJECT_ID")
390
+ .retrieveConversation("CONVERSATION_ID");
391
+
392
+ const history = await conversation.history();
393
+
394
+ const snapshot = AgentConversation.reduceChatEvents([], history);
395
+ ```
396
+
397
+ Each exchange in the snapshot represents a single user-agent interaction:
398
+
399
+ ```typescript
400
+ type ConversationExchange = {
401
+ id: string; // The run ID
402
+ messages: Map<string, ConversationExchangeMessage>;
403
+ toolCalls: Map<string, AgentToolCall>;
404
+ submittedUserMessage?: UserChatMessage;
405
+ };
406
+
407
+ type AgentToolCall = {
408
+ id: string;
409
+ state: "error" | "pending" | "success";
410
+ request: ChatEventWithChunkType<"toolRequest"> | undefined;
411
+ result: ChatEventWithChunkType<"toolResponse"> | undefined;
412
+ };
413
+ ```
414
+
415
+ #### Incremental Updates
416
+
417
+ The reducer is a pure function with signature `(snapshot, events) => newSnapshot`. You can incrementally update a snapshot as new events arrive:
418
+
419
+ ```typescript
420
+ import {
421
+ AgentConversation,
422
+ UserChatMessage,
423
+ } from "@dremio/js-sdk/enterprise/ai";
424
+
425
+ let snapshot = AgentConversation.reduceChatEvents([], historyEvents);
426
+
427
+ const runId = await conversation.startRun({
428
+ message: UserChatMessage.new("What tables exist?"),
429
+ });
361
430
 
362
431
  conversation.runEvents$(runId).subscribe((chatEvent) => {
363
- conversationSnapshot.addChatEvent(chatEvent);
364
- console.log(conversationSnapshot.get(runId)!.toJSON());
432
+ snapshot = AgentConversation.reduceChatEvents(snapshot, [chatEvent]);
433
+
434
+ const currentExchange = snapshot[snapshot.length - 1];
435
+ console.log("Current exchange:", currentExchange);
365
436
  });
366
437
  ```
367
438
 
368
- #### Accessing Snapshot Data
439
+ ### `UserChatMessage`
440
+
441
+ Create user messages to send to the AI Agent.
369
442
 
370
- The snapshot is iterable and provides access to exchanges:
443
+ #### Create a Simple Message
371
444
 
372
445
  ```typescript
373
- // Iterate through all exchanges
374
- for (const exchange of conversationSnapshot) {
375
- console.log("Exchange ID:", exchange.id);
376
- for (const message of exchange.messages) {
377
- console.log("Message:", message);
378
- }
379
- for (const toolCall of exchange.toolCalls) {
380
- console.log("Tool Call:", toolCall.id, toolCall.state);
381
- }
382
- }
446
+ import { UserChatMessage } from "@dremio/js-sdk/enterprise/ai";
383
447
 
384
- // Get a specific exchange
385
- const exchange = conversationSnapshot.get(runId);
448
+ const message = UserChatMessage.new("What tables are available?");
386
449
  ```
387
450
 
388
- #### Snapshot Methods
451
+ #### Create a Message with Context
389
452
 
390
- - `length: number` - Get the number of exchanges in the snapshot
391
- - `clone(): AgentConversationSnapshotBuilder` - Create a deep clone of the builder
392
- - `slice(startExchangeId, endExchangeId?)` - Get a shallow clone containing exchanges in a range
393
- - `toJSON()` - Serialize the snapshot to JSON
453
+ ```typescript
454
+ import { UserChatMessage } from "@dremio/js-sdk/enterprise/ai";
394
455
 
395
- #### Snapshot Output Example
456
+ const message = UserChatMessage.new("Analyze this data", {
457
+ context: "Additional context about the request",
458
+ skillIds: ["skill-id-1", "skill-id-2"],
459
+ });
460
+ ```
396
461
 
397
- The `toJSON()` method returns an array of exchanges with their messages and tool calls:
462
+ #### Message Properties
398
463
 
399
- ```json
400
- [
401
- {
402
- "id": "run-id-1",
403
- "messages": [
404
- {
405
- "id": "msg-1",
406
- "runId": "run-id-1",
407
- "conversationId": "conv-id",
408
- "role": "user",
409
- "content": {
410
- "chunkType": "userMessage",
411
- "text": "What data is available?"
412
- }
413
- },
414
- {
415
- "id": "msg-2",
416
- "runId": "run-id-1",
417
- "conversationId": "conv-id",
418
- "role": "agent",
419
- "content": {
420
- "chunkType": "model",
421
- "name": "modelGeneric",
422
- "result": {
423
- "text": "Here are the available datasets..."
424
- }
425
- }
426
- }
427
- ],
428
- "toolCalls": [
429
- {
430
- "id": "tool-call-1",
431
- "state": "success",
432
- "request": {
433
- "content": {
434
- "chunkType": "toolRequest",
435
- "name": "queryTool",
436
- "arguments": { "query": "SELECT * FROM schemas" }
437
- }
438
- },
439
- "result": {
440
- "content": {
441
- "chunkType": "toolResponse",
442
- "name": "queryTool",
443
- "result": {
444
- "rows": [{ "schema_name": "public" }]
445
- }
446
- }
447
- }
448
- }
449
- ]
450
- }
451
- ]
464
+ - `id: string` - Unique identifier for the message
465
+ - `createdAt: Temporal.ZonedDateTime` - When the message was created
466
+ - `content: string` - The message text
467
+ - `prompt?: object` - Optional prompt configuration including context, skillIds, and approvals
468
+
469
+ ### `AgentConversationMachine`
470
+
471
+ An XState state machine for managing conversation lifecycle with built-in state management.
472
+
473
+ #### Create and Use the Machine
474
+
475
+ ```typescript
476
+ import { createActor } from "xstate";
477
+ import { UserChatMessage } from "@dremio/js-sdk/enterprise/ai";
478
+
479
+ const conversationMachine = dremio.ai("PROJECT_ID").conversationMachine;
480
+
481
+ // Create a new conversation
482
+ const actor = createActor(conversationMachine, {
483
+ input: {
484
+ conversationId: null,
485
+ },
486
+ });
487
+
488
+ actor.subscribe((snapshot) => {
489
+ console.log("State:", snapshot.value);
490
+ console.log("Exchanges:", snapshot.context.conversationSnapshot);
491
+ });
492
+
493
+ actor.start();
494
+
495
+ // Send additional messages
496
+ actor.send({
497
+ type: "SUBMIT_USER_MESSAGE",
498
+ message: UserChatMessage.new("What data sources are available?"),
499
+ });
452
500
  ```
453
501
 
502
+ #### Machine States
503
+
504
+ - `uninitialized` - Initial state before conversation is created
505
+ - `creating_conversation` - Creating a new conversation
506
+ - `retrieving_history` - Fetching conversation history
507
+ - `idle` - Ready to accept new messages
508
+ - `submitting_message` - Sending a user message
509
+ - `streaming` - Receiving agent responses
510
+ - `retrieve_history_failed` - Error state when history retrieval fails
511
+
512
+ #### Machine Events
513
+
514
+ - `SUBMIT_USER_MESSAGE` - Send a new message
515
+ - `REFRESH_HISTORY` - Reload conversation history
516
+ - `CANCEL_RUN` - Cancel the current run
517
+
454
518
  ## Catalog
455
519
 
456
520
  ### `CatalogReference` Interface
@@ -125,6 +125,17 @@ export declare class AIResource {
125
125
  message: string;
126
126
  };
127
127
  role: "agent";
128
+ } | {
129
+ conversationId: string;
130
+ modelName: string;
131
+ modelProviderId: string;
132
+ runId: string;
133
+ createdAt: import("temporal-polyfill").Temporal.Instant;
134
+ id: string;
135
+ content: {
136
+ chunkType: "endOfStream";
137
+ };
138
+ role: "agent";
128
139
  } | {
129
140
  conversationId: string;
130
141
  modelName: string;
@@ -221,6 +232,17 @@ export declare class AIResource {
221
232
  message: string;
222
233
  };
223
234
  role: "agent";
235
+ } | {
236
+ conversationId: string;
237
+ modelName: string;
238
+ modelProviderId: string;
239
+ runId: string;
240
+ createdAt: import("temporal-polyfill").Temporal.Instant;
241
+ id: string;
242
+ content: {
243
+ chunkType: "endOfStream";
244
+ };
245
+ role: "agent";
224
246
  } | {
225
247
  conversationId: string;
226
248
  modelName: string;
@@ -324,6 +346,17 @@ export declare class AIResource {
324
346
  message: string;
325
347
  };
326
348
  role: "agent";
349
+ } | {
350
+ conversationId: string;
351
+ modelName: string;
352
+ modelProviderId: string;
353
+ runId: string;
354
+ createdAt: import("temporal-polyfill").Temporal.Instant;
355
+ id: string;
356
+ content: {
357
+ chunkType: "endOfStream";
358
+ };
359
+ role: "agent";
327
360
  } | {
328
361
  conversationId: string;
329
362
  modelName: string;
@@ -435,6 +468,17 @@ export declare class AIResource {
435
468
  message: string;
436
469
  };
437
470
  role: "agent";
471
+ } | {
472
+ conversationId: string;
473
+ modelName: string;
474
+ modelProviderId: string;
475
+ runId: string;
476
+ createdAt: import("temporal-polyfill").Temporal.Instant;
477
+ id: string;
478
+ content: {
479
+ chunkType: "endOfStream";
480
+ };
481
+ role: "agent";
438
482
  } | {
439
483
  conversationId: string;
440
484
  modelName: string;
@@ -535,6 +579,17 @@ export declare class AIResource {
535
579
  message: string;
536
580
  };
537
581
  role: "agent";
582
+ } | {
583
+ conversationId: string;
584
+ modelName: string;
585
+ modelProviderId: string;
586
+ runId: string;
587
+ createdAt: import("temporal-polyfill").Temporal.Instant;
588
+ id: string;
589
+ content: {
590
+ chunkType: "endOfStream";
591
+ };
592
+ role: "agent";
538
593
  } | {
539
594
  conversationId: string;
540
595
  modelName: string;
@@ -650,6 +705,17 @@ export declare class AIResource {
650
705
  message: string;
651
706
  };
652
707
  role: "agent";
708
+ } | {
709
+ conversationId: string;
710
+ modelName: string;
711
+ modelProviderId: string;
712
+ runId: string;
713
+ createdAt: import("temporal-polyfill").Temporal.Instant;
714
+ id: string;
715
+ content: {
716
+ chunkType: "endOfStream";
717
+ };
718
+ role: "agent";
653
719
  } | {
654
720
  conversationId: string;
655
721
  modelName: string;
@@ -713,7 +779,13 @@ export declare class AIResource {
713
779
  id: string | undefined;
714
780
  }, never, never, never, "uninitialized" | "creating_conversation" | "retrieving_history" | "idle" | "submitting_message" | "retrieve_history_failed" | "submitting_message_failed" | {
715
781
  streaming: "monitoring_replies" | "stopping";
716
- }, string, import("../../enterprise/ai/conversations/createConversationMachine.ts").ConversationMachineInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
782
+ }, string, import("../../enterprise/ai/conversations/createConversationMachine.ts").ConversationMachineInput, import("xstate").NonReducibleUnknown, {
783
+ type: "chatEventReceived";
784
+ chatEvent: ChatEvent;
785
+ } | {
786
+ type: "conversationCreated";
787
+ id: string;
788
+ }, import("xstate").MetaObject, {
717
789
  id: "agentConversation";
718
790
  states: {
719
791
  readonly creating_conversation: {};
@@ -67,6 +67,17 @@ export declare class AIResource {
67
67
  message: string;
68
68
  };
69
69
  role: "agent";
70
+ } | {
71
+ conversationId: string;
72
+ modelName: string;
73
+ modelProviderId: string;
74
+ runId: string;
75
+ createdAt: import("temporal-polyfill").Temporal.Instant;
76
+ id: string;
77
+ content: {
78
+ chunkType: "endOfStream";
79
+ };
80
+ role: "agent";
70
81
  } | {
71
82
  conversationId: string;
72
83
  modelName: string;
@@ -163,6 +174,17 @@ export declare class AIResource {
163
174
  message: string;
164
175
  };
165
176
  role: "agent";
177
+ } | {
178
+ conversationId: string;
179
+ modelName: string;
180
+ modelProviderId: string;
181
+ runId: string;
182
+ createdAt: import("temporal-polyfill").Temporal.Instant;
183
+ id: string;
184
+ content: {
185
+ chunkType: "endOfStream";
186
+ };
187
+ role: "agent";
166
188
  } | {
167
189
  conversationId: string;
168
190
  modelName: string;
@@ -266,6 +288,17 @@ export declare class AIResource {
266
288
  message: string;
267
289
  };
268
290
  role: "agent";
291
+ } | {
292
+ conversationId: string;
293
+ modelName: string;
294
+ modelProviderId: string;
295
+ runId: string;
296
+ createdAt: import("temporal-polyfill").Temporal.Instant;
297
+ id: string;
298
+ content: {
299
+ chunkType: "endOfStream";
300
+ };
301
+ role: "agent";
269
302
  } | {
270
303
  conversationId: string;
271
304
  modelName: string;
@@ -377,6 +410,17 @@ export declare class AIResource {
377
410
  message: string;
378
411
  };
379
412
  role: "agent";
413
+ } | {
414
+ conversationId: string;
415
+ modelName: string;
416
+ modelProviderId: string;
417
+ runId: string;
418
+ createdAt: import("temporal-polyfill").Temporal.Instant;
419
+ id: string;
420
+ content: {
421
+ chunkType: "endOfStream";
422
+ };
423
+ role: "agent";
380
424
  } | {
381
425
  conversationId: string;
382
426
  modelName: string;
@@ -477,6 +521,17 @@ export declare class AIResource {
477
521
  message: string;
478
522
  };
479
523
  role: "agent";
524
+ } | {
525
+ conversationId: string;
526
+ modelName: string;
527
+ modelProviderId: string;
528
+ runId: string;
529
+ createdAt: import("temporal-polyfill").Temporal.Instant;
530
+ id: string;
531
+ content: {
532
+ chunkType: "endOfStream";
533
+ };
534
+ role: "agent";
480
535
  } | {
481
536
  conversationId: string;
482
537
  modelName: string;
@@ -592,6 +647,17 @@ export declare class AIResource {
592
647
  message: string;
593
648
  };
594
649
  role: "agent";
650
+ } | {
651
+ conversationId: string;
652
+ modelName: string;
653
+ modelProviderId: string;
654
+ runId: string;
655
+ createdAt: import("temporal-polyfill").Temporal.Instant;
656
+ id: string;
657
+ content: {
658
+ chunkType: "endOfStream";
659
+ };
660
+ role: "agent";
595
661
  } | {
596
662
  conversationId: string;
597
663
  modelName: string;
@@ -655,7 +721,13 @@ export declare class AIResource {
655
721
  id: string | undefined;
656
722
  }, never, never, never, "uninitialized" | "creating_conversation" | "retrieving_history" | "idle" | "submitting_message" | "retrieve_history_failed" | "submitting_message_failed" | {
657
723
  streaming: "monitoring_replies" | "stopping";
658
- }, string, import("./conversations/createConversationMachine.ts").ConversationMachineInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
724
+ }, string, import("./conversations/createConversationMachine.ts").ConversationMachineInput, import("xstate").NonReducibleUnknown, {
725
+ type: "chatEventReceived";
726
+ chatEvent: ChatEvent;
727
+ } | {
728
+ type: "conversationCreated";
729
+ id: string;
730
+ }, import("xstate").MetaObject, {
659
731
  id: "agentConversation";
660
732
  states: {
661
733
  readonly creating_conversation: {};
@@ -57,6 +57,14 @@ export declare const chatEventCodec: z.ZodMiniCodec<z.ZodMiniDiscriminatedUnion<
57
57
  * anyways, so the parser should throw to the generic response error handler.
58
58
  */
59
59
  message: z.ZodMiniString<string>;
60
+ }, z.core.$strip>, z.ZodMiniObject<{
61
+ chunkType: z.ZodMiniLiteral<"endOfStream">;
62
+ conversationId: z.ZodMiniString<string>;
63
+ createdAt: z.ZodMiniString<string>;
64
+ messageId: z.ZodMiniString<string>;
65
+ modelName: z.ZodMiniString<string>;
66
+ modelProviderId: z.ZodMiniString<string>;
67
+ runId: z.ZodMiniString<string>;
60
68
  }, z.core.$strip>, z.ZodMiniObject<{
61
69
  chunkType: z.ZodMiniLiteral<"conversationUpdate">;
62
70
  summary: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -140,6 +148,17 @@ export declare const chatEventCodec: z.ZodMiniCodec<z.ZodMiniDiscriminatedUnion<
140
148
  message: z.ZodMiniString<string>;
141
149
  }, z.core.$strip>;
142
150
  role: z.ZodMiniLiteral<"agent">;
151
+ }, z.core.$strict>, z.ZodMiniObject<{
152
+ conversationId: z.ZodMiniString<string>;
153
+ modelName: z.ZodMiniString<string>;
154
+ modelProviderId: z.ZodMiniString<string>;
155
+ runId: z.ZodMiniString<string>;
156
+ createdAt: z.ZodMiniCustom<Temporal.Instant, Temporal.Instant>;
157
+ id: z.ZodMiniString<string>;
158
+ content: z.ZodMiniObject<{
159
+ chunkType: z.ZodMiniLiteral<"endOfStream">;
160
+ }, z.core.$strip>;
161
+ role: z.ZodMiniLiteral<"agent">;
143
162
  }, z.core.$strict>, z.ZodMiniObject<{
144
163
  conversationId: z.ZodMiniString<string>;
145
164
  modelName: z.ZodMiniString<string>;