begeniux 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,523 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ BeGenProvider: () => BeGenProvider,
34
+ BeGenSurface: () => BeGenSurface,
35
+ PERSONAS: () => PERSONAS,
36
+ createGeminiClassifier: () => createGeminiClassifier,
37
+ createHeuristicClassifier: () => createHeuristicClassifier,
38
+ useBeGenContext: () => useBeGenContext,
39
+ useBehaviorTracker: () => useBehaviorTracker
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/BeGenProvider.tsx
44
+ var React = __toESM(require("react"), 1);
45
+ var import_jsx_runtime = require("react/jsx-runtime");
46
+ var BeGenContext = React.createContext(null);
47
+ function BeGenProvider({ children }) {
48
+ const [variant, setVariant] = React.useState("neutral");
49
+ const [directive, setDirective] = React.useState(null);
50
+ const [summary, setSummary] = React.useState(null);
51
+ const value = React.useMemo(
52
+ () => ({ variant, directive, summary, setVariant, setDirective, setSummary }),
53
+ [variant, directive, summary]
54
+ );
55
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BeGenContext.Provider, { value, children });
56
+ }
57
+
58
+ // src/BeGenSurface.tsx
59
+ var React2 = __toESM(require("react"), 1);
60
+
61
+ // src/useBehaviorTracker.ts
62
+ var import_react = require("react");
63
+ var RECENT_EVENTS_CAP = 5;
64
+ var HOVER_MIN_MS = 200;
65
+ function targetLabel(el) {
66
+ if (!(el instanceof HTMLElement)) return "unknown";
67
+ return el.dataset.begenId || el.getAttribute("data-product-id") || el.getAttribute("aria-label") || el.tagName.toLowerCase();
68
+ }
69
+ function computeSummary(buffer, bufferSize, pageContext) {
70
+ const now = Date.now();
71
+ const windowStart = now - 6e4;
72
+ let clicksLastMin = 0;
73
+ let dwellSum = 0;
74
+ let dwellCount = 0;
75
+ let maxScroll = 0;
76
+ const hoverTargets = /* @__PURE__ */ new Set();
77
+ for (const ev of buffer) {
78
+ if (ev.kind === "click" && ev.t >= windowStart) clicksLastMin += 1;
79
+ if (ev.kind === "dwell") {
80
+ dwellSum += ev.durationMs;
81
+ dwellCount += 1;
82
+ }
83
+ if (ev.kind === "scroll" && ev.depth > maxScroll) maxScroll = ev.depth;
84
+ if (ev.kind === "hover") hoverTargets.add(ev.target);
85
+ }
86
+ return {
87
+ clicks_per_min: clicksLastMin,
88
+ avg_dwell_ms: dwellCount === 0 ? 0 : Math.round(dwellSum / dwellCount),
89
+ scroll_depth: Math.max(0, Math.min(1, maxScroll)),
90
+ hover_count: hoverTargets.size,
91
+ events_seen: Math.min(buffer.length, bufferSize),
92
+ page_context: pageContext
93
+ };
94
+ }
95
+ function useBehaviorTracker(opts) {
96
+ const {
97
+ containerRef,
98
+ flushEveryEvents = 10,
99
+ flushAfterMs = 5e3,
100
+ bufferSize = 50,
101
+ onFlush,
102
+ pageContext,
103
+ seedTrace
104
+ } = opts;
105
+ const bufferRef = (0, import_react.useRef)([]);
106
+ const sinceFlushRef = (0, import_react.useRef)(0);
107
+ const lastFlushAtRef = (0, import_react.useRef)(Date.now());
108
+ const hoverStartRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
109
+ const scrollRafRef = (0, import_react.useRef)(null);
110
+ const onFlushRef = (0, import_react.useRef)(onFlush);
111
+ const pageContextRef = (0, import_react.useRef)(pageContext);
112
+ (0, import_react.useEffect)(() => {
113
+ onFlushRef.current = onFlush;
114
+ }, [onFlush]);
115
+ (0, import_react.useEffect)(() => {
116
+ pageContextRef.current = pageContext;
117
+ }, [pageContext]);
118
+ const [recentEvents, setRecentEvents] = (0, import_react.useState)([]);
119
+ const pushEvent = (ev) => {
120
+ const buf = bufferRef.current;
121
+ buf.push(ev);
122
+ if (buf.length > bufferSize) buf.splice(0, buf.length - bufferSize);
123
+ sinceFlushRef.current += 1;
124
+ setRecentEvents((prev) => {
125
+ const next = [...prev, ev];
126
+ if (next.length > RECENT_EVENTS_CAP) next.splice(0, next.length - RECENT_EVENTS_CAP);
127
+ return next;
128
+ });
129
+ if (sinceFlushRef.current >= flushEveryEvents) {
130
+ flush();
131
+ }
132
+ };
133
+ const flush = () => {
134
+ const summary = computeSummary(bufferRef.current, bufferSize, pageContextRef.current);
135
+ sinceFlushRef.current = 0;
136
+ lastFlushAtRef.current = Date.now();
137
+ onFlushRef.current(summary);
138
+ };
139
+ (0, import_react.useEffect)(() => {
140
+ if (seedTrace && seedTrace.length > 0) {
141
+ const buf = bufferRef.current;
142
+ const maxT = seedTrace.reduce((m, e) => e.t > m ? e.t : m, -Infinity);
143
+ const now = Date.now();
144
+ const offset = Number.isFinite(maxT) ? now - maxT : 0;
145
+ const rebased = seedTrace.map((e) => ({ ...e, t: e.t + offset }));
146
+ buf.push(...rebased);
147
+ if (buf.length > bufferSize) buf.splice(0, buf.length - bufferSize);
148
+ const summary = computeSummary(buf, bufferSize, pageContextRef.current);
149
+ sinceFlushRef.current = 0;
150
+ lastFlushAtRef.current = Date.now();
151
+ onFlushRef.current(summary);
152
+ }
153
+ }, []);
154
+ (0, import_react.useEffect)(() => {
155
+ const el = containerRef.current;
156
+ if (!el) return;
157
+ const onClick = (e) => {
158
+ pushEvent({ kind: "click", target: targetLabel(e.target), t: Date.now() });
159
+ };
160
+ const onMouseOver = (e) => {
161
+ const label = targetLabel(e.target);
162
+ if (!hoverStartRef.current.has(label)) {
163
+ hoverStartRef.current.set(label, Date.now());
164
+ }
165
+ };
166
+ const onMouseOut = (e) => {
167
+ const label = targetLabel(e.target);
168
+ const started = hoverStartRef.current.get(label);
169
+ if (started == null) return;
170
+ hoverStartRef.current.delete(label);
171
+ const durationMs = Date.now() - started;
172
+ if (durationMs < HOVER_MIN_MS) return;
173
+ const t = Date.now();
174
+ pushEvent({ kind: "hover", target: label, durationMs, t });
175
+ pushEvent({ kind: "dwell", target: label, durationMs, t });
176
+ };
177
+ const computeScrollDepth = () => {
178
+ const rect = el.getBoundingClientRect();
179
+ const viewportH = window.innerHeight || 1;
180
+ const elementH = el.scrollHeight || rect.height || 1;
181
+ const visibleBottom = Math.min(rect.bottom, viewportH);
182
+ const scrolledPast = Math.max(0, visibleBottom - rect.top);
183
+ return Math.max(0, Math.min(1, scrolledPast / elementH));
184
+ };
185
+ const onScroll = () => {
186
+ if (scrollRafRef.current != null) return;
187
+ scrollRafRef.current = requestAnimationFrame(() => {
188
+ scrollRafRef.current = null;
189
+ pushEvent({ kind: "scroll", depth: computeScrollDepth(), t: Date.now() });
190
+ });
191
+ };
192
+ el.addEventListener("click", onClick);
193
+ el.addEventListener("mouseover", onMouseOver);
194
+ el.addEventListener("mouseout", onMouseOut);
195
+ window.addEventListener("scroll", onScroll, { passive: true });
196
+ const interval = window.setInterval(() => {
197
+ if (Date.now() - lastFlushAtRef.current >= flushAfterMs) {
198
+ flush();
199
+ }
200
+ }, Math.max(250, Math.floor(flushAfterMs / 4)));
201
+ return () => {
202
+ el.removeEventListener("click", onClick);
203
+ el.removeEventListener("mouseover", onMouseOver);
204
+ el.removeEventListener("mouseout", onMouseOut);
205
+ window.removeEventListener("scroll", onScroll);
206
+ window.clearInterval(interval);
207
+ if (scrollRafRef.current != null) cancelAnimationFrame(scrollRafRef.current);
208
+ };
209
+ }, [containerRef, flushAfterMs, flushEveryEvents, bufferSize]);
210
+ return { recentEvents };
211
+ }
212
+
213
+ // src/personas.ts
214
+ function buildDecisive() {
215
+ const events = [];
216
+ const productIds = ["p-101", "p-102", "p-103", "p-104", "p-105", "p-106"];
217
+ let t = 0;
218
+ for (let i = 0; i < 12; i++) {
219
+ t += 1500;
220
+ events.push({ kind: "click", target: productIds[i % productIds.length], t });
221
+ }
222
+ for (let i = 0; i < 6; i++) {
223
+ t += 800;
224
+ events.push({
225
+ kind: "dwell",
226
+ target: productIds[i % productIds.length],
227
+ durationMs: 600 + i * 80,
228
+ t
229
+ });
230
+ }
231
+ for (let i = 0; i < 6; i++) {
232
+ t += 1200;
233
+ events.push({
234
+ kind: "scroll",
235
+ depth: Math.min(0.95, 0.4 + i * 0.1),
236
+ t
237
+ });
238
+ }
239
+ for (let i = 0; i < 2; i++) {
240
+ t += 600;
241
+ events.push({
242
+ kind: "hover",
243
+ target: productIds[i],
244
+ durationMs: 250,
245
+ t
246
+ });
247
+ }
248
+ return events;
249
+ }
250
+ function buildDeliberate() {
251
+ const events = [];
252
+ const productIds = ["p-201", "p-202", "p-203", "p-204", "p-205", "p-206"];
253
+ let t = 0;
254
+ for (let i = 0; i < 6; i++) {
255
+ t += 5500;
256
+ const target = productIds[i];
257
+ events.push({ kind: "hover", target, durationMs: 1800 + i * 200, t });
258
+ t += 200;
259
+ events.push({
260
+ kind: "dwell",
261
+ target,
262
+ durationMs: 5e3 + i * 400,
263
+ t
264
+ });
265
+ }
266
+ for (let i = 0; i < 3; i++) {
267
+ t += 4e3;
268
+ events.push({ kind: "click", target: productIds[i], t });
269
+ }
270
+ for (let i = 0; i < 5; i++) {
271
+ t += 1500;
272
+ events.push({
273
+ kind: "scroll",
274
+ depth: Math.min(0.6, 0.2 + i * 0.08),
275
+ t
276
+ });
277
+ }
278
+ return events;
279
+ }
280
+ var PERSONAS = {
281
+ get decisive() {
282
+ return buildDecisive();
283
+ },
284
+ get deliberate() {
285
+ return buildDeliberate();
286
+ }
287
+ };
288
+
289
+ // src/BeGenSurface.tsx
290
+ var import_jsx_runtime2 = require("react/jsx-runtime");
291
+ function BeGenSurface(props) {
292
+ const {
293
+ variants,
294
+ classify,
295
+ variantProps,
296
+ pageContext,
297
+ seedPersona,
298
+ rateLimitMs = 4e3,
299
+ className,
300
+ style
301
+ } = props;
302
+ const containerRef = React2.useRef(null);
303
+ const ctx = React2.useContext(BeGenContext);
304
+ const [currentVariant, setCurrentVariant] = React2.useState("neutral");
305
+ const [lastDirective, setLastDirective] = React2.useState(null);
306
+ const [lastSummary, setLastSummary] = React2.useState(null);
307
+ const lastClassifyAtRef = React2.useRef(0);
308
+ const inFlightRef = React2.useRef(false);
309
+ const classifyRef = React2.useRef(classify);
310
+ React2.useEffect(() => {
311
+ classifyRef.current = classify;
312
+ }, [classify]);
313
+ const ctxRef = React2.useRef(ctx);
314
+ React2.useEffect(() => {
315
+ ctxRef.current = ctx;
316
+ }, [ctx]);
317
+ const handleFlush = React2.useCallback(async (summary) => {
318
+ setLastSummary(summary);
319
+ ctxRef.current?.setSummary(summary);
320
+ const now = Date.now();
321
+ if (inFlightRef.current) return;
322
+ if (now - lastClassifyAtRef.current < rateLimitMs) return;
323
+ lastClassifyAtRef.current = now;
324
+ inFlightRef.current = true;
325
+ try {
326
+ const directive = await classifyRef.current(summary);
327
+ setLastDirective(directive);
328
+ setCurrentVariant(directive.variant);
329
+ ctxRef.current?.setDirective(directive);
330
+ ctxRef.current?.setVariant(directive.variant);
331
+ } catch {
332
+ } finally {
333
+ inFlightRef.current = false;
334
+ }
335
+ }, [rateLimitMs]);
336
+ const seedTrace = seedPersona ? PERSONAS[seedPersona] : void 0;
337
+ useBehaviorTracker({
338
+ containerRef,
339
+ onFlush: handleFlush,
340
+ pageContext,
341
+ seedTrace
342
+ });
343
+ const ActiveComponent = variants[currentVariant] ?? variants.neutral;
344
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
345
+ "div",
346
+ {
347
+ ref: containerRef,
348
+ className,
349
+ style,
350
+ "data-begen-surface": true,
351
+ "data-begen-variant": currentVariant,
352
+ children: [
353
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
354
+ "div",
355
+ {
356
+ style: {
357
+ opacity: 1,
358
+ transition: "opacity 200ms ease",
359
+ animation: "begen-fade-in 200ms ease"
360
+ },
361
+ children: ActiveComponent ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActiveComponent, { ...variantProps ?? {} }) : null
362
+ },
363
+ currentVariant
364
+ ),
365
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BeGenSurfaceStyles, {}),
366
+ lastDirective && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
367
+ "span",
368
+ {
369
+ style: { display: "none" },
370
+ "data-begen-confidence": lastDirective.confidence,
371
+ "data-begen-reasoning": lastDirective.reasoning,
372
+ "data-begen-events": lastSummary?.events_seen ?? 0
373
+ }
374
+ )
375
+ ]
376
+ }
377
+ );
378
+ }
379
+ var STYLE_INJECTED = "__begen_styles__";
380
+ function BeGenSurfaceStyles() {
381
+ React2.useEffect(() => {
382
+ if (typeof document === "undefined") return;
383
+ if (document[STYLE_INJECTED]) return;
384
+ const tag = document.createElement("style");
385
+ tag.setAttribute("data-begen-styles", "");
386
+ tag.textContent = `@keyframes begen-fade-in { from { opacity: 0 } to { opacity: 1 } }`;
387
+ document.head.appendChild(tag);
388
+ document[STYLE_INJECTED] = true;
389
+ }, []);
390
+ return null;
391
+ }
392
+
393
+ // src/useBeGenContext.ts
394
+ var React3 = __toESM(require("react"), 1);
395
+ function useBeGenContext() {
396
+ const ctx = React3.useContext(BeGenContext);
397
+ if (!ctx) {
398
+ throw new Error("useBeGenContext must be used inside <BeGenProvider>");
399
+ }
400
+ return ctx;
401
+ }
402
+
403
+ // src/classifier/gemini.ts
404
+ var CLASSIFIER_SYSTEM_PROMPT = `
405
+ You classify e-commerce shopper behavior into UI variants.
406
+
407
+ You receive a JSON object describing a user's recent interaction pattern on
408
+ a product listing page. Decide which UI variant best serves them right now.
409
+
410
+ Variants:
411
+ - "decisive": user knows what they want; minimize friction. Dense grid,
412
+ prominent prices, fast paths to cart, no recommendations.
413
+ Signals: high clicks/min, low dwell, high scroll depth, few hovers.
414
+ - "deliberate": user is researching; help them compare. Larger cards,
415
+ reviews surfaced inline, "people also viewed", expandable detail.
416
+ Signals: low clicks/min, high dwell, hovers across multiple products.
417
+ - "neutral": insufficient signal yet, or pattern is mixed. Baseline grid.
418
+ Default for first ~10 events.
419
+
420
+ Examples:
421
+ Input: {"clicks_per_min":14,"avg_dwell_ms":820,"scroll_depth":0.91,"hover_count":2,"events_seen":18}
422
+ Output: {"variant":"decisive","confidence":0.86,"reasoning":"Fast clicks, low dwell, deep scroll \u2014 purposeful navigation."}
423
+
424
+ Input: {"clicks_per_min":3,"avg_dwell_ms":7400,"scroll_depth":0.42,"hover_count":4,"events_seen":22}
425
+ Output: {"variant":"deliberate","confidence":0.81,"reasoning":"Slow pace, long dwell, multi-product hover \u2014 comparing options."}
426
+
427
+ Input: {"clicks_per_min":5,"avg_dwell_ms":2100,"scroll_depth":0.55,"hover_count":2,"events_seen":7}
428
+ Output: {"variant":"neutral","confidence":0.6,"reasoning":"Not enough events yet to commit to a mode."}
429
+
430
+ Return ONLY a JSON object. No prose, no markdown.
431
+ `.trim();
432
+ var VALID_VARIANTS = /* @__PURE__ */ new Set(["decisive", "deliberate", "neutral"]);
433
+ var FALLBACK = {
434
+ variant: "neutral",
435
+ confidence: 0,
436
+ reasoning: "Classifier error."
437
+ };
438
+ function createGeminiClassifier(opts) {
439
+ const { apiKey, model = "gemini-2.0-flash", endpoint, fetchImpl } = opts;
440
+ const url = endpoint ?? `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent`;
441
+ const fetcher = fetchImpl ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : null);
442
+ return async (summary) => {
443
+ if (!fetcher) return FALLBACK;
444
+ try {
445
+ const res = await fetcher(`${url}?key=${encodeURIComponent(apiKey)}`, {
446
+ method: "POST",
447
+ headers: { "content-type": "application/json" },
448
+ body: JSON.stringify({
449
+ systemInstruction: { parts: [{ text: CLASSIFIER_SYSTEM_PROMPT }] },
450
+ contents: [
451
+ {
452
+ role: "user",
453
+ parts: [{ text: JSON.stringify(summary) }]
454
+ }
455
+ ],
456
+ generationConfig: {
457
+ responseMimeType: "application/json",
458
+ temperature: 0.2
459
+ }
460
+ })
461
+ });
462
+ if (!res.ok) return FALLBACK;
463
+ const data = await res.json();
464
+ const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
465
+ if (!text) return FALLBACK;
466
+ const parsed = JSON.parse(text);
467
+ if (!parsed || typeof parsed !== "object" || typeof parsed.variant !== "string" || !VALID_VARIANTS.has(parsed.variant) || typeof parsed.reasoning !== "string") {
468
+ return FALLBACK;
469
+ }
470
+ const confidence = typeof parsed.confidence === "number" && Number.isFinite(parsed.confidence) ? Math.max(0, Math.min(1, parsed.confidence)) : 0.5;
471
+ return {
472
+ variant: parsed.variant,
473
+ confidence,
474
+ reasoning: parsed.reasoning
475
+ };
476
+ } catch {
477
+ return FALLBACK;
478
+ }
479
+ };
480
+ }
481
+
482
+ // src/classifier/heuristic.ts
483
+ function createHeuristicClassifier() {
484
+ return async (summary) => {
485
+ if (summary.events_seen < 10) {
486
+ return {
487
+ variant: "neutral",
488
+ confidence: 0.5,
489
+ reasoning: "Insufficient events."
490
+ };
491
+ }
492
+ if (summary.clicks_per_min > 8 && summary.avg_dwell_ms < 2e3) {
493
+ return {
494
+ variant: "decisive",
495
+ confidence: 0.8,
496
+ reasoning: "Fast pace, low dwell."
497
+ };
498
+ }
499
+ if (summary.avg_dwell_ms > 4e3 && summary.hover_count > 2) {
500
+ return {
501
+ variant: "deliberate",
502
+ confidence: 0.8,
503
+ reasoning: "Slow pace, multi-hover."
504
+ };
505
+ }
506
+ return {
507
+ variant: "neutral",
508
+ confidence: 0.6,
509
+ reasoning: "Mixed signals."
510
+ };
511
+ };
512
+ }
513
+ // Annotate the CommonJS export names for ESM import in node:
514
+ 0 && (module.exports = {
515
+ BeGenProvider,
516
+ BeGenSurface,
517
+ PERSONAS,
518
+ createGeminiClassifier,
519
+ createHeuristicClassifier,
520
+ useBeGenContext,
521
+ useBehaviorTracker
522
+ });
523
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/BeGenProvider.tsx","../src/BeGenSurface.tsx","../src/useBehaviorTracker.ts","../src/personas.ts","../src/useBeGenContext.ts","../src/classifier/gemini.ts","../src/classifier/heuristic.ts"],"sourcesContent":["// Components\nexport { BeGenProvider } from \"./BeGenProvider\";\nexport { BeGenSurface } from \"./BeGenSurface\";\n\n// Hooks\nexport { useBehaviorTracker } from \"./useBehaviorTracker\";\nexport { useBeGenContext } from \"./useBeGenContext\";\n\n// Classifier helpers\nexport { createGeminiClassifier } from \"./classifier/gemini\";\nexport { createHeuristicClassifier } from \"./classifier/heuristic\";\n\n// Persona trace presets\nexport { PERSONAS } from \"./personas\";\n\n// Types\nexport type {\n BehaviorEvent,\n BehaviorSummary,\n Variant,\n AgentDirective,\n ClassifyFn,\n} from \"./types\";\nexport type { BeGenSurfaceProps } from \"./BeGenSurface\";\nexport type { BeGenContextValue } from \"./BeGenProvider\";\nexport type { CreateGeminiClassifierOpts } from \"./classifier/gemini\";\nexport type { UseBehaviorTrackerOpts } from \"./useBehaviorTracker\";\n","import * as React from \"react\";\nimport type { AgentDirective, BehaviorSummary, Variant } from \"./types\";\n\nexport type BeGenContextValue = {\n variant: Variant;\n directive: AgentDirective | null;\n summary: BehaviorSummary | null;\n setVariant: (v: Variant) => void;\n setDirective: (d: AgentDirective) => void;\n setSummary: (s: BehaviorSummary) => void;\n};\n\nexport const BeGenContext = React.createContext<BeGenContextValue | null>(null);\n\nexport function BeGenProvider({ children }: { children: React.ReactNode }) {\n const [variant, setVariant] = React.useState<Variant>(\"neutral\");\n const [directive, setDirective] = React.useState<AgentDirective | null>(null);\n const [summary, setSummary] = React.useState<BehaviorSummary | null>(null);\n\n const value = React.useMemo<BeGenContextValue>(\n () => ({ variant, directive, summary, setVariant, setDirective, setSummary }),\n [variant, directive, summary],\n );\n\n return <BeGenContext.Provider value={value}>{children}</BeGenContext.Provider>;\n}\n","import * as React from \"react\";\nimport type { AgentDirective, BehaviorSummary, ClassifyFn, Variant } from \"./types\";\nimport { useBehaviorTracker } from \"./useBehaviorTracker\";\nimport { BeGenContext } from \"./BeGenProvider\";\nimport { PERSONAS } from \"./personas\";\n\nexport type BeGenSurfaceProps = {\n variants: Record<Variant, React.ComponentType<any>>;\n classify: ClassifyFn;\n variantProps?: Record<string, any>;\n pageContext: BehaviorSummary[\"page_context\"];\n seedPersona?: \"decisive\" | \"deliberate\";\n rateLimitMs?: number;\n className?: string;\n style?: React.CSSProperties;\n children?: never;\n};\n\nexport function BeGenSurface(props: BeGenSurfaceProps) {\n const {\n variants,\n classify,\n variantProps,\n pageContext,\n seedPersona,\n rateLimitMs = 4000,\n className,\n style,\n } = props;\n\n const containerRef = React.useRef<HTMLDivElement>(null);\n const ctx = React.useContext(BeGenContext);\n\n const [currentVariant, setCurrentVariant] = React.useState<Variant>(\"neutral\");\n const [lastDirective, setLastDirective] = React.useState<AgentDirective | null>(null);\n const [lastSummary, setLastSummary] = React.useState<BehaviorSummary | null>(null);\n\n const lastClassifyAtRef = React.useRef(0);\n const inFlightRef = React.useRef(false);\n const classifyRef = React.useRef(classify);\n React.useEffect(() => {\n classifyRef.current = classify;\n }, [classify]);\n\n const ctxRef = React.useRef(ctx);\n React.useEffect(() => {\n ctxRef.current = ctx;\n }, [ctx]);\n\n const handleFlush = React.useCallback(async (summary: BehaviorSummary) => {\n setLastSummary(summary);\n ctxRef.current?.setSummary(summary);\n\n const now = Date.now();\n if (inFlightRef.current) return;\n if (now - lastClassifyAtRef.current < rateLimitMs) return;\n\n lastClassifyAtRef.current = now;\n inFlightRef.current = true;\n try {\n const directive = await classifyRef.current(summary);\n setLastDirective(directive);\n setCurrentVariant(directive.variant);\n ctxRef.current?.setDirective(directive);\n ctxRef.current?.setVariant(directive.variant);\n } catch {\n // Keep current variant on classifier failure.\n } finally {\n inFlightRef.current = false;\n }\n }, [rateLimitMs]);\n\n const seedTrace = seedPersona ? PERSONAS[seedPersona] : undefined;\n\n useBehaviorTracker({\n containerRef,\n onFlush: handleFlush,\n pageContext,\n seedTrace,\n });\n\n const ActiveComponent = variants[currentVariant] ?? variants.neutral;\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={style}\n data-begen-surface\n data-begen-variant={currentVariant}\n >\n <div\n key={currentVariant}\n style={{\n opacity: 1,\n transition: \"opacity 200ms ease\",\n animation: \"begen-fade-in 200ms ease\",\n }}\n >\n {ActiveComponent ? <ActiveComponent {...(variantProps ?? {})} /> : null}\n </div>\n <BeGenSurfaceStyles />\n {/* Expose directive/summary on a hidden node for debugging */}\n {lastDirective && (\n <span\n style={{ display: \"none\" }}\n data-begen-confidence={lastDirective.confidence}\n data-begen-reasoning={lastDirective.reasoning}\n data-begen-events={lastSummary?.events_seen ?? 0}\n />\n )}\n </div>\n );\n}\n\nconst STYLE_INJECTED = \"__begen_styles__\";\n\nfunction BeGenSurfaceStyles() {\n React.useEffect(() => {\n if (typeof document === \"undefined\") return;\n if ((document as any)[STYLE_INJECTED]) return;\n const tag = document.createElement(\"style\");\n tag.setAttribute(\"data-begen-styles\", \"\");\n tag.textContent = `@keyframes begen-fade-in { from { opacity: 0 } to { opacity: 1 } }`;\n document.head.appendChild(tag);\n (document as any)[STYLE_INJECTED] = true;\n }, []);\n return null;\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type { BehaviorEvent, BehaviorSummary } from \"./types\";\n\nexport type UseBehaviorTrackerOpts = {\n containerRef: React.RefObject<HTMLElement>;\n flushEveryEvents?: number;\n flushAfterMs?: number;\n bufferSize?: number;\n onFlush: (summary: BehaviorSummary) => void;\n pageContext: BehaviorSummary[\"page_context\"];\n seedTrace?: BehaviorEvent[];\n};\n\nconst RECENT_EVENTS_CAP = 5;\nconst HOVER_MIN_MS = 200;\n\nfunction targetLabel(el: EventTarget | null): string {\n if (!(el instanceof HTMLElement)) return \"unknown\";\n return (\n el.dataset.begenId ||\n el.getAttribute(\"data-product-id\") ||\n el.getAttribute(\"aria-label\") ||\n el.tagName.toLowerCase()\n );\n}\n\nfunction computeSummary(\n buffer: BehaviorEvent[],\n bufferSize: number,\n pageContext: BehaviorSummary[\"page_context\"],\n): BehaviorSummary {\n const now = Date.now();\n const windowStart = now - 60_000;\n\n let clicksLastMin = 0;\n let dwellSum = 0;\n let dwellCount = 0;\n let maxScroll = 0;\n const hoverTargets = new Set<string>();\n\n for (const ev of buffer) {\n if (ev.kind === \"click\" && ev.t >= windowStart) clicksLastMin += 1;\n if (ev.kind === \"dwell\") {\n dwellSum += ev.durationMs;\n dwellCount += 1;\n }\n if (ev.kind === \"scroll\" && ev.depth > maxScroll) maxScroll = ev.depth;\n if (ev.kind === \"hover\") hoverTargets.add(ev.target);\n }\n\n return {\n clicks_per_min: clicksLastMin,\n avg_dwell_ms: dwellCount === 0 ? 0 : Math.round(dwellSum / dwellCount),\n scroll_depth: Math.max(0, Math.min(1, maxScroll)),\n hover_count: hoverTargets.size,\n events_seen: Math.min(buffer.length, bufferSize),\n page_context: pageContext,\n };\n}\n\nexport function useBehaviorTracker(opts: UseBehaviorTrackerOpts): {\n recentEvents: BehaviorEvent[];\n} {\n const {\n containerRef,\n flushEveryEvents = 10,\n flushAfterMs = 5000,\n bufferSize = 50,\n onFlush,\n pageContext,\n seedTrace,\n } = opts;\n\n const bufferRef = useRef<BehaviorEvent[]>([]);\n const sinceFlushRef = useRef(0);\n const lastFlushAtRef = useRef(Date.now());\n const hoverStartRef = useRef<Map<string, number>>(new Map());\n const scrollRafRef = useRef<number | null>(null);\n\n const onFlushRef = useRef(onFlush);\n const pageContextRef = useRef(pageContext);\n useEffect(() => {\n onFlushRef.current = onFlush;\n }, [onFlush]);\n useEffect(() => {\n pageContextRef.current = pageContext;\n }, [pageContext]);\n\n const [recentEvents, setRecentEvents] = useState<BehaviorEvent[]>([]);\n\n const pushEvent = (ev: BehaviorEvent) => {\n const buf = bufferRef.current;\n buf.push(ev);\n if (buf.length > bufferSize) buf.splice(0, buf.length - bufferSize);\n sinceFlushRef.current += 1;\n\n setRecentEvents((prev) => {\n const next = [...prev, ev];\n if (next.length > RECENT_EVENTS_CAP) next.splice(0, next.length - RECENT_EVENTS_CAP);\n return next;\n });\n\n if (sinceFlushRef.current >= flushEveryEvents) {\n flush();\n }\n };\n\n const flush = () => {\n const summary = computeSummary(bufferRef.current, bufferSize, pageContextRef.current);\n sinceFlushRef.current = 0;\n lastFlushAtRef.current = Date.now();\n onFlushRef.current(summary);\n };\n\n useEffect(() => {\n if (seedTrace && seedTrace.length > 0) {\n const buf = bufferRef.current;\n // Rebase t values so the latest seed event aligns with Date.now().\n // Personas use small relative timestamps; this ensures click-per-min\n // and freshness-based metrics see them as recent activity.\n const maxT = seedTrace.reduce((m, e) => (e.t > m ? e.t : m), -Infinity);\n const now = Date.now();\n const offset = Number.isFinite(maxT) ? now - maxT : 0;\n const rebased = seedTrace.map((e) => ({ ...e, t: e.t + offset }));\n buf.push(...rebased);\n if (buf.length > bufferSize) buf.splice(0, buf.length - bufferSize);\n const summary = computeSummary(buf, bufferSize, pageContextRef.current);\n sinceFlushRef.current = 0;\n lastFlushAtRef.current = Date.now();\n onFlushRef.current(summary);\n }\n // mount-only seed\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const onClick = (e: MouseEvent) => {\n pushEvent({ kind: \"click\", target: targetLabel(e.target), t: Date.now() });\n };\n\n const onMouseOver = (e: MouseEvent) => {\n const label = targetLabel(e.target);\n if (!hoverStartRef.current.has(label)) {\n hoverStartRef.current.set(label, Date.now());\n }\n };\n\n const onMouseOut = (e: MouseEvent) => {\n const label = targetLabel(e.target);\n const started = hoverStartRef.current.get(label);\n if (started == null) return;\n hoverStartRef.current.delete(label);\n const durationMs = Date.now() - started;\n if (durationMs < HOVER_MIN_MS) return;\n const t = Date.now();\n pushEvent({ kind: \"hover\", target: label, durationMs, t });\n pushEvent({ kind: \"dwell\", target: label, durationMs, t });\n };\n\n const computeScrollDepth = () => {\n const rect = el.getBoundingClientRect();\n const viewportH = window.innerHeight || 1;\n const elementH = el.scrollHeight || rect.height || 1;\n const visibleBottom = Math.min(rect.bottom, viewportH);\n const scrolledPast = Math.max(0, visibleBottom - rect.top);\n return Math.max(0, Math.min(1, scrolledPast / elementH));\n };\n\n const onScroll = () => {\n if (scrollRafRef.current != null) return;\n scrollRafRef.current = requestAnimationFrame(() => {\n scrollRafRef.current = null;\n pushEvent({ kind: \"scroll\", depth: computeScrollDepth(), t: Date.now() });\n });\n };\n\n el.addEventListener(\"click\", onClick);\n el.addEventListener(\"mouseover\", onMouseOver);\n el.addEventListener(\"mouseout\", onMouseOut);\n window.addEventListener(\"scroll\", onScroll, { passive: true });\n\n const interval = window.setInterval(() => {\n if (Date.now() - lastFlushAtRef.current >= flushAfterMs) {\n flush();\n }\n }, Math.max(250, Math.floor(flushAfterMs / 4)));\n\n return () => {\n el.removeEventListener(\"click\", onClick);\n el.removeEventListener(\"mouseover\", onMouseOver);\n el.removeEventListener(\"mouseout\", onMouseOut);\n window.removeEventListener(\"scroll\", onScroll);\n window.clearInterval(interval);\n if (scrollRafRef.current != null) cancelAnimationFrame(scrollRafRef.current);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [containerRef, flushAfterMs, flushEveryEvents, bufferSize]);\n\n return { recentEvents };\n}\n","import type { BehaviorEvent } from \"./types\";\n\n// Persona traces use *relative* t values (ms). The tracker rebases them so the\n// latest event becomes Date.now() at mount, keeping clicks_per_min meaningful.\n\nfunction buildDecisive(): BehaviorEvent[] {\n // ~12 fast clicks across 6 product targets, short dwells, deep scroll.\n const events: BehaviorEvent[] = [];\n const productIds = [\"p-101\", \"p-102\", \"p-103\", \"p-104\", \"p-105\", \"p-106\"];\n let t = 0;\n\n for (let i = 0; i < 12; i++) {\n t += 1500;\n events.push({ kind: \"click\", target: productIds[i % productIds.length], t });\n }\n for (let i = 0; i < 6; i++) {\n t += 800;\n events.push({\n kind: \"dwell\",\n target: productIds[i % productIds.length],\n durationMs: 600 + i * 80,\n t,\n });\n }\n for (let i = 0; i < 6; i++) {\n t += 1200;\n events.push({\n kind: \"scroll\",\n depth: Math.min(0.95, 0.4 + i * 0.1),\n t,\n });\n }\n for (let i = 0; i < 2; i++) {\n t += 600;\n events.push({\n kind: \"hover\",\n target: productIds[i],\n durationMs: 250,\n t,\n });\n }\n\n return events;\n}\n\nfunction buildDeliberate(): BehaviorEvent[] {\n // ~3 clicks across 6 distinct hover targets, long dwells, modest scroll.\n const events: BehaviorEvent[] = [];\n const productIds = [\"p-201\", \"p-202\", \"p-203\", \"p-204\", \"p-205\", \"p-206\"];\n let t = 0;\n\n for (let i = 0; i < 6; i++) {\n t += 5500;\n const target = productIds[i];\n events.push({ kind: \"hover\", target, durationMs: 1800 + i * 200, t });\n t += 200;\n events.push({\n kind: \"dwell\",\n target,\n durationMs: 5000 + i * 400,\n t,\n });\n }\n for (let i = 0; i < 3; i++) {\n t += 4000;\n events.push({ kind: \"click\", target: productIds[i], t });\n }\n for (let i = 0; i < 5; i++) {\n t += 1500;\n events.push({\n kind: \"scroll\",\n depth: Math.min(0.6, 0.2 + i * 0.08),\n t,\n });\n }\n\n return events;\n}\n\nexport const PERSONAS: Record<\"decisive\" | \"deliberate\", BehaviorEvent[]> = {\n get decisive() {\n return buildDecisive();\n },\n get deliberate() {\n return buildDeliberate();\n },\n};\n","import * as React from \"react\";\nimport { BeGenContext, type BeGenContextValue } from \"./BeGenProvider\";\n\nexport function useBeGenContext(): BeGenContextValue {\n const ctx = React.useContext(BeGenContext);\n if (!ctx) {\n throw new Error(\"useBeGenContext must be used inside <BeGenProvider>\");\n }\n return ctx;\n}\n","import type { AgentDirective, ClassifyFn, Variant } from \"../types\";\n\nconst CLASSIFIER_SYSTEM_PROMPT = `\nYou classify e-commerce shopper behavior into UI variants.\n\nYou receive a JSON object describing a user's recent interaction pattern on\na product listing page. Decide which UI variant best serves them right now.\n\nVariants:\n- \"decisive\": user knows what they want; minimize friction. Dense grid,\n prominent prices, fast paths to cart, no recommendations.\n Signals: high clicks/min, low dwell, high scroll depth, few hovers.\n- \"deliberate\": user is researching; help them compare. Larger cards,\n reviews surfaced inline, \"people also viewed\", expandable detail.\n Signals: low clicks/min, high dwell, hovers across multiple products.\n- \"neutral\": insufficient signal yet, or pattern is mixed. Baseline grid.\n Default for first ~10 events.\n\nExamples:\nInput: {\"clicks_per_min\":14,\"avg_dwell_ms\":820,\"scroll_depth\":0.91,\"hover_count\":2,\"events_seen\":18}\nOutput: {\"variant\":\"decisive\",\"confidence\":0.86,\"reasoning\":\"Fast clicks, low dwell, deep scroll — purposeful navigation.\"}\n\nInput: {\"clicks_per_min\":3,\"avg_dwell_ms\":7400,\"scroll_depth\":0.42,\"hover_count\":4,\"events_seen\":22}\nOutput: {\"variant\":\"deliberate\",\"confidence\":0.81,\"reasoning\":\"Slow pace, long dwell, multi-product hover — comparing options.\"}\n\nInput: {\"clicks_per_min\":5,\"avg_dwell_ms\":2100,\"scroll_depth\":0.55,\"hover_count\":2,\"events_seen\":7}\nOutput: {\"variant\":\"neutral\",\"confidence\":0.6,\"reasoning\":\"Not enough events yet to commit to a mode.\"}\n\nReturn ONLY a JSON object. No prose, no markdown.\n`.trim();\n\nconst VALID_VARIANTS: ReadonlySet<Variant> = new Set([\"decisive\", \"deliberate\", \"neutral\"]);\n\nconst FALLBACK: AgentDirective = {\n variant: \"neutral\",\n confidence: 0,\n reasoning: \"Classifier error.\",\n};\n\nexport type CreateGeminiClassifierOpts = {\n apiKey: string;\n model?: string;\n endpoint?: string;\n fetchImpl?: typeof fetch;\n};\n\nexport function createGeminiClassifier(opts: CreateGeminiClassifierOpts): ClassifyFn {\n const { apiKey, model = \"gemini-2.0-flash\", endpoint, fetchImpl } = opts;\n const url =\n endpoint ??\n `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent`;\n const fetcher = fetchImpl ?? (typeof fetch !== \"undefined\" ? fetch.bind(globalThis) : null);\n\n return async (summary) => {\n if (!fetcher) return FALLBACK;\n try {\n const res = await fetcher(`${url}?key=${encodeURIComponent(apiKey)}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n systemInstruction: { parts: [{ text: CLASSIFIER_SYSTEM_PROMPT }] },\n contents: [\n {\n role: \"user\",\n parts: [{ text: JSON.stringify(summary) }],\n },\n ],\n generationConfig: {\n responseMimeType: \"application/json\",\n temperature: 0.2,\n },\n }),\n });\n\n if (!res.ok) return FALLBACK;\n const data = (await res.json()) as {\n candidates?: { content?: { parts?: { text?: string }[] } }[];\n };\n const text = data.candidates?.[0]?.content?.parts?.[0]?.text;\n if (!text) return FALLBACK;\n\n const parsed = JSON.parse(text) as Partial<AgentDirective>;\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n typeof parsed.variant !== \"string\" ||\n !VALID_VARIANTS.has(parsed.variant as Variant) ||\n typeof parsed.reasoning !== \"string\"\n ) {\n return FALLBACK;\n }\n const confidence =\n typeof parsed.confidence === \"number\" && Number.isFinite(parsed.confidence)\n ? Math.max(0, Math.min(1, parsed.confidence))\n : 0.5;\n\n return {\n variant: parsed.variant as Variant,\n confidence,\n reasoning: parsed.reasoning,\n };\n } catch {\n return FALLBACK;\n }\n };\n}\n","import type { ClassifyFn } from \"../types\";\n\nexport function createHeuristicClassifier(): ClassifyFn {\n return async (summary) => {\n if (summary.events_seen < 10) {\n return {\n variant: \"neutral\",\n confidence: 0.5,\n reasoning: \"Insufficient events.\",\n };\n }\n if (summary.clicks_per_min > 8 && summary.avg_dwell_ms < 2000) {\n return {\n variant: \"decisive\",\n confidence: 0.8,\n reasoning: \"Fast pace, low dwell.\",\n };\n }\n if (summary.avg_dwell_ms > 4000 && summary.hover_count > 2) {\n return {\n variant: \"deliberate\",\n confidence: 0.8,\n reasoning: \"Slow pace, multi-hover.\",\n };\n }\n return {\n variant: \"neutral\",\n confidence: 0.6,\n reasoning: \"Mixed signals.\",\n };\n };\n}\n"],"mappings":"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","names":["React","import_jsx_runtime","React"]}
@@ -0,0 +1,94 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React$1 from 'react';
3
+
4
+ type BehaviorEvent = {
5
+ kind: "click";
6
+ target: string;
7
+ t: number;
8
+ } | {
9
+ kind: "scroll";
10
+ depth: number;
11
+ t: number;
12
+ } | {
13
+ kind: "hover";
14
+ target: string;
15
+ durationMs: number;
16
+ t: number;
17
+ } | {
18
+ kind: "dwell";
19
+ target: string;
20
+ durationMs: number;
21
+ t: number;
22
+ };
23
+ type BehaviorSummary = {
24
+ clicks_per_min: number;
25
+ avg_dwell_ms: number;
26
+ scroll_depth: number;
27
+ hover_count: number;
28
+ events_seen: number;
29
+ page_context: {
30
+ route: string;
31
+ visible_product_ids: string[];
32
+ };
33
+ };
34
+ type Variant = "decisive" | "deliberate" | "neutral";
35
+ type AgentDirective = {
36
+ variant: Variant;
37
+ confidence: number;
38
+ reasoning: string;
39
+ };
40
+ type ClassifyFn = (summary: BehaviorSummary) => Promise<AgentDirective>;
41
+
42
+ type BeGenContextValue = {
43
+ variant: Variant;
44
+ directive: AgentDirective | null;
45
+ summary: BehaviorSummary | null;
46
+ setVariant: (v: Variant) => void;
47
+ setDirective: (d: AgentDirective) => void;
48
+ setSummary: (s: BehaviorSummary) => void;
49
+ };
50
+ declare function BeGenProvider({ children }: {
51
+ children: React$1.ReactNode;
52
+ }): react_jsx_runtime.JSX.Element;
53
+
54
+ type BeGenSurfaceProps = {
55
+ variants: Record<Variant, React$1.ComponentType<any>>;
56
+ classify: ClassifyFn;
57
+ variantProps?: Record<string, any>;
58
+ pageContext: BehaviorSummary["page_context"];
59
+ seedPersona?: "decisive" | "deliberate";
60
+ rateLimitMs?: number;
61
+ className?: string;
62
+ style?: React$1.CSSProperties;
63
+ children?: never;
64
+ };
65
+ declare function BeGenSurface(props: BeGenSurfaceProps): react_jsx_runtime.JSX.Element;
66
+
67
+ type UseBehaviorTrackerOpts = {
68
+ containerRef: React.RefObject<HTMLElement>;
69
+ flushEveryEvents?: number;
70
+ flushAfterMs?: number;
71
+ bufferSize?: number;
72
+ onFlush: (summary: BehaviorSummary) => void;
73
+ pageContext: BehaviorSummary["page_context"];
74
+ seedTrace?: BehaviorEvent[];
75
+ };
76
+ declare function useBehaviorTracker(opts: UseBehaviorTrackerOpts): {
77
+ recentEvents: BehaviorEvent[];
78
+ };
79
+
80
+ declare function useBeGenContext(): BeGenContextValue;
81
+
82
+ type CreateGeminiClassifierOpts = {
83
+ apiKey: string;
84
+ model?: string;
85
+ endpoint?: string;
86
+ fetchImpl?: typeof fetch;
87
+ };
88
+ declare function createGeminiClassifier(opts: CreateGeminiClassifierOpts): ClassifyFn;
89
+
90
+ declare function createHeuristicClassifier(): ClassifyFn;
91
+
92
+ declare const PERSONAS: Record<"decisive" | "deliberate", BehaviorEvent[]>;
93
+
94
+ export { type AgentDirective, type BeGenContextValue, BeGenProvider, BeGenSurface, type BeGenSurfaceProps, type BehaviorEvent, type BehaviorSummary, type ClassifyFn, type CreateGeminiClassifierOpts, PERSONAS, type UseBehaviorTrackerOpts, type Variant, createGeminiClassifier, createHeuristicClassifier, useBeGenContext, useBehaviorTracker };