Skip to content

Commit a9d66a9

Browse files
committed
feat: add AGON playground for real-time encoding and token comparison
1 parent 91173de commit a9d66a9

11 files changed

Lines changed: 2368 additions & 2 deletions

File tree

PLAYGROUND.md

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# AGON Playground Implementation Plan
2+
3+
## Overview
4+
Add an interactive playground to the MkDocs documentation where users can:
5+
1. Input JSON data and see real-time encoding in all 4 AGON formats
6+
2. Compare token counts and savings across formats
7+
3. See which format would be auto-selected
8+
4. Edit and experiment with different data shapes
9+
10+
## Technical Approach
11+
12+
### Challenge
13+
AGON is implemented in Rust with Python bindings - cannot run directly in the browser.
14+
15+
### Solution: Pure JavaScript Implementation
16+
Implement lightweight JavaScript versions of the encoders for the playground. This provides:
17+
- Zero latency (no server round-trips)
18+
- Works offline
19+
- Self-contained in docs
20+
- No backend infrastructure needed
21+
22+
The encoding formats are simple string transformations that can be ported accurately to JavaScript.
23+
24+
## Implementation Plan
25+
26+
### 1. Create Playground Page
27+
**File:** `docs/playground.md`
28+
29+
- New documentation page with embedded playground
30+
- JSON editor input area
31+
- Output panels for each format (JSON, Rows, Columns, Struct)
32+
- Token count comparison chart
33+
- Auto-format recommendation indicator
34+
35+
### 2. Create JavaScript Encoder Module
36+
**File:** `docs/javascripts/agon-playground.js`
37+
38+
Implement:
39+
- `encodeRows(data)` - AGONRows format encoder
40+
- `encodeColumns(data)` - AGONColumns format encoder
41+
- `encodeStruct(data)` - AGONStruct format encoder
42+
- `estimateTokens(text)` - Simple token estimation (chars/4 or GPT tokenizer)
43+
- `autoSelect(data)` - Format selection logic with min_savings threshold
44+
45+
### 3. Create Playground UI Component
46+
**File:** `docs/javascripts/playground-ui.js`
47+
48+
Features:
49+
- **Monaco Editor** for JSON input (VS Code editor with full syntax highlighting, auto-completion, JSON validation)
50+
- Live encoding preview (debounced for performance)
51+
- Tab panels for each encoding output
52+
- Token savings visualization (reuse Chart.js from benchmarks)
53+
- Copy-to-clipboard buttons
54+
- Example data dropdown (pre-loaded examples from benchmarks)
55+
- Error handling for invalid JSON
56+
57+
**Monaco Setup:**
58+
- Load from CDN: `monaco-editor` via `@monaco-editor/loader`
59+
- Configure for JSON language with schema validation
60+
- Theme sync with MkDocs light/dark mode
61+
62+
### 4. Add Styling
63+
**File:** `docs/stylesheets/playground.css`
64+
65+
- Responsive two-column layout (input | output)
66+
- Dark/light mode support (matches Material theme)
67+
- Syntax highlighting for output formats
68+
- Mobile-friendly collapsible panels
69+
70+
### 5. Update MkDocs Configuration
71+
**File:** `mkdocs.yml`
72+
73+
- Add playground to navigation
74+
- Include new JavaScript/CSS files
75+
- Add extra_css entry
76+
77+
## Files to Create/Modify
78+
79+
| File | Action | Description |
80+
|------|--------|-------------|
81+
| `docs/playground.md` | Create | Playground page with HTML structure |
82+
| `docs/javascripts/agon-playground.js` | Create | Core encoding logic in JS |
83+
| `docs/javascripts/playground-ui.js` | Create | UI interactions and rendering |
84+
| `docs/stylesheets/playground.css` | Create | Playground styling |
85+
| `mkdocs.yml` | Modify | Add nav entry and extra files |
86+
87+
## External Dependencies (CDN)
88+
89+
| Library | Purpose | Size | CDN |
90+
|---------|---------|------|-----|
91+
| Monaco Editor | JSON input editor | ~2MB | jsdelivr |
92+
| js-tiktoken | Accurate token counting | ~300KB | jsdelivr |
93+
| Chart.js | Already included | - | Already in mkdocs.yml |
94+
95+
## Encoding Implementation Details
96+
97+
### AGONRows Encoder (JS)
98+
```javascript
99+
// Input: [{id: 1, name: "Alice"}, {id: 2, name: "Bob"}]
100+
// Output: [2]{id name}
101+
// 1 Alice
102+
// 2 Bob
103+
```
104+
105+
Key logic:
106+
1. Detect if data is uniform array of objects
107+
2. Extract field names from first object
108+
3. Generate header `[count]{field1 field2 ...}`
109+
4. Render each row with tab-delimited values
110+
5. Handle nested objects with indentation
111+
112+
### AGONColumns Encoder (JS)
113+
```javascript
114+
// Input: [{id: 1, name: "Alice"}, {id: 2, name: "Bob"}]
115+
// Output: [2]
116+
// ├ id: 1 2
117+
// └ name: Alice Bob
118+
```
119+
120+
Key logic:
121+
1. Transpose data (group by field instead of row)
122+
2. Generate `[count]` header
123+
3. Render each field with tree chars (├ / └)
124+
4. Tab-delimit values within each field line
125+
126+
### AGONStruct Encoder (JS)
127+
```javascript
128+
// Input: {price: {fmt: "$100", raw: 100}, change: {fmt: "+5", raw: 5}}
129+
// Output: @FR: fmt, raw
130+
//
131+
// price: FR($100, 100)
132+
// change: FR(+5, 5)
133+
```
134+
135+
Key logic:
136+
1. Detect repeated object patterns (same field structure)
137+
2. Generate template definition if ≥3 occurrences
138+
3. Replace instances with template calls
139+
140+
### Token Counting (Accurate)
141+
Use **js-tiktoken** for GPT-accurate token counts:
142+
- Load `tiktoken` from npm CDN (jsdelivr/unpkg)
143+
- Use `o200k_base` encoding (GPT-4o default, matches AGON's default)
144+
- Lazy-load tokenizer on first use to avoid blocking page load
145+
- Cache tokenizer instance for subsequent calculations
146+
147+
## UI Layout
148+
149+
```
150+
┌─────────────────────────────────────────────────────────────┐
151+
│ AGON Playground [Load Example ▼] │
152+
├───────────────────────────┬─────────────────────────────────┤
153+
│ JSON Input │ Encoded Output │
154+
│ ┌─────────────────────┐ │ ┌───────────────────────────┐ │
155+
│ │ { │ │ │ [JSON] [Rows] [Cols] [St] │ │
156+
│ │ "users": [ │ │ ├───────────────────────────┤ │
157+
│ │ {"id": 1, ... │ │ │ [2]{id name} │ │
158+
│ │ ] │ │ │ 1 Alice │ │
159+
│ │ } │ │ │ 2 Bob │ │
160+
│ └─────────────────────┘ │ └───────────────────────────┘ │
161+
│ │ │
162+
│ ┌─────────────────────────────────────────────────────────┐│
163+
│ │ Token Comparison Chart ││
164+
│ │ [====== JSON 45 ======] ││
165+
│ │ [=== Rows 26 ===] ✓ Best (-42%) ││
166+
│ │ [==== Cols 30 ====] ││
167+
│ │ [===== Struct 35 =====] ││
168+
│ └─────────────────────────────────────────────────────────┘│
169+
└─────────────────────────────────────────────────────────────┘
170+
```
171+
172+
## Example Data Options
173+
174+
Pre-loaded examples from benchmark data:
175+
1. User list (simple - Rows wins)
176+
2. Employee records (wide - Columns wins)
177+
3. Market data (nested patterns - Struct wins)
178+
4. Hiking data (mixed - demonstrates auto selection)
179+
180+
## Verification
181+
182+
1. **Unit test encoders**: Compare JS output with Python AGON output for test cases
183+
2. **Visual testing**: Load playground, test each example, verify outputs match docs
184+
3. **Build check**: `mkdocs build` succeeds without errors
185+
4. **Live preview**: `mkdocs serve` shows interactive playground

docs/data/gainers.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

docs/data/quote.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

docs/data/toon.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"context": {
3+
"task": "Our favorite hikes together",
4+
"location": "Boulder",
5+
"season": "spring_2025"
6+
},
7+
"friends": ["ana", "luis", "sam"],
8+
"hikes": [
9+
{
10+
"id": 1,
11+
"name": "Blue Lake Trail",
12+
"distanceKm": 7.5,
13+
"elevationGain": 320,
14+
"companion": "ana",
15+
"wasSunny": true
16+
},
17+
{
18+
"id": 2,
19+
"name": "Ridge Overlook",
20+
"distanceKm": 9.2,
21+
"elevationGain": 540,
22+
"companion": "luis",
23+
"wasSunny": false
24+
},
25+
{
26+
"id": 3,
27+
"name": "Wildflower Loop",
28+
"distanceKm": 5.1,
29+
"elevationGain": 180,
30+
"companion": "sam",
31+
"wasSunny": true
32+
}
33+
]
34+
}

0 commit comments

Comments
 (0)