@goreal-ai/echo-pdk 0.1.0

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 (53) hide show
  1. package/dist/ai-judge/index.d.ts +177 -0
  2. package/dist/ai-judge/index.d.ts.map +1 -0
  3. package/dist/ai-judge/index.js +299 -0
  4. package/dist/ai-judge/index.js.map +1 -0
  5. package/dist/evaluator/evaluator.d.ts +136 -0
  6. package/dist/evaluator/evaluator.d.ts.map +1 -0
  7. package/dist/evaluator/evaluator.js +407 -0
  8. package/dist/evaluator/evaluator.js.map +1 -0
  9. package/dist/evaluator/index.d.ts +7 -0
  10. package/dist/evaluator/index.d.ts.map +1 -0
  11. package/dist/evaluator/index.js +8 -0
  12. package/dist/evaluator/index.js.map +1 -0
  13. package/dist/evaluator/operators.d.ts +105 -0
  14. package/dist/evaluator/operators.d.ts.map +1 -0
  15. package/dist/evaluator/operators.js +371 -0
  16. package/dist/evaluator/operators.js.map +1 -0
  17. package/dist/index.d.ts +115 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +388 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/parser/ast.d.ts +106 -0
  22. package/dist/parser/ast.d.ts.map +1 -0
  23. package/dist/parser/ast.js +260 -0
  24. package/dist/parser/ast.js.map +1 -0
  25. package/dist/parser/index.d.ts +8 -0
  26. package/dist/parser/index.d.ts.map +1 -0
  27. package/dist/parser/index.js +13 -0
  28. package/dist/parser/index.js.map +1 -0
  29. package/dist/parser/lexer.d.ts +199 -0
  30. package/dist/parser/lexer.d.ts.map +1 -0
  31. package/dist/parser/lexer.js +491 -0
  32. package/dist/parser/lexer.js.map +1 -0
  33. package/dist/parser/parser.d.ts +49 -0
  34. package/dist/parser/parser.d.ts.map +1 -0
  35. package/dist/parser/parser.js +615 -0
  36. package/dist/parser/parser.js.map +1 -0
  37. package/dist/plugins/index.d.ts +62 -0
  38. package/dist/plugins/index.d.ts.map +1 -0
  39. package/dist/plugins/index.js +170 -0
  40. package/dist/plugins/index.js.map +1 -0
  41. package/dist/renderer/index.d.ts +6 -0
  42. package/dist/renderer/index.d.ts.map +1 -0
  43. package/dist/renderer/index.js +5 -0
  44. package/dist/renderer/index.js.map +1 -0
  45. package/dist/renderer/renderer.d.ts +97 -0
  46. package/dist/renderer/renderer.d.ts.map +1 -0
  47. package/dist/renderer/renderer.js +243 -0
  48. package/dist/renderer/renderer.js.map +1 -0
  49. package/dist/types.d.ts +255 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +9 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +54 -0
