@m4trix/core 0.14.0 → 0.15.1

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/dist/index.js CHANGED
@@ -21,715 +21,6 @@ var __privateSet = (obj, member, value, setter) => {
21
21
  return value;
22
22
  };
23
23
 
24
- // src/stream/Pump.ts
25
- var Pump = class _Pump {
26
- constructor(src) {
27
- this.src = src;
28
- }
29
- /**
30
- * Wrap an existing AsyncIterable or Readable stream into a Pump
31
- *
32
- * @template U The type of data in the source stream
33
- * @param source The source stream to convert to a Pump (AsyncIterable, ReadableStream, or NodeJS.ReadableStream)
34
- * @returns A new Pump instance that wraps the source
35
- */
36
- static from(source) {
37
- async function* gen() {
38
- let seq = 0;
39
- function isAsyncIterable(obj) {
40
- return Symbol.asyncIterator in obj;
41
- }
42
- function isWebReadableStream(obj) {
43
- return "getReader" in obj && typeof obj.getReader === "function";
44
- }
45
- function isNodeReadableStream(obj) {
46
- return "pipe" in obj && "on" in obj && typeof obj.pipe === "function" && typeof obj.on === "function";
47
- }
48
- if (isAsyncIterable(source)) {
49
- const iterator = source[Symbol.asyncIterator]();
50
- try {
51
- while (true) {
52
- const result = await iterator.next();
53
- if (result.done)
54
- break;
55
- yield {
56
- sequence: seq++,
57
- data: result.value,
58
- done: false
59
- };
60
- }
61
- } finally {
62
- }
63
- } else if (isWebReadableStream(source)) {
64
- const reader = source.getReader();
65
- try {
66
- while (true) {
67
- const result = await reader.read();
68
- if (result.done)
69
- break;
70
- yield {
71
- sequence: seq++,
72
- data: result.value,
73
- done: false
74
- };
75
- }
76
- } finally {
77
- reader.releaseLock();
78
- }
79
- } else if (isNodeReadableStream(source)) {
80
- try {
81
- for await (const chunk of source) {
82
- yield {
83
- sequence: seq++,
84
- data: chunk,
85
- done: false
86
- };
87
- }
88
- } catch (error) {
89
- console.error("Error reading from Node.js stream:", error);
90
- throw error;
91
- }
92
- }
93
- yield { sequence: seq, data: void 0, done: true };
94
- }
95
- return new _Pump(gen());
96
- }
97
- /**
98
- * Sync or async map over the data portion of each chunk
99
- *
100
- * @template U The output type after transformation
101
- * @param fn The mapping function that transforms each chunk
102
- * @returns A new Pump instance with the transformed data
103
- */
104
- map(fn) {
105
- async function* gen() {
106
- for await (const { sequence, data, done } of this.src) {
107
- if (done) {
108
- const out2 = data !== void 0 ? await fn(data) : void 0;
109
- yield { sequence, data: out2, done };
110
- break;
111
- }
112
- const out = await fn(data);
113
- yield { sequence, data: out, done };
114
- }
115
- }
116
- return new _Pump(gen.call(this));
117
- }
118
- /**
119
- * Stateful map allows processing stream chunks with a persistent context object.
120
- *
121
- * The context is initialized when the first chunk arrives and can be updated with each chunk.
122
- * This is useful for maintaining state across the stream processing.
123
- *
124
- * If you plan to use sockets you should rather opt for asyncStatefulMap.
125
- *
126
- * The pipe closes only after all processing is complete, including any final operations in onClose.
127
- *
128
- * TODO: Un-tested
129
- *
130
- * @param handlers Object containing callback functions for stream processing
131
- * @param handlers.onFirstChunk Function called when the first chunk arrives, initializes the context
132
- * @param handlers.onChunk Function called for each subsequent chunk, updates the context
133
- * @param handlers.onClose Optional function called when the stream closes, allows final processing
134
- * @returns A new Pump instance with transformed data
135
- */
136
- statefulMap(handlers) {
137
- const { src } = this;
138
- const gen = async function* () {
139
- let context;
140
- let initialized = false;
141
- let lastChunk;
142
- let seq = 0;
143
- const queue = [];
144
- const yieldData = (data) => {
145
- queue.push(data);
146
- };
147
- for await (const { data, done } of src) {
148
- if (done) {
149
- if (context && handlers.onClose) {
150
- await handlers.onClose(lastChunk, context, yieldData);
151
- }
152
- while (queue.length > 0) {
153
- yield { sequence: seq++, data: queue.shift(), done: false };
154
- }
155
- yield {
156
- sequence: seq++,
157
- data: void 0,
158
- done: true
159
- };
160
- break;
161
- }
162
- if (!initialized) {
163
- context = await handlers.onFirstChunk(data, yieldData);
164
- initialized = true;
165
- } else if (context) {
166
- context = await handlers.onChunk(data, context, yieldData);
167
- }
168
- lastChunk = data;
169
- while (queue.length > 0) {
170
- yield { sequence: seq++, data: queue.shift(), done: false };
171
- }
172
- }
173
- };
174
- return new _Pump(gen());
175
- }
176
- /**
177
- * Async map means that each incoming chunk is causing an async operation that when it completes
178
- * should yield a new chunk.
179
- * The pipe closes only after you unlock the pipe by using the unlockCloseEvent callback.
180
- *
181
- * Stateful refers to the fact that you can create your own small context object that is passed in the subsequent callbacks.
182
- * This allows you to keep track of things like a socket connection.
183
- *
184
- * Why is this nice? Well if you use things like a socket the pipe might have received the close event,
185
- * before you got any or all of your socket responses. Sockets don't fit into the standard promise pattern,
186
- * which makes it harder to wait for them.
187
- *
188
- * TODO: Un-tested
189
- *
190
- * @param handlers Object containing callback functions for stream processing
191
- * @param handlers.onFirstChunk Function called when the first chunk arrives, initializes the context
192
- * @param handlers.onChunk Function called for each subsequent chunk, updates the context
193
- * @param handlers.onClose Optional function called when the stream closes, allows final processing
194
- * @returns A new Pump instance with transformed data
195
- */
196
- asyncStatefulMap(handlers) {
197
- const { src } = this;
198
- const gen = async function* () {
199
- let context;
200
- let initialized = false;
201
- let lastChunk;
202
- let seq = 0;
203
- let lockedCloseEvent = true;
204
- const queue = [];
205
- const yieldData = (data) => {
206
- queue.push(data);
207
- };
208
- const unlockCloseEvent = () => {
209
- lockedCloseEvent = false;
210
- };
211
- for await (const { data, done } of src) {
212
- if (done) {
213
- if (context && handlers.onClose) {
214
- await handlers.onClose(
215
- lastChunk,
216
- context,
217
- yieldData,
218
- unlockCloseEvent
219
- );
220
- }
221
- const timestamp = Date.now();
222
- while (lockedCloseEvent && Date.now() - timestamp < 1e4) {
223
- while (queue.length > 0) {
224
- yield { sequence: seq++, data: queue.shift(), done: false };
225
- }
226
- await new Promise((resolve) => setTimeout(resolve, 5));
227
- }
228
- while (queue.length > 0) {
229
- yield { sequence: seq++, data: queue.shift(), done: false };
230
- }
231
- yield {
232
- sequence: seq++,
233
- data: void 0,
234
- done: true
235
- };
236
- break;
237
- }
238
- if (!initialized) {
239
- context = await handlers.onFirstChunk(
240
- data,
241
- yieldData,
242
- unlockCloseEvent
243
- );
244
- initialized = true;
245
- } else if (context) {
246
- context = await handlers.onChunk(
247
- data,
248
- context,
249
- yieldData,
250
- unlockCloseEvent
251
- );
252
- }
253
- lastChunk = data;
254
- while (queue.length > 0) {
255
- yield { sequence: seq++, data: queue.shift(), done: false };
256
- }
257
- }
258
- };
259
- return new _Pump(gen());
260
- }
261
- /**
262
- * Filter items based on a predicate
263
- *
264
- * @param predicate A function that determines whether to keep each chunk
265
- * @returns A new Pump instance containing only chunks that passed the predicate
266
- */
267
- filter(predicate) {
268
- async function* gen() {
269
- for await (const { sequence, data, done } of this.src) {
270
- if (done) {
271
- yield { sequence, data, done: true };
272
- break;
273
- }
274
- const keep = await predicate(data);
275
- if (keep) {
276
- yield { sequence, data, done: false };
277
- }
278
- }
279
- }
280
- return new _Pump(gen.call(this));
281
- }
282
- /**
283
- * Bundles (accumulates) chunks together based on a condition rather than a fixed size.
284
- *
285
- * This is useful when you need to group chunks dynamically based on their content or other criteria.
286
- *
287
- * Example: Bundling text chunks with a maximum character limit
288
- *
289
- * Input chunks: ["Hello", " this", " is", " a few", " chunks", " of text"]
290
- * With max size of 10 characters:
291
- * - First bundle: ["Hello", " this"] (10 chars)
292
- * - Second bundle: [" is", " a few"] (8 chars)
293
- * - Third bundle: [" chunks", " of text"] (13 chars)
294
- *
295
- * @param closeBundleCondition - Function that determines when to close the current bundle
296
- * Returns true when the current bundle should be emitted
297
- * Parameters:
298
- * - chunk: The current chunk being processed
299
- * - accumulatedChunks: Array of chunks in the current bundle
300
- *
301
- * @returns A pump that emits arrays of bundled items
302
- */
303
- bundle(closeBundleCondition) {
304
- async function* gen() {
305
- let buffer = [];
306
- let lastSequence = 0;
307
- for await (const { sequence, data, done } of this.src) {
308
- lastSequence = sequence;
309
- if (done) {
310
- if (buffer.length > 0) {
311
- yield { sequence, data: [...buffer], done: false };
312
- }
313
- yield {
314
- sequence: lastSequence,
315
- data: void 0,
316
- done: true
317
- };
318
- break;
319
- }
320
- const shouldClose = await closeBundleCondition(data, buffer);
321
- buffer.push(data);
322
- if (shouldClose) {
323
- yield {
324
- sequence: lastSequence,
325
- data: [...buffer],
326
- done: false
327
- };
328
- buffer = [];
329
- }
330
- }
331
- }
332
- return new _Pump(gen.call(this));
333
- }
334
- /**
335
- * Tap into each chunk without altering it
336
- *
337
- * @param fn A function that receives each chunk but doesn't affect the stream
338
- * @returns The same pump instance with unmodified data
339
- */
340
- onChunk(fn) {
341
- async function* gen() {
342
- for await (const chunk of this.src) {
343
- if (chunk.data === void 0 && chunk.done) {
344
- yield chunk;
345
- }
346
- await fn(chunk.data);
347
- yield chunk;
348
- }
349
- }
350
- return new _Pump(gen.call(this));
351
- }
352
- /**
353
- * Collect all chunks in the stream and run a callback when the stream is done.
354
- * The callback receives an array of all chunks that passed through.
355
- *
356
- * This is useful for analytics, logging, or processing the complete stream history
357
- * after all chunks have been received.
358
- *
359
- * @param fn - Callback function that receives the array of all chunks when the stream is complete
360
- * @returns The same pump, for chaining
361
- */
362
- onClose(fn) {
363
- async function* gen() {
364
- const history = [];
365
- for await (const chunk of this.src) {
366
- if (chunk.data !== void 0) {
367
- history.push(chunk.data);
368
- }
369
- if (chunk.done) {
370
- await fn(history);
371
- }
372
- yield chunk;
373
- }
374
- }
375
- return new _Pump(gen.call(this));
376
- }
377
- /**
378
- * Batch `n` chunks into arrays before emitting
379
- *
380
- * @param n The number of chunks to batch together
381
- * @returns A new Pump instance that emits arrays of batched chunks
382
- */
383
- batch(n) {
384
- async function* gen() {
385
- let buffer = [];
386
- for await (const chunk of this.src) {
387
- if (chunk.done) {
388
- if (chunk.data === void 0) {
389
- yield {
390
- sequence: buffer[0].sequence,
391
- data: buffer.map((c) => c.data),
392
- done: false
393
- };
394
- yield {
395
- sequence: chunk.sequence,
396
- data: void 0,
397
- done: true
398
- };
399
- buffer = [];
400
- } else {
401
- buffer.push(chunk);
402
- yield {
403
- sequence: buffer[0].sequence,
404
- data: buffer.map((c) => c.data),
405
- done: true
406
- };
407
- }
408
- break;
409
- }
410
- buffer.push(chunk);
411
- if (buffer.length === n) {
412
- yield {
413
- sequence: buffer[0].sequence,
414
- data: buffer.map((c) => c.data),
415
- done: chunk.done
416
- };
417
- buffer = [];
418
- }
419
- }
420
- }
421
- return new _Pump(gen.call(this));
422
- }
423
- /**
424
- * If you want to prevent chunk starvation, you can buffer the chunks.
425
- * Chunks will not be bundled into arrays or object but kept as is,
426
- * but the pipeline will not progress at that segment until the buffer is filled up.
427
- * Once a buffer is filled up it will drain and never buffer again.
428
- *
429
- * @param n The number of chunks to buffer before processing continues
430
- * @returns A new Pump instance with buffering behavior
431
- */
432
- buffer(n) {
433
- async function* gen() {
434
- let buffer = [];
435
- let bufferFilled = false;
436
- for await (const chunk of this.src) {
437
- if (!bufferFilled) {
438
- if (!chunk.done) {
439
- buffer.push(chunk);
440
- }
441
- if (buffer.length >= n || chunk.done) {
442
- bufferFilled = true;
443
- for (const bufferedChunk of buffer) {
444
- yield bufferedChunk;
445
- }
446
- if (chunk.done) {
447
- yield {
448
- sequence: chunk.sequence,
449
- data: void 0,
450
- done: true
451
- };
452
- break;
453
- }
454
- buffer = [];
455
- }
456
- } else {
457
- yield chunk;
458
- }
459
- }
460
- for (const bufferedChunk of buffer) {
461
- yield bufferedChunk;
462
- }
463
- }
464
- return new _Pump(gen.call(this));
465
- }
466
- /**
467
- * Rechunk the stream: transform one chunk into zero, one, or many output chunks.
468
- * The handler function receives the current buffer of chunks, a push function to emit new chunks,
469
- * and a flag indicating if this is the last chunk in the stream.
470
- *
471
- * @param handler Function that transforms chunks and pushes new ones
472
- * @returns A new Pump instance with rechunked data
473
- */
474
- rechunk(handler) {
475
- async function* gen() {
476
- let buffer = [];
477
- let seq = 0;
478
- const pending = [];
479
- const push = (chunk) => {
480
- pending.push(chunk);
481
- };
482
- for await (const { data, done } of this.src) {
483
- if (!done) {
484
- if (data !== void 0) {
485
- buffer.push(data);
486
- }
487
- await handler({
488
- buffer,
489
- push,
490
- lastChunk: false,
491
- setBuffer: (b) => {
492
- buffer = b;
493
- }
494
- });
495
- } else {
496
- await handler({
497
- buffer,
498
- push,
499
- lastChunk: true,
500
- setBuffer: (b) => {
501
- buffer = b;
502
- }
503
- });
504
- }
505
- while (pending.length > 0) {
506
- const out = pending.shift();
507
- yield { sequence: seq++, data: out, done: false };
508
- }
509
- if (done) {
510
- break;
511
- }
512
- }
513
- yield { sequence: seq, data: void 0, done: true };
514
- }
515
- return new _Pump(gen.call(this));
516
- }
517
- slidingWindow(size, step, fn) {
518
- async function* gen() {
519
- const history = [];
520
- let offset = 0;
521
- let lastSeq = 0;
522
- function buildWindow(_offset, _size, _history) {
523
- const window = Array(_size).fill(void 0);
524
- let windowIndex = 0;
525
- for (let i = _offset; i > _offset - _size; i -= step) {
526
- if (i >= history.length) {
527
- windowIndex++;
528
- continue;
529
- }
530
- if (i < 0) {
531
- break;
532
- }
533
- window[windowIndex] = _history[i];
534
- windowIndex++;
535
- }
536
- return window;
537
- }
538
- for await (const { sequence, data, done } of this.src) {
539
- if (done) {
540
- for (let i = 0; i < size - 1; i++) {
541
- const window2 = buildWindow(offset + i, size, history);
542
- yield { sequence: lastSeq, data: window2, done: false };
543
- }
544
- if (data === void 0) {
545
- yield {
546
- sequence: lastSeq,
547
- data: void 0,
548
- done: true
549
- };
550
- } else {
551
- yield {
552
- sequence: lastSeq,
553
- data: [
554
- history[history.length - 2] ?? void 0,
555
- history[history.length - 3] ?? void 0,
556
- history[history.length - 1]
557
- ],
558
- done: true
559
- };
560
- }
561
- break;
562
- }
563
- lastSeq = sequence;
564
- history.push(data);
565
- const window = buildWindow(offset, size, history);
566
- yield { sequence, data: window, done: false };
567
- offset++;
568
- }
569
- }
570
- const base = new _Pump(gen.call(this));
571
- return fn ? base.map(fn) : base;
572
- }
573
- /**
574
- * Sequentially flatten inner stream sources emitted by the pipeline.
575
- * Works with any Source type (AsyncIterable or ReadableStream).
576
- * This method is only available when the current Pump contains Source elements.
577
- *
578
- * @template U The type of data in the inner streams
579
- * @template F The type of inner stream source (extends Source<U>)
580
- * @returns A Pump instance with flattened stream data
581
- */
582
- sequenceStreams() {
583
- async function* gen() {
584
- let seq = 0;
585
- for await (const { data: innerSource, done: outerDone } of this.src) {
586
- if (outerDone)
587
- break;
588
- const innerPump = _Pump.from(innerSource);
589
- for await (const { data, done } of innerPump.src) {
590
- if (done)
591
- break;
592
- yield { sequence: seq++, data, done: false };
593
- }
594
- }
595
- yield { sequence: seq, data: void 0, done: true };
596
- }
597
- return new _Pump(gen.call(this));
598
- }
599
- /**
600
- * Fork the stream: two independent Pump<T> consumers
601
- * Both resulting Pumps will receive the same data, allowing for divergent processing paths.
602
- *
603
- * @returns An array containing two independent Pump instances with the same source data
604
- */
605
- fork() {
606
- const buffers = [[], []];
607
- let done = false;
608
- const srcIter = this.src[Symbol.asyncIterator]();
609
- async function fill() {
610
- const { value, done: streamDone } = await srcIter.next();
611
- if (streamDone) {
612
- done = true;
613
- return;
614
- }
615
- buffers.forEach((q) => q.push(value));
616
- if (value.done)
617
- done = true;
618
- }
619
- function makeStream(buf) {
620
- return {
621
- [Symbol.asyncIterator]() {
622
- return {
623
- async next() {
624
- while (buf.length === 0 && !done) {
625
- await fill();
626
- }
627
- if (buf.length === 0)
628
- return {
629
- done: true,
630
- value: void 0
631
- };
632
- return { done: false, value: buf.shift() };
633
- }
634
- };
635
- }
636
- };
637
- }
638
- return [new _Pump(makeStream(buffers[0])), new _Pump(makeStream(buffers[1]))];
639
- }
640
- /**
641
- * Drain the pipeline, consuming all chunks.
642
- * Returns a Promise that resolves when all chunks have been consumed.
643
- *
644
- * @returns A Promise that resolves when all chunks have been consumed
645
- */
646
- drain() {
647
- return (async () => {
648
- for await (const { done } of this.src) {
649
- if (done)
650
- break;
651
- }
652
- })();
653
- }
654
- /**
655
- * Drain the pipeline to a StreamTransformer.
656
- * Applies transform() to each data chunk, then closes the transformer,
657
- * and returns its response (which can be of any type defined by the transformer).
658
- *
659
- * Example with httpStreamResponse:
660
- * ```
661
- * const { transform, response, close } = httpStreamResponse(options);
662
- * return Pump.from(messageStream).drainTo({ transform, close, response });
663
- * ```
664
- *
665
- * @template U The type of data expected by the transformer (extends T)
666
- * @template R The response type produced by the transformer
667
- * @param transformer The StreamTransformer to drain to
668
- * @returns The response from the transformer
669
- */
670
- drainTo(transformer) {
671
- (async () => {
672
- for await (const { data, done } of this.src) {
673
- if (done)
674
- break;
675
- transformer.transform(data);
676
- }
677
- transformer.close();
678
- })();
679
- return transformer.response;
680
- }
681
- };
682
-
683
- // src/stream/utility/pipe-transformers/response.ts
684
- function httpStreamResponse(options = {}) {
685
- const { init, encoder } = options;
686
- const encodeFn = encoder ?? ((d) => {
687
- if (d instanceof Uint8Array)
688
- return d;
689
- if (typeof d === "string")
690
- return d;
691
- return JSON.stringify(d);
692
- });
693
- const { readable, writable } = new TransformStream();
694
- const writer = writable.getWriter();
695
- const response = new Response(readable, init);
696
- const transform = (chunk) => {
697
- const encoded = encodeFn(chunk);
698
- const bytes = typeof encoded === "string" ? new TextEncoder().encode(encoded) : encoded;
699
- writer.write(bytes);
700
- return chunk;
701
- };
702
- const close = () => {
703
- writer.close();
704
- };
705
- return { transform, response, close };
706
- }
707
-
708
- // src/stream/utility/rechunker/ensure-full-words.ts
709
- async function ensureFullWords({
710
- buffer,
711
- push,
712
- lastChunk
713
- }) {
714
- const combined = buffer.join("");
715
- const lastBoundary = Math.max(
716
- combined.lastIndexOf(" "),
717
- combined.lastIndexOf("\n"),
718
- combined.lastIndexOf(" ")
719
- );
720
- if (lastBoundary !== -1 || lastChunk) {
721
- const emitPart = lastBoundary !== -1 ? combined.slice(0, lastBoundary + 1) : combined;
722
- const leftoverPart = lastBoundary !== -1 ? combined.slice(lastBoundary + 1) : "";
723
- if (emitPart.trim().length > 0) {
724
- push(emitPart);
725
- }
726
- buffer.length = 0;
727
- if (leftoverPart.length > 0) {
728
- buffer.push(leftoverPart);
729
- }
730
- }
731
- }
732
-
733
24
  // src/api/socket-handler/SocketIoFactory.ts
