@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.
package/dist/index.cjs ADDED
@@ -0,0 +1,3188 @@
1
+ 'use strict';
2
+
3
+ var ai = require('ai');
4
+ var zod = require('zod');
5
+ var Handlebars = require('handlebars');
6
+ var fs = require('fs/promises');
7
+ var path3 = require('path');
8
+ var yaml = require('yaml');
9
+ var crypto = require('crypto');
10
+ var google = require('@ai-sdk/google');
11
+ var genai = require('@google/genai');
12
+ var merge = require('lodash/merge');
13
+ var openai = require('@ai-sdk/openai');
14
+
15
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
+
17
+ function _interopNamespace(e) {
18
+ if (e && e.__esModule) return e;
19
+ var n = Object.create(null);
20
+ if (e) {
21
+ Object.keys(e).forEach(function (k) {
22
+ if (k !== 'default') {
23
+ var d = Object.getOwnPropertyDescriptor(e, k);
24
+ Object.defineProperty(n, k, d.get ? d : {
25
+ enumerable: true,
26
+ get: function () { return e[k]; }
27
+ });
28
+ }
29
+ });
30
+ }
31
+ n.default = e;
32
+ return Object.freeze(n);
33
+ }
34
+
35
+ var Handlebars__default = /*#__PURE__*/_interopDefault(Handlebars);
36
+ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
37
+ var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
38
+ var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
39
+ var merge__default = /*#__PURE__*/_interopDefault(merge);
40
+
41
+ // src/errors/utils.ts
42
+ function wrapAsError(error, ErrorClass, options) {
43
+ const cause = error instanceof Error ? error : new Error(String(error));
44
+ return new ErrorClass(cause.message, { ...options, cause });
45
+ }
46
+
47
+ // src/errors/types.ts
48
+ var ExecutionErrorCode = /* @__PURE__ */ ((ExecutionErrorCode2) => {
49
+ ExecutionErrorCode2["EXECUTION_ERROR"] = "EXECUTION_ERROR";
50
+ ExecutionErrorCode2["STREAM_ERROR"] = "STREAM_ERROR";
51
+ ExecutionErrorCode2["RESULT_EXTRACTION_ERROR"] = "RESULT_EXTRACTION_ERROR";
52
+ ExecutionErrorCode2["CANCELLED"] = "CANCELLED";
53
+ ExecutionErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
54
+ return ExecutionErrorCode2;
55
+ })(ExecutionErrorCode || {});
56
+ var ConfigurationErrorCode = /* @__PURE__ */ ((ConfigurationErrorCode2) => {
57
+ ConfigurationErrorCode2["CONFIG_ERROR"] = "CONFIG_ERROR";
58
+ ConfigurationErrorCode2["MISSING_API_KEY"] = "MISSING_API_KEY";
59
+ ConfigurationErrorCode2["INVALID_CONFIG"] = "INVALID_CONFIG";
60
+ ConfigurationErrorCode2["MISSING_REQUIRED"] = "MISSING_REQUIRED";
61
+ return ConfigurationErrorCode2;
62
+ })(ConfigurationErrorCode || {});
63
+ var FileErrorCode = /* @__PURE__ */ ((FileErrorCode2) => {
64
+ FileErrorCode2["FILE_ERROR"] = "FILE_ERROR";
65
+ FileErrorCode2["UPLOAD_ERROR"] = "UPLOAD_ERROR";
66
+ FileErrorCode2["DELETE_ERROR"] = "DELETE_ERROR";
67
+ FileErrorCode2["NOT_FOUND"] = "NOT_FOUND";
68
+ FileErrorCode2["TOO_LARGE"] = "TOO_LARGE";
69
+ FileErrorCode2["UNSUPPORTED_TYPE"] = "UNSUPPORTED_TYPE";
70
+ return FileErrorCode2;
71
+ })(FileErrorCode || {});
72
+ var AgtlantisError = class extends Error {
73
+ code;
74
+ cause;
75
+ context;
76
+ constructor(message, options) {
77
+ super(message);
78
+ this.name = "AgtlantisError";
79
+ this.code = options.code;
80
+ this.cause = options.cause;
81
+ this.context = options.context;
82
+ const ErrorWithCapture = Error;
83
+ ErrorWithCapture.captureStackTrace?.(this, this.constructor);
84
+ }
85
+ get isRetryable() {
86
+ return false;
87
+ }
88
+ toJSON() {
89
+ return {
90
+ name: this.name,
91
+ message: this.message,
92
+ code: this.code,
93
+ isRetryable: this.isRetryable,
94
+ context: this.context,
95
+ cause: this.cause?.message,
96
+ stack: this.stack
97
+ };
98
+ }
99
+ };
100
+ var ExecutionError = class _ExecutionError extends AgtlantisError {
101
+ constructor(message, options = {}) {
102
+ super(message, {
103
+ code: options.code ?? "EXECUTION_ERROR" /* EXECUTION_ERROR */,
104
+ cause: options.cause,
105
+ context: options.context
106
+ });
107
+ this.name = "ExecutionError";
108
+ }
109
+ static from(error, code = "EXECUTION_ERROR" /* EXECUTION_ERROR */, context) {
110
+ if (error instanceof _ExecutionError) {
111
+ return error;
112
+ }
113
+ return wrapAsError(error, _ExecutionError, { code, context });
114
+ }
115
+ };
116
+ var ConfigurationError = class _ConfigurationError extends AgtlantisError {
117
+ constructor(message, options = {}) {
118
+ super(message, {
119
+ code: options.code ?? "CONFIG_ERROR" /* CONFIG_ERROR */,
120
+ cause: options.cause,
121
+ context: options.context
122
+ });
123
+ this.name = "ConfigurationError";
124
+ }
125
+ static from(error, code = "CONFIG_ERROR" /* CONFIG_ERROR */, context) {
126
+ if (error instanceof _ConfigurationError) {
127
+ return error;
128
+ }
129
+ return wrapAsError(error, _ConfigurationError, { code, context });
130
+ }
131
+ };
132
+ var FileError = class _FileError extends AgtlantisError {
133
+ constructor(message, options = {}) {
134
+ super(message, {
135
+ code: options.code ?? "FILE_ERROR" /* FILE_ERROR */,
136
+ cause: options.cause,
137
+ context: options.context
138
+ });
139
+ this.name = "FileError";
140
+ }
141
+ static from(error, code = "FILE_ERROR" /* FILE_ERROR */, context) {
142
+ if (error instanceof _FileError) {
143
+ return error;
144
+ }
145
+ return wrapAsError(error, _FileError, { code, context });
146
+ }
147
+ };
148
+
149
+ // src/execution/constants.ts
150
+ var ERRORS = {
151
+ ALREADY_CONSUMED: "Execution already consumed",
152
+ METADATA_NOT_AVAILABLE: "Metadata not available yet. Consume the execution first.",
153
+ NO_RESULT: "No result available",
154
+ UNKNOWN_ERROR: "Execution failed with unknown error"
155
+ };
156
+
157
+ // src/execution/utils.ts
158
+ function getDuration(startTime) {
159
+ return Date.now() - startTime;
160
+ }
161
+ function combineSignals(...signals) {
162
+ const controller = new AbortController();
163
+ for (const signal of signals) {
164
+ if (signal.aborted) {
165
+ controller.abort(signal.reason);
166
+ return controller.signal;
167
+ }
168
+ signal.addEventListener("abort", () => controller.abort(signal.reason), {
169
+ once: true
170
+ });
171
+ }
172
+ return controller.signal;
173
+ }
174
+ var Deferred = class {
175
+ promise;
176
+ resolve;
177
+ reject;
178
+ constructor() {
179
+ let res;
180
+ let rej;
181
+ this.promise = new Promise((resolve2, reject) => {
182
+ res = resolve2;
183
+ rej = reject;
184
+ });
185
+ this.resolve = res;
186
+ this.reject = rej;
187
+ }
188
+ };
189
+
190
+ // src/execution/shared.ts
191
+ function isAbortError(error, signal) {
192
+ if (error instanceof Error && error.name === "AbortError") {
193
+ return true;
194
+ }
195
+ return signal.aborted;
196
+ }
197
+ function normalizeError(error) {
198
+ return error instanceof Error ? error : new Error(String(error));
199
+ }
200
+ function determineResultStatus(cancelRequested, aborted, hasError) {
201
+ if (cancelRequested || aborted) {
202
+ return "canceled";
203
+ }
204
+ if (hasError) {
205
+ return "failed";
206
+ }
207
+ return "succeeded";
208
+ }
209
+ function createHookRunner(runHooks) {
210
+ let ran = false;
211
+ return {
212
+ ensureRun: async () => {
213
+ if (!ran) {
214
+ ran = true;
215
+ await runHooks();
216
+ }
217
+ },
218
+ hasRun: () => ran
219
+ };
220
+ }
221
+
222
+ // src/execution/streaming-host.ts
223
+ var StreamingExecutionHost = class {
224
+ constructor(createSession, generator, userSignal) {
225
+ this.createSession = createSession;
226
+ this.generator = generator;
227
+ this.effectiveSignal = userSignal ? combineSignals(userSignal, this.abortController.signal) : this.abortController.signal;
228
+ this.consumerPromise = this.startConsuming();
229
+ }
230
+ abortController = new AbortController();
231
+ effectiveSignal;
232
+ consumerPromise;
233
+ eventBuffer = [];
234
+ subscribers = /* @__PURE__ */ new Set();
235
+ completed = false;
236
+ cleaned = false;
237
+ hookRunner = null;
238
+ cancelRequested = false;
239
+ extractedOutcome = null;
240
+ extractedSummary = null;
241
+ hasDataField(event) {
242
+ return "data" in event && event.data !== void 0;
243
+ }
244
+ hasSummaryField(event) {
245
+ return "summary" in event && event.summary !== void 0;
246
+ }
247
+ hasErrorField(event) {
248
+ return "error" in event && event.error instanceof Error;
249
+ }
250
+ extractResultAndMetadata(event) {
251
+ const isCompleteOrError = event.type === "complete" || event.type === "error";
252
+ if (!isCompleteOrError) {
253
+ return;
254
+ }
255
+ if (this.hasErrorField(event)) {
256
+ this.extractedOutcome = { type: "error", error: event.error };
257
+ } else if (this.hasDataField(event)) {
258
+ this.extractedOutcome = { type: "result", value: event.data };
259
+ }
260
+ if (this.hasSummaryField(event)) {
261
+ this.extractedSummary = event.summary;
262
+ }
263
+ }
264
+ notifySubscribers(event) {
265
+ this.subscribers.forEach((fn) => fn(event));
266
+ }
267
+ async startConsuming() {
268
+ const session = this.createSession(this.effectiveSignal);
269
+ this.hookRunner = createHookRunner(() => session.runOnDoneHooks());
270
+ const gen = this.generator(session);
271
+ try {
272
+ let next = await gen.next();
273
+ while (!next.done) {
274
+ this.eventBuffer.push(next.value);
275
+ this.notifySubscribers(next.value);
276
+ const isTerminal = next.value.type === "complete" || next.value.type === "error";
277
+ if (isTerminal) {
278
+ this.extractResultAndMetadata(next.value);
279
+ this.abortController.abort();
280
+ break;
281
+ }
282
+ if (this.abortController.signal.aborted) {
283
+ break;
284
+ }
285
+ next = await gen.next();
286
+ }
287
+ if (next.done && next.value !== void 0) {
288
+ const finalEvent = await Promise.resolve(next.value);
289
+ this.eventBuffer.push(finalEvent);
290
+ this.notifySubscribers(finalEvent);
291
+ this.extractResultAndMetadata(finalEvent);
292
+ const isTerminal = finalEvent.type === "complete" || finalEvent.type === "error";
293
+ if (isTerminal) {
294
+ this.abortController.abort();
295
+ }
296
+ }
297
+ return this.buildResult(session);
298
+ } catch (error) {
299
+ const errorObj = normalizeError(error);
300
+ if (isAbortError(error, this.abortController.signal)) {
301
+ return {
302
+ success: false,
303
+ aborted: true,
304
+ error: errorObj,
305
+ summary: await session.getSummary()
306
+ };
307
+ }
308
+ const errorEvent = await session.fail(errorObj);
309
+ this.eventBuffer.push(errorEvent);
310
+ this.notifySubscribers(errorEvent);
311
+ this.extractResultAndMetadata(errorEvent);
312
+ this.abortController.abort();
313
+ return this.buildResult(session);
314
+ } finally {
315
+ this.completed = true;
316
+ await this.hookRunner?.ensureRun();
317
+ await gen.return(void 0);
318
+ }
319
+ }
320
+ async buildResult(session) {
321
+ const summary = this.extractedSummary ?? await session.getSummary();
322
+ if (this.extractedOutcome?.type === "error") {
323
+ return {
324
+ success: false,
325
+ aborted: false,
326
+ error: this.extractedOutcome.error,
327
+ summary
328
+ };
329
+ }
330
+ if (this.extractedOutcome?.type === "result") {
331
+ return {
332
+ success: true,
333
+ result: this.extractedOutcome.value,
334
+ summary
335
+ };
336
+ }
337
+ return {
338
+ success: false,
339
+ aborted: true,
340
+ error: new Error(ERRORS.NO_RESULT),
341
+ summary
342
+ };
343
+ }
344
+ /**
345
+ * Get the event stream.
346
+ * Returns buffered events first, then real-time events.
347
+ * Can be called multiple times - replays buffer each time.
348
+ */
349
+ async *stream() {
350
+ let index = 0;
351
+ while (index < this.eventBuffer.length) {
352
+ yield this.eventBuffer[index++];
353
+ }
354
+ if (this.completed) {
355
+ return;
356
+ }
357
+ const queue = [];
358
+ let pending = new Deferred();
359
+ const subscriber = (event) => {
360
+ queue.push(event);
361
+ pending.resolve();
362
+ };
363
+ this.subscribers.add(subscriber);
364
+ try {
365
+ while (!this.completed || queue.length > 0) {
366
+ if (queue.length > 0) {
367
+ yield queue.shift();
368
+ } else if (!this.completed) {
369
+ await pending.promise;
370
+ pending = new Deferred();
371
+ }
372
+ }
373
+ } finally {
374
+ this.subscribers.delete(subscriber);
375
+ }
376
+ }
377
+ cancel() {
378
+ this.cancelRequested = true;
379
+ this.abortController.abort();
380
+ }
381
+ async cleanup() {
382
+ if (this.cleaned) {
383
+ return;
384
+ }
385
+ this.cleaned = true;
386
+ if (!this.completed) {
387
+ this.cancel();
388
+ await this.consumerPromise.catch(() => {
389
+ });
390
+ }
391
+ this.subscribers.clear();
392
+ await this.hookRunner?.ensureRun();
393
+ }
394
+ async [Symbol.asyncDispose]() {
395
+ await this.cleanup();
396
+ }
397
+ /**
398
+ * Get the execution result with status, summary, and all events.
399
+ * Never throws - returns a discriminated union with status.
400
+ */
401
+ async result() {
402
+ const internal = await this.consumerPromise;
403
+ const events = Object.freeze([...this.eventBuffer]);
404
+ if (internal.success) {
405
+ return {
406
+ status: "succeeded",
407
+ value: internal.result,
408
+ summary: internal.summary,
409
+ events
410
+ };
411
+ }
412
+ if (this.cancelRequested || internal.aborted) {
413
+ return {
414
+ status: "canceled",
415
+ summary: internal.summary,
416
+ events
417
+ };
418
+ }
419
+ return {
420
+ status: "failed",
421
+ error: internal.error,
422
+ summary: internal.summary,
423
+ events
424
+ };
425
+ }
426
+ };
427
+
428
+ // src/execution/simple-host.ts
429
+ var SimpleExecutionHost = class {
430
+ abortController = new AbortController();
431
+ effectiveSignal;
432
+ consumerPromise;
433
+ cachedSession;
434
+ startTime = Date.now();
435
+ cancelRequested = false;
436
+ constructor(createSession, fn, userSignal) {
437
+ this.effectiveSignal = userSignal ? combineSignals(userSignal, this.abortController.signal) : this.abortController.signal;
438
+ this.consumerPromise = this.execute(createSession, fn);
439
+ }
440
+ async execute(createSession, fn) {
441
+ const session = createSession(this.effectiveSignal);
442
+ this.cachedSession = session;
443
+ const hookRunner = createHookRunner(() => session.runOnDoneHooks());
444
+ session.notifyExecutionStart();
445
+ try {
446
+ const result = await fn(session);
447
+ await session.notifyExecutionDone(result, this.startTime);
448
+ return {
449
+ success: true,
450
+ result,
451
+ summary: await session.getSummary()
452
+ };
453
+ } catch (error) {
454
+ const errorObj = normalizeError(error);
455
+ const isCancellation = isAbortError(error, this.abortController.signal);
456
+ if (!isCancellation) {
457
+ await session.notifyExecutionError(errorObj, this.startTime);
458
+ }
459
+ return {
460
+ success: false,
461
+ error: errorObj,
462
+ aborted: isCancellation,
463
+ summary: await session.getSummary()
464
+ };
465
+ } finally {
466
+ await hookRunner.ensureRun();
467
+ }
468
+ }
469
+ /**
470
+ * Request cancellation of the execution.
471
+ * Aborts the current LLM call if in progress.
472
+ * No-op if execution already completed.
473
+ */
474
+ cancel() {
475
+ this.cancelRequested = true;
476
+ this.abortController.abort();
477
+ }
478
+ /**
479
+ * Get the execution result with status and summary.
480
+ * Never throws - returns a discriminated union with status.
481
+ */
482
+ async result() {
483
+ const internal = await this.consumerPromise;
484
+ if (internal.success) {
485
+ return {
486
+ status: "succeeded",
487
+ value: internal.result,
488
+ summary: internal.summary
489
+ };
490
+ }
491
+ if (this.cancelRequested || internal.aborted) {
492
+ return {
493
+ status: "canceled",
494
+ summary: internal.summary
495
+ };
496
+ }
497
+ return {
498
+ status: "failed",
499
+ error: internal.error,
500
+ summary: internal.summary
501
+ };
502
+ }
503
+ /**
504
+ * Cleanup resources.
505
+ * For SimpleExecution, hooks are already run during execution,
506
+ * so this is intentionally a no-op.
507
+ */
508
+ async cleanup() {
509
+ }
510
+ async [Symbol.asyncDispose]() {
511
+ await this.cleanup();
512
+ }
513
+ };
514
+
515
+ // src/execution/mapping.ts
516
+ function mapExecution(execution, fn) {
517
+ if ("stream" in execution) {
518
+ return mapStreamingExecution(execution, fn);
519
+ }
520
+ return mapSimpleExecution(execution, fn);
521
+ }
522
+ function mapExecutionResult(execution, fn) {
523
+ if ("stream" in execution) {
524
+ return mapStreamingExecutionResult(execution, fn);
525
+ }
526
+ return mapSimpleExecution(execution, fn);
527
+ }
528
+ function mapStreamingExecution(execution, fn) {
529
+ return {
530
+ stream() {
531
+ const original = execution.stream();
532
+ return {
533
+ [Symbol.asyncIterator]() {
534
+ const iter = original[Symbol.asyncIterator]();
535
+ return {
536
+ async next() {
537
+ const { value, done } = await iter.next();
538
+ if (done) return { value: void 0, done: true };
539
+ const event = value;
540
+ if (event.type === "error") {
541
+ return { value: event, done: false };
542
+ }
543
+ const { metrics, ...pureEvent } = event;
544
+ try {
545
+ const mapped = await fn(pureEvent);
546
+ return {
547
+ value: { ...mapped, metrics },
548
+ done: false
549
+ };
550
+ } catch (err) {
551
+ const errorEvent = {
552
+ type: "error",
553
+ error: normalizeError(err),
554
+ metrics
555
+ };
556
+ return { value: errorEvent, done: false };
557
+ }
558
+ }
559
+ };
560
+ }
561
+ };
562
+ },
563
+ async result() {
564
+ const original = await execution.result();
565
+ if (original.status !== "succeeded") {
566
+ return original;
567
+ }
568
+ try {
569
+ const mappedEvents = [];
570
+ for (const event of original.events) {
571
+ if (event.type === "error") {
572
+ mappedEvents.push(event);
573
+ continue;
574
+ }
575
+ const { metrics, ...pureEvent } = event;
576
+ const mapped = await fn(pureEvent);
577
+ mappedEvents.push({ ...mapped, metrics });
578
+ }
579
+ const completionEvent = mappedEvents.find((e) => e.type === "complete");
580
+ return {
581
+ status: "succeeded",
582
+ value: completionEvent.data,
583
+ events: mappedEvents,
584
+ summary: original.summary
585
+ };
586
+ } catch (err) {
587
+ return {
588
+ status: "failed",
589
+ error: normalizeError(err),
590
+ events: original.events,
591
+ summary: original.summary
592
+ };
593
+ }
594
+ },
595
+ cancel: () => execution.cancel(),
596
+ cleanup: () => execution.cleanup(),
597
+ [Symbol.asyncDispose]: () => execution[Symbol.asyncDispose]()
598
+ };
599
+ }
600
+ function mapStreamingExecutionResult(execution, fn) {
601
+ return {
602
+ stream() {
603
+ const original = execution.stream();
604
+ return {
605
+ [Symbol.asyncIterator]() {
606
+ const iter = original[Symbol.asyncIterator]();
607
+ return {
608
+ async next() {
609
+ const { value, done } = await iter.next();
610
+ if (done) return { value: void 0, done: true };
611
+ const event = value;
612
+ if (event.type === "complete") {
613
+ const { metrics, ...rest } = event;
614
+ try {
615
+ const mapped = await fn(rest.data);
616
+ return {
617
+ value: { type: "complete", data: mapped, summary: rest.summary, metrics },
618
+ done: false
619
+ };
620
+ } catch (err) {
621
+ const errorEvent = {
622
+ type: "error",
623
+ error: normalizeError(err),
624
+ metrics
625
+ };
626
+ return { value: errorEvent, done: false };
627
+ }
628
+ }
629
+ return { value: event, done: false };
630
+ }
631
+ };
632
+ }
633
+ };
634
+ },
635
+ async result() {
636
+ const original = await execution.result();
637
+ if (original.status !== "succeeded") {
638
+ return original;
639
+ }
640
+ try {
641
+ const mapped = await fn(original.value);
642
+ const mappedEvents = original.events.map((event) => {
643
+ if (event.type === "complete") {
644
+ return { ...event, data: mapped };
645
+ }
646
+ return event;
647
+ });
648
+ return {
649
+ status: "succeeded",
650
+ value: mapped,
651
+ events: mappedEvents,
652
+ summary: original.summary
653
+ };
654
+ } catch (err) {
655
+ return {
656
+ status: "failed",
657
+ error: normalizeError(err),
658
+ events: original.events,
659
+ summary: original.summary
660
+ };
661
+ }
662
+ },
663
+ cancel: () => execution.cancel(),
664
+ cleanup: () => execution.cleanup(),
665
+ [Symbol.asyncDispose]: () => execution[Symbol.asyncDispose]()
666
+ };
667
+ }
668
+ function mapSimpleExecution(execution, fn) {
669
+ return {
670
+ async result() {
671
+ const original = await execution.result();
672
+ if (original.status !== "succeeded") {
673
+ return original;
674
+ }
675
+ try {
676
+ const mapped = await fn(original.value);
677
+ return {
678
+ status: "succeeded",
679
+ value: mapped,
680
+ summary: original.summary
681
+ };
682
+ } catch (err) {
683
+ return {
684
+ status: "failed",
685
+ error: normalizeError(err),
686
+ summary: original.summary
687
+ };
688
+ }
689
+ },
690
+ cancel: () => execution.cancel(),
691
+ cleanup: () => execution.cleanup(),
692
+ [Symbol.asyncDispose]: () => execution[Symbol.asyncDispose]()
693
+ };
694
+ }
695
+
696
+ // src/observability/logger.ts
697
+ var noopLogger = {};
698
+ function createLogger(handlers) {
699
+ return handlers;
700
+ }
701
+ var TOOL_DESCRIPTIONS = {
702
+ reportProgress: "[OPTIONAL] Report progress during task execution. Use this to show intermediate work. You may call this multiple times, then you MUST call tools::submitResult.",
703
+ submitResult: "[REQUIRED] Submit the final result. You MUST call this exactly once to complete the task. Without this call, the task FAILS."
704
+ };
705
+ var TOOL_CALLING_PROTOCOL = `## CRITICAL INSTRUCTION - READ CAREFULLY
706
+
707
+ You have 2 tools available:
708
+ 1. reportProgress - [OPTIONAL] Show intermediate work (multiple times)
709
+ 2. submitResult - [REQUIRED] Submit your final answer
710
+
711
+ \u26A0\uFE0F IMPORTANT RULES:
712
+ - You may call reportProgress 0-3 times to show progress
713
+ - You MUST call submitResult exactly once to complete the task
714
+ - After calling reportProgress, you MUST call submitResult in your NEXT response
715
+ - If you call reportProgress more than 3 times without submitResult, the task FAILS
716
+ - The task is NOT complete until submitResult is called
717
+
718
+ CORRECT SEQUENCE:
719
+ 1. [Optional] reportProgress
720
+ 2. [Required] submitResult (exactly once)
721
+
722
+ \u274C WRONG: reportProgress \u2192 reportProgress \u2192 reportProgress \u2192 reportProgress (no submitResult = FAIL)
723
+ \u2705 CORRECT: reportProgress \u2192 submitResult (SUCCESS)`;
724
+ function defineProgressivePattern(config) {
725
+ return new ProgressivePattern(config.progressSchema, config.resultSchema);
726
+ }
727
+ var ProgressivePattern = class {
728
+ constructor(progressSchema, resultSchema) {
729
+ this.progressSchema = progressSchema;
730
+ this.resultSchema = resultSchema;
731
+ }
732
+ lastParseError = null;
733
+ /**
734
+ * Runs the pattern within an existing session. Use this for composing
735
+ * multiple patterns or when you need fine-grained control over the session.
736
+ *
737
+ * @param session - The streaming session to run within
738
+ * @param options - Stream options including:
739
+ * - `stopWhen` - Additional stop conditions (combined with default `hasToolCall('submitResult')`)
740
+ * - `protocol` - Custom protocol instructions (replaces default `TOOL_CALLING_PROTOCOL`)
741
+ * - All other `streamText` options except `tools`, `toolChoice`, `stopWhen`
742
+ *
743
+ * @example Basic usage
744
+ * ```typescript
745
+ * provider.streamingExecution(async function*(session) {
746
+ * yield* pattern.runInSession(session, {
747
+ * system: 'You are an analyzer.',
748
+ * messages: [{ role: 'user', content: 'Analyze...' }],
749
+ * });
750
+ * });
751
+ * ```
752
+ *
753
+ * @example With custom stopWhen
754
+ * ```typescript
755
+ * yield* pattern.runInSession(session, {
756
+ * prompt: 'Analyze...',
757
+ * stopWhen: stepCountIs(5), // Combined: submitResult OR 5 steps
758
+ * });
759
+ * ```
760
+ */
761
+ async *runInSession(session, options) {
762
+ const {
763
+ tools: userTools,
764
+ system,
765
+ stopWhen: userStopWhen,
766
+ protocol,
767
+ ...restOptions
768
+ } = options;
769
+ const internalTools = this.createTools();
770
+ const allTools = { ...userTools, ...internalTools };
771
+ const systemString = typeof system === "string" ? system : void 0;
772
+ const fullSystem = this.renderSystemPrompt(systemString, protocol);
773
+ const defaultStopCondition = ai.hasToolCall("submitResult");
774
+ const stopConditions = this.combineStopConditions(defaultStopCondition, userStopWhen);
775
+ const stream = session.streamText({
776
+ ...restOptions,
777
+ system: fullSystem,
778
+ tools: allTools,
779
+ toolChoice: "required",
780
+ stopWhen: stopConditions
781
+ });
782
+ let result = null;
783
+ for await (const part of stream.fullStream) {
784
+ if (part.type === "tool-call") {
785
+ if (part.toolName === "reportProgress") {
786
+ const input = "input" in part ? part.input : void 0;
787
+ const progressData = this.parseProgressInput(input);
788
+ if (progressData !== null) {
789
+ yield session.emit({
790
+ type: "progress",
791
+ data: progressData
792
+ });
793
+ }
794
+ } else if (part.toolName === "submitResult") {
795
+ const input = "input" in part ? part.input : void 0;
796
+ result = this.parseResultInput(input);
797
+ }
798
+ }
799
+ }
800
+ if (result === null) {
801
+ const baseMsg = "ProgressivePattern: No result received.";
802
+ const detail = this.lastParseError ? ` Last parse error: ${this.lastParseError.message}` : " The LLM did not call submitResult tool.";
803
+ throw new Error(baseMsg + detail);
804
+ }
805
+ const completeEvent = await session.done(result);
806
+ yield completeEvent;
807
+ return completeEvent;
808
+ }
809
+ /**
810
+ * Standalone execution that creates a new session internally.
811
+ * Use this for simple, single-pattern executions.
812
+ *
813
+ * @param provider - The AI provider to use
814
+ * @param options - Stream options including:
815
+ * - `stopWhen` - Additional stop conditions (combined with default `hasToolCall('submitResult')`)
816
+ * - `protocol` - Custom protocol instructions (replaces default `TOOL_CALLING_PROTOCOL`)
817
+ *
818
+ * @example Basic usage
819
+ * ```typescript
820
+ * for await (const event of pattern.run(provider, {
821
+ * system: 'You are an analyzer.',
822
+ * prompt: 'Analyze this document...',
823
+ * })) {
824
+ * if (event.type === 'progress') {
825
+ * console.log('Progress:', event.data);
826
+ * } else if (event.type === 'complete') {
827
+ * console.log('Result:', event.data);
828
+ * }
829
+ * }
830
+ * ```
831
+ *
832
+ * @example With step limit
833
+ * ```typescript
834
+ * import { stepCountIs } from 'ai';
835
+ *
836
+ * for await (const event of pattern.run(provider, {
837
+ * prompt: 'Analyze...',
838
+ * stopWhen: stepCountIs(10),
839
+ * })) { ... }
840
+ * ```
841
+ */
842
+ run(provider, options) {
843
+ const self = this;
844
+ const execution = provider.streamingExecution(async function* (session) {
845
+ return yield* self.runInSession(session, options);
846
+ });
847
+ return execution.stream();
848
+ }
849
+ createTools() {
850
+ return {
851
+ reportProgress: ai.tool({
852
+ description: TOOL_DESCRIPTIONS.reportProgress,
853
+ inputSchema: zod.z.object({
854
+ data: this.progressSchema
855
+ }),
856
+ execute: async () => ({
857
+ status: "progress_recorded",
858
+ instruction: "After all progress reports, you MUST call tools::submitResult to complete the task."
859
+ })
860
+ }),
861
+ submitResult: ai.tool({
862
+ description: TOOL_DESCRIPTIONS.submitResult,
863
+ inputSchema: zod.z.object({
864
+ data: this.resultSchema
865
+ }),
866
+ execute: async () => ({
867
+ status: "result_submitted",
868
+ message: "Task completed successfully."
869
+ })
870
+ })
871
+ };
872
+ }
873
+ parseJsonWrapper(input, schema) {
874
+ try {
875
+ if (!input || typeof input !== "object") return null;
876
+ const wrapper = input;
877
+ if (wrapper.data === void 0) return null;
878
+ const parsed = typeof wrapper.data === "string" ? JSON.parse(wrapper.data) : wrapper.data;
879
+ return schema.parse(parsed);
880
+ } catch (error) {
881
+ this.lastParseError = error instanceof Error ? error : new Error(String(error));
882
+ return null;
883
+ }
884
+ }
885
+ parseProgressInput(input) {
886
+ return this.parseJsonWrapper(input, this.progressSchema);
887
+ }
888
+ parseResultInput(input) {
889
+ return this.parseJsonWrapper(input, this.resultSchema);
890
+ }
891
+ combineStopConditions(defaultCondition, userConditions) {
892
+ if (!userConditions) {
893
+ return [defaultCondition];
894
+ }
895
+ const userArray = Array.isArray(userConditions) ? userConditions : [userConditions];
896
+ return [defaultCondition, ...userArray];
897
+ }
898
+ renderSystemPrompt(userSystem, protocol) {
899
+ const protocolText = protocol ?? TOOL_CALLING_PROTOCOL;
900
+ return userSystem ? `${userSystem}
901
+
902
+ ${protocolText}` : protocolText;
903
+ }
904
+ };
905
+
906
+ // src/pricing/validator.ts
907
+ function validatePriceValue(value, fieldName, context) {
908
+ if (!Number.isFinite(value)) {
909
+ throw new Error(`${context}: ${fieldName} must be a finite number`);
910
+ }
911
+ if (value < 0) {
912
+ throw new Error(`${context}: ${fieldName} cannot be negative`);
913
+ }
914
+ }
915
+ function validateModelPricing(pricing, context) {
916
+ validatePriceValue(
917
+ pricing.inputPricePerMillion,
918
+ "inputPricePerMillion",
919
+ context
920
+ );
921
+ validatePriceValue(
922
+ pricing.outputPricePerMillion,
923
+ "outputPricePerMillion",
924
+ context
925
+ );
926
+ if (pricing.cachedInputPricePerMillion !== void 0) {
927
+ validatePriceValue(
928
+ pricing.cachedInputPricePerMillion,
929
+ "cachedInputPricePerMillion",
930
+ context
931
+ );
932
+ }
933
+ }
934
+ function validateProviderPricing(pricing, providerContext) {
935
+ for (const [model, modelPricing] of Object.entries(pricing)) {
936
+ const context = providerContext ? `${providerContext}/${model}` : model;
937
+ validateModelPricing(modelPricing, context);
938
+ }
939
+ }
940
+ function validatePricingConfig(config) {
941
+ if (config.providers) {
942
+ for (const [providerKey, pricing] of Object.entries(config.providers)) {
943
+ if (pricing) {
944
+ validateProviderPricing(pricing, providerKey);
945
+ }
946
+ }
947
+ }
948
+ if (config.fallback) {
949
+ validateModelPricing(config.fallback, "fallback");
950
+ }
951
+ }
952
+
953
+ // src/pricing/defaults.ts
954
+ var OPENAI_PRICING = {
955
+ "gpt-4o": { inputPricePerMillion: 2.5, outputPricePerMillion: 10 },
956
+ "gpt-4o-mini": { inputPricePerMillion: 0.15, outputPricePerMillion: 0.6 },
957
+ "gpt-4-turbo": { inputPricePerMillion: 10, outputPricePerMillion: 30 },
958
+ "gpt-4-turbo-preview": {
959
+ inputPricePerMillion: 10,
960
+ outputPricePerMillion: 30
961
+ },
962
+ "gpt-4": { inputPricePerMillion: 30, outputPricePerMillion: 60 },
963
+ "gpt-4-32k": { inputPricePerMillion: 60, outputPricePerMillion: 120 },
964
+ "gpt-3.5-turbo": { inputPricePerMillion: 0.5, outputPricePerMillion: 1.5 },
965
+ "gpt-3.5-turbo-16k": {
966
+ inputPricePerMillion: 3,
967
+ outputPricePerMillion: 4
968
+ },
969
+ "o1": { inputPricePerMillion: 15, outputPricePerMillion: 60 },
970
+ "o1-mini": { inputPricePerMillion: 3, outputPricePerMillion: 12 },
971
+ "o1-preview": { inputPricePerMillion: 15, outputPricePerMillion: 60 },
972
+ "o3": { inputPricePerMillion: 20, outputPricePerMillion: 80 },
973
+ "o3-mini": { inputPricePerMillion: 4, outputPricePerMillion: 16 }
974
+ };
975
+ var GOOGLE_PRICING = {
976
+ "gemini-2.5-flash": {
977
+ inputPricePerMillion: 0.15,
978
+ outputPricePerMillion: 0.6,
979
+ cachedInputPricePerMillion: 0.0375
980
+ },
981
+ "gemini-2.5-flash-lite": {
982
+ inputPricePerMillion: 0.075,
983
+ outputPricePerMillion: 0.3,
984
+ cachedInputPricePerMillion: 0.01875
985
+ },
986
+ "gemini-2.5-pro": {
987
+ inputPricePerMillion: 1.25,
988
+ outputPricePerMillion: 10,
989
+ cachedInputPricePerMillion: 0.3125
990
+ },
991
+ "gemini-2.0-flash": {
992
+ inputPricePerMillion: 0.1,
993
+ outputPricePerMillion: 0.4,
994
+ cachedInputPricePerMillion: 0.025
995
+ },
996
+ "gemini-2.0-flash-lite": {
997
+ inputPricePerMillion: 0.075,
998
+ outputPricePerMillion: 0.3,
999
+ cachedInputPricePerMillion: 0.01875
1000
+ },
1001
+ "gemini-1.5-pro": {
1002
+ inputPricePerMillion: 1.25,
1003
+ outputPricePerMillion: 5,
1004
+ cachedInputPricePerMillion: 0.3125
1005
+ },
1006
+ "gemini-1.5-flash": {
1007
+ inputPricePerMillion: 0.075,
1008
+ outputPricePerMillion: 0.3,
1009
+ cachedInputPricePerMillion: 0.01875
1010
+ },
1011
+ "gemini-1.5-flash-8b": {
1012
+ inputPricePerMillion: 0.0375,
1013
+ outputPricePerMillion: 0.15,
1014
+ cachedInputPricePerMillion: 0.01
1015
+ },
1016
+ "gemini-pro": { inputPricePerMillion: 0.5, outputPricePerMillion: 1.5 }
1017
+ };
1018
+ var ANTHROPIC_PRICING = {
1019
+ "claude-opus-4-5-20250514": {
1020
+ inputPricePerMillion: 15,
1021
+ outputPricePerMillion: 75,
1022
+ cachedInputPricePerMillion: 1.875
1023
+ },
1024
+ "claude-sonnet-4-20250514": {
1025
+ inputPricePerMillion: 3,
1026
+ outputPricePerMillion: 15,
1027
+ cachedInputPricePerMillion: 0.375
1028
+ },
1029
+ "claude-3-5-sonnet-20241022": {
1030
+ inputPricePerMillion: 3,
1031
+ outputPricePerMillion: 15,
1032
+ cachedInputPricePerMillion: 0.375
1033
+ },
1034
+ "claude-3-5-haiku-20241022": {
1035
+ inputPricePerMillion: 0.8,
1036
+ outputPricePerMillion: 4,
1037
+ cachedInputPricePerMillion: 0.1
1038
+ },
1039
+ "claude-3-opus-20240229": {
1040
+ inputPricePerMillion: 15,
1041
+ outputPricePerMillion: 75,
1042
+ cachedInputPricePerMillion: 1.875
1043
+ },
1044
+ "claude-3-sonnet-20240229": {
1045
+ inputPricePerMillion: 3,
1046
+ outputPricePerMillion: 15,
1047
+ cachedInputPricePerMillion: 0.375
1048
+ },
1049
+ "claude-3-haiku-20240307": {
1050
+ inputPricePerMillion: 0.25,
1051
+ outputPricePerMillion: 1.25,
1052
+ cachedInputPricePerMillion: 0.03
1053
+ }
1054
+ };
1055
+ var DEFAULT_PRICING_CONFIG = {
1056
+ providers: {
1057
+ openai: OPENAI_PRICING,
1058
+ google: GOOGLE_PRICING,
1059
+ anthropic: ANTHROPIC_PRICING
1060
+ },
1061
+ fallback: {
1062
+ inputPricePerMillion: 1,
1063
+ outputPricePerMillion: 5
1064
+ }
1065
+ };
1066
+ var DEFAULT_FALLBACK_PRICING = {
1067
+ inputPricePerMillion: 1,
1068
+ outputPricePerMillion: 5
1069
+ };
1070
+
1071
+ // src/pricing/config.ts
1072
+ var globalConfig;
1073
+ function configurePricing(config) {
1074
+ if (config) {
1075
+ validatePricingConfig(config);
1076
+ }
1077
+ globalConfig = config;
1078
+ }
1079
+ function getPricingConfig() {
1080
+ return globalConfig;
1081
+ }
1082
+ function resetPricingConfig() {
1083
+ globalConfig = void 0;
1084
+ }
1085
+ function getEffectivePricing(model, provider) {
1086
+ if (globalConfig?.providers?.[provider]?.[model]) {
1087
+ return {
1088
+ pricing: globalConfig.providers[provider][model],
1089
+ source: "global"
1090
+ };
1091
+ }
1092
+ const defaultPricing = DEFAULT_PRICING_CONFIG.providers[provider];
1093
+ if (defaultPricing?.[model]) {
1094
+ return {
1095
+ pricing: defaultPricing[model],
1096
+ source: "default"
1097
+ };
1098
+ }
1099
+ return {
1100
+ pricing: globalConfig?.fallback ?? DEFAULT_PRICING_CONFIG.fallback ?? DEFAULT_FALLBACK_PRICING,
1101
+ source: "fallback"
1102
+ };
1103
+ }
1104
+
1105
+ // src/pricing/calculator.ts
1106
+ var TOKENS_PER_MILLION = 1e6;
1107
+ function getModelPricing(model, provider, providerPricing) {
1108
+ if (providerPricing?.[model]) {
1109
+ return providerPricing[model];
1110
+ }
1111
+ const globalConfig2 = getPricingConfig();
1112
+ if (globalConfig2?.providers?.[provider]?.[model]) {
1113
+ return globalConfig2.providers[provider][model];
1114
+ }
1115
+ const defaultProviderPricing = DEFAULT_PRICING_CONFIG.providers[provider];
1116
+ if (defaultProviderPricing?.[model]) {
1117
+ return defaultProviderPricing[model];
1118
+ }
1119
+ return globalConfig2?.fallback ?? DEFAULT_PRICING_CONFIG.fallback ?? DEFAULT_FALLBACK_PRICING;
1120
+ }
1121
+ function validateCostParams(params) {
1122
+ const { inputTokens, outputTokens, cachedInputTokens = 0 } = params;
1123
+ if (inputTokens < 0 || outputTokens < 0 || cachedInputTokens < 0) {
1124
+ throw new Error("Token counts must be non-negative");
1125
+ }
1126
+ if (cachedInputTokens > inputTokens) {
1127
+ throw new Error("cachedInputTokens cannot exceed inputTokens");
1128
+ }
1129
+ if (!Number.isFinite(inputTokens) || !Number.isFinite(outputTokens) || !Number.isFinite(cachedInputTokens)) {
1130
+ throw new Error("Token counts must be finite numbers");
1131
+ }
1132
+ }
1133
+ function calculateCost(params, providerPricing) {
1134
+ validateCostParams(params);
1135
+ const {
1136
+ inputTokens,
1137
+ outputTokens,
1138
+ cachedInputTokens = 0,
1139
+ model,
1140
+ provider
1141
+ } = params;
1142
+ const pricing = getModelPricing(model, provider, providerPricing);
1143
+ const nonCachedInputTokens = inputTokens - cachedInputTokens;
1144
+ const inputCost = nonCachedInputTokens / TOKENS_PER_MILLION * pricing.inputPricePerMillion;
1145
+ const outputCost = outputTokens / TOKENS_PER_MILLION * pricing.outputPricePerMillion;
1146
+ const cachedInputPricePerMillion = pricing.cachedInputPricePerMillion ?? pricing.inputPricePerMillion;
1147
+ const cachedInputCost = cachedInputTokens / TOKENS_PER_MILLION * cachedInputPricePerMillion;
1148
+ return {
1149
+ total: inputCost + outputCost + cachedInputCost,
1150
+ inputCost,
1151
+ outputCost,
1152
+ cachedInputCost
1153
+ };
1154
+ }
1155
+ function calculateCostFromUsage(usage, model, provider, providerPricing) {
1156
+ return calculateCost(
1157
+ {
1158
+ inputTokens: usage.inputTokens ?? 0,
1159
+ outputTokens: usage.outputTokens ?? 0,
1160
+ cachedInputTokens: usage.inputTokenDetails?.cacheReadTokens ?? 0,
1161
+ model,
1162
+ provider
1163
+ },
1164
+ providerPricing
1165
+ );
1166
+ }
1167
+ function calculateTotalCost(calls, providerPricing) {
1168
+ const costByModel = {};
1169
+ let totalCost = 0;
1170
+ for (const call of calls) {
1171
+ const cost = calculateCostFromUsage(
1172
+ call.usage,
1173
+ call.model,
1174
+ call.provider,
1175
+ providerPricing
1176
+ );
1177
+ totalCost += cost.total;
1178
+ const key = `${call.provider}/${call.model}`;
1179
+ costByModel[key] = (costByModel[key] ?? 0) + cost.total;
1180
+ }
1181
+ return { totalCost, costByModel };
1182
+ }
1183
+
1184
+ // src/prompt/errors.ts
1185
+ var PromptErrorCode = /* @__PURE__ */ ((PromptErrorCode2) => {
1186
+ PromptErrorCode2["PROMPT_ERROR"] = "PROMPT_ERROR";
1187
+ PromptErrorCode2["NOT_FOUND"] = "PROMPT_NOT_FOUND";
1188
+ PromptErrorCode2["INVALID_FORMAT"] = "PROMPT_INVALID_FORMAT";
1189
+ PromptErrorCode2["TEMPLATE_ERROR"] = "PROMPT_TEMPLATE_ERROR";
1190
+ PromptErrorCode2["IO_ERROR"] = "PROMPT_IO_ERROR";
1191
+ return PromptErrorCode2;
1192
+ })(PromptErrorCode || {});
1193
+ var PromptError = class _PromptError extends AgtlantisError {
1194
+ constructor(message, options = {}) {
1195
+ super(message, {
1196
+ code: options.code ?? "PROMPT_ERROR" /* PROMPT_ERROR */,
1197
+ cause: options.cause,
1198
+ context: options.context
1199
+ });
1200
+ this.name = "PromptError";
1201
+ }
1202
+ /**
1203
+ * Creates a PromptError from an unknown error.
1204
+ */
1205
+ static from(error, code = "PROMPT_ERROR" /* PROMPT_ERROR */, context) {
1206
+ if (error instanceof _PromptError) {
1207
+ return error;
1208
+ }
1209
+ const cause = error instanceof Error ? error : new Error(String(error));
1210
+ return new _PromptError(cause.message, { code, cause, context });
1211
+ }
1212
+ };
1213
+ var PromptNotFoundError = class extends PromptError {
1214
+ promptId;
1215
+ version;
1216
+ constructor(promptId, version, options = {}) {
1217
+ const message = version ? `Prompt '${promptId}' version '${version}' not found` : `Prompt '${promptId}' not found`;
1218
+ super(message, {
1219
+ code: "PROMPT_NOT_FOUND" /* NOT_FOUND */,
1220
+ cause: options.cause,
1221
+ context: { promptId, version, ...options.context }
1222
+ });
1223
+ this.name = "PromptNotFoundError";
1224
+ this.promptId = promptId;
1225
+ this.version = version;
1226
+ }
1227
+ };
1228
+ var PromptInvalidFormatError = class extends PromptError {
1229
+ promptId;
1230
+ details;
1231
+ constructor(promptId, details, options = {}) {
1232
+ super(`Invalid format for prompt '${promptId}': ${details}`, {
1233
+ code: "PROMPT_INVALID_FORMAT" /* INVALID_FORMAT */,
1234
+ cause: options.cause,
1235
+ context: { promptId, details, ...options.context }
1236
+ });
1237
+ this.name = "PromptInvalidFormatError";
1238
+ this.promptId = promptId;
1239
+ this.details = details;
1240
+ }
1241
+ };
1242
+ var PromptTemplateError = class extends PromptError {
1243
+ promptId;
1244
+ details;
1245
+ constructor(promptId, details, options = {}) {
1246
+ super(`Template compilation failed for prompt '${promptId}': ${details}`, {
1247
+ code: "PROMPT_TEMPLATE_ERROR" /* TEMPLATE_ERROR */,
1248
+ cause: options.cause,
1249
+ context: { promptId, details, ...options.context }
1250
+ });
1251
+ this.name = "PromptTemplateError";
1252
+ this.promptId = promptId;
1253
+ this.details = details;
1254
+ }
1255
+ };
1256
+ var PromptIOError = class extends PromptError {
1257
+ operation;
1258
+ path;
1259
+ constructor(operation, path5, options = {}) {
1260
+ const opText = operation === "list" ? "list prompts in" : `${operation} prompt file`;
1261
+ super(`Failed to ${opText}: ${path5}`, {
1262
+ code: "PROMPT_IO_ERROR" /* IO_ERROR */,
1263
+ cause: options.cause,
1264
+ context: { operation, path: path5, ...options.context }
1265
+ });
1266
+ this.name = "PromptIOError";
1267
+ this.operation = operation;
1268
+ this.path = path5;
1269
+ }
1270
+ };
1271
+
1272
+ // src/prompt/template.ts
1273
+ var handlebars = Handlebars__default.default.create();
1274
+ handlebars.registerHelper("add", (a, b) => {
1275
+ const numA = Number(a);
1276
+ const numB = Number(b);
1277
+ if (Number.isNaN(numA) || Number.isNaN(numB)) {
1278
+ return NaN;
1279
+ }
1280
+ return numA + numB;
1281
+ });
1282
+ function wrapTemplateError(promptId, error) {
1283
+ const message = error instanceof Error ? error.message : String(error);
1284
+ const cause = error instanceof Error ? error : void 0;
1285
+ return new PromptTemplateError(promptId, message, { cause });
1286
+ }
1287
+ function compileTemplate(template, promptId) {
1288
+ try {
1289
+ const compiled = handlebars.compile(template, {
1290
+ strict: true,
1291
+ noEscape: true
1292
+ });
1293
+ return (input) => {
1294
+ try {
1295
+ return compiled(input);
1296
+ } catch (error) {
1297
+ throw wrapTemplateError(promptId, error);
1298
+ }
1299
+ };
1300
+ } catch (error) {
1301
+ throw wrapTemplateError(promptId, error);
1302
+ }
1303
+ }
1304
+
1305
+ // src/prompt/prompt-template.ts
1306
+ var PromptTemplate = class _PromptTemplate {
1307
+ constructor(id, version, system, userTemplate) {
1308
+ this.id = id;
1309
+ this.version = version;
1310
+ this.system = system;
1311
+ this.userTemplate = userTemplate;
1312
+ }
1313
+ /**
1314
+ * Creates a PromptTemplate instance from raw data.
1315
+ *
1316
+ * @param data - Raw prompt template data
1317
+ * @returns PromptTemplate instance
1318
+ */
1319
+ static from(data) {
1320
+ return new _PromptTemplate(data.id, data.version, data.system, data.userTemplate);
1321
+ }
1322
+ /**
1323
+ * Compiles templates and returns a PromptRenderer.
1324
+ *
1325
+ * @typeParam TSystemInput - Type of input for system prompt template
1326
+ * @typeParam TUserInput - Type of input for user prompt template (defaults to TSystemInput)
1327
+ * @returns Compiled prompt renderer with renderSystemPrompt and renderUserPrompt functions
1328
+ * @throws {PromptTemplateError} If template compilation fails
1329
+ *
1330
+ * @example
1331
+ * ```typescript
1332
+ * // Different input types for system and user prompts
1333
+ * const renderer = template.compile<SessionCtx, TurnCtx>();
1334
+ *
1335
+ * // Same input type for both
1336
+ * const simpleRenderer = template.compile<CommonCtx>();
1337
+ * ```
1338
+ */
1339
+ compile() {
1340
+ return {
1341
+ id: this.id,
1342
+ version: this.version,
1343
+ renderSystemPrompt: compileTemplate(this.system, this.id),
1344
+ renderUserPrompt: compileTemplate(this.userTemplate, this.id)
1345
+ };
1346
+ }
1347
+ /**
1348
+ * Returns raw data representation.
1349
+ * Useful for serialization or passing to repository.write().
1350
+ */
1351
+ toData() {
1352
+ return {
1353
+ id: this.id,
1354
+ version: this.version,
1355
+ system: this.system,
1356
+ userTemplate: this.userTemplate
1357
+ };
1358
+ }
1359
+ };
1360
+ function toErrorCause(error) {
1361
+ return error instanceof Error ? error : void 0;
1362
+ }
1363
+ function toErrorMessage(error) {
1364
+ return error instanceof Error ? error.message : String(error);
1365
+ }
1366
+ var defaultFileSystem = {
1367
+ readFile: (filePath) => fs__namespace.readFile(filePath, "utf-8"),
1368
+ writeFile: (filePath, content) => fs__namespace.writeFile(filePath, content, "utf-8"),
1369
+ readdir: (dirPath) => fs__namespace.readdir(dirPath)
1370
+ };
1371
+ function parseVersion(version) {
1372
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
1373
+ if (!match) return null;
1374
+ return [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10)];
1375
+ }
1376
+ function compareVersions(a, b) {
1377
+ const parsedA = parseVersion(a);
1378
+ const parsedB = parseVersion(b);
1379
+ if (!parsedA && !parsedB) return 0;
1380
+ if (!parsedA) return 1;
1381
+ if (!parsedB) return -1;
1382
+ for (let i = 0; i < 3; i++) {
1383
+ if (parsedA[i] !== parsedB[i]) {
1384
+ return parsedA[i] - parsedB[i];
1385
+ }
1386
+ }
1387
+ return 0;
1388
+ }
1389
+ var FILE_EXTENSION = ".yaml";
1390
+ function getFileName(id, version) {
1391
+ return `${id}-${version}${FILE_EXTENSION}`;
1392
+ }
1393
+ function parseFileName(fileName) {
1394
+ if (!fileName.endsWith(FILE_EXTENSION)) return null;
1395
+ const baseName = fileName.slice(0, -FILE_EXTENSION.length);
1396
+ const lastDash = baseName.lastIndexOf("-");
1397
+ if (lastDash === -1) return null;
1398
+ const id = baseName.slice(0, lastDash);
1399
+ const version = baseName.slice(lastDash + 1);
1400
+ if (!id || !parseVersion(version)) return null;
1401
+ return { id, version };
1402
+ }
1403
+ function parsePromptYaml(content, promptId) {
1404
+ let parsed;
1405
+ try {
1406
+ parsed = yaml__namespace.parse(content);
1407
+ } catch (error) {
1408
+ throw new PromptInvalidFormatError(
1409
+ promptId,
1410
+ `Invalid YAML: ${toErrorMessage(error)}`,
1411
+ { cause: toErrorCause(error) }
1412
+ );
1413
+ }
1414
+ if (!parsed || typeof parsed !== "object") {
1415
+ throw new PromptInvalidFormatError(promptId, "Expected YAML object");
1416
+ }
1417
+ const obj = parsed;
1418
+ const requiredFields = ["id", "version", "system", "userTemplate"];
1419
+ for (const field of requiredFields) {
1420
+ if (typeof obj[field] !== "string") {
1421
+ throw new PromptInvalidFormatError(
1422
+ promptId,
1423
+ `Missing or invalid required field: ${field} (expected string)`
1424
+ );
1425
+ }
1426
+ }
1427
+ return {
1428
+ id: obj.id,
1429
+ version: obj.version,
1430
+ system: obj.system,
1431
+ userTemplate: obj.userTemplate
1432
+ };
1433
+ }
1434
+ function serializePromptYaml(content) {
1435
+ return yaml__namespace.stringify(content);
1436
+ }
1437
+ var FilePromptRepository = class {
1438
+ directory;
1439
+ fileSystem;
1440
+ cacheEnabled;
1441
+ contentCache = /* @__PURE__ */ new Map();
1442
+ constructor(options) {
1443
+ this.directory = options.directory;
1444
+ this.fileSystem = options.fs ?? defaultFileSystem;
1445
+ this.cacheEnabled = options.cache ?? true;
1446
+ }
1447
+ /**
1448
+ * Generates file name from prompt id and version.
1449
+ * Override this along with `parseFileName` to change file naming convention.
1450
+ */
1451
+ getFileName(id, version) {
1452
+ return getFileName(id, version);
1453
+ }
1454
+ /**
1455
+ * Parses file name into id and version.
1456
+ * Override this along with `getFileName` to change file naming convention.
1457
+ */
1458
+ parseFileName(fileName) {
1459
+ return parseFileName(fileName);
1460
+ }
1461
+ /**
1462
+ * Parses raw file content into PromptTemplateData.
1463
+ * Override this to support different file formats (e.g., JSON, TOML).
1464
+ */
1465
+ parseContent(content, promptId) {
1466
+ return parsePromptYaml(content, promptId);
1467
+ }
1468
+ /**
1469
+ * Serializes PromptTemplateData to file content string.
1470
+ * Override this to support different file formats (e.g., JSON, TOML).
1471
+ */
1472
+ serializeContent(content) {
1473
+ return serializePromptYaml(content);
1474
+ }
1475
+ getCacheKey(id, version) {
1476
+ return `${id}:${version}`;
1477
+ }
1478
+ async read(id, version) {
1479
+ if (version) {
1480
+ const cacheKey = this.getCacheKey(id, version);
1481
+ if (this.cacheEnabled) {
1482
+ const cached = this.contentCache.get(cacheKey);
1483
+ if (cached) {
1484
+ return cached;
1485
+ }
1486
+ }
1487
+ const fileName = this.getFileName(id, version);
1488
+ const filePath = path3__namespace.join(this.directory, fileName);
1489
+ let content;
1490
+ try {
1491
+ content = await this.fileSystem.readFile(filePath);
1492
+ } catch (error) {
1493
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
1494
+ throw new PromptNotFoundError(id, version);
1495
+ }
1496
+ throw new PromptIOError("read", filePath, { cause: toErrorCause(error) });
1497
+ }
1498
+ const promptContent = this.parseContent(content, id);
1499
+ if (promptContent.id !== id || promptContent.version !== version) {
1500
+ throw new PromptInvalidFormatError(
1501
+ id,
1502
+ `File content mismatch: expected id='${id}' version='${version}', got id='${promptContent.id}' version='${promptContent.version}'`
1503
+ );
1504
+ }
1505
+ if (this.cacheEnabled) {
1506
+ this.contentCache.set(cacheKey, promptContent);
1507
+ }
1508
+ return promptContent;
1509
+ }
1510
+ let files;
1511
+ try {
1512
+ files = await this.fileSystem.readdir(this.directory);
1513
+ } catch (error) {
1514
+ throw new PromptIOError("list", this.directory, { cause: toErrorCause(error) });
1515
+ }
1516
+ const versions = [];
1517
+ for (const file of files) {
1518
+ const parsed = this.parseFileName(file);
1519
+ if (parsed && parsed.id === id) {
1520
+ versions.push(parsed.version);
1521
+ }
1522
+ }
1523
+ if (versions.length === 0) {
1524
+ throw new PromptNotFoundError(id);
1525
+ }
1526
+ versions.sort((a, b) => compareVersions(b, a));
1527
+ const latestVersion = versions[0];
1528
+ return this.read(id, latestVersion);
1529
+ }
1530
+ async write(content) {
1531
+ if (this.cacheEnabled) {
1532
+ this.contentCache.delete(this.getCacheKey(content.id, content.version));
1533
+ }
1534
+ const fileName = this.getFileName(content.id, content.version);
1535
+ const filePath = path3__namespace.join(this.directory, fileName);
1536
+ if (!parseVersion(content.version)) {
1537
+ throw new PromptInvalidFormatError(
1538
+ content.id,
1539
+ `Invalid version format: '${content.version}' (expected semver like '1.0.0')`
1540
+ );
1541
+ }
1542
+ compileTemplate(content.system, content.id);
1543
+ compileTemplate(content.userTemplate, content.id);
1544
+ const yamlContent = this.serializeContent(content);
1545
+ try {
1546
+ await this.fileSystem.writeFile(filePath, yamlContent);
1547
+ } catch (error) {
1548
+ throw new PromptIOError("write", filePath, { cause: toErrorCause(error) });
1549
+ }
1550
+ }
1551
+ };
1552
+ function createFilePromptRepository(options) {
1553
+ return new FilePromptRepository(options);
1554
+ }
1555
+
1556
+ // src/provider/types.ts
1557
+ var FILE_SOURCE_TYPES = /* @__PURE__ */ new Set(["path", "data", "base64", "url"]);
1558
+ function isFileSource(v) {
1559
+ return typeof v === "object" && v !== null && FILE_SOURCE_TYPES.has(v.source);
1560
+ }
1561
+ function isFileSourcePath(v) {
1562
+ return v.source === "path";
1563
+ }
1564
+ function isFileSourceData(v) {
1565
+ return v.source === "data";
1566
+ }
1567
+ function isFileSourceBase64(v) {
1568
+ return v.source === "base64";
1569
+ }
1570
+ function isFileSourceUrl(v) {
1571
+ return v.source === "url";
1572
+ }
1573
+ async function computeFileSourceHash(source) {
1574
+ if (source.hash) {
1575
+ return source.hash;
1576
+ }
1577
+ const hash = crypto.createHash("sha256");
1578
+ switch (source.source) {
1579
+ case "path": {
1580
+ const fullPath = path3__namespace.default.isAbsolute(source.path) ? source.path : path3__namespace.default.resolve(process.cwd(), source.path);
1581
+ const content = await fs.readFile(fullPath);
1582
+ hash.update(content);
1583
+ break;
1584
+ }
1585
+ case "data": {
1586
+ hash.update(source.data);
1587
+ break;
1588
+ }
1589
+ case "base64": {
1590
+ const buffer = Buffer.from(source.data, "base64");
1591
+ hash.update(buffer);
1592
+ break;
1593
+ }
1594
+ case "url": {
1595
+ hash.update(source.url);
1596
+ break;
1597
+ }
1598
+ }
1599
+ return hash.digest("hex");
1600
+ }
1601
+
1602
+ // src/provider/file-cache.ts
1603
+ var InMemoryFileCache = class {
1604
+ cache = /* @__PURE__ */ new Map();
1605
+ defaultTTL;
1606
+ constructor(options) {
1607
+ this.defaultTTL = options?.defaultTTL;
1608
+ }
1609
+ get(hash) {
1610
+ const entry = this.cache.get(hash);
1611
+ if (!entry) return null;
1612
+ if (entry.expiresAt !== void 0 && Date.now() > entry.expiresAt) {
1613
+ this.cache.delete(hash);
1614
+ return null;
1615
+ }
1616
+ return entry.file;
1617
+ }
1618
+ set(hash, file, ttl) {
1619
+ const effectiveTTL = ttl ?? this.defaultTTL;
1620
+ const expiresAt = effectiveTTL !== void 0 ? Date.now() + effectiveTTL : void 0;
1621
+ this.cache.set(hash, { file, expiresAt });
1622
+ }
1623
+ delete(hash) {
1624
+ this.cache.delete(hash);
1625
+ }
1626
+ clear() {
1627
+ this.cache.clear();
1628
+ }
1629
+ };
1630
+
1631
+ // src/provider/base-provider.ts
1632
+ var BaseProvider = class {
1633
+ streamingExecution(generator, options) {
1634
+ return new StreamingExecutionHost(
1635
+ (signal) => this.createStreamingSession(signal),
1636
+ generator,
1637
+ options?.signal
1638
+ );
1639
+ }
1640
+ /**
1641
+ * Execute a non-streaming function with cancellation support.
1642
+ * Returns immediately - execution starts in the background.
1643
+ */
1644
+ simpleExecution(fn, options) {
1645
+ return new SimpleExecutionHost(
1646
+ (signal) => this.createSimpleSession(signal),
1647
+ fn,
1648
+ options?.signal
1649
+ );
1650
+ }
1651
+ };
1652
+
1653
+ // src/provider/noop-file-manager.ts
1654
+ var NoOpFileManager = class {
1655
+ upload(_files) {
1656
+ throw new FileError("File upload not supported by this provider", {
1657
+ code: "UNSUPPORTED_TYPE" /* UNSUPPORTED_TYPE */,
1658
+ context: {
1659
+ provider: "noop",
1660
+ suggestion: "Use a provider with file support (e.g., Google) or pass files inline"
1661
+ }
1662
+ });
1663
+ }
1664
+ delete(_fileId) {
1665
+ throw new FileError("File delete not supported by this provider", {
1666
+ code: "UNSUPPORTED_TYPE" /* UNSUPPORTED_TYPE */,
1667
+ context: {
1668
+ provider: "noop"
1669
+ }
1670
+ });
1671
+ }
1672
+ clear() {
1673
+ return Promise.resolve();
1674
+ }
1675
+ getUploadedFiles() {
1676
+ return [];
1677
+ }
1678
+ };
1679
+ var EXTENSION_TO_MIME = {
1680
+ ".pdf": "application/pdf",
1681
+ ".html": "text/html",
1682
+ ".htm": "text/html",
1683
+ ".txt": "text/plain",
1684
+ ".json": "application/json",
1685
+ ".xml": "application/xml",
1686
+ ".csv": "text/csv",
1687
+ ".png": "image/png",
1688
+ ".jpg": "image/jpeg",
1689
+ ".jpeg": "image/jpeg",
1690
+ ".gif": "image/gif",
1691
+ ".webp": "image/webp",
1692
+ ".svg": "image/svg+xml",
1693
+ ".bmp": "image/bmp",
1694
+ ".zip": "application/zip"
1695
+ };
1696
+ function inferMediaType(filePath) {
1697
+ const ext = path3__namespace.extname(filePath).toLowerCase();
1698
+ return EXTENSION_TO_MIME[ext];
1699
+ }
1700
+ function scanForFileSources(input, currentPath = []) {
1701
+ if (isFileSource(input)) {
1702
+ return [{ part: input, path: currentPath }];
1703
+ }
1704
+ if (input === null || typeof input !== "object") {
1705
+ return [];
1706
+ }
1707
+ if (Buffer.isBuffer(input) || input instanceof Uint8Array || input instanceof URL) {
1708
+ return [];
1709
+ }
1710
+ const results = [];
1711
+ if (Array.isArray(input)) {
1712
+ for (let i = 0; i < input.length; i++) {
1713
+ results.push(...scanForFileSources(input[i], [...currentPath, i]));
1714
+ }
1715
+ } else {
1716
+ for (const key of Object.keys(input)) {
1717
+ results.push(
1718
+ ...scanForFileSources(input[key], [
1719
+ ...currentPath,
1720
+ key
1721
+ ])
1722
+ );
1723
+ }
1724
+ }
1725
+ return results;
1726
+ }
1727
+ var DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
1728
+ async function resolveFileSource(part, options = {}) {
1729
+ const { basePath = process.cwd(), maxSize = DEFAULT_MAX_SIZE } = options;
1730
+ if (!isFileSourcePath(part)) {
1731
+ return part;
1732
+ }
1733
+ const fullPath = path3__namespace.isAbsolute(part.path) ? part.path : path3__namespace.resolve(basePath, part.path);
1734
+ const stats = await fs.stat(fullPath).catch((err) => {
1735
+ throw new FileError(`File not found: ${part.path}`, {
1736
+ code: "NOT_FOUND" /* NOT_FOUND */,
1737
+ context: { path: part.path, fullPath },
1738
+ cause: err
1739
+ });
1740
+ });
1741
+ if (stats.size > maxSize) {
1742
+ throw new FileError(`File too large: ${stats.size} bytes > ${maxSize} bytes`, {
1743
+ code: "TOO_LARGE" /* TOO_LARGE */,
1744
+ context: { path: part.path, size: stats.size, maxSize }
1745
+ });
1746
+ }
1747
+ const buffer = await fs.readFile(fullPath);
1748
+ const mediaType = part.mediaType ?? inferMediaType(part.path) ?? "application/octet-stream";
1749
+ const filename = part.filename ?? path3__namespace.basename(part.path);
1750
+ const result = {
1751
+ source: "data",
1752
+ data: buffer,
1753
+ mediaType,
1754
+ filename
1755
+ };
1756
+ return result;
1757
+ }
1758
+ function deepClone(value) {
1759
+ if (value === null || typeof value !== "object") return value;
1760
+ if (Buffer.isBuffer(value)) return Buffer.from(value);
1761
+ if (value instanceof URL) return new URL(value.href);
1762
+ if (value instanceof Uint8Array) return new Uint8Array(value);
1763
+ if (Array.isArray(value)) return value.map(deepClone);
1764
+ const result = {};
1765
+ for (const key of Object.keys(value)) {
1766
+ result[key] = deepClone(value[key]);
1767
+ }
1768
+ return result;
1769
+ }
1770
+ function setAtPath(obj, targetPath, value) {
1771
+ if (targetPath.length === 0) {
1772
+ return value;
1773
+ }
1774
+ let current = obj;
1775
+ for (let i = 0; i < targetPath.length - 1; i++) {
1776
+ current = current[targetPath[i]];
1777
+ }
1778
+ current[targetPath[targetPath.length - 1]] = value;
1779
+ return obj;
1780
+ }
1781
+ async function resolveFileSourcesInInput(input, options = {}) {
1782
+ const found = scanForFileSources(input);
1783
+ if (found.length === 0) {
1784
+ return input;
1785
+ }
1786
+ const resolved = await Promise.all(found.map(({ part }) => resolveFileSource(part, options)));
1787
+ if (found.length === 1 && found[0].path.length === 0) {
1788
+ return resolved[0];
1789
+ }
1790
+ const result = deepClone(input);
1791
+ for (let i = 0; i < found.length; i++) {
1792
+ setAtPath(result, found[i].path, resolved[i]);
1793
+ }
1794
+ return result;
1795
+ }
1796
+ function getFileSourceDisplayInfo(part) {
1797
+ switch (part.source) {
1798
+ case "path":
1799
+ return {
1800
+ source: "path",
1801
+ description: part.path,
1802
+ mediaType: part.mediaType ?? inferMediaType(part.path) ?? "unknown",
1803
+ filename: part.filename ?? path3__namespace.basename(part.path)
1804
+ };
1805
+ case "url":
1806
+ return {
1807
+ source: "url",
1808
+ description: part.url,
1809
+ mediaType: part.mediaType ?? "unknown",
1810
+ filename: part.filename
1811
+ };
1812
+ case "base64": {
1813
+ const sizeKB = (part.data.length * 3 / 4 / 1024).toFixed(1);
1814
+ return {
1815
+ source: "base64",
1816
+ description: `[base64 data, ~${sizeKB}KB]`,
1817
+ mediaType: part.mediaType,
1818
+ filename: part.filename
1819
+ };
1820
+ }
1821
+ case "data": {
1822
+ const size = Buffer.isBuffer(part.data) ? part.data.length : part.data.length;
1823
+ const sizeKB = (size / 1024).toFixed(1);
1824
+ return {
1825
+ source: "data",
1826
+ description: `[Buffer, ${sizeKB}KB]`,
1827
+ mediaType: part.mediaType,
1828
+ filename: part.filename
1829
+ };
1830
+ }
1831
+ }
1832
+ }
1833
+ function getFileSourcesDisplayInfo(input) {
1834
+ const found = scanForFileSources(input);
1835
+ return found.map(({ part }) => getFileSourceDisplayInfo(part));
1836
+ }
1837
+ function assertValidUploadResponse(response, context) {
1838
+ if (!response.name || !response.uri || !response.mimeType) {
1839
+ throw new FileError("Invalid upload response from Google API: missing required fields", {
1840
+ code: "UPLOAD_ERROR" /* UPLOAD_ERROR */,
1841
+ context: {
1842
+ ...context,
1843
+ hasName: !!response.name,
1844
+ hasUri: !!response.uri,
1845
+ hasMediaType: !!response.mimeType
1846
+ }
1847
+ });
1848
+ }
1849
+ }
1850
+ function isImageMediaType(mediaType) {
1851
+ return mediaType.startsWith("image/");
1852
+ }
1853
+ function createPart(uri, mediaType) {
1854
+ const url = new URL(uri);
1855
+ if (isImageMediaType(mediaType)) {
1856
+ return { type: "image", image: url, mediaType };
1857
+ }
1858
+ return { type: "file", data: url, mediaType };
1859
+ }
1860
+ var GoogleFileManager = class {
1861
+ uploadedFiles = [];
1862
+ client;
1863
+ cache;
1864
+ constructor(apiKey, options) {
1865
+ this.client = new genai.GoogleGenAI({ apiKey });
1866
+ this.cache = options?.cache ?? null;
1867
+ }
1868
+ async uploadOne(fileSource, index, hash) {
1869
+ if (this.cache) {
1870
+ const cached = this.cache.get(hash);
1871
+ if (cached) return cached;
1872
+ }
1873
+ if (fileSource.source === "url") {
1874
+ const mediaType = fileSource.mediaType ?? "application/octet-stream";
1875
+ const result = {
1876
+ id: null,
1877
+ part: createPart(fileSource.url, mediaType)
1878
+ };
1879
+ if (this.cache) {
1880
+ this.cache.set(hash, result);
1881
+ }
1882
+ return result;
1883
+ }
1884
+ if (fileSource.source === "path") {
1885
+ const fullPath = path3__namespace.default.isAbsolute(fileSource.path) ? fileSource.path : path3__namespace.default.resolve(process.cwd(), fileSource.path);
1886
+ try {
1887
+ const uploaded = await this.client.files.upload({
1888
+ file: fullPath,
1889
+ config: {
1890
+ mimeType: fileSource.mediaType,
1891
+ displayName: fileSource.filename ?? path3__namespace.default.basename(fileSource.path)
1892
+ }
1893
+ });
1894
+ assertValidUploadResponse(uploaded, {
1895
+ source: "path",
1896
+ path: fileSource.path
1897
+ });
1898
+ const result = {
1899
+ id: uploaded.name,
1900
+ part: createPart(uploaded.uri, uploaded.mimeType)
1901
+ };
1902
+ if (this.cache) {
1903
+ this.cache.set(hash, result);
1904
+ }
1905
+ return result;
1906
+ } catch (error) {
1907
+ if (error instanceof FileError) throw error;
1908
+ throw FileError.from(error, "UPLOAD_ERROR" /* UPLOAD_ERROR */, {
1909
+ source: "path",
1910
+ path: fileSource.path,
1911
+ mediaType: fileSource.mediaType
1912
+ });
1913
+ }
1914
+ }
1915
+ const buffer = fileSource.source === "base64" ? Buffer.from(fileSource.data, "base64") : fileSource.data;
1916
+ const arrayBuffer = buffer.buffer.slice(
1917
+ buffer.byteOffset,
1918
+ buffer.byteOffset + buffer.byteLength
1919
+ );
1920
+ const blob = new Blob([arrayBuffer], { type: fileSource.mediaType });
1921
+ try {
1922
+ const uploaded = await this.client.files.upload({
1923
+ file: blob,
1924
+ config: {
1925
+ mimeType: fileSource.mediaType,
1926
+ displayName: fileSource.filename ?? `upload-${Date.now()}-${index}`
1927
+ }
1928
+ });
1929
+ assertValidUploadResponse(uploaded, {
1930
+ source: fileSource.source,
1931
+ mediaType: fileSource.mediaType
1932
+ });
1933
+ const result = {
1934
+ id: uploaded.name,
1935
+ part: createPart(uploaded.uri, uploaded.mimeType)
1936
+ };
1937
+ if (this.cache) {
1938
+ this.cache.set(hash, result);
1939
+ }
1940
+ return result;
1941
+ } catch (error) {
1942
+ if (error instanceof FileError) throw error;
1943
+ throw FileError.from(error, "UPLOAD_ERROR" /* UPLOAD_ERROR */, {
1944
+ source: fileSource.source,
1945
+ mediaType: fileSource.mediaType,
1946
+ filename: fileSource.filename
1947
+ });
1948
+ }
1949
+ }
1950
+ async upload(files) {
1951
+ const hashes = await Promise.all(files.map((file) => computeFileSourceHash(file)));
1952
+ const results = await Promise.allSettled(
1953
+ files.map((file, i) => this.uploadOne(file, i, hashes[i]))
1954
+ );
1955
+ const successful = [];
1956
+ const failed = [];
1957
+ for (let i = 0; i < results.length; i++) {
1958
+ const result = results[i];
1959
+ if (result.status === "fulfilled") {
1960
+ successful.push({ file: result.value, hash: hashes[i] });
1961
+ } else {
1962
+ failed.push(result);
1963
+ }
1964
+ }
1965
+ if (failed.length > 0) {
1966
+ await Promise.all(
1967
+ successful.filter(({ file }) => file.id !== null).map(async ({ file, hash }) => {
1968
+ await this.client.files.delete({ name: file.id }).catch(() => {
1969
+ });
1970
+ if (this.cache) {
1971
+ this.cache.delete(hash);
1972
+ }
1973
+ })
1974
+ );
1975
+ const firstError = failed[0].reason;
1976
+ throw new FileError(
1977
+ `Failed to upload ${failed.length} file(s): ${firstError instanceof Error ? firstError.message : String(firstError)}`,
1978
+ {
1979
+ code: "UPLOAD_ERROR" /* UPLOAD_ERROR */,
1980
+ cause: firstError instanceof Error ? firstError : void 0,
1981
+ context: {
1982
+ totalFiles: files.length,
1983
+ failedCount: failed.length,
1984
+ successCount: successful.length
1985
+ }
1986
+ }
1987
+ );
1988
+ }
1989
+ this.uploadedFiles.push(...successful.filter(({ file }) => file.id !== null).map(({ file }) => file));
1990
+ return successful.map(({ file }) => file);
1991
+ }
1992
+ async delete(fileId) {
1993
+ try {
1994
+ await this.client.files.delete({ name: fileId });
1995
+ this.uploadedFiles = this.uploadedFiles.filter((f) => f.id !== fileId);
1996
+ } catch (error) {
1997
+ throw FileError.from(error, "DELETE_ERROR" /* DELETE_ERROR */, {
1998
+ fileId
1999
+ });
2000
+ }
2001
+ }
2002
+ async clear() {
2003
+ await Promise.all(
2004
+ this.uploadedFiles.filter((f) => f.id !== null).map((f) => this.delete(f.id).catch(() => {
2005
+ }))
2006
+ );
2007
+ this.uploadedFiles = [];
2008
+ }
2009
+ getUploadedFiles() {
2010
+ return [...this.uploadedFiles];
2011
+ }
2012
+ };
2013
+
2014
+ // src/session/usage-extractors.ts
2015
+ function mergeUsages(usages) {
2016
+ if (usages.length === 0) {
2017
+ return createZeroUsage();
2018
+ }
2019
+ let inputTokens = 0;
2020
+ let outputTokens = 0;
2021
+ let totalTokens = 0;
2022
+ let noCacheTokens = 0;
2023
+ let cacheReadTokens = 0;
2024
+ let cacheWriteTokens = 0;
2025
+ let textTokens = 0;
2026
+ let reasoningTokens = 0;
2027
+ for (const usage of usages) {
2028
+ inputTokens += usage.inputTokens ?? 0;
2029
+ outputTokens += usage.outputTokens ?? 0;
2030
+ totalTokens += usage.totalTokens ?? 0;
2031
+ noCacheTokens += usage.inputTokenDetails?.noCacheTokens ?? 0;
2032
+ cacheReadTokens += usage.inputTokenDetails?.cacheReadTokens ?? 0;
2033
+ cacheWriteTokens += usage.inputTokenDetails?.cacheWriteTokens ?? 0;
2034
+ textTokens += usage.outputTokenDetails?.textTokens ?? 0;
2035
+ reasoningTokens += usage.outputTokenDetails?.reasoningTokens ?? 0;
2036
+ }
2037
+ return {
2038
+ inputTokens,
2039
+ outputTokens,
2040
+ totalTokens,
2041
+ inputTokenDetails: {
2042
+ noCacheTokens,
2043
+ cacheReadTokens,
2044
+ cacheWriteTokens
2045
+ },
2046
+ outputTokenDetails: {
2047
+ textTokens,
2048
+ reasoningTokens
2049
+ }
2050
+ };
2051
+ }
2052
+ function createZeroUsage() {
2053
+ return {
2054
+ inputTokens: 0,
2055
+ outputTokens: 0,
2056
+ totalTokens: 0,
2057
+ inputTokenDetails: {
2058
+ noCacheTokens: 0,
2059
+ cacheReadTokens: 0,
2060
+ cacheWriteTokens: 0
2061
+ },
2062
+ outputTokenDetails: {
2063
+ textTokens: 0,
2064
+ reasoningTokens: 0
2065
+ }
2066
+ };
2067
+ }
2068
+ function detectProviderType(modelId) {
2069
+ const lowerModel = modelId.toLowerCase();
2070
+ if (lowerModel.startsWith("gpt-") || lowerModel === "o1" || lowerModel.startsWith("o1-") || lowerModel === "o3" || lowerModel.startsWith("o3-")) {
2071
+ return "openai";
2072
+ }
2073
+ if (lowerModel.startsWith("gemini")) {
2074
+ return "google";
2075
+ }
2076
+ if (lowerModel.startsWith("claude")) {
2077
+ return "anthropic";
2078
+ }
2079
+ return void 0;
2080
+ }
2081
+
2082
+ // src/session/types.ts
2083
+ var SessionSummary = class _SessionSummary {
2084
+ totalLLMUsage;
2085
+ llmCallCount;
2086
+ llmCalls;
2087
+ toolCalls;
2088
+ customRecords;
2089
+ llmCost;
2090
+ additionalCosts;
2091
+ metadata;
2092
+ /** Cost breakdown by model. Key format: `${provider}/${model}` */
2093
+ costByModel;
2094
+ startTime;
2095
+ constructor(data, startTime) {
2096
+ this.startTime = startTime;
2097
+ this.totalLLMUsage = data.totalLLMUsage;
2098
+ this.llmCallCount = data.llmCalls.length;
2099
+ this.llmCalls = Object.freeze([...data.llmCalls]);
2100
+ this.toolCalls = Object.freeze([...data.toolCalls]);
2101
+ this.customRecords = Object.freeze([...data.customRecords]);
2102
+ this.llmCost = data.llmCost;
2103
+ this.additionalCosts = Object.freeze([...data.additionalCosts]);
2104
+ this.metadata = Object.freeze({ ...data.metadata });
2105
+ this.costByModel = Object.freeze({ ...data.costByModel });
2106
+ }
2107
+ /**
2108
+ * Total duration from session start to now (computed dynamically).
2109
+ */
2110
+ get totalDuration() {
2111
+ return Date.now() - this.startTime;
2112
+ }
2113
+ /**
2114
+ * Creates an empty SessionSummary.
2115
+ */
2116
+ static empty(startTime) {
2117
+ return new _SessionSummary(
2118
+ {
2119
+ totalLLMUsage: createZeroUsage(),
2120
+ llmCalls: [],
2121
+ toolCalls: [],
2122
+ customRecords: [],
2123
+ llmCost: 0,
2124
+ additionalCosts: [],
2125
+ metadata: {},
2126
+ costByModel: {}
2127
+ },
2128
+ startTime
2129
+ );
2130
+ }
2131
+ /**
2132
+ * Creates a SessionSummary with custom data for testing purposes.
2133
+ * @internal For testing only - do not use in production code.
2134
+ */
2135
+ static forTest(data) {
2136
+ const startTime = data.startTime ?? Date.now() - 1e3;
2137
+ return new _SessionSummary(
2138
+ {
2139
+ totalLLMUsage: data.totalLLMUsage ?? createZeroUsage(),
2140
+ llmCalls: data.llmCalls ?? [],
2141
+ toolCalls: data.toolCalls ?? [],
2142
+ customRecords: data.customRecords ?? [],
2143
+ llmCost: data.llmCost ?? 0,
2144
+ additionalCosts: data.additionalCosts ?? [],
2145
+ metadata: data.metadata ?? {},
2146
+ costByModel: data.costByModel ?? {}
2147
+ },
2148
+ startTime
2149
+ );
2150
+ }
2151
+ /**
2152
+ * Total cost of all additional (non-LLM) operations.
2153
+ */
2154
+ get totalAdditionalCost() {
2155
+ return this.additionalCosts.reduce((sum, c) => sum + c.cost, 0);
2156
+ }
2157
+ /**
2158
+ * Total cost including LLM and additional costs.
2159
+ */
2160
+ get totalCost() {
2161
+ return this.llmCost + this.totalAdditionalCost;
2162
+ }
2163
+ /**
2164
+ * Returns a new SessionSummary with an LLM call added.
2165
+ */
2166
+ withLLMCall(call, newLlmCost, newCostByModel, newTotalUsage) {
2167
+ return new _SessionSummary(
2168
+ {
2169
+ totalLLMUsage: newTotalUsage,
2170
+ llmCalls: [...this.llmCalls, call],
2171
+ toolCalls: [...this.toolCalls],
2172
+ customRecords: [...this.customRecords],
2173
+ llmCost: newLlmCost,
2174
+ additionalCosts: [...this.additionalCosts],
2175
+ metadata: { ...this.metadata },
2176
+ costByModel: newCostByModel
2177
+ },
2178
+ this.startTime
2179
+ );
2180
+ }
2181
+ /**
2182
+ * Returns a new SessionSummary with an additional cost recorded.
2183
+ */
2184
+ withAdditionalCost(cost) {
2185
+ return new _SessionSummary(
2186
+ {
2187
+ totalLLMUsage: this.totalLLMUsage,
2188
+ llmCalls: [...this.llmCalls],
2189
+ toolCalls: [...this.toolCalls],
2190
+ customRecords: [...this.customRecords],
2191
+ llmCost: this.llmCost,
2192
+ additionalCosts: [...this.additionalCosts, cost],
2193
+ metadata: { ...this.metadata },
2194
+ costByModel: { ...this.costByModel }
2195
+ },
2196
+ this.startTime
2197
+ );
2198
+ }
2199
+ /**
2200
+ * Returns a new SessionSummary with metadata updated.
2201
+ */
2202
+ withMetadata(key, value) {
2203
+ return new _SessionSummary(
2204
+ {
2205
+ totalLLMUsage: this.totalLLMUsage,
2206
+ llmCalls: [...this.llmCalls],
2207
+ toolCalls: [...this.toolCalls],
2208
+ customRecords: [...this.customRecords],
2209
+ llmCost: this.llmCost,
2210
+ additionalCosts: [...this.additionalCosts],
2211
+ metadata: { ...this.metadata, [key]: value },
2212
+ costByModel: { ...this.costByModel }
2213
+ },
2214
+ this.startTime
2215
+ );
2216
+ }
2217
+ /**
2218
+ * Returns a new SessionSummary with a tool call added.
2219
+ */
2220
+ withToolCall(call) {
2221
+ return new _SessionSummary(
2222
+ {
2223
+ totalLLMUsage: this.totalLLMUsage,
2224
+ llmCalls: [...this.llmCalls],
2225
+ toolCalls: [...this.toolCalls, call],
2226
+ customRecords: [...this.customRecords],
2227
+ llmCost: this.llmCost,
2228
+ additionalCosts: [...this.additionalCosts],
2229
+ metadata: { ...this.metadata },
2230
+ costByModel: { ...this.costByModel }
2231
+ },
2232
+ this.startTime
2233
+ );
2234
+ }
2235
+ /**
2236
+ * Returns a new SessionSummary with a custom record added.
2237
+ */
2238
+ withCustomRecord(record) {
2239
+ return new _SessionSummary(
2240
+ {
2241
+ totalLLMUsage: this.totalLLMUsage,
2242
+ llmCalls: [...this.llmCalls],
2243
+ toolCalls: [...this.toolCalls],
2244
+ customRecords: [...this.customRecords, record],
2245
+ llmCost: this.llmCost,
2246
+ additionalCosts: [...this.additionalCosts],
2247
+ metadata: { ...this.metadata },
2248
+ costByModel: { ...this.costByModel }
2249
+ },
2250
+ this.startTime
2251
+ );
2252
+ }
2253
+ /**
2254
+ * Serializes to plain JSON object for database storage.
2255
+ */
2256
+ toJSON() {
2257
+ return {
2258
+ totalDuration: this.totalDuration,
2259
+ totalLLMUsage: this.totalLLMUsage,
2260
+ llmCallCount: this.llmCallCount,
2261
+ llmCalls: [...this.llmCalls],
2262
+ toolCalls: [...this.toolCalls],
2263
+ customRecords: [...this.customRecords],
2264
+ llmCost: this.llmCost,
2265
+ additionalCosts: [...this.additionalCosts],
2266
+ metadata: { ...this.metadata },
2267
+ costByModel: { ...this.costByModel },
2268
+ totalCost: this.totalCost,
2269
+ totalAdditionalCost: this.totalAdditionalCost
2270
+ };
2271
+ }
2272
+ };
2273
+
2274
+ // src/session/simple-session.ts
2275
+ var SimpleSession = class {
2276
+ defaultLanguageModel;
2277
+ modelFactory;
2278
+ providerType;
2279
+ providerPricing;
2280
+ defaultProviderOptions;
2281
+ defaultTools;
2282
+ _fileManager;
2283
+ logger;
2284
+ sessionStartTime;
2285
+ signal;
2286
+ summary;
2287
+ pendingUsagePromises = [];
2288
+ onDoneFns = [];
2289
+ constructor(options) {
2290
+ this.defaultLanguageModel = options.defaultLanguageModel ?? null;
2291
+ this.modelFactory = options.modelFactory ?? null;
2292
+ this.providerType = options.providerType;
2293
+ this.providerPricing = options.providerPricing;
2294
+ this.defaultProviderOptions = options.defaultProviderOptions;
2295
+ this.defaultTools = options.defaultTools;
2296
+ this._fileManager = options.fileManager;
2297
+ this.logger = options.logger ?? noopLogger;
2298
+ this.sessionStartTime = options.startTime ?? Date.now();
2299
+ this.signal = options.signal;
2300
+ this.summary = SessionSummary.empty(this.sessionStartTime);
2301
+ }
2302
+ getModel(requestedModelId) {
2303
+ if (requestedModelId) {
2304
+ if (!this.modelFactory) {
2305
+ throw new Error(
2306
+ `Model '${requestedModelId}' requested but no modelFactory provided. Either use the default model or configure the provider with modelFactory.`
2307
+ );
2308
+ }
2309
+ return this.modelFactory(requestedModelId);
2310
+ }
2311
+ if (!this.defaultLanguageModel) {
2312
+ throw new Error(
2313
+ "No model specified and no default model set. Either specify a model in the call or configure the provider with withDefaultModel()."
2314
+ );
2315
+ }
2316
+ return this.defaultLanguageModel;
2317
+ }
2318
+ extractModelId(model) {
2319
+ const modelWithId = model;
2320
+ if (!modelWithId.modelId) {
2321
+ console.warn(
2322
+ '[SimpleSession] Model does not have modelId property, using "unknown". This may affect cost tracking accuracy.'
2323
+ );
2324
+ }
2325
+ return modelWithId.modelId ?? "unknown";
2326
+ }
2327
+ async generateText(params) {
2328
+ const callStartTime = Date.now();
2329
+ const { model: requestedModel, providerOptions, tools, ...restParams } = params;
2330
+ const languageModel = this.getModel(requestedModel);
2331
+ const modelId = this.extractModelId(languageModel);
2332
+ const mergedProviderOptions = this.defaultProviderOptions || providerOptions ? merge__default.default({}, this.defaultProviderOptions ?? {}, providerOptions ?? {}) : void 0;
2333
+ const mergedTools = this.defaultTools || tools ? { ...this.defaultTools, ...tools } : void 0;
2334
+ this.logger.onLLMCallStart?.({
2335
+ type: "llm_call_start",
2336
+ callType: "generateText",
2337
+ modelId,
2338
+ timestamp: callStartTime,
2339
+ request: { params: restParams }
2340
+ });
2341
+ try {
2342
+ const result = await ai.generateText({
2343
+ ...restParams,
2344
+ tools: mergedTools,
2345
+ providerOptions: mergedProviderOptions,
2346
+ model: languageModel,
2347
+ abortSignal: this.signal
2348
+ });
2349
+ const callEndTime = Date.now();
2350
+ const call = {
2351
+ startTime: callStartTime,
2352
+ endTime: callEndTime,
2353
+ duration: callEndTime - callStartTime,
2354
+ usage: result.usage ?? createZeroUsage(),
2355
+ type: "generateText",
2356
+ model: modelId,
2357
+ provider: this.providerType
2358
+ };
2359
+ this.updateSummaryWithLLMCall(call);
2360
+ this.logger.onLLMCallEnd?.({
2361
+ type: "llm_call_end",
2362
+ callType: "generateText",
2363
+ modelId,
2364
+ timestamp: callEndTime,
2365
+ response: {
2366
+ duration: callEndTime - callStartTime,
2367
+ usage: result.usage,
2368
+ raw: result
2369
+ }
2370
+ });
2371
+ return result;
2372
+ } catch (error) {
2373
+ const callEndTime = Date.now();
2374
+ this.logger.onLLMCallEnd?.({
2375
+ type: "llm_call_end",
2376
+ callType: "generateText",
2377
+ modelId,
2378
+ timestamp: callEndTime,
2379
+ response: {
2380
+ duration: callEndTime - callStartTime,
2381
+ raw: null,
2382
+ error: error instanceof Error ? error : new Error(String(error))
2383
+ }
2384
+ });
2385
+ throw error;
2386
+ }
2387
+ }
2388
+ streamText(params) {
2389
+ const callStartTime = Date.now();
2390
+ const { model: requestedModel, providerOptions, tools, ...restParams } = params;
2391
+ const languageModel = this.getModel(requestedModel);
2392
+ const modelId = this.extractModelId(languageModel);
2393
+ const mergedProviderOptions = this.defaultProviderOptions || providerOptions ? merge__default.default({}, this.defaultProviderOptions ?? {}, providerOptions ?? {}) : void 0;
2394
+ const mergedTools = this.defaultTools || tools ? { ...this.defaultTools, ...tools } : void 0;
2395
+ this.logger.onLLMCallStart?.({
2396
+ type: "llm_call_start",
2397
+ callType: "streamText",
2398
+ modelId,
2399
+ timestamp: callStartTime,
2400
+ request: { params: restParams }
2401
+ });
2402
+ const result = ai.streamText({
2403
+ ...restParams,
2404
+ tools: mergedTools,
2405
+ providerOptions: mergedProviderOptions,
2406
+ model: languageModel,
2407
+ abortSignal: this.signal
2408
+ });
2409
+ const usagePromise = Promise.resolve(result.usage).then((usage) => {
2410
+ const callEndTime = Date.now();
2411
+ const call = {
2412
+ startTime: callStartTime,
2413
+ endTime: callEndTime,
2414
+ duration: callEndTime - callStartTime,
2415
+ usage: usage ?? createZeroUsage(),
2416
+ type: "streamText",
2417
+ model: modelId,
2418
+ provider: this.providerType
2419
+ };
2420
+ this.updateSummaryWithLLMCall(call);
2421
+ this.logger.onLLMCallEnd?.({
2422
+ type: "llm_call_end",
2423
+ callType: "streamText",
2424
+ modelId,
2425
+ timestamp: callEndTime,
2426
+ response: {
2427
+ duration: callEndTime - callStartTime,
2428
+ usage,
2429
+ raw: result
2430
+ }
2431
+ });
2432
+ return usage;
2433
+ });
2434
+ this.pendingUsagePromises.push(usagePromise);
2435
+ return result;
2436
+ }
2437
+ get fileManager() {
2438
+ return this._fileManager;
2439
+ }
2440
+ record(data) {
2441
+ this.summary = this.summary.withCustomRecord(data);
2442
+ }
2443
+ recordToolCall(toolCallSummary) {
2444
+ this.summary = this.summary.withToolCall(toolCallSummary);
2445
+ }
2446
+ recordLLMCall(record) {
2447
+ const call = {
2448
+ ...record,
2449
+ type: record.type ?? "manual"
2450
+ };
2451
+ this.updateSummaryWithLLMCall(call);
2452
+ }
2453
+ recordAdditionalCost(cost) {
2454
+ this.summary = this.summary.withAdditionalCost({
2455
+ ...cost,
2456
+ timestamp: Date.now()
2457
+ });
2458
+ }
2459
+ setMetadata(keyOrData, value) {
2460
+ if (typeof keyOrData === "string") {
2461
+ this.summary = this.summary.withMetadata(keyOrData, value);
2462
+ } else {
2463
+ for (const [k, v] of Object.entries(keyOrData)) {
2464
+ this.summary = this.summary.withMetadata(k, v);
2465
+ }
2466
+ }
2467
+ }
2468
+ updateSummaryWithLLMCall(call) {
2469
+ const newCalls = [...this.summary.llmCalls, call];
2470
+ const { totalCost: llmCost, costByModel } = calculateTotalCost(
2471
+ newCalls.map((c) => ({ usage: c.usage, model: c.model, provider: c.provider })),
2472
+ this.providerPricing
2473
+ );
2474
+ const newTotalUsage = mergeUsages(newCalls.map((c) => c.usage));
2475
+ this.summary = this.summary.withLLMCall(call, llmCost, costByModel, newTotalUsage);
2476
+ }
2477
+ onDone(fn) {
2478
+ this.onDoneFns.push(fn);
2479
+ }
2480
+ async runOnDoneHooks() {
2481
+ const reversedHooks = [...this.onDoneFns].reverse();
2482
+ for (const fn of reversedHooks) {
2483
+ try {
2484
+ await fn();
2485
+ } catch (error) {
2486
+ console.error("[SimpleSession] onDone hook error:", error);
2487
+ }
2488
+ }
2489
+ }
2490
+ async getSummary() {
2491
+ await Promise.all(this.pendingUsagePromises);
2492
+ return this.summary;
2493
+ }
2494
+ /**
2495
+ * Notifies Logger of execution start.
2496
+ * @internal Called by SimpleExecutionHost - not intended for direct use.
2497
+ */
2498
+ notifyExecutionStart() {
2499
+ this._logger.onExecutionStart?.({
2500
+ type: "execution_start",
2501
+ timestamp: Date.now()
2502
+ });
2503
+ }
2504
+ /**
2505
+ * Notifies Logger of execution completion with result data and summary.
2506
+ * @param data - The execution result data
2507
+ * @param startTime - Execution start timestamp for duration calculation
2508
+ * @internal Called by SimpleExecutionHost - not intended for direct use.
2509
+ */
2510
+ async notifyExecutionDone(data, startTime) {
2511
+ const summary = await this.getSummary();
2512
+ this._logger.onExecutionDone?.({
2513
+ type: "execution_done",
2514
+ timestamp: Date.now(),
2515
+ duration: Date.now() - startTime,
2516
+ data,
2517
+ summary
2518
+ });
2519
+ }
2520
+ /**
2521
+ * Notifies Logger of execution error with error details and summary (if available).
2522
+ * Gracefully handles getSummary() failures - summary will be undefined if it fails.
2523
+ * @param error - The error that occurred
2524
+ * @param startTime - Execution start timestamp for duration calculation
2525
+ * @internal Called by SimpleExecutionHost - not intended for direct use.
2526
+ */
2527
+ async notifyExecutionError(error, startTime) {
2528
+ let summary;
2529
+ try {
2530
+ summary = await this.getSummary();
2531
+ } catch {
2532
+ }
2533
+ this._logger.onExecutionError?.({
2534
+ type: "execution_error",
2535
+ timestamp: Date.now(),
2536
+ duration: Date.now() - startTime,
2537
+ error,
2538
+ summary
2539
+ });
2540
+ }
2541
+ get _logger() {
2542
+ return this.logger;
2543
+ }
2544
+ get _startTime() {
2545
+ return this.sessionStartTime;
2546
+ }
2547
+ get _modelId() {
2548
+ if (!this.defaultLanguageModel) {
2549
+ return "unknown";
2550
+ }
2551
+ return this.extractModelId(this.defaultLanguageModel);
2552
+ }
2553
+ };
2554
+
2555
+ // src/session/streaming-session.ts
2556
+ var StreamingSession = class extends SimpleSession {
2557
+ lastEventTime;
2558
+ _terminated = false;
2559
+ constructor(options) {
2560
+ super({
2561
+ defaultLanguageModel: options.defaultLanguageModel,
2562
+ modelFactory: options.modelFactory,
2563
+ providerType: options.providerType,
2564
+ providerPricing: options.providerPricing,
2565
+ fileManager: options.fileManager,
2566
+ logger: options.logger,
2567
+ startTime: options.startTime,
2568
+ signal: options.signal,
2569
+ defaultProviderOptions: options.defaultProviderOptions,
2570
+ defaultTools: options.defaultTools
2571
+ });
2572
+ this.lastEventTime = this._startTime;
2573
+ this._logger.onExecutionStart?.({
2574
+ type: "execution_start",
2575
+ timestamp: Date.now()
2576
+ });
2577
+ }
2578
+ /**
2579
+ * Emits a streaming event with automatically attached metrics.
2580
+ *
2581
+ * Reserved types ('complete', 'error') throw at runtime - use session.done()
2582
+ * or session.fail() instead.
2583
+ *
2584
+ * @param event - The event to emit (metrics will be added automatically)
2585
+ * @returns The complete event with metrics attached
2586
+ * @throws Error when attempting to emit reserved types ('complete', 'error')
2587
+ */
2588
+ emit(event) {
2589
+ if (this._terminated) {
2590
+ throw new Error("Session already terminated. Cannot call emit() after a terminal operation.");
2591
+ }
2592
+ const eventType = event.type;
2593
+ if (eventType === "complete" || eventType === "error") {
2594
+ throw new Error(
2595
+ `Cannot emit reserved type "${eventType}". Use session.done() for completion or session.fail() for errors.`
2596
+ );
2597
+ }
2598
+ return this.emitInternal(event);
2599
+ }
2600
+ /**
2601
+ * Internal emit method - bypasses reserved type check.
2602
+ * Used by done() and fail() to emit terminal events.
2603
+ */
2604
+ emitInternal(event) {
2605
+ const metrics = this.createMetrics();
2606
+ const fullEvent = { ...event, metrics };
2607
+ this._logger.onExecutionEmit?.({
2608
+ type: "execution_emit",
2609
+ event: fullEvent
2610
+ });
2611
+ return fullEvent;
2612
+ }
2613
+ /**
2614
+ * Signals successful completion of the streaming execution.
2615
+ * Emits a 'complete' event with the result data and session summary.
2616
+ * Also triggers Logger.onExecutionDone for observability.
2617
+ * @param data - The final result data
2618
+ * @returns The complete event with data and summary
2619
+ */
2620
+ async done(data) {
2621
+ if (this._terminated) {
2622
+ throw new Error("Session already terminated. Cannot call done() after a terminal operation.");
2623
+ }
2624
+ this._terminated = true;
2625
+ const summary = await this.getSummary();
2626
+ this._logger.onExecutionDone?.({
2627
+ type: "execution_done",
2628
+ timestamp: Date.now(),
2629
+ duration: summary.totalDuration,
2630
+ data,
2631
+ summary
2632
+ });
2633
+ return this.emitInternal({
2634
+ type: "complete",
2635
+ data,
2636
+ summary
2637
+ });
2638
+ }
2639
+ /**
2640
+ * Signals that the streaming execution failed with an error.
2641
+ * Emits an 'error' event and triggers Logger.onExecutionError for observability.
2642
+ * Gracefully handles getSummary() failures - summary will be undefined if it fails.
2643
+ * @param error - The error that caused the failure
2644
+ * @param data - Optional partial result data (if any was produced before failure)
2645
+ * @returns The error event
2646
+ */
2647
+ async fail(error, data) {
2648
+ if (this._terminated) {
2649
+ throw new Error("Session already terminated. Cannot call fail() after a terminal operation.");
2650
+ }
2651
+ this._terminated = true;
2652
+ let summary;
2653
+ try {
2654
+ summary = await this.getSummary();
2655
+ } catch {
2656
+ }
2657
+ this._logger.onExecutionError?.({
2658
+ type: "execution_error",
2659
+ timestamp: Date.now(),
2660
+ duration: summary?.totalDuration ?? Date.now() - this._startTime,
2661
+ error,
2662
+ data,
2663
+ summary
2664
+ });
2665
+ const errorEvent = {
2666
+ type: "error",
2667
+ error
2668
+ };
2669
+ if (summary) {
2670
+ errorEvent.summary = summary;
2671
+ }
2672
+ if (data !== void 0) {
2673
+ errorEvent.data = data;
2674
+ }
2675
+ return this.emitInternal(errorEvent);
2676
+ }
2677
+ createMetrics() {
2678
+ const now = Date.now();
2679
+ const metrics = {
2680
+ timestamp: now,
2681
+ elapsedMs: now - this._startTime,
2682
+ deltaMs: now - this.lastEventTime
2683
+ };
2684
+ this.lastEventTime = now;
2685
+ return metrics;
2686
+ }
2687
+ };
2688
+ function createStreamingSession(options) {
2689
+ const session = new StreamingSession({
2690
+ defaultLanguageModel: options.defaultLanguageModel,
2691
+ providerType: options.providerType,
2692
+ fileManager: options.fileManager,
2693
+ logger: options.logger ?? noopLogger,
2694
+ startTime: options.startTime,
2695
+ signal: options.signal
2696
+ });
2697
+ return session;
2698
+ }
2699
+
2700
+ // src/provider/google/factory.ts
2701
+ var GoogleProvider = class _GoogleProvider extends BaseProvider {
2702
+ constructor(apiKey, defaultModelId, logger, safetySettings, pricingConfig, defaultOptions, searchEnabled = false, urlContextEnabled = false, fileCache) {
2703
+ super();
2704
+ this.apiKey = apiKey;
2705
+ this.defaultModelId = defaultModelId;
2706
+ this.logger = logger;
2707
+ this.safetySettings = safetySettings;
2708
+ this.pricingConfig = pricingConfig;
2709
+ this.defaultOptions = defaultOptions;
2710
+ this.searchEnabled = searchEnabled;
2711
+ this.urlContextEnabled = urlContextEnabled;
2712
+ this.fileCache = fileCache;
2713
+ this.google = google.createGoogleGenerativeAI({ apiKey });
2714
+ }
2715
+ google;
2716
+ withDefaultModel(modelId) {
2717
+ return new _GoogleProvider(
2718
+ this.apiKey,
2719
+ modelId,
2720
+ this.logger,
2721
+ this.safetySettings,
2722
+ this.pricingConfig,
2723
+ this.defaultOptions,
2724
+ this.searchEnabled,
2725
+ this.urlContextEnabled,
2726
+ this.fileCache
2727
+ );
2728
+ }
2729
+ withLogger(newLogger) {
2730
+ return new _GoogleProvider(
2731
+ this.apiKey,
2732
+ this.defaultModelId,
2733
+ newLogger,
2734
+ this.safetySettings,
2735
+ this.pricingConfig,
2736
+ this.defaultOptions,
2737
+ this.searchEnabled,
2738
+ this.urlContextEnabled,
2739
+ this.fileCache
2740
+ );
2741
+ }
2742
+ withPricing(pricing) {
2743
+ validateProviderPricing(pricing, "google");
2744
+ return new _GoogleProvider(
2745
+ this.apiKey,
2746
+ this.defaultModelId,
2747
+ this.logger,
2748
+ this.safetySettings,
2749
+ pricing,
2750
+ this.defaultOptions,
2751
+ this.searchEnabled,
2752
+ this.urlContextEnabled,
2753
+ this.fileCache
2754
+ );
2755
+ }
2756
+ /**
2757
+ * Set default provider-specific options for all LLM calls.
2758
+ * These options will be deep-merged with per-call providerOptions.
2759
+ *
2760
+ * @example
2761
+ * ```typescript
2762
+ * createGoogleProvider({ apiKey: 'xxx' })
2763
+ * .withDefaultModel('gemini-2.0-flash-thinking-exp')
2764
+ * .withDefaultOptions({
2765
+ * thinkingConfig: { includeThoughts: true, thinkingLevel: 'low' }
2766
+ * })
2767
+ * ```
2768
+ */
2769
+ withDefaultOptions(options) {
2770
+ return new _GoogleProvider(
2771
+ this.apiKey,
2772
+ this.defaultModelId,
2773
+ this.logger,
2774
+ this.safetySettings,
2775
+ this.pricingConfig,
2776
+ options,
2777
+ this.searchEnabled,
2778
+ this.urlContextEnabled,
2779
+ this.fileCache
2780
+ );
2781
+ }
2782
+ /**
2783
+ * Enable Google Search grounding for all LLM calls.
2784
+ * Allows the model to access real-time web information.
2785
+ *
2786
+ * @example
2787
+ * ```typescript
2788
+ * createGoogleProvider({ apiKey: 'xxx' })
2789
+ * .withDefaultModel('gemini-2.5-flash')
2790
+ * .withSearchEnabled()
2791
+ * ```
2792
+ */
2793
+ withSearchEnabled() {
2794
+ return new _GoogleProvider(
2795
+ this.apiKey,
2796
+ this.defaultModelId,
2797
+ this.logger,
2798
+ this.safetySettings,
2799
+ this.pricingConfig,
2800
+ this.defaultOptions,
2801
+ true,
2802
+ this.urlContextEnabled,
2803
+ this.fileCache
2804
+ );
2805
+ }
2806
+ /**
2807
+ * Enable URL Context grounding for all LLM calls.
2808
+ * Allows the model to retrieve and use content from URLs in the prompt.
2809
+ *
2810
+ * @example
2811
+ * ```typescript
2812
+ * createGoogleProvider({ apiKey: 'xxx' })
2813
+ * .withDefaultModel('gemini-2.5-flash')
2814
+ * .withUrlContextEnabled()
2815
+ * ```
2816
+ */
2817
+ withUrlContextEnabled() {
2818
+ return new _GoogleProvider(
2819
+ this.apiKey,
2820
+ this.defaultModelId,
2821
+ this.logger,
2822
+ this.safetySettings,
2823
+ this.pricingConfig,
2824
+ this.defaultOptions,
2825
+ this.searchEnabled,
2826
+ true,
2827
+ this.fileCache
2828
+ );
2829
+ }
2830
+ /**
2831
+ * Set a file cache for reusing uploaded files across sessions.
2832
+ * If no cache is provided, creates a new InMemoryFileCache.
2833
+ *
2834
+ * @example
2835
+ * ```typescript
2836
+ * // Use default InMemoryFileCache
2837
+ * createGoogleProvider({ apiKey: 'xxx' })
2838
+ * .withFileCache()
2839
+ *
2840
+ * // Use custom cache with TTL
2841
+ * const cache = new InMemoryFileCache({ defaultTTL: 3600000 });
2842
+ * createGoogleProvider({ apiKey: 'xxx' })
2843
+ * .withFileCache(cache)
2844
+ * ```
2845
+ */
2846
+ withFileCache(cache) {
2847
+ return new _GoogleProvider(
2848
+ this.apiKey,
2849
+ this.defaultModelId,
2850
+ this.logger,
2851
+ this.safetySettings,
2852
+ this.pricingConfig,
2853
+ this.defaultOptions,
2854
+ this.searchEnabled,
2855
+ this.urlContextEnabled,
2856
+ cache ?? new InMemoryFileCache()
2857
+ );
2858
+ }
2859
+ getSessionConfig() {
2860
+ const defaultTools = {
2861
+ ...this.searchEnabled && { google_search: this.google.tools.googleSearch({}) },
2862
+ ...this.urlContextEnabled && { url_context: this.google.tools.urlContext({}) }
2863
+ };
2864
+ const hasDefaultTools = this.searchEnabled || this.urlContextEnabled;
2865
+ return {
2866
+ defaultLanguageModel: this.defaultModelId ? this.createModel(this.defaultModelId) : null,
2867
+ modelFactory: (modelId) => this.createModel(modelId),
2868
+ providerType: "google",
2869
+ providerPricing: this.pricingConfig,
2870
+ fileManager: new GoogleFileManager(this.apiKey, { cache: this.fileCache }),
2871
+ logger: this.logger,
2872
+ defaultProviderOptions: this.defaultOptions ? { google: this.defaultOptions } : void 0,
2873
+ defaultTools: hasDefaultTools ? defaultTools : void 0
2874
+ };
2875
+ }
2876
+ createStreamingSession(signal) {
2877
+ return new StreamingSession({ ...this.getSessionConfig(), signal });
2878
+ }
2879
+ createSimpleSession(signal) {
2880
+ return new SimpleSession({ ...this.getSessionConfig(), signal });
2881
+ }
2882
+ /**
2883
+ * Type assertion needed because @ai-sdk/google's type signature doesn't
2884
+ * include the second parameter, but it's supported at runtime.
2885
+ */
2886
+ createModel(modelId) {
2887
+ if (this.safetySettings) {
2888
+ return this.google(modelId, { safetySettings: this.safetySettings });
2889
+ }
2890
+ return this.google(modelId);
2891
+ }
2892
+ };
2893
+ function createGoogleProvider(config) {
2894
+ return new GoogleProvider(
2895
+ config.apiKey,
2896
+ null,
2897
+ // No default model - must be set with withDefaultModel()
2898
+ noopLogger,
2899
+ config.safetySettings
2900
+ );
2901
+ }
2902
+ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
2903
+ constructor(apiKey, defaultModelId, logger, baseURL, organization, pricingConfig, defaultOptions, fileCache) {
2904
+ super();
2905
+ this.apiKey = apiKey;
2906
+ this.defaultModelId = defaultModelId;
2907
+ this.logger = logger;
2908
+ this.baseURL = baseURL;
2909
+ this.organization = organization;
2910
+ this.pricingConfig = pricingConfig;
2911
+ this.defaultOptions = defaultOptions;
2912
+ this.fileCache = fileCache;
2913
+ this.openai = openai.createOpenAI({
2914
+ apiKey,
2915
+ baseURL,
2916
+ organization
2917
+ });
2918
+ }
2919
+ openai;
2920
+ withDefaultModel(modelId) {
2921
+ return new _OpenAIProvider(
2922
+ this.apiKey,
2923
+ modelId,
2924
+ this.logger,
2925
+ this.baseURL,
2926
+ this.organization,
2927
+ this.pricingConfig,
2928
+ this.defaultOptions,
2929
+ this.fileCache
2930
+ );
2931
+ }
2932
+ withLogger(newLogger) {
2933
+ return new _OpenAIProvider(
2934
+ this.apiKey,
2935
+ this.defaultModelId,
2936
+ newLogger,
2937
+ this.baseURL,
2938
+ this.organization,
2939
+ this.pricingConfig,
2940
+ this.defaultOptions,
2941
+ this.fileCache
2942
+ );
2943
+ }
2944
+ withPricing(pricing) {
2945
+ validateProviderPricing(pricing, "openai");
2946
+ return new _OpenAIProvider(
2947
+ this.apiKey,
2948
+ this.defaultModelId,
2949
+ this.logger,
2950
+ this.baseURL,
2951
+ this.organization,
2952
+ pricing,
2953
+ this.defaultOptions,
2954
+ this.fileCache
2955
+ );
2956
+ }
2957
+ /**
2958
+ * Set default provider-specific options for all LLM calls.
2959
+ * These options will be deep-merged with per-call providerOptions.
2960
+ *
2961
+ * @example
2962
+ * ```typescript
2963
+ * createOpenAIProvider({ apiKey: 'xxx' })
2964
+ * .withDefaultModel('gpt-4o')
2965
+ * .withDefaultOptions({
2966
+ * reasoningEffort: 'high',
2967
+ * parallelToolCalls: true,
2968
+ * })
2969
+ * ```
2970
+ */
2971
+ withDefaultOptions(options) {
2972
+ return new _OpenAIProvider(
2973
+ this.apiKey,
2974
+ this.defaultModelId,
2975
+ this.logger,
2976
+ this.baseURL,
2977
+ this.organization,
2978
+ this.pricingConfig,
2979
+ options,
2980
+ this.fileCache
2981
+ );
2982
+ }
2983
+ /**
2984
+ * Set a file cache for API consistency with GoogleProvider.
2985
+ * Note: OpenAI does not support file caching, so this is a no-op.
2986
+ *
2987
+ * @example
2988
+ * ```typescript
2989
+ * createOpenAIProvider({ apiKey: 'xxx' })
2990
+ * .withFileCache()
2991
+ * ```
2992
+ */
2993
+ withFileCache(cache) {
2994
+ return new _OpenAIProvider(
2995
+ this.apiKey,
2996
+ this.defaultModelId,
2997
+ this.logger,
2998
+ this.baseURL,
2999
+ this.organization,
3000
+ this.pricingConfig,
3001
+ this.defaultOptions,
3002
+ cache
3003
+ );
3004
+ }
3005
+ getSessionConfig() {
3006
+ return {
3007
+ defaultLanguageModel: this.defaultModelId ? this.openai(this.defaultModelId) : null,
3008
+ modelFactory: (modelId) => this.openai(modelId),
3009
+ providerType: "openai",
3010
+ providerPricing: this.pricingConfig,
3011
+ fileManager: new NoOpFileManager(),
3012
+ logger: this.logger,
3013
+ defaultProviderOptions: this.defaultOptions ? { openai: this.defaultOptions } : void 0
3014
+ };
3015
+ }
3016
+ createStreamingSession(signal) {
3017
+ return new StreamingSession({ ...this.getSessionConfig(), signal });
3018
+ }
3019
+ createSimpleSession(signal) {
3020
+ return new SimpleSession({ ...this.getSessionConfig(), signal });
3021
+ }
3022
+ };
3023
+ function createOpenAIProvider(config) {
3024
+ return new OpenAIProvider(
3025
+ config.apiKey,
3026
+ null,
3027
+ // No default model - must be set with withDefaultModel()
3028
+ noopLogger,
3029
+ config.baseURL,
3030
+ config.organization
3031
+ );
3032
+ }
3033
+
3034
+ // src/validation/validation-history.ts
3035
+ var ValidationHistory = class {
3036
+ attempts = [];
3037
+ get nextAttempt() {
3038
+ return this.attempts.length + 1;
3039
+ }
3040
+ get last() {
3041
+ return this.attempts.at(-1);
3042
+ }
3043
+ get all() {
3044
+ return this.attempts;
3045
+ }
3046
+ get failureReasons() {
3047
+ return this.attempts.filter((a) => !a.valid && a.reason).map((a) => a.reason);
3048
+ }
3049
+ get isRetry() {
3050
+ return this.attempts.length > 0;
3051
+ }
3052
+ /** Internal use only - not exposed via ReadonlyValidationHistory. */
3053
+ add(result, validation) {
3054
+ this.attempts.push({
3055
+ result,
3056
+ ...validation,
3057
+ attempt: this.attempts.length + 1
3058
+ });
3059
+ }
3060
+ };
3061
+
3062
+ // src/validation/errors.ts
3063
+ var ValidationErrorCode = /* @__PURE__ */ ((ValidationErrorCode2) => {
3064
+ ValidationErrorCode2["VALIDATION_EXHAUSTED"] = "VALIDATION_EXHAUSTED";
3065
+ return ValidationErrorCode2;
3066
+ })(ValidationErrorCode || {});
3067
+ var ValidationExhaustedError = class extends AgtlantisError {
3068
+ constructor(message, history) {
3069
+ super(message, {
3070
+ code: "VALIDATION_EXHAUSTED" /* VALIDATION_EXHAUSTED */,
3071
+ context: {
3072
+ attempts: history.all.length,
3073
+ failureReasons: history.failureReasons
3074
+ }
3075
+ });
3076
+ this.history = history;
3077
+ this.name = "ValidationExhaustedError";
3078
+ }
3079
+ };
3080
+
3081
+ // src/validation/with-validation.ts
3082
+ async function withValidation(execute, options) {
3083
+ const { validate, maxAttempts: rawMax, signal, retryDelay, onAttempt } = options;
3084
+ const maxAttempts = Math.max(1, rawMax ?? 3);
3085
+ const history = new ValidationHistory();
3086
+ while (history.nextAttempt <= maxAttempts) {
3087
+ signal?.throwIfAborted();
3088
+ const result = await execute(history);
3089
+ const validation = await validate(result, history);
3090
+ history.add(result, validation);
3091
+ onAttempt?.(history.last);
3092
+ if (validation.valid) {
3093
+ return result;
3094
+ }
3095
+ const hasMoreAttempts = history.nextAttempt <= maxAttempts;
3096
+ if (retryDelay && hasMoreAttempts) {
3097
+ await new Promise((resolve2) => setTimeout(resolve2, retryDelay));
3098
+ }
3099
+ }
3100
+ throw new ValidationExhaustedError(
3101
+ `Validation failed after ${history.all.length} attempts`,
3102
+ history
3103
+ );
3104
+ }
3105
+
3106
+ exports.ANTHROPIC_PRICING = ANTHROPIC_PRICING;
3107
+ exports.AgtlantisError = AgtlantisError;
3108
+ exports.BaseProvider = BaseProvider;
3109
+ exports.ConfigurationError = ConfigurationError;
3110
+ exports.ConfigurationErrorCode = ConfigurationErrorCode;
3111
+ exports.DEFAULT_FALLBACK_PRICING = DEFAULT_FALLBACK_PRICING;
3112
+ exports.DEFAULT_MAX_SIZE = DEFAULT_MAX_SIZE;
3113
+ exports.DEFAULT_PRICING_CONFIG = DEFAULT_PRICING_CONFIG;
3114
+ exports.ERRORS = ERRORS;
3115
+ exports.EXTENSION_TO_MIME = EXTENSION_TO_MIME;
3116
+ exports.ExecutionError = ExecutionError;
3117
+ exports.ExecutionErrorCode = ExecutionErrorCode;
3118
+ exports.FileError = FileError;
3119
+ exports.FileErrorCode = FileErrorCode;
3120
+ exports.FilePromptRepository = FilePromptRepository;
3121
+ exports.GOOGLE_PRICING = GOOGLE_PRICING;
3122
+ exports.GoogleFileManager = GoogleFileManager;
3123
+ exports.GoogleProvider = GoogleProvider;
3124
+ exports.InMemoryFileCache = InMemoryFileCache;
3125
+ exports.NoOpFileManager = NoOpFileManager;
3126
+ exports.OPENAI_PRICING = OPENAI_PRICING;
3127
+ exports.ProgressivePattern = ProgressivePattern;
3128
+ exports.PromptError = PromptError;
3129
+ exports.PromptErrorCode = PromptErrorCode;
3130
+ exports.PromptIOError = PromptIOError;
3131
+ exports.PromptInvalidFormatError = PromptInvalidFormatError;
3132
+ exports.PromptNotFoundError = PromptNotFoundError;
3133
+ exports.PromptTemplate = PromptTemplate;
3134
+ exports.PromptTemplateError = PromptTemplateError;
3135
+ exports.SessionSummary = SessionSummary;
3136
+ exports.SimpleExecutionHost = SimpleExecutionHost;
3137
+ exports.SimpleSession = SimpleSession;
3138
+ exports.StreamingExecutionHost = StreamingExecutionHost;
3139
+ exports.StreamingSession = StreamingSession;
3140
+ exports.TOOL_CALLING_PROTOCOL = TOOL_CALLING_PROTOCOL;
3141
+ exports.ValidationErrorCode = ValidationErrorCode;
3142
+ exports.ValidationExhaustedError = ValidationExhaustedError;
3143
+ exports.ValidationHistory = ValidationHistory;
3144
+ exports.calculateCost = calculateCost;
3145
+ exports.calculateCostFromUsage = calculateCostFromUsage;
3146
+ exports.calculateTotalCost = calculateTotalCost;
3147
+ exports.combineSignals = combineSignals;
3148
+ exports.compileTemplate = compileTemplate;
3149
+ exports.computeFileSourceHash = computeFileSourceHash;
3150
+ exports.configurePricing = configurePricing;
3151
+ exports.createFilePromptRepository = createFilePromptRepository;
3152
+ exports.createGoogleProvider = createGoogleProvider;
3153
+ exports.createHookRunner = createHookRunner;
3154
+ exports.createLogger = createLogger;
3155
+ exports.createOpenAIProvider = createOpenAIProvider;
3156
+ exports.createStreamingSession = createStreamingSession;
3157
+ exports.createZeroUsage = createZeroUsage;
3158
+ exports.defineProgressivePattern = defineProgressivePattern;
3159
+ exports.detectProviderType = detectProviderType;
3160
+ exports.determineResultStatus = determineResultStatus;
3161
+ exports.getDuration = getDuration;
3162
+ exports.getEffectivePricing = getEffectivePricing;
3163
+ exports.getFileSourceDisplayInfo = getFileSourceDisplayInfo;
3164
+ exports.getFileSourcesDisplayInfo = getFileSourcesDisplayInfo;
3165
+ exports.getModelPricing = getModelPricing;
3166
+ exports.getPricingConfig = getPricingConfig;
3167
+ exports.inferMediaType = inferMediaType;
3168
+ exports.isAbortError = isAbortError;
3169
+ exports.isFileSource = isFileSource;
3170
+ exports.isFileSourceBase64 = isFileSourceBase64;
3171
+ exports.isFileSourceData = isFileSourceData;
3172
+ exports.isFileSourcePath = isFileSourcePath;
3173
+ exports.isFileSourceUrl = isFileSourceUrl;
3174
+ exports.mapExecution = mapExecution;
3175
+ exports.mapExecutionResult = mapExecutionResult;
3176
+ exports.mergeUsages = mergeUsages;
3177
+ exports.noopLogger = noopLogger;
3178
+ exports.normalizeError = normalizeError;
3179
+ exports.resetPricingConfig = resetPricingConfig;
3180
+ exports.resolveFileSource = resolveFileSource;
3181
+ exports.resolveFileSourcesInInput = resolveFileSourcesInInput;
3182
+ exports.scanForFileSources = scanForFileSources;
3183
+ exports.validateModelPricing = validateModelPricing;
3184
+ exports.validatePricingConfig = validatePricingConfig;
3185
+ exports.validateProviderPricing = validateProviderPricing;
3186
+ exports.withValidation = withValidation;
3187
+ //# sourceMappingURL=index.cjs.map
3188
+ //# sourceMappingURL=index.cjs.map