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 +21 -0
- package/README.md +311 -0
- package/dist/index.cjs +523 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +94 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.js +480 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
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["<BeGenSurface>"]
|
|
94
|
+
Provider["<BeGenProvider>"]
|
|
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).
|