@agtlantis/core 0.4.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.
@@ -0,0 +1,2144 @@
1
+ 'use strict';
2
+
3
+ var test = require('ai/test');
4
+ var ai = require('ai');
5
+ var merge = require('lodash/merge');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var merge__default = /*#__PURE__*/_interopDefault(merge);
10
+
11
+ // src/session/usage-extractors.ts
12
+ function mergeUsages(usages) {
13
+ if (usages.length === 0) {
14
+ return createZeroUsage();
15
+ }
16
+ let inputTokens = 0;
17
+ let outputTokens = 0;
18
+ let totalTokens = 0;
19
+ let noCacheTokens = 0;
20
+ let cacheReadTokens = 0;
21
+ let cacheWriteTokens = 0;
22
+ let textTokens = 0;
23
+ let reasoningTokens = 0;
24
+ for (const usage of usages) {
25
+ inputTokens += usage.inputTokens ?? 0;
26
+ outputTokens += usage.outputTokens ?? 0;
27
+ totalTokens += usage.totalTokens ?? 0;
28
+ noCacheTokens += usage.inputTokenDetails?.noCacheTokens ?? 0;
29
+ cacheReadTokens += usage.inputTokenDetails?.cacheReadTokens ?? 0;
30
+ cacheWriteTokens += usage.inputTokenDetails?.cacheWriteTokens ?? 0;
31
+ textTokens += usage.outputTokenDetails?.textTokens ?? 0;
32
+ reasoningTokens += usage.outputTokenDetails?.reasoningTokens ?? 0;
33
+ }
34
+ return {
35
+ inputTokens,
36
+ outputTokens,
37
+ totalTokens,
38
+ inputTokenDetails: {
39
+ noCacheTokens,
40
+ cacheReadTokens,
41
+ cacheWriteTokens
42
+ },
43
+ outputTokenDetails: {
44
+ textTokens,
45
+ reasoningTokens
46
+ }
47
+ };
48
+ }
49
+ function createZeroUsage() {
50
+ return {
51
+ inputTokens: 0,
52
+ outputTokens: 0,
53
+ totalTokens: 0,
54
+ inputTokenDetails: {
55
+ noCacheTokens: 0,
56
+ cacheReadTokens: 0,
57
+ cacheWriteTokens: 0
58
+ },
59
+ outputTokenDetails: {
60
+ textTokens: 0,
61
+ reasoningTokens: 0
62
+ }
63
+ };
64
+ }
65
+
66
+ // src/session/types.ts
67
+ var SessionSummary = class _SessionSummary {
68
+ totalLLMUsage;
69
+ llmCallCount;
70
+ llmCalls;
71
+ toolCalls;
72
+ customRecords;
73
+ llmCost;
74
+ additionalCosts;
75
+ metadata;
76
+ /** Cost breakdown by model. Key format: `${provider}/${model}` */
77
+ costByModel;
78
+ startTime;
79
+ constructor(data, startTime) {
80
+ this.startTime = startTime;
81
+ this.totalLLMUsage = data.totalLLMUsage;
82
+ this.llmCallCount = data.llmCalls.length;
83
+ this.llmCalls = Object.freeze([...data.llmCalls]);
84
+ this.toolCalls = Object.freeze([...data.toolCalls]);
85
+ this.customRecords = Object.freeze([...data.customRecords]);
86
+ this.llmCost = data.llmCost;
87
+ this.additionalCosts = Object.freeze([...data.additionalCosts]);
88
+ this.metadata = Object.freeze({ ...data.metadata });
89
+ this.costByModel = Object.freeze({ ...data.costByModel });
90
+ }
91
+ /**
92
+ * Total duration from session start to now (computed dynamically).
93
+ */
94
+ get totalDuration() {
95
+ return Date.now() - this.startTime;
96
+ }
97
+ /**
98
+ * Creates an empty SessionSummary.
99
+ */
100
+ static empty(startTime) {
101
+ return new _SessionSummary(
102
+ {
103
+ totalLLMUsage: createZeroUsage(),
104
+ llmCalls: [],
105
+ toolCalls: [],
106
+ customRecords: [],
107
+ llmCost: 0,
108
+ additionalCosts: [],
109
+ metadata: {},
110
+ costByModel: {}
111
+ },
112
+ startTime
113
+ );
114
+ }
115
+ /**
116
+ * Creates a SessionSummary with custom data for testing purposes.
117
+ * @internal For testing only - do not use in production code.
118
+ */
119
+ static forTest(data) {
120
+ const startTime = data.startTime ?? Date.now() - 1e3;
121
+ return new _SessionSummary(
122
+ {
123
+ totalLLMUsage: data.totalLLMUsage ?? createZeroUsage(),
124
+ llmCalls: data.llmCalls ?? [],
125
+ toolCalls: data.toolCalls ?? [],
126
+ customRecords: data.customRecords ?? [],
127
+ llmCost: data.llmCost ?? 0,
128
+ additionalCosts: data.additionalCosts ?? [],
129
+ metadata: data.metadata ?? {},
130
+ costByModel: data.costByModel ?? {}
131
+ },
132
+ startTime
133
+ );
134
+ }
135
+ /**
136
+ * Total cost of all additional (non-LLM) operations.
137
+ */
138
+ get totalAdditionalCost() {
139
+ return this.additionalCosts.reduce((sum, c) => sum + c.cost, 0);
140
+ }
141
+ /**
142
+ * Total cost including LLM and additional costs.
143
+ */
144
+ get totalCost() {
145
+ return this.llmCost + this.totalAdditionalCost;
146
+ }
147
+ /**
148
+ * Returns a new SessionSummary with an LLM call added.
149
+ */
150
+ withLLMCall(call, newLlmCost, newCostByModel, newTotalUsage) {
151
+ return new _SessionSummary(
152
+ {
153
+ totalLLMUsage: newTotalUsage,
154
+ llmCalls: [...this.llmCalls, call],
155
+ toolCalls: [...this.toolCalls],
156
+ customRecords: [...this.customRecords],
157
+ llmCost: newLlmCost,
158
+ additionalCosts: [...this.additionalCosts],
159
+ metadata: { ...this.metadata },
160
+ costByModel: newCostByModel
161
+ },
162
+ this.startTime
163
+ );
164
+ }
165
+ /**
166
+ * Returns a new SessionSummary with an additional cost recorded.
167
+ */
168
+ withAdditionalCost(cost) {
169
+ return new _SessionSummary(
170
+ {
171
+ totalLLMUsage: this.totalLLMUsage,
172
+ llmCalls: [...this.llmCalls],
173
+ toolCalls: [...this.toolCalls],
174
+ customRecords: [...this.customRecords],
175
+ llmCost: this.llmCost,
176
+ additionalCosts: [...this.additionalCosts, cost],
177
+ metadata: { ...this.metadata },
178
+ costByModel: { ...this.costByModel }
179
+ },
180
+ this.startTime
181
+ );
182
+ }
183
+ /**
184
+ * Returns a new SessionSummary with metadata updated.
185
+ */
186
+ withMetadata(key, value) {
187
+ return new _SessionSummary(
188
+ {
189
+ totalLLMUsage: this.totalLLMUsage,
190
+ llmCalls: [...this.llmCalls],
191
+ toolCalls: [...this.toolCalls],
192
+ customRecords: [...this.customRecords],
193
+ llmCost: this.llmCost,
194
+ additionalCosts: [...this.additionalCosts],
195
+ metadata: { ...this.metadata, [key]: value },
196
+ costByModel: { ...this.costByModel }
197
+ },
198
+ this.startTime
199
+ );
200
+ }
201
+ /**
202
+ * Returns a new SessionSummary with a tool call added.
203
+ */
204
+ withToolCall(call) {
205
+ return new _SessionSummary(
206
+ {
207
+ totalLLMUsage: this.totalLLMUsage,
208
+ llmCalls: [...this.llmCalls],
209
+ toolCalls: [...this.toolCalls, call],
210
+ customRecords: [...this.customRecords],
211
+ llmCost: this.llmCost,
212
+ additionalCosts: [...this.additionalCosts],
213
+ metadata: { ...this.metadata },
214
+ costByModel: { ...this.costByModel }
215
+ },
216
+ this.startTime
217
+ );
218
+ }
219
+ /**
220
+ * Returns a new SessionSummary with a custom record added.
221
+ */
222
+ withCustomRecord(record) {
223
+ return new _SessionSummary(
224
+ {
225
+ totalLLMUsage: this.totalLLMUsage,
226
+ llmCalls: [...this.llmCalls],
227
+ toolCalls: [...this.toolCalls],
228
+ customRecords: [...this.customRecords, record],
229
+ llmCost: this.llmCost,
230
+ additionalCosts: [...this.additionalCosts],
231
+ metadata: { ...this.metadata },
232
+ costByModel: { ...this.costByModel }
233
+ },
234
+ this.startTime
235
+ );
236
+ }
237
+ /**
238
+ * Serializes to plain JSON object for database storage.
239
+ */
240
+ toJSON() {
241
+ return {
242
+ totalDuration: this.totalDuration,
243
+ totalLLMUsage: this.totalLLMUsage,
244
+ llmCallCount: this.llmCallCount,
245
+ llmCalls: [...this.llmCalls],
246
+ toolCalls: [...this.toolCalls],
247
+ customRecords: [...this.customRecords],
248
+ llmCost: this.llmCost,
249
+ additionalCosts: [...this.additionalCosts],
250
+ metadata: { ...this.metadata },
251
+ costByModel: { ...this.costByModel },
252
+ totalCost: this.totalCost,
253
+ totalAdditionalCost: this.totalAdditionalCost
254
+ };
255
+ }
256
+ };
257
+
258
+ // src/testing/fixtures.ts
259
+ var TEST_API_KEY = "test-api-key";
260
+ function createMockUsage(overrides) {
261
+ const inputTokens = overrides?.inputTokens ?? 10;
262
+ const outputTokens = overrides?.outputTokens ?? 5;
263
+ return {
264
+ inputTokens,
265
+ outputTokens,
266
+ totalTokens: overrides?.totalTokens ?? inputTokens + outputTokens,
267
+ inputTokenDetails: {
268
+ cacheReadTokens: void 0,
269
+ cacheWriteTokens: void 0,
270
+ noCacheTokens: void 0,
271
+ ...overrides?.inputTokenDetails
272
+ },
273
+ outputTokenDetails: {
274
+ textTokens: void 0,
275
+ reasoningTokens: void 0,
276
+ ...overrides?.outputTokenDetails
277
+ }
278
+ };
279
+ }
280
+ function createTestEvent(type, overrides) {
281
+ return {
282
+ type,
283
+ ...overrides
284
+ };
285
+ }
286
+ function createDummyLLMCall() {
287
+ return {
288
+ startTime: Date.now() - 100,
289
+ endTime: Date.now(),
290
+ duration: 100,
291
+ usage: createMockUsage(),
292
+ type: "generateText",
293
+ model: "test-model",
294
+ provider: "openai"
295
+ };
296
+ }
297
+ function createMockSessionSummary(overrides) {
298
+ let startTime = overrides?.startTime;
299
+ if (startTime === void 0 && overrides?.totalDuration !== void 0) {
300
+ startTime = Date.now() - overrides.totalDuration;
301
+ }
302
+ const llmCost = overrides?.llmCost ?? overrides?.totalCost ?? 0;
303
+ let llmCalls = overrides?.llmCalls;
304
+ if (!llmCalls && overrides?.llmCallCount !== void 0) {
305
+ llmCalls = Array.from({ length: overrides.llmCallCount }, () => createDummyLLMCall());
306
+ }
307
+ return SessionSummary.forTest({
308
+ startTime,
309
+ totalLLMUsage: overrides?.totalLLMUsage ?? createMockUsage(),
310
+ llmCalls: llmCalls ?? [],
311
+ toolCalls: overrides?.toolCalls ?? [],
312
+ customRecords: overrides?.customRecords ?? [],
313
+ llmCost,
314
+ additionalCosts: overrides?.additionalCosts ?? [],
315
+ metadata: overrides?.metadata ?? {},
316
+ costByModel: overrides?.costByModel ?? {}
317
+ });
318
+ }
319
+
320
+ // src/testing/helpers.ts
321
+ async function collectEvents(execution) {
322
+ const events = [];
323
+ const iterable = "stream" in execution && typeof execution.stream === "function" ? execution.stream() : execution;
324
+ for await (const event of iterable) {
325
+ events.push(event);
326
+ }
327
+ return events;
328
+ }
329
+ async function consumeExecution(execution) {
330
+ const iterable = "stream" in execution && typeof execution.stream === "function" ? execution.stream() : execution;
331
+ for await (const _event of iterable) {
332
+ }
333
+ }
334
+ function expectFileManagerInterface(obj) {
335
+ const fm = obj;
336
+ const requiredMethods = ["upload", "delete", "clear", "getUploadedFiles"];
337
+ for (const method of requiredMethods) {
338
+ if (typeof fm[method] !== "function") {
339
+ throw new Error(
340
+ `Expected FileManager.${method} to be a function, got ${typeof fm[method]}`
341
+ );
342
+ }
343
+ }
344
+ }
345
+
346
+ // src/observability/logger.ts
347
+ var noopLogger = {};
348
+
349
+ // src/execution/constants.ts
350
+ var ERRORS = {
351
+ NO_RESULT: "No result available"};
352
+
353
+ // src/execution/utils.ts
354
+ function combineSignals(...signals) {
355
+ const controller = new AbortController();
356
+ for (const signal of signals) {
357
+ if (signal.aborted) {
358
+ controller.abort(signal.reason);
359
+ return controller.signal;
360
+ }
361
+ signal.addEventListener("abort", () => controller.abort(signal.reason), {
362
+ once: true
363
+ });
364
+ }
365
+ return controller.signal;
366
+ }
367
+ var Deferred = class {
368
+ promise;
369
+ resolve;
370
+ reject;
371
+ constructor() {
372
+ let res;
373
+ let rej;
374
+ this.promise = new Promise((resolve, reject) => {
375
+ res = resolve;
376
+ rej = reject;
377
+ });
378
+ this.resolve = res;
379
+ this.reject = rej;
380
+ }
381
+ };
382
+
383
+ // src/execution/shared.ts
384
+ function isAbortError(error, signal) {
385
+ if (error instanceof Error && error.name === "AbortError") {
386
+ return true;
387
+ }
388
+ return signal.aborted;
389
+ }
390
+ function normalizeError(error) {
391
+ return error instanceof Error ? error : new Error(String(error));
392
+ }
393
+ function createHookRunner(runHooks) {
394
+ let ran = false;
395
+ return {
396
+ ensureRun: async () => {
397
+ if (!ran) {
398
+ ran = true;
399
+ await runHooks();
400
+ }
401
+ },
402
+ hasRun: () => ran
403
+ };
404
+ }
405
+
406
+ // src/execution/streaming-host.ts
407
+ var StreamingExecutionHost = class {
408
+ constructor(createSession, generator, userSignal) {
409
+ this.createSession = createSession;
410
+ this.generator = generator;
411
+ this.effectiveSignal = userSignal ? combineSignals(userSignal, this.abortController.signal) : this.abortController.signal;
412
+ this.consumerPromise = this.startConsuming();
413
+ }
414
+ abortController = new AbortController();
415
+ effectiveSignal;
416
+ consumerPromise;
417
+ eventBuffer = [];
418
+ subscribers = /* @__PURE__ */ new Set();
419
+ completed = false;
420
+ cleaned = false;
421
+ hookRunner = null;
422
+ cancelRequested = false;
423
+ extractedOutcome = null;
424
+ extractedSummary = null;
425
+ hasDataField(event) {
426
+ return "data" in event && event.data !== void 0;
427
+ }
428
+ hasSummaryField(event) {
429
+ return "summary" in event && event.summary !== void 0;
430
+ }
431
+ hasErrorField(event) {
432
+ return "error" in event && event.error instanceof Error;
433
+ }
434
+ extractResultAndMetadata(event) {
435
+ const isCompleteOrError = event.type === "complete" || event.type === "error";
436
+ if (!isCompleteOrError) {
437
+ return;
438
+ }
439
+ if (this.hasErrorField(event)) {
440
+ this.extractedOutcome = { type: "error", error: event.error };
441
+ } else if (this.hasDataField(event)) {
442
+ this.extractedOutcome = { type: "result", value: event.data };
443
+ }
444
+ if (this.hasSummaryField(event)) {
445
+ this.extractedSummary = event.summary;
446
+ }
447
+ }
448
+ notifySubscribers(event) {
449
+ this.subscribers.forEach((fn) => fn(event));
450
+ }
451
+ async startConsuming() {
452
+ const session = this.createSession(this.effectiveSignal);
453
+ this.hookRunner = createHookRunner(() => session.runOnDoneHooks());
454
+ const gen = this.generator(session);
455
+ try {
456
+ let next = await gen.next();
457
+ while (!next.done) {
458
+ this.eventBuffer.push(next.value);
459
+ this.notifySubscribers(next.value);
460
+ const isTerminal = next.value.type === "complete" || next.value.type === "error";
461
+ if (isTerminal) {
462
+ this.extractResultAndMetadata(next.value);
463
+ this.abortController.abort();
464
+ break;
465
+ }
466
+ if (this.abortController.signal.aborted) {
467
+ break;
468
+ }
469
+ next = await gen.next();
470
+ }
471
+ if (next.done && next.value !== void 0) {
472
+ const finalEvent = await Promise.resolve(next.value);
473
+ this.eventBuffer.push(finalEvent);
474
+ this.notifySubscribers(finalEvent);
475
+ this.extractResultAndMetadata(finalEvent);
476
+ const isTerminal = finalEvent.type === "complete" || finalEvent.type === "error";
477
+ if (isTerminal) {
478
+ this.abortController.abort();
479
+ }
480
+ }
481
+ return this.buildResult(session);
482
+ } catch (error) {
483
+ const errorObj = normalizeError(error);
484
+ if (isAbortError(error, this.abortController.signal)) {
485
+ return {
486
+ success: false,
487
+ aborted: true,
488
+ error: errorObj,
489
+ summary: await session.getSummary()
490
+ };
491
+ }
492
+ const errorEvent = await session.fail(errorObj);
493
+ this.eventBuffer.push(errorEvent);
494
+ this.notifySubscribers(errorEvent);
495
+ this.extractResultAndMetadata(errorEvent);
496
+ this.abortController.abort();
497
+ return this.buildResult(session);
498
+ } finally {
499
+ this.completed = true;
500
+ await this.hookRunner?.ensureRun();
501
+ await gen.return(void 0);
502
+ }
503
+ }
504
+ async buildResult(session) {
505
+ const summary = this.extractedSummary ?? await session.getSummary();
506
+ if (this.extractedOutcome?.type === "error") {
507
+ return {
508
+ success: false,
509
+ aborted: false,
510
+ error: this.extractedOutcome.error,
511
+ summary
512
+ };
513
+ }
514
+ if (this.extractedOutcome?.type === "result") {
515
+ return {
516
+ success: true,
517
+ result: this.extractedOutcome.value,
518
+ summary
519
+ };
520
+ }
521
+ return {
522
+ success: false,
523
+ aborted: true,
524
+ error: new Error(ERRORS.NO_RESULT),
525
+ summary
526
+ };
527
+ }
528
+ /**
529
+ * Get the event stream.
530
+ * Returns buffered events first, then real-time events.
531
+ * Can be called multiple times - replays buffer each time.
532
+ */
533
+ async *stream() {
534
+ let index = 0;
535
+ while (index < this.eventBuffer.length) {
536
+ yield this.eventBuffer[index++];
537
+ }
538
+ if (this.completed) {
539
+ return;
540
+ }
541
+ const queue = [];
542
+ let pending = new Deferred();
543
+ const subscriber = (event) => {
544
+ queue.push(event);
545
+ pending.resolve();
546
+ };
547
+ this.subscribers.add(subscriber);
548
+ try {
549
+ while (!this.completed || queue.length > 0) {
550
+ if (queue.length > 0) {
551
+ yield queue.shift();
552
+ } else if (!this.completed) {
553
+ await pending.promise;
554
+ pending = new Deferred();
555
+ }
556
+ }
557
+ } finally {
558
+ this.subscribers.delete(subscriber);
559
+ }
560
+ }
561
+ cancel() {
562
+ this.cancelRequested = true;
563
+ this.abortController.abort();
564
+ }
565
+ async cleanup() {
566
+ if (this.cleaned) {
567
+ return;
568
+ }
569
+ this.cleaned = true;
570
+ if (!this.completed) {
571
+ this.cancel();
572
+ await this.consumerPromise.catch(() => {
573
+ });
574
+ }
575
+ this.subscribers.clear();
576
+ await this.hookRunner?.ensureRun();
577
+ }
578
+ async [Symbol.asyncDispose]() {
579
+ await this.cleanup();
580
+ }
581
+ /**
582
+ * Get the execution result with status, summary, and all events.
583
+ * Never throws - returns a discriminated union with status.
584
+ */
585
+ async result() {
586
+ const internal = await this.consumerPromise;
587
+ const events = Object.freeze([...this.eventBuffer]);
588
+ if (internal.success) {
589
+ return {
590
+ status: "succeeded",
591
+ value: internal.result,
592
+ summary: internal.summary,
593
+ events
594
+ };
595
+ }
596
+ if (this.cancelRequested || internal.aborted) {
597
+ return {
598
+ status: "canceled",
599
+ summary: internal.summary,
600
+ events
601
+ };
602
+ }
603
+ return {
604
+ status: "failed",
605
+ error: internal.error,
606
+ summary: internal.summary,
607
+ events
608
+ };
609
+ }
610
+ };
611
+
612
+ // src/execution/simple-host.ts
613
+ var SimpleExecutionHost = class {
614
+ abortController = new AbortController();
615
+ effectiveSignal;
616
+ consumerPromise;
617
+ cachedSession;
618
+ startTime = Date.now();
619
+ cancelRequested = false;
620
+ constructor(createSession, fn, userSignal) {
621
+ this.effectiveSignal = userSignal ? combineSignals(userSignal, this.abortController.signal) : this.abortController.signal;
622
+ this.consumerPromise = this.execute(createSession, fn);
623
+ }
624
+ async execute(createSession, fn) {
625
+ const session = createSession(this.effectiveSignal);
626
+ this.cachedSession = session;
627
+ const hookRunner = createHookRunner(() => session.runOnDoneHooks());
628
+ session.notifyExecutionStart();
629
+ try {
630
+ const result = await fn(session);
631
+ await session.notifyExecutionDone(result, this.startTime);
632
+ return {
633
+ success: true,
634
+ result,
635
+ summary: await session.getSummary()
636
+ };
637
+ } catch (error) {
638
+ const errorObj = normalizeError(error);
639
+ const isCancellation = isAbortError(error, this.abortController.signal);
640
+ if (!isCancellation) {
641
+ await session.notifyExecutionError(errorObj, this.startTime);
642
+ }
643
+ return {
644
+ success: false,
645
+ error: errorObj,
646
+ aborted: isCancellation,
647
+ summary: await session.getSummary()
648
+ };
649
+ } finally {
650
+ await hookRunner.ensureRun();
651
+ }
652
+ }
653
+ /**
654
+ * Request cancellation of the execution.
655
+ * Aborts the current LLM call if in progress.
656
+ * No-op if execution already completed.
657
+ */
658
+ cancel() {
659
+ this.cancelRequested = true;
660
+ this.abortController.abort();
661
+ }
662
+ /**
663
+ * Get the execution result with status and summary.
664
+ * Never throws - returns a discriminated union with status.
665
+ */
666
+ async result() {
667
+ const internal = await this.consumerPromise;
668
+ if (internal.success) {
669
+ return {
670
+ status: "succeeded",
671
+ value: internal.result,
672
+ summary: internal.summary
673
+ };
674
+ }
675
+ if (this.cancelRequested || internal.aborted) {
676
+ return {
677
+ status: "canceled",
678
+ summary: internal.summary
679
+ };
680
+ }
681
+ return {
682
+ status: "failed",
683
+ error: internal.error,
684
+ summary: internal.summary
685
+ };
686
+ }
687
+ /**
688
+ * Cleanup resources.
689
+ * For SimpleExecution, hooks are already run during execution,
690
+ * so this is intentionally a no-op.
691
+ */
692
+ async cleanup() {
693
+ }
694
+ async [Symbol.asyncDispose]() {
695
+ await this.cleanup();
696
+ }
697
+ };
698
+
699
+ // src/provider/base-provider.ts
700
+ var BaseProvider = class {
701
+ streamingExecution(generator, options) {
702
+ return new StreamingExecutionHost(
703
+ (signal) => this.createStreamingSession(signal),
704
+ generator,
705
+ options?.signal
706
+ );
707
+ }
708
+ /**
709
+ * Execute a non-streaming function with cancellation support.
710
+ * Returns immediately - execution starts in the background.
711
+ */
712
+ simpleExecution(fn, options) {
713
+ return new SimpleExecutionHost(
714
+ (signal) => this.createSimpleSession(signal),
715
+ fn,
716
+ options?.signal
717
+ );
718
+ }
719
+ };
720
+
721
+ // src/pricing/defaults.ts
722
+ var OPENAI_PRICING = {
723
+ "gpt-4o": { inputPricePerMillion: 2.5, outputPricePerMillion: 10 },
724
+ "gpt-4o-mini": { inputPricePerMillion: 0.15, outputPricePerMillion: 0.6 },
725
+ "gpt-4-turbo": { inputPricePerMillion: 10, outputPricePerMillion: 30 },
726
+ "gpt-4-turbo-preview": {
727
+ inputPricePerMillion: 10,
728
+ outputPricePerMillion: 30
729
+ },
730
+ "gpt-4": { inputPricePerMillion: 30, outputPricePerMillion: 60 },
731
+ "gpt-4-32k": { inputPricePerMillion: 60, outputPricePerMillion: 120 },
732
+ "gpt-3.5-turbo": { inputPricePerMillion: 0.5, outputPricePerMillion: 1.5 },
733
+ "gpt-3.5-turbo-16k": {
734
+ inputPricePerMillion: 3,
735
+ outputPricePerMillion: 4
736
+ },
737
+ "o1": { inputPricePerMillion: 15, outputPricePerMillion: 60 },
738
+ "o1-mini": { inputPricePerMillion: 3, outputPricePerMillion: 12 },
739
+ "o1-preview": { inputPricePerMillion: 15, outputPricePerMillion: 60 },
740
+ "o3": { inputPricePerMillion: 20, outputPricePerMillion: 80 },
741
+ "o3-mini": { inputPricePerMillion: 4, outputPricePerMillion: 16 }
742
+ };
743
+ var GOOGLE_PRICING = {
744
+ "gemini-2.5-flash": {
745
+ inputPricePerMillion: 0.15,
746
+ outputPricePerMillion: 0.6,
747
+ cachedInputPricePerMillion: 0.0375
748
+ },
749
+ "gemini-2.5-flash-lite": {
750
+ inputPricePerMillion: 0.075,
751
+ outputPricePerMillion: 0.3,
752
+ cachedInputPricePerMillion: 0.01875
753
+ },
754
+ "gemini-2.5-pro": {
755
+ inputPricePerMillion: 1.25,
756
+ outputPricePerMillion: 10,
757
+ cachedInputPricePerMillion: 0.3125
758
+ },
759
+ "gemini-2.0-flash": {
760
+ inputPricePerMillion: 0.1,
761
+ outputPricePerMillion: 0.4,
762
+ cachedInputPricePerMillion: 0.025
763
+ },
764
+ "gemini-2.0-flash-lite": {
765
+ inputPricePerMillion: 0.075,
766
+ outputPricePerMillion: 0.3,
767
+ cachedInputPricePerMillion: 0.01875
768
+ },
769
+ "gemini-1.5-pro": {
770
+ inputPricePerMillion: 1.25,
771
+ outputPricePerMillion: 5,
772
+ cachedInputPricePerMillion: 0.3125
773
+ },
774
+ "gemini-1.5-flash": {
775
+ inputPricePerMillion: 0.075,
776
+ outputPricePerMillion: 0.3,
777
+ cachedInputPricePerMillion: 0.01875
778
+ },
779
+ "gemini-1.5-flash-8b": {
780
+ inputPricePerMillion: 0.0375,
781
+ outputPricePerMillion: 0.15,
782
+ cachedInputPricePerMillion: 0.01
783
+ },
784
+ "gemini-pro": { inputPricePerMillion: 0.5, outputPricePerMillion: 1.5 }
785
+ };
786
+ var ANTHROPIC_PRICING = {
787
+ "claude-opus-4-5-20250514": {
788
+ inputPricePerMillion: 15,
789
+ outputPricePerMillion: 75,
790
+ cachedInputPricePerMillion: 1.875
791
+ },
792
+ "claude-sonnet-4-20250514": {
793
+ inputPricePerMillion: 3,
794
+ outputPricePerMillion: 15,
795
+ cachedInputPricePerMillion: 0.375
796
+ },
797
+ "claude-3-5-sonnet-20241022": {
798
+ inputPricePerMillion: 3,
799
+ outputPricePerMillion: 15,
800
+ cachedInputPricePerMillion: 0.375
801
+ },
802
+ "claude-3-5-haiku-20241022": {
803
+ inputPricePerMillion: 0.8,
804
+ outputPricePerMillion: 4,
805
+ cachedInputPricePerMillion: 0.1
806
+ },
807
+ "claude-3-opus-20240229": {
808
+ inputPricePerMillion: 15,
809
+ outputPricePerMillion: 75,
810
+ cachedInputPricePerMillion: 1.875
811
+ },
812
+ "claude-3-sonnet-20240229": {
813
+ inputPricePerMillion: 3,
814
+ outputPricePerMillion: 15,
815
+ cachedInputPricePerMillion: 0.375
816
+ },
817
+ "claude-3-haiku-20240307": {
818
+ inputPricePerMillion: 0.25,
819
+ outputPricePerMillion: 1.25,
820
+ cachedInputPricePerMillion: 0.03
821
+ }
822
+ };
823
+ var DEFAULT_PRICING_CONFIG = {
824
+ providers: {
825
+ openai: OPENAI_PRICING,
826
+ google: GOOGLE_PRICING,
827
+ anthropic: ANTHROPIC_PRICING
828
+ },
829
+ fallback: {
830
+ inputPricePerMillion: 1,
831
+ outputPricePerMillion: 5
832
+ }
833
+ };
834
+ var DEFAULT_FALLBACK_PRICING = {
835
+ inputPricePerMillion: 1,
836
+ outputPricePerMillion: 5
837
+ };
838
+
839
+ // src/pricing/config.ts
840
+ var globalConfig;
841
+ function getPricingConfig() {
842
+ return globalConfig;
843
+ }
844
+
845
+ // src/pricing/calculator.ts
846
+ var TOKENS_PER_MILLION = 1e6;
847
+ function getModelPricing(model, provider, providerPricing) {
848
+ if (providerPricing?.[model]) {
849
+ return providerPricing[model];
850
+ }
851
+ const globalConfig2 = getPricingConfig();
852
+ const defaultProviderPricing = DEFAULT_PRICING_CONFIG.providers[provider];
853
+ if (defaultProviderPricing?.[model]) {
854
+ return defaultProviderPricing[model];
855
+ }
856
+ return globalConfig2?.fallback ?? DEFAULT_PRICING_CONFIG.fallback ?? DEFAULT_FALLBACK_PRICING;
857
+ }
858
+ function validateCostParams(params) {
859
+ const { inputTokens, outputTokens, cachedInputTokens = 0 } = params;
860
+ if (inputTokens < 0 || outputTokens < 0 || cachedInputTokens < 0) {
861
+ throw new Error("Token counts must be non-negative");
862
+ }
863
+ if (cachedInputTokens > inputTokens) {
864
+ throw new Error("cachedInputTokens cannot exceed inputTokens");
865
+ }
866
+ if (!Number.isFinite(inputTokens) || !Number.isFinite(outputTokens) || !Number.isFinite(cachedInputTokens)) {
867
+ throw new Error("Token counts must be finite numbers");
868
+ }
869
+ }
870
+ function calculateCost(params, providerPricing) {
871
+ validateCostParams(params);
872
+ const {
873
+ inputTokens,
874
+ outputTokens,
875
+ cachedInputTokens = 0,
876
+ model,
877
+ provider
878
+ } = params;
879
+ const pricing = getModelPricing(model, provider, providerPricing);
880
+ const nonCachedInputTokens = inputTokens - cachedInputTokens;
881
+ const inputCost = nonCachedInputTokens / TOKENS_PER_MILLION * pricing.inputPricePerMillion;
882
+ const outputCost = outputTokens / TOKENS_PER_MILLION * pricing.outputPricePerMillion;
883
+ const cachedInputPricePerMillion = pricing.cachedInputPricePerMillion ?? pricing.inputPricePerMillion;
884
+ const cachedInputCost = cachedInputTokens / TOKENS_PER_MILLION * cachedInputPricePerMillion;
885
+ return {
886
+ total: inputCost + outputCost + cachedInputCost,
887
+ inputCost,
888
+ outputCost,
889
+ cachedInputCost
890
+ };
891
+ }
892
+ function calculateCostFromUsage(usage, model, provider, providerPricing) {
893
+ return calculateCost(
894
+ {
895
+ inputTokens: usage.inputTokens ?? 0,
896
+ outputTokens: usage.outputTokens ?? 0,
897
+ cachedInputTokens: usage.inputTokenDetails?.cacheReadTokens ?? 0,
898
+ model,
899
+ provider
900
+ },
901
+ providerPricing
902
+ );
903
+ }
904
+ function calculateTotalCost(calls, providerPricing) {
905
+ const costByModel = {};
906
+ let totalCost = 0;
907
+ for (const call of calls) {
908
+ const cost = calculateCostFromUsage(
909
+ call.usage,
910
+ call.model,
911
+ call.provider,
912
+ providerPricing
913
+ );
914
+ totalCost += cost.total;
915
+ const key = `${call.provider}/${call.model}`;
916
+ costByModel[key] = (costByModel[key] ?? 0) + cost.total;
917
+ }
918
+ return { totalCost, costByModel };
919
+ }
920
+
921
+ // src/session/simple-session.ts
922
+ var SimpleSession = class {
923
+ defaultLanguageModel;
924
+ modelFactory;
925
+ providerType;
926
+ providerPricing;
927
+ defaultProviderOptions;
928
+ defaultTools;
929
+ _fileManager;
930
+ logger;
931
+ sessionStartTime;
932
+ signal;
933
+ summary;
934
+ pendingUsagePromises = [];
935
+ onDoneFns = [];
936
+ constructor(options) {
937
+ this.defaultLanguageModel = options.defaultLanguageModel ?? null;
938
+ this.modelFactory = options.modelFactory ?? null;
939
+ this.providerType = options.providerType;
940
+ this.providerPricing = options.providerPricing;
941
+ this.defaultProviderOptions = options.defaultProviderOptions;
942
+ this.defaultTools = options.defaultTools;
943
+ this._fileManager = options.fileManager;
944
+ this.logger = options.logger ?? noopLogger;
945
+ this.sessionStartTime = options.startTime ?? Date.now();
946
+ this.signal = options.signal;
947
+ this.summary = SessionSummary.empty(this.sessionStartTime);
948
+ }
949
+ getModel(requestedModelId) {
950
+ if (requestedModelId) {
951
+ if (!this.modelFactory) {
952
+ throw new Error(
953
+ `Model '${requestedModelId}' requested but no modelFactory provided. Either use the default model or configure the provider with modelFactory.`
954
+ );
955
+ }
956
+ return this.modelFactory(requestedModelId);
957
+ }
958
+ if (!this.defaultLanguageModel) {
959
+ throw new Error(
960
+ "No model specified and no default model set. Either specify a model in the call or configure the provider with withDefaultModel()."
961
+ );
962
+ }
963
+ return this.defaultLanguageModel;
964
+ }
965
+ extractModelId(model) {
966
+ const modelWithId = model;
967
+ if (!modelWithId.modelId) {
968
+ console.warn(
969
+ '[SimpleSession] Model does not have modelId property, using "unknown". This may affect cost tracking accuracy.'
970
+ );
971
+ }
972
+ return modelWithId.modelId ?? "unknown";
973
+ }
974
+ async generateText(params) {
975
+ const callStartTime = Date.now();
976
+ const { model: requestedModel, providerOptions, tools, ...restParams } = params;
977
+ const languageModel = this.getModel(requestedModel);
978
+ const modelId = this.extractModelId(languageModel);
979
+ const mergedProviderOptions = this.defaultProviderOptions || providerOptions ? merge__default.default({}, this.defaultProviderOptions ?? {}, providerOptions ?? {}) : void 0;
980
+ const mergedTools = this.defaultTools || tools ? { ...this.defaultTools, ...tools } : void 0;
981
+ this.logger.onLLMCallStart?.({
982
+ type: "llm_call_start",
983
+ callType: "generateText",
984
+ modelId,
985
+ timestamp: callStartTime,
986
+ request: { params: restParams }
987
+ });
988
+ try {
989
+ const result = await ai.generateText({
990
+ ...restParams,
991
+ tools: mergedTools,
992
+ providerOptions: mergedProviderOptions,
993
+ model: languageModel,
994
+ abortSignal: this.signal
995
+ });
996
+ const callEndTime = Date.now();
997
+ const call = {
998
+ startTime: callStartTime,
999
+ endTime: callEndTime,
1000
+ duration: callEndTime - callStartTime,
1001
+ usage: result.usage ?? createZeroUsage(),
1002
+ type: "generateText",
1003
+ model: modelId,
1004
+ provider: this.providerType
1005
+ };
1006
+ this.updateSummaryWithLLMCall(call);
1007
+ this.logger.onLLMCallEnd?.({
1008
+ type: "llm_call_end",
1009
+ callType: "generateText",
1010
+ modelId,
1011
+ timestamp: callEndTime,
1012
+ response: {
1013
+ duration: callEndTime - callStartTime,
1014
+ usage: result.usage,
1015
+ raw: result
1016
+ }
1017
+ });
1018
+ return result;
1019
+ } catch (error) {
1020
+ const callEndTime = Date.now();
1021
+ this.logger.onLLMCallEnd?.({
1022
+ type: "llm_call_end",
1023
+ callType: "generateText",
1024
+ modelId,
1025
+ timestamp: callEndTime,
1026
+ response: {
1027
+ duration: callEndTime - callStartTime,
1028
+ raw: null,
1029
+ error: error instanceof Error ? error : new Error(String(error))
1030
+ }
1031
+ });
1032
+ throw error;
1033
+ }
1034
+ }
1035
+ streamText(params) {
1036
+ const callStartTime = Date.now();
1037
+ const { model: requestedModel, providerOptions, tools, ...restParams } = params;
1038
+ const languageModel = this.getModel(requestedModel);
1039
+ const modelId = this.extractModelId(languageModel);
1040
+ const mergedProviderOptions = this.defaultProviderOptions || providerOptions ? merge__default.default({}, this.defaultProviderOptions ?? {}, providerOptions ?? {}) : void 0;
1041
+ const mergedTools = this.defaultTools || tools ? { ...this.defaultTools, ...tools } : void 0;
1042
+ this.logger.onLLMCallStart?.({
1043
+ type: "llm_call_start",
1044
+ callType: "streamText",
1045
+ modelId,
1046
+ timestamp: callStartTime,
1047
+ request: { params: restParams }
1048
+ });
1049
+ const result = ai.streamText({
1050
+ ...restParams,
1051
+ tools: mergedTools,
1052
+ providerOptions: mergedProviderOptions,
1053
+ model: languageModel,
1054
+ abortSignal: this.signal
1055
+ });
1056
+ const usagePromise = Promise.resolve(result.usage).then((usage) => {
1057
+ const callEndTime = Date.now();
1058
+ const call = {
1059
+ startTime: callStartTime,
1060
+ endTime: callEndTime,
1061
+ duration: callEndTime - callStartTime,
1062
+ usage: usage ?? createZeroUsage(),
1063
+ type: "streamText",
1064
+ model: modelId,
1065
+ provider: this.providerType
1066
+ };
1067
+ this.updateSummaryWithLLMCall(call);
1068
+ this.logger.onLLMCallEnd?.({
1069
+ type: "llm_call_end",
1070
+ callType: "streamText",
1071
+ modelId,
1072
+ timestamp: callEndTime,
1073
+ response: {
1074
+ duration: callEndTime - callStartTime,
1075
+ usage,
1076
+ raw: result
1077
+ }
1078
+ });
1079
+ return usage;
1080
+ });
1081
+ this.pendingUsagePromises.push(usagePromise);
1082
+ return result;
1083
+ }
1084
+ get fileManager() {
1085
+ return this._fileManager;
1086
+ }
1087
+ record(data) {
1088
+ this.summary = this.summary.withCustomRecord(data);
1089
+ }
1090
+ recordToolCall(toolCallSummary) {
1091
+ this.summary = this.summary.withToolCall(toolCallSummary);
1092
+ }
1093
+ recordLLMCall(record) {
1094
+ const call = {
1095
+ ...record,
1096
+ type: record.type ?? "manual"
1097
+ };
1098
+ this.updateSummaryWithLLMCall(call);
1099
+ }
1100
+ recordAdditionalCost(cost) {
1101
+ this.summary = this.summary.withAdditionalCost({
1102
+ ...cost,
1103
+ timestamp: Date.now()
1104
+ });
1105
+ }
1106
+ setMetadata(keyOrData, value) {
1107
+ if (typeof keyOrData === "string") {
1108
+ this.summary = this.summary.withMetadata(keyOrData, value);
1109
+ } else {
1110
+ for (const [k, v] of Object.entries(keyOrData)) {
1111
+ this.summary = this.summary.withMetadata(k, v);
1112
+ }
1113
+ }
1114
+ }
1115
+ updateSummaryWithLLMCall(call) {
1116
+ const newCalls = [...this.summary.llmCalls, call];
1117
+ const { totalCost: llmCost, costByModel } = calculateTotalCost(
1118
+ newCalls.map((c) => ({ usage: c.usage, model: c.model, provider: c.provider })),
1119
+ this.providerPricing
1120
+ );
1121
+ const newTotalUsage = mergeUsages(newCalls.map((c) => c.usage));
1122
+ this.summary = this.summary.withLLMCall(call, llmCost, costByModel, newTotalUsage);
1123
+ }
1124
+ onDone(fn) {
1125
+ this.onDoneFns.push(fn);
1126
+ }
1127
+ async runOnDoneHooks() {
1128
+ const reversedHooks = [...this.onDoneFns].reverse();
1129
+ for (const fn of reversedHooks) {
1130
+ try {
1131
+ await fn();
1132
+ } catch (error) {
1133
+ console.error("[SimpleSession] onDone hook error:", error);
1134
+ }
1135
+ }
1136
+ }
1137
+ async getSummary() {
1138
+ await Promise.all(this.pendingUsagePromises);
1139
+ return this.summary;
1140
+ }
1141
+ /**
1142
+ * Notifies Logger of execution start.
1143
+ * @internal Called by SimpleExecutionHost - not intended for direct use.
1144
+ */
1145
+ notifyExecutionStart() {
1146
+ this._logger.onExecutionStart?.({
1147
+ type: "execution_start",
1148
+ timestamp: Date.now()
1149
+ });
1150
+ }
1151
+ /**
1152
+ * Notifies Logger of execution completion with result data and summary.
1153
+ * @param data - The execution result data
1154
+ * @param startTime - Execution start timestamp for duration calculation
1155
+ * @internal Called by SimpleExecutionHost - not intended for direct use.
1156
+ */
1157
+ async notifyExecutionDone(data, startTime) {
1158
+ const summary = await this.getSummary();
1159
+ this._logger.onExecutionDone?.({
1160
+ type: "execution_done",
1161
+ timestamp: Date.now(),
1162
+ duration: Date.now() - startTime,
1163
+ data,
1164
+ summary
1165
+ });
1166
+ }
1167
+ /**
1168
+ * Notifies Logger of execution error with error details and summary (if available).
1169
+ * Gracefully handles getSummary() failures - summary will be undefined if it fails.
1170
+ * @param error - The error that occurred
1171
+ * @param startTime - Execution start timestamp for duration calculation
1172
+ * @internal Called by SimpleExecutionHost - not intended for direct use.
1173
+ */
1174
+ async notifyExecutionError(error, startTime) {
1175
+ let summary;
1176
+ try {
1177
+ summary = await this.getSummary();
1178
+ } catch {
1179
+ }
1180
+ this._logger.onExecutionError?.({
1181
+ type: "execution_error",
1182
+ timestamp: Date.now(),
1183
+ duration: Date.now() - startTime,
1184
+ error,
1185
+ summary
1186
+ });
1187
+ }
1188
+ get _logger() {
1189
+ return this.logger;
1190
+ }
1191
+ get _startTime() {
1192
+ return this.sessionStartTime;
1193
+ }
1194
+ get _modelId() {
1195
+ if (!this.defaultLanguageModel) {
1196
+ return "unknown";
1197
+ }
1198
+ return this.extractModelId(this.defaultLanguageModel);
1199
+ }
1200
+ };
1201
+
1202
+ // src/session/streaming-session.ts
1203
+ var StreamingSession = class extends SimpleSession {
1204
+ lastEventTime;
1205
+ _terminated = false;
1206
+ constructor(options) {
1207
+ super({
1208
+ defaultLanguageModel: options.defaultLanguageModel,
1209
+ modelFactory: options.modelFactory,
1210
+ providerType: options.providerType,
1211
+ providerPricing: options.providerPricing,
1212
+ fileManager: options.fileManager,
1213
+ logger: options.logger,
1214
+ startTime: options.startTime,
1215
+ signal: options.signal,
1216
+ defaultProviderOptions: options.defaultProviderOptions,
1217
+ defaultTools: options.defaultTools
1218
+ });
1219
+ this.lastEventTime = this._startTime;
1220
+ this._logger.onExecutionStart?.({
1221
+ type: "execution_start",
1222
+ timestamp: Date.now()
1223
+ });
1224
+ }
1225
+ /**
1226
+ * Emits a streaming event with automatically attached metrics.
1227
+ *
1228
+ * Reserved types ('complete', 'error') throw at runtime - use session.done()
1229
+ * or session.fail() instead.
1230
+ *
1231
+ * @param event - The event to emit (metrics will be added automatically)
1232
+ * @returns The complete event with metrics attached
1233
+ * @throws Error when attempting to emit reserved types ('complete', 'error')
1234
+ */
1235
+ emit(event) {
1236
+ if (this._terminated) {
1237
+ throw new Error("Session already terminated. Cannot call emit() after a terminal operation.");
1238
+ }
1239
+ const eventType = event.type;
1240
+ if (eventType === "complete" || eventType === "error") {
1241
+ throw new Error(
1242
+ `Cannot emit reserved type "${eventType}". Use session.done() for completion or session.fail() for errors.`
1243
+ );
1244
+ }
1245
+ return this.emitInternal(event);
1246
+ }
1247
+ /**
1248
+ * Internal emit method - bypasses reserved type check.
1249
+ * Used by done() and fail() to emit terminal events.
1250
+ */
1251
+ emitInternal(event) {
1252
+ const metrics = this.createMetrics();
1253
+ const fullEvent = { ...event, metrics };
1254
+ this._logger.onExecutionEmit?.({
1255
+ type: "execution_emit",
1256
+ event: fullEvent
1257
+ });
1258
+ return fullEvent;
1259
+ }
1260
+ /**
1261
+ * Signals successful completion of the streaming execution.
1262
+ * Emits a 'complete' event with the result data and session summary.
1263
+ * Also triggers Logger.onExecutionDone for observability.
1264
+ * @param data - The final result data
1265
+ * @returns The complete event with data and summary
1266
+ */
1267
+ async done(data) {
1268
+ if (this._terminated) {
1269
+ throw new Error("Session already terminated. Cannot call done() after a terminal operation.");
1270
+ }
1271
+ this._terminated = true;
1272
+ const summary = await this.getSummary();
1273
+ this._logger.onExecutionDone?.({
1274
+ type: "execution_done",
1275
+ timestamp: Date.now(),
1276
+ duration: summary.totalDuration,
1277
+ data,
1278
+ summary
1279
+ });
1280
+ return this.emitInternal({
1281
+ type: "complete",
1282
+ data,
1283
+ summary
1284
+ });
1285
+ }
1286
+ /**
1287
+ * Signals that the streaming execution failed with an error.
1288
+ * Emits an 'error' event and triggers Logger.onExecutionError for observability.
1289
+ * Gracefully handles getSummary() failures - summary will be undefined if it fails.
1290
+ * @param error - The error that caused the failure
1291
+ * @param data - Optional partial result data (if any was produced before failure)
1292
+ * @returns The error event
1293
+ */
1294
+ async fail(error, data) {
1295
+ if (this._terminated) {
1296
+ throw new Error("Session already terminated. Cannot call fail() after a terminal operation.");
1297
+ }
1298
+ this._terminated = true;
1299
+ let summary;
1300
+ try {
1301
+ summary = await this.getSummary();
1302
+ } catch {
1303
+ }
1304
+ this._logger.onExecutionError?.({
1305
+ type: "execution_error",
1306
+ timestamp: Date.now(),
1307
+ duration: summary?.totalDuration ?? Date.now() - this._startTime,
1308
+ error,
1309
+ data,
1310
+ summary
1311
+ });
1312
+ const errorEvent = {
1313
+ type: "error",
1314
+ error
1315
+ };
1316
+ if (summary) {
1317
+ errorEvent.summary = summary;
1318
+ }
1319
+ if (data !== void 0) {
1320
+ errorEvent.data = data;
1321
+ }
1322
+ return this.emitInternal(errorEvent);
1323
+ }
1324
+ createMetrics() {
1325
+ const now = Date.now();
1326
+ const metrics = {
1327
+ timestamp: now,
1328
+ elapsedMs: now - this._startTime,
1329
+ deltaMs: now - this.lastEventTime
1330
+ };
1331
+ this.lastEventTime = now;
1332
+ return metrics;
1333
+ }
1334
+ };
1335
+
1336
+ // src/errors/utils.ts
1337
+ function wrapAsError(error, ErrorClass, options) {
1338
+ const cause = error instanceof Error ? error : new Error(String(error));
1339
+ return new ErrorClass(cause.message, { ...options, cause });
1340
+ }
1341
+
1342
+ // src/errors/types.ts
1343
+ var AgtlantisError = class extends Error {
1344
+ code;
1345
+ cause;
1346
+ context;
1347
+ constructor(message, options) {
1348
+ super(message);
1349
+ this.name = "AgtlantisError";
1350
+ this.code = options.code;
1351
+ this.cause = options.cause;
1352
+ this.context = options.context;
1353
+ const ErrorWithCapture = Error;
1354
+ ErrorWithCapture.captureStackTrace?.(this, this.constructor);
1355
+ }
1356
+ get isRetryable() {
1357
+ return false;
1358
+ }
1359
+ toJSON() {
1360
+ return {
1361
+ name: this.name,
1362
+ message: this.message,
1363
+ code: this.code,
1364
+ isRetryable: this.isRetryable,
1365
+ context: this.context,
1366
+ cause: this.cause?.message,
1367
+ stack: this.stack
1368
+ };
1369
+ }
1370
+ };
1371
+ var FileError = class _FileError extends AgtlantisError {
1372
+ constructor(message, options = {}) {
1373
+ super(message, {
1374
+ code: options.code ?? "FILE_ERROR" /* FILE_ERROR */,
1375
+ cause: options.cause,
1376
+ context: options.context
1377
+ });
1378
+ this.name = "FileError";
1379
+ }
1380
+ static from(error, code = "FILE_ERROR" /* FILE_ERROR */, context) {
1381
+ if (error instanceof _FileError) {
1382
+ return error;
1383
+ }
1384
+ return wrapAsError(error, _FileError, { code, context });
1385
+ }
1386
+ };
1387
+
1388
+ // src/provider/noop-file-manager.ts
1389
+ var NoOpFileManager = class {
1390
+ upload(_files) {
1391
+ throw new FileError("File upload not supported by this provider", {
1392
+ code: "UNSUPPORTED_TYPE" /* UNSUPPORTED_TYPE */,
1393
+ context: {
1394
+ provider: "noop",
1395
+ suggestion: "Use a provider with file support (e.g., Google) or pass files inline"
1396
+ }
1397
+ });
1398
+ }
1399
+ delete(_fileId) {
1400
+ throw new FileError("File delete not supported by this provider", {
1401
+ code: "UNSUPPORTED_TYPE" /* UNSUPPORTED_TYPE */,
1402
+ context: {
1403
+ provider: "noop"
1404
+ }
1405
+ });
1406
+ }
1407
+ clear() {
1408
+ return Promise.resolve();
1409
+ }
1410
+ getUploadedFiles() {
1411
+ return [];
1412
+ }
1413
+ };
1414
+
1415
+ // src/testing/mock-provider.ts
1416
+ var MockProvider = class _MockProvider extends BaseProvider {
1417
+ calls = [];
1418
+ modelSource;
1419
+ fileManagerInstance;
1420
+ loggerInstance;
1421
+ defaultModelId;
1422
+ pricingConfig;
1423
+ providerTypeId;
1424
+ constructor(config) {
1425
+ super();
1426
+ if (!config.model && !config.modelFactory) {
1427
+ throw new Error("MockProvider requires either model or modelFactory");
1428
+ }
1429
+ this.modelSource = config.modelFactory ?? config.model;
1430
+ this.fileManagerInstance = config.fileManager ?? new NoOpFileManager();
1431
+ this.loggerInstance = config.logger ?? noopLogger;
1432
+ this.defaultModelId = null;
1433
+ this.providerTypeId = config.providerType ?? "mock";
1434
+ }
1435
+ /**
1436
+ * Creates instance for fluent API without calling constructor.
1437
+ * Shares calls array between fluent instances for tracking.
1438
+ */
1439
+ static createWithConfig(modelSource, fileManager, logger, defaultModelId, pricingConfig, providerType, existingCalls) {
1440
+ const provider = Object.create(_MockProvider.prototype);
1441
+ Object.assign(provider, {
1442
+ modelSource,
1443
+ fileManagerInstance: fileManager,
1444
+ loggerInstance: logger,
1445
+ defaultModelId,
1446
+ pricingConfig,
1447
+ providerTypeId: providerType,
1448
+ calls: existingCalls
1449
+ });
1450
+ return provider;
1451
+ }
1452
+ getCalls() {
1453
+ return [...this.calls];
1454
+ }
1455
+ clearCalls() {
1456
+ this.calls.length = 0;
1457
+ }
1458
+ withDefaultModel(modelId) {
1459
+ return _MockProvider.createWithConfig(
1460
+ this.modelSource,
1461
+ this.fileManagerInstance,
1462
+ this.loggerInstance,
1463
+ modelId,
1464
+ this.pricingConfig,
1465
+ this.providerTypeId,
1466
+ this.calls
1467
+ );
1468
+ }
1469
+ withLogger(logger) {
1470
+ return _MockProvider.createWithConfig(
1471
+ this.modelSource,
1472
+ this.fileManagerInstance,
1473
+ logger,
1474
+ this.defaultModelId,
1475
+ this.pricingConfig,
1476
+ this.providerTypeId,
1477
+ this.calls
1478
+ );
1479
+ }
1480
+ withPricing(pricing) {
1481
+ return _MockProvider.createWithConfig(
1482
+ this.modelSource,
1483
+ this.fileManagerInstance,
1484
+ this.loggerInstance,
1485
+ this.defaultModelId,
1486
+ pricing,
1487
+ this.providerTypeId,
1488
+ this.calls
1489
+ );
1490
+ }
1491
+ /**
1492
+ * Mock implementation - returns same provider since mocks don't use provider options.
1493
+ */
1494
+ withDefaultOptions(_options) {
1495
+ return this;
1496
+ }
1497
+ createSimpleSession(signal) {
1498
+ return new SimpleSession({ ...this.buildSessionConfig(), signal });
1499
+ }
1500
+ createStreamingSession(signal) {
1501
+ return new StreamingSession({ ...this.buildSessionConfig(), signal });
1502
+ }
1503
+ buildSessionConfig() {
1504
+ const effectiveModelId = this.defaultModelId ?? "default";
1505
+ return {
1506
+ defaultLanguageModel: this.createTrackingModel(effectiveModelId),
1507
+ modelFactory: (modelId) => this.createTrackingModel(modelId),
1508
+ providerType: this.providerTypeId,
1509
+ providerPricing: this.pricingConfig,
1510
+ fileManager: this.fileManagerInstance,
1511
+ logger: this.loggerInstance
1512
+ };
1513
+ }
1514
+ getBaseModel(modelId) {
1515
+ if (typeof this.modelSource === "function") {
1516
+ return this.modelSource(modelId);
1517
+ }
1518
+ return this.modelSource;
1519
+ }
1520
+ createTrackingModel(modelId) {
1521
+ const baseModel = this.getBaseModel(modelId);
1522
+ const calls = this.calls;
1523
+ return {
1524
+ ...baseModel,
1525
+ specificationVersion: baseModel.specificationVersion,
1526
+ provider: baseModel.provider,
1527
+ modelId: baseModel.modelId,
1528
+ supportedUrls: baseModel.supportedUrls,
1529
+ doGenerate: async (params) => {
1530
+ calls.push({
1531
+ modelId,
1532
+ type: "generate",
1533
+ timestamp: Date.now(),
1534
+ params
1535
+ });
1536
+ return baseModel.doGenerate(params);
1537
+ },
1538
+ doStream: async (params) => {
1539
+ calls.push({
1540
+ modelId,
1541
+ type: "stream",
1542
+ timestamp: Date.now(),
1543
+ params
1544
+ });
1545
+ return baseModel.doStream(params);
1546
+ }
1547
+ };
1548
+ }
1549
+ };
1550
+ function createMockProvider(configOrModel) {
1551
+ if (typeof configOrModel === "function") {
1552
+ return new MockProvider({ modelFactory: configOrModel });
1553
+ }
1554
+ if (configOrModel instanceof test.MockLanguageModelV3) {
1555
+ return new MockProvider({ model: configOrModel });
1556
+ }
1557
+ return new MockProvider(configOrModel);
1558
+ }
1559
+
1560
+ // src/testing/mock.ts
1561
+ var DEFAULT_USAGE = {
1562
+ inputTokens: { total: 0, noCache: 0, cacheRead: void 0, cacheWrite: void 0 },
1563
+ outputTokens: { total: 0, text: 0, reasoning: void 0 }
1564
+ };
1565
+ var DEFAULT_FINISH = {
1566
+ unified: "stop",
1567
+ raw: void 0
1568
+ };
1569
+ var mock = {
1570
+ /**
1571
+ * Creates a MockLanguageModelV3 that returns text content.
1572
+ *
1573
+ * @param text - The text to return from generateText
1574
+ * @param options - Optional overrides for usage, finishReason, etc.
1575
+ *
1576
+ * @example
1577
+ * const model = mock.text('Hello, world!');
1578
+ *
1579
+ * @example
1580
+ * // With custom usage for cost calculation tests
1581
+ * const model = mock.text('Hello', {
1582
+ * usage: {
1583
+ * inputTokens: { total: 100 },
1584
+ * outputTokens: { total: 50 },
1585
+ * },
1586
+ * });
1587
+ */
1588
+ text(text, options) {
1589
+ return new test.MockLanguageModelV3({
1590
+ doGenerate: async () => ({
1591
+ content: [{ type: "text", text }],
1592
+ finishReason: options?.finishReason ?? DEFAULT_FINISH,
1593
+ usage: options?.usage ?? DEFAULT_USAGE,
1594
+ warnings: options?.warnings ?? [],
1595
+ providerMetadata: options?.providerMetadata
1596
+ })
1597
+ });
1598
+ },
1599
+ /**
1600
+ * Creates a MockLanguageModelV3 that returns JSON content.
1601
+ *
1602
+ * Automatically stringifies the data. Use with generateObject or
1603
+ * generateText + Output.object.
1604
+ *
1605
+ * @param data - The object to return as JSON
1606
+ * @param options - Optional overrides for usage, finishReason, etc.
1607
+ *
1608
+ * @example
1609
+ * const model = mock.json({ name: 'Alice', age: 30 });
1610
+ */
1611
+ json(data, options) {
1612
+ return mock.text(JSON.stringify(data), options);
1613
+ },
1614
+ /**
1615
+ * Creates a MockLanguageModelV3 that streams text chunks.
1616
+ *
1617
+ * @param chunks - Array of text strings to stream
1618
+ * @param options - Optional overrides for finishReason, usage, etc.
1619
+ *
1620
+ * @example
1621
+ * const model = mock.stream(['Hello', ', ', 'world!']);
1622
+ */
1623
+ stream(chunks, options) {
1624
+ return new test.MockLanguageModelV3({
1625
+ doStream: async () => ({
1626
+ stream: test.simulateReadableStream({
1627
+ chunks: [
1628
+ { type: "text-start", id: "text-1" },
1629
+ ...chunks.map((chunk) => ({
1630
+ type: "text-delta",
1631
+ id: "text-1",
1632
+ delta: chunk
1633
+ })),
1634
+ { type: "text-end", id: "text-1" },
1635
+ {
1636
+ type: "finish",
1637
+ finishReason: options?.finishReason ?? DEFAULT_FINISH,
1638
+ usage: options?.usage ?? DEFAULT_USAGE,
1639
+ logprobs: void 0
1640
+ }
1641
+ ]
1642
+ })
1643
+ })
1644
+ });
1645
+ },
1646
+ /**
1647
+ * Creates a MockLanguageModelV3 that throws an error.
1648
+ *
1649
+ * @param error - The error to throw
1650
+ *
1651
+ * @example
1652
+ * const model = mock.error(new Error('Rate limit exceeded'));
1653
+ *
1654
+ * await expect(generateText({ model, prompt: 'Hi' }))
1655
+ * .rejects.toThrow('Rate limit exceeded');
1656
+ */
1657
+ error(error) {
1658
+ return new test.MockLanguageModelV3({
1659
+ doGenerate: async () => {
1660
+ throw error;
1661
+ },
1662
+ doStream: async () => {
1663
+ throw error;
1664
+ }
1665
+ });
1666
+ },
1667
+ /**
1668
+ * Creates a MockProvider with call tracking.
1669
+ *
1670
+ * Supports three input styles:
1671
+ * - Single model: `mock.provider(mock.text('Hello'))`
1672
+ * - Model factory: `mock.provider((modelId) => mock.text(modelId))`
1673
+ * - Full config: `mock.provider({ model, fileManager, logger })`
1674
+ *
1675
+ * @example
1676
+ * ```typescript
1677
+ * // Basic usage
1678
+ * const provider = mock.provider(mock.text('Hello!'));
1679
+ * const execution = provider.simpleExecution(async (session) => {
1680
+ * const { text } = await session.generateText({ prompt: 'Say hi' });
1681
+ * return text;
1682
+ * });
1683
+ * expect(await execution.toResult()).toBe('Hello!');
1684
+ * expect(provider.getCalls()).toHaveLength(1);
1685
+ *
1686
+ * // With model factory for different responses per model
1687
+ * const provider = mock.provider((modelId) => {
1688
+ * if (modelId === 'gpt-4') return mock.text('GPT-4 response');
1689
+ * return mock.text('Default response');
1690
+ * });
1691
+ * ```
1692
+ */
1693
+ provider(configOrModel) {
1694
+ return createMockProvider(configOrModel);
1695
+ }
1696
+ };
1697
+
1698
+ // src/execution/testing/helpers.ts
1699
+ function createAbortScenario() {
1700
+ const controller = new AbortController();
1701
+ return {
1702
+ controller,
1703
+ signal: controller.signal,
1704
+ abort: (reason) => controller.abort(reason),
1705
+ isAborted: () => controller.signal.aborted
1706
+ };
1707
+ }
1708
+ function createAlreadyAbortedSignal(reason = "Already aborted") {
1709
+ const controller = new AbortController();
1710
+ controller.abort(reason);
1711
+ return controller.signal;
1712
+ }
1713
+ function createSimpleGenerator(result, events = []) {
1714
+ return async function* (session) {
1715
+ for (const event of events) {
1716
+ yield session.emit(event);
1717
+ }
1718
+ return session.done(result);
1719
+ };
1720
+ }
1721
+ function createErrorGenerator(error, eventsBeforeError = []) {
1722
+ return async function* (session) {
1723
+ for (const event of eventsBeforeError) {
1724
+ yield session.emit(event);
1725
+ }
1726
+ throw error;
1727
+ };
1728
+ }
1729
+ function createCancelableGenerator(abortScenario, onCancel, eventsBeforeWait = []) {
1730
+ return async function* (session) {
1731
+ for (const event of eventsBeforeWait) {
1732
+ yield session.emit(event);
1733
+ }
1734
+ await new Promise((_, reject) => {
1735
+ const signal = abortScenario.signal;
1736
+ if (signal.aborted) {
1737
+ onCancel?.();
1738
+ reject(new DOMException("Aborted", "AbortError"));
1739
+ return;
1740
+ }
1741
+ signal.addEventListener("abort", () => {
1742
+ onCancel?.();
1743
+ reject(new DOMException("Aborted", "AbortError"));
1744
+ });
1745
+ });
1746
+ };
1747
+ }
1748
+ function createCancelableFunction(abortScenario, onCancel) {
1749
+ return async () => {
1750
+ await new Promise((_, reject) => {
1751
+ const signal = abortScenario.signal;
1752
+ if (signal.aborted) {
1753
+ onCancel?.();
1754
+ reject(new DOMException("Aborted", "AbortError"));
1755
+ return;
1756
+ }
1757
+ signal.addEventListener("abort", () => {
1758
+ onCancel?.();
1759
+ reject(new DOMException("Aborted", "AbortError"));
1760
+ });
1761
+ });
1762
+ return "should-not-reach";
1763
+ };
1764
+ }
1765
+ function createDelayedGenerator(delayMs, result, abortScenario) {
1766
+ return async function* (session) {
1767
+ await new Promise((resolve, reject) => {
1768
+ const timeoutId = setTimeout(resolve, delayMs);
1769
+ if (abortScenario) {
1770
+ abortScenario.signal.addEventListener("abort", () => {
1771
+ clearTimeout(timeoutId);
1772
+ reject(new DOMException("Aborted", "AbortError"));
1773
+ });
1774
+ }
1775
+ });
1776
+ return session.done(result);
1777
+ };
1778
+ }
1779
+ function createSlowGenerator(events, delayBetweenEventsMs, abortScenario) {
1780
+ return async function* (session) {
1781
+ for (const event of events) {
1782
+ if (abortScenario?.isAborted()) {
1783
+ throw new DOMException("Aborted", "AbortError");
1784
+ }
1785
+ await new Promise((resolve, reject) => {
1786
+ const timeoutId = setTimeout(resolve, delayBetweenEventsMs);
1787
+ if (abortScenario) {
1788
+ if (abortScenario.signal.aborted) {
1789
+ clearTimeout(timeoutId);
1790
+ reject(new DOMException("Aborted", "AbortError"));
1791
+ return;
1792
+ }
1793
+ abortScenario.signal.addEventListener(
1794
+ "abort",
1795
+ () => {
1796
+ clearTimeout(timeoutId);
1797
+ reject(new DOMException("Aborted", "AbortError"));
1798
+ },
1799
+ { once: true }
1800
+ );
1801
+ }
1802
+ });
1803
+ yield session.emit(event);
1804
+ }
1805
+ return void 0;
1806
+ };
1807
+ }
1808
+ async function collectStreamAsync(stream) {
1809
+ const collected = [];
1810
+ for await (const event of stream) {
1811
+ collected.push(event);
1812
+ }
1813
+ return collected;
1814
+ }
1815
+ function createNeverEndingGenerator(eventsBeforeWait = [], abortScenario) {
1816
+ return async function* (session) {
1817
+ for (const event of eventsBeforeWait) {
1818
+ yield session.emit(event);
1819
+ }
1820
+ await new Promise((_, reject) => {
1821
+ if (abortScenario) {
1822
+ if (abortScenario.signal.aborted) {
1823
+ reject(new DOMException("Aborted", "AbortError"));
1824
+ return;
1825
+ }
1826
+ abortScenario.signal.addEventListener(
1827
+ "abort",
1828
+ () => reject(new DOMException("Aborted", "AbortError")),
1829
+ { once: true }
1830
+ );
1831
+ }
1832
+ });
1833
+ return void 0;
1834
+ };
1835
+ }
1836
+ function createOrderTrackingLogger() {
1837
+ const callOrder = [];
1838
+ const logger = {
1839
+ onLLMCallStart: () => {
1840
+ },
1841
+ onLLMCallEnd: () => {
1842
+ },
1843
+ onExecutionStart: () => {
1844
+ callOrder.push("start");
1845
+ },
1846
+ onExecutionEmit: () => {
1847
+ callOrder.push("emit");
1848
+ },
1849
+ onExecutionDone: () => {
1850
+ callOrder.push("done");
1851
+ },
1852
+ onExecutionError: () => {
1853
+ callOrder.push("error");
1854
+ }
1855
+ };
1856
+ return {
1857
+ logger,
1858
+ getCallOrder: () => [...callOrder]
1859
+ };
1860
+ }
1861
+
1862
+ // src/execution/testing/fixtures.ts
1863
+ var TEST_PROVIDER_TYPE = "google";
1864
+ var noop = () => {
1865
+ };
1866
+ var noopFactory = () => noop;
1867
+ function createNoopWithReturn(value) {
1868
+ return () => value;
1869
+ }
1870
+ function createNoopAsync(value) {
1871
+ return () => Promise.resolve(value);
1872
+ }
1873
+ function createMockModel(options = {}) {
1874
+ const { mockFn = noopFactory } = options;
1875
+ return {
1876
+ specificationVersion: "v1",
1877
+ provider: "test-provider",
1878
+ modelId: "test-model",
1879
+ defaultObjectGenerationMode: "json",
1880
+ doGenerate: mockFn(),
1881
+ doStream: mockFn()
1882
+ };
1883
+ }
1884
+ function createMockFileManager(options = {}) {
1885
+ const { mockFn } = options;
1886
+ if (mockFn) {
1887
+ return {
1888
+ upload: mockFn(),
1889
+ delete: mockFn(),
1890
+ clear: mockFn(),
1891
+ getUploadedFiles: mockFn()
1892
+ };
1893
+ }
1894
+ return {
1895
+ upload: createNoopAsync([]),
1896
+ delete: createNoopAsync(void 0),
1897
+ clear: createNoopAsync(void 0),
1898
+ getUploadedFiles: createNoopWithReturn([])
1899
+ };
1900
+ }
1901
+ function createMockLogger(options = {}) {
1902
+ const { mockFn = noopFactory } = options;
1903
+ return {
1904
+ onLLMCallStart: mockFn(),
1905
+ onLLMCallEnd: mockFn(),
1906
+ onExecutionStart: mockFn(),
1907
+ onExecutionEmit: mockFn(),
1908
+ onExecutionDone: mockFn(),
1909
+ onExecutionError: mockFn()
1910
+ };
1911
+ }
1912
+ function createMockUsage2(overrides = {}) {
1913
+ return {
1914
+ inputTokens: 100,
1915
+ outputTokens: 50,
1916
+ totalTokens: 150,
1917
+ inputTokenDetails: {
1918
+ noCacheTokens: 100,
1919
+ cacheReadTokens: 0,
1920
+ cacheWriteTokens: 0
1921
+ },
1922
+ outputTokenDetails: {
1923
+ textTokens: 50,
1924
+ reasoningTokens: 0
1925
+ },
1926
+ ...overrides
1927
+ };
1928
+ }
1929
+ function createSimpleSessionFactory(options = {}) {
1930
+ const { mockFn, logger } = options;
1931
+ return (signal) => new SimpleSession({
1932
+ defaultLanguageModel: createMockModel({ mockFn }),
1933
+ providerType: TEST_PROVIDER_TYPE,
1934
+ fileManager: createMockFileManager({ mockFn }),
1935
+ signal,
1936
+ logger
1937
+ });
1938
+ }
1939
+ function createStreamingSessionFactory(options = {}) {
1940
+ const { mockFn, logger } = options;
1941
+ return () => new StreamingSession({
1942
+ defaultLanguageModel: createMockModel({ mockFn }),
1943
+ providerType: TEST_PROVIDER_TYPE,
1944
+ fileManager: createMockFileManager({ mockFn }),
1945
+ logger
1946
+ });
1947
+ }
1948
+ function createStreamingSessionFactoryWithSignal(options = {}) {
1949
+ const { mockFn, logger, onSignalCapture } = options;
1950
+ return (signal) => {
1951
+ onSignalCapture?.(signal);
1952
+ return new StreamingSession({
1953
+ defaultLanguageModel: createMockModel({ mockFn }),
1954
+ providerType: TEST_PROVIDER_TYPE,
1955
+ fileManager: createMockFileManager({ mockFn }),
1956
+ signal,
1957
+ logger
1958
+ });
1959
+ };
1960
+ }
1961
+ async function collectEvents2(stream) {
1962
+ const events = [];
1963
+ for await (const event of stream) {
1964
+ events.push(event);
1965
+ }
1966
+ return events;
1967
+ }
1968
+ function createControllablePromise() {
1969
+ let resolve;
1970
+ let reject;
1971
+ const promise = new Promise((res, rej) => {
1972
+ resolve = res;
1973
+ reject = rej;
1974
+ });
1975
+ return { promise, resolve, reject };
1976
+ }
1977
+
1978
+ // src/testing/test-execution.ts
1979
+ function createTestMetrics() {
1980
+ return { timestamp: Date.now(), elapsedMs: 0, deltaMs: 0 };
1981
+ }
1982
+ function createTestExecution(result, events = []) {
1983
+ const summary = SessionSummary.forTest({});
1984
+ const completionEvent = {
1985
+ type: "complete",
1986
+ data: result,
1987
+ summary,
1988
+ metrics: createTestMetrics()
1989
+ };
1990
+ const allEvents = [
1991
+ ...events.map(
1992
+ (e) => ({ ...e, metrics: createTestMetrics() })
1993
+ ),
1994
+ completionEvent
1995
+ ];
1996
+ return {
1997
+ stream() {
1998
+ return {
1999
+ [Symbol.asyncIterator]() {
2000
+ let index = 0;
2001
+ return {
2002
+ async next() {
2003
+ if (index < allEvents.length) {
2004
+ return { value: allEvents[index++], done: false };
2005
+ }
2006
+ return { value: void 0, done: true };
2007
+ }
2008
+ };
2009
+ }
2010
+ };
2011
+ },
2012
+ async result() {
2013
+ return { status: "succeeded", value: result, events: allEvents, summary };
2014
+ },
2015
+ cancel() {
2016
+ },
2017
+ async cleanup() {
2018
+ },
2019
+ async [Symbol.asyncDispose]() {
2020
+ }
2021
+ };
2022
+ }
2023
+ function createTestErrorExecution(error, options = {}) {
2024
+ const summary = SessionSummary.forTest({});
2025
+ const errorEvent = {
2026
+ type: "error",
2027
+ error,
2028
+ summary,
2029
+ metrics: createTestMetrics()
2030
+ };
2031
+ if (options.data !== void 0) {
2032
+ errorEvent.data = options.data;
2033
+ }
2034
+ const typedErrorEvent = errorEvent;
2035
+ const allEvents = [
2036
+ ...(options.events ?? []).map(
2037
+ (e) => ({ ...e, metrics: createTestMetrics() })
2038
+ ),
2039
+ typedErrorEvent
2040
+ ];
2041
+ return {
2042
+ stream() {
2043
+ return {
2044
+ [Symbol.asyncIterator]() {
2045
+ let index = 0;
2046
+ return {
2047
+ async next() {
2048
+ if (index < allEvents.length) {
2049
+ return { value: allEvents[index++], done: false };
2050
+ }
2051
+ return { value: void 0, done: true };
2052
+ }
2053
+ };
2054
+ }
2055
+ };
2056
+ },
2057
+ async result() {
2058
+ return { status: "failed", error, events: allEvents, summary };
2059
+ },
2060
+ cancel() {
2061
+ },
2062
+ async cleanup() {
2063
+ },
2064
+ async [Symbol.asyncDispose]() {
2065
+ }
2066
+ };
2067
+ }
2068
+ function createTestCanceledExecution(events = []) {
2069
+ const summary = SessionSummary.forTest({});
2070
+ const allEvents = events.map(
2071
+ (e) => ({ ...e, metrics: createTestMetrics() })
2072
+ );
2073
+ return {
2074
+ stream() {
2075
+ return {
2076
+ [Symbol.asyncIterator]() {
2077
+ let index = 0;
2078
+ return {
2079
+ async next() {
2080
+ if (index < allEvents.length) {
2081
+ return { value: allEvents[index++], done: false };
2082
+ }
2083
+ return { value: void 0, done: true };
2084
+ }
2085
+ };
2086
+ }
2087
+ };
2088
+ },
2089
+ async result() {
2090
+ return { status: "canceled", events: allEvents, summary };
2091
+ },
2092
+ cancel() {
2093
+ },
2094
+ async cleanup() {
2095
+ },
2096
+ async [Symbol.asyncDispose]() {
2097
+ }
2098
+ };
2099
+ }
2100
+
2101
+ Object.defineProperty(exports, "MockLanguageModelV3", {
2102
+ enumerable: true,
2103
+ get: function () { return test.MockLanguageModelV3; }
2104
+ });
2105
+ Object.defineProperty(exports, "simulateReadableStream", {
2106
+ enumerable: true,
2107
+ get: function () { return test.simulateReadableStream; }
2108
+ });
2109
+ exports.MockProvider = MockProvider;
2110
+ exports.TEST_API_KEY = TEST_API_KEY;
2111
+ exports.TEST_PROVIDER_TYPE = TEST_PROVIDER_TYPE;
2112
+ exports.collectEvents = collectEvents;
2113
+ exports.collectExecutionEvents = collectEvents2;
2114
+ exports.collectStreamAsync = collectStreamAsync;
2115
+ exports.consumeExecution = consumeExecution;
2116
+ exports.createAbortScenario = createAbortScenario;
2117
+ exports.createAlreadyAbortedSignal = createAlreadyAbortedSignal;
2118
+ exports.createCancelableFunction = createCancelableFunction;
2119
+ exports.createCancelableGenerator = createCancelableGenerator;
2120
+ exports.createControllablePromise = createControllablePromise;
2121
+ exports.createDelayedGenerator = createDelayedGenerator;
2122
+ exports.createErrorGenerator = createErrorGenerator;
2123
+ exports.createMockFileManager = createMockFileManager;
2124
+ exports.createMockLanguageModelUsage = createMockUsage2;
2125
+ exports.createMockLogger = createMockLogger;
2126
+ exports.createMockModel = createMockModel;
2127
+ exports.createMockProvider = createMockProvider;
2128
+ exports.createMockSessionSummary = createMockSessionSummary;
2129
+ exports.createMockUsage = createMockUsage;
2130
+ exports.createNeverEndingGenerator = createNeverEndingGenerator;
2131
+ exports.createOrderTrackingLogger = createOrderTrackingLogger;
2132
+ exports.createSimpleGenerator = createSimpleGenerator;
2133
+ exports.createSimpleSessionFactory = createSimpleSessionFactory;
2134
+ exports.createSlowGenerator = createSlowGenerator;
2135
+ exports.createStreamingSessionFactory = createStreamingSessionFactory;
2136
+ exports.createStreamingSessionFactoryWithSignal = createStreamingSessionFactoryWithSignal;
2137
+ exports.createTestCanceledExecution = createTestCanceledExecution;
2138
+ exports.createTestErrorExecution = createTestErrorExecution;
2139
+ exports.createTestEvent = createTestEvent;
2140
+ exports.createTestExecution = createTestExecution;
2141
+ exports.expectFileManagerInterface = expectFileManagerInterface;
2142
+ exports.mock = mock;
2143
+ //# sourceMappingURL=index.cjs.map
2144
+ //# sourceMappingURL=index.cjs.map