@affectively/aeon-pages-runtime 0.3.1 → 0.5.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.
@@ -0,0 +1,4021 @@
1
+ import {
2
+ __esm,
3
+ __export,
4
+ __toCommonJS
5
+ } from "./chunk-tgx0r0vn.js";
6
+
7
+ // src/router/esi-cyrano.ts
8
+ function esiContext(context, options = {}) {
9
+ const { emitExhaust = true, id } = options;
10
+ return {
11
+ id: id || `esi-context-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
12
+ params: {
13
+ model: "custom",
14
+ custom: {
15
+ type: "context-drop",
16
+ emitExhaust
17
+ }
18
+ },
19
+ content: {
20
+ type: "json",
21
+ value: JSON.stringify(context)
22
+ },
23
+ contextAware: true,
24
+ signals: ["emotion", "preferences", "history", "time", "device"]
25
+ };
26
+ }
27
+ function esiCyrano(config, options = {}) {
28
+ const {
29
+ intent,
30
+ tone = "warm",
31
+ trigger = "always",
32
+ fallback,
33
+ suggestTool,
34
+ suggestRoute,
35
+ autoAcceptNavigation = false,
36
+ priority = 1,
37
+ maxTriggersPerSession,
38
+ cooldownSeconds,
39
+ speak = false,
40
+ showCaption = true,
41
+ requiredTier
42
+ } = config;
43
+ const systemPrompt = buildCyranoSystemPrompt(intent, tone);
44
+ return {
45
+ id: `esi-cyrano-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
46
+ params: {
47
+ model: "llm",
48
+ system: systemPrompt,
49
+ temperature: 0.7,
50
+ maxTokens: 150,
51
+ fallback,
52
+ custom: {
53
+ type: "cyrano-whisper",
54
+ intent,
55
+ tone,
56
+ trigger,
57
+ suggestTool,
58
+ suggestRoute,
59
+ autoAcceptNavigation,
60
+ priority,
61
+ maxTriggersPerSession,
62
+ cooldownSeconds,
63
+ speak,
64
+ showCaption
65
+ },
66
+ ...options
67
+ },
68
+ content: {
69
+ type: "template",
70
+ value: buildCyranoPrompt(intent, trigger),
71
+ variables: {
72
+ intent,
73
+ tone,
74
+ trigger
75
+ }
76
+ },
77
+ contextAware: true,
78
+ signals: ["emotion", "preferences", "history", "time"],
79
+ requiredTier
80
+ };
81
+ }
82
+ function buildCyranoSystemPrompt(intent, tone) {
83
+ const toneGuide = {
84
+ warm: "Be warm, caring, and approachable. Use gentle language.",
85
+ calm: "Be calm, measured, and reassuring. Use a steady pace.",
86
+ encouraging: "Be supportive and uplifting. Celebrate small wins.",
87
+ playful: "Be light-hearted and fun. Use appropriate humor.",
88
+ professional: "Be clear and direct. Maintain professionalism.",
89
+ empathetic: "Show deep understanding. Validate feelings.",
90
+ neutral: "Be balanced and objective. Provide information."
91
+ };
92
+ const intentGuide = {
93
+ greeting: "Welcome the user. Make them feel at home.",
94
+ "proactive-check-in": "Check in gently. Ask how they are doing.",
95
+ "supportive-presence": "Simply acknowledge. Let them know you are here.",
96
+ "gentle-nudge": "Suggest an action softly. No pressure.",
97
+ "tool-suggestion": "Recommend a tool that might help.",
98
+ "navigation-hint": "Suggest exploring another area.",
99
+ intervention: "Step in supportively. Offer help.",
100
+ celebration: "Celebrate their progress. Be genuinely happy for them.",
101
+ reflection: "Invite them to reflect. Ask thoughtful questions.",
102
+ guidance: "Offer helpful guidance. Be a trusted advisor.",
103
+ farewell: "Wish them well. Leave the door open.",
104
+ custom: "Respond appropriately to the context."
105
+ };
106
+ return `You are Cyrano, an ambient AI companion. ${toneGuide[tone]} ${intentGuide[intent]}
107
+
108
+ Keep responses brief (1-2 sentences). Be natural and conversational.
109
+ Never start with "I" - use "You" or the situation as the subject.
110
+ Never say "As an AI" or similar phrases.
111
+ Respond to the emotional context provided.`;
112
+ }
113
+ function buildCyranoPrompt(intent, trigger) {
114
+ const prompts = {
115
+ greeting: "Generate a warm greeting based on the time of day and user context.",
116
+ "proactive-check-in": "Check in with the user based on their emotional state and behavior.",
117
+ "supportive-presence": "Acknowledge the user's presence and current activity.",
118
+ "gentle-nudge": "Gently suggest the user might benefit from a particular action.",
119
+ "tool-suggestion": "Suggest a specific tool that could help with the user's current state.",
120
+ "navigation-hint": "Suggest the user might want to explore a different area.",
121
+ intervention: "Offer supportive intervention based on detected stress or difficulty.",
122
+ celebration: "Celebrate the user's progress or achievement.",
123
+ reflection: "Invite the user to reflect on their current experience.",
124
+ guidance: "Offer helpful guidance for the user's current situation.",
125
+ farewell: "Say goodbye warmly, acknowledging the session.",
126
+ custom: "Respond appropriately to the context provided."
127
+ };
128
+ let prompt = prompts[intent] || prompts.custom;
129
+ if (trigger !== "always" && trigger !== "never") {
130
+ prompt += ` The trigger condition is: ${trigger}.`;
131
+ }
132
+ return prompt;
133
+ }
134
+ function esiHalo(config, options = {}) {
135
+ const {
136
+ observe,
137
+ window: window2 = "session",
138
+ action = "whisper-to-cyrano",
139
+ sensitivity = 0.5,
140
+ crisisLevel = false,
141
+ parameters = {}
142
+ } = config;
143
+ return {
144
+ id: `esi-halo-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
145
+ params: {
146
+ model: "custom",
147
+ custom: {
148
+ type: "halo-insight",
149
+ observe,
150
+ window: window2,
151
+ action,
152
+ sensitivity,
153
+ crisisLevel,
154
+ parameters
155
+ },
156
+ ...options
157
+ },
158
+ content: {
159
+ type: "json",
160
+ value: JSON.stringify({
161
+ observation: observe,
162
+ window: window2,
163
+ action,
164
+ sensitivity,
165
+ crisisLevel
166
+ })
167
+ },
168
+ contextAware: true,
169
+ signals: ["emotion", "history", "time"]
170
+ };
171
+ }
172
+ function evaluateTrigger(trigger, context, sessionContext) {
173
+ if (trigger === "always")
174
+ return true;
175
+ if (trigger === "never")
176
+ return false;
177
+ const [type, condition] = trigger.split(":");
178
+ switch (type) {
179
+ case "dwell": {
180
+ const match = condition?.match(/>(\d+)s/);
181
+ if (!match)
182
+ return false;
183
+ const threshold = parseInt(match[1], 10) * 1000;
184
+ const dwellTime = sessionContext?.behavior?.dwellTime || 0;
185
+ return dwellTime > threshold;
186
+ }
187
+ case "scroll": {
188
+ const match = condition?.match(/>(\d+\.?\d*)/);
189
+ if (!match)
190
+ return false;
191
+ const threshold = parseFloat(match[1]);
192
+ const scrollDepth = sessionContext?.behavior?.scrollDepth || 0;
193
+ return scrollDepth > threshold;
194
+ }
195
+ case "emotion": {
196
+ const targetEmotion = condition;
197
+ return sessionContext?.emotion?.primary === targetEmotion || context.emotionState?.primary === targetEmotion;
198
+ }
199
+ case "behavior": {
200
+ if (condition === "aimless") {
201
+ return sessionContext?.behavior?.isAimlessClicking === true;
202
+ }
203
+ if (condition === "hesitation") {
204
+ return sessionContext?.behavior?.hesitationDetected === true;
205
+ }
206
+ return false;
207
+ }
208
+ case "hrv": {
209
+ const match = condition?.match(/<(\d+)/);
210
+ if (!match)
211
+ return false;
212
+ const threshold = parseInt(match[1], 10);
213
+ const hrv = sessionContext?.biometric?.hrv || 100;
214
+ return hrv < threshold;
215
+ }
216
+ case "stress": {
217
+ const match = condition?.match(/>(\d+)/);
218
+ if (!match)
219
+ return false;
220
+ const threshold = parseInt(match[1], 10);
221
+ const stress = sessionContext?.biometric?.stressScore || 0;
222
+ return stress > threshold;
223
+ }
224
+ case "session": {
225
+ if (condition === "start") {
226
+ return context.isNewSession;
227
+ }
228
+ const idleMatch = condition?.match(/idle:(\d+)m/);
229
+ if (idleMatch) {
230
+ return false;
231
+ }
232
+ return false;
233
+ }
234
+ case "navigation": {
235
+ const targetRoute = condition?.replace("to:", "");
236
+ return sessionContext?.currentRoute === targetRoute;
237
+ }
238
+ case "time": {
239
+ const hour = context.localHour;
240
+ if (condition === "morning")
241
+ return hour >= 6 && hour < 12;
242
+ if (condition === "afternoon")
243
+ return hour >= 12 && hour < 18;
244
+ if (condition === "evening")
245
+ return hour >= 18 && hour < 22;
246
+ if (condition === "night")
247
+ return hour >= 22 || hour < 6;
248
+ return false;
249
+ }
250
+ default:
251
+ return false;
252
+ }
253
+ }
254
+ function createExhaustEntry(directive, result, type) {
255
+ return {
256
+ type,
257
+ timestamp: Date.now(),
258
+ content: {
259
+ directiveId: directive.id,
260
+ output: result.output,
261
+ model: result.model,
262
+ success: result.success,
263
+ latencyMs: result.latencyMs
264
+ },
265
+ visible: type === "cyrano" || type === "user",
266
+ source: directive.params.model
267
+ };
268
+ }
269
+ function getToolSuggestions(context, sessionContext) {
270
+ const suggestions = [];
271
+ for (const [, config] of Object.entries(CYRANO_TOOL_SUGGESTIONS)) {
272
+ for (const trigger of config.triggers) {
273
+ if (evaluateTrigger(trigger, context, sessionContext)) {
274
+ suggestions.push({
275
+ tool: config.tool,
276
+ reason: config.reason,
277
+ priority: trigger.startsWith("stress") || trigger.startsWith("hrv") ? 2 : 1
278
+ });
279
+ break;
280
+ }
281
+ }
282
+ }
283
+ return suggestions.sort((a, b) => b.priority - a.priority);
284
+ }
285
+ var CYRANO_TOOL_SUGGESTIONS;
286
+ var init_esi_cyrano = __esm(() => {
287
+ CYRANO_TOOL_SUGGESTIONS = {
288
+ breathing: {
289
+ triggers: ["stress:>70", "hrv:<40", "emotion:anxious"],
290
+ tool: "breathing/4-7-8",
291
+ reason: "You seem stressed - a breathing exercise might help"
292
+ },
293
+ grounding: {
294
+ triggers: ["emotion:overwhelmed", "behavior:aimless"],
295
+ tool: "grounding/5-4-3-2-1",
296
+ reason: "A grounding exercise can help center you"
297
+ },
298
+ journaling: {
299
+ triggers: ["dwell:>120s", "emotion:reflective"],
300
+ tool: "journaling/freeform",
301
+ reason: "Would you like to write about what's on your mind?"
302
+ },
303
+ insights: {
304
+ triggers: ["navigation:to:/insights", "dwell:>60s"],
305
+ tool: "insights/dashboard",
306
+ reason: "Your recent patterns are ready to explore"
307
+ }
308
+ };
309
+ });
310
+
311
+ // src/router/esi.ts
312
+ function getCacheKey(directive, context) {
313
+ const contextParts = directive.contextAware ? [
314
+ context.tier,
315
+ context.emotionState?.primary,
316
+ context.localHour
317
+ ].join(":") : "";
318
+ return directive.cacheKey || `esi:${directive.params.model}:${directive.content.value}:${contextParts}`;
319
+ }
320
+ function getCached(key) {
321
+ const entry = esiCache.get(key);
322
+ if (!entry)
323
+ return null;
324
+ if (Date.now() > entry.expiresAt) {
325
+ esiCache.delete(key);
326
+ return null;
327
+ }
328
+ return { ...entry.result, cached: true };
329
+ }
330
+ function setCache(key, result, ttl) {
331
+ if (ttl <= 0)
332
+ return;
333
+ esiCache.set(key, {
334
+ result,
335
+ expiresAt: Date.now() + ttl * 1000
336
+ });
337
+ }
338
+ function interpolatePrompt(content, context, signals = []) {
339
+ let prompt = content.value;
340
+ if (content.type === "template" && content.variables) {
341
+ for (const [key, value] of Object.entries(content.variables)) {
342
+ prompt = prompt.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), String(value));
343
+ }
344
+ }
345
+ if (signals.length > 0) {
346
+ const contextParts = [];
347
+ if (signals.includes("emotion") && context.emotionState) {
348
+ contextParts.push(`User emotion: ${context.emotionState.primary} ` + `(valence: ${context.emotionState.valence.toFixed(2)}, ` + `arousal: ${context.emotionState.arousal.toFixed(2)})`);
349
+ }
350
+ if (signals.includes("preferences") && Object.keys(context.preferences).length > 0) {
351
+ contextParts.push(`User preferences: ${JSON.stringify(context.preferences)}`);
352
+ }
353
+ if (signals.includes("history") && context.recentPages.length > 0) {
354
+ contextParts.push(`Recent pages: ${context.recentPages.slice(-5).join(", ")}`);
355
+ }
356
+ if (signals.includes("time")) {
357
+ contextParts.push(`Local time: ${context.localHour}:00, Timezone: ${context.timezone}`);
358
+ }
359
+ if (signals.includes("device")) {
360
+ contextParts.push(`Device: ${context.viewport.width}x${context.viewport.height}, ` + `Connection: ${context.connection}`);
361
+ }
362
+ if (contextParts.length > 0) {
363
+ prompt = `[Context]
364
+ ${contextParts.join(`
365
+ `)}
366
+
367
+ [Task]
368
+ ${prompt}`;
369
+ }
370
+ }
371
+ return prompt;
372
+ }
373
+ function checkTierAccess(directive, context, config) {
374
+ const tierLimits = config.tierLimits?.[context.tier];
375
+ if (!tierLimits) {
376
+ return { allowed: true };
377
+ }
378
+ if (!tierLimits.allowedModels.includes(directive.params.model)) {
379
+ return {
380
+ allowed: false,
381
+ reason: `Model '${directive.params.model}' not available for ${context.tier} tier`
382
+ };
383
+ }
384
+ if (directive.params.maxTokens && directive.params.maxTokens > tierLimits.maxTokens) {
385
+ return {
386
+ allowed: false,
387
+ reason: `Token limit ${directive.params.maxTokens} exceeds ${context.tier} tier max of ${tierLimits.maxTokens}`
388
+ };
389
+ }
390
+ return { allowed: true };
391
+ }
392
+
393
+ class EdgeWorkersESIProcessor {
394
+ name = "edge-workers";
395
+ config;
396
+ warmupPromise;
397
+ constructor(config = {}) {
398
+ this.config = {
399
+ enabled: config.enabled ?? false,
400
+ endpoint: config.endpoint || process.env.ESI_ENDPOINT || "",
401
+ timeout: config.timeout ?? 5000,
402
+ defaultCacheTtl: config.defaultCacheTtl ?? 300,
403
+ maxConcurrent: config.maxConcurrent ?? 5,
404
+ warmupModels: config.warmupModels,
405
+ tierLimits: config.tierLimits
406
+ };
407
+ }
408
+ async warmup() {
409
+ if (this.warmupPromise)
410
+ return this.warmupPromise;
411
+ this.warmupPromise = (async () => {
412
+ if (!this.config.warmupModels?.length)
413
+ return;
414
+ await Promise.all(this.config.warmupModels.map((model) => fetch(`${this.config.endpoint}/api/warmup`, {
415
+ method: "POST",
416
+ headers: { "Content-Type": "application/json" },
417
+ body: JSON.stringify({ model })
418
+ }).catch(() => {})));
419
+ })();
420
+ return this.warmupPromise;
421
+ }
422
+ isModelAvailable(model) {
423
+ return ["llm", "embed", "vision", "tts", "stt", "emotion", "classify", "custom"].includes(model);
424
+ }
425
+ async process(directive, context) {
426
+ const startTime = Date.now();
427
+ const cacheKey = getCacheKey(directive, context);
428
+ const cached = getCached(cacheKey);
429
+ if (cached) {
430
+ return cached;
431
+ }
432
+ const access = checkTierAccess(directive, context, this.config);
433
+ if (!access.allowed) {
434
+ return {
435
+ id: directive.id,
436
+ success: false,
437
+ error: access.reason,
438
+ latencyMs: Date.now() - startTime,
439
+ cached: false,
440
+ model: directive.params.model
441
+ };
442
+ }
443
+ const prompt = directive.contextAware ? interpolatePrompt(directive.content, context, directive.signals) : directive.content.value;
444
+ try {
445
+ const result = await this.callEdgeWorkers(directive, prompt);
446
+ const cacheTtl = directive.params.cacheTtl ?? this.config.defaultCacheTtl;
447
+ setCache(cacheKey, result, cacheTtl);
448
+ return {
449
+ ...result,
450
+ latencyMs: Date.now() - startTime
451
+ };
452
+ } catch (error) {
453
+ if (directive.params.fallback) {
454
+ return {
455
+ id: directive.id,
456
+ success: true,
457
+ output: directive.params.fallback,
458
+ latencyMs: Date.now() - startTime,
459
+ cached: false,
460
+ model: directive.params.model
461
+ };
462
+ }
463
+ return {
464
+ id: directive.id,
465
+ success: false,
466
+ error: error instanceof Error ? error.message : "Unknown error",
467
+ latencyMs: Date.now() - startTime,
468
+ cached: false,
469
+ model: directive.params.model
470
+ };
471
+ }
472
+ }
473
+ async processBatch(directives, context) {
474
+ const semaphore = new Semaphore(this.config.maxConcurrent);
475
+ return Promise.all(directives.map(async (directive) => {
476
+ await semaphore.acquire();
477
+ try {
478
+ return await this.process(directive, context);
479
+ } finally {
480
+ semaphore.release();
481
+ }
482
+ }));
483
+ }
484
+ async stream(directive, context, onChunk) {
485
+ const startTime = Date.now();
486
+ const access = checkTierAccess(directive, context, this.config);
487
+ if (!access.allowed) {
488
+ return {
489
+ id: directive.id,
490
+ success: false,
491
+ error: access.reason,
492
+ latencyMs: Date.now() - startTime,
493
+ cached: false,
494
+ model: directive.params.model
495
+ };
496
+ }
497
+ const prompt = directive.contextAware ? interpolatePrompt(directive.content, context, directive.signals) : directive.content.value;
498
+ try {
499
+ const response = await fetch(`${this.config.endpoint}/api/llm/stream`, {
500
+ method: "POST",
501
+ headers: { "Content-Type": "application/json" },
502
+ body: JSON.stringify({
503
+ input: prompt,
504
+ model: directive.params.variant,
505
+ options: {
506
+ temperature: directive.params.temperature,
507
+ max_tokens: directive.params.maxTokens,
508
+ stop: directive.params.stop,
509
+ top_p: directive.params.topP,
510
+ system: directive.params.system
511
+ }
512
+ }),
513
+ signal: AbortSignal.timeout(directive.params.timeout ?? this.config.timeout)
514
+ });
515
+ if (!response.ok) {
516
+ throw new Error(`Stream failed: ${response.status}`);
517
+ }
518
+ const reader = response.body?.getReader();
519
+ if (!reader) {
520
+ throw new Error("No response body");
521
+ }
522
+ const decoder = new TextDecoder;
523
+ let fullOutput = "";
524
+ while (true) {
525
+ const { done, value } = await reader.read();
526
+ if (done)
527
+ break;
528
+ const chunk = decoder.decode(value);
529
+ fullOutput += chunk;
530
+ onChunk(chunk);
531
+ }
532
+ return {
533
+ id: directive.id,
534
+ success: true,
535
+ output: fullOutput,
536
+ latencyMs: Date.now() - startTime,
537
+ cached: false,
538
+ model: directive.params.variant || directive.params.model
539
+ };
540
+ } catch (error) {
541
+ if (directive.params.fallback) {
542
+ onChunk(directive.params.fallback);
543
+ return {
544
+ id: directive.id,
545
+ success: true,
546
+ output: directive.params.fallback,
547
+ latencyMs: Date.now() - startTime,
548
+ cached: false,
549
+ model: directive.params.model
550
+ };
551
+ }
552
+ return {
553
+ id: directive.id,
554
+ success: false,
555
+ error: error instanceof Error ? error.message : "Stream failed",
556
+ latencyMs: Date.now() - startTime,
557
+ cached: false,
558
+ model: directive.params.model
559
+ };
560
+ }
561
+ }
562
+ async callEdgeWorkers(directive, prompt) {
563
+ const endpoint = this.getEndpointForModel(directive.params.model);
564
+ const response = await fetch(`${this.config.endpoint}${endpoint}`, {
565
+ method: "POST",
566
+ headers: { "Content-Type": "application/json" },
567
+ body: JSON.stringify(this.buildRequestBody(directive, prompt)),
568
+ signal: AbortSignal.timeout(directive.params.timeout ?? this.config.timeout)
569
+ });
570
+ if (!response.ok) {
571
+ const error = await response.text();
572
+ throw new Error(`ESI inference failed: ${response.status} - ${error}`);
573
+ }
574
+ const data = await response.json();
575
+ return this.parseResponse(directive, data);
576
+ }
577
+ getEndpointForModel(model) {
578
+ switch (model) {
579
+ case "llm":
580
+ return "/api/llm/infer";
581
+ case "embed":
582
+ return "/api/embed";
583
+ case "vision":
584
+ return "/api/vision";
585
+ case "tts":
586
+ return "/api/tts";
587
+ case "stt":
588
+ return "/api/stt";
589
+ case "emotion":
590
+ return "/api/emotion";
591
+ case "classify":
592
+ return "/api/classify";
593
+ case "custom":
594
+ return "/api/custom";
595
+ default:
596
+ return "/api/llm/infer";
597
+ }
598
+ }
599
+ buildRequestBody(directive, prompt) {
600
+ const { params, content } = directive;
601
+ const body = {
602
+ input: content.type === "base64" ? content.value : prompt,
603
+ model: params.variant
604
+ };
605
+ if (params.model === "llm") {
606
+ body.options = {
607
+ temperature: params.temperature,
608
+ max_tokens: params.maxTokens,
609
+ stop: params.stop,
610
+ top_p: params.topP,
611
+ frequency_penalty: params.frequencyPenalty,
612
+ presence_penalty: params.presencePenalty,
613
+ system: params.system
614
+ };
615
+ }
616
+ if (params.custom) {
617
+ body.custom = params.custom;
618
+ }
619
+ return body;
620
+ }
621
+ parseResponse(directive, data) {
622
+ const base = {
623
+ id: directive.id,
624
+ success: true,
625
+ latencyMs: 0,
626
+ cached: false,
627
+ model: String(data.model || directive.params.model)
628
+ };
629
+ switch (directive.params.model) {
630
+ case "embed":
631
+ return { ...base, embedding: data.embedding };
632
+ case "tts":
633
+ return { ...base, audio: data.audio };
634
+ default:
635
+ return {
636
+ ...base,
637
+ output: String(data.output || data.text || data.result || ""),
638
+ tokens: data.tokens
639
+ };
640
+ }
641
+ }
642
+ }
643
+
644
+ class Semaphore {
645
+ permits;
646
+ queue = [];
647
+ constructor(permits) {
648
+ this.permits = permits;
649
+ }
650
+ async acquire() {
651
+ if (this.permits > 0) {
652
+ this.permits--;
653
+ return;
654
+ }
655
+ return new Promise((resolve) => {
656
+ this.queue.push(resolve);
657
+ });
658
+ }
659
+ release() {
660
+ const next = this.queue.shift();
661
+ if (next) {
662
+ next();
663
+ } else {
664
+ this.permits++;
665
+ }
666
+ }
667
+ }
668
+ function esiInfer(prompt, options = {}) {
669
+ return {
670
+ id: `esi-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
671
+ params: {
672
+ model: "llm",
673
+ ...options
674
+ },
675
+ content: {
676
+ type: "text",
677
+ value: prompt
678
+ },
679
+ contextAware: options.system?.includes("{context}")
680
+ };
681
+ }
682
+ function esiEmbed(text) {
683
+ return {
684
+ id: `esi-embed-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
685
+ params: { model: "embed" },
686
+ content: { type: "text", value: text }
687
+ };
688
+ }
689
+ function esiEmotion(text, contextAware = true) {
690
+ return {
691
+ id: `esi-emotion-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
692
+ params: { model: "emotion" },
693
+ content: { type: "text", value: text },
694
+ contextAware,
695
+ signals: contextAware ? ["emotion", "history"] : undefined
696
+ };
697
+ }
698
+ function esiVision(base64Image, prompt, options = {}) {
699
+ return {
700
+ id: `esi-vision-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
701
+ params: {
702
+ model: "vision",
703
+ system: prompt,
704
+ ...options
705
+ },
706
+ content: { type: "base64", value: base64Image }
707
+ };
708
+ }
709
+ function esiWithContext(prompt, signals = ["emotion", "preferences", "time"], options = {}) {
710
+ return {
711
+ id: `esi-ctx-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
712
+ params: {
713
+ model: "llm",
714
+ ...options
715
+ },
716
+ content: { type: "text", value: prompt },
717
+ contextAware: true,
718
+ signals
719
+ };
720
+ }
721
+ var esiCache;
722
+ var init_esi = __esm(() => {
723
+ init_esi_cyrano();
724
+ esiCache = new Map;
725
+ });
726
+
727
+ // src/router/esi-control.ts
728
+ function generateSchemaPrompt(schema) {
729
+ const schemaDescription = describeZodSchema(schema);
730
+ return `
731
+
732
+ Respond with valid JSON matching this schema:
733
+ ${schemaDescription}
734
+
735
+ Output ONLY the JSON, no markdown, no explanation.`;
736
+ }
737
+ function describeZodSchema(schema) {
738
+ const def = schema._def;
739
+ if (def.typeName === "ZodObject") {
740
+ const shape = def.shape;
741
+ const fields = Object.entries(shape).map(([key, fieldSchema]) => {
742
+ const fieldDef = fieldSchema._def;
743
+ return ` "${key}": ${describeZodType(fieldDef)}`;
744
+ });
745
+ return `{
746
+ ${fields.join(`,
747
+ `)}
748
+ }`;
749
+ }
750
+ return describeZodType(def);
751
+ }
752
+ function describeZodType(def) {
753
+ const typeName = def.typeName;
754
+ switch (typeName) {
755
+ case "ZodString":
756
+ return "string";
757
+ case "ZodNumber":
758
+ return "number";
759
+ case "ZodBoolean":
760
+ return "boolean";
761
+ case "ZodArray":
762
+ const innerType = def.type;
763
+ return `array of ${describeZodType(innerType._def)}`;
764
+ case "ZodEnum":
765
+ const values = def.values;
766
+ return `one of: ${values.map((v) => `"${v}"`).join(" | ")}`;
767
+ case "ZodLiteral":
768
+ return JSON.stringify(def.value);
769
+ case "ZodOptional":
770
+ const optionalType = def.innerType;
771
+ return `${describeZodType(optionalType._def)} (optional)`;
772
+ case "ZodNullable":
773
+ const nullableType = def.innerType;
774
+ return `${describeZodType(nullableType._def)} or null`;
775
+ case "ZodObject":
776
+ return "object";
777
+ default:
778
+ return "any";
779
+ }
780
+ }
781
+ function parseWithSchema(output, schema) {
782
+ let jsonStr = output.trim();
783
+ if (jsonStr.startsWith("```")) {
784
+ const match = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
785
+ if (match) {
786
+ jsonStr = match[1].trim();
787
+ }
788
+ }
789
+ let parsed;
790
+ try {
791
+ parsed = JSON.parse(jsonStr);
792
+ } catch (e) {
793
+ const jsonMatch = jsonStr.match(/\{[\s\S]*\}/);
794
+ if (jsonMatch) {
795
+ try {
796
+ parsed = JSON.parse(jsonMatch[0]);
797
+ } catch {
798
+ return {
799
+ success: false,
800
+ errors: [`Failed to parse JSON: ${e instanceof Error ? e.message : "Unknown error"}`]
801
+ };
802
+ }
803
+ } else {
804
+ return {
805
+ success: false,
806
+ errors: [`No valid JSON found in output`]
807
+ };
808
+ }
809
+ }
810
+ const result = schema.safeParse(parsed);
811
+ if (result.success) {
812
+ return { success: true, data: result.data };
813
+ }
814
+ return {
815
+ success: false,
816
+ errors: result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`)
817
+ };
818
+ }
819
+ function createControlProcessor(processESI) {
820
+ return {
821
+ async processWithSchema(prompt, schema, params, context) {
822
+ const fullPrompt = prompt + generateSchemaPrompt(schema);
823
+ const directive = {
824
+ id: `esi-schema-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
825
+ params: {
826
+ model: "llm",
827
+ ...params
828
+ },
829
+ content: {
830
+ type: "text",
831
+ value: fullPrompt
832
+ }
833
+ };
834
+ const result = await processESI(directive, context);
835
+ if (!result.success || !result.output) {
836
+ return {
837
+ ...result,
838
+ validationErrors: result.error ? [result.error] : ["No output"]
839
+ };
840
+ }
841
+ const parseResult = parseWithSchema(result.output, schema);
842
+ if (parseResult.success) {
843
+ return {
844
+ ...result,
845
+ data: parseResult.data,
846
+ rawOutput: result.output
847
+ };
848
+ }
849
+ return {
850
+ ...result,
851
+ rawOutput: result.output,
852
+ validationErrors: parseResult.errors
853
+ };
854
+ },
855
+ async processIf(directive, context) {
856
+ const schemaResult = await this.processWithSchema(directive.prompt, directive.schema, directive.params || {}, context);
857
+ let conditionMet = false;
858
+ if (schemaResult.data !== undefined) {
859
+ try {
860
+ conditionMet = directive.when(schemaResult.data, context);
861
+ } catch (e) {
862
+ conditionMet = false;
863
+ }
864
+ }
865
+ return {
866
+ id: directive.id,
867
+ conditionMet,
868
+ data: schemaResult.data,
869
+ inferenceResult: schemaResult
870
+ };
871
+ },
872
+ async processMatch(directive, context) {
873
+ const schemaResult = await this.processWithSchema(directive.prompt, directive.schema, directive.params || {}, context);
874
+ let matchedCase;
875
+ if (schemaResult.data !== undefined) {
876
+ for (const caseItem of directive.cases) {
877
+ try {
878
+ if (caseItem.match(schemaResult.data, context)) {
879
+ matchedCase = caseItem.id;
880
+ break;
881
+ }
882
+ } catch {}
883
+ }
884
+ if (!matchedCase && directive.defaultCase) {
885
+ matchedCase = directive.defaultCase;
886
+ }
887
+ }
888
+ return {
889
+ id: directive.id,
890
+ matchedCase,
891
+ data: schemaResult.data,
892
+ inferenceResult: schemaResult
893
+ };
894
+ }
895
+ };
896
+ }
897
+ function esiIf(prompt, schema, when, options = {}) {
898
+ return {
899
+ id: `esi-if-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
900
+ prompt,
901
+ schema,
902
+ when,
903
+ params: options
904
+ };
905
+ }
906
+ function esiMatch(prompt, schema, cases, defaultCase, options = {}) {
907
+ return {
908
+ id: `esi-match-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
909
+ prompt,
910
+ schema,
911
+ cases,
912
+ defaultCase,
913
+ params: options
914
+ };
915
+ }
916
+ var init_esi_control = () => {};
917
+
918
+ // src/router/esi-control-react.tsx
919
+ import {
920
+ createContext,
921
+ useContext,
922
+ useEffect,
923
+ useState,
924
+ useCallback,
925
+ useMemo,
926
+ Children,
927
+ isValidElement
928
+ } from "react";
929
+ import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
930
+ function usePresenceForESI() {
931
+ const ctx = useContext(PresenceContext);
932
+ return ctx || { users: [], localUser: null };
933
+ }
934
+ function ESIStructured({
935
+ children,
936
+ prompt,
937
+ schema,
938
+ render,
939
+ fallback,
940
+ loading = "...",
941
+ retryOnFail = false,
942
+ maxRetries = 2,
943
+ temperature,
944
+ maxTokens,
945
+ cacheTtl,
946
+ onSuccess,
947
+ onValidationError,
948
+ onError,
949
+ className
950
+ }) {
951
+ const { process: process2, enabled } = useESI();
952
+ const [result, setResult] = useState(null);
953
+ const [isLoading, setIsLoading] = useState(true);
954
+ const [retryCount, setRetryCount] = useState(0);
955
+ const promptText = prompt || (typeof children === "string" ? children : String(children || ""));
956
+ const fullPrompt = promptText + generateSchemaPrompt(schema);
957
+ useEffect(() => {
958
+ if (!enabled) {
959
+ setIsLoading(false);
960
+ return;
961
+ }
962
+ async function runInference() {
963
+ setIsLoading(true);
964
+ const directive = {
965
+ id: `esi-structured-${Date.now()}`,
966
+ params: {
967
+ model: "llm",
968
+ temperature,
969
+ maxTokens,
970
+ cacheTtl
971
+ },
972
+ content: {
973
+ type: "text",
974
+ value: fullPrompt
975
+ }
976
+ };
977
+ const inferenceResult = await process2(directive);
978
+ if (!inferenceResult.success || !inferenceResult.output) {
979
+ setResult({
980
+ ...inferenceResult,
981
+ validationErrors: [inferenceResult.error || "No output"]
982
+ });
983
+ onError?.(inferenceResult.error || "Inference failed");
984
+ setIsLoading(false);
985
+ return;
986
+ }
987
+ const parseResult = parseWithSchema(inferenceResult.output, schema);
988
+ if (parseResult.success) {
989
+ const schemaResult = {
990
+ ...inferenceResult,
991
+ data: parseResult.data,
992
+ rawOutput: inferenceResult.output
993
+ };
994
+ setResult(schemaResult);
995
+ onSuccess?.(parseResult.data);
996
+ } else {
997
+ if (retryOnFail && retryCount < maxRetries) {
998
+ setRetryCount((c) => c + 1);
999
+ } else {
1000
+ const schemaResult = {
1001
+ ...inferenceResult,
1002
+ rawOutput: inferenceResult.output,
1003
+ validationErrors: parseResult.errors
1004
+ };
1005
+ setResult(schemaResult);
1006
+ onValidationError?.(parseResult.errors, inferenceResult.output);
1007
+ }
1008
+ }
1009
+ setIsLoading(false);
1010
+ }
1011
+ runInference();
1012
+ }, [fullPrompt, enabled, retryCount]);
1013
+ if (isLoading) {
1014
+ return /* @__PURE__ */ jsxDEV("span", {
1015
+ className,
1016
+ children: loading
1017
+ }, undefined, false, undefined, this);
1018
+ }
1019
+ if (!result?.data) {
1020
+ return /* @__PURE__ */ jsxDEV("span", {
1021
+ className,
1022
+ children: fallback
1023
+ }, undefined, false, undefined, this);
1024
+ }
1025
+ if (render) {
1026
+ return /* @__PURE__ */ jsxDEV("span", {
1027
+ className,
1028
+ children: render(result.data, {
1029
+ cached: result.cached,
1030
+ latencyMs: result.latencyMs
1031
+ })
1032
+ }, undefined, false, undefined, this);
1033
+ }
1034
+ return /* @__PURE__ */ jsxDEV("span", {
1035
+ className,
1036
+ children: JSON.stringify(result.data)
1037
+ }, undefined, false, undefined, this);
1038
+ }
1039
+ function ESIIf({
1040
+ children,
1041
+ prompt,
1042
+ schema,
1043
+ when,
1044
+ then: thenContent,
1045
+ else: elseContent,
1046
+ loading = null,
1047
+ temperature,
1048
+ cacheTtl,
1049
+ onEvaluate,
1050
+ className
1051
+ }) {
1052
+ const [conditionMet, setConditionMet] = useState(null);
1053
+ const [data, setData] = useState(null);
1054
+ const handleSuccess = useCallback((result) => {
1055
+ setData(result);
1056
+ try {
1057
+ const met = when(result, {});
1058
+ setConditionMet(met);
1059
+ onEvaluate?.(result, met);
1060
+ } catch {
1061
+ setConditionMet(false);
1062
+ }
1063
+ }, [when, onEvaluate]);
1064
+ return /* @__PURE__ */ jsxDEV("span", {
1065
+ className,
1066
+ children: [
1067
+ /* @__PURE__ */ jsxDEV(ESIStructured, {
1068
+ prompt,
1069
+ schema,
1070
+ temperature,
1071
+ cacheTtl,
1072
+ loading,
1073
+ onSuccess: handleSuccess,
1074
+ render: () => null,
1075
+ children
1076
+ }, undefined, false, undefined, this),
1077
+ conditionMet === true && thenContent,
1078
+ conditionMet === false && elseContent
1079
+ ]
1080
+ }, undefined, true, undefined, this);
1081
+ }
1082
+ function ESICase({ children }) {
1083
+ return /* @__PURE__ */ jsxDEV(Fragment, {
1084
+ children
1085
+ }, undefined, false, undefined, this);
1086
+ }
1087
+ function ESIDefault({ children }) {
1088
+ return /* @__PURE__ */ jsxDEV(Fragment, {
1089
+ children
1090
+ }, undefined, false, undefined, this);
1091
+ }
1092
+ function ESIMatch({
1093
+ children,
1094
+ prompt,
1095
+ schema,
1096
+ loading = null,
1097
+ temperature,
1098
+ cacheTtl,
1099
+ onMatch,
1100
+ className
1101
+ }) {
1102
+ const [matchedIndex, setMatchedIndex] = useState(null);
1103
+ const [data, setData] = useState(null);
1104
+ const { cases, defaultCase, promptFromChildren } = useMemo(() => {
1105
+ const cases2 = [];
1106
+ let defaultCase2 = null;
1107
+ let promptFromChildren2 = "";
1108
+ Children.forEach(children, (child) => {
1109
+ if (!isValidElement(child)) {
1110
+ if (typeof child === "string") {
1111
+ promptFromChildren2 += child;
1112
+ }
1113
+ return;
1114
+ }
1115
+ if (child.type === ESICase) {
1116
+ const props = child.props;
1117
+ cases2.push({
1118
+ match: props.match,
1119
+ content: props.children
1120
+ });
1121
+ } else if (child.type === ESIDefault) {
1122
+ defaultCase2 = child.props.children;
1123
+ }
1124
+ });
1125
+ return { cases: cases2, defaultCase: defaultCase2, promptFromChildren: promptFromChildren2 };
1126
+ }, [children]);
1127
+ const handleSuccess = useCallback((result) => {
1128
+ setData(result);
1129
+ for (let i = 0;i < cases.length; i++) {
1130
+ try {
1131
+ if (cases[i].match(result, {})) {
1132
+ setMatchedIndex(i);
1133
+ onMatch?.(result, i);
1134
+ return;
1135
+ }
1136
+ } catch {}
1137
+ }
1138
+ setMatchedIndex(-1);
1139
+ onMatch?.(result, -1);
1140
+ }, [cases, onMatch]);
1141
+ const finalPrompt = prompt || promptFromChildren;
1142
+ return /* @__PURE__ */ jsxDEV("span", {
1143
+ className,
1144
+ children: [
1145
+ /* @__PURE__ */ jsxDEV(ESIStructured, {
1146
+ prompt: finalPrompt,
1147
+ schema,
1148
+ temperature,
1149
+ cacheTtl,
1150
+ loading,
1151
+ onSuccess: handleSuccess,
1152
+ render: () => null
1153
+ }, undefined, false, undefined, this),
1154
+ matchedIndex !== null && matchedIndex >= 0 && cases[matchedIndex]?.content,
1155
+ matchedIndex === -1 && defaultCase
1156
+ ]
1157
+ }, undefined, true, undefined, this);
1158
+ }
1159
+ function defaultDescribeUsers(users) {
1160
+ if (users.length === 0)
1161
+ return "No other users are viewing this content.";
1162
+ if (users.length === 1)
1163
+ return `1 user is viewing: ${describeUser(users[0])}`;
1164
+ const roles = [...new Set(users.map((u) => u.role).filter(Boolean))];
1165
+ const roleStr = roles.length > 0 ? ` with roles: ${roles.join(", ")}` : "";
1166
+ return `${users.length} users are viewing${roleStr}:
1167
+ ${users.map(describeUser).join(`
1168
+ `)}`;
1169
+ }
1170
+ function describeUser(user) {
1171
+ const parts = [user.name || user.userId];
1172
+ if (user.role)
1173
+ parts.push(`(${user.role})`);
1174
+ if (user.status)
1175
+ parts.push(`[${user.status}]`);
1176
+ return `- ${parts.join(" ")}`;
1177
+ }
1178
+ function ESICollaborative({
1179
+ children,
1180
+ prompt,
1181
+ schema,
1182
+ render,
1183
+ fallback,
1184
+ loading = "...",
1185
+ describeUsers = defaultDescribeUsers,
1186
+ reactToPresenceChange = true,
1187
+ presenceDebounce = 2000,
1188
+ temperature,
1189
+ maxTokens,
1190
+ cacheTtl,
1191
+ onSuccess,
1192
+ className
1193
+ }) {
1194
+ const presence = usePresenceForESI();
1195
+ const [debouncedUsers, setDebouncedUsers] = useState(presence.users);
1196
+ const [result, setResult] = useState(null);
1197
+ useEffect(() => {
1198
+ if (!reactToPresenceChange)
1199
+ return;
1200
+ const timer = setTimeout(() => {
1201
+ setDebouncedUsers(presence.users);
1202
+ }, presenceDebounce);
1203
+ return () => clearTimeout(timer);
1204
+ }, [presence.users, reactToPresenceChange, presenceDebounce]);
1205
+ const basePrompt = prompt || (typeof children === "string" ? children : String(children || ""));
1206
+ const presenceDescription = describeUsers(debouncedUsers);
1207
+ const collaborativePrompt = `[Audience Context]
1208
+ ${presenceDescription}
1209
+
1210
+ [Task]
1211
+ ${basePrompt}
1212
+
1213
+ Consider ALL viewers when generating your response. The content should be relevant and appropriate for everyone currently viewing.`;
1214
+ const handleSuccess = useCallback((data) => {
1215
+ setResult(data);
1216
+ onSuccess?.(data, debouncedUsers);
1217
+ }, [debouncedUsers, onSuccess]);
1218
+ return /* @__PURE__ */ jsxDEV(ESIStructured, {
1219
+ prompt: collaborativePrompt,
1220
+ schema,
1221
+ temperature,
1222
+ maxTokens,
1223
+ cacheTtl,
1224
+ loading,
1225
+ fallback,
1226
+ onSuccess: handleSuccess,
1227
+ className,
1228
+ render: (data, meta) => {
1229
+ if (render) {
1230
+ return render(data, debouncedUsers);
1231
+ }
1232
+ return JSON.stringify(data);
1233
+ }
1234
+ }, undefined, false, undefined, this);
1235
+ }
1236
+ function ESIReflect({
1237
+ children,
1238
+ prompt,
1239
+ schema,
1240
+ until,
1241
+ maxIterations = 3,
1242
+ render,
1243
+ showProgress = false,
1244
+ fallback,
1245
+ loading = "...",
1246
+ onIteration,
1247
+ onComplete,
1248
+ className
1249
+ }) {
1250
+ const { process: process2, enabled } = useESI();
1251
+ const [currentResult, setCurrentResult] = useState(null);
1252
+ const [iteration, setIteration] = useState(0);
1253
+ const [isComplete, setIsComplete] = useState(false);
1254
+ const [isLoading, setIsLoading] = useState(true);
1255
+ const basePrompt = prompt || (typeof children === "string" ? children : String(children || ""));
1256
+ useEffect(() => {
1257
+ if (!enabled) {
1258
+ setIsLoading(false);
1259
+ return;
1260
+ }
1261
+ async function runReflection() {
1262
+ setIsLoading(true);
1263
+ let currentIteration = 0;
1264
+ let lastResult = null;
1265
+ let previousAttempts = [];
1266
+ while (currentIteration < maxIterations) {
1267
+ let reflectionPrompt = basePrompt;
1268
+ if (currentIteration > 0 && lastResult) {
1269
+ reflectionPrompt = `[Previous Attempt ${currentIteration}]
1270
+ ${JSON.stringify(lastResult)}
1271
+
1272
+ [Reflection]
1273
+ The previous attempt did not meet the quality threshold. Please improve upon it.
1274
+
1275
+ [Original Task]
1276
+ ${basePrompt}`;
1277
+ }
1278
+ const fullPrompt = reflectionPrompt + generateSchemaPrompt(schema);
1279
+ const directive = {
1280
+ id: `esi-reflect-${Date.now()}-${currentIteration}`,
1281
+ params: { model: "llm" },
1282
+ content: { type: "text", value: fullPrompt }
1283
+ };
1284
+ const result = await process2(directive);
1285
+ if (!result.success || !result.output) {
1286
+ break;
1287
+ }
1288
+ const parseResult = parseWithSchema(result.output, schema);
1289
+ if (!parseResult.success) {
1290
+ currentIteration++;
1291
+ continue;
1292
+ }
1293
+ lastResult = parseResult.data;
1294
+ setCurrentResult(parseResult.data);
1295
+ setIteration(currentIteration + 1);
1296
+ onIteration?.(parseResult.data, currentIteration + 1);
1297
+ if (until(parseResult.data, currentIteration + 1)) {
1298
+ setIsComplete(true);
1299
+ onComplete?.(parseResult.data, currentIteration + 1);
1300
+ break;
1301
+ }
1302
+ previousAttempts.push(result.output);
1303
+ currentIteration++;
1304
+ }
1305
+ if (!isComplete && lastResult) {
1306
+ setIsComplete(true);
1307
+ onComplete?.(lastResult, currentIteration);
1308
+ }
1309
+ setIsLoading(false);
1310
+ }
1311
+ runReflection();
1312
+ }, [basePrompt, enabled, maxIterations]);
1313
+ if (isLoading) {
1314
+ if (showProgress && currentResult) {
1315
+ return /* @__PURE__ */ jsxDEV("span", {
1316
+ className,
1317
+ children: [
1318
+ render ? render(currentResult, iteration) : JSON.stringify(currentResult),
1319
+ /* @__PURE__ */ jsxDEV("span", {
1320
+ children: [
1321
+ " (refining... iteration ",
1322
+ iteration,
1323
+ ")"
1324
+ ]
1325
+ }, undefined, true, undefined, this)
1326
+ ]
1327
+ }, undefined, true, undefined, this);
1328
+ }
1329
+ return /* @__PURE__ */ jsxDEV("span", {
1330
+ className,
1331
+ children: loading
1332
+ }, undefined, false, undefined, this);
1333
+ }
1334
+ if (!currentResult) {
1335
+ return /* @__PURE__ */ jsxDEV("span", {
1336
+ className,
1337
+ children: fallback
1338
+ }, undefined, false, undefined, this);
1339
+ }
1340
+ if (render) {
1341
+ return /* @__PURE__ */ jsxDEV("span", {
1342
+ className,
1343
+ children: render(currentResult, iteration)
1344
+ }, undefined, false, undefined, this);
1345
+ }
1346
+ return /* @__PURE__ */ jsxDEV("span", {
1347
+ className,
1348
+ children: JSON.stringify(currentResult)
1349
+ }, undefined, false, undefined, this);
1350
+ }
1351
+ function ESIOptimize({
1352
+ children,
1353
+ prompt,
1354
+ schema,
1355
+ criteria = ["clarity", "relevance", "completeness", "conciseness"],
1356
+ targetQuality = 0.85,
1357
+ maxRounds = 3,
1358
+ onlyWhenAlone = true,
1359
+ render,
1360
+ fallback,
1361
+ loading = "...",
1362
+ onImprove,
1363
+ onOptimized,
1364
+ className
1365
+ }) {
1366
+ const { process: process2, enabled } = useESI();
1367
+ const presence = usePresenceForESI();
1368
+ const [result, setResult] = useState(null);
1369
+ const [meta, setMeta] = useState({
1370
+ rounds: 0,
1371
+ quality: 0,
1372
+ improvements: [],
1373
+ wasOptimized: false
1374
+ });
1375
+ const [isLoading, setIsLoading] = useState(true);
1376
+ const basePrompt = prompt || (typeof children === "string" ? children : String(children || ""));
1377
+ const shouldOptimize = !onlyWhenAlone || presence.users.length <= 1;
1378
+ useEffect(() => {
1379
+ if (!enabled) {
1380
+ setIsLoading(false);
1381
+ return;
1382
+ }
1383
+ async function runOptimization() {
1384
+ setIsLoading(true);
1385
+ const criteriaList = criteria.join(", ");
1386
+ const firstPassPrompt = `${basePrompt}
1387
+
1388
+ After generating your response, assess its quality on these criteria: ${criteriaList}
1389
+
1390
+ ${generateSchemaPrompt(schema)}
1391
+
1392
+ Additionally, include a self-assessment in this format:
1393
+ {
1394
+ "result": <your response matching the schema above>,
1395
+ "selfAssessment": {
1396
+ "quality": <0-1 score>,
1397
+ "strengths": [<list of strengths>],
1398
+ "weaknesses": [<list of weaknesses>],
1399
+ "improvementSuggestions": [<specific improvements>]
1400
+ }
1401
+ }`;
1402
+ let currentResult = null;
1403
+ let currentQuality = 0;
1404
+ let round = 0;
1405
+ let improvements = [];
1406
+ let lastWeaknesses = [];
1407
+ const firstResult = await process2({
1408
+ id: `esi-optimize-${Date.now()}-0`,
1409
+ params: { model: "llm" },
1410
+ content: { type: "text", value: firstPassPrompt }
1411
+ });
1412
+ if (!firstResult.success || !firstResult.output) {
1413
+ setIsLoading(false);
1414
+ return;
1415
+ }
1416
+ try {
1417
+ const parsed = JSON.parse(extractJson(firstResult.output));
1418
+ const validated = schema.safeParse(parsed.result);
1419
+ if (validated.success) {
1420
+ currentResult = validated.data;
1421
+ currentQuality = parsed.selfAssessment?.quality || 0.5;
1422
+ lastWeaknesses = parsed.selfAssessment?.weaknesses || [];
1423
+ round = 1;
1424
+ setResult(currentResult);
1425
+ setMeta({
1426
+ rounds: 1,
1427
+ quality: currentQuality,
1428
+ improvements: [],
1429
+ wasOptimized: false
1430
+ });
1431
+ onImprove?.(currentResult, 1, currentQuality);
1432
+ }
1433
+ } catch {
1434
+ const parseResult = parseWithSchema(firstResult.output, schema);
1435
+ if (parseResult.success) {
1436
+ currentResult = parseResult.data;
1437
+ currentQuality = 0.6;
1438
+ round = 1;
1439
+ setResult(currentResult);
1440
+ } else {
1441
+ setIsLoading(false);
1442
+ return;
1443
+ }
1444
+ }
1445
+ if (shouldOptimize && currentQuality < targetQuality) {
1446
+ while (round < maxRounds && currentQuality < targetQuality) {
1447
+ const optimizePrompt = `You previously generated this response:
1448
+ ${JSON.stringify(currentResult)}
1449
+
1450
+ Quality score: ${currentQuality.toFixed(2)}
1451
+ Weaknesses identified: ${lastWeaknesses.join(", ") || "none specified"}
1452
+
1453
+ Please improve the response, focusing on: ${criteriaList}
1454
+ Address the weaknesses and aim for a quality score above ${targetQuality}.
1455
+
1456
+ ${generateSchemaPrompt(schema)}
1457
+
1458
+ Include your improved self-assessment:
1459
+ {
1460
+ "result": <improved response>,
1461
+ "selfAssessment": {
1462
+ "quality": <0-1 score>,
1463
+ "strengths": [...],
1464
+ "weaknesses": [...],
1465
+ "improvementSuggestions": [...]
1466
+ },
1467
+ "improvementsMade": [<what you improved>]
1468
+ }`;
1469
+ const improvedResult = await process2({
1470
+ id: `esi-optimize-${Date.now()}-${round}`,
1471
+ params: { model: "llm" },
1472
+ content: { type: "text", value: optimizePrompt }
1473
+ });
1474
+ if (!improvedResult.success || !improvedResult.output) {
1475
+ break;
1476
+ }
1477
+ try {
1478
+ const parsed = JSON.parse(extractJson(improvedResult.output));
1479
+ const validated = schema.safeParse(parsed.result);
1480
+ if (validated.success) {
1481
+ const newQuality = parsed.selfAssessment?.quality || currentQuality;
1482
+ if (newQuality > currentQuality) {
1483
+ currentResult = validated.data;
1484
+ currentQuality = newQuality;
1485
+ lastWeaknesses = parsed.selfAssessment?.weaknesses || [];
1486
+ if (parsed.improvementsMade) {
1487
+ improvements.push(...parsed.improvementsMade);
1488
+ }
1489
+ setResult(currentResult);
1490
+ setMeta({
1491
+ rounds: round + 1,
1492
+ quality: currentQuality,
1493
+ improvements,
1494
+ wasOptimized: true
1495
+ });
1496
+ onImprove?.(currentResult, round + 1, currentQuality);
1497
+ }
1498
+ }
1499
+ } catch {}
1500
+ round++;
1501
+ }
1502
+ }
1503
+ if (currentResult) {
1504
+ setMeta((prev) => ({
1505
+ ...prev,
1506
+ rounds: round,
1507
+ quality: currentQuality,
1508
+ wasOptimized: round > 1
1509
+ }));
1510
+ onOptimized?.(currentResult, round, currentQuality);
1511
+ }
1512
+ setIsLoading(false);
1513
+ }
1514
+ runOptimization();
1515
+ }, [basePrompt, enabled, shouldOptimize, targetQuality, maxRounds]);
1516
+ if (isLoading) {
1517
+ return /* @__PURE__ */ jsxDEV("span", {
1518
+ className,
1519
+ children: loading
1520
+ }, undefined, false, undefined, this);
1521
+ }
1522
+ if (!result) {
1523
+ return /* @__PURE__ */ jsxDEV("span", {
1524
+ className,
1525
+ children: fallback
1526
+ }, undefined, false, undefined, this);
1527
+ }
1528
+ if (render) {
1529
+ return /* @__PURE__ */ jsxDEV("span", {
1530
+ className,
1531
+ children: render(result, meta)
1532
+ }, undefined, false, undefined, this);
1533
+ }
1534
+ return /* @__PURE__ */ jsxDEV("span", {
1535
+ className,
1536
+ children: JSON.stringify(result)
1537
+ }, undefined, false, undefined, this);
1538
+ }
1539
+ function extractJson(str) {
1540
+ let cleaned = str.trim();
1541
+ if (cleaned.startsWith("```")) {
1542
+ const match = cleaned.match(/```(?:json)?\s*([\s\S]*?)```/);
1543
+ if (match)
1544
+ cleaned = match[1].trim();
1545
+ }
1546
+ const jsonMatch = cleaned.match(/\{[\s\S]*\}/);
1547
+ if (jsonMatch)
1548
+ return jsonMatch[0];
1549
+ return cleaned;
1550
+ }
1551
+ function ESIAuto({
1552
+ children,
1553
+ prompt,
1554
+ schema,
1555
+ render,
1556
+ collaborativeThreshold = 2,
1557
+ optimizeSettings,
1558
+ fallback,
1559
+ loading,
1560
+ className
1561
+ }) {
1562
+ const presence = usePresenceForESI();
1563
+ const userCount = presence.users.length;
1564
+ const mode = userCount >= collaborativeThreshold ? "collaborative" : userCount === 1 ? "optimized" : "basic";
1565
+ if (mode === "collaborative") {
1566
+ return /* @__PURE__ */ jsxDEV(ESICollaborative, {
1567
+ prompt,
1568
+ schema,
1569
+ fallback,
1570
+ loading,
1571
+ className,
1572
+ render: render ? (data) => render(data, "collaborative") : undefined,
1573
+ children
1574
+ }, undefined, false, undefined, this);
1575
+ }
1576
+ if (mode === "optimized") {
1577
+ return /* @__PURE__ */ jsxDEV(ESIOptimize, {
1578
+ prompt,
1579
+ schema,
1580
+ criteria: optimizeSettings?.criteria,
1581
+ targetQuality: optimizeSettings?.targetQuality,
1582
+ maxRounds: optimizeSettings?.maxRounds,
1583
+ fallback,
1584
+ loading,
1585
+ className,
1586
+ render: render ? (data) => render(data, "optimized") : undefined,
1587
+ children
1588
+ }, undefined, false, undefined, this);
1589
+ }
1590
+ return /* @__PURE__ */ jsxDEV(ESIStructured, {
1591
+ prompt,
1592
+ schema,
1593
+ fallback,
1594
+ loading,
1595
+ className,
1596
+ render: render ? (data) => render(data, "basic") : undefined,
1597
+ children
1598
+ }, undefined, false, undefined, this);
1599
+ }
1600
+ function ESIShow({
1601
+ condition,
1602
+ children,
1603
+ fallback = null,
1604
+ loading = null,
1605
+ cacheTtl,
1606
+ onEvaluate,
1607
+ className
1608
+ }) {
1609
+ const [show, setShow] = useState(null);
1610
+ const boolSchema = {
1611
+ safeParse: (val) => {
1612
+ if (typeof val === "boolean")
1613
+ return { success: true, data: val };
1614
+ if (typeof val === "string") {
1615
+ const lower = val.toLowerCase().trim();
1616
+ if (lower === "true" || lower === "yes" || lower === "1")
1617
+ return { success: true, data: true };
1618
+ if (lower === "false" || lower === "no" || lower === "0")
1619
+ return { success: true, data: false };
1620
+ }
1621
+ if (typeof val === "object" && val !== null && "result" in val) {
1622
+ return { success: true, data: Boolean(val.result) };
1623
+ }
1624
+ return { success: false, error: "Not a boolean" };
1625
+ }
1626
+ };
1627
+ return /* @__PURE__ */ jsxDEV("span", {
1628
+ className,
1629
+ children: [
1630
+ /* @__PURE__ */ jsxDEV(ESIStructured, {
1631
+ prompt: `Evaluate this condition and respond with only "true" or "false": ${condition}`,
1632
+ schema: boolSchema,
1633
+ cacheTtl,
1634
+ loading,
1635
+ onSuccess: (result) => {
1636
+ setShow(result);
1637
+ onEvaluate?.(result);
1638
+ },
1639
+ render: () => null
1640
+ }, undefined, false, undefined, this),
1641
+ show === true && children,
1642
+ show === false && fallback
1643
+ ]
1644
+ }, undefined, true, undefined, this);
1645
+ }
1646
+ function ESIHide({
1647
+ condition,
1648
+ children,
1649
+ loading = null,
1650
+ cacheTtl,
1651
+ className
1652
+ }) {
1653
+ return /* @__PURE__ */ jsxDEV(ESIShow, {
1654
+ condition,
1655
+ fallback: children,
1656
+ loading,
1657
+ cacheTtl,
1658
+ className,
1659
+ children: null
1660
+ }, undefined, false, undefined, this);
1661
+ }
1662
+ function ESIWhen({ condition, children, loading, cacheTtl, className }) {
1663
+ return /* @__PURE__ */ jsxDEV(ESIShow, {
1664
+ condition,
1665
+ loading,
1666
+ cacheTtl,
1667
+ className,
1668
+ children
1669
+ }, undefined, false, undefined, this);
1670
+ }
1671
+ function ESIUnless({ condition, children, loading, cacheTtl, className }) {
1672
+ return /* @__PURE__ */ jsxDEV(ESIHide, {
1673
+ condition,
1674
+ loading,
1675
+ cacheTtl,
1676
+ className,
1677
+ children
1678
+ }, undefined, false, undefined, this);
1679
+ }
1680
+ function ESITierGate({ minTier, children, fallback = null, className }) {
1681
+ const [hasAccess, setHasAccess] = useState(null);
1682
+ useEffect(() => {
1683
+ const state = typeof window !== "undefined" && window.__AEON_ESI_STATE__ || {};
1684
+ if (state.isAdmin === true || state.userTier === "admin") {
1685
+ setHasAccess(true);
1686
+ return;
1687
+ }
1688
+ const userTier = state.userTier || "free";
1689
+ const userLevel = TIER_LEVELS[userTier] ?? 0;
1690
+ const requiredLevel = TIER_LEVELS[minTier] ?? 0;
1691
+ setHasAccess(userLevel >= requiredLevel);
1692
+ }, [minTier]);
1693
+ if (hasAccess === null)
1694
+ return /* @__PURE__ */ jsxDEV("span", {
1695
+ className
1696
+ }, undefined, false, undefined, this);
1697
+ return /* @__PURE__ */ jsxDEV("span", {
1698
+ className,
1699
+ children: hasAccess ? children : fallback
1700
+ }, undefined, false, undefined, this);
1701
+ }
1702
+ function ESIEmotionGate({
1703
+ allow,
1704
+ block,
1705
+ valenceRange,
1706
+ arousalRange,
1707
+ children,
1708
+ fallback = null,
1709
+ className
1710
+ }) {
1711
+ const [hasAccess, setHasAccess] = useState(null);
1712
+ useEffect(() => {
1713
+ const state = typeof window !== "undefined" && window.__AEON_ESI_STATE__ || {};
1714
+ const emotion = state.emotionState || {};
1715
+ let access = true;
1716
+ if (allow && allow.length > 0 && emotion.primary) {
1717
+ access = access && allow.includes(emotion.primary);
1718
+ }
1719
+ if (block && block.length > 0 && emotion.primary) {
1720
+ access = access && !block.includes(emotion.primary);
1721
+ }
1722
+ if (valenceRange && emotion.valence !== undefined) {
1723
+ access = access && emotion.valence >= valenceRange[0] && emotion.valence <= valenceRange[1];
1724
+ }
1725
+ if (arousalRange && emotion.arousal !== undefined) {
1726
+ access = access && emotion.arousal >= arousalRange[0] && emotion.arousal <= arousalRange[1];
1727
+ }
1728
+ setHasAccess(access);
1729
+ }, [allow, block, valenceRange, arousalRange]);
1730
+ if (hasAccess === null)
1731
+ return /* @__PURE__ */ jsxDEV("span", {
1732
+ className
1733
+ }, undefined, false, undefined, this);
1734
+ return /* @__PURE__ */ jsxDEV("span", {
1735
+ className,
1736
+ children: hasAccess ? children : fallback
1737
+ }, undefined, false, undefined, this);
1738
+ }
1739
+ function ESITimeGate({
1740
+ after,
1741
+ before,
1742
+ days,
1743
+ children,
1744
+ fallback = null,
1745
+ className
1746
+ }) {
1747
+ const [inRange, setInRange] = useState(null);
1748
+ useEffect(() => {
1749
+ const now = new Date;
1750
+ const hour = now.getHours();
1751
+ const day = now.getDay();
1752
+ let access = true;
1753
+ if (after !== undefined)
1754
+ access = access && hour >= after;
1755
+ if (before !== undefined)
1756
+ access = access && hour < before;
1757
+ if (days && days.length > 0)
1758
+ access = access && days.includes(day);
1759
+ setInRange(access);
1760
+ }, [after, before, days]);
1761
+ if (inRange === null)
1762
+ return /* @__PURE__ */ jsxDEV("span", {
1763
+ className
1764
+ }, undefined, false, undefined, this);
1765
+ return /* @__PURE__ */ jsxDEV("span", {
1766
+ className,
1767
+ children: inRange ? children : fallback
1768
+ }, undefined, false, undefined, this);
1769
+ }
1770
+ function ESIABTest({
1771
+ name,
1772
+ variants,
1773
+ selectionPrompt,
1774
+ random = false,
1775
+ onSelect,
1776
+ loading = null,
1777
+ className
1778
+ }) {
1779
+ const [selectedVariant, setSelectedVariant] = useState(null);
1780
+ const variantKeys = Object.keys(variants);
1781
+ useEffect(() => {
1782
+ if (random || !selectionPrompt) {
1783
+ const selected = variantKeys[Math.floor(Math.random() * variantKeys.length)];
1784
+ setSelectedVariant(selected);
1785
+ onSelect?.(selected);
1786
+ }
1787
+ }, [random, selectionPrompt]);
1788
+ if (random || !selectionPrompt) {
1789
+ if (!selectedVariant)
1790
+ return /* @__PURE__ */ jsxDEV("span", {
1791
+ className,
1792
+ children: loading
1793
+ }, undefined, false, undefined, this);
1794
+ return /* @__PURE__ */ jsxDEV("span", {
1795
+ className,
1796
+ children: variants[selectedVariant]
1797
+ }, undefined, false, undefined, this);
1798
+ }
1799
+ const variantSchema = {
1800
+ safeParse: (val) => {
1801
+ const str = String(val).trim();
1802
+ if (variantKeys.includes(str))
1803
+ return { success: true, data: str };
1804
+ for (const key of variantKeys) {
1805
+ if (str.toLowerCase().includes(key.toLowerCase())) {
1806
+ return { success: true, data: key };
1807
+ }
1808
+ }
1809
+ return { success: false, error: "Invalid variant" };
1810
+ }
1811
+ };
1812
+ return /* @__PURE__ */ jsxDEV("span", {
1813
+ className,
1814
+ children: [
1815
+ /* @__PURE__ */ jsxDEV(ESIStructured, {
1816
+ prompt: `${selectionPrompt}
1817
+
1818
+ Available variants: ${variantKeys.join(", ")}
1819
+
1820
+ Respond with only the variant name.`,
1821
+ schema: variantSchema,
1822
+ loading,
1823
+ onSuccess: (selected) => {
1824
+ setSelectedVariant(selected);
1825
+ onSelect?.(selected);
1826
+ },
1827
+ render: () => null
1828
+ }, undefined, false, undefined, this),
1829
+ selectedVariant && variants[selectedVariant]
1830
+ ]
1831
+ }, undefined, true, undefined, this);
1832
+ }
1833
+ function ESIForEach({
1834
+ prompt,
1835
+ itemSchema,
1836
+ render,
1837
+ maxItems = 10,
1838
+ empty = null,
1839
+ loading = "...",
1840
+ as: Wrapper = "div",
1841
+ className
1842
+ }) {
1843
+ const [items, setItems] = useState([]);
1844
+ const [isLoading, setIsLoading] = useState(true);
1845
+ const arraySchema = {
1846
+ safeParse: (val) => {
1847
+ try {
1848
+ let arr;
1849
+ if (Array.isArray(val)) {
1850
+ arr = val;
1851
+ } else if (typeof val === "string") {
1852
+ arr = JSON.parse(val);
1853
+ } else if (typeof val === "object" && val !== null && "items" in val) {
1854
+ arr = val.items;
1855
+ } else {
1856
+ return { success: false, error: "Not an array" };
1857
+ }
1858
+ const validItems = [];
1859
+ for (const item of arr.slice(0, maxItems)) {
1860
+ const result = itemSchema.safeParse(item);
1861
+ if (result.success) {
1862
+ validItems.push(result.data);
1863
+ }
1864
+ }
1865
+ return { success: true, data: validItems };
1866
+ } catch {
1867
+ return { success: false, error: "Parse error" };
1868
+ }
1869
+ }
1870
+ };
1871
+ return /* @__PURE__ */ jsxDEV(ESIStructured, {
1872
+ prompt: `${prompt}
1873
+
1874
+ Respond with a JSON array of items (max ${maxItems}).`,
1875
+ schema: arraySchema,
1876
+ loading,
1877
+ fallback: empty,
1878
+ className,
1879
+ onSuccess: (result) => {
1880
+ setItems(result);
1881
+ setIsLoading(false);
1882
+ },
1883
+ render: (data) => {
1884
+ if (data.length === 0)
1885
+ return /* @__PURE__ */ jsxDEV(Fragment, {
1886
+ children: empty
1887
+ }, undefined, false, undefined, this);
1888
+ return /* @__PURE__ */ jsxDEV(Wrapper, {
1889
+ className,
1890
+ children: data.map((item, i) => render(item, i))
1891
+ }, undefined, false, undefined, this);
1892
+ }
1893
+ }, undefined, false, undefined, this);
1894
+ }
1895
+ function ESIFirst({
1896
+ context,
1897
+ children,
1898
+ fallback = null,
1899
+ loading = null,
1900
+ className
1901
+ }) {
1902
+ return /* @__PURE__ */ jsxDEV("span", {
1903
+ className,
1904
+ children
1905
+ }, undefined, false, undefined, this);
1906
+ }
1907
+ function ESIClamp({
1908
+ prompt,
1909
+ min,
1910
+ max,
1911
+ render,
1912
+ defaultValue,
1913
+ loading = "...",
1914
+ className
1915
+ }) {
1916
+ const numSchema = {
1917
+ safeParse: (val) => {
1918
+ let num;
1919
+ if (typeof val === "number") {
1920
+ num = val;
1921
+ } else if (typeof val === "string") {
1922
+ num = parseFloat(val);
1923
+ } else if (typeof val === "object" && val !== null && "value" in val) {
1924
+ num = Number(val.value);
1925
+ } else {
1926
+ return { success: false, error: "Not a number" };
1927
+ }
1928
+ if (isNaN(num))
1929
+ return { success: false, error: "NaN" };
1930
+ return { success: true, data: Math.max(min, Math.min(max, num)) };
1931
+ }
1932
+ };
1933
+ return /* @__PURE__ */ jsxDEV(ESIStructured, {
1934
+ prompt: `${prompt}
1935
+
1936
+ Respond with a number between ${min} and ${max}.`,
1937
+ schema: numSchema,
1938
+ loading,
1939
+ fallback: defaultValue !== undefined ? render(defaultValue) : null,
1940
+ className,
1941
+ render: (value) => render(value)
1942
+ }, undefined, false, undefined, this);
1943
+ }
1944
+ function ESISelect({
1945
+ prompt,
1946
+ options,
1947
+ render,
1948
+ defaultOption,
1949
+ loading = "...",
1950
+ onSelect,
1951
+ className
1952
+ }) {
1953
+ const optionSchema = {
1954
+ safeParse: (val) => {
1955
+ const str = String(val).trim().toLowerCase();
1956
+ const match = options.find((o) => o.toLowerCase() === str);
1957
+ if (match)
1958
+ return { success: true, data: match };
1959
+ const partial = options.find((o) => str.includes(o.toLowerCase()) || o.toLowerCase().includes(str));
1960
+ if (partial)
1961
+ return { success: true, data: partial };
1962
+ return { success: false, error: "No match" };
1963
+ }
1964
+ };
1965
+ return /* @__PURE__ */ jsxDEV(ESIStructured, {
1966
+ prompt: `${prompt}
1967
+
1968
+ Options: ${options.join(", ")}
1969
+
1970
+ Respond with only one of the options.`,
1971
+ schema: optionSchema,
1972
+ loading,
1973
+ fallback: defaultOption ? render(defaultOption) : null,
1974
+ className,
1975
+ onSuccess: onSelect,
1976
+ render: (selected) => render(selected)
1977
+ }, undefined, false, undefined, this);
1978
+ }
1979
+ function ESIScore({
1980
+ prompt,
1981
+ render,
1982
+ thresholds = DEFAULT_THRESHOLDS,
1983
+ loading = "...",
1984
+ className
1985
+ }) {
1986
+ return /* @__PURE__ */ jsxDEV(ESIClamp, {
1987
+ prompt,
1988
+ min: 0,
1989
+ max: 1,
1990
+ loading,
1991
+ className,
1992
+ render: (score) => {
1993
+ const label = thresholds.find((t) => score <= t.value)?.label || "unknown";
1994
+ return render(score, label);
1995
+ }
1996
+ }, undefined, false, undefined, this);
1997
+ }
1998
+ var PresenceContext, TIER_LEVELS, DEFAULT_THRESHOLDS, ESIControl;
1999
+ var init_esi_control_react = __esm(() => {
2000
+ init_esi_control();
2001
+ init_esi_react();
2002
+ PresenceContext = createContext(null);
2003
+ TIER_LEVELS = { free: 0, starter: 1, pro: 2, enterprise: 3, admin: 999 };
2004
+ DEFAULT_THRESHOLDS = [
2005
+ { value: 0.2, label: "very low" },
2006
+ { value: 0.4, label: "low" },
2007
+ { value: 0.6, label: "moderate" },
2008
+ { value: 0.8, label: "high" },
2009
+ { value: 1, label: "very high" }
2010
+ ];
2011
+ ESIControl = {
2012
+ Structured: ESIStructured,
2013
+ If: ESIIf,
2014
+ Show: ESIShow,
2015
+ Hide: ESIHide,
2016
+ When: ESIWhen,
2017
+ Unless: ESIUnless,
2018
+ Match: ESIMatch,
2019
+ Case: ESICase,
2020
+ Default: ESIDefault,
2021
+ First: ESIFirst,
2022
+ TierGate: ESITierGate,
2023
+ EmotionGate: ESIEmotionGate,
2024
+ TimeGate: ESITimeGate,
2025
+ ForEach: ESIForEach,
2026
+ Select: ESISelect,
2027
+ ABTest: ESIABTest,
2028
+ Clamp: ESIClamp,
2029
+ Score: ESIScore,
2030
+ Collaborative: ESICollaborative,
2031
+ Reflect: ESIReflect,
2032
+ Optimize: ESIOptimize,
2033
+ Auto: ESIAuto
2034
+ };
2035
+ });
2036
+
2037
+ // src/router/esi-format-react.tsx
2038
+ import {
2039
+ Children as Children2,
2040
+ cloneElement,
2041
+ isValidElement as isValidElement2,
2042
+ useState as useState2,
2043
+ useEffect as useEffect2,
2044
+ useMemo as useMemo2,
2045
+ useCallback as useCallback2
2046
+ } from "react";
2047
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
2048
+ function wrapChildren(children, onOutput) {
2049
+ return Children2.map(children, (child) => {
2050
+ if (!isValidElement2(child)) {
2051
+ if (typeof child === "string") {
2052
+ onOutput(child);
2053
+ }
2054
+ return null;
2055
+ }
2056
+ const childProps = child.props;
2057
+ const originalRender = childProps.render;
2058
+ const originalOnComplete = childProps.onComplete;
2059
+ const newProps = {
2060
+ ...childProps,
2061
+ render: (result) => {
2062
+ const text = typeof result === "string" ? result : typeof result === "object" && result !== null && ("output" in result) ? String(result.output) : JSON.stringify(result);
2063
+ onOutput(text);
2064
+ return originalRender ? originalRender(result) : null;
2065
+ },
2066
+ onComplete: (result) => {
2067
+ if (result && typeof result === "object" && "output" in result) {
2068
+ onOutput(String(result.output));
2069
+ }
2070
+ originalOnComplete?.(result);
2071
+ }
2072
+ };
2073
+ return cloneElement(child, newProps);
2074
+ });
2075
+ }
2076
+ function parseMarkdown(text, options = {}) {
2077
+ const { gfm = true, allowHtml = false, linkTarget = "_blank" } = options;
2078
+ let html = text;
2079
+ if (!allowHtml) {
2080
+ html = html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2081
+ }
2082
+ html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {
2083
+ const langClass = lang ? ` class="language-${lang}"` : "";
2084
+ return `<pre><code${langClass}>${code.trim()}</code></pre>`;
2085
+ });
2086
+ html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
2087
+ html = html.replace(/^######\s+(.+)$/gm, "<h6>$1</h6>");
2088
+ html = html.replace(/^#####\s+(.+)$/gm, "<h5>$1</h5>");
2089
+ html = html.replace(/^####\s+(.+)$/gm, "<h4>$1</h4>");
2090
+ html = html.replace(/^###\s+(.+)$/gm, "<h3>$1</h3>");
2091
+ html = html.replace(/^##\s+(.+)$/gm, "<h2>$1</h2>");
2092
+ html = html.replace(/^#\s+(.+)$/gm, "<h1>$1</h1>");
2093
+ html = html.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>");
2094
+ html = html.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
2095
+ html = html.replace(/\*(.+?)\*/g, "<em>$1</em>");
2096
+ html = html.replace(/___(.+?)___/g, "<strong><em>$1</em></strong>");
2097
+ html = html.replace(/__(.+?)__/g, "<strong>$1</strong>");
2098
+ html = html.replace(/_(.+?)_/g, "<em>$1</em>");
2099
+ if (gfm) {
2100
+ html = html.replace(/~~(.+?)~~/g, "<del>$1</del>");
2101
+ }
2102
+ html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, `<a href="$2" target="${linkTarget}" rel="noopener noreferrer">$1</a>`);
2103
+ html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1" />');
2104
+ html = html.replace(/^>\s+(.+)$/gm, "<blockquote>$1</blockquote>");
2105
+ html = html.replace(/^(---|\*\*\*|___)$/gm, "<hr />");
2106
+ html = html.replace(/^[\*\-\+]\s+(.+)$/gm, "<li>$1</li>");
2107
+ html = html.replace(/(<li>.*<\/li>\n?)+/g, "<ul>$&</ul>");
2108
+ html = html.replace(/^\d+\.\s+(.+)$/gm, "<li>$1</li>");
2109
+ if (gfm) {
2110
+ html = html.replace(/<li>\[ \]\s*(.+)<\/li>/g, '<li><input type="checkbox" disabled /> $1</li>');
2111
+ html = html.replace(/<li>\[x\]\s*(.+)<\/li>/gi, '<li><input type="checkbox" disabled checked /> $1</li>');
2112
+ }
2113
+ if (gfm) {
2114
+ const tableRegex = /^\|(.+)\|$/gm;
2115
+ const rows = html.match(tableRegex);
2116
+ if (rows && rows.length >= 2) {
2117
+ const separatorIdx = rows.findIndex((row) => /^\|[\s\-:|]+\|$/.test(row));
2118
+ if (separatorIdx === 1) {
2119
+ const headerRow = rows[0];
2120
+ const dataRows = rows.slice(2);
2121
+ const headerCells = headerRow.split("|").filter((c) => c.trim());
2122
+ const headerHtml = `<thead><tr>${headerCells.map((c) => `<th>${c.trim()}</th>`).join("")}</tr></thead>`;
2123
+ const bodyHtml = dataRows.map((row) => {
2124
+ const cells = row.split("|").filter((c) => c.trim());
2125
+ return `<tr>${cells.map((c) => `<td>${c.trim()}</td>`).join("")}</tr>`;
2126
+ }).join("");
2127
+ const tableHtml = `<table>${headerHtml}<tbody>${bodyHtml}</tbody></table>`;
2128
+ const tableMarkdown = rows.slice(0, separatorIdx + 1 + dataRows.length).join(`
2129
+ `);
2130
+ html = html.replace(tableMarkdown, tableHtml);
2131
+ }
2132
+ }
2133
+ }
2134
+ html = html.replace(/^(?!<[a-z]|$)(.+)$/gm, "<p>$1</p>");
2135
+ html = html.replace(/<p>(<(?:h[1-6]|ul|ol|li|blockquote|pre|table|hr)[^>]*>)/g, "$1");
2136
+ html = html.replace(/(<\/(?:h[1-6]|ul|ol|li|blockquote|pre|table|hr)>)<\/p>/g, "$1");
2137
+ html = html.replace(/\n\n/g, "</p><p>");
2138
+ html = html.replace(/\n/g, "<br />");
2139
+ return html;
2140
+ }
2141
+ function parseLatex(text, options = {}) {
2142
+ const { mode = "auto", displayMode = false } = options;
2143
+ const isBlock = mode === "block" || mode === "auto" && (text.includes("\\[") || text.includes("$$"));
2144
+ let html = text;
2145
+ html = html.replace(/\$\$([\s\S]+?)\$\$/g, '<div class="math-block">$1</div>');
2146
+ html = html.replace(/\\\[([\s\S]+?)\\\]/g, '<div class="math-block">$1</div>');
2147
+ html = html.replace(/\$([^$]+)\$/g, '<span class="math-inline">$1</span>');
2148
+ html = html.replace(/\\\((.+?)\\\)/g, '<span class="math-inline">$1</span>');
2149
+ const symbols = {
2150
+ "\\alpha": "α",
2151
+ "\\beta": "β",
2152
+ "\\gamma": "γ",
2153
+ "\\delta": "δ",
2154
+ "\\epsilon": "ε",
2155
+ "\\zeta": "ζ",
2156
+ "\\eta": "η",
2157
+ "\\theta": "θ",
2158
+ "\\iota": "ι",
2159
+ "\\kappa": "κ",
2160
+ "\\lambda": "λ",
2161
+ "\\mu": "μ",
2162
+ "\\nu": "ν",
2163
+ "\\xi": "ξ",
2164
+ "\\pi": "π",
2165
+ "\\rho": "ρ",
2166
+ "\\sigma": "σ",
2167
+ "\\tau": "τ",
2168
+ "\\upsilon": "υ",
2169
+ "\\phi": "φ",
2170
+ "\\chi": "χ",
2171
+ "\\psi": "ψ",
2172
+ "\\omega": "ω",
2173
+ "\\Gamma": "Γ",
2174
+ "\\Delta": "Δ",
2175
+ "\\Theta": "Θ",
2176
+ "\\Lambda": "Λ",
2177
+ "\\Xi": "Ξ",
2178
+ "\\Pi": "Π",
2179
+ "\\Sigma": "Σ",
2180
+ "\\Phi": "Φ",
2181
+ "\\Psi": "Ψ",
2182
+ "\\Omega": "Ω",
2183
+ "\\infty": "∞",
2184
+ "\\pm": "±",
2185
+ "\\mp": "∓",
2186
+ "\\times": "×",
2187
+ "\\div": "÷",
2188
+ "\\cdot": "·",
2189
+ "\\leq": "≤",
2190
+ "\\geq": "≥",
2191
+ "\\neq": "≠",
2192
+ "\\approx": "≈",
2193
+ "\\equiv": "≡",
2194
+ "\\subset": "⊂",
2195
+ "\\supset": "⊃",
2196
+ "\\in": "∈",
2197
+ "\\notin": "∉",
2198
+ "\\cup": "∪",
2199
+ "\\cap": "∩",
2200
+ "\\emptyset": "∅",
2201
+ "\\forall": "∀",
2202
+ "\\exists": "∃",
2203
+ "\\nabla": "∇",
2204
+ "\\partial": "∂",
2205
+ "\\sum": "∑",
2206
+ "\\prod": "∏",
2207
+ "\\int": "∫",
2208
+ "\\oint": "∮",
2209
+ "\\sqrt": "√",
2210
+ "\\therefore": "∴",
2211
+ "\\because": "∵",
2212
+ "\\angle": "∠",
2213
+ "\\perp": "⊥",
2214
+ "\\parallel": "∥",
2215
+ "\\rightarrow": "→",
2216
+ "\\leftarrow": "←",
2217
+ "\\Rightarrow": "⇒",
2218
+ "\\Leftarrow": "⇐",
2219
+ "\\leftrightarrow": "↔",
2220
+ "\\Leftrightarrow": "⇔"
2221
+ };
2222
+ for (const [latex, symbol] of Object.entries(symbols)) {
2223
+ html = html.replace(new RegExp(latex.replace(/\\/g, "\\\\"), "g"), symbol);
2224
+ }
2225
+ html = html.replace(/\\frac\{([^}]+)\}\{([^}]+)\}/g, '<span class="frac"><span class="num">$1</span><span class="den">$2</span></span>');
2226
+ html = html.replace(/\^{([^}]+)}/g, "<sup>$1</sup>");
2227
+ html = html.replace(/\^(\w)/g, "<sup>$1</sup>");
2228
+ html = html.replace(/_{([^}]+)}/g, "<sub>$1</sub>");
2229
+ html = html.replace(/_(\w)/g, "<sub>$1</sub>");
2230
+ html = html.replace(/\\sqrt\{([^}]+)\}/g, "√($1)");
2231
+ html = html.replace(/\\textbf\{([^}]+)\}/g, "<strong>$1</strong>");
2232
+ html = html.replace(/\\textit\{([^}]+)\}/g, "<em>$1</em>");
2233
+ html = html.replace(/\\text\{([^}]+)\}/g, "$1");
2234
+ html = html.replace(/\\[a-zA-Z]+/g, "");
2235
+ if (displayMode || isBlock) {
2236
+ html = `<div class="math-display">${html}</div>`;
2237
+ }
2238
+ return html;
2239
+ }
2240
+ function formatJson(text, options = {}) {
2241
+ const { indent = 2, syntaxHighlight = true } = options;
2242
+ try {
2243
+ const parsed = JSON.parse(text);
2244
+ const formatted = JSON.stringify(parsed, null, indent);
2245
+ if (!syntaxHighlight) {
2246
+ return `<pre><code>${escapeHtml(formatted)}</code></pre>`;
2247
+ }
2248
+ let highlighted = escapeHtml(formatted);
2249
+ highlighted = highlighted.replace(/("(?:[^"\\]|\\.)*")\s*:/g, '<span class="json-key">$1</span>:');
2250
+ highlighted = highlighted.replace(/:\s*("(?:[^"\\]|\\.)*")/g, ': <span class="json-string">$1</span>');
2251
+ highlighted = highlighted.replace(/:\s*(-?\d+\.?\d*(?:[eE][+-]?\d+)?)/g, ': <span class="json-number">$1</span>');
2252
+ highlighted = highlighted.replace(/:\s*(true|false|null)/g, ': <span class="json-$1">$1</span>');
2253
+ return `<pre class="json-highlight"><code>${highlighted}</code></pre>`;
2254
+ } catch {
2255
+ return `<pre><code>${escapeHtml(text)}</code></pre>`;
2256
+ }
2257
+ }
2258
+ function escapeHtml(text) {
2259
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
2260
+ }
2261
+ function formatCode(text, options = {}) {
2262
+ const { language, lineNumbers = false, startLine = 1, highlightLines = [] } = options;
2263
+ const lines = text.split(`
2264
+ `);
2265
+ const langClass = language ? ` language-${language}` : "";
2266
+ if (!lineNumbers) {
2267
+ return `<pre><code class="code-block${langClass}">${escapeHtml(text)}</code></pre>`;
2268
+ }
2269
+ const lineHtml = lines.map((line, i) => {
2270
+ const lineNum = startLine + i;
2271
+ const isHighlighted = highlightLines.includes(lineNum);
2272
+ const highlightClass = isHighlighted ? " highlighted" : "";
2273
+ return `<span class="line${highlightClass}"><span class="line-number">${lineNum}</span><span class="line-content">${escapeHtml(line)}</span></span>`;
2274
+ }).join(`
2275
+ `);
2276
+ return `<pre class="code-with-lines${langClass}"><code>${lineHtml}</code></pre>`;
2277
+ }
2278
+ var useESIContext = null, ESIMarkdown = ({
2279
+ children,
2280
+ className,
2281
+ as: Wrapper = "div",
2282
+ fallback,
2283
+ gfm = true,
2284
+ syntaxHighlight = false,
2285
+ allowHtml = false,
2286
+ linkTarget = "_blank"
2287
+ }) => {
2288
+ const [output, setOutput] = useState2(null);
2289
+ const [isLoading, setIsLoading] = useState2(true);
2290
+ if (typeof children === "string") {
2291
+ const html2 = parseMarkdown(children, { gfm, allowHtml, linkTarget });
2292
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2293
+ className,
2294
+ dangerouslySetInnerHTML: { __html: html2 }
2295
+ }, undefined, false, undefined, this);
2296
+ }
2297
+ const wrappedChildren = useMemo2(() => {
2298
+ return wrapChildren(children, (text) => {
2299
+ setOutput(text);
2300
+ setIsLoading(false);
2301
+ });
2302
+ }, [children]);
2303
+ if (isLoading) {
2304
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2305
+ className,
2306
+ children: wrappedChildren
2307
+ }, undefined, false, undefined, this);
2308
+ }
2309
+ if (!output) {
2310
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2311
+ className,
2312
+ children: fallback
2313
+ }, undefined, false, undefined, this);
2314
+ }
2315
+ const html = parseMarkdown(output, { gfm, allowHtml, linkTarget });
2316
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2317
+ className: `esi-markdown ${className || ""}`,
2318
+ dangerouslySetInnerHTML: { __html: html }
2319
+ }, undefined, false, undefined, this);
2320
+ }, ESILatex = ({
2321
+ children,
2322
+ className,
2323
+ as: Wrapper = "div",
2324
+ fallback,
2325
+ mode = "auto",
2326
+ displayMode = false
2327
+ }) => {
2328
+ const [output, setOutput] = useState2(null);
2329
+ const [isLoading, setIsLoading] = useState2(true);
2330
+ if (typeof children === "string") {
2331
+ const html2 = parseLatex(children, { mode, displayMode });
2332
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2333
+ className: `esi-latex ${className || ""}`,
2334
+ dangerouslySetInnerHTML: { __html: html2 }
2335
+ }, undefined, false, undefined, this);
2336
+ }
2337
+ const wrappedChildren = useMemo2(() => {
2338
+ return wrapChildren(children, (text) => {
2339
+ setOutput(text);
2340
+ setIsLoading(false);
2341
+ });
2342
+ }, [children]);
2343
+ if (isLoading) {
2344
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2345
+ className,
2346
+ children: wrappedChildren
2347
+ }, undefined, false, undefined, this);
2348
+ }
2349
+ if (!output) {
2350
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2351
+ className,
2352
+ children: fallback
2353
+ }, undefined, false, undefined, this);
2354
+ }
2355
+ const html = parseLatex(output, { mode, displayMode });
2356
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2357
+ className: `esi-latex ${className || ""}`,
2358
+ dangerouslySetInnerHTML: { __html: html }
2359
+ }, undefined, false, undefined, this);
2360
+ }, ESIJson = ({
2361
+ children,
2362
+ className,
2363
+ as: Wrapper = "div",
2364
+ fallback,
2365
+ indent = 2,
2366
+ syntaxHighlight = true,
2367
+ theme = "auto",
2368
+ copyable = false
2369
+ }) => {
2370
+ const [output, setOutput] = useState2(null);
2371
+ const [isLoading, setIsLoading] = useState2(true);
2372
+ const [copied, setCopied] = useState2(false);
2373
+ const handleCopy = () => {
2374
+ if (output) {
2375
+ navigator.clipboard.writeText(output);
2376
+ setCopied(true);
2377
+ setTimeout(() => setCopied(false), 2000);
2378
+ }
2379
+ };
2380
+ if (typeof children === "string") {
2381
+ const html2 = formatJson(children, { indent, syntaxHighlight, theme });
2382
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2383
+ className: `esi-json ${className || ""}`,
2384
+ children: [
2385
+ copyable && /* @__PURE__ */ jsxDEV2("button", {
2386
+ className: "esi-json-copy",
2387
+ onClick: handleCopy,
2388
+ "aria-label": "Copy JSON",
2389
+ children: copied ? "✓" : "⎘"
2390
+ }, undefined, false, undefined, this),
2391
+ /* @__PURE__ */ jsxDEV2("div", {
2392
+ dangerouslySetInnerHTML: { __html: html2 }
2393
+ }, undefined, false, undefined, this)
2394
+ ]
2395
+ }, undefined, true, undefined, this);
2396
+ }
2397
+ const wrappedChildren = useMemo2(() => {
2398
+ return wrapChildren(children, (text) => {
2399
+ setOutput(text);
2400
+ setIsLoading(false);
2401
+ });
2402
+ }, [children]);
2403
+ if (isLoading) {
2404
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2405
+ className,
2406
+ children: wrappedChildren
2407
+ }, undefined, false, undefined, this);
2408
+ }
2409
+ if (!output) {
2410
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2411
+ className,
2412
+ children: fallback
2413
+ }, undefined, false, undefined, this);
2414
+ }
2415
+ const html = formatJson(output, { indent, syntaxHighlight, theme });
2416
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2417
+ className: `esi-json ${className || ""}`,
2418
+ children: [
2419
+ copyable && /* @__PURE__ */ jsxDEV2("button", {
2420
+ className: "esi-json-copy",
2421
+ onClick: handleCopy,
2422
+ "aria-label": "Copy JSON",
2423
+ children: copied ? "✓" : "⎘"
2424
+ }, undefined, false, undefined, this),
2425
+ /* @__PURE__ */ jsxDEV2("div", {
2426
+ dangerouslySetInnerHTML: { __html: html }
2427
+ }, undefined, false, undefined, this)
2428
+ ]
2429
+ }, undefined, true, undefined, this);
2430
+ }, ESIPlaintext = ({
2431
+ children,
2432
+ className,
2433
+ as: Wrapper = "div",
2434
+ fallback,
2435
+ preserveWhitespace = true,
2436
+ wordWrap = true,
2437
+ maxWidth
2438
+ }) => {
2439
+ const [output, setOutput] = useState2(null);
2440
+ const [isLoading, setIsLoading] = useState2(true);
2441
+ const style = useMemo2(() => ({
2442
+ whiteSpace: preserveWhitespace ? "pre-wrap" : "normal",
2443
+ wordWrap: wordWrap ? "break-word" : "normal",
2444
+ maxWidth: maxWidth ? `${maxWidth}ch` : undefined,
2445
+ fontFamily: "monospace"
2446
+ }), [preserveWhitespace, wordWrap, maxWidth]);
2447
+ if (typeof children === "string") {
2448
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2449
+ className: `esi-plaintext ${className || ""}`,
2450
+ style,
2451
+ children
2452
+ }, undefined, false, undefined, this);
2453
+ }
2454
+ const wrappedChildren = useMemo2(() => {
2455
+ return wrapChildren(children, (text) => {
2456
+ setOutput(text);
2457
+ setIsLoading(false);
2458
+ });
2459
+ }, [children]);
2460
+ if (isLoading) {
2461
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2462
+ className,
2463
+ children: wrappedChildren
2464
+ }, undefined, false, undefined, this);
2465
+ }
2466
+ if (!output) {
2467
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2468
+ className,
2469
+ children: fallback
2470
+ }, undefined, false, undefined, this);
2471
+ }
2472
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2473
+ className: `esi-plaintext ${className || ""}`,
2474
+ style,
2475
+ children: output
2476
+ }, undefined, false, undefined, this);
2477
+ }, ESICode = ({
2478
+ children,
2479
+ className,
2480
+ as: Wrapper = "div",
2481
+ fallback,
2482
+ language,
2483
+ autoDetect = false,
2484
+ generateFrom,
2485
+ model = "codestral",
2486
+ lineNumbers = false,
2487
+ startLine = 1,
2488
+ highlightLines = [],
2489
+ copyable = false,
2490
+ temperature = 0.2,
2491
+ onLanguageDetect,
2492
+ onGenerate
2493
+ }) => {
2494
+ const [output, setOutput] = useState2(null);
2495
+ const [detectedLang, setDetectedLang] = useState2(language);
2496
+ const [isLoading, setIsLoading] = useState2(true);
2497
+ const [isGenerating, setIsGenerating] = useState2(false);
2498
+ const [copied, setCopied] = useState2(false);
2499
+ const handleCopy = useCallback2(() => {
2500
+ if (output) {
2501
+ navigator.clipboard.writeText(output);
2502
+ setCopied(true);
2503
+ setTimeout(() => setCopied(false), 2000);
2504
+ }
2505
+ }, [output]);
2506
+ const extractCode = useCallback2((text) => {
2507
+ const match = text.match(/```(\w*)\n?([\s\S]*?)```/);
2508
+ if (match) {
2509
+ return { code: match[2].trim(), lang: match[1] || undefined };
2510
+ }
2511
+ return { code: text };
2512
+ }, []);
2513
+ useEffect2(() => {
2514
+ if (!generateFrom || !useESIContext)
2515
+ return;
2516
+ setIsGenerating(true);
2517
+ setIsLoading(true);
2518
+ const generateCode = async () => {
2519
+ try {
2520
+ const esi = useESIContext();
2521
+ const langHint = language ? ` in ${language}` : "";
2522
+ const prompt = `Generate clean, production-ready code${langHint} for the following requirement. Output ONLY the code, no explanations:
2523
+
2524
+ ${generateFrom}`;
2525
+ const result = await esi.process({
2526
+ id: `esi-code-gen-${Date.now()}`,
2527
+ params: {
2528
+ model: "llm",
2529
+ variant: model,
2530
+ temperature,
2531
+ system: `You are an expert programmer. Generate clean, well-documented code. Output ONLY code wrapped in a markdown code block with the language specified. No explanations before or after.`
2532
+ },
2533
+ content: {
2534
+ type: "text",
2535
+ value: prompt
2536
+ }
2537
+ });
2538
+ if (result.success && result.output) {
2539
+ const { code: code2, lang: lang2 } = extractCode(result.output);
2540
+ setOutput(code2);
2541
+ const finalLang2 = language || lang2;
2542
+ setDetectedLang(finalLang2);
2543
+ onGenerate?.(code2, finalLang2 || "text");
2544
+ }
2545
+ } catch (err) {
2546
+ console.error("Code generation failed:", err);
2547
+ } finally {
2548
+ setIsLoading(false);
2549
+ setIsGenerating(false);
2550
+ }
2551
+ };
2552
+ generateCode();
2553
+ }, [generateFrom, model, language, temperature, extractCode, onGenerate]);
2554
+ useEffect2(() => {
2555
+ if (!autoDetect || !output || detectedLang || !useESIContext)
2556
+ return;
2557
+ const detectLanguage = async () => {
2558
+ try {
2559
+ const esi = useESIContext();
2560
+ const result = await esi.process({
2561
+ id: `esi-lang-detect-${Date.now()}`,
2562
+ params: {
2563
+ model: "llm",
2564
+ variant: model,
2565
+ temperature: 0,
2566
+ maxTokens: 20,
2567
+ system: "You are a code language detector. Respond with ONLY the programming language name, nothing else."
2568
+ },
2569
+ content: {
2570
+ type: "text",
2571
+ value: `What programming language is this code written in?
2572
+
2573
+ ${output.slice(0, 500)}`
2574
+ }
2575
+ });
2576
+ if (result.success && result.output) {
2577
+ const lang2 = result.output.trim().toLowerCase();
2578
+ setDetectedLang(lang2);
2579
+ onLanguageDetect?.(lang2);
2580
+ }
2581
+ } catch (err) {
2582
+ console.error("Language detection failed:", err);
2583
+ }
2584
+ };
2585
+ detectLanguage();
2586
+ }, [autoDetect, output, detectedLang, model, onLanguageDetect]);
2587
+ if (typeof children === "string" && !generateFrom) {
2588
+ const { code: code2, lang: lang2 } = extractCode(children);
2589
+ const finalLang2 = language || lang2 || detectedLang;
2590
+ const html2 = formatCode(code2, {
2591
+ language: finalLang2,
2592
+ lineNumbers,
2593
+ startLine,
2594
+ highlightLines
2595
+ });
2596
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2597
+ className: `esi-code ${className || ""}`,
2598
+ children: [
2599
+ copyable && /* @__PURE__ */ jsxDEV2("button", {
2600
+ className: "esi-code-copy",
2601
+ onClick: handleCopy,
2602
+ "aria-label": "Copy code",
2603
+ children: copied ? "✓" : "⎘"
2604
+ }, undefined, false, undefined, this),
2605
+ /* @__PURE__ */ jsxDEV2("div", {
2606
+ dangerouslySetInnerHTML: { __html: html2 }
2607
+ }, undefined, false, undefined, this)
2608
+ ]
2609
+ }, undefined, true, undefined, this);
2610
+ }
2611
+ if (generateFrom && isGenerating) {
2612
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2613
+ className: `esi-code esi-code-generating ${className || ""}`,
2614
+ children: /* @__PURE__ */ jsxDEV2("div", {
2615
+ className: "esi-code-loading",
2616
+ children: "Generating code..."
2617
+ }, undefined, false, undefined, this)
2618
+ }, undefined, false, undefined, this);
2619
+ }
2620
+ const wrappedChildren = useMemo2(() => {
2621
+ if (generateFrom)
2622
+ return null;
2623
+ return wrapChildren(children, (text) => {
2624
+ setOutput(text);
2625
+ setIsLoading(false);
2626
+ });
2627
+ }, [children, generateFrom]);
2628
+ if (isLoading && !generateFrom) {
2629
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2630
+ className,
2631
+ children: wrappedChildren
2632
+ }, undefined, false, undefined, this);
2633
+ }
2634
+ if (!output) {
2635
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2636
+ className,
2637
+ children: fallback
2638
+ }, undefined, false, undefined, this);
2639
+ }
2640
+ const { code, lang } = extractCode(output);
2641
+ const finalLang = language || lang || detectedLang;
2642
+ const html = formatCode(code, {
2643
+ language: finalLang,
2644
+ lineNumbers,
2645
+ startLine,
2646
+ highlightLines
2647
+ });
2648
+ return /* @__PURE__ */ jsxDEV2(Wrapper, {
2649
+ className: `esi-code ${className || ""}`,
2650
+ children: [
2651
+ copyable && /* @__PURE__ */ jsxDEV2("button", {
2652
+ className: "esi-code-copy",
2653
+ onClick: handleCopy,
2654
+ "aria-label": "Copy code",
2655
+ children: copied ? "✓" : "⎘"
2656
+ }, undefined, false, undefined, this),
2657
+ /* @__PURE__ */ jsxDEV2("div", {
2658
+ dangerouslySetInnerHTML: { __html: html }
2659
+ }, undefined, false, undefined, this)
2660
+ ]
2661
+ }, undefined, true, undefined, this);
2662
+ };
2663
+ var init_esi_format_react = __esm(() => {
2664
+ try {
2665
+ const esiReact = (init_esi_react(), __toCommonJS(exports_esi_react));
2666
+ useESIContext = esiReact.useESI;
2667
+ } catch {}
2668
+ });
2669
+
2670
+ // src/router/esi-react.tsx
2671
+ var exports_esi_react = {};
2672
+ __export(exports_esi_react, {
2673
+ useMeetsTierRequirement: () => useMeetsTierRequirement,
2674
+ useIsAdmin: () => useIsAdmin,
2675
+ useGlobalESIState: () => useGlobalESIState,
2676
+ useESITier: () => useESITier,
2677
+ useESIPreferences: () => useESIPreferences,
2678
+ useESIInfer: () => useESIInfer,
2679
+ useESIFeature: () => useESIFeature,
2680
+ useESIEmotionState: () => useESIEmotionState,
2681
+ useESI: () => useESI,
2682
+ updateGlobalESIState: () => updateGlobalESIState,
2683
+ default: () => esi_react_default,
2684
+ ESIVision: () => ESIVision,
2685
+ ESIProvider: () => ESIProvider,
2686
+ ESIInfer: () => ESIInfer,
2687
+ ESIEmotion: () => ESIEmotion,
2688
+ ESIEmbed: () => ESIEmbed,
2689
+ ESI: () => ESI
2690
+ });
2691
+ import {
2692
+ createContext as createContext3,
2693
+ useContext as useContext3,
2694
+ useEffect as useEffect3,
2695
+ useState as useState3,
2696
+ useCallback as useCallback3
2697
+ } from "react";
2698
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
2699
+ function useESI() {
2700
+ const ctx = useContext3(ESIContext);
2701
+ if (!ctx) {
2702
+ throw new Error("useESI must be used within an ESIProvider");
2703
+ }
2704
+ return ctx;
2705
+ }
2706
+ function useESIInfer(options = {}) {
2707
+ const { process: process2, processWithStream, enabled } = useESI();
2708
+ const [result, setResult] = useState3(null);
2709
+ const [isLoading, setIsLoading] = useState3(false);
2710
+ const [error, setError] = useState3(null);
2711
+ const run = useCallback3(async (prompt) => {
2712
+ if (!enabled) {
2713
+ setError("ESI is disabled");
2714
+ return null;
2715
+ }
2716
+ setIsLoading(true);
2717
+ setError(null);
2718
+ const directive = options.contextAware ? esiWithContext(prompt, options.signals, {
2719
+ model: options.model,
2720
+ variant: options.variant,
2721
+ temperature: options.temperature,
2722
+ maxTokens: options.maxTokens,
2723
+ system: options.system,
2724
+ cacheTtl: options.cacheTtl
2725
+ }) : esiInfer(prompt, {
2726
+ model: options.model,
2727
+ variant: options.variant,
2728
+ temperature: options.temperature,
2729
+ maxTokens: options.maxTokens,
2730
+ system: options.system,
2731
+ cacheTtl: options.cacheTtl
2732
+ });
2733
+ try {
2734
+ let inferenceResult;
2735
+ if (options.stream) {
2736
+ let output = "";
2737
+ inferenceResult = await processWithStream(directive, (chunk) => {
2738
+ output += chunk;
2739
+ setResult((prev) => ({
2740
+ ...prev,
2741
+ output
2742
+ }));
2743
+ });
2744
+ } else {
2745
+ inferenceResult = await process2(directive);
2746
+ }
2747
+ setResult(inferenceResult);
2748
+ setIsLoading(false);
2749
+ if (!inferenceResult.success) {
2750
+ setError(inferenceResult.error || "Inference failed");
2751
+ }
2752
+ options.onComplete?.(inferenceResult);
2753
+ return inferenceResult;
2754
+ } catch (err) {
2755
+ const errorMsg = err instanceof Error ? err.message : "Unknown error";
2756
+ setError(errorMsg);
2757
+ setIsLoading(false);
2758
+ options.onError?.(errorMsg);
2759
+ return null;
2760
+ }
2761
+ }, [process2, processWithStream, enabled, options]);
2762
+ const reset = useCallback3(() => {
2763
+ setResult(null);
2764
+ setError(null);
2765
+ setIsLoading(false);
2766
+ }, []);
2767
+ return { run, result, isLoading, error, reset };
2768
+ }
2769
+ function useGlobalESIState() {
2770
+ const [state, setState] = useState3(() => {
2771
+ if (typeof window !== "undefined" && window.__AEON_ESI_STATE__) {
2772
+ return window.__AEON_ESI_STATE__;
2773
+ }
2774
+ return DEFAULT_ESI_STATE;
2775
+ });
2776
+ useEffect3(() => {
2777
+ if (typeof window !== "undefined" && window.__AEON_ESI_STATE__?.subscribe) {
2778
+ const unsubscribe = window.__AEON_ESI_STATE__.subscribe((newState) => {
2779
+ setState(newState);
2780
+ });
2781
+ return unsubscribe;
2782
+ }
2783
+ }, []);
2784
+ return state;
2785
+ }
2786
+ function useESIFeature(feature) {
2787
+ const { features, isAdmin, userTier } = useGlobalESIState();
2788
+ if (isAdmin === true || userTier === "admin") {
2789
+ return true;
2790
+ }
2791
+ return features[feature] ?? false;
2792
+ }
2793
+ function useIsAdmin() {
2794
+ const { isAdmin, userTier } = useGlobalESIState();
2795
+ return isAdmin === true || userTier === "admin";
2796
+ }
2797
+ function useESITier() {
2798
+ const { userTier } = useGlobalESIState();
2799
+ return userTier;
2800
+ }
2801
+ function useMeetsTierRequirement(requiredTier) {
2802
+ const { userTier, isAdmin } = useGlobalESIState();
2803
+ if (isAdmin === true || userTier === "admin") {
2804
+ return true;
2805
+ }
2806
+ const userLevel = TIER_ORDER[userTier] ?? 0;
2807
+ const requiredLevel = TIER_ORDER[requiredTier] ?? 0;
2808
+ return userLevel >= requiredLevel;
2809
+ }
2810
+ function useESIEmotionState() {
2811
+ const { emotionState } = useGlobalESIState();
2812
+ return emotionState;
2813
+ }
2814
+ function useESIPreferences() {
2815
+ const { preferences } = useGlobalESIState();
2816
+ return preferences;
2817
+ }
2818
+ function updateGlobalESIState(partial) {
2819
+ if (typeof window !== "undefined" && window.__AEON_ESI_STATE__?.update) {
2820
+ window.__AEON_ESI_STATE__.update(partial);
2821
+ } else if (typeof window !== "undefined" && window.__AEON_ESI_STATE__) {
2822
+ Object.assign(window.__AEON_ESI_STATE__, partial);
2823
+ }
2824
+ }
2825
+ var ESIContext, ESIProvider = ({
2826
+ children,
2827
+ config,
2828
+ userContext,
2829
+ processor: customProcessor
2830
+ }) => {
2831
+ const [processor] = useState3(() => customProcessor || new EdgeWorkersESIProcessor(config));
2832
+ useEffect3(() => {
2833
+ processor.warmup?.();
2834
+ }, [processor]);
2835
+ const process2 = useCallback3(async (directive) => {
2836
+ if (!userContext) {
2837
+ return {
2838
+ id: directive.id,
2839
+ success: false,
2840
+ error: "No user context available",
2841
+ latencyMs: 0,
2842
+ cached: false,
2843
+ model: directive.params.model
2844
+ };
2845
+ }
2846
+ return processor.process(directive, userContext);
2847
+ }, [processor, userContext]);
2848
+ const processWithStream = useCallback3(async (directive, onChunk) => {
2849
+ if (!userContext) {
2850
+ return {
2851
+ id: directive.id,
2852
+ success: false,
2853
+ error: "No user context available",
2854
+ latencyMs: 0,
2855
+ cached: false,
2856
+ model: directive.params.model
2857
+ };
2858
+ }
2859
+ if (!processor.stream) {
2860
+ return processor.process(directive, userContext);
2861
+ }
2862
+ return processor.stream(directive, userContext, onChunk);
2863
+ }, [processor, userContext]);
2864
+ return /* @__PURE__ */ jsxDEV3(ESIContext.Provider, {
2865
+ value: {
2866
+ processor,
2867
+ userContext: userContext || null,
2868
+ enabled: config?.enabled ?? true,
2869
+ process: process2,
2870
+ processWithStream
2871
+ },
2872
+ children
2873
+ }, undefined, false, undefined, this);
2874
+ }, ESIInfer = ({
2875
+ children,
2876
+ prompt,
2877
+ model = "llm",
2878
+ variant,
2879
+ temperature,
2880
+ maxTokens,
2881
+ system,
2882
+ stream = false,
2883
+ fallback,
2884
+ loading = "...",
2885
+ contextAware = false,
2886
+ signals,
2887
+ cacheTtl,
2888
+ render,
2889
+ className,
2890
+ onComplete,
2891
+ onError
2892
+ }) => {
2893
+ const { process: process2, processWithStream, enabled } = useESI();
2894
+ const [output, setOutput] = useState3("");
2895
+ const [isLoading, setIsLoading] = useState3(true);
2896
+ const [error, setError] = useState3(null);
2897
+ const promptText = prompt || (typeof children === "string" ? children : String(children || ""));
2898
+ useEffect3(() => {
2899
+ if (!enabled) {
2900
+ setOutput(typeof fallback === "string" ? fallback : "");
2901
+ setIsLoading(false);
2902
+ return;
2903
+ }
2904
+ const directive = contextAware ? esiWithContext(promptText, signals, {
2905
+ model,
2906
+ variant,
2907
+ temperature,
2908
+ maxTokens,
2909
+ system,
2910
+ cacheTtl,
2911
+ fallback: typeof fallback === "string" ? fallback : undefined
2912
+ }) : esiInfer(promptText, {
2913
+ model,
2914
+ variant,
2915
+ temperature,
2916
+ maxTokens,
2917
+ system,
2918
+ cacheTtl,
2919
+ fallback: typeof fallback === "string" ? fallback : undefined
2920
+ });
2921
+ if (stream) {
2922
+ setOutput("");
2923
+ processWithStream(directive, (chunk) => {
2924
+ setOutput((prev) => prev + chunk);
2925
+ }).then((result) => {
2926
+ setIsLoading(false);
2927
+ if (!result.success) {
2928
+ setError(result.error || "Inference failed");
2929
+ onError?.(result.error || "Inference failed");
2930
+ }
2931
+ onComplete?.(result);
2932
+ });
2933
+ } else {
2934
+ process2(directive).then((result) => {
2935
+ setIsLoading(false);
2936
+ if (result.success && result.output) {
2937
+ setOutput(result.output);
2938
+ } else {
2939
+ setError(result.error || "Inference failed");
2940
+ onError?.(result.error || "Inference failed");
2941
+ }
2942
+ onComplete?.(result);
2943
+ });
2944
+ }
2945
+ }, [promptText, model, variant, temperature, maxTokens, system, contextAware, stream, enabled]);
2946
+ if (isLoading && !stream) {
2947
+ return /* @__PURE__ */ jsxDEV3("span", {
2948
+ className,
2949
+ children: loading
2950
+ }, undefined, false, undefined, this);
2951
+ }
2952
+ if (error && fallback) {
2953
+ return /* @__PURE__ */ jsxDEV3("span", {
2954
+ className,
2955
+ children: fallback
2956
+ }, undefined, false, undefined, this);
2957
+ }
2958
+ if (render) {
2959
+ return /* @__PURE__ */ jsxDEV3("span", {
2960
+ className,
2961
+ children: render({
2962
+ id: "",
2963
+ success: !error,
2964
+ output,
2965
+ error: error || undefined,
2966
+ latencyMs: 0,
2967
+ cached: false,
2968
+ model
2969
+ })
2970
+ }, undefined, false, undefined, this);
2971
+ }
2972
+ return /* @__PURE__ */ jsxDEV3("span", {
2973
+ className,
2974
+ children: output || (isLoading ? loading : "")
2975
+ }, undefined, false, undefined, this);
2976
+ }, ESIEmbed = ({ children, onComplete, onError }) => {
2977
+ const { process: process2, enabled } = useESI();
2978
+ const text = typeof children === "string" ? children : String(children || "");
2979
+ useEffect3(() => {
2980
+ if (!enabled)
2981
+ return;
2982
+ const directive = esiEmbed(text);
2983
+ process2(directive).then((result) => {
2984
+ if (result.success && result.embedding) {
2985
+ onComplete?.(result.embedding);
2986
+ } else {
2987
+ onError?.(result.error || "Embedding failed");
2988
+ }
2989
+ });
2990
+ }, [text, enabled]);
2991
+ return null;
2992
+ }, ESIEmotion = ({
2993
+ children,
2994
+ contextAware = true,
2995
+ onComplete,
2996
+ onError
2997
+ }) => {
2998
+ const { process: process2, enabled } = useESI();
2999
+ const text = typeof children === "string" ? children : String(children || "");
3000
+ useEffect3(() => {
3001
+ if (!enabled)
3002
+ return;
3003
+ const directive = esiEmotion(text, contextAware);
3004
+ process2(directive).then((result) => {
3005
+ if (result.success && result.output) {
3006
+ try {
3007
+ const parsed = JSON.parse(result.output);
3008
+ onComplete?.(parsed);
3009
+ } catch {
3010
+ onComplete?.({ emotion: result.output, confidence: 1 });
3011
+ }
3012
+ } else {
3013
+ onError?.(result.error || "Emotion detection failed");
3014
+ }
3015
+ });
3016
+ }, [text, contextAware, enabled]);
3017
+ return null;
3018
+ }, ESIVision = ({
3019
+ src,
3020
+ prompt,
3021
+ fallback,
3022
+ loading = "...",
3023
+ className,
3024
+ onComplete,
3025
+ onError
3026
+ }) => {
3027
+ const { process: process2, enabled } = useESI();
3028
+ const [output, setOutput] = useState3("");
3029
+ const [isLoading, setIsLoading] = useState3(true);
3030
+ const [error, setError] = useState3(null);
3031
+ useEffect3(() => {
3032
+ if (!enabled) {
3033
+ setOutput(typeof fallback === "string" ? fallback : "");
3034
+ setIsLoading(false);
3035
+ return;
3036
+ }
3037
+ const directive = esiVision(src, prompt);
3038
+ process2(directive).then((result) => {
3039
+ setIsLoading(false);
3040
+ if (result.success && result.output) {
3041
+ setOutput(result.output);
3042
+ } else {
3043
+ setError(result.error || "Vision analysis failed");
3044
+ onError?.(result.error || "Vision analysis failed");
3045
+ }
3046
+ onComplete?.(result);
3047
+ });
3048
+ }, [src, prompt, enabled]);
3049
+ if (isLoading) {
3050
+ return /* @__PURE__ */ jsxDEV3("span", {
3051
+ className,
3052
+ children: loading
3053
+ }, undefined, false, undefined, this);
3054
+ }
3055
+ if (error && fallback) {
3056
+ return /* @__PURE__ */ jsxDEV3("span", {
3057
+ className,
3058
+ children: fallback
3059
+ }, undefined, false, undefined, this);
3060
+ }
3061
+ return /* @__PURE__ */ jsxDEV3("span", {
3062
+ className,
3063
+ children: output
3064
+ }, undefined, false, undefined, this);
3065
+ }, DEFAULT_ESI_STATE, TIER_ORDER, ESI, esi_react_default;
3066
+ var init_esi_react = __esm(() => {
3067
+ init_esi();
3068
+ init_esi_control_react();
3069
+ init_esi_format_react();
3070
+ ESIContext = createContext3(null);
3071
+ DEFAULT_ESI_STATE = {
3072
+ userTier: "free",
3073
+ emotionState: null,
3074
+ preferences: {
3075
+ theme: "auto",
3076
+ reducedMotion: false
3077
+ },
3078
+ localHour: new Date().getHours(),
3079
+ timezone: "UTC",
3080
+ features: {
3081
+ aiInference: true,
3082
+ emotionTracking: true,
3083
+ collaboration: false,
3084
+ advancedInsights: false,
3085
+ customThemes: false,
3086
+ voiceSynthesis: false,
3087
+ imageAnalysis: false
3088
+ },
3089
+ isNewSession: true,
3090
+ recentPages: [],
3091
+ viewport: { width: 1920, height: 1080 },
3092
+ connection: "4g"
3093
+ };
3094
+ TIER_ORDER = {
3095
+ free: 0,
3096
+ starter: 1,
3097
+ pro: 2,
3098
+ enterprise: 3,
3099
+ admin: 999
3100
+ };
3101
+ ESI = {
3102
+ Provider: ESIProvider,
3103
+ Infer: ESIInfer,
3104
+ Embed: ESIEmbed,
3105
+ Emotion: ESIEmotion,
3106
+ Vision: ESIVision,
3107
+ Structured: ESIStructured,
3108
+ If: ESIIf,
3109
+ Show: ESIShow,
3110
+ Hide: ESIHide,
3111
+ When: ESIWhen,
3112
+ Unless: ESIUnless,
3113
+ Match: ESIMatch,
3114
+ Case: ESICase,
3115
+ Default: ESIDefault,
3116
+ First: ESIFirst,
3117
+ TierGate: ESITierGate,
3118
+ EmotionGate: ESIEmotionGate,
3119
+ TimeGate: ESITimeGate,
3120
+ ForEach: ESIForEach,
3121
+ Select: ESISelect,
3122
+ ABTest: ESIABTest,
3123
+ Clamp: ESIClamp,
3124
+ Score: ESIScore,
3125
+ Collaborative: ESICollaborative,
3126
+ Reflect: ESIReflect,
3127
+ Optimize: ESIOptimize,
3128
+ Auto: ESIAuto,
3129
+ Markdown: ESIMarkdown,
3130
+ Latex: ESILatex,
3131
+ Json: ESIJson,
3132
+ Plaintext: ESIPlaintext,
3133
+ Code: ESICode
3134
+ };
3135
+ esi_react_default = ESI;
3136
+ });
3137
+
3138
+ // src/router/types.ts
3139
+ var DEFAULT_ROUTER_CONFIG = {
3140
+ adapter: "heuristic",
3141
+ speculation: {
3142
+ enabled: true,
3143
+ depth: 2,
3144
+ prerenderTop: 1,
3145
+ maxPrefetch: 5
3146
+ },
3147
+ personalization: {
3148
+ featureGating: true,
3149
+ emotionTheming: true,
3150
+ componentOrdering: true,
3151
+ densityAdaptation: true
3152
+ }
3153
+ };
3154
+ var DEFAULT_ESI_CONFIG = {
3155
+ enabled: false,
3156
+ endpoint: process.env.ESI_ENDPOINT || "",
3157
+ timeout: 5000,
3158
+ defaultCacheTtl: 300,
3159
+ maxConcurrent: 5,
3160
+ warmupModels: ["llm"],
3161
+ tierLimits: {
3162
+ free: {
3163
+ maxInferencesPerRequest: 2,
3164
+ allowedModels: ["llm", "embed"],
3165
+ maxTokens: 500
3166
+ },
3167
+ starter: {
3168
+ maxInferencesPerRequest: 5,
3169
+ allowedModels: ["llm", "embed", "classify"],
3170
+ maxTokens: 1000
3171
+ },
3172
+ pro: {
3173
+ maxInferencesPerRequest: 20,
3174
+ allowedModels: ["llm", "embed", "classify", "vision", "tts"],
3175
+ maxTokens: 4000
3176
+ },
3177
+ enterprise: {
3178
+ maxInferencesPerRequest: 100,
3179
+ allowedModels: ["llm", "embed", "classify", "vision", "tts", "stt", "custom"],
3180
+ maxTokens: 32000
3181
+ },
3182
+ admin: {
3183
+ maxInferencesPerRequest: 999999,
3184
+ allowedModels: ["llm", "embed", "classify", "vision", "tts", "stt", "emotion", "custom"],
3185
+ maxTokens: 999999
3186
+ }
3187
+ }
3188
+ };
3189
+
3190
+ // src/router/index.ts
3191
+ init_esi();
3192
+ init_esi_react();
3193
+
3194
+ // src/router/heuristic-adapter.ts
3195
+ var DEFAULT_CONFIG = {
3196
+ tierFeatures: {
3197
+ free: {},
3198
+ starter: {},
3199
+ pro: {},
3200
+ enterprise: {},
3201
+ admin: {}
3202
+ },
3203
+ defaultAccent: "#336699",
3204
+ signals: {},
3205
+ defaultPaths: ["/"],
3206
+ maxSpeculationPaths: 5
3207
+ };
3208
+ function defaultDeriveTheme(context) {
3209
+ if (context.preferences.theme) {
3210
+ return context.preferences.theme;
3211
+ }
3212
+ const hour = context.localHour;
3213
+ const isNight = hour >= 20 || hour < 6;
3214
+ const isEvening = hour >= 18 && hour < 20;
3215
+ if (isNight) {
3216
+ return "dark";
3217
+ }
3218
+ if (isEvening) {
3219
+ return "auto";
3220
+ }
3221
+ return "light";
3222
+ }
3223
+ function determineDensity(context) {
3224
+ if (context.preferences.density) {
3225
+ return context.preferences.density;
3226
+ }
3227
+ const { width, height } = context.viewport;
3228
+ if (width < 768) {
3229
+ return "compact";
3230
+ }
3231
+ if (width >= 1440 && height >= 900) {
3232
+ return "comfortable";
3233
+ }
3234
+ return "normal";
3235
+ }
3236
+ function buildTransitionMatrix(history) {
3237
+ const matrix = {};
3238
+ for (let i = 0;i < history.length - 1; i++) {
3239
+ const from = history[i];
3240
+ const to = history[i + 1];
3241
+ if (!matrix[from]) {
3242
+ matrix[from] = {};
3243
+ }
3244
+ matrix[from][to] = (matrix[from][to] || 0) + 1;
3245
+ }
3246
+ for (const from of Object.keys(matrix)) {
3247
+ const total = Object.values(matrix[from]).reduce((a, b) => a + b, 0);
3248
+ for (const to of Object.keys(matrix[from])) {
3249
+ matrix[from][to] /= total;
3250
+ }
3251
+ }
3252
+ return matrix;
3253
+ }
3254
+ function defaultPredictNavigation(currentPath, context, defaultPaths, topN) {
3255
+ const history = context.recentPages;
3256
+ if (history.length >= 3) {
3257
+ const matrix = buildTransitionMatrix(history);
3258
+ const transitions = matrix[currentPath];
3259
+ if (transitions) {
3260
+ const sorted = Object.entries(transitions).sort(([, a], [, b]) => b - a).slice(0, topN).map(([path]) => path);
3261
+ if (sorted.length > 0) {
3262
+ return sorted;
3263
+ }
3264
+ }
3265
+ }
3266
+ return defaultPaths.filter((p) => p !== currentPath).slice(0, topN);
3267
+ }
3268
+ function defaultScoreRelevance(node, context) {
3269
+ let score = 50;
3270
+ if (node.requiredTier) {
3271
+ const tierOrder = ["free", "starter", "pro", "enterprise"];
3272
+ const requiredIndex = tierOrder.indexOf(node.requiredTier);
3273
+ const userIndex = tierOrder.indexOf(context.tier);
3274
+ if (userIndex < requiredIndex) {
3275
+ return 0;
3276
+ }
3277
+ score += 10;
3278
+ }
3279
+ if (node.relevanceSignals) {
3280
+ for (const signal of node.relevanceSignals) {
3281
+ if (signal.startsWith("recentPage:")) {
3282
+ const page = signal.slice("recentPage:".length);
3283
+ if (context.recentPages.includes(page)) {
3284
+ score += 20;
3285
+ }
3286
+ }
3287
+ if (signal.startsWith("timeOfDay:")) {
3288
+ const timeRange = signal.slice("timeOfDay:".length);
3289
+ const hour = context.localHour;
3290
+ if (timeRange === "morning" && hour >= 5 && hour < 12)
3291
+ score += 15;
3292
+ if (timeRange === "afternoon" && hour >= 12 && hour < 17)
3293
+ score += 15;
3294
+ if (timeRange === "evening" && hour >= 17 && hour < 21)
3295
+ score += 15;
3296
+ if (timeRange === "night" && (hour >= 21 || hour < 5))
3297
+ score += 15;
3298
+ }
3299
+ if (signal.startsWith("preference:")) {
3300
+ const pref = signal.slice("preference:".length);
3301
+ if (context.preferences[pref]) {
3302
+ score += 20;
3303
+ }
3304
+ }
3305
+ if (signal.startsWith("tier:")) {
3306
+ const requiredTier = signal.slice("tier:".length);
3307
+ const tierOrder = ["free", "starter", "pro", "enterprise"];
3308
+ if (tierOrder.indexOf(context.tier) >= tierOrder.indexOf(requiredTier)) {
3309
+ score += 15;
3310
+ }
3311
+ }
3312
+ }
3313
+ }
3314
+ if (node.defaultHidden) {
3315
+ score -= 30;
3316
+ }
3317
+ return Math.max(0, Math.min(100, score));
3318
+ }
3319
+ function orderComponentsByRelevance(tree, context, scoreRelevance) {
3320
+ const scored = [];
3321
+ tree.nodes.forEach((node, id) => {
3322
+ scored.push({
3323
+ id,
3324
+ score: scoreRelevance(node, context)
3325
+ });
3326
+ });
3327
+ return scored.sort((a, b) => b.score - a.score).map((s) => s.id);
3328
+ }
3329
+ function findHiddenComponents(tree, context, scoreRelevance) {
3330
+ const hidden = [];
3331
+ tree.nodes.forEach((node, id) => {
3332
+ const score = scoreRelevance(node, context);
3333
+ if (score === 0) {
3334
+ hidden.push(id);
3335
+ }
3336
+ });
3337
+ return hidden;
3338
+ }
3339
+ function computeSkeletonHints(route, context, tree) {
3340
+ let layout = "custom";
3341
+ if (route === "/" || route.includes("dashboard")) {
3342
+ layout = "dashboard";
3343
+ } else if (route.includes("chat") || route.includes("message")) {
3344
+ layout = "chat";
3345
+ } else if (route.includes("setting") || route.includes("config")) {
3346
+ layout = "settings";
3347
+ } else if (route.includes("tool")) {
3348
+ layout = "tools";
3349
+ }
3350
+ const baseHeight = context.viewport.height;
3351
+ const contentMultiplier = tree.nodes.size > 10 ? 1.5 : 1;
3352
+ const estimatedHeight = Math.round(baseHeight * contentMultiplier);
3353
+ const sections = tree.getChildren(tree.rootId).map((child, i) => ({
3354
+ id: child.id,
3355
+ height: Math.round(estimatedHeight / (tree.nodes.size || 1)),
3356
+ priority: i + 1
3357
+ }));
3358
+ return {
3359
+ layout,
3360
+ estimatedHeight,
3361
+ sections
3362
+ };
3363
+ }
3364
+ function getPrefetchDepth(context) {
3365
+ switch (context.connection) {
3366
+ case "fast":
3367
+ case "4g":
3368
+ return { prefetch: 5, prerender: 1 };
3369
+ case "3g":
3370
+ return { prefetch: 3, prerender: 0 };
3371
+ case "2g":
3372
+ return { prefetch: 1, prerender: 0 };
3373
+ case "slow-2g":
3374
+ return { prefetch: 0, prerender: 0 };
3375
+ default:
3376
+ return { prefetch: 3, prerender: 0 };
3377
+ }
3378
+ }
3379
+
3380
+ class HeuristicAdapter {
3381
+ name = "heuristic";
3382
+ config;
3383
+ constructor(config = {}) {
3384
+ this.config = {
3385
+ ...DEFAULT_CONFIG,
3386
+ ...config,
3387
+ tierFeatures: config.tierFeatures ?? DEFAULT_CONFIG.tierFeatures,
3388
+ signals: config.signals ?? DEFAULT_CONFIG.signals
3389
+ };
3390
+ }
3391
+ async route(path, context, tree) {
3392
+ const startTime = Date.now();
3393
+ const sessionId = this.generateSessionId(path, context);
3394
+ const featureFlags = { ...this.config.tierFeatures[context.tier] };
3395
+ const theme = this.config.signals.deriveTheme ? this.config.signals.deriveTheme(context) : defaultDeriveTheme(context);
3396
+ const accent = this.config.signals.deriveAccent ? this.config.signals.deriveAccent(context) : this.config.defaultAccent;
3397
+ const density = determineDensity(context);
3398
+ const scoreRelevance = this.config.signals.scoreRelevance ?? defaultScoreRelevance;
3399
+ const componentOrder = orderComponentsByRelevance(tree, context, scoreRelevance);
3400
+ const hiddenComponents = findHiddenComponents(tree, context, scoreRelevance);
3401
+ const predictions = this.config.signals.predictNavigation ? this.config.signals.predictNavigation(path, context) : defaultPredictNavigation(path, context, this.config.defaultPaths, this.config.maxSpeculationPaths);
3402
+ const { prefetch: prefetchDepth, prerender: prerenderCount } = getPrefetchDepth(context);
3403
+ const prefetch = predictions.slice(0, prefetchDepth);
3404
+ const prerender = predictions.slice(0, prerenderCount);
3405
+ const skeleton = computeSkeletonHints(path, context, tree);
3406
+ return {
3407
+ route: path,
3408
+ sessionId,
3409
+ componentOrder,
3410
+ hiddenComponents,
3411
+ featureFlags,
3412
+ theme,
3413
+ accent,
3414
+ density,
3415
+ prefetch,
3416
+ prerender,
3417
+ skeleton,
3418
+ routedAt: startTime,
3419
+ routerName: this.name,
3420
+ confidence: 0.85
3421
+ };
3422
+ }
3423
+ async speculate(currentPath, context) {
3424
+ return this.config.signals.predictNavigation ? this.config.signals.predictNavigation(currentPath, context) : defaultPredictNavigation(currentPath, context, this.config.defaultPaths, this.config.maxSpeculationPaths);
3425
+ }
3426
+ personalizeTree(tree, decision) {
3427
+ const cloned = tree.clone();
3428
+ if (decision.hiddenComponents) {
3429
+ for (const id of decision.hiddenComponents) {
3430
+ const node = cloned.getNode(id);
3431
+ if (node) {
3432
+ node.defaultHidden = true;
3433
+ }
3434
+ }
3435
+ }
3436
+ return cloned;
3437
+ }
3438
+ emotionToAccent(emotionState) {
3439
+ if (this.config.signals.deriveAccent) {
3440
+ return this.config.signals.deriveAccent({
3441
+ emotionState,
3442
+ tier: "free",
3443
+ recentPages: [],
3444
+ dwellTimes: new Map,
3445
+ clickPatterns: [],
3446
+ preferences: {},
3447
+ viewport: { width: 0, height: 0 },
3448
+ connection: "fast",
3449
+ reducedMotion: false,
3450
+ localHour: 12,
3451
+ timezone: "UTC",
3452
+ isNewSession: true
3453
+ });
3454
+ }
3455
+ return this.config.defaultAccent;
3456
+ }
3457
+ generateSessionId(path, context) {
3458
+ const base = path.replace(/^\/|\/$/g, "").replace(/\//g, "-") || "index";
3459
+ const userId = context.userId || "anon";
3460
+ const sessionPrefix = context.sessionId || Date.now().toString(36);
3461
+ return `${base}-${userId.slice(0, 8)}-${sessionPrefix.slice(0, 8)}`;
3462
+ }
3463
+ }
3464
+ // src/router/context-extractor.ts
3465
+ function parseCookies(cookieHeader) {
3466
+ if (!cookieHeader)
3467
+ return {};
3468
+ return cookieHeader.split(";").reduce((acc, cookie) => {
3469
+ const [key, value] = cookie.trim().split("=");
3470
+ if (key && value) {
3471
+ acc[key] = decodeURIComponent(value);
3472
+ }
3473
+ return acc;
3474
+ }, {});
3475
+ }
3476
+ function parseJSON(value, fallback) {
3477
+ if (!value)
3478
+ return fallback;
3479
+ try {
3480
+ return JSON.parse(value);
3481
+ } catch {
3482
+ return fallback;
3483
+ }
3484
+ }
3485
+ function extractViewport(request) {
3486
+ const headers = request.headers;
3487
+ const viewportWidth = headers.get("sec-ch-viewport-width");
3488
+ const viewportHeight = headers.get("sec-ch-viewport-height");
3489
+ const dpr = headers.get("sec-ch-dpr");
3490
+ if (viewportWidth && viewportHeight) {
3491
+ return {
3492
+ width: parseInt(viewportWidth, 10),
3493
+ height: parseInt(viewportHeight, 10),
3494
+ devicePixelRatio: dpr ? parseFloat(dpr) : undefined
3495
+ };
3496
+ }
3497
+ const xViewport = headers.get("x-viewport");
3498
+ if (xViewport) {
3499
+ const [width, height, devicePixelRatio] = xViewport.split(",").map(Number);
3500
+ return { width: width || 1920, height: height || 1080, devicePixelRatio };
3501
+ }
3502
+ return { width: 1920, height: 1080 };
3503
+ }
3504
+ function extractConnection(request) {
3505
+ const headers = request.headers;
3506
+ const downlink = headers.get("downlink");
3507
+ const rtt = headers.get("rtt");
3508
+ const ect = headers.get("ect");
3509
+ if (ect) {
3510
+ switch (ect) {
3511
+ case "4g":
3512
+ return "fast";
3513
+ case "3g":
3514
+ return "3g";
3515
+ case "2g":
3516
+ return "2g";
3517
+ case "slow-2g":
3518
+ return "slow-2g";
3519
+ }
3520
+ }
3521
+ if (downlink) {
3522
+ const mbps = parseFloat(downlink);
3523
+ if (mbps >= 10)
3524
+ return "fast";
3525
+ if (mbps >= 2)
3526
+ return "4g";
3527
+ if (mbps >= 0.5)
3528
+ return "3g";
3529
+ if (mbps >= 0.1)
3530
+ return "2g";
3531
+ return "slow-2g";
3532
+ }
3533
+ if (rtt) {
3534
+ const ms = parseInt(rtt, 10);
3535
+ if (ms < 50)
3536
+ return "fast";
3537
+ if (ms < 100)
3538
+ return "4g";
3539
+ if (ms < 300)
3540
+ return "3g";
3541
+ if (ms < 700)
3542
+ return "2g";
3543
+ return "slow-2g";
3544
+ }
3545
+ return "4g";
3546
+ }
3547
+ function extractReducedMotion(request) {
3548
+ const prefersReducedMotion = request.headers.get("sec-ch-prefers-reduced-motion");
3549
+ return prefersReducedMotion === "reduce";
3550
+ }
3551
+ function extractTimeContext(request) {
3552
+ const headers = request.headers;
3553
+ const xTimezone = headers.get("x-timezone");
3554
+ const xLocalHour = headers.get("x-local-hour");
3555
+ const cfTimezone = request.cf?.timezone;
3556
+ const timezone = xTimezone || cfTimezone || "UTC";
3557
+ const localHour = xLocalHour ? parseInt(xLocalHour, 10) : new Date().getUTCHours();
3558
+ return { timezone, localHour };
3559
+ }
3560
+ function extractIdentity(cookies, request) {
3561
+ const userId = cookies["user_id"] || request.headers.get("x-user-id") || undefined;
3562
+ const tierCookie = cookies["user_tier"];
3563
+ const tierHeader = request.headers.get("x-user-tier");
3564
+ const tier = tierCookie || tierHeader || "free";
3565
+ const isAdminCookie = cookies["is_admin"] === "true" || cookies["user_role"] === "admin";
3566
+ const isAdminHeader = request.headers.get("x-user-admin") === "true" || request.headers.get("x-user-role") === "admin";
3567
+ const isAdmin = isAdminCookie || isAdminHeader || tier === "enterprise";
3568
+ return { userId, tier, isAdmin };
3569
+ }
3570
+ function extractNavigationHistory(cookies) {
3571
+ const recentPages = parseJSON(cookies["recent_pages"], []);
3572
+ const dwellTimesObj = parseJSON(cookies["dwell_times"], {});
3573
+ const clickPatterns = parseJSON(cookies["click_patterns"], []);
3574
+ return {
3575
+ recentPages,
3576
+ dwellTimes: new Map(Object.entries(dwellTimesObj)),
3577
+ clickPatterns
3578
+ };
3579
+ }
3580
+ function extractEmotionState(cookies, request) {
3581
+ const xEmotion = request.headers.get("x-emotion-state");
3582
+ if (xEmotion) {
3583
+ return parseJSON(xEmotion, undefined);
3584
+ }
3585
+ const emotionCookie = cookies["emotion_state"];
3586
+ if (emotionCookie) {
3587
+ return parseJSON(emotionCookie, undefined);
3588
+ }
3589
+ return;
3590
+ }
3591
+ function extractPreferences(cookies) {
3592
+ return parseJSON(cookies["user_preferences"], {});
3593
+ }
3594
+ function extractSessionInfo(cookies) {
3595
+ const sessionId = cookies["session_id"];
3596
+ const sessionStarted = cookies["session_started"];
3597
+ return {
3598
+ sessionId,
3599
+ isNewSession: !sessionId,
3600
+ sessionStartedAt: sessionStarted ? new Date(sessionStarted) : undefined
3601
+ };
3602
+ }
3603
+ async function extractUserContext(request, options = {}) {
3604
+ const cookies = parseCookies(request.headers.get("cookie"));
3605
+ const viewport = extractViewport(request);
3606
+ const connection = extractConnection(request);
3607
+ const reducedMotion = extractReducedMotion(request);
3608
+ const { timezone, localHour } = extractTimeContext(request);
3609
+ const { userId, tier: initialTier, isAdmin } = extractIdentity(cookies, request);
3610
+ const { recentPages, dwellTimes, clickPatterns } = extractNavigationHistory(cookies);
3611
+ const preferences = extractPreferences(cookies);
3612
+ const { sessionId, isNewSession, sessionStartedAt } = extractSessionInfo(cookies);
3613
+ let tier = initialTier;
3614
+ if (options.resolveUserTier && userId) {
3615
+ try {
3616
+ tier = await options.resolveUserTier(userId);
3617
+ } catch {}
3618
+ }
3619
+ let emotionState = extractEmotionState(cookies, request);
3620
+ if (!emotionState && options.detectEmotion) {
3621
+ try {
3622
+ emotionState = await options.detectEmotion(request);
3623
+ } catch {}
3624
+ }
3625
+ let context = {
3626
+ userId,
3627
+ tier,
3628
+ isAdmin,
3629
+ recentPages,
3630
+ dwellTimes,
3631
+ clickPatterns,
3632
+ emotionState,
3633
+ preferences,
3634
+ viewport,
3635
+ connection,
3636
+ reducedMotion,
3637
+ localHour,
3638
+ timezone,
3639
+ sessionId,
3640
+ isNewSession,
3641
+ sessionStartedAt
3642
+ };
3643
+ if (options.enrich) {
3644
+ context = await options.enrich(context, request);
3645
+ }
3646
+ return context;
3647
+ }
3648
+ function createContextMiddleware(options = {}) {
3649
+ return async (request) => {
3650
+ return extractUserContext(request, options);
3651
+ };
3652
+ }
3653
+ function setContextCookies(response, context, currentPath) {
3654
+ const headers = new Headers(response.headers);
3655
+ const recentPages = [...context.recentPages.slice(-9), currentPath];
3656
+ headers.append("Set-Cookie", `recent_pages=${encodeURIComponent(JSON.stringify(recentPages))}; Path=/; Max-Age=604800; SameSite=Lax`);
3657
+ if (context.isNewSession) {
3658
+ const sessionId = `sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
3659
+ headers.append("Set-Cookie", `session_id=${sessionId}; Path=/; Max-Age=86400; SameSite=Lax`);
3660
+ headers.append("Set-Cookie", `session_started=${new Date().toISOString()}; Path=/; Max-Age=86400; SameSite=Lax`);
3661
+ }
3662
+ return new Response(response.body, {
3663
+ status: response.status,
3664
+ statusText: response.statusText,
3665
+ headers
3666
+ });
3667
+ }
3668
+ function addSpeculationHeaders(response, prefetch, prerender) {
3669
+ const headers = new Headers(response.headers);
3670
+ if (prefetch.length > 0) {
3671
+ const linkHeader = prefetch.map((path) => `<${path}>; rel=prefetch`).join(", ");
3672
+ headers.append("Link", linkHeader);
3673
+ }
3674
+ if (prerender.length > 0) {
3675
+ headers.set("X-Prerender-Hints", prerender.join(","));
3676
+ }
3677
+ return new Response(response.body, {
3678
+ status: response.status,
3679
+ statusText: response.statusText,
3680
+ headers
3681
+ });
3682
+ }
3683
+ function serializeToESIState(context) {
3684
+ const tierFeatures = {
3685
+ free: {
3686
+ aiInference: true,
3687
+ emotionTracking: true,
3688
+ collaboration: false,
3689
+ advancedInsights: false,
3690
+ customThemes: false,
3691
+ voiceSynthesis: false,
3692
+ imageAnalysis: false
3693
+ },
3694
+ starter: {
3695
+ aiInference: true,
3696
+ emotionTracking: true,
3697
+ collaboration: false,
3698
+ advancedInsights: true,
3699
+ customThemes: true,
3700
+ voiceSynthesis: false,
3701
+ imageAnalysis: false
3702
+ },
3703
+ pro: {
3704
+ aiInference: true,
3705
+ emotionTracking: true,
3706
+ collaboration: true,
3707
+ advancedInsights: true,
3708
+ customThemes: true,
3709
+ voiceSynthesis: true,
3710
+ imageAnalysis: true
3711
+ },
3712
+ enterprise: {
3713
+ aiInference: true,
3714
+ emotionTracking: true,
3715
+ collaboration: true,
3716
+ advancedInsights: true,
3717
+ customThemes: true,
3718
+ voiceSynthesis: true,
3719
+ imageAnalysis: true
3720
+ },
3721
+ admin: {
3722
+ aiInference: true,
3723
+ emotionTracking: true,
3724
+ collaboration: true,
3725
+ advancedInsights: true,
3726
+ customThemes: true,
3727
+ voiceSynthesis: true,
3728
+ imageAnalysis: true
3729
+ }
3730
+ };
3731
+ const features = context.isAdmin ? tierFeatures.admin : tierFeatures[context.tier] || tierFeatures.free;
3732
+ return {
3733
+ userTier: context.tier,
3734
+ isAdmin: context.isAdmin,
3735
+ emotionState: context.emotionState ? {
3736
+ primary: context.emotionState.primary,
3737
+ valence: context.emotionState.valence,
3738
+ arousal: context.emotionState.arousal,
3739
+ confidence: context.emotionState.confidence
3740
+ } : undefined,
3741
+ preferences: {
3742
+ theme: context.preferences.theme,
3743
+ reducedMotion: context.reducedMotion,
3744
+ language: context.preferences.language
3745
+ },
3746
+ sessionId: context.sessionId,
3747
+ localHour: context.localHour,
3748
+ timezone: context.timezone,
3749
+ features,
3750
+ userId: context.userId,
3751
+ isNewSession: context.isNewSession,
3752
+ recentPages: context.recentPages.slice(-10),
3753
+ viewport: {
3754
+ width: context.viewport.width,
3755
+ height: context.viewport.height
3756
+ },
3757
+ connection: context.connection
3758
+ };
3759
+ }
3760
+ function generateESIStateScript(esiState) {
3761
+ const stateJson = JSON.stringify(esiState);
3762
+ return `<script>window.__AEON_ESI_STATE__=${stateJson};</script>`;
3763
+ }
3764
+ function generateESIStateScriptFromContext(context) {
3765
+ const esiState = serializeToESIState(context);
3766
+ return generateESIStateScript(esiState);
3767
+ }
3768
+ // src/router/speculation.ts
3769
+ function supportsSpeculationRules() {
3770
+ if (typeof document === "undefined")
3771
+ return false;
3772
+ return "supports" in HTMLScriptElement && HTMLScriptElement.supports?.("speculationrules");
3773
+ }
3774
+ function supportsLinkPrefetch() {
3775
+ if (typeof document === "undefined")
3776
+ return false;
3777
+ const link = document.createElement("link");
3778
+ return link.relList?.supports?.("prefetch") ?? false;
3779
+ }
3780
+ function addSpeculationRules(prefetch, prerender) {
3781
+ if (!supportsSpeculationRules())
3782
+ return null;
3783
+ const rules = {};
3784
+ if (prefetch.length > 0) {
3785
+ rules.prefetch = [{ urls: prefetch }];
3786
+ }
3787
+ if (prerender.length > 0) {
3788
+ rules.prerender = [{ urls: prerender }];
3789
+ }
3790
+ if (Object.keys(rules).length === 0)
3791
+ return null;
3792
+ const script = document.createElement("script");
3793
+ script.type = "speculationrules";
3794
+ script.textContent = JSON.stringify(rules);
3795
+ document.head.appendChild(script);
3796
+ return script;
3797
+ }
3798
+ function removeSpeculationRules(script) {
3799
+ script.remove();
3800
+ }
3801
+ function linkPrefetch(path) {
3802
+ if (!supportsLinkPrefetch())
3803
+ return null;
3804
+ const existing = document.querySelector(`link[rel="prefetch"][href="${path}"]`);
3805
+ if (existing)
3806
+ return existing;
3807
+ const link = document.createElement("link");
3808
+ link.rel = "prefetch";
3809
+ link.href = path;
3810
+ document.head.appendChild(link);
3811
+ return link;
3812
+ }
3813
+ function removePrefetch(link) {
3814
+ link.remove();
3815
+ }
3816
+
3817
+ class SpeculationManager {
3818
+ options;
3819
+ state;
3820
+ observers = new Map;
3821
+ hoverTimers = new Map;
3822
+ speculationScript = null;
3823
+ prefetchLinks = new Map;
3824
+ constructor(options = {}) {
3825
+ this.options = {
3826
+ maxPrefetch: options.maxPrefetch ?? 5,
3827
+ maxPrerender: options.maxPrerender ?? 1,
3828
+ hoverDelay: options.hoverDelay ?? 100,
3829
+ prefetchOnVisible: options.prefetchOnVisible ?? true,
3830
+ visibilityThreshold: options.visibilityThreshold ?? 0.1,
3831
+ cacheDuration: options.cacheDuration ?? 5 * 60 * 1000,
3832
+ onSpeculate: options.onSpeculate ?? (() => {})
3833
+ };
3834
+ this.state = {
3835
+ prefetched: new Set,
3836
+ prerendered: new Set,
3837
+ pending: new Set
3838
+ };
3839
+ }
3840
+ initFromHints(prefetch = [], prerender = []) {
3841
+ const newPrefetch = prefetch.filter((p) => !this.state.prefetched.has(p) && !this.state.prerendered.has(p)).slice(0, this.options.maxPrefetch);
3842
+ const newPrerender = prerender.filter((p) => !this.state.prerendered.has(p)).slice(0, this.options.maxPrerender);
3843
+ if (supportsSpeculationRules()) {
3844
+ this.speculationScript = addSpeculationRules(newPrefetch, newPrerender);
3845
+ newPrefetch.forEach((p) => {
3846
+ this.state.prefetched.add(p);
3847
+ this.options.onSpeculate(p, "prefetch");
3848
+ });
3849
+ newPrerender.forEach((p) => {
3850
+ this.state.prerendered.add(p);
3851
+ this.options.onSpeculate(p, "prerender");
3852
+ });
3853
+ } else {
3854
+ newPrefetch.forEach((path) => {
3855
+ const link = linkPrefetch(path);
3856
+ if (link) {
3857
+ this.prefetchLinks.set(path, link);
3858
+ this.state.prefetched.add(path);
3859
+ this.options.onSpeculate(path, "prefetch");
3860
+ }
3861
+ });
3862
+ }
3863
+ }
3864
+ prefetch(path) {
3865
+ if (this.state.prefetched.has(path) || this.state.prerendered.has(path)) {
3866
+ return false;
3867
+ }
3868
+ if (this.state.prefetched.size >= this.options.maxPrefetch) {
3869
+ return false;
3870
+ }
3871
+ if (supportsSpeculationRules()) {
3872
+ const allPrefetch = [...this.state.prefetched, path];
3873
+ const allPrerender = [...this.state.prerendered];
3874
+ if (this.speculationScript) {
3875
+ removeSpeculationRules(this.speculationScript);
3876
+ }
3877
+ this.speculationScript = addSpeculationRules(allPrefetch, allPrerender);
3878
+ } else {
3879
+ const link = linkPrefetch(path);
3880
+ if (link) {
3881
+ this.prefetchLinks.set(path, link);
3882
+ }
3883
+ }
3884
+ this.state.prefetched.add(path);
3885
+ this.options.onSpeculate(path, "prefetch");
3886
+ return true;
3887
+ }
3888
+ watchHover(element) {
3889
+ const path = new URL(element.href, window.location.href).pathname;
3890
+ const handleMouseEnter = () => {
3891
+ if (this.state.prefetched.has(path) || this.state.pending.has(path)) {
3892
+ return;
3893
+ }
3894
+ this.state.pending.add(path);
3895
+ const timer = setTimeout(() => {
3896
+ this.prefetch(path);
3897
+ this.state.pending.delete(path);
3898
+ }, this.options.hoverDelay);
3899
+ this.hoverTimers.set(element, timer);
3900
+ };
3901
+ const handleMouseLeave = () => {
3902
+ const timer = this.hoverTimers.get(element);
3903
+ if (timer) {
3904
+ clearTimeout(timer);
3905
+ this.hoverTimers.delete(element);
3906
+ }
3907
+ this.state.pending.delete(path);
3908
+ };
3909
+ element.addEventListener("mouseenter", handleMouseEnter);
3910
+ element.addEventListener("mouseleave", handleMouseLeave);
3911
+ return () => {
3912
+ element.removeEventListener("mouseenter", handleMouseEnter);
3913
+ element.removeEventListener("mouseleave", handleMouseLeave);
3914
+ handleMouseLeave();
3915
+ };
3916
+ }
3917
+ watchVisible(element) {
3918
+ if (!this.options.prefetchOnVisible) {
3919
+ return () => {};
3920
+ }
3921
+ const path = new URL(element.href, window.location.href).pathname;
3922
+ const observer = new IntersectionObserver((entries) => {
3923
+ entries.forEach((entry) => {
3924
+ if (entry.isIntersecting) {
3925
+ this.prefetch(path);
3926
+ observer.disconnect();
3927
+ this.observers.delete(element);
3928
+ }
3929
+ });
3930
+ }, { threshold: this.options.visibilityThreshold });
3931
+ observer.observe(element);
3932
+ this.observers.set(element, observer);
3933
+ return () => {
3934
+ observer.disconnect();
3935
+ this.observers.delete(element);
3936
+ };
3937
+ }
3938
+ watchAllLinks() {
3939
+ const links = document.querySelectorAll('a[href^="/"]');
3940
+ const cleanups = [];
3941
+ links.forEach((link) => {
3942
+ if (link instanceof HTMLAnchorElement) {
3943
+ cleanups.push(this.watchHover(link));
3944
+ cleanups.push(this.watchVisible(link));
3945
+ }
3946
+ });
3947
+ return () => {
3948
+ cleanups.forEach((cleanup) => cleanup());
3949
+ };
3950
+ }
3951
+ clear() {
3952
+ if (this.speculationScript) {
3953
+ removeSpeculationRules(this.speculationScript);
3954
+ this.speculationScript = null;
3955
+ }
3956
+ this.prefetchLinks.forEach((link) => removePrefetch(link));
3957
+ this.prefetchLinks.clear();
3958
+ this.observers.forEach((observer) => observer.disconnect());
3959
+ this.observers.clear();
3960
+ this.hoverTimers.forEach((timer) => clearTimeout(timer));
3961
+ this.hoverTimers.clear();
3962
+ this.state.prefetched.clear();
3963
+ this.state.prerendered.clear();
3964
+ this.state.pending.clear();
3965
+ }
3966
+ getState() {
3967
+ return {
3968
+ prefetched: new Set(this.state.prefetched),
3969
+ prerendered: new Set(this.state.prerendered),
3970
+ pending: new Set(this.state.pending)
3971
+ };
3972
+ }
3973
+ }
3974
+ function createSpeculationHook(useState4, useEffect4, useRef) {
3975
+ return function useSpeculation(options = {}) {
3976
+ const managerRef = useRef(null);
3977
+ const [state, setState] = useState4({
3978
+ prefetched: new Set,
3979
+ prerendered: new Set,
3980
+ pending: new Set
3981
+ });
3982
+ useEffect4(() => {
3983
+ managerRef.current = new SpeculationManager({
3984
+ ...options,
3985
+ onSpeculate: (path, type) => {
3986
+ options.onSpeculate?.(path, type);
3987
+ setState(managerRef.current.getState());
3988
+ }
3989
+ });
3990
+ const cleanup = managerRef.current.watchAllLinks();
3991
+ return () => {
3992
+ cleanup();
3993
+ managerRef.current?.clear();
3994
+ };
3995
+ }, []);
3996
+ return {
3997
+ state,
3998
+ prefetch: (path) => managerRef.current?.prefetch(path),
3999
+ initFromHints: (prefetch, prerender) => managerRef.current?.initFromHints(prefetch, prerender),
4000
+ clear: () => managerRef.current?.clear()
4001
+ };
4002
+ };
4003
+ }
4004
+ function autoInitSpeculation() {
4005
+ if (typeof window === "undefined")
4006
+ return null;
4007
+ const hints = window.__AEON_SPECULATION__;
4008
+ const manager = new SpeculationManager;
4009
+ if (hints) {
4010
+ manager.initFromHints(hints.prefetch || [], hints.prerender || []);
4011
+ }
4012
+ manager.watchAllLinks();
4013
+ return manager;
4014
+ }
4015
+
4016
+ // src/router/index.ts
4017
+ init_esi_control();
4018
+ init_esi_control_react();
4019
+ init_esi_cyrano();
4020
+
4021
+ export { DEFAULT_ROUTER_CONFIG, DEFAULT_ESI_CONFIG, esiContext, esiCyrano, esiHalo, evaluateTrigger, createExhaustEntry, CYRANO_TOOL_SUGGESTIONS, getToolSuggestions, EdgeWorkersESIProcessor, esiInfer, esiEmbed, esiEmotion, esiVision, esiWithContext, generateSchemaPrompt, parseWithSchema, createControlProcessor, esiIf, esiMatch, ESIStructured, ESIIf, ESICase, ESIDefault, ESIMatch, ESICollaborative, ESIReflect, ESIOptimize, ESIAuto, ESIShow, ESIHide, ESIWhen, ESIUnless, ESITierGate, ESIEmotionGate, ESITimeGate, ESIABTest, ESIForEach, ESIFirst, ESIClamp, ESISelect, ESIScore, ESIControl, ESIProvider, useESI, ESIInfer, ESIEmbed, ESIEmotion, ESIVision, useESIInfer, useGlobalESIState, useESIFeature, useESITier, useESIEmotionState, useESIPreferences, updateGlobalESIState, ESI, HeuristicAdapter, extractUserContext, createContextMiddleware, setContextCookies, addSpeculationHeaders, serializeToESIState, generateESIStateScript, generateESIStateScriptFromContext, supportsSpeculationRules, supportsLinkPrefetch, SpeculationManager, createSpeculationHook, autoInitSpeculation };