@juspay/neurolink 9.56.2 → 9.57.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.
Files changed (78) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/auth/AuthProviderFactory.d.ts +3 -3
  3. package/dist/auth/providers/BaseAuthProvider.d.ts +2 -2
  4. package/dist/auth/providers/BaseAuthProvider.js +1 -1
  5. package/dist/auth/serverBridge.d.ts +2 -2
  6. package/dist/browser/neurolink.min.js +285 -285
  7. package/dist/cli/factories/commandFactory.js +32 -8
  8. package/dist/cli/loop/optionsSchema.js +4 -0
  9. package/dist/cli/parser.js +3 -3
  10. package/dist/constants/enums.d.ts +8 -1
  11. package/dist/constants/enums.js +7 -0
  12. package/dist/dynamic/dynamicResolver.d.ts +282 -0
  13. package/dist/dynamic/dynamicResolver.js +633 -0
  14. package/dist/dynamic/index.d.ts +10 -0
  15. package/dist/dynamic/index.js +12 -0
  16. package/dist/dynamic/resolution.d.ts +17 -0
  17. package/dist/dynamic/resolution.js +21 -0
  18. package/dist/evaluation/index.js +1 -1
  19. package/dist/index.js +19 -2
  20. package/dist/lib/auth/AuthProviderFactory.d.ts +3 -3
  21. package/dist/lib/auth/providers/BaseAuthProvider.d.ts +2 -2
  22. package/dist/lib/auth/providers/BaseAuthProvider.js +1 -1
  23. package/dist/lib/auth/serverBridge.d.ts +2 -2
  24. package/dist/lib/constants/enums.d.ts +8 -1
  25. package/dist/lib/constants/enums.js +7 -0
  26. package/dist/lib/dynamic/dynamicResolver.d.ts +282 -0
  27. package/dist/lib/dynamic/dynamicResolver.js +634 -0
  28. package/dist/lib/dynamic/index.d.ts +10 -0
  29. package/dist/lib/dynamic/index.js +13 -0
  30. package/dist/lib/dynamic/resolution.d.ts +17 -0
  31. package/dist/lib/dynamic/resolution.js +22 -0
  32. package/dist/lib/evaluation/index.js +1 -1
  33. package/dist/lib/index.js +19 -2
  34. package/dist/lib/mcp/mcpServerBase.d.ts +1 -1
  35. package/dist/lib/mcp/mcpServerBase.js +1 -1
  36. package/dist/lib/neurolink.d.ts +18 -6
  37. package/dist/lib/neurolink.js +187 -42
  38. package/dist/lib/observability/exporters/baseExporter.d.ts +1 -1
  39. package/dist/lib/observability/exporters/baseExporter.js +1 -1
  40. package/dist/lib/types/auth.d.ts +6 -6
  41. package/dist/lib/types/config.d.ts +4 -4
  42. package/dist/lib/types/dynamic.d.ts +98 -0
  43. package/dist/lib/types/dynamic.js +10 -0
  44. package/dist/lib/types/generate.d.ts +29 -0
  45. package/dist/lib/types/index.d.ts +1 -0
  46. package/dist/lib/types/index.js +2 -0
  47. package/dist/lib/types/scorer.d.ts +1 -1
  48. package/dist/lib/types/scorer.js +1 -1
  49. package/dist/lib/types/span.d.ts +1 -1
  50. package/dist/lib/types/span.js +1 -1
  51. package/dist/lib/types/stream.d.ts +6 -0
  52. package/dist/lib/utils/conversationMemory.d.ts +10 -0
  53. package/dist/lib/utils/conversationMemory.js +185 -1
  54. package/dist/lib/utils/errorHandling.d.ts +13 -0
  55. package/dist/lib/utils/errorHandling.js +31 -0
  56. package/dist/mcp/mcpServerBase.d.ts +1 -1
  57. package/dist/mcp/mcpServerBase.js +1 -1
  58. package/dist/neurolink.d.ts +18 -6
  59. package/dist/neurolink.js +187 -42
  60. package/dist/observability/exporters/baseExporter.d.ts +1 -1
  61. package/dist/observability/exporters/baseExporter.js +1 -1
  62. package/dist/types/auth.d.ts +6 -6
  63. package/dist/types/config.d.ts +4 -4
  64. package/dist/types/dynamic.d.ts +98 -0
  65. package/dist/types/dynamic.js +9 -0
  66. package/dist/types/generate.d.ts +29 -0
  67. package/dist/types/index.d.ts +1 -0
  68. package/dist/types/index.js +2 -0
  69. package/dist/types/scorer.d.ts +1 -1
  70. package/dist/types/scorer.js +1 -1
  71. package/dist/types/span.d.ts +1 -1
  72. package/dist/types/span.js +1 -1
  73. package/dist/types/stream.d.ts +6 -0
  74. package/dist/utils/conversationMemory.d.ts +10 -0
  75. package/dist/utils/conversationMemory.js +185 -1
  76. package/dist/utils/errorHandling.d.ts +13 -0
  77. package/dist/utils/errorHandling.js +31 -0
  78. package/package.json +2 -1