@@ -0,0 +1,177 @@
1
+ /**
2
+ * @fileoverview AI Judge - LLM-based condition evaluation
3
+ *
4
+ * This module handles the #ai_judge operator which queries an LLM
5
+ * to evaluate boolean conditions.
6
+ *
7
+ * FEATURES:
8
+ * - Provider abstraction for different backends (OpenAI, Anthropic)
9
+ * - Automatic caching with TTL to avoid redundant API calls
10
+ * - Structured prompts for consistent yes/no answers
11
+ * - Graceful error handling
12
+ *
13
+ * API KEY CONFIGURATION:
14
+ * The API key can be provided in three ways (in priority order):
15
+ * 1. Programmatic: createEcho({ aiProvider: { apiKey: '...' } })
16
+ * 2. Environment: ECHO_API_KEY or OPENAI_API_KEY
17
+ * 3. Config file: echo.config.yaml (aiProvider.apiKey)
18
+ */
19
+ import type { AIProviderConfig } from '../types.js';
20
+ /**
21
+ * AI Provider interface for evaluating boolean conditions.
22
+ */
23
+ export interface AIProvider {
24
+ /**
25
+ * Evaluate a boolean question about a value.
26
+ *
27
+ * @param value - The value to evaluate
28
+ * @param question - The yes/no question to ask
29
+ * @returns true or false based on the AI's response
30
+ */
31
+ evaluate(value: unknown, question: string): Promise<boolean>;
32
+ }
33
+ /**
34
+ * Create an OpenAI-based AI provider.
35
+ *
36
+ * @param config - Configuration with API key and model
37
+ * @returns AIProvider using OpenAI
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const provider = createOpenAIProvider({
42
+ * type: 'openai',
43
+ * apiKey: process.env.OPENAI_API_KEY,
44
+ * model: 'gpt-4o-mini',
45
+ * });
46
+ *
47
+ * const result = await provider.evaluate(
48
+ * 'This is a family-friendly movie.',
49
+ * 'Is this content appropriate for children?'
50
+ * );
51
+ * ```
52
+ */
53
+ export declare function createOpenAIProvider(config: AIProviderConfig): AIProvider;
54
+ /**
55
+ * Build the prompt for the AI judge.
56
+ *
57
+ * The prompt is designed to get a clear yes/no answer.
58
+ *
59
+ * @param value - The value to evaluate
60
+ * @param question - The question to ask
61
+ * @returns Formatted prompt string
62
+ */
63
+ export declare function buildPrompt(value: unknown, question: string): string;
64
+ /**
65
+ * Create an AI Judge instance with the given configuration.
66
+ *
67
+ * @param config - AI provider configuration
68
+ * @returns An AIProvider implementation
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const judge = createAIJudge({
73
+ * type: 'openai',
74
+ * apiKey: process.env.OPENAI_API_KEY,
75
+ * });
76
+ *
77
+ * const isAppropriate = await judge.evaluate(content, 'Is this safe for work?');
78
+ * ```
79
+ */
80
+ export declare function createAIJudge(config: AIProviderConfig): AIProvider;
81
+ /**
82
+ * Options for creating a cache key.
83
+ */
84
+ export interface CacheKeyOptions {
85
+ /** The value being evaluated (can be very large, e.g., 200K tokens) */
86
+ value: unknown;
87
+ /** The boolean question to ask */
88
+ question: string;
89
+ /** The AI provider type (e.g., 'openai', 'anthropic') */
90
+ provider?: string;
91
+ /** The model identifier (e.g., 'gpt-4o-mini') */
92
+ model?: string;
93
+ }
94
+ /**
95
+ * Create a cache key for an AI judge evaluation.
96
+ *
97
+ * Uses SHA-256 hashing to create a fixed-size key regardless of input size.
98
+ * This is critical because the value being evaluated can be extremely large
99
+ * (e.g., a 200K token document). Storing the raw value as a Map key would
100
+ * cause severe memory bloat.
101
+ *
102
+ * The hash includes provider and model to prevent cache collisions when
103
+ * multiple Echo instances use different AI configurations.
104
+ *
105
+ * @param options - The cache key options
106
+ * @returns A 64-character hex hash string
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const key = createCacheKey({
111
+ * value: largeDocument,
112
+ * question: 'Is this appropriate?',
113
+ * provider: 'openai',
114
+ * model: 'gpt-4o-mini',
115
+ * });
116
+ * // Returns: "a8f4b2c1e9d3..." (64 chars)
117
+ * ```
118
+ */
119
+ export declare function createCacheKey(options: CacheKeyOptions): string;
120
+ /**
121
+ * Get a cached result if available and not expired.
122
+ *
123
+ * @param key - The cache key
124
+ * @returns The cached result or undefined if not found/expired
125
+ */
126
+ export declare function getCached(key: string): boolean | undefined;
127
+ /**
128
+ * Store a result in the cache.
129
+ *
130
+ * @param key - The cache key
131
+ * @param result - The result to cache
132
+ */
133
+ export declare function setCache(key: string, result: boolean): void;
134
+ /**
135
+ * Clear the entire cache.
136
+ */
137
+ export declare function clearCache(): void;
138
+ /**
139
+ * Get the current cache size (for testing/debugging).
140
+ */
141
+ export declare function getCacheSize(): number;
142
+ /**
143
+ * Options for the caching wrapper.
144
+ */
145
+ export interface WithCacheOptions {
146
+ /** The AI provider type for cache key isolation */
147
+ providerType: string;
148
+ /** The model identifier for cache key isolation */
149
+ model: string;
150
+ }
151
+ /**
152
+ * Wrap an AI provider with caching.
153
+ *
154
+ * The cache is isolated by provider type and model to prevent collisions
155
+ * when multiple Echo instances use different AI configurations.
156
+ *
157
+ * @param provider - The AI provider to wrap
158
+ * @param options - Cache options including provider/model for key isolation
159
+ * @returns A caching wrapper around the provider
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * const provider = createOpenAIProvider(config);
164
+ * const cachedProvider = withCache(provider, {
165
+ * providerType: 'openai',
166
+ * model: 'gpt-4o-mini',
167
+ * });
168
+ *
169
+ * // First call hits the API
170
+ * const result1 = await cachedProvider.evaluate(value, question);
171
+ *
172
+ * // Second call with same inputs returns cached result
173
+ * const result2 = await cachedProvider.evaluate(value, question);
174
+ * ```
175
+ */
176
+ export declare function withCache(provider: AIProvider, options: WithCacheOptions): AIProvider;
177
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai-judge/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAiCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA0DzE;AAyCD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUpE;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAclE;AAYD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,uEAAuE;IACvE,KAAK,EAAE,OAAO,CAAC;IACf,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAI/D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAW1D;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAK3D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,GAAG,UAAU,CA2BrF"}
@@ -0,0 +1,299 @@
1
+ /**
2
+ * @fileoverview AI Judge - LLM-based condition evaluation
3
+ *
4
+ * This module handles the #ai_judge operator which queries an LLM
5
+ * to evaluate boolean conditions.
6
+ *
7
+ * FEATURES:
8
+ * - Provider abstraction for different backends (OpenAI, Anthropic)
9
+ * - Automatic caching with TTL to avoid redundant API calls
10
+ * - Structured prompts for consistent yes/no answers
11
+ * - Graceful error handling
12
+ *
13
+ * API KEY CONFIGURATION:
14
+ * The API key can be provided in three ways (in priority order):
15
+ * 1. Programmatic: createEcho({ aiProvider: { apiKey: '...' } })
16
+ * 2. Environment: ECHO_API_KEY or OPENAI_API_KEY
17
+ * 3. Config file: echo.config.yaml (aiProvider.apiKey)
18
+ */
19
+ import { createHash } from 'crypto';
20
+ // =============================================================================
21
+ // OPENAI PROVIDER
22
+ // =============================================================================
23
+ /**
24
+ * Create an OpenAI-based AI provider.
25
+ *
26
+ * @param config - Configuration with API key and model
27
+ * @returns AIProvider using OpenAI
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const provider = createOpenAIProvider({
32
+ * type: 'openai',
33
+ * apiKey: process.env.OPENAI_API_KEY,
34
+ * model: 'gpt-4o-mini',
35
+ * });
36
+ *
37
+ * const result = await provider.evaluate(
38
+ * 'This is a family-friendly movie.',
39
+ * 'Is this content appropriate for children?'
40
+ * );
41
+ * ```
42
+ */
43
+ export function createOpenAIProvider(config) {
44
+ const apiKey = config.apiKey;
45
+ const model = config.model ?? 'gpt-4o-mini';
46
+ const timeout = config.timeout ?? 30000;
47
+ if (!apiKey) {
48
+ throw new Error('OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it in config.');
49
+ }
50
+ return {
51
+ async evaluate(value, question) {
52
+ const prompt = buildPrompt(value, question);
53
+ const messages = [
54
+ {
55
+ role: 'system',
56
+ content: 'You are a precise yes/no evaluator. Answer ONLY with "yes" or "no" (lowercase, no punctuation). Do not explain or elaborate.',
57
+ },
58
+ {
59
+ role: 'user',
60
+ content: prompt,
61
+ },
62
+ ];
63
+ try {
64
+ const response = await callOpenAI(apiKey, model, messages, timeout);
65
+ const answer = response.choices[0]?.message?.content?.trim().toLowerCase();
66
+ if (answer === 'yes') {
67
+ return true;
68
+ }
69
+ if (answer === 'no') {
70
+ return false;
71
+ }
72
+ // Unexpected response - try to interpret
73
+ if (answer?.includes('yes')) {
74
+ return true;
75
+ }
76
+ if (answer?.includes('no')) {
77
+ return false;
78
+ }
79
+ // Default to false for ambiguous responses
80
+ console.warn(`AI Judge returned unexpected response: "${answer}". Defaulting to false.`);
81
+ return false;
82
+ }
83
+ catch (error) {
84
+ // Re-throw with more context
85
+ if (error instanceof Error) {
86
+ throw new Error(`AI Judge evaluation failed: ${error.message}`);
87
+ }
88
+ throw new Error('AI Judge evaluation failed: Unknown error');
89
+ }
90
+ },
91
+ };
92
+ }
93
+ /**
94
+ * Call the OpenAI Chat Completions API.
95
+ */
96
+ async function callOpenAI(apiKey, model, messages, timeout) {
97
+ const controller = new AbortController();
98
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
99
+ try {
100
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
101
+ method: 'POST',
102
+ headers: {
103
+ 'Content-Type': 'application/json',
104
+ Authorization: `Bearer ${apiKey}`,
105
+ },
106
+ body: JSON.stringify({
107
+ model,
108
+ messages,
109
+ max_tokens: 10,
110
+ temperature: 0, // Deterministic responses
111
+ }),
112
+ signal: controller.signal,
113
+ });
114
+ if (!response.ok) {
115
+ const errorBody = await response.text();
116
+ throw new Error(`OpenAI API error (${response.status}): ${errorBody}`);
117
+ }
118
+ return (await response.json());
119
+ }
120
+ finally {
121
+ clearTimeout(timeoutId);
122
+ }
123
+ }
124
+ /**
125
+ * Build the prompt for the AI judge.
126
+ *
127
+ * The prompt is designed to get a clear yes/no answer.
128
+ *
129
+ * @param value - The value to evaluate
130
+ * @param question - The question to ask
131
+ * @returns Formatted prompt string
132
+ */
133
+ export function buildPrompt(value, question) {
134
+ const valueStr = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
135
+ return `Given the following value:
136
+ ---
137
+ ${valueStr}
138
+ ---
139
+
140
+ Answer with ONLY "yes" or "no":
141
+ ${question}`;
142
+ }
143
+ // =============================================================================
144
+ // AI JUDGE FACTORY
145
+ // =============================================================================
146
+ /**
147
+ * Create an AI Judge instance with the given configuration.
148
+ *
149
+ * @param config - AI provider configuration
150
+ * @returns An AIProvider implementation
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const judge = createAIJudge({
155
+ * type: 'openai',
156
+ * apiKey: process.env.OPENAI_API_KEY,
157
+ * });
158
+ *
159
+ * const isAppropriate = await judge.evaluate(content, 'Is this safe for work?');
160
+ * ```
161
+ */
162
+ export function createAIJudge(config) {
163
+ switch (config.type) {
164
+ case 'openai':
165
+ return createOpenAIProvider(config);
166
+ case 'anthropic':
167
+ // TODO: Implement Anthropic provider
168
+ throw new Error('Anthropic provider not yet implemented. Use OpenAI for now.');
169
+ default:
170
+ throw new Error(`Unknown AI provider type: ${config.type}`);
171
+ }
172
+ }
173
+ // =============================================================================
174
+ // CACHING
175
+ // =============================================================================
176
+ /** Module-level cache for AI judge results */
177
+ const cache = new Map();
178
+ /** Cache TTL in milliseconds (5 minutes) */
179
+ const CACHE_TTL = 5 * 60 * 1000;
180
+ /**
181
+ * Create a cache key for an AI judge evaluation.
182
+ *
183
+ * Uses SHA-256 hashing to create a fixed-size key regardless of input size.
184
+ * This is critical because the value being evaluated can be extremely large
185
+ * (e.g., a 200K token document). Storing the raw value as a Map key would
186
+ * cause severe memory bloat.
187
+ *
188
+ * The hash includes provider and model to prevent cache collisions when
189
+ * multiple Echo instances use different AI configurations.
190
+ *
191
+ * @param options - The cache key options
192
+ * @returns A 64-character hex hash string
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * const key = createCacheKey({
197
+ * value: largeDocument,
198
+ * question: 'Is this appropriate?',
199
+ * provider: 'openai',
200
+ * model: 'gpt-4o-mini',
201
+ * });
202
+ * // Returns: "a8f4b2c1e9d3..." (64 chars)
203
+ * ```
204
+ */
205
+ export function createCacheKey(options) {
206
+ const { value, question, provider, model } = options;
207
+ const data = JSON.stringify({ value, question, provider, model });
208
+ return createHash('sha256').update(data).digest('hex');
209
+ }
210
+ /**
211
+ * Get a cached result if available and not expired.
212
+ *
213
+ * @param key - The cache key
214
+ * @returns The cached result or undefined if not found/expired
215
+ */
216
+ export function getCached(key) {
217
+ const entry = cache.get(key);
218
+ if (!entry)
219
+ return undefined;
220
+ // Check if expired
221
+ if (Date.now() - entry.timestamp > CACHE_TTL) {
222
+ cache.delete(key);
223
+ return undefined;
224
+ }
225
+ return entry.result;
226
+ }
227
+ /**
228
+ * Store a result in the cache.
229
+ *
230
+ * @param key - The cache key
231
+ * @param result - The result to cache
232
+ */
233
+ export function setCache(key, result) {
234
+ cache.set(key, {
235
+ result,
236
+ timestamp: Date.now(),
237
+ });
238
+ }
239
+ /**
240
+ * Clear the entire cache.
241
+ */
242
+ export function clearCache() {
243
+ cache.clear();
244
+ }
245
+ /**
246
+ * Get the current cache size (for testing/debugging).
247
+ */
248
+ export function getCacheSize() {
249
+ return cache.size;
250
+ }
251
+ /**
252
+ * Wrap an AI provider with caching.
253
+ *
254
+ * The cache is isolated by provider type and model to prevent collisions
255
+ * when multiple Echo instances use different AI configurations.
256
+ *
257
+ * @param provider - The AI provider to wrap
258
+ * @param options - Cache options including provider/model for key isolation
259
+ * @returns A caching wrapper around the provider
260
+ *
261
+ * @example
262
+ * ```typescript
263
+ * const provider = createOpenAIProvider(config);
264
+ * const cachedProvider = withCache(provider, {
265
+ * providerType: 'openai',
266
+ * model: 'gpt-4o-mini',
267
+ * });
268
+ *
269
+ * // First call hits the API
270
+ * const result1 = await cachedProvider.evaluate(value, question);
271
+ *
272
+ * // Second call with same inputs returns cached result
273
+ * const result2 = await cachedProvider.evaluate(value, question);
274
+ * ```
275
+ */
276
+ export function withCache(provider, options) {
277
+ const { providerType, model } = options;
278
+ return {
279
+ async evaluate(value, question) {
280
+ const key = createCacheKey({
281
+ value,
282
+ question,
283
+ provider: providerType,
284
+ model,
285
+ });
286
+ // Check cache first
287
+ const cached = getCached(key);
288
+ if (cached !== undefined) {
289
+ return cached;
290
+ }
291
+ // Call the provider
292
+ const result = await provider.evaluate(value, question);
293
+ // Cache the result
294
+ setCache(key, result);
295
+ return result;
296
+ },
297
+ };
298
+ }
299
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai-judge/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @fileoverview Echo Evaluator - Condition evaluation engine
3
+ *
4
+ * This file implements the evaluator for Echo DSL.
5
+ * The evaluator processes the AST and determines which nodes should be rendered
6
+ * based on the provided context and condition evaluation.
7
+ *
8
+ * KEY OPTIMIZATION: AI JUDGE PARALLELIZATION
9
+ * Before evaluating the AST, we:
10
+ * 1. Collect ALL #ai_judge conditions from the tree
11
+ * 2. Evaluate them in parallel using Promise.all
12
+ * 3. Cache the results
13
+ * 4. Use cached results during tree evaluation
14
+ *
15
+ * This prevents sequential blocking on AI calls.
16
+ */
17
+ import type { ASTNode, ConditionalNode, ConditionExpr, EchoConfig, OperatorDefinition } from '../types.js';
18
+ /**
19
+ * Evaluation context containing variables and resolved AI judges.
20
+ */
21
+ export interface EvaluationContext {
22
+ /** Variables from user context */
23
+ variables: Record<string, unknown>;
24
+ /** Pre-resolved AI judge results (from parallel evaluation) */
25
+ aiJudgeResults: Map<string, boolean>;
26
+ /** Configuration */
27
+ config: EchoConfig;
28
+ /** Registered sections (for [#INCLUDE]) */
29
+ sections: Map<string, ASTNode[]>;
30
+ /** Custom operators (plugins) */
31
+ operators: Map<string, OperatorDefinition>;
32
+ }
33
+ /**
34
+ * Result of evaluating a node.
35
+ */
36
+ export interface EvaluatedNode {
37
+ /** The original node */
38
+ node: ASTNode;
39
+ /** Whether this node should be rendered */
40
+ shouldRender: boolean;
41
+ /** For conditionals: the branch to render */
42
+ selectedBranch?: ASTNode[];
43
+ }
44
+ /**
45
+ * Options for variable resolution.
46
+ */
47
+ export interface ResolveVariableOptions {
48
+ /** Whether to throw on malformed paths (default: false) */
49
+ strict?: boolean;
50
+ }
51
+ /**
52
+ * Resolve a variable path from context.
53
+ *
54
+ * Supports:
55
+ * - Simple: "name" -> context.name
56
+ * - Nested: "user.name" -> context.user.name
57
+ * - Array: "items[0]" -> context.items[0]
58
+ * - Mixed: "users[0].name" -> context.users[0].name
59
+ *
60
+ * @param path - The variable path
61
+ * @param context - The context object
62
+ * @param options - Resolution options
63
+ * @returns The resolved value or undefined
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const context = { user: { name: 'Alice' }, items: [1, 2, 3] };
68
+ * resolveVariable('user.name', context); // 'Alice'
69
+ * resolveVariable('items[0]', context); // 1
70
+ * ```
71
+ */
72
+ export declare function resolveVariable(path: string, context: Record<string, unknown>, options?: ResolveVariableOptions): unknown;
73
+ /**
74
+ * Evaluate a condition expression.
75
+ *
76
+ * @param condition - The condition to evaluate
77
+ * @param ctx - The evaluation context
78
+ * @returns true if condition is satisfied
79
+ */
80
+ export declare function evaluateCondition(condition: ConditionExpr, ctx: EvaluationContext): Promise<boolean>;
81
+ /**
82
+ * Pre-evaluate all AI judge conditions in parallel.
83
+ *
84
+ * This is the key optimization for performance.
85
+ * Call this before evaluating the AST to pre-resolve all AI conditions.
86
+ *
87
+ * @param ast - The AST to scan for AI judges
88
+ * @param ctx - The evaluation context (will be mutated with results)
89
+ */
90
+ export declare function preEvaluateAiJudges(ast: ASTNode[], ctx: EvaluationContext): Promise<void>;
91
+ /**
92
+ * Evaluate a conditional node and determine which branch to render.
93
+ *
94
+ * @param node - The conditional node
95
+ * @param ctx - The evaluation context
96
+ * @returns The nodes to render (empty if condition is false with no else)
97
+ */
98
+ export declare function evaluateConditional(node: ConditionalNode, ctx: EvaluationContext): Promise<ASTNode[]>;
99
+ /**
100
+ * Evaluate an AST with the given context.
101
+ *
102
+ * This is the main entry point for AST evaluation. It:
103
+ * 1. Collects section definitions (first pass)
104
+ * 2. Pre-evaluates AI judge conditions in parallel
105
+ * 3. Evaluates the AST and selects conditional branches
106
+ * 4. Returns a flattened AST ready for rendering
107
+ *
108
+ * @param ast - The AST to evaluate
109
+ * @param context - Variable context
110
+ * @param config - Echo configuration
111
+ * @param operators - Custom operators (from plugins)
112
+ * @returns Evaluated AST and section map
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const result = await evaluate(ast, { name: 'Alice', age: 25 });
117
+ * console.log(result.ast); // Flattened, evaluated AST
118
+ * ```
119
+ */
120
+ export declare function evaluate(ast: ASTNode[], context: Record<string, unknown>, config?: EchoConfig, operators?: Map<string, OperatorDefinition>): Promise<{
121
+ ast: ASTNode[];
122
+ sections: Map<string, ASTNode[]>;
123
+ }>;
124
+ /**
125
+ * Create an evaluation context manually.
126
+ * Useful for advanced use cases where you need more control.
127
+ *
128
+ * @param options - Context options
129
+ * @returns A new EvaluationContext
130
+ */
131
+ export declare function createEvaluationContext(options: {
132
+ variables: Record<string, unknown>;
133
+ config?: EchoConfig;
134
+ operators?: Map<string, OperatorDefinition>;
135
+ }): EvaluationContext;
136
+ //# sourceMappingURL=evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/evaluator/evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EAGf,aAAa,EACb,UAAU,EACV,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAQrB;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,+DAA+D;IAC/D,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,oBAAoB;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,2CAA2C;IAC3C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACjC,iCAAiC;IACjC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,2CAA2C;IAC3C,YAAY,EAAE,OAAO,CAAC;IACtB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC;CAC5B;AAMD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAiDT;AAqDD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,aAAa,EACxB,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,OAAO,CAAC,CAwClB;AAiBD;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,OAAO,EAAE,EACd,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Cf;AAMD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,OAAO,EAAE,CAAC,CAqBpB;AA+HD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,OAAO,EAAE,EACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,GAAE,UAAe,EACvB,SAAS,GAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAa,GACrD,OAAO,CAAC;IAAE,GAAG,EAAE,OAAO,EAAE,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC,CAoB/D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC7C,GAAG,iBAAiB,CAQpB"}