@dxos/assistant 0.8.0 → 0.8.1-main.303c73a

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 (65) hide show
  1. package/dist/lib/browser/index.mjs +976 -536
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/testing/index.mjs +2 -2
  5. package/dist/lib/browser/testing/index.mjs.map +1 -1
  6. package/dist/lib/node/index.cjs +1172 -735
  7. package/dist/lib/node/index.cjs.map +4 -4
  8. package/dist/lib/node/meta.json +1 -1
  9. package/dist/lib/node/testing/index.cjs +22 -22
  10. package/dist/lib/node/testing/index.cjs.map +2 -2
  11. package/dist/lib/node-esm/index.mjs +976 -536
  12. package/dist/lib/node-esm/index.mjs.map +4 -4
  13. package/dist/lib/node-esm/meta.json +1 -1
  14. package/dist/lib/node-esm/testing/index.mjs +2 -2
  15. package/dist/lib/node-esm/testing/index.mjs.map +1 -1
  16. package/dist/types/src/ai-service/edge-client.d.ts +19 -0
  17. package/dist/types/src/ai-service/edge-client.d.ts.map +1 -0
  18. package/dist/types/src/ai-service/index.d.ts +4 -1
  19. package/dist/types/src/ai-service/index.d.ts.map +1 -1
  20. package/dist/types/src/ai-service/message-collector.d.ts +88 -0
  21. package/dist/types/src/ai-service/message-collector.d.ts.map +1 -0
  22. package/dist/types/src/ai-service/ollama-client.d.ts +43 -0
  23. package/dist/types/src/ai-service/ollama-client.d.ts.map +1 -0
  24. package/dist/types/src/ai-service/parser.d.ts +3 -1
  25. package/dist/types/src/ai-service/parser.d.ts.map +1 -1
  26. package/dist/types/src/ai-service/service.d.ts +9 -0
  27. package/dist/types/src/ai-service/service.d.ts.map +1 -0
  28. package/dist/types/src/ai-service/stream.d.ts +2 -1
  29. package/dist/types/src/ai-service/stream.d.ts.map +1 -1
  30. package/dist/types/src/ai-service/testing/mock.d.ts +2 -2
  31. package/dist/types/src/ai-service/testing/mock.d.ts.map +1 -1
  32. package/dist/types/src/ai-service/types.d.ts +1 -1
  33. package/dist/types/src/ai-service/types.d.ts.map +1 -1
  34. package/dist/types/src/conversation/conversation.d.ts +3 -1
  35. package/dist/types/src/conversation/conversation.d.ts.map +1 -1
  36. package/dist/types/src/conversation/types.d.ts +1 -1
  37. package/dist/types/src/conversation/types.d.ts.map +1 -1
  38. package/dist/types/src/testing/query-promts.d.ts +1 -1
  39. package/dist/types/src/testing/query-promts.d.ts.map +1 -1
  40. package/dist/types/src/testing/test-data.d.ts +1 -1
  41. package/dist/types/src/testing/test-data.d.ts.map +1 -1
  42. package/dist/types/src/testing/test-schema.d.ts +1 -1
  43. package/dist/types/src/testing/test-schema.d.ts.map +1 -1
  44. package/package.json +17 -14
  45. package/src/ai-service/client.test.ts +94 -7
  46. package/src/ai-service/{client.ts → edge-client.ts} +15 -24
  47. package/src/ai-service/index.ts +4 -1
  48. package/src/ai-service/message-collector.ts +84 -0
  49. package/src/ai-service/ollama-client.ts +473 -0
  50. package/src/ai-service/parser.ts +7 -2
  51. package/src/ai-service/service.ts +15 -0
  52. package/src/ai-service/stream.ts +5 -3
  53. package/src/ai-service/testing/mock.ts +7 -2
  54. package/src/ai-service/types.ts +1 -1
  55. package/src/bin/chat.ts +2 -2
  56. package/src/conversation/conversation.test.ts +3 -3
  57. package/src/conversation/conversation.ts +3 -2
  58. package/src/conversation/types.ts +1 -1
  59. package/src/testing/artifacts.test.ts +2 -2
  60. package/src/testing/query-promts.ts +1 -1
  61. package/src/testing/query.test.ts +2 -2
  62. package/src/testing/test-data.ts +1 -1
  63. package/src/testing/test-schema.ts +1 -1
  64. package/dist/types/src/ai-service/client.d.ts +0 -25
  65. package/dist/types/src/ai-service/client.d.ts.map +0 -1
@@ -28,18 +28,21 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var node_exports = {};
30
30
  __export(node_exports, {
31
- AIServiceClientImpl: () => AIServiceClientImpl,
31
+ AIServiceEdgeClient: () => AIServiceEdgeClient,
32
32
  DEFAULT_LLM_MODEL: () => DEFAULT_LLM_MODEL,
33
33
  DEFAULT_LLM_MODELS: () => DEFAULT_LLM_MODELS,
34
34
  EchoDataSource: () => import_chunk_QPHGQINW.EchoDataSource,
35
35
  GenerateRequest: () => GenerateRequest,
36
- GenerationStream: () => GenerationStream,
36
+ GenerationStreamImpl: () => GenerationStreamImpl,
37
37
  LLMModel: () => LLMModel,
38
+ MessageCollector: () => MessageCollector,
38
39
  MixedStreamParser: () => MixedStreamParser,
40
+ OllamaClient: () => OllamaClient,
39
41
  StreamTransform: () => StreamTransform,
40
42
  ToolTypes: () => ToolTypes,
41
43
  createArtifactElement: () => createArtifactElement,
42
44
  createGenerationStream: () => createGenerationStream,
45
+ emitMessageAsEvents: () => emitMessageAsEvents,
43
46
  executeQuery: () => import_chunk_QPHGQINW.executeQuery,
44
47
  executeQueryPlan: () => import_chunk_QPHGQINW.executeQueryPlan,
45
48
  formatInferredRelationshipLabel: () => import_chunk_QPHGQINW.formatInferredRelationshipLabel,
@@ -54,26 +57,45 @@ __export(node_exports, {
54
57
  });
55
58
  module.exports = __toCommonJS(node_exports);
56
59
  var import_chunk_QPHGQINW = require("./chunk-QPHGQINW.cjs");
57
- var import_schema = require("@effect/schema");
60
+ var import_effect = require("effect");
58
61
  var import_artifact = require("@dxos/artifact");
59
62
  var import_invariant = require("@dxos/invariant");
60
63
  var import_log = require("@dxos/log");
61
64
  var import_async = require("@dxos/async");
62
65
  var import_log2 = require("@dxos/log");
63
66
  var import_artifact2 = require("@dxos/artifact");
64
- var import_async2 = require("@dxos/async");
65
67
  var import_echo_schema = require("@dxos/echo-schema");
66
68
  var import_invariant2 = require("@dxos/invariant");
67
69
  var import_log3 = require("@dxos/log");
68
- var import_util = require("@dxos/util");
69
- var P = __toESM(require("parsimmon"));
70
- var import_schema2 = require("@effect/schema");
70
+ var import_effect2 = require("effect");
71
71
  var import_artifact3 = require("@dxos/artifact");
72
72
  var import_echo_schema2 = require("@dxos/echo-schema");
73
73
  var import_artifact4 = require("@dxos/artifact");
74
74
  var import_echo_schema3 = require("@dxos/echo-schema");
75
75
  var import_invariant3 = require("@dxos/invariant");
76
76
  var import_log4 = require("@dxos/log");
77
+ var import_artifact5 = require("@dxos/artifact");
78
+ var import_async2 = require("@dxos/async");
79
+ var import_echo_schema4 = require("@dxos/echo-schema");
80
+ var import_invariant4 = require("@dxos/invariant");
81
+ var import_log5 = require("@dxos/log");
82
+ var import_util = require("@dxos/util");
83
+ var P = __toESM(require("parsimmon"));
84
+ var DEFAULT_LLM_MODEL = "@anthropic/claude-3-5-sonnet-20241022";
85
+ var DEFAULT_LLM_MODELS = [
86
+ // AI Gateway.
87
+ // https://developers.cloudflare.com/ai-gateway
88
+ "@anthropic/claude-3-5-haiku-20241022",
89
+ "@anthropic/claude-3-5-sonnet-20241022",
90
+ "@anthropic/claude-3-7-sonnet-20250219",
91
+ // Workers AI.
92
+ // https://developers.cloudflare.com/workers-ai/models
93
+ "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b",
94
+ "@hf/nousresearch/hermes-2-pro-mistral-7b",
95
+ "@ollama/llama-3-1-nemotron-70b-instruct",
96
+ "@ollama/llama-3-1-nemotron-mini-4b-instruct",
97
+ "@ollama/llama-3-2-3b"
98
+ ];
77
99
  async function* iterSSEMessages(response, controller) {
78
100
  if (!response.body) {
79
101
  controller.abort();
@@ -321,7 +343,7 @@ var createGenerationStream = (response, controller = new AbortController()) => {
321
343
  raw: sse.raw
322
344
  }, {
323
345
  F: __dxlog_file,
324
- L: 21,
346
+ L: 22,
325
347
  S: this,
326
348
  C: (f, a) => f(...a)
327
349
  });
@@ -337,7 +359,7 @@ var createGenerationStream = (response, controller = new AbortController()) => {
337
359
  raw: sse.raw
338
360
  }, {
339
361
  F: __dxlog_file,
340
- L: 37,
362
+ L: 38,
341
363
  S: this,
342
364
  C: (f, a) => f(...a)
343
365
  });
@@ -352,9 +374,9 @@ var createGenerationStream = (response, controller = new AbortController()) => {
352
374
  }
353
375
  }
354
376
  };
355
- return new GenerationStream(controller, iterator);
377
+ return new GenerationStreamImpl(controller, iterator);
356
378
  };
357
- var GenerationStream = class {
379
+ var GenerationStreamImpl = class {
358
380
  constructor(_controller, _getIterator) {
359
381
  this._controller = _controller;
360
382
  this._getIterator = _getIterator;
@@ -393,18 +415,19 @@ var GenerationStream = class {
393
415
  this._done.wake();
394
416
  } catch (err) {
395
417
  this._done.throw(err);
418
+ throw err;
396
419
  }
397
420
  };
398
421
  return generator.call(this);
399
422
  })();
400
423
  }
401
424
  };
402
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/client.ts";
403
- var AIServiceClientImpl = class {
425
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/edge-client.ts";
426
+ var AIServiceEdgeClient = class {
404
427
  constructor({ endpoint }) {
405
428
  (0, import_invariant.invariant)(endpoint, "endpoint is required", {
406
429
  F: __dxlog_file2,
407
- L: 34,
430
+ L: 23,
408
431
  S: this,
409
432
  A: [
410
433
  "endpoint",
@@ -413,6 +436,10 @@ var AIServiceClientImpl = class {
413
436
  });
414
437
  this._endpoint = endpoint;
415
438
  }
439
+ /**
440
+ * @deprecated
441
+ */
442
+ // TODO(burdon): Remove.
416
443
  async appendMessages(messages) {
417
444
  const url = `${this._endpoint}/message`;
418
445
  const res = await fetch(url, {
@@ -421,7 +448,7 @@ var AIServiceClientImpl = class {
421
448
  "Content-Type": "application/json"
422
449
  },
423
450
  body: JSON.stringify({
424
- messages: await import_schema.Schema.encodePromise(import_schema.Schema.Array(import_artifact.Message))(messages)
451
+ messages: await import_effect.Schema.encodePromise(import_effect.Schema.Array(import_artifact.Message))(messages)
425
452
  })
426
453
  });
427
454
  if (!res.ok) {
@@ -432,15 +459,11 @@ var AIServiceClientImpl = class {
432
459
  * Process request and open message stream.
433
460
  */
434
461
  async exec(request) {
435
- request = {
436
- tools: request.tools ?? [],
437
- ...request
438
- };
439
462
  import_log.log.info("requesting", {
440
463
  endpoint: this._endpoint
441
464
  }, {
442
465
  F: __dxlog_file2,
443
- L: 63,
466
+ L: 50,
444
467
  S: this,
445
468
  C: (f, a) => f(...a)
446
469
  });
@@ -451,11 +474,15 @@ var AIServiceClientImpl = class {
451
474
  headers: {
452
475
  "Content-Type": "application/json"
453
476
  },
454
- body: JSON.stringify(request)
477
+ body: JSON.stringify({
478
+ // TODO(dmaretskyi): Errors if tools are not provided.
479
+ tools: request.tools ?? [],
480
+ ...request
481
+ })
455
482
  });
456
483
  (0, import_invariant.invariant)(response.body instanceof ReadableStream, void 0, {
457
484
  F: __dxlog_file2,
458
- L: 72,
485
+ L: 63,
459
486
  S: this,
460
487
  A: [
461
488
  "response.body instanceof ReadableStream",
@@ -465,807 +492,1217 @@ var AIServiceClientImpl = class {
465
492
  return createGenerationStream(response, controller);
466
493
  }
467
494
  };
468
- var DEFAULT_LLM_MODEL = "@anthropic/claude-3-5-sonnet-20241022";
469
- var DEFAULT_LLM_MODELS = [
470
- // AI Gateway.
471
- // https://developers.cloudflare.com/ai-gateway
472
- "@anthropic/claude-3-5-haiku-20241022",
473
- "@anthropic/claude-3-5-sonnet-20241022",
474
- "@anthropic/claude-3-7-sonnet-20250219",
475
- // Workers AI.
476
- // https://developers.cloudflare.com/workers-ai/models
477
- "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b",
478
- "@hf/nousresearch/hermes-2-pro-mistral-7b",
479
- "@ollama/llama-3-1-nemotron-70b-instruct",
480
- "@ollama/llama-3-1-nemotron-mini-4b-instruct",
481
- "@ollama/llama-3-2-3b"
482
- ];
483
- var textChunk = P.regexp(/[^<]+/).map((content) => ({
484
- type: "text",
485
- content
486
- }));
487
- var attribute = P.seq(P.regexp(/[a-zA-Z_][a-zA-Z0-9_-]*/), P.string("=").trim(P.optWhitespace), P.alt(P.regexp(/"[^"]*"/).map((s) => s.slice(1, -1)), P.regexp(/'[^']*'/).map((s) => s.slice(1, -1)))).map(([name, _, value]) => [
488
- name,
489
- value
490
- ]);
491
- var tagName = P.regexp(/[a-zA-Z_][a-zA-Z0-9_-]*/);
492
- var selfClosingTag = P.seqMap(
493
- //
494
- P.string("<"),
495
- tagName,
496
- P.optWhitespace.then(attribute).many(),
497
- P.optWhitespace.then(P.string("/>")),
498
- P.optWhitespace,
499
- (_, tag, attributes, __) => ({
500
- type: "tag",
501
- tag,
502
- attributes: Object.fromEntries(attributes),
503
- content: [],
504
- selfClosing: true
505
- })
506
- );
507
- var openTag = P.seqMap(
508
- //
509
- P.string("<"),
510
- tagName,
511
- P.optWhitespace.then(attribute).many(),
512
- P.string(">"),
513
- P.regexp(/[^<]*/),
514
- (_, tag, attributes, __, content) => ({
515
- type: "tag",
516
- tag,
517
- attributes: Object.fromEntries(attributes),
518
- content: content.length ? [
519
- {
520
- type: "text",
521
- content
522
- }
523
- ] : []
524
- })
525
- );
526
- var closeTag = P.seqMap(
527
- //
528
- P.string("</"),
529
- tagName,
530
- P.string(">"),
531
- P.optWhitespace,
532
- (_, tag) => ({
533
- type: "tag",
534
- tag,
535
- content: [],
536
- closing: true
537
- })
538
- );
539
- var mixedChunk = P.alt(selfClosingTag, openTag, closeTag, textChunk);
540
- var StreamTransform = class {
495
+ var MessageCollector = class {
541
496
  constructor() {
542
- this._buffer = "";
497
+ this._messages = [];
498
+ this._pendingMessage = void 0;
543
499
  }
544
- transform(chunk) {
545
- this._buffer += chunk;
546
- const results = [];
547
- const parser = mixedChunk.many().skip(P.optWhitespace);
548
- const result = parser.parse(this._buffer);
549
- if (result.status) {
550
- for (const chunk2 of result.value) {
551
- results.push(chunk2);
552
- }
553
- this._buffer = "";
500
+ get messages() {
501
+ return this._messages;
502
+ }
503
+ get pendingMessage() {
504
+ return this._pendingMessage;
505
+ }
506
+ push(event) {
507
+ switch (event.type) {
508
+ case "message_start":
509
+ this._pendingMessage = event.message;
510
+ break;
511
+ case "message_stop":
512
+ if (this._pendingMessage) {
513
+ this._messages.push(this._pendingMessage);
514
+ this._pendingMessage = void 0;
515
+ }
516
+ break;
517
+ case "content_block_start":
518
+ if (this._pendingMessage) {
519
+ this._pendingMessage.content = this._pendingMessage.content || [];
520
+ this._pendingMessage.content[event.index] = event.content;
521
+ }
522
+ break;
523
+ case "content_block_delta":
524
+ if (this._pendingMessage && this._pendingMessage.content) {
525
+ const block = this._pendingMessage.content[event.index];
526
+ if (block && event.delta.type === "text_delta" && block.type === "text") {
527
+ block.text = (block.text || "") + event.delta.text;
528
+ }
529
+ }
530
+ break;
531
+ case "content_block_stop":
532
+ if (this._pendingMessage && this._pendingMessage.content) {
533
+ const block = this._pendingMessage.content[event.index];
534
+ if (block) {
535
+ block.pending = false;
536
+ }
537
+ }
538
+ break;
539
+ case "message_delta":
540
+ if (this._pendingMessage && event.delta) {
541
+ Object.assign(this._pendingMessage, event.delta);
542
+ }
543
+ break;
554
544
  }
555
- return results;
556
545
  }
557
- // TODO(burdon): Process remaining buffer?
558
- flush() {
559
- const remaining = this._buffer;
560
- this._buffer = "";
561
- return remaining.length > 0 ? [
562
- {
563
- type: "text",
564
- content: remaining
565
- }
566
- ] : [];
546
+ pushMessage(message) {
547
+ this._messages.push(message);
567
548
  }
568
549
  };
569
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/parser.ts";
570
- var MixedStreamParser = class {
571
- constructor() {
572
- this.message = new import_async2.Event();
573
- this.block = new import_async2.Event();
574
- this.update = new import_async2.Event();
575
- }
576
- _emitBlock(contentBlock, streamBlock) {
577
- const messageBlock = streamBlock ? mergeMessageBlock(contentBlock, streamBlock) : contentBlock;
578
- if (messageBlock) {
579
- if (messageBlock.type === "text" && messageBlock.text.length === 0) {
580
- return;
550
+ function* emitMessageAsEvents(message) {
551
+ yield {
552
+ type: "message_start",
553
+ message
554
+ };
555
+ yield {
556
+ type: "message_stop"
557
+ };
558
+ }
559
+ var createArtifactElement = (id) => `<artifact id=${id} />`;
560
+ var LLMModel = import_effect2.Schema.Literal(...DEFAULT_LLM_MODELS);
561
+ var ToolTypes = Object.freeze({
562
+ // TODO(dmaretskyi): Not implemented yet.
563
+ // DatabaseQuery: 'database_query',
564
+ TextToImage: "text_to_image"
565
+ });
566
+ var GenerateRequest = import_effect2.Schema.Struct({
567
+ spaceId: import_effect2.Schema.optional(import_artifact3.SpaceIdSchema),
568
+ threadId: import_effect2.Schema.optional(import_echo_schema2.ObjectId),
569
+ /**
570
+ * Preferred model or system default.
571
+ */
572
+ model: import_effect2.Schema.optional(LLMModel),
573
+ /**
574
+ * Tools available for the LLM.
575
+ */
576
+ tools: import_effect2.Schema.optional(import_effect2.Schema.Array(import_artifact3.Tool).pipe(import_effect2.Schema.mutable)),
577
+ /**
578
+ * System instructions to the LLM.
579
+ */
580
+ systemPrompt: import_effect2.Schema.optional(import_effect2.Schema.String),
581
+ /**
582
+ * History of messages to include in the context window.
583
+ */
584
+ // TODO(burdon): Rename messages.
585
+ history: import_effect2.Schema.optional(import_effect2.Schema.Array(import_artifact3.Message)),
586
+ /**
587
+ * Current request.
588
+ */
589
+ prompt: import_effect2.Schema.optional(import_artifact3.Message)
590
+ });
591
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/conversation/conversation.ts";
592
+ var runLLM = async (params) => {
593
+ let conversationResult = null;
594
+ const history = params.history ?? [];
595
+ const generate = async () => {
596
+ (0, import_log4.log)("llm generate", {
597
+ tools: params.tools
598
+ }, {
599
+ F: __dxlog_file3,
600
+ L: 44,
601
+ S: void 0,
602
+ C: (f, a) => f(...a)
603
+ });
604
+ const beginTs = Date.now();
605
+ const stream = await params.client.exec({
606
+ model: params.model,
607
+ spaceId: params.spaceId,
608
+ threadId: params.threadId,
609
+ history,
610
+ systemPrompt: params.system,
611
+ tools: params.tools
612
+ });
613
+ for await (const event of stream) {
614
+ params.logger?.(event);
615
+ }
616
+ await stream.complete();
617
+ const messages = [];
618
+ const message = messages.at(-1);
619
+ (0, import_invariant3.invariant)(message, void 0, {
620
+ F: __dxlog_file3,
621
+ L: 63,
622
+ S: void 0,
623
+ A: [
624
+ "message",
625
+ ""
626
+ ]
627
+ });
628
+ (0, import_log4.log)("llm result", {
629
+ time: Date.now() - beginTs,
630
+ message
631
+ }, {
632
+ F: __dxlog_file3,
633
+ L: 65,
634
+ S: void 0,
635
+ C: (f, a) => f(...a)
636
+ });
637
+ (0, import_invariant3.invariant)(message, void 0, {
638
+ F: __dxlog_file3,
639
+ L: 66,
640
+ S: void 0,
641
+ A: [
642
+ "message",
643
+ ""
644
+ ]
645
+ });
646
+ params.logger?.({
647
+ type: "message",
648
+ message
649
+ });
650
+ history.push(...messages.map((message2) => ({
651
+ ...message2,
652
+ content: message2.content.filter((block) => block.type !== "image")
653
+ })));
654
+ const isToolUse2 = message.content.at(-1)?.type === "tool_use";
655
+ if (isToolUse2) {
656
+ const toolCalls = message.content.filter((block) => block.type === "tool_use");
657
+ (0, import_invariant3.invariant)(toolCalls.length === 1, void 0, {
658
+ F: __dxlog_file3,
659
+ L: 77,
660
+ S: void 0,
661
+ A: [
662
+ "toolCalls.length === 1",
663
+ ""
664
+ ]
665
+ });
666
+ const toolCall = toolCalls[0];
667
+ const tool = params.tools.find((tool2) => tool2.name === toolCall.name);
668
+ if (!tool) {
669
+ throw new Error(`Tool not found: ${toolCall.name}`);
581
670
  }
582
- (0, import_invariant2.invariant)(this._message, void 0, {
671
+ (0, import_invariant3.invariant)(tool.execute, void 0, {
583
672
  F: __dxlog_file3,
584
- L: 46,
585
- S: this,
673
+ L: 84,
674
+ S: void 0,
586
675
  A: [
587
- "this._message",
676
+ "tool.execute",
588
677
  ""
589
678
  ]
590
679
  });
591
- this._message.content.push(messageBlock);
592
- this.block.emit(messageBlock);
593
- }
594
- }
595
- _emitUpdate(contentBlock, streamBlock) {
596
- const messageBlock = mergeMessageBlock(contentBlock, streamBlock);
597
- if (messageBlock) {
598
- messageBlock.pending = true;
599
- this.update.emit(messageBlock);
600
- }
601
- }
602
- /**
603
- * Parse stream until end.
604
- */
605
- async parse(stream) {
606
- const transformer = new StreamTransform();
607
- let contentBlock;
608
- let streamBlock;
609
- const stack = [];
610
- const messagesCollected = [];
611
- for await (const event of stream) {
612
- switch (event.type) {
613
- //
614
- // Messages.
615
- //
616
- case "message_start": {
617
- if (this._message) {
618
- import_log3.log.warn("unexpected message_start", void 0, {
619
- F: __dxlog_file3,
620
- L: 88,
621
- S: this,
622
- C: (f, a) => f(...a)
623
- });
624
- }
625
- this._message = (0, import_echo_schema.createStatic)(import_artifact2.Message, {
626
- role: "assistant",
627
- content: []
680
+ const toolResult = await tool.execute(toolCall.input);
681
+ switch (toolResult.kind) {
682
+ case "error": {
683
+ import_log4.log.warn("tool error", {
684
+ message: toolResult.message
685
+ }, {
686
+ F: __dxlog_file3,
687
+ L: 88,
688
+ S: void 0,
689
+ C: (f, a) => f(...a)
628
690
  });
629
- this.message.emit(this._message);
630
- break;
631
- }
632
- case "message_delta": {
633
- if (!this._message) {
634
- import_log3.log.warn("unexpected message_delta", void 0, {
635
- F: __dxlog_file3,
636
- L: 98,
637
- S: this,
638
- C: (f, a) => f(...a)
639
- });
640
- }
641
- break;
642
- }
643
- case "message_stop": {
644
- if (!this._message) {
645
- import_log3.log.warn("unexpected message_stop", void 0, {
646
- F: __dxlog_file3,
647
- L: 106,
648
- S: this,
649
- C: (f, a) => f(...a)
650
- });
651
- } else {
652
- messagesCollected.push(this._message);
653
- this._message = void 0;
654
- }
655
- break;
656
- }
657
- //
658
- // Content blocks.
659
- //
660
- case "content_block_start": {
661
- if (contentBlock) {
662
- import_log3.log.warn("unexpected content_block_start", {
663
- content: contentBlock
664
- }, {
665
- F: __dxlog_file3,
666
- L: 120,
667
- S: this,
668
- C: (f, a) => f(...a)
669
- });
670
- }
671
- contentBlock = event.content;
672
- break;
673
- }
674
- case "content_block_delta": {
675
- if (!contentBlock) {
676
- import_log3.log.warn("unexpected content_block_delta", void 0, {
677
- F: __dxlog_file3,
678
- L: 130,
679
- S: this,
680
- C: (f, a) => f(...a)
681
- });
682
- break;
683
- }
684
- switch (event.delta.type) {
685
- //
686
- // Text
687
- //
688
- case "text_delta": {
689
- const chunks = transformer.transform(event.delta.text);
690
- for (const chunk of chunks) {
691
- switch (streamBlock?.type) {
692
- //
693
- // XML Fragment.
694
- //
695
- case "tag": {
696
- if (chunk.type === "tag") {
697
- if (chunk.selfClosing) {
698
- streamBlock.content.push(chunk);
699
- } else if (chunk.closing) {
700
- if (stack.length > 0) {
701
- const top = stack.pop();
702
- (0, import_invariant2.invariant)(top && top.type === "tag", void 0, {
703
- F: __dxlog_file3,
704
- L: 154,
705
- S: this,
706
- A: [
707
- "top && top.type === 'tag'",
708
- ""
709
- ]
710
- });
711
- top.content.push(streamBlock);
712
- streamBlock = top;
713
- } else {
714
- this._emitBlock(contentBlock, streamBlock);
715
- streamBlock = void 0;
716
- }
717
- } else {
718
- stack.push(streamBlock);
719
- streamBlock = chunk;
720
- }
721
- } else {
722
- if (streamBlock.content.length === 0) {
723
- streamBlock.content.push(chunk);
724
- } else {
725
- const last = streamBlock.content.at(-1);
726
- (0, import_invariant2.invariant)(last, void 0, {
727
- F: __dxlog_file3,
728
- L: 171,
729
- S: this,
730
- A: [
731
- "last",
732
- ""
733
- ]
734
- });
735
- if (last.type === "text") {
736
- last.content += chunk.content;
737
- } else {
738
- streamBlock.content.push(chunk);
739
- }
740
- }
741
- }
742
- break;
743
- }
744
- //
745
- // Text Fragment.
746
- //
747
- case "text": {
748
- if (chunk.type === "tag") {
749
- this._emitBlock(contentBlock, streamBlock);
750
- if (chunk.selfClosing) {
751
- this._emitBlock(contentBlock, chunk);
752
- streamBlock = void 0;
753
- } else {
754
- streamBlock = chunk;
755
- }
756
- } else {
757
- streamBlock.content += chunk.content;
758
- }
759
- break;
760
- }
761
- //
762
- // No current chunk.
763
- //
764
- default: {
765
- if (chunk.type === "tag" && chunk.selfClosing) {
766
- this._emitBlock(contentBlock, chunk);
767
- } else {
768
- streamBlock = chunk;
769
- }
770
- }
771
- }
772
- }
773
- break;
774
- }
775
- //
776
- // JSON
777
- //
778
- case "input_json_delta": {
779
- if (!contentBlock) {
780
- import_log3.log.warn("unexpected input_json_delta", {
781
- contentBlock
782
- }, {
783
- F: __dxlog_file3,
784
- L: 221,
785
- S: this,
786
- C: (f, a) => f(...a)
787
- });
788
- break;
691
+ const resultMessage = {
692
+ id: import_echo_schema3.ObjectId.random(),
693
+ spaceId: params.spaceId,
694
+ threadId: params.threadId,
695
+ role: "user",
696
+ content: [
697
+ {
698
+ type: "tool_result",
699
+ toolUseId: toolCall.id,
700
+ content: toolResult.message,
701
+ isError: true
789
702
  }
790
- if (streamBlock?.type === "json") {
791
- streamBlock.content += event.delta.partial_json;
792
- } else {
793
- streamBlock = {
794
- type: "json",
795
- content: event.delta.partial_json
796
- };
703
+ ]
704
+ };
705
+ params.logger?.({
706
+ type: "message",
707
+ message: resultMessage
708
+ });
709
+ history.push(resultMessage);
710
+ return true;
711
+ }
712
+ case "success": {
713
+ (0, import_log4.log)("tool success", {
714
+ result: toolResult.result
715
+ }, {
716
+ F: __dxlog_file3,
717
+ L: 110,
718
+ S: void 0,
719
+ C: (f, a) => f(...a)
720
+ });
721
+ const resultMessage = {
722
+ id: import_echo_schema3.ObjectId.random(),
723
+ spaceId: params.spaceId,
724
+ threadId: params.threadId,
725
+ role: "user",
726
+ content: [
727
+ {
728
+ type: "tool_result",
729
+ toolUseId: toolCall.id,
730
+ content: JSON.stringify(toolResult.result)
797
731
  }
798
- break;
799
- }
800
- }
801
- break;
732
+ ]
733
+ };
734
+ params.logger?.({
735
+ type: "message",
736
+ message: resultMessage
737
+ });
738
+ history.push(resultMessage);
739
+ return true;
802
740
  }
803
- case "content_block_stop": {
804
- if (!contentBlock) {
805
- import_log3.log.warn("unexpected content_block_stop", void 0, {
806
- F: __dxlog_file3,
807
- L: 238,
808
- S: this,
809
- C: (f, a) => f(...a)
810
- });
811
- break;
812
- }
813
- this._emitBlock(contentBlock, streamBlock);
814
- contentBlock = void 0;
815
- streamBlock = void 0;
816
- break;
741
+ case "break": {
742
+ (0, import_log4.log)("tool break", {
743
+ result: toolResult.result
744
+ }, {
745
+ F: __dxlog_file3,
746
+ L: 131,
747
+ S: void 0,
748
+ C: (f, a) => f(...a)
749
+ });
750
+ conversationResult = toolResult.result;
751
+ return false;
817
752
  }
818
753
  }
819
- if (contentBlock && streamBlock) {
820
- this._emitUpdate(contentBlock, streamBlock);
821
- }
822
754
  }
823
- return messagesCollected;
755
+ return false;
756
+ };
757
+ while (await generate()) {
824
758
  }
759
+ return {
760
+ result: conversationResult,
761
+ history
762
+ };
825
763
  };
826
- var mergeMessageBlock = (contentBlock, streamBlock) => {
827
- (0, import_log3.log)("mergeMessageBlock", {
828
- contentBlock,
829
- streamBlock
830
- }, {
764
+ var isToolUse = (message, { onlyToolNames } = {}) => {
765
+ const block = message.content.at(-1);
766
+ (0, import_invariant3.invariant)(block, void 0, {
831
767
  F: __dxlog_file3,
832
- L: 265,
768
+ L: 152,
833
769
  S: void 0,
834
- C: (f, a) => f(...a)
770
+ A: [
771
+ "block",
772
+ ""
773
+ ]
835
774
  });
836
- switch (streamBlock.type) {
837
- //
838
- // Text
839
- //
840
- case "text": {
775
+ return block.type === "tool_use" && (!onlyToolNames || onlyToolNames.includes(block.name));
776
+ };
777
+ var runTools = async ({ message, tools, extensions }) => {
778
+ const toolCalls = message.content.filter((block) => block.type === "tool_use");
779
+ (0, import_invariant3.invariant)(toolCalls.length === 1, void 0, {
780
+ F: __dxlog_file3,
781
+ L: 174,
782
+ S: void 0,
783
+ A: [
784
+ "toolCalls.length === 1",
785
+ ""
786
+ ]
787
+ });
788
+ const toolCall = toolCalls[0];
789
+ const tool = tools.find((tool2) => tool2.name === toolCall.name);
790
+ if (!tool) {
791
+ throw new Error(`Tool not found: ${toolCall.name}`);
792
+ }
793
+ let toolResult;
794
+ try {
795
+ (0, import_invariant3.invariant)(tool.execute, void 0, {
796
+ F: __dxlog_file3,
797
+ L: 183,
798
+ S: void 0,
799
+ A: [
800
+ "tool.execute",
801
+ ""
802
+ ]
803
+ });
804
+ toolResult = await tool.execute(toolCall.input, {
805
+ extensions
806
+ });
807
+ } catch (error) {
808
+ (0, import_log4.log)("tool error", {
809
+ error
810
+ }, {
811
+ F: __dxlog_file3,
812
+ L: 186,
813
+ S: void 0,
814
+ C: (f, a) => f(...a)
815
+ });
816
+ toolResult = import_artifact4.ToolResult.Error(error.message);
817
+ }
818
+ switch (toolResult.kind) {
819
+ case "error": {
820
+ (0, import_log4.log)("tool error", {
821
+ message: toolResult.message
822
+ }, {
823
+ F: __dxlog_file3,
824
+ L: 192,
825
+ S: void 0,
826
+ C: (f, a) => f(...a)
827
+ });
828
+ const resultMessage = (0, import_echo_schema3.createStatic)(import_artifact4.Message, {
829
+ role: "user",
830
+ content: [
831
+ {
832
+ type: "tool_result",
833
+ toolUseId: toolCall.id,
834
+ content: toolResult.message,
835
+ isError: true
836
+ }
837
+ ]
838
+ });
841
839
  return {
842
- ...contentBlock,
843
- type: "text",
844
- text: streamBlock.content
840
+ type: "continue",
841
+ message: resultMessage
845
842
  };
846
843
  }
847
- //
848
- // XML
849
- //
850
- case "tag": {
851
- switch (streamBlock.tag) {
852
- case "cot": {
853
- const content = streamBlock.content.map((block) => {
854
- switch (block.type) {
855
- case "text":
856
- return block.content;
857
- default:
858
- return null;
859
- }
860
- }).filter(import_util.isNotFalsy).join("\n");
861
- return {
862
- ...contentBlock,
863
- type: "text",
864
- disposition: "cot",
865
- text: content
866
- };
867
- }
868
- case "artifact": {
869
- const { attributes } = streamBlock;
870
- return {
871
- type: "json",
872
- disposition: "artifact",
873
- json: JSON.stringify(attributes)
874
- };
875
- }
876
- case "suggest": {
877
- if (streamBlock.content.length === 1 && streamBlock.content[0].type === "text") {
878
- return {
879
- type: "json",
880
- disposition: "suggest",
881
- json: JSON.stringify({
882
- text: streamBlock.content[0].content
883
- })
884
- };
885
- }
886
- break;
887
- }
888
- case "select": {
889
- return {
890
- type: "json",
891
- disposition: "select",
892
- json: JSON.stringify({
893
- options: streamBlock.content.flatMap((content) => content.type === "tag" && content.content.length === 1 && content.content[0].type === "text" ? [
894
- content.content[0].content
895
- ] : [])
896
- })
897
- };
898
- }
899
- case "tool-list": {
900
- return {
901
- type: "json",
902
- disposition: "tool_list",
903
- json: JSON.stringify({})
904
- };
905
- }
906
- }
907
- break;
844
+ case "success": {
845
+ (0, import_log4.log)("tool success", {
846
+ result: toolResult.result
847
+ }, {
848
+ F: __dxlog_file3,
849
+ L: 213,
850
+ S: void 0,
851
+ C: (f, a) => f(...a)
852
+ });
853
+ const resultMessage = (0, import_echo_schema3.createStatic)(import_artifact4.Message, {
854
+ role: "user",
855
+ content: [
856
+ {
857
+ type: "tool_result",
858
+ toolUseId: toolCall.id,
859
+ content: typeof toolResult.result === "string" ? toolResult.result : JSON.stringify(toolResult.result) ?? ""
860
+ },
861
+ ...toolResult.extractContentBlocks ?? []
862
+ ]
863
+ });
864
+ return {
865
+ type: "continue",
866
+ message: resultMessage
867
+ };
908
868
  }
909
- //
910
- // JSON
911
- //
912
- case "json": {
913
- switch (contentBlock.type) {
914
- case "tool_use": {
915
- return {
916
- ...contentBlock,
917
- input: (0, import_util.safeParseJson)(streamBlock.content) ?? {}
918
- };
919
- }
920
- }
869
+ case "break": {
870
+ (0, import_log4.log)("tool break", {
871
+ result: toolResult.result
872
+ }, {
873
+ F: __dxlog_file3,
874
+ L: 234,
875
+ S: void 0,
876
+ C: (f, a) => f(...a)
877
+ });
921
878
  return {
922
- ...contentBlock,
923
- type: "json",
924
- disposition: "artifact",
925
- json: streamBlock.content
879
+ type: "break",
880
+ result: toolResult.result
926
881
  };
927
882
  }
928
883
  }
929
884
  };
930
- var createArtifactElement = (id) => `<artifact id=${id} />`;
931
- var LLMModel = import_schema2.Schema.Literal(...DEFAULT_LLM_MODELS);
932
- var ToolTypes = Object.freeze({
933
- // TODO(dmaretskyi): Not implemented yet.
934
- // DatabaseQuery: 'database_query',
935
- TextToImage: "text_to_image"
936
- });
937
- var GenerateRequest = import_schema2.Schema.Struct({
938
- spaceId: import_schema2.Schema.optional(import_artifact3.SpaceIdSchema),
939
- threadId: import_schema2.Schema.optional(import_echo_schema2.ObjectId),
940
- /**
941
- * Preferred model or system default.
942
- */
943
- model: import_schema2.Schema.optional(LLMModel),
944
- /**
945
- * Tools available for the LLM.
946
- */
947
- tools: import_schema2.Schema.optional(import_schema2.Schema.Array(import_artifact3.Tool).pipe(import_schema2.Schema.mutable)),
885
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/ollama-client.ts";
886
+ var DEFAULT_OLLAMA_URL = "http://localhost:11434";
887
+ var DEFAULT_OLLAMA_MODEL = "llama3.2:1b";
888
+ var OllamaClient = class _OllamaClient {
948
889
  /**
949
- * System instructions to the LLM.
950
- */
951
- systemPrompt: import_schema2.Schema.optional(import_schema2.Schema.String),
952
- /**
953
- * History of messages to include in the context window.
890
+ * Create a test client with small local model and no temperature for predictable results.
954
891
  */
955
- // TODO(burdon): Rename messages.
956
- history: import_schema2.Schema.optional(import_schema2.Schema.Array(import_artifact3.Message)),
892
+ static createClient(options) {
893
+ return new _OllamaClient({
894
+ tools: options?.tools,
895
+ overrides: {
896
+ model: DEFAULT_OLLAMA_MODEL,
897
+ temperature: 0
898
+ }
899
+ });
900
+ }
957
901
  /**
958
- * Current request.
902
+ * Check if Ollama server is running and accessible.
903
+ * @returns Promise that resolves to true if Ollama is running, false otherwise.
959
904
  */
960
- prompt: import_schema2.Schema.optional(import_artifact3.Message)
961
- });
962
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/conversation/conversation.ts";
963
- var runLLM = async (params) => {
964
- let conversationResult = null;
965
- const history = params.history ?? [];
966
- const generate = async () => {
967
- (0, import_log4.log)("llm generate", {
968
- tools: params.tools
969
- }, {
970
- F: __dxlog_file4,
971
- L: 44,
972
- S: void 0,
973
- C: (f, a) => f(...a)
974
- });
975
- const beginTs = Date.now();
976
- const stream = await params.client.exec({
977
- model: params.model,
978
- spaceId: params.spaceId,
979
- threadId: params.threadId,
980
- history,
981
- systemPrompt: params.system,
982
- tools: params.tools
983
- });
984
- for await (const event of stream) {
985
- params.logger?.(event);
905
+ static async isRunning() {
906
+ try {
907
+ const response = await fetch(`${DEFAULT_OLLAMA_URL}/api/version`, {
908
+ method: "GET",
909
+ headers: {
910
+ "Content-Type": "application/json"
911
+ },
912
+ signal: AbortSignal.timeout(100)
913
+ });
914
+ return response.ok;
915
+ } catch (error) {
916
+ return false;
986
917
  }
987
- await stream.complete();
988
- const messages = [];
989
- const message = messages.at(-1);
990
- (0, import_invariant3.invariant)(message, void 0, {
918
+ }
919
+ constructor({ endpoint, tools, overrides, maxToolInvocations }) {
920
+ this._endpoint = endpoint ?? DEFAULT_OLLAMA_URL;
921
+ this._tools = tools ?? [];
922
+ this._modelOverride = overrides?.model;
923
+ this._temperatureOverride = overrides?.temperature;
924
+ this._maxToolInvocations = maxToolInvocations ?? 3;
925
+ }
926
+ _getEmbededTools(clientTools) {
927
+ return [
928
+ ...this._tools,
929
+ ...clientTools.filter((tool) => tool.type !== void 0 && WELL_KNOWN_TOOLS[tool.type]).map((tool) => WELL_KNOWN_TOOLS[tool.type])
930
+ ];
931
+ }
932
+ async *_generateStream(request, signal) {
933
+ (0, import_invariant2.invariant)(request.prompt === void 0, "Prompt must be in history", {
991
934
  F: __dxlog_file4,
992
- L: 63,
993
- S: void 0,
935
+ L: 99,
936
+ S: this,
994
937
  A: [
995
- "message",
996
- ""
938
+ "request.prompt === undefined",
939
+ "'Prompt must be in history'"
997
940
  ]
998
941
  });
999
- (0, import_log4.log)("llm result", {
1000
- time: Date.now() - beginTs,
1001
- message
942
+ const ollamaRequest = {
943
+ model: this._modelOverride ?? request.model ?? "llama3",
944
+ messages: [],
945
+ stream: true,
946
+ options: {
947
+ temperature: this._temperatureOverride ?? 0.7
948
+ }
949
+ };
950
+ if (request.systemPrompt) {
951
+ ollamaRequest.messages.push({
952
+ role: "system",
953
+ content: request.systemPrompt
954
+ });
955
+ }
956
+ if (request.history?.length) {
957
+ for (const message of request.history) {
958
+ const role = message.role === "assistant" ? "assistant" : "user";
959
+ if (message.content.length === 0) {
960
+ continue;
961
+ }
962
+ for (const content of message.content) {
963
+ switch (content.type) {
964
+ case "text": {
965
+ ollamaRequest.messages.push({
966
+ role,
967
+ content: content.text
968
+ });
969
+ break;
970
+ }
971
+ case "tool_use": {
972
+ ollamaRequest.messages.push({
973
+ role: "assistant",
974
+ content: "",
975
+ tool_calls: [
976
+ {
977
+ function: {
978
+ name: content.name,
979
+ arguments: content.input
980
+ }
981
+ }
982
+ ]
983
+ });
984
+ break;
985
+ }
986
+ case "tool_result": {
987
+ ollamaRequest.messages.push({
988
+ role: "tool",
989
+ content: JSON.stringify({
990
+ type: "tool_result",
991
+ toolUseId: content.toolUseId,
992
+ content: content.content
993
+ })
994
+ });
995
+ break;
996
+ }
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+ if (request.tools?.length || this._tools.length) {
1002
+ const allTools = [
1003
+ ...request.tools ?? [],
1004
+ ...this._tools
1005
+ ];
1006
+ const withWellKnownTools = allTools.map((tool) => tool.type !== void 0 && WELL_KNOWN_TOOLS[tool.type] ? WELL_KNOWN_TOOLS[tool.type] : tool);
1007
+ if (withWellKnownTools.length > 0) {
1008
+ ollamaRequest.tools = withWellKnownTools.map((tool) => ({
1009
+ type: "function",
1010
+ function: {
1011
+ name: tool.name,
1012
+ description: tool.description,
1013
+ parameters: {
1014
+ type: "object",
1015
+ properties: tool.parameters?.properties,
1016
+ required: tool.parameters?.required
1017
+ }
1018
+ }
1019
+ }));
1020
+ }
1021
+ }
1022
+ import_log3.log.info("generate request", {
1023
+ history: request.history,
1024
+ prompt: request.prompt,
1025
+ ollamaRequest
1002
1026
  }, {
1003
1027
  F: __dxlog_file4,
1004
- L: 65,
1005
- S: void 0,
1028
+ L: 193,
1029
+ S: this,
1006
1030
  C: (f, a) => f(...a)
1007
1031
  });
1008
- (0, import_invariant3.invariant)(message, void 0, {
1009
- F: __dxlog_file4,
1010
- L: 66,
1011
- S: void 0,
1012
- A: [
1013
- "message",
1014
- ""
1015
- ]
1032
+ const response = await fetch(`${this._endpoint}/api/chat`, {
1033
+ method: "POST",
1034
+ headers: {
1035
+ "Content-Type": "application/json"
1036
+ },
1037
+ body: JSON.stringify(ollamaRequest),
1038
+ signal
1016
1039
  });
1017
- params.logger?.({
1018
- type: "message",
1019
- message
1040
+ if (!response.ok) {
1041
+ throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
1042
+ }
1043
+ if (!response.body) {
1044
+ throw new Error("Ollama API returned no response body");
1045
+ }
1046
+ const reader = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new OllamaDecoderStream()).getReader();
1047
+ try {
1048
+ const messageId = import_echo_schema.ObjectId.random();
1049
+ yield {
1050
+ type: "message_start",
1051
+ message: {
1052
+ id: messageId,
1053
+ role: "assistant",
1054
+ content: []
1055
+ }
1056
+ };
1057
+ const textBlock = {
1058
+ type: "text",
1059
+ text: ""
1060
+ };
1061
+ let currentBlockIndex = 0;
1062
+ yield {
1063
+ type: "content_block_start",
1064
+ index: currentBlockIndex,
1065
+ content: textBlock
1066
+ };
1067
+ while (true) {
1068
+ const { done, value: data } = await reader.read();
1069
+ if (done) {
1070
+ break;
1071
+ }
1072
+ import_log3.log.info("ollama data", {
1073
+ data
1074
+ }, {
1075
+ F: __dxlog_file4,
1076
+ L: 256,
1077
+ S: this,
1078
+ C: (f, a) => f(...a)
1079
+ });
1080
+ if (data.message?.content) {
1081
+ yield {
1082
+ type: "content_block_delta",
1083
+ index: 0,
1084
+ delta: {
1085
+ type: "text_delta",
1086
+ text: data.message.content
1087
+ }
1088
+ };
1089
+ }
1090
+ if (data.message?.tool_calls && data.message?.tool_calls?.length > 0) {
1091
+ if (data.message.tool_calls.length > 1) {
1092
+ import_log3.log.warn("Ollama returned multiple tool calls. Only the first one will be used.", void 0, {
1093
+ F: __dxlog_file4,
1094
+ L: 273,
1095
+ S: this,
1096
+ C: (f, a) => f(...a)
1097
+ });
1098
+ }
1099
+ yield {
1100
+ type: "content_block_stop",
1101
+ index: currentBlockIndex++
1102
+ };
1103
+ yield {
1104
+ type: "content_block_start",
1105
+ index: currentBlockIndex,
1106
+ content: {
1107
+ type: "tool_use",
1108
+ id: import_echo_schema.ObjectId.random(),
1109
+ name: data.message.tool_calls[0].function.name,
1110
+ input: sanitizeToolArguments(data.message.tool_calls[0].function.arguments)
1111
+ }
1112
+ };
1113
+ yield {
1114
+ type: "message_delta",
1115
+ delta: {
1116
+ stopReason: "tool_use"
1117
+ }
1118
+ };
1119
+ }
1120
+ }
1121
+ yield {
1122
+ type: "content_block_stop",
1123
+ index: currentBlockIndex
1124
+ };
1125
+ yield {
1126
+ type: "message_stop"
1127
+ };
1128
+ } finally {
1129
+ reader.releaseLock();
1130
+ }
1131
+ }
1132
+ async exec(request) {
1133
+ const controller = new AbortController();
1134
+ try {
1135
+ return new GenerationStreamImpl(controller, async function* () {
1136
+ const collector = new MessageCollector();
1137
+ let toolInvocations = 0;
1138
+ while (true) {
1139
+ for await (const event of this._generateStream({
1140
+ ...request,
1141
+ history: [
1142
+ ...request.history ?? [],
1143
+ ...request.prompt ? [
1144
+ request.prompt
1145
+ ] : [],
1146
+ ...collector.messages
1147
+ ],
1148
+ prompt: void 0
1149
+ }, controller.signal)) {
1150
+ collector.push(event);
1151
+ yield event;
1152
+ }
1153
+ if (collector.messages.length > 0 && !isToolUse(collector.messages.at(-1), {
1154
+ onlyToolNames: this._getEmbededTools(request.tools ?? []).map((tool) => tool.name)
1155
+ })) {
1156
+ break;
1157
+ }
1158
+ if (++toolInvocations > this._maxToolInvocations) {
1159
+ throw new Error("Maximum number of tool invocations reached");
1160
+ }
1161
+ const result = await runTools({
1162
+ message: collector.messages.at(-1),
1163
+ tools: this._getEmbededTools(request.tools ?? [])
1164
+ });
1165
+ switch (result.type) {
1166
+ case "continue": {
1167
+ collector.pushMessage(result.message);
1168
+ yield* emitMessageAsEvents(result.message);
1169
+ break;
1170
+ }
1171
+ case "break": {
1172
+ throw new Error("Tool use breaks not allowed");
1173
+ }
1174
+ }
1175
+ }
1176
+ }.bind(this));
1177
+ } catch (error) {
1178
+ controller.abort();
1179
+ throw error;
1180
+ }
1181
+ }
1182
+ };
1183
+ var sanitizeToolArguments = (args) => {
1184
+ if (args.type === "object" && typeof args.properties === "object" && Array.isArray(args.required)) {
1185
+ return args.properties;
1186
+ }
1187
+ return args;
1188
+ };
1189
+ var SAMPLE_IMAGE_URL = "https://images.nightcafe.studio/jobs/BNmcRhHCM1JRKoUtqSei/BNmcRhHCM1JRKoUtqSei--1--5b9rv.jpg";
1190
+ var WELL_KNOWN_TOOLS = {
1191
+ [ToolTypes.TextToImage]: (0, import_artifact2.defineTool)("system", {
1192
+ name: "text-to-image",
1193
+ description: "Generate an image from a text prompt",
1194
+ schema: import_echo_schema.S.Struct({
1195
+ prompt: import_echo_schema.S.String.annotations({
1196
+ description: "The text prompt describing the image to generate"
1197
+ })
1198
+ }),
1199
+ execute: async ({ prompt }) => {
1200
+ const image = await fetch(SAMPLE_IMAGE_URL).then(async (res) => Buffer.from(await res.arrayBuffer()));
1201
+ const imageBase64 = image.toString("base64");
1202
+ const id = import_echo_schema.ObjectId.random();
1203
+ return import_artifact2.ToolResult.Success(`The generation was successful. Image ID: ${id} Prompt: ${prompt}`, [
1204
+ {
1205
+ type: "image",
1206
+ id,
1207
+ source: {
1208
+ type: "base64",
1209
+ mediaType: "image/jpeg",
1210
+ data: imageBase64
1211
+ }
1212
+ }
1213
+ ]);
1214
+ }
1215
+ })
1216
+ };
1217
+ var OllamaDecoderStream = class extends TransformStream {
1218
+ constructor() {
1219
+ super({
1220
+ transform: (chunk, controller) => {
1221
+ this._buffer += chunk;
1222
+ const lines = this._buffer.split("\n");
1223
+ this._buffer = lines.pop() || "";
1224
+ for (const line of lines) {
1225
+ controller.enqueue(JSON.parse(line.trim()));
1226
+ }
1227
+ },
1228
+ flush: (controller) => {
1229
+ this._buffer = this._buffer.trim();
1230
+ if (this._buffer.length > 0) {
1231
+ controller.enqueue(JSON.parse(this._buffer));
1232
+ }
1233
+ }
1020
1234
  });
1021
- history.push(...messages.map((message2) => ({
1022
- ...message2,
1023
- content: message2.content.filter((block) => block.type !== "image")
1024
- })));
1025
- const isToolUse2 = message.content.at(-1)?.type === "tool_use";
1026
- if (isToolUse2) {
1027
- const toolCalls = message.content.filter((block) => block.type === "tool_use");
1028
- (0, import_invariant3.invariant)(toolCalls.length === 1, void 0, {
1029
- F: __dxlog_file4,
1030
- L: 77,
1031
- S: void 0,
1032
- A: [
1033
- "toolCalls.length === 1",
1034
- ""
1035
- ]
1036
- });
1037
- const toolCall = toolCalls[0];
1038
- const tool = params.tools.find((tool2) => tool2.name === toolCall.name);
1039
- if (!tool) {
1040
- throw new Error(`Tool not found: ${toolCall.name}`);
1235
+ this._buffer = "";
1236
+ }
1237
+ };
1238
+ var textChunk = P.regexp(/[^<]+/).map((content) => ({
1239
+ type: "text",
1240
+ content
1241
+ }));
1242
+ var attribute = P.seq(P.regexp(/[a-zA-Z_][a-zA-Z0-9_-]*/), P.string("=").trim(P.optWhitespace), P.alt(P.regexp(/"[^"]*"/).map((s) => s.slice(1, -1)), P.regexp(/'[^']*'/).map((s) => s.slice(1, -1)))).map(([name, _, value]) => [
1243
+ name,
1244
+ value
1245
+ ]);
1246
+ var tagName = P.regexp(/[a-zA-Z_][a-zA-Z0-9_-]*/);
1247
+ var selfClosingTag = P.seqMap(
1248
+ //
1249
+ P.string("<"),
1250
+ tagName,
1251
+ P.optWhitespace.then(attribute).many(),
1252
+ P.optWhitespace.then(P.string("/>")),
1253
+ P.optWhitespace,
1254
+ (_, tag, attributes, __) => ({
1255
+ type: "tag",
1256
+ tag,
1257
+ attributes: Object.fromEntries(attributes),
1258
+ content: [],
1259
+ selfClosing: true
1260
+ })
1261
+ );
1262
+ var openTag = P.seqMap(
1263
+ //
1264
+ P.string("<"),
1265
+ tagName,
1266
+ P.optWhitespace.then(attribute).many(),
1267
+ P.string(">"),
1268
+ P.regexp(/[^<]*/),
1269
+ (_, tag, attributes, __, content) => ({
1270
+ type: "tag",
1271
+ tag,
1272
+ attributes: Object.fromEntries(attributes),
1273
+ content: content.length ? [
1274
+ {
1275
+ type: "text",
1276
+ content
1277
+ }
1278
+ ] : []
1279
+ })
1280
+ );
1281
+ var closeTag = P.seqMap(
1282
+ //
1283
+ P.string("</"),
1284
+ tagName,
1285
+ P.string(">"),
1286
+ P.optWhitespace,
1287
+ (_, tag) => ({
1288
+ type: "tag",
1289
+ tag,
1290
+ content: [],
1291
+ closing: true
1292
+ })
1293
+ );
1294
+ var mixedChunk = P.alt(selfClosingTag, openTag, closeTag, textChunk);
1295
+ var StreamTransform = class {
1296
+ constructor() {
1297
+ this._buffer = "";
1298
+ }
1299
+ transform(chunk) {
1300
+ this._buffer += chunk;
1301
+ const results = [];
1302
+ const parser = mixedChunk.many().skip(P.optWhitespace);
1303
+ const result = parser.parse(this._buffer);
1304
+ if (result.status) {
1305
+ for (const chunk2 of result.value) {
1306
+ results.push(chunk2);
1041
1307
  }
1042
- (0, import_invariant3.invariant)(tool.execute, void 0, {
1043
- F: __dxlog_file4,
1044
- L: 84,
1045
- S: void 0,
1308
+ this._buffer = "";
1309
+ }
1310
+ return results;
1311
+ }
1312
+ // TODO(burdon): Process remaining buffer?
1313
+ flush() {
1314
+ const remaining = this._buffer;
1315
+ this._buffer = "";
1316
+ return remaining.length > 0 ? [
1317
+ {
1318
+ type: "text",
1319
+ content: remaining
1320
+ }
1321
+ ] : [];
1322
+ }
1323
+ };
1324
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/parser.ts";
1325
+ var MixedStreamParser = class {
1326
+ constructor() {
1327
+ this.message = new import_async2.Event();
1328
+ this.block = new import_async2.Event();
1329
+ this.update = new import_async2.Event();
1330
+ this.streamEvent = new import_async2.Event();
1331
+ }
1332
+ _emitBlock(contentBlock, streamBlock) {
1333
+ const messageBlock = streamBlock ? mergeMessageBlock(contentBlock, streamBlock) : contentBlock;
1334
+ if (messageBlock) {
1335
+ if (messageBlock.type === "text" && messageBlock.text.length === 0) {
1336
+ return;
1337
+ }
1338
+ (0, import_invariant4.invariant)(this._message, void 0, {
1339
+ F: __dxlog_file5,
1340
+ L: 49,
1341
+ S: this,
1046
1342
  A: [
1047
- "tool.execute",
1343
+ "this._message",
1048
1344
  ""
1049
1345
  ]
1050
1346
  });
1051
- const toolResult = await tool.execute(toolCall.input);
1052
- switch (toolResult.kind) {
1053
- case "error": {
1054
- import_log4.log.warn("tool error", {
1055
- message: toolResult.message
1056
- }, {
1057
- F: __dxlog_file4,
1058
- L: 88,
1059
- S: void 0,
1060
- C: (f, a) => f(...a)
1061
- });
1062
- const resultMessage = {
1063
- id: import_echo_schema3.ObjectId.random(),
1064
- spaceId: params.spaceId,
1065
- threadId: params.threadId,
1066
- role: "user",
1347
+ this._message.content.push(messageBlock);
1348
+ this.block.emit(messageBlock);
1349
+ }
1350
+ }
1351
+ _emitUpdate(contentBlock, streamBlock) {
1352
+ const messageBlock = mergeMessageBlock(contentBlock, streamBlock);
1353
+ if (messageBlock) {
1354
+ messageBlock.pending = true;
1355
+ this.update.emit(messageBlock);
1356
+ }
1357
+ }
1358
+ /**
1359
+ * Parse stream until end.
1360
+ */
1361
+ async parse(stream) {
1362
+ const transformer = new StreamTransform();
1363
+ let contentBlock;
1364
+ let streamBlock;
1365
+ const stack = [];
1366
+ const messagesCollected = [];
1367
+ for await (const event of stream) {
1368
+ this.streamEvent.emit(event);
1369
+ switch (event.type) {
1370
+ //
1371
+ // Messages.
1372
+ //
1373
+ case "message_start": {
1374
+ if (this._message) {
1375
+ import_log5.log.warn("unexpected message_start", void 0, {
1376
+ F: __dxlog_file5,
1377
+ L: 93,
1378
+ S: this,
1379
+ C: (f, a) => f(...a)
1380
+ });
1381
+ }
1382
+ this._message = (0, import_echo_schema4.createStatic)(import_artifact5.Message, {
1383
+ role: event.message.role,
1067
1384
  content: [
1068
- {
1069
- type: "tool_result",
1070
- toolUseId: toolCall.id,
1071
- content: toolResult.message,
1072
- isError: true
1073
- }
1385
+ ...event.message.content
1074
1386
  ]
1075
- };
1076
- params.logger?.({
1077
- type: "message",
1078
- message: resultMessage
1079
1387
  });
1080
- history.push(resultMessage);
1081
- return true;
1388
+ this.message.emit(this._message);
1389
+ break;
1082
1390
  }
1083
- case "success": {
1084
- (0, import_log4.log)("tool success", {
1085
- result: toolResult.result
1086
- }, {
1087
- F: __dxlog_file4,
1088
- L: 110,
1089
- S: void 0,
1090
- C: (f, a) => f(...a)
1091
- });
1092
- const resultMessage = {
1093
- id: import_echo_schema3.ObjectId.random(),
1094
- spaceId: params.spaceId,
1095
- threadId: params.threadId,
1096
- role: "user",
1097
- content: [
1098
- {
1099
- type: "tool_result",
1100
- toolUseId: toolCall.id,
1101
- content: JSON.stringify(toolResult.result)
1391
+ case "message_delta": {
1392
+ if (!this._message) {
1393
+ import_log5.log.warn("unexpected message_delta", void 0, {
1394
+ F: __dxlog_file5,
1395
+ L: 103,
1396
+ S: this,
1397
+ C: (f, a) => f(...a)
1398
+ });
1399
+ }
1400
+ break;
1401
+ }
1402
+ case "message_stop": {
1403
+ if (!this._message) {
1404
+ import_log5.log.warn("unexpected message_stop", void 0, {
1405
+ F: __dxlog_file5,
1406
+ L: 111,
1407
+ S: this,
1408
+ C: (f, a) => f(...a)
1409
+ });
1410
+ } else {
1411
+ messagesCollected.push(this._message);
1412
+ this._message = void 0;
1413
+ }
1414
+ break;
1415
+ }
1416
+ //
1417
+ // Content blocks.
1418
+ //
1419
+ case "content_block_start": {
1420
+ if (contentBlock) {
1421
+ import_log5.log.warn("unexpected content_block_start", {
1422
+ content: contentBlock
1423
+ }, {
1424
+ F: __dxlog_file5,
1425
+ L: 125,
1426
+ S: this,
1427
+ C: (f, a) => f(...a)
1428
+ });
1429
+ }
1430
+ contentBlock = event.content;
1431
+ break;
1432
+ }
1433
+ case "content_block_delta": {
1434
+ if (!contentBlock) {
1435
+ import_log5.log.warn("unexpected content_block_delta", void 0, {
1436
+ F: __dxlog_file5,
1437
+ L: 135,
1438
+ S: this,
1439
+ C: (f, a) => f(...a)
1440
+ });
1441
+ break;
1442
+ }
1443
+ switch (event.delta.type) {
1444
+ //
1445
+ // Text
1446
+ //
1447
+ case "text_delta": {
1448
+ const chunks = transformer.transform(event.delta.text);
1449
+ for (const chunk of chunks) {
1450
+ switch (streamBlock?.type) {
1451
+ //
1452
+ // XML Fragment.
1453
+ //
1454
+ case "tag": {
1455
+ if (chunk.type === "tag") {
1456
+ if (chunk.selfClosing) {
1457
+ streamBlock.content.push(chunk);
1458
+ } else if (chunk.closing) {
1459
+ if (stack.length > 0) {
1460
+ const top = stack.pop();
1461
+ (0, import_invariant4.invariant)(top && top.type === "tag", void 0, {
1462
+ F: __dxlog_file5,
1463
+ L: 159,
1464
+ S: this,
1465
+ A: [
1466
+ "top && top.type === 'tag'",
1467
+ ""
1468
+ ]
1469
+ });
1470
+ top.content.push(streamBlock);
1471
+ streamBlock = top;
1472
+ } else {
1473
+ this._emitBlock(contentBlock, streamBlock);
1474
+ streamBlock = void 0;
1475
+ }
1476
+ } else {
1477
+ stack.push(streamBlock);
1478
+ streamBlock = chunk;
1479
+ }
1480
+ } else {
1481
+ if (streamBlock.content.length === 0) {
1482
+ streamBlock.content.push(chunk);
1483
+ } else {
1484
+ const last = streamBlock.content.at(-1);
1485
+ (0, import_invariant4.invariant)(last, void 0, {
1486
+ F: __dxlog_file5,
1487
+ L: 176,
1488
+ S: this,
1489
+ A: [
1490
+ "last",
1491
+ ""
1492
+ ]
1493
+ });
1494
+ if (last.type === "text") {
1495
+ last.content += chunk.content;
1496
+ } else {
1497
+ streamBlock.content.push(chunk);
1498
+ }
1499
+ }
1500
+ }
1501
+ break;
1502
+ }
1503
+ //
1504
+ // Text Fragment.
1505
+ //
1506
+ case "text": {
1507
+ if (chunk.type === "tag") {
1508
+ this._emitBlock(contentBlock, streamBlock);
1509
+ if (chunk.selfClosing) {
1510
+ this._emitBlock(contentBlock, chunk);
1511
+ streamBlock = void 0;
1512
+ } else {
1513
+ streamBlock = chunk;
1514
+ }
1515
+ } else {
1516
+ streamBlock.content += chunk.content;
1517
+ }
1518
+ break;
1519
+ }
1520
+ //
1521
+ // No current chunk.
1522
+ //
1523
+ default: {
1524
+ if (chunk.type === "tag" && chunk.selfClosing) {
1525
+ this._emitBlock(contentBlock, chunk);
1526
+ } else {
1527
+ streamBlock = chunk;
1528
+ }
1529
+ }
1530
+ }
1102
1531
  }
1103
- ]
1104
- };
1105
- params.logger?.({
1106
- type: "message",
1107
- message: resultMessage
1108
- });
1109
- history.push(resultMessage);
1110
- return true;
1532
+ break;
1533
+ }
1534
+ //
1535
+ // JSON
1536
+ //
1537
+ case "input_json_delta": {
1538
+ if (!contentBlock) {
1539
+ import_log5.log.warn("unexpected input_json_delta", {
1540
+ contentBlock
1541
+ }, {
1542
+ F: __dxlog_file5,
1543
+ L: 226,
1544
+ S: this,
1545
+ C: (f, a) => f(...a)
1546
+ });
1547
+ break;
1548
+ }
1549
+ if (streamBlock?.type === "json") {
1550
+ streamBlock.content += event.delta.partial_json;
1551
+ } else {
1552
+ streamBlock = {
1553
+ type: "json",
1554
+ content: event.delta.partial_json
1555
+ };
1556
+ }
1557
+ break;
1558
+ }
1559
+ }
1560
+ break;
1111
1561
  }
1112
- case "break": {
1113
- (0, import_log4.log)("tool break", {
1114
- result: toolResult.result
1115
- }, {
1116
- F: __dxlog_file4,
1117
- L: 131,
1118
- S: void 0,
1119
- C: (f, a) => f(...a)
1120
- });
1121
- conversationResult = toolResult.result;
1122
- return false;
1562
+ case "content_block_stop": {
1563
+ if (!contentBlock) {
1564
+ import_log5.log.warn("unexpected content_block_stop", void 0, {
1565
+ F: __dxlog_file5,
1566
+ L: 243,
1567
+ S: this,
1568
+ C: (f, a) => f(...a)
1569
+ });
1570
+ break;
1571
+ }
1572
+ this._emitBlock(contentBlock, streamBlock);
1573
+ contentBlock = void 0;
1574
+ streamBlock = void 0;
1575
+ break;
1123
1576
  }
1124
1577
  }
1578
+ if (contentBlock && streamBlock) {
1579
+ this._emitUpdate(contentBlock, streamBlock);
1580
+ }
1125
1581
  }
1126
- return false;
1127
- };
1128
- while (await generate()) {
1582
+ return messagesCollected;
1129
1583
  }
1130
- return {
1131
- result: conversationResult,
1132
- history
1133
- };
1134
- };
1135
- var isToolUse = (message) => {
1136
- const block = message.content.at(-1);
1137
- (0, import_invariant3.invariant)(block, void 0, {
1138
- F: __dxlog_file4,
1139
- L: 152,
1140
- S: void 0,
1141
- A: [
1142
- "block",
1143
- ""
1144
- ]
1145
- });
1146
- return block.type === "tool_use";
1147
1584
  };
1148
- var runTools = async ({ message, tools, extensions }) => {
1149
- const toolCalls = message.content.filter((block) => block.type === "tool_use");
1150
- (0, import_invariant3.invariant)(toolCalls.length === 1, void 0, {
1151
- F: __dxlog_file4,
1152
- L: 174,
1585
+ var mergeMessageBlock = (contentBlock, streamBlock) => {
1586
+ (0, import_log5.log)("mergeMessageBlock", {
1587
+ contentBlock,
1588
+ streamBlock
1589
+ }, {
1590
+ F: __dxlog_file5,
1591
+ L: 270,
1153
1592
  S: void 0,
1154
- A: [
1155
- "toolCalls.length === 1",
1156
- ""
1157
- ]
1593
+ C: (f, a) => f(...a)
1158
1594
  });
1159
- const toolCall = toolCalls[0];
1160
- const tool = tools.find((tool2) => tool2.name === toolCall.name);
1161
- if (!tool) {
1162
- throw new Error(`Tool not found: ${toolCall.name}`);
1163
- }
1164
- let toolResult;
1165
- try {
1166
- (0, import_invariant3.invariant)(tool.execute, void 0, {
1167
- F: __dxlog_file4,
1168
- L: 183,
1169
- S: void 0,
1170
- A: [
1171
- "tool.execute",
1172
- ""
1173
- ]
1174
- });
1175
- toolResult = await tool.execute(toolCall.input, {
1176
- extensions
1177
- });
1178
- } catch (error) {
1179
- (0, import_log4.log)("tool error", {
1180
- error
1181
- }, {
1182
- F: __dxlog_file4,
1183
- L: 186,
1184
- S: void 0,
1185
- C: (f, a) => f(...a)
1186
- });
1187
- toolResult = import_artifact4.ToolResult.Error(error.message);
1188
- }
1189
- switch (toolResult.kind) {
1190
- case "error": {
1191
- (0, import_log4.log)("tool error", {
1192
- message: toolResult.message
1193
- }, {
1194
- F: __dxlog_file4,
1195
- L: 192,
1196
- S: void 0,
1197
- C: (f, a) => f(...a)
1198
- });
1199
- const resultMessage = (0, import_echo_schema3.createStatic)(import_artifact4.Message, {
1200
- role: "user",
1201
- content: [
1202
- {
1203
- type: "tool_result",
1204
- toolUseId: toolCall.id,
1205
- content: toolResult.message,
1206
- isError: true
1207
- }
1208
- ]
1209
- });
1595
+ switch (streamBlock.type) {
1596
+ //
1597
+ // Text
1598
+ //
1599
+ case "text": {
1210
1600
  return {
1211
- type: "continue",
1212
- message: resultMessage
1601
+ ...contentBlock,
1602
+ type: "text",
1603
+ text: streamBlock.content
1213
1604
  };
1214
1605
  }
1215
- case "success": {
1216
- (0, import_log4.log)("tool success", {
1217
- result: toolResult.result
1218
- }, {
1219
- F: __dxlog_file4,
1220
- L: 213,
1221
- S: void 0,
1222
- C: (f, a) => f(...a)
1223
- });
1224
- const resultMessage = (0, import_echo_schema3.createStatic)(import_artifact4.Message, {
1225
- role: "user",
1226
- content: [
1227
- {
1228
- type: "tool_result",
1229
- toolUseId: toolCall.id,
1230
- content: typeof toolResult.result === "string" ? toolResult.result : JSON.stringify(toolResult.result) ?? ""
1606
+ //
1607
+ // XML
1608
+ //
1609
+ case "tag": {
1610
+ switch (streamBlock.tag) {
1611
+ case "cot": {
1612
+ const content = streamBlock.content.map((block) => {
1613
+ switch (block.type) {
1614
+ case "text":
1615
+ return block.content;
1616
+ default:
1617
+ return null;
1618
+ }
1619
+ }).filter(import_util.isNotFalsy).join("\n");
1620
+ return {
1621
+ ...contentBlock,
1622
+ type: "text",
1623
+ disposition: "cot",
1624
+ text: content
1625
+ };
1626
+ }
1627
+ case "artifact": {
1628
+ const { attributes } = streamBlock;
1629
+ return {
1630
+ type: "json",
1631
+ disposition: "artifact",
1632
+ json: JSON.stringify(attributes)
1633
+ };
1634
+ }
1635
+ case "suggest": {
1636
+ if (streamBlock.content.length === 1 && streamBlock.content[0].type === "text") {
1637
+ return {
1638
+ type: "json",
1639
+ disposition: "suggest",
1640
+ json: JSON.stringify({
1641
+ text: streamBlock.content[0].content
1642
+ })
1643
+ };
1231
1644
  }
1232
- ]
1233
- });
1234
- return {
1235
- type: "continue",
1236
- message: resultMessage
1237
- };
1645
+ break;
1646
+ }
1647
+ case "select": {
1648
+ return {
1649
+ type: "json",
1650
+ disposition: "select",
1651
+ json: JSON.stringify({
1652
+ options: streamBlock.content.flatMap((content) => content.type === "tag" && content.content.length === 1 && content.content[0].type === "text" ? [
1653
+ content.content[0].content
1654
+ ] : [])
1655
+ })
1656
+ };
1657
+ }
1658
+ case "tool-list": {
1659
+ return {
1660
+ type: "json",
1661
+ disposition: "tool_list",
1662
+ json: JSON.stringify({})
1663
+ };
1664
+ }
1665
+ }
1666
+ break;
1238
1667
  }
1239
- case "break": {
1240
- (0, import_log4.log)("tool break", {
1241
- result: toolResult.result
1242
- }, {
1243
- F: __dxlog_file4,
1244
- L: 233,
1245
- S: void 0,
1246
- C: (f, a) => f(...a)
1247
- });
1668
+ //
1669
+ // JSON
1670
+ //
1671
+ case "json": {
1672
+ switch (contentBlock.type) {
1673
+ case "tool_use": {
1674
+ return {
1675
+ ...contentBlock,
1676
+ input: (0, import_util.safeParseJson)(streamBlock.content) ?? {}
1677
+ };
1678
+ }
1679
+ }
1248
1680
  return {
1249
- type: "break",
1250
- result: toolResult.result
1681
+ ...contentBlock,
1682
+ type: "json",
1683
+ disposition: "artifact",
1684
+ json: streamBlock.content
1251
1685
  };
1252
1686
  }
1253
1687
  }
1254
1688
  };
1255
1689
  // Annotate the CommonJS export names for ESM import in node:
1256
1690
  0 && (module.exports = {
1257
- AIServiceClientImpl,
1691
+ AIServiceEdgeClient,
1258
1692
  DEFAULT_LLM_MODEL,
1259
1693
  DEFAULT_LLM_MODELS,
1260
1694
  EchoDataSource,
1261
1695
  GenerateRequest,
1262
- GenerationStream,
1696
+ GenerationStreamImpl,
1263
1697
  LLMModel,
1698
+ MessageCollector,
1264
1699
  MixedStreamParser,
1700
+ OllamaClient,
1265
1701
  StreamTransform,
1266
1702
  ToolTypes,
1267
1703
  createArtifactElement,
1268
1704
  createGenerationStream,
1705
+ emitMessageAsEvents,
1269
1706
  executeQuery,
1270
1707
  executeQueryPlan,
1271
1708
  formatInferredRelationshipLabel,