@@ -0,0 +1,633 @@
1
+ /**
2
+ * Dynamic Argument Resolution Utilities
3
+ *
4
+ * Provides utilities for resolving dynamic arguments to their actual values,
5
+ * with support for caching, memoization, fallbacks, and conditional resolution.
6
+ *
7
+ * @module dynamic/dynamicResolver
8
+ */
9
+ import { isDynamicFunction, isContextAwareFunction } from "./resolution.js";
10
+ import { logger } from "../utils/logger.js";
11
+ import { withTimeout } from "../utils/errorHandling.js";
12
+ /**
13
+ * Default resolution options
14
+ */
15
+ const DEFAULT_RESOLUTION_OPTIONS = {
16
+ timeout: 5000,
17
+ cache: false,
18
+ cacheKey: "",
19
+ cacheTtl: 60000, // 1 minute
20
+ defaultValue: undefined,
21
+ throwOnError: true,
22
+ };
23
+ /**
24
+ * Resolution cache for dynamic arguments
25
+ */
26
+ class ResolutionCache {
27
+ cache = new Map();
28
+ cleanupInterval = null;
29
+ constructor(cleanupIntervalMs = 60000) {
30
+ this.startCleanup(cleanupIntervalMs);
31
+ }
32
+ get(key) {
33
+ const entry = this.cache.get(key);
34
+ if (!entry) {
35
+ return undefined;
36
+ }
37
+ if (Date.now() > entry.expiresAt) {
38
+ this.cache.delete(key);
39
+ return undefined;
40
+ }
41
+ return entry.value;
42
+ }
43
+ set(key, value, ttl) {
44
+ const now = Date.now();
45
+ this.cache.set(key, {
46
+ value,
47
+ resolvedAt: now,
48
+ expiresAt: now + ttl,
49
+ key,
50
+ });
51
+ }
52
+ delete(key) {
53
+ return this.cache.delete(key);
54
+ }
55
+ clear() {
56
+ this.cache.clear();
57
+ }
58
+ size() {
59
+ return this.cache.size;
60
+ }
61
+ startCleanup(intervalMs) {
62
+ const timer = setInterval(() => {
63
+ const now = Date.now();
64
+ for (const [key, entry] of this.cache.entries()) {
65
+ if (now > entry.expiresAt) {
66
+ this.cache.delete(key);
67
+ }
68
+ }
69
+ }, intervalMs);
70
+ if (typeof timer.unref === "function") {
71
+ timer.unref();
72
+ }
73
+ this.cleanupInterval = timer;
74
+ }
75
+ destroy() {
76
+ if (this.cleanupInterval) {
77
+ clearInterval(this.cleanupInterval);
78
+ this.cleanupInterval = null;
79
+ }
80
+ this.cache.clear();
81
+ }
82
+ }
83
+ // Global resolution cache
84
+ const globalCache = new ResolutionCache();
85
+ // Stable per-instance ids for function arguments — `String(fn)` is unsafe
86
+ // because two distinct closures with identical source text collide.
87
+ const functionIds = new WeakMap();
88
+ let nextFunctionId = 0;
89
+ function getArgumentId(argument) {
90
+ if (typeof argument !== "function") {
91
+ return String(argument);
92
+ }
93
+ let id = functionIds.get(argument);
94
+ if (id === undefined) {
95
+ id = `fn:${++nextFunctionId}`;
96
+ functionIds.set(argument, id);
97
+ }
98
+ return id;
99
+ }
100
+ /**
101
+ * Generate cache key for dynamic argument resolution
102
+ */
103
+ function generateCacheKey(argumentId, context, options) {
104
+ if (options?.cacheKey) {
105
+ return options.cacheKey;
106
+ }
107
+ const parts = [argumentId];
108
+ if (context?.requestContext) {
109
+ // Extract cache-scoping ids from generic context (consumer-defined shape)
110
+ const rc = context.requestContext;
111
+ if (rc.user?.id) {
112
+ parts.push(`user:${rc.user.id}`);
113
+ }
114
+ if (rc.tenant?.id) {
115
+ parts.push(`tenant:${rc.tenant.id}`);
116
+ }
117
+ if (rc.session?.id) {
118
+ parts.push(`session:${rc.session.id}`);
119
+ }
120
+ }
121
+ return parts.join(":");
122
+ }
123
+ /**
124
+ * Resolve a dynamic argument to its actual value
125
+ *
126
+ * @template T - The expected resolved type
127
+ * @param argument - The dynamic argument to resolve
128
+ * @param context - Resolution context (optional for static values)
129
+ * @param options - Resolution options
130
+ * @returns Resolution result with value and metadata
131
+ *
132
+ * @example Resolve static value
133
+ * ```typescript
134
+ * const result = await resolveDynamicArgument("gpt-4o");
135
+ * console.log(result.value); // "gpt-4o"
136
+ * console.log(result.resolutionType); // "static"
137
+ * ```
138
+ *
139
+ * @example Resolve context-aware function
140
+ * ```typescript
141
+ * const modelSelector = ({ requestContext }) =>
142
+ * requestContext.tenant?.plan === "enterprise" ? "claude-3-opus" : "claude-3-sonnet";
143
+ *
144
+ * const result = await resolveDynamicArgument(modelSelector, {
145
+ * requestContext: { requestId: "123", tenant: { id: "t1", plan: "enterprise" } }
146
+ * });
147
+ * console.log(result.value); // "claude-3-opus"
148
+ * ```
149
+ */
150
+ export async function resolveDynamicArgument(argument, context, options) {
151
+ const startTime = Date.now();
152
+ const opts = { ...DEFAULT_RESOLUTION_OPTIONS, ...options };
153
+ // Check cache first
154
+ if (opts.cache) {
155
+ const cacheKey = generateCacheKey(getArgumentId(argument), context, options);
156
+ const cached = globalCache.get(cacheKey);
157
+ if (cached !== undefined) {
158
+ return {
159
+ value: cached,
160
+ fromCache: true,
161
+ resolutionTime: Date.now() - startTime,
162
+ resolutionType: "static", // Cached value, original type unknown
163
+ };
164
+ }
165
+ }
166
+ try {
167
+ // Static value
168
+ if (!isDynamicFunction(argument)) {
169
+ const result = {
170
+ value: argument,
171
+ fromCache: false,
172
+ resolutionTime: Date.now() - startTime,
173
+ resolutionType: "static",
174
+ };
175
+ if (opts.cache) {
176
+ const cacheKey = generateCacheKey(getArgumentId(argument), context, options);
177
+ globalCache.set(cacheKey, argument, opts.cacheTtl);
178
+ }
179
+ return result;
180
+ }
181
+ // Function value
182
+ let resolvedValue;
183
+ let resolutionType = "async-function";
184
+ const resolutionPromise = (async () => {
185
+ if (isContextAwareFunction(argument)) {
186
+ // Context-aware function — pass an empty context if caller didn't
187
+ // provide one. Combinators (withFallback, conditional, etc.) return
188
+ // arity-1 functions even when their inputs don't need context, so
189
+ // requiring a context here would force callers to invent one.
190
+ resolutionType = "context-aware";
191
+ return argument(context ?? { requestContext: {} });
192
+ }
193
+ else {
194
+ // No-argument function
195
+ const fn = argument;
196
+ const result = fn();
197
+ if (result instanceof Promise) {
198
+ resolutionType = "async-function";
199
+ return result;
200
+ }
201
+ else {
202
+ resolutionType = "sync-function";
203
+ return result;
204
+ }
205
+ }
206
+ })();
207
+ // Apply timeout if specified
208
+ if (opts.timeout > 0) {
209
+ resolvedValue = await withTimeout(resolutionPromise, opts.timeout, new Error(`Dynamic argument resolution timed out after ${opts.timeout}ms`));
210
+ }
211
+ else {
212
+ resolvedValue = await resolutionPromise;
213
+ }
214
+ const result = {
215
+ value: resolvedValue,
216
+ fromCache: false,
217
+ resolutionTime: Date.now() - startTime,
218
+ resolutionType: resolutionType,
219
+ };
220
+ // Cache if enabled
221
+ if (opts.cache) {
222
+ const cacheKey = generateCacheKey(getArgumentId(argument), context, options);
223
+ globalCache.set(cacheKey, resolvedValue, opts.cacheTtl);
224
+ }
225
+ return result;
226
+ }
227
+ catch (error) {
228
+ logger.error("Dynamic argument resolution failed", {
229
+ error: error instanceof Error ? error.message : String(error),
230
+ resolutionTime: Date.now() - startTime,
231
+ });
232
+ if (opts.throwOnError) {
233
+ throw error;
234
+ }
235
+ // Return default value on error
236
+ return {
237
+ value: opts.defaultValue,
238
+ fromCache: false,
239
+ resolutionTime: Date.now() - startTime,
240
+ resolutionType: "static",
241
+ };
242
+ }
243
+ }
244
+ /**
245
+ * Resolve multiple dynamic arguments in parallel
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * const [model, temperature] = await resolveDynamicArguments(
250
+ * [
251
+ * ({ requestContext }) => requestContext.user?.preferences?.preferredModel || "gpt-4o",
252
+ * 0.7,
253
+ * ],
254
+ * context
255
+ * );
256
+ * ```
257
+ */
258
+ export async function resolveDynamicArguments(arguments_, context, options) {
259
+ const results = await Promise.all(arguments_.map((arg) => resolveDynamicArgument(arg, context, options)));
260
+ return results.map((r) => r.value);
261
+ }
262
+ /**
263
+ * Resolve all properties of a dynamic configuration object
264
+ *
265
+ * @example
266
+ * ```typescript
267
+ * const dynamicConfig = {
268
+ * model: ({ requestContext }) => requestContext.tenant?.settings?.defaultModel || "gpt-4o",
269
+ * temperature: 0.7,
270
+ * maxTokens: async () => (await fetchConfig()).maxTokens,
271
+ * };
272
+ *
273
+ * const resolved = await resolveDynamicConfig(dynamicConfig, context);
274
+ * // resolved.model, resolved.temperature, resolved.maxTokens are all resolved values
275
+ * ```
276
+ */
277
+ export async function resolveDynamicConfig(config, context, options) {
278
+ const entries = Object.entries(config);
279
+ const resolvedEntries = await Promise.all(entries.map(async ([key, value]) => {
280
+ const result = await resolveDynamicArgument(value, context, options);
281
+ return [key, result.value];
282
+ }));
283
+ return Object.fromEntries(resolvedEntries);
284
+ }
285
+ /**
286
+ * Create a memoized dynamic argument that caches its result
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * const expensiveModelSelector = memoizeDynamicArgument(
291
+ * async ({ requestContext }) => {
292
+ * const config = await fetchTenantConfig(requestContext.tenant?.id);
293
+ * return config.preferredModel;
294
+ * },
295
+ * { cacheTtl: 300000 } // Cache for 5 minutes
296
+ * );
297
+ * ```
298
+ */
299
+ export function memoizeDynamicArgument(argument, options) {
300
+ if (!isDynamicFunction(argument)) {
301
+ return argument; // Static values don't need memoization
302
+ }
303
+ const cache = new Map();
304
+ const ttl = options?.cacheTtl || 60000;
305
+ return async (context) => {
306
+ const key = options?.cacheKey ||
307
+ generateCacheKey("memoized", context, { cacheKey: options?.cacheKey });
308
+ const cached = cache.get(key);
309
+ if (cached && Date.now() < cached.expiresAt) {
310
+ return cached.value;
311
+ }
312
+ const result = await resolveDynamicArgument(argument, context);
313
+ cache.set(key, { value: result.value, expiresAt: Date.now() + ttl });
314
+ return result.value;
315
+ };
316
+ }
317
+ /**
318
+ * Create a dynamic argument with fallback chain
319
+ *
320
+ * @example
321
+ * ```typescript
322
+ * const modelWithFallback = withFallback(
323
+ * ({ requestContext }) => requestContext.user?.preferences?.preferredModel,
324
+ * ({ requestContext }) => requestContext.tenant?.settings?.defaultModel,
325
+ * "gpt-4o" // Final static fallback
326
+ * );
327
+ * ```
328
+ */
329
+ export function withFallback(...arguments_) {
330
+ return async (context) => {
331
+ let lastError;
332
+ for (const arg of arguments_) {
333
+ try {
334
+ const result = await resolveDynamicArgument(arg, context, {
335
+ throwOnError: false,
336
+ });
337
+ if (result.value !== undefined && result.value !== null) {
338
+ return result.value;
339
+ }
340
+ }
341
+ catch (err) {
342
+ lastError = err;
343
+ }
344
+ }
345
+ const msg = lastError instanceof Error ? lastError.message : String(lastError || "");
346
+ throw new Error(`All fallbacks failed${msg ? `: ${msg}` : ""}`, {
347
+ cause: lastError,
348
+ });
349
+ };
350
+ }
351
+ /**
352
+ * Create a conditional dynamic argument
353
+ *
354
+ * @example
355
+ * ```typescript
356
+ * const conditionalModel = conditional(
357
+ * ({ requestContext }) => requestContext.tenant?.plan === "enterprise",
358
+ * "claude-3-opus", // If true
359
+ * "claude-3-sonnet" // If false
360
+ * );
361
+ * ```
362
+ */
363
+ export function conditional(condition, ifTrue, ifFalse) {
364
+ return async (context) => {
365
+ const conditionResult = await resolveDynamicArgument(condition, context);
366
+ if (conditionResult.value) {
367
+ return (await resolveDynamicArgument(ifTrue, context)).value;
368
+ }
369
+ return (await resolveDynamicArgument(ifFalse, context)).value;
370
+ };
371
+ }
372
+ /**
373
+ * Create a mapped dynamic argument that transforms the result
374
+ *
375
+ * @example
376
+ * ```typescript
377
+ * const upperCaseModel = mapDynamicArgument(
378
+ * ({ requestContext }) => requestContext.user?.preferences?.preferredModel,
379
+ * (model) => model?.toUpperCase()
380
+ * );
381
+ * ```
382
+ */
383
+ export function mapDynamicArgument(argument, transform) {
384
+ return async (context) => {
385
+ const result = await resolveDynamicArgument(argument, context);
386
+ return transform(result.value);
387
+ };
388
+ }
389
+ /**
390
+ * Create a dynamic argument that combines multiple arguments
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * const combinedConfig = combineDynamicArguments(
395
+ * [
396
+ * ({ requestContext }) => requestContext.user?.preferences?.preferredModel,
397
+ * ({ requestContext }) => requestContext.tenant?.settings?.defaultTemperature,
398
+ * ],
399
+ * ([model, temperature]) => ({ model: model || "gpt-4o", temperature: temperature || 0.7 })
400
+ * );
401
+ * ```
402
+ */
403
+ export function combineDynamicArguments(arguments_, combiner) {
404
+ return async (context) => {
405
+ const results = await resolveDynamicArguments(arguments_, context);
406
+ return combiner(results);
407
+ };
408
+ }
409
+ /**
410
+ * Check if a value contains any dynamic arguments (is a function)
411
+ */
412
+ export function hasDynamicArgument(value) {
413
+ return isDynamicFunction(value);
414
+ }
415
+ /**
416
+ * Check if an object has any dynamic properties
417
+ */
418
+ export function hasDynamicProperties(config) {
419
+ return Object.values(config).some((value) => isDynamicFunction(value));
420
+ }
421
+ /**
422
+ * Clear the global resolution cache
423
+ */
424
+ export function clearResolutionCache() {
425
+ globalCache.clear();
426
+ }
427
+ /**
428
+ * Get resolution cache statistics
429
+ */
430
+ export function getResolutionCacheStats() {
431
+ return { size: globalCache.size() };
432
+ }
433
+ /**
434
+ * Destroy the resolver (cleanup intervals, etc.)
435
+ */
436
+ export function destroyResolver() {
437
+ globalCache.destroy();
438
+ }
439
+ // ============================================================================
440
+ // Environment Variable Interpolation
441
+ // ============================================================================
442
+ /**
443
+ * Pattern for environment variable interpolation
444
+ * Supports: ${ENV_VAR}, ${ENV_VAR:-default}, ${ENV_VAR:+replacement}
445
+ */
446
+ const ENV_VAR_PATTERN = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::([+-]?)([^}]*))?\}/g;
447
+ /**
448
+ * Interpolate environment variables in a string
449
+ *
450
+ * Supports syntax:
451
+ * - ${VAR} - Simple substitution
452
+ * - ${VAR:-default} - Use default if VAR is unset or empty
453
+ * - ${VAR:+replacement} - Use replacement if VAR is set and non-empty
454
+ *
455
+ * @example
456
+ * ```typescript
457
+ * interpolateEnvVars("Model: ${DEFAULT_MODEL:-gpt-4o}");
458
+ * // Returns "Model: gpt-4o" if DEFAULT_MODEL is not set
459
+ *
460
+ * interpolateEnvVars("API Key: ${OPENAI_API_KEY}");
461
+ * // Returns "API Key: sk-xxx..." if OPENAI_API_KEY is set
462
+ *
463
+ * interpolateEnvVars("Debug: ${DEBUG:+enabled}");
464
+ * // Returns "Debug: enabled" if DEBUG is set, "Debug: " otherwise
465
+ * ```
466
+ */
467
+ export function interpolateEnvVars(input, customEnv) {
468
+ const env = customEnv || process.env;
469
+ return input.replace(ENV_VAR_PATTERN, (match, varName, modifier, value) => {
470
+ const envValue = env[varName];
471
+ const isSet = envValue !== undefined && envValue !== "";
472
+ if (modifier === "-") {
473
+ // ${VAR:-default} - Use default if unset or empty
474
+ return isSet ? envValue : value || "";
475
+ }
476
+ else if (modifier === "+") {
477
+ // ${VAR:+replacement} - Use replacement if set and non-empty
478
+ return isSet ? value || "" : "";
479
+ }
480
+ else {
481
+ // ${VAR} - Simple substitution
482
+ return envValue || "";
483
+ }
484
+ });
485
+ }
486
+ /**
487
+ * Create a dynamic argument that interpolates environment variables
488
+ *
489
+ * @example
490
+ * ```typescript
491
+ * const model = fromEnv("${PREFERRED_MODEL:-gpt-4o}");
492
+ * // Resolves to value of PREFERRED_MODEL or "gpt-4o" as fallback
493
+ * ```
494
+ */
495
+ export function fromEnv(template) {
496
+ return () => interpolateEnvVars(template);
497
+ }
498
+ /**
499
+ * Create a dynamic argument from a single environment variable
500
+ *
501
+ * @example
502
+ * ```typescript
503
+ * const apiKey = envVar("OPENAI_API_KEY");
504
+ * // Resolves to value of OPENAI_API_KEY or undefined
505
+ *
506
+ * const model = envVar("DEFAULT_MODEL", "gpt-4o");
507
+ * // Resolves to DEFAULT_MODEL value or "gpt-4o" as default
508
+ * ```
509
+ */
510
+ export function envVar(name, defaultValue) {
511
+ return () => {
512
+ const value = process.env[name];
513
+ return (value !== undefined && value !== "" ? value : defaultValue);
514
+ };
515
+ }
516
+ /**
517
+ * Create a dynamic argument that selects from environment-based configurations
518
+ *
519
+ * @example
520
+ * ```typescript
521
+ * const model = envSwitch("NODE_ENV", {
522
+ * development: "gpt-4o-mini",
523
+ * production: "gpt-4o",
524
+ * test: "gpt-3.5-turbo",
525
+ * }, "gpt-4o-mini");
526
+ * ```
527
+ */
528
+ export function envSwitch(envVarName, options, defaultValue) {
529
+ return () => {
530
+ const envValue = process.env[envVarName];
531
+ if (envValue && envValue in options) {
532
+ return options[envValue];
533
+ }
534
+ return defaultValue;
535
+ };
536
+ }
537
+ /**
538
+ * Create a dynamic argument that parses a JSON value from an environment variable
539
+ *
540
+ * @example
541
+ * ```typescript
542
+ * // If RATE_LIMITS='{"requestsPerMinute": 100, "tokensPerDay": 50000}'
543
+ * const rateLimits = envJson<RateLimits>("RATE_LIMITS", { requestsPerMinute: 10 });
544
+ * ```
545
+ */
546
+ export function envJson(name, defaultValue) {
547
+ return () => {
548
+ const value = process.env[name];
549
+ if (!value) {
550
+ return defaultValue;
551
+ }
552
+ try {
553
+ return JSON.parse(value);
554
+ }
555
+ catch {
556
+ logger.warn(`Failed to parse JSON from environment variable ${name}`);
557
+ return defaultValue;
558
+ }
559
+ };
560
+ }
561
+ /**
562
+ * Create a dynamic argument that reads a number from an environment variable
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * const maxTokens = envNumber("MAX_TOKENS", 1000);
567
+ * const temperature = envNumber("TEMPERATURE", 0.7);
568
+ * ```
569
+ */
570
+ export function envNumber(name, defaultValue) {
571
+ return () => {
572
+ const value = process.env[name];
573
+ if (!value) {
574
+ return defaultValue;
575
+ }
576
+ const parsed = parseFloat(value);
577
+ return isNaN(parsed) ? defaultValue : parsed;
578
+ };
579
+ }
580
+ /**
581
+ * Create a dynamic argument that reads a boolean from an environment variable
582
+ *
583
+ * @example
584
+ * ```typescript
585
+ * const enableDebug = envBoolean("DEBUG", false);
586
+ * const enableTools = envBoolean("ENABLE_TOOLS", true);
587
+ * ```
588
+ */
589
+ export function envBoolean(name, defaultValue) {
590
+ return () => {
591
+ const value = process.env[name];
592
+ if (!value) {
593
+ return defaultValue;
594
+ }
595
+ const lower = value.toLowerCase();
596
+ if (lower === "true" ||
597
+ lower === "1" ||
598
+ lower === "yes" ||
599
+ lower === "on") {
600
+ return true;
601
+ }
602
+ if (lower === "false" ||
603
+ lower === "0" ||
604
+ lower === "no" ||
605
+ lower === "off") {
606
+ return false;
607
+ }
608
+ return defaultValue;
609
+ };
610
+ }
611
+ /**
612
+ * Create a dynamic argument that reads a comma-separated list from an environment variable
613
+ *
614
+ * @example
615
+ * ```typescript
616
+ * // If ALLOWED_PROVIDERS='openai,anthropic,vertex'
617
+ * const providers = envList("ALLOWED_PROVIDERS", ["openai"]);
618
+ * // Returns ["openai", "anthropic", "vertex"]
619
+ * ```
620
+ */
621
+ export function envList(name, defaultValue, separator = ",") {
622
+ return () => {
623
+ const value = process.env[name];
624
+ if (!value) {
625
+ return defaultValue;
626
+ }
627
+ return value
628
+ .split(separator)
629
+ .map((s) => s.trim())
630
+ .filter(Boolean);
631
+ };
632
+ }
633
+ export { globalCache as resolutionCache };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Dynamic Arguments Module
3
+ *
4
+ * Resolves function-valued options to their actual values before
5
+ * provider dispatch. All type definitions live in `src/lib/types/dynamic.ts`.
6
+ *
7
+ * @module dynamic
8
+ */
9
+ export { isDynamicFunction, isContextAwareFunction } from "./resolution.js";
10
+ export { resolveDynamicArgument, resolveDynamicArguments, resolveDynamicConfig, memoizeDynamicArgument, withFallback, conditional, mapDynamicArgument, combineDynamicArguments, hasDynamicArgument, hasDynamicProperties, clearResolutionCache, getResolutionCacheStats, destroyResolver, resolutionCache, interpolateEnvVars, fromEnv, envVar, envSwitch, envJson, envNumber, envBoolean, envList, } from "./dynamicResolver.js";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Dynamic Arguments Module
3
+ *
4
+ * Resolves function-valued options to their actual values before
5
+ * provider dispatch. All type definitions live in `src/lib/types/dynamic.ts`.
6
+ *
7
+ * @module dynamic
8
+ */
9
+ // Type guards
10
+ export { isDynamicFunction, isContextAwareFunction } from "./resolution.js";
11
+ // Resolution utilities
12
+ export { resolveDynamicArgument, resolveDynamicArguments, resolveDynamicConfig, memoizeDynamicArgument, withFallback, conditional, mapDynamicArgument, combineDynamicArguments, hasDynamicArgument, hasDynamicProperties, clearResolutionCache, getResolutionCacheStats, destroyResolver, resolutionCache, interpolateEnvVars, fromEnv, envVar, envSwitch, envJson, envNumber, envBoolean, envList, } from "./dynamicResolver.js";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Dynamic Arguments Runtime Utilities
3
+ *
4
+ * Provides type guard functions for dynamic argument resolution.
5
+ * Type definitions live in src/lib/types/dynamic.ts (canonical location).
6
+ *
7
+ * @module dynamic/resolution
8
+ */
9
+ import type { DynamicArgument, DynamicResolutionContext } from "../types/index.js";
10
+ /**
11
+ * Type guard to check if a value is a DynamicArgument function
12
+ */
13
+ export declare function isDynamicFunction<T>(value: DynamicArgument<T>): value is (() => T) | (() => Promise<T>) | ((context: DynamicResolutionContext) => T) | ((context: DynamicResolutionContext) => Promise<T>);
14
+ /**
15
+ * Type guard to check if a function expects context
16
+ */
17
+ export declare function isContextAwareFunction<T>(fn: Function): fn is ((context: DynamicResolutionContext) => T) | ((context: DynamicResolutionContext) => Promise<T>);
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Dynamic Arguments Runtime Utilities
3
+ *
4
+ * Provides type guard functions for dynamic argument resolution.
5
+ * Type definitions live in src/lib/types/dynamic.ts (canonical location).
6
+ *
7
+ * @module dynamic/resolution
8
+ */
9
+ /**
10
+ * Type guard to check if a value is a DynamicArgument function
11
+ */
12
+ export function isDynamicFunction(value) {
13
+ return typeof value === "function";
14
+ }
15
+ /**
16
+ * Type guard to check if a function expects context
17
+ */
18
+ export function isContextAwareFunction(fn) {
19
+ // Check function parameter count
20
+ return fn.length > 0;
21
+ }
@@ -14,7 +14,7 @@ export * from "./pipeline/index.js";
14
14
  export * from "./reporting/index.js";
15
15
  // Re-export scorers
16
16
  export * from "./scorers/index.js";
17
- // Re-export Factory and Registry (Mastra-inspired patterns)
17
+ // Re-export Factory and Registry
18
18
  export { BatchEvaluator } from "./BatchEvaluator.js";
19
19
  export { EvaluationAggregator } from "./EvaluationAggregator.js";
20
20
  export { EvaluatorFactory, getEvaluatorFactory } from "./EvaluatorFactory.js";