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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BeGeniux contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,311 @@
1
+ # begeniux
2
+
3
+ **Behaviorally-adaptive UI through LLM agents and the AG-UI protocol.**
4
+
5
+ Most generative UI today reacts to *prompts*. **BeGeniux reacts to behavioral traces** — clicks, scrolls, hovers, dwells — and re-renders the UI to match observed user behavior, in real time, at session granularity.
6
+
7
+ You wrap a region of UI in `<BeGenSurface>`, pass in a set of variant components and a `classify` function. The library handles behavior tracking, summarization, and variant swapping. Bring your own LLM — Gemini, Claude, OpenAI, a heuristic, anything that satisfies `ClassifyFn`.
8
+
9
+ ---
10
+
11
+ ## Why this exists
12
+
13
+ Adaptive UI research is 30+ years old. SUPPLE (2004) showed UIs could regenerate per-user. Contextual bandits (2010) showed online learning could pick layouts. Implicit-feedback work (2005) showed clicks already encode preference. None of this shipped at scale. Why?
14
+
15
+ - **Hand-coded rules** couldn't keep up with the combinatorics of real UIs.
16
+ - **Shallow ML** needed huge population-level traffic to converge — too slow for a single session.
17
+ - **A/B tests** optimize *populations*, not *individuals* — the wrong granularity.
18
+
19
+ In-context learning (GPT-3 onward) finally cracked it. An LLM can reason from a handful of behavioral signals to a sensible UI choice, **without training, without traffic, in one session**. That's the unlock.
20
+
21
+ ```mermaid
22
+ flowchart LR
23
+ subgraph Trad["Today's generative UI"]
24
+ direction LR
25
+ P["💬 User<br/>prompt"] --> M1["LLM"] --> U1["Generated UI"]
26
+ end
27
+ subgraph Be["BeGeniux"]
28
+ direction LR
29
+ B["🖱️ Behavioral trace<br/>clicks · scrolls · hovers · dwells"] --> M2["LLM<br/>as policy"] --> U2["Adapted UI<br/>session-granular"]
30
+ end
31
+ Trad ~~~ Be
32
+ ```
33
+
34
+ > Our contribution is the combination of three ideas that have not been combined before: **interaction traces as the input modality** (not text prompts), **LLM agents as the policy** (not hand-coded rules or shallow classifiers), and **session-granularity adaptation** (not population-level A/B tests) — under developer-declared invariants that keep the policy honest. The first two are 2024+ technology that finally make 30 years of adaptive UI research tractable.
35
+
36
+ ### The goal
37
+
38
+ Make any web region **behaviorally adaptive** with one component swap. The developer keeps full control of the variants — the library only decides *which* one is rendered, *when*, and *why* (with the LLM's reasoning string attached).
39
+
40
+ ---
41
+
42
+ ## How it works
43
+
44
+ Every `<BeGenSurface>` runs a tight loop, scoped to its own DOM region:
45
+
46
+ ```mermaid
47
+ sequenceDiagram
48
+ autonumber
49
+ participant U as User
50
+ participant T as useBehaviorTracker
51
+ participant S as BeGenSurface
52
+ participant C as classify (your code)
53
+ participant V as Active variant
54
+
55
+ U->>T: clicks · scrolls · hovers · dwells
56
+ Note over T: Ring buffer of last 50 events<br/>(scoped to this surface only)
57
+ T->>T: Every 10 events OR 5s →<br/>compute BehaviorSummary
58
+ T->>S: BehaviorSummary
59
+ S->>S: rate-limit gate (≥4s since last call)
60
+ S->>C: classify(summary)
61
+ Note over C: Your LLM / AG-UI route /<br/>heuristic — anything matching ClassifyFn
62
+ C-->>S: AgentDirective<br/>{variant, confidence, reasoning}
63
+ S->>V: mount variants[directive.variant]<br/>with variantProps
64
+ V->>U: new UI · ≤ 2s round-trip
65
+ ```
66
+
67
+ Three things keep this honest:
68
+
69
+ 1. **Listeners scoped to the container element**, not `window` — two surfaces side-by-side never cross-pollute events.
70
+ 2. **Rate limit on `classify`** (default 4s) — caps cost and prevents thrash.
71
+ 3. **Errors keep the current variant.** A classifier failure never crashes the UI; the user just stays on what they had.
72
+
73
+ ---
74
+
75
+ ## Where it fits in your stack
76
+
77
+ The library is one layer. You bring your variants and your policy:
78
+
79
+ ```mermaid
80
+ flowchart TB
81
+ subgraph YourApp["Your application"]
82
+ direction TB
83
+ Page["Page / Route"]
84
+ Variants["Your variant components<br/>DenseGrid · DeliberateGrid · NeutralGrid"]
85
+ Classify["Your classify function"]
86
+ Page --> Surface
87
+ Surface -->|renders one of| Variants
88
+ Surface -->|invokes| Classify
89
+ end
90
+
91
+ subgraph Lib["begeniux (this package)"]
92
+ direction TB
93
+ Surface["&lt;BeGenSurface&gt;"]
94
+ Provider["&lt;BeGenProvider&gt;"]
95
+ Tracker["useBehaviorTracker"]
96
+ Ctx["BeGenContext"]
97
+ Surface -.uses.-> Tracker
98
+ Surface -.publishes to.-> Ctx
99
+ Provider -.exposes.-> Ctx
100
+ end
101
+
102
+ subgraph Policy["Behind your classify fn (you choose)"]
103
+ direction TB
104
+ Gemini["Gemini 2.0 Flash<br/>via createGeminiClassifier"]
105
+ AGUI["AG-UI / CopilotKit route"]
106
+ Anth["Claude / OpenAI / local model"]
107
+ Heur["createHeuristicClassifier<br/>(zero-dep fallback)"]
108
+ end
109
+
110
+ Classify -.-> Gemini
111
+ Classify -.-> AGUI
112
+ Classify -.-> Anth
113
+ Classify -.-> Heur
114
+ ```
115
+
116
+ **Nothing in this library imports CopilotKit, AG-UI SDK, Next.js, or any LLM SDK.** It runs anywhere React 18+ runs. The agent backend is a `ClassifyFn` injection — that's the entire integration surface.
117
+
118
+ ---
119
+
120
+ ## The contract
121
+
122
+ Three types are the entire boundary between your code and the library:
123
+
124
+ ```mermaid
125
+ flowchart LR
126
+ E["BehaviorEvent[]<br/><i>click · scroll · hover · dwell</i>"]
127
+ S["BehaviorSummary<br/><i>clicks_per_min, avg_dwell_ms,<br/>scroll_depth, hover_count,<br/>events_seen, page_context</i>"]
128
+ D["AgentDirective<br/><i>variant · confidence · reasoning</i>"]
129
+ V["Rendered variant"]
130
+
131
+ E -->|tracker aggregates| S
132
+ S -->|ClassifyFn = your policy| D
133
+ D -->|surface selects| V
134
+ ```
135
+
136
+ In code:
137
+
138
+ ```ts
139
+ type ClassifyFn = (summary: BehaviorSummary) => Promise<AgentDirective>;
140
+
141
+ type BehaviorSummary = {
142
+ clicks_per_min: number;
143
+ avg_dwell_ms: number;
144
+ scroll_depth: number; // 0–1
145
+ hover_count: number;
146
+ events_seen: number; // saturates at 50
147
+ page_context: { route: string; visible_product_ids: string[] };
148
+ };
149
+
150
+ type AgentDirective = {
151
+ variant: "decisive" | "deliberate" | "neutral";
152
+ confidence: number; // 0–1
153
+ reasoning: string; // one-sentence English
154
+ };
155
+ ```
156
+
157
+ Whatever you put behind `ClassifyFn` — Gemini, Claude, OpenAI, a CopilotKit/AG-UI route, a hand-tuned regex — it's the policy that decides which variant the user sees. Freeze these types and the library and your agent backend evolve independently. See [`src/types.ts`](./src/types.ts) for the canonical definitions.
158
+
159
+ ---
160
+
161
+ ## Install
162
+
163
+ ```bash
164
+ npm install begeniux
165
+ ```
166
+
167
+ Peer dependencies: `react@>=18`, `react-dom@>=18`. The library has zero runtime dependencies and works without CopilotKit, AG-UI, or any specific LLM SDK.
168
+
169
+ ## Quick start
170
+
171
+ ```tsx
172
+ import {
173
+ BeGenProvider,
174
+ BeGenSurface,
175
+ createGeminiClassifier,
176
+ } from "begeniux";
177
+
178
+ const classify = createGeminiClassifier({
179
+ apiKey: process.env.NEXT_PUBLIC_GEMINI_KEY!,
180
+ });
181
+
182
+ export default function App({ products }) {
183
+ return (
184
+ <BeGenProvider>
185
+ <BeGenSurface
186
+ variants={{
187
+ decisive: DenseGrid,
188
+ deliberate: DeliberateGrid,
189
+ neutral: NeutralGrid,
190
+ }}
191
+ variantProps={{ products }}
192
+ classify={classify}
193
+ pageContext={{
194
+ route: "/products",
195
+ visible_product_ids: products.map((p) => p.id),
196
+ }}
197
+ />
198
+ </BeGenProvider>
199
+ );
200
+ }
201
+ ```
202
+
203
+ That's the whole integration. The surface tracks behavior in its DOM region, calls `classify` on a debounce, and swaps the rendered variant component when the directive changes.
204
+
205
+ ## API
206
+
207
+ | Export | What it does |
208
+ |---|---|
209
+ | `<BeGenProvider>` | Context provider for surface state. Required if you want to call `useBeGenContext()` from a child. |
210
+ | `<BeGenSurface>` | The main component. Tracks behavior, calls `classify`, renders the active variant. |
211
+ | `useBehaviorTracker(opts)` | Low-level hook for custom integrations — same engine the surface uses. |
212
+ | `useBeGenContext()` | Reads the current `variant`, `directive`, and `summary` from context. |
213
+ | `createGeminiClassifier(opts)` | Returns a `ClassifyFn` that calls Google's Gemini API directly. |
214
+ | `createHeuristicClassifier()` | Zero-dependency heuristic fallback. Useful for offline dev and demos. |
215
+ | `PERSONAS` | Pre-canned behavior traces (`decisive`, `deliberate`) for deterministic demos via `seedPersona`. |
216
+
217
+ Full type signatures live in [`src/types.ts`](./src/types.ts) — that file is the contract between the library and the consumer (also visualized [above](#the-contract)).
218
+
219
+ ## Wiring AG-UI / CopilotKit
220
+
221
+ The library is intentionally agnostic to the agent backend. To route through CopilotKit/AG-UI, write a thin `ClassifyFn`:
222
+
223
+ ```tsx
224
+ const classify: ClassifyFn = async (summary) => {
225
+ const res = await fetch("/api/copilotkit", {
226
+ method: "POST",
227
+ headers: { "content-type": "application/json" },
228
+ body: JSON.stringify({ tool: "classify_behavior", summary }),
229
+ });
230
+ return res.json();
231
+ };
232
+ ```
233
+
234
+ Your route is responsible for invoking the agent and returning a JSON body that matches `AgentDirective`. The library never imports CopilotKit directly — keeping the package install-anywhere.
235
+
236
+ ## Determinism for demos
237
+
238
+ Pass `seedPersona="decisive"` or `seedPersona="deliberate"` to `<BeGenSurface>` and the surface will pre-seed its tracker with a canned trace. Within a couple of seconds of mount you'll get a stable directive — useful for split-screen demos, screenshots, and judges.
239
+
240
+ ```tsx
241
+ <BeGenSurface
242
+ variants={variants}
243
+ classify={classify}
244
+ pageContext={pageContext}
245
+ seedPersona="decisive"
246
+ />
247
+ ```
248
+
249
+ The traces live in [`src/personas.ts`](./src/personas.ts) — feel free to tune them.
250
+
251
+ ## Reading state from children
252
+
253
+ Wrap with `<BeGenProvider>` (or place provider above the surface) and call `useBeGenContext()`:
254
+
255
+ ```tsx
256
+ function TelemetryStrip() {
257
+ const { variant, directive, summary } = useBeGenContext();
258
+ return (
259
+ <div>
260
+ Mode: {variant}
261
+ {directive && ` · ${directive.reasoning}`}
262
+ {summary && ` · ${summary.events_seen} events`}
263
+ </div>
264
+ );
265
+ }
266
+ ```
267
+
268
+ Nice for debugging, demo overlays, or analytics.
269
+
270
+ ## Local development
271
+
272
+ ```bash
273
+ git clone <this repo>
274
+ cd packages/begeniux
275
+ npm install
276
+ npm run build # one-shot build to dist/
277
+ npm run dev # tsup --watch
278
+
279
+ cd examples/basic
280
+ npm install
281
+ npm run dev # http://localhost:5180
282
+ ```
283
+
284
+ The example imports from `../../src/index.ts` via a Vite alias, so source changes hot-reload. Two seeded surfaces render side-by-side using the heuristic classifier — no API keys required.
285
+
286
+ ## Research lineages
287
+
288
+ This library combines four threads of prior work that have rarely been combined in production UI:
289
+
290
+ - **Adaptive User Interfaces** — Gajos & Weld, *SUPPLE: Automatically Generating User Interfaces* (IUI 2004).
291
+ - **Contextual bandits** — Li et al., *A Contextual-Bandit Approach to Personalized News Article Recommendation* (WWW 2010).
292
+ - **Implicit feedback / behavior modeling** — Joachims et al., *Accurately Interpreting Clickthrough Data as Implicit Feedback* (SIGIR 2005).
293
+ - **In-context learning as policy** — Brown et al., *Language Models are Few-Shot Learners* (NeurIPS 2020).
294
+
295
+ The novel contribution is the combination: behavioral traces as input, LLM agents as policy, session-granularity adaptation, with developer-declared invariants.
296
+
297
+ ## Roadmap
298
+
299
+ - Multi-armed bandit policies (Thompson sampling) for variant selection.
300
+ - **Invariant DSL** — declare UI properties that must hold across variants (e.g., "cancel button always reachable", "checkout step never re-ordered").
301
+ - Behavior embeddings for open-ended UI generation beyond a fixed variant set.
302
+ - Eval harness with replay traces and counterfactual scoring.
303
+ - First-class adapters for CopilotKit, LangGraph, Mastra, and the Anthropic SDK.
304
+
305
+ ## Contributing
306
+
307
+ PRs welcome. Keep the public surface small — anything not exported from `src/index.ts` is private. Don't bundle React; don't add heavy dependencies; don't assume Next.js. The library should drop into Vite, CRA, Remix, Next, or anywhere React 18+ runs.
308
+
309
+ ## License
310
+
311
+ MIT — see [LICENSE](./LICENSE).