734
25
  var SocketIoFactory = class _SocketIoFactory {
735
26
  constructor(socket, prefix, hooks) {
@@ -787,16 +78,10 @@ var SocketIoFactory = class _SocketIoFactory {
787
78
  this.socket.on(prefix("voice:output_file"), onVoiceOutputFile);
788
79
  }
789
80
  if (onVoiceOutputTranscriptDelta) {
790
- this.socket.on(
791
- prefix("voice:output_transcript_delta"),
792
- onVoiceOutputTranscriptDelta
793
- );
81
+ this.socket.on(prefix("voice:output_transcript_delta"), onVoiceOutputTranscriptDelta);
794
82
  }
795
83
  if (onVoiceOutputTranscriptFull) {
796
- this.socket.on(
797
- prefix("voice:output_transcript_full"),
798
- onVoiceOutputTranscriptFull
799
- );
84
+ this.socket.on(prefix("voice:output_transcript_full"), onVoiceOutputTranscriptFull);
800
85
  }
801
86
  }
802
87
  setupChatEvents(_socket) {
@@ -1012,10 +297,7 @@ var runSubscriber = (agent, publishesTo, dequeue, plane, emitQueue, channelName)
1012
297
  if (listensTo.length > 0 && !listensTo.includes(envelope.name)) {
1013
298
  return;
1014
299
  }
1015
- const runEvents = plane.getRunEvents(
1016
- envelope.meta.runId,
1017
- envelope.meta.contextId
1018
- );
300
+ const runEvents = plane.getRunEvents(envelope.meta.runId, envelope.meta.contextId);
1019
301
  const contextEvents = plane.getContextEvents(envelope.meta.contextId);
1020
302
  yield* Effect.withSpan("agent.listen", {
1021
303
  attributes: {
@@ -1050,9 +332,7 @@ var runSubscriber = (agent, publishesTo, dequeue, plane, emitQueue, channelName)
1050
332
  ).catch(() => {
1051
333
  });
1052
334
  } else {
1053
- Effect.runFork(
1054
- plane.publishToChannels(publishesTo, fullEnvelope)
1055
- );
335
+ Effect.runFork(plane.publishToChannels(publishesTo, fullEnvelope));
1056
336
  }
1057
337
  },
1058
338
  runEvents,
@@ -1078,14 +358,7 @@ var run = (network, plane, options) => Effect.gen(function* () {
1078
358
  for (const reg of registrations.values()) {
1079
359
  for (const channel of reg.subscribedTo) {
1080
360
  const dequeue = yield* plane.subscribe(channel.name);
1081
- yield* runSubscriber(
1082
- reg.agent,
1083
- reg.publishesTo,
1084
- dequeue,
1085
- plane,
1086
- emitQueue,
1087
- channel.name
1088
- );
361
+ yield* runSubscriber(reg.agent, reg.publishesTo, dequeue, plane, emitQueue, channel.name);
1089
362
  }
1090
363
  }
1091
364
  yield* Effect.never;
@@ -1153,14 +426,7 @@ function streamFromDequeue(take, signal, eventFilter) {
1153
426
  };
1154
427
  }
1155
428
  function expose(network, options) {
1156
- const {
1157
- auth,
1158
- select,
1159
- plane: providedPlane,
1160
- onRequest,
1161
- triggerEvents,
1162
- tracingLayer
1163
- } = options;
429
+ const { auth, select, plane: providedPlane, onRequest, triggerEvents, tracingLayer } = options;
1164
430
  const triggerEventDef = triggerEvents?.[0];
1165
431
  const triggerEventName = triggerEventDef?.name ?? "request";
1166
432
  const channels = resolveChannels(network, select);
@@ -1207,10 +473,8 @@ function expose(network, options) {
1207
473
  meta,
1208
474
  payload: opts.event.payload
1209
475
  };
1210
- Effect.runPromise(plane.publish(targetChannel, envelope)).catch(
1211
- () => {
1212
- }
1213
- );
476
+ Effect.runPromise(plane.publish(targetChannel, envelope)).catch(() => {
477
+ });
1214
478
  };
1215
479
  const dequeue = yield* plane.subscribe(channels[0]);
1216
480
  if (onRequest) {
@@ -1250,10 +514,7 @@ function expose(network, options) {
1250
514
  if (auth) {
1251
515
  const result = await auth(req);
1252
516
  if (!result.allowed) {
1253
- throw new ExposeAuthError(
1254
- result.message ?? "Unauthorized",
1255
- result.status ?? 401
1256
- );
517
+ throw new ExposeAuthError(result.message ?? "Unauthorized", result.status ?? 401);
1257
518
  }
1258
519
  }
1259
520
  return consumer ? createStream(req, consumer) : createStream(req);
@@ -1288,6 +549,7 @@ var AgentNetwork = class _AgentNetwork {
1288
549
  createChannel: (name) => network.addChannel(name),
1289
550
  sink: Sink,
1290
551
  registerAgent: (agent) => network.registerAgentInternal(agent),
552
+ registerAggregator: (aggregator) => network.registerAggregatorInternal(aggregator),
1291
553
  spawner: (factory) => network.createSpawnerInternal(factory)
1292
554
  };
1293
555
  callback(ctx);
@@ -1322,6 +584,9 @@ var AgentNetwork = class _AgentNetwork {
1322
584
  };
1323
585
  return binding;
1324
586
  }
587
+ registerAggregatorInternal(aggregator) {
588
+ return this.registerAgentInternal(aggregator);
589
+ }
1325
590
  createSpawnerInternal(factoryClass) {
1326
591
  const reg = {
1327
592
  factoryClass,
@@ -1426,7 +691,9 @@ var AgentNetworkEvent = {
1426
691
  const makeBound = (meta, payload2) => Effect.runSync(
1427
692
  decodeEnvelope({ name, meta, payload: payload2 })
1428
693
  );
1429
- const makeEffect = (payload2) => decodePayload(payload2).pipe(Effect.map((p) => ({ name, payload: p })));
694
+ const makeEffect = (payload2) => decodePayload(payload2).pipe(
695
+ Effect.map((p) => ({ name, payload: p }))
696
+ );
1430
697
  const makeBoundEffect = (meta, payload2) => decodeEnvelope({ name, meta, payload: payload2 });
1431
698
  const is = Schema.is(envelopeSchema);
1432
699
  return {
@@ -1443,20 +710,110 @@ var AgentNetworkEvent = {
1443
710
  };
1444
711
  }
1445
712
  };
1446
- var _params, _logic, _id, _listensTo;
713
+ var EventAggregator = class _EventAggregator {
714
+ constructor({
715
+ listensTo = [],
716
+ emits = [],
717
+ emitWhen
718
+ }) {
719
+ this._listensTo = listensTo;
720
+ this._emits = emits;
721
+ this._emitWhen = emitWhen;
722
+ }
723
+ static listensTo(events) {
724
+ return new _EventAggregator({ listensTo: [...events] });
725
+ }
726
+ emits(events) {
727
+ return new _EventAggregator({
728
+ listensTo: this._listensTo,
729
+ emits: [...this._emits, ...events],
730
+ emitWhen: this._emitWhen
731
+ });
732
+ }
733
+ emitWhen(fn) {
734
+ return new _EventAggregator({
735
+ listensTo: this._listensTo,
736
+ emits: this._emits,
737
+ emitWhen: fn
738
+ });
739
+ }
740
+ mapToEmit(fn) {
741
+ return new EventAggregatorInstance({
742
+ listensTo: this._listensTo.map((eventDef) => eventDef.name),
743
+ emitWhen: this._emitWhen ?? (() => true),
744
+ mapToEmit: fn
745
+ });
746
+ }
747
+ };
748
+ var _id, _listensTo, _emitWhen, _mapToEmit;
749
+ var EventAggregatorInstance = class {
750
+ constructor({
751
+ listensTo,
752
+ emitWhen,
753
+ mapToEmit
754
+ }) {
755
+ __privateAdd(this, _id, void 0);
756
+ __privateAdd(this, _listensTo, void 0);
757
+ __privateAdd(this, _emitWhen, void 0);
758
+ __privateAdd(this, _mapToEmit, void 0);
759
+ __privateSet(this, _id, `event-aggregator-${randomUUID()}`);
760
+ __privateSet(this, _listensTo, listensTo);
761
+ __privateSet(this, _emitWhen, emitWhen);
762
+ __privateSet(this, _mapToEmit, mapToEmit);
763
+ }
764
+ getId() {
765
+ return __privateGet(this, _id);
766
+ }
767
+ getListensTo() {
768
+ return __privateGet(this, _listensTo);
769
+ }
770
+ async invoke(options) {
771
+ const { triggerEvent, emit, runEvents, contextEvents } = options ?? {};
772
+ if (triggerEvent == null) {
773
+ return;
774
+ }
775
+ const emitFn = emit ?? ((_event) => {
776
+ });
777
+ const runEventsValue = runEvents ?? [];
778
+ const contextEventsValue = contextEvents ?? {
779
+ all: [],
780
+ byRun: () => [],
781
+ map: /* @__PURE__ */ new Map()
782
+ };
783
+ const shouldEmit = await __privateGet(this, _emitWhen).call(this, {
784
+ triggerEvent,
785
+ runEvents: runEventsValue,
786
+ contextEvents: contextEventsValue
787
+ });
788
+ if (!shouldEmit) {
789
+ return;
790
+ }
791
+ await __privateGet(this, _mapToEmit).call(this, {
792
+ triggerEvent,
793
+ emit: emitFn,
794
+ runEvents: runEventsValue,
795
+ contextEvents: contextEventsValue
796
+ });
797
+ }
798
+ };
799
+ _id = new WeakMap();
800
+ _listensTo = new WeakMap();
801
+ _emitWhen = new WeakMap();
802
+ _mapToEmit = new WeakMap();
803
+ var _params, _logic, _id2, _listensTo2;
1447
804
  var Agent = class {
1448
805
  constructor(logic, params, listensTo) {
1449
806
  __privateAdd(this, _params, void 0);
1450
807
  __privateAdd(this, _logic, void 0);
1451
- __privateAdd(this, _id, void 0);
1452
- __privateAdd(this, _listensTo, void 0);
808
+ __privateAdd(this, _id2, void 0);
809
+ __privateAdd(this, _listensTo2, void 0);
1453
810
  __privateSet(this, _logic, logic);
1454
811
  __privateSet(this, _params, params);
1455
- __privateSet(this, _id, `agent-${randomUUID()}`);
1456
- __privateSet(this, _listensTo, listensTo ?? []);
812
+ __privateSet(this, _id2, `agent-${randomUUID()}`);
813
+ __privateSet(this, _listensTo2, listensTo ?? []);
1457
814
  }
1458
815
  getListensTo() {
1459
- return __privateGet(this, _listensTo);
816
+ return __privateGet(this, _listensTo2);
1460
817
  }
1461
818
  async invoke(options) {
1462
819
  const { triggerEvent, emit, runEvents, contextEvents } = options ?? {};
@@ -1475,13 +832,13 @@ var Agent = class {
1475
832
  });
1476
833
  }
1477
834
  getId() {
1478
- return __privateGet(this, _id);
835
+ return __privateGet(this, _id2);
1479
836
  }
1480
837
  };
1481
838
  _params = new WeakMap();
1482
839
  _logic = new WeakMap();
1483
- _id = new WeakMap();
1484
- _listensTo = new WeakMap();
840
+ _id2 = new WeakMap();
841
+ _listensTo2 = new WeakMap();
1485
842
 
1486
843
  // src/matrix/agent-factory.ts
1487
844
  var AgentFactory = class _AgentFactory {
@@ -1666,9 +1023,7 @@ var Skill = class _Skill {
1666
1023
  const layersObj = runtime?.layers ?? {};
1667
1024
  const chunks = [];
1668
1025
  const emit = (chunk) => {
1669
- const decoded = Effect.runSync(
1670
- decodeChunk(chunk)
1671
- );
1026
+ const decoded = Effect.runSync(decodeChunk(chunk));
1672
1027
  chunks.push(decoded);
1673
1028
  };
1674
1029
  const done = await defineFn({
@@ -1676,9 +1031,7 @@ var Skill = class _Skill {
1676
1031
  emit,
1677
1032
  layers: layersObj
1678
1033
  });
1679
- const decodedDone = Effect.runSync(
1680
- decodeDone(done)
1681
- );
1034
+ const decodedDone = Effect.runSync(decodeDone(done));
1682
1035
  return { chunks, done: decodedDone };
1683
1036
  };
1684
1037
  return {
@@ -1689,9 +1042,7 @@ var Skill = class _Skill {
1689
1042
  const layersObj = runtime?.layers ?? {};
1690
1043
  const chunks = [];
1691
1044
  const emit = (chunk) => {
1692
- const decoded = Effect.runSync(
1693
- decodeChunk(chunk)
1694
- );
1045
+ const decoded = Effect.runSync(decodeChunk(chunk));
1695
1046
  chunks.push(decoded);
1696
1047
  };
1697
1048
  const done = await defineFn({
@@ -1699,9 +1050,7 @@ var Skill = class _Skill {
1699
1050
  emit,
1700
1051
  layers: layersObj
1701
1052
  });
1702
- const decodedDone = Effect.runSync(
1703
- decodeDone(done)
1704
- );
1053
+ const decodedDone = Effect.runSync(decodeDone(done));
1705
1054
  for (const c of chunks) {
1706
1055
  yield c;
1707
1056
  }
@@ -1806,9 +1155,7 @@ var NextEndpoint = {
1806
1155
  var ExpressEndpoint = {
1807
1156
  from(api, options) {
1808
1157
  if (api.protocol !== "sse") {
1809
- throw new Error(
1810
- `ExpressEndpoint: unsupported protocol "${api.protocol}"`
1811
- );
1158
+ throw new Error(`ExpressEndpoint: unsupported protocol "${api.protocol}"`);
1812
1159
  }
1813
1160
  const { requestToContextId, requestToRunId } = options;
1814
1161
  return {
@@ -1911,21 +1258,11 @@ function getDepth(parent) {
1911
1258
  return 1 + getDepth(p.parent);
1912
1259
  }
1913
1260
  var consoleTracer = Tracer.make({
1914
- span: (name, parent, context, links, startTime, kind) => new ConsoleSpan(
1915
- name,
1916
- parent,
1917
- context,
1918
- links,
1919
- startTime,
1920
- kind,
1921
- getDepth(parent)
1922
- ),
1261
+ span: (name, parent, context, links, startTime, kind) => new ConsoleSpan(name, parent, context, links, startTime, kind, getDepth(parent)),
1923
1262
  context: (f) => f()
1924
1263
  });
1925
- var consoleTracerLayer = Layer.setTracer(
1926
- consoleTracer
1927
- );
1264
+ var consoleTracerLayer = Layer.setTracer(consoleTracer);
1928
1265
 
1929
- export { Agent, AgentFactory, AgentNetwork, AgentNetworkEvent, Channel, ChannelName, ConfiguredChannel, DepedencyLayer, Done, EventMetaSchema, ExposeAuthError, ExpressEndpoint, LayerName, NextEndpoint, Pump, Sink, Skill, SocketIoFactory, consoleTracer, consoleTracerLayer, ensureFullWords, formatSSE, httpStreamResponse, isHttpStreamSink, toSSEStream };
1266
+ export { Agent, AgentFactory, AgentNetwork, AgentNetworkEvent, Channel, ChannelName, ConfiguredChannel, DepedencyLayer, Done, EventAggregator, EventAggregatorInstance, EventMetaSchema, ExposeAuthError, ExpressEndpoint, LayerName, NextEndpoint, Sink, Skill, SocketIoFactory, consoleTracer, consoleTracerLayer, formatSSE, isHttpStreamSink, toSSEStream };
1930
1267
  //# sourceMappingURL=out.js.map
1931
1268
  //# sourceMappingURL=index.js.map