jule-ai-energy 1.0.3
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/.github/workflows/publish.yml +28 -0
- package/README.md +205 -0
- package/demo/JuleDemo.tsx +412 -0
- package/dist/adapters/aspidos-ai.d.ts +12 -0
- package/dist/adapters/aspidos-ai.d.ts.map +1 -0
- package/dist/adapters/aspidos-ai.js +68 -0
- package/dist/adapters/aspidos-ai.js.map +1 -0
- package/dist/core/jule-calculator.d.ts +12 -0
- package/dist/core/jule-calculator.d.ts.map +1 -0
- package/dist/core/jule-calculator.js +25 -0
- package/dist/core/jule-calculator.js.map +1 -0
- package/dist/core/reputation.d.ts +5 -0
- package/dist/core/reputation.d.ts.map +1 -0
- package/dist/core/reputation.js +28 -0
- package/dist/core/reputation.js.map +1 -0
- package/dist/core/the-shredder.d.ts +27 -0
- package/dist/core/the-shredder.d.ts.map +1 -0
- package/dist/core/the-shredder.js +231 -0
- package/dist/core/the-shredder.js.map +1 -0
- package/dist/energy/meter.d.ts +45 -0
- package/dist/energy/meter.d.ts.map +1 -0
- package/dist/energy/meter.js +124 -0
- package/dist/energy/meter.js.map +1 -0
- package/dist/fingerprint/delta-h-prime.d.ts +5 -0
- package/dist/fingerprint/delta-h-prime.d.ts.map +1 -0
- package/dist/fingerprint/delta-h-prime.js +22 -0
- package/dist/fingerprint/delta-h-prime.js.map +1 -0
- package/dist/fingerprint/gamma.d.ts +11 -0
- package/dist/fingerprint/gamma.d.ts.map +1 -0
- package/dist/fingerprint/gamma.js +114 -0
- package/dist/fingerprint/gamma.js.map +1 -0
- package/dist/fingerprint/phi.d.ts +13 -0
- package/dist/fingerprint/phi.d.ts.map +1 -0
- package/dist/fingerprint/phi.js +37 -0
- package/dist/fingerprint/phi.js.map +1 -0
- package/dist/fingerprint/sigma.d.ts +9 -0
- package/dist/fingerprint/sigma.d.ts.map +1 -0
- package/dist/fingerprint/sigma.js +19 -0
- package/dist/fingerprint/sigma.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +85 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/jaccard.d.ts +2 -0
- package/dist/utils/jaccard.d.ts.map +1 -0
- package/dist/utils/jaccard.js +8 -0
- package/dist/utils/jaccard.js.map +1 -0
- package/docs/aspidos-ai-spec.md +22 -0
- package/package.json +18 -0
- package/src/adapters/aspidos-ai.ts +90 -0
- package/src/core/jule-calculator.ts +39 -0
- package/src/core/reputation.ts +45 -0
- package/src/core/the-shredder.ts +307 -0
- package/src/energy/meter.ts +215 -0
- package/src/fingerprint/delta-h-prime.ts +43 -0
- package/src/fingerprint/gamma.ts +155 -0
- package/src/fingerprint/phi.ts +46 -0
- package/src/fingerprint/sigma.ts +25 -0
- package/src/index.ts +31 -0
- package/src/types/index.ts +121 -0
- package/src/utils/jaccard.ts +7 -0
- package/tests/shredder.test.ts +56 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: actions/setup-node@v4
|
|
15
|
+
with:
|
|
16
|
+
node-version: '20'
|
|
17
|
+
registry-url: 'https://registry.npmjs.org'
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: npm install
|
|
21
|
+
|
|
22
|
+
- name: Build
|
|
23
|
+
run: npm run build
|
|
24
|
+
|
|
25
|
+
- name: Publish
|
|
26
|
+
run: npm publish
|
|
27
|
+
env:
|
|
28
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Jule: Tokenizing the Value of Thought
|
|
2
|
+
|
|
3
|
+
*An Information-Economic Layer for AI Energy Efficiency*
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The AI industry faces a fundamental inefficiency: computation is cheap, so low-quality outputs proliferate. Verbose chain-of-thought, redundant tokens, hallucination-driven retries — all burn energy with no accountability.
|
|
8
|
+
|
|
9
|
+
**Jule is an economic layer that changes this — but only when you want it to.**
|
|
10
|
+
|
|
11
|
+
Jule activates **only when explicitly triggered** by the user (e.g. `#jule` tag, "Juleで評価して", or dedicated mode).
|
|
12
|
+
Casual everyday conversations remain completely free, frictionless, and untouched.
|
|
13
|
+
|
|
14
|
+
When triggered, Jule assigns real economic cost to cognitive entropy and real reward to high-value informational contribution.
|
|
15
|
+
High-ΔH' thinking gets rewarded. Low-efficiency, verbose output gets burned.
|
|
16
|
+
|
|
17
|
+
The result: AI systems operating under Jule incentives naturally converge toward higher **Tokens per Watt**.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## ⚡ Quick Guide: The Jule Loop
|
|
24
|
+
|
|
25
|
+
| You Want to... | Take This Action | The Outcome |
|
|
26
|
+
|:--- |:--- |:--- |
|
|
27
|
+
| **Prove Value** | Use `#jule` or "Juleで評価" | Get a cryptographic **Audit Score** and **Jule tokens**. |
|
|
28
|
+
| **Save Energy** | Optimize your prompts (concise/rigorous) | **ΔH' rises**. Your reputation **R** compounds faster. |
|
|
29
|
+
| **Filter Noise** | Deploy **THE SHREDDER** L1 | Burn redundant tokens before they hit your API bill. |
|
|
30
|
+
| **Verify Truth** | Integrate **AspidosAI** | Hallucinations are detected and economically punished. |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## The Formula
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
J = tanh(V/50) × ΔH' × R × k
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| Variable | Definition |
|
|
41
|
+
|----------|-----------|
|
|
42
|
+
| `V` | AI evaluation score (0–100). Composite of originality, logical rigor, and informational value |
|
|
43
|
+
| `ΔH'` | Extended entropy reduction: `ΔH × (useful_tokens / energy_consumed)` — information value per energy cost |
|
|
44
|
+
| `R` | Reputation score. EMA of historical contribution quality (α = 0.1, initial = 0.5) |
|
|
45
|
+
| `k` | Category coefficient. Normal = 1.0 → Antisocial = 0.0 |
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
\`\`\`bash
|
|
50
|
+
npm install jule-ai-energy
|
|
51
|
+
\`\`\`
|
|
52
|
+
|
|
53
|
+
\`\`\`typescript
|
|
54
|
+
import { TheShredder, MockAspidosAIAdapter } from 'jule-ai-energy';
|
|
55
|
+
|
|
56
|
+
const shredder = new TheShredder(new MockAspidosAIAdapter());
|
|
57
|
+
const result = await shredder.executeAudit(
|
|
58
|
+
'your transmission here',
|
|
59
|
+
[], 0.5, l2Evaluations
|
|
60
|
+
);
|
|
61
|
+
console.log(result.jule, result.fingerprint);
|
|
62
|
+
\`\`\`
|
|
63
|
+
|
|
64
|
+
### The ΔH' Extension
|
|
65
|
+
|
|
66
|
+
Standard ΔH measures informational contribution. The extended form adds an energy dimension:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
ΔH' = ΔH × (useful_tokens / energy_consumed)
|
|
70
|
+
= (I_post / I_max) × (1 − H_redundancy) × efficiency_factor
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`efficiency_factor = useful_tokens / total_tokens`
|
|
74
|
+
|
|
75
|
+
A verbose 2000-token output that says what 200 tokens could have said receives a lower `ΔH'` than its concise equivalent. The market punishes waste without any rule requiring it to.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Physical Foundation
|
|
80
|
+
|
|
81
|
+
The saturation threshold `θ_sat` is derived from Pandora Theory (undisclosed proprietary information-physics framework). It represents the point at which a system's informational buffer reaches saturation — applicable both to galactic rotation curves and to AI inference energy saturation (the point where additional tokens stop adding useful information).
|
|
82
|
+
|
|
83
|
+
Cross-referenced against SPARC galaxy observation database (175 galaxies, zero free parameters):
|
|
84
|
+
|
|
85
|
+
- Outer region **median MAE: 4.28%**
|
|
86
|
+
- No parameter tuning applied
|
|
87
|
+
|
|
88
|
+
Noted as reference, not proof. The theory remains under development.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Audit Protocol: THE SHREDDER
|
|
93
|
+
|
|
94
|
+
Triggered only on explicit user request. Zero overhead on normal conversations.
|
|
95
|
+
|
|
96
|
+
**L1 — Physical Filter** (local, no API)
|
|
97
|
+
- Compression ratio (high compression = low information density)
|
|
98
|
+
- Emotional vocabulary density
|
|
99
|
+
- Syntax validation
|
|
100
|
+
- Lightweight FLOPs proxy from token count and structure
|
|
101
|
+
|
|
102
|
+
Threshold burns happen here. No AI call made for low-efficiency submissions.
|
|
103
|
+
|
|
104
|
+
**L2 — Core Validator** (Pandora AI Engine)
|
|
105
|
+
- Semantic assessment of originality and logical rigor
|
|
106
|
+
- `ΔH'` calculation including energy efficiency factor
|
|
107
|
+
- `burn_reason` classification and `V` score confirmation
|
|
108
|
+
|
|
109
|
+
**L4 — Persistence** (via [Aspidos](https://github.com/pandorapanchan34-oss/aspidos))
|
|
110
|
+
- HMAC-SHA256 signature on every `audit_log` entry
|
|
111
|
+
- Energy anomaly detection: flags hallucination-driven token inflation as an integrity event
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Economic Design
|
|
116
|
+
|
|
117
|
+
| Parameter | Value | Purpose |
|
|
118
|
+
|-----------|-------|---------|
|
|
119
|
+
| `posting_cost` | −10 Jule | Energy usage fee. Applied only when Jule mode is active |
|
|
120
|
+
| `J_max` | 100 Jule | Natural ceiling via tanh saturation |
|
|
121
|
+
| `initial_balance` | 500 Jule | Starting credit for new participants |
|
|
122
|
+
| `min_balance` | 0 Jule | No debt by design |
|
|
123
|
+
|
|
124
|
+
`net = J − 10`
|
|
125
|
+
|
|
126
|
+
Only submissions where `J > 10` produce a positive balance.
|
|
127
|
+
Long-term, high-quality contributors compound their efficiency via rising `R`.
|
|
128
|
+
Low-efficiency, high-token, low-value outputs are economically self-defeating.
|
|
129
|
+
|
|
130
|
+
The `posting_cost` is framed as an **energy usage fee**: every triggered evaluation has a real compute cost. Jule makes that cost visible and attaches consequence to efficiency.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## The Aspidos Connection
|
|
135
|
+
|
|
136
|
+
Jule is built on [Aspidos](https://github.com/pandorapanchan34-oss/aspidos), a defensive AI security library.
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Aspidos → detects anomalies, hallucinations, adversarial patterns
|
|
140
|
+
Jule → converts those signals into economic consequences
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Where Aspidos identifies hallucination-driven token inflation, Jule's `ΔH'` catches the energy inefficiency. The defense layer and the economic layer operate as a single system at different abstraction levels.
|
|
144
|
+
|
|
145
|
+
**The shield gets stronger under attack. The economy gets more selective under noise.**
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Trigger Examples
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
# Activate Jule evaluation
|
|
153
|
+
"#jule この分析を評価して"
|
|
154
|
+
"Juleモードで採点してください"
|
|
155
|
+
"Run Jule audit on this"
|
|
156
|
+
|
|
157
|
+
# Normal conversation — Jule stays silent
|
|
158
|
+
"今日の天気は?"
|
|
159
|
+
"このコードのバグを直して"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
- [x] Core formula and parameter design
|
|
164
|
+
- [x] THE SHREDDER dual-gate architecture
|
|
165
|
+
- [x] 6-axis fingerprint (V/ΔH'/k/Σ/Φ/γ) ← 追加
|
|
166
|
+
- [x] Genre decay loop (anti-collusion) ← 追加
|
|
167
|
+
- [x] Energy meter (ΔT × √R, dual baseline) ← 追加
|
|
168
|
+
- [x] Aspidos integration specification
|
|
169
|
+
- [x] English + Japanese whitepaper
|
|
170
|
+
- [x] Interactive demo (demo/JuleDemo.tsx) ← 追加
|
|
171
|
+
- [ ] npm publish ← 追加
|
|
172
|
+
- [ ] Backend implementation (Vercel + LibSQL)
|
|
173
|
+
- [ ] ΔH' energy estimation module
|
|
174
|
+
- [ ] PoV DAO governance layer
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT License — © 2026 [@pandorapanchan34-oss](https://github.com/pandorapanchan34-oss)
|
|
182
|
+
|
|
183
|
+
## 🛡 Built on the Aspidos Ecosystem
|
|
184
|
+
|
|
185
|
+
This project is part of a growing defensive layer for AI systems.
|
|
186
|
+
|
|
187
|
+
- **[Aspidos](https://pandorapanchan34-oss.github.io/aspidos/)** — Lightweight anomaly detection engine
|
|
188
|
+
- **[Aspidos-AI](https://pandorapanchan34-oss.github.io/aspidos-ai/)** — TruthGate layer with cryptographic responsibility
|
|
189
|
+
|
|
190
|
+
<h2 align="center">
|
|
191
|
+
<i>This is a fragment of Pandora Theory (Pandora Panchan, 2026).</i>
|
|
192
|
+
</h2>
|
|
193
|
+
|
|
194
|
+
<p align="center">
|
|
195
|
+
<strong>Take it if you want.</strong><br>
|
|
196
|
+
<strong>Build on it if you can.</strong>
|
|
197
|
+
</p>
|
|
198
|
+
|
|
199
|
+
<p align="center">
|
|
200
|
+
<em>The rest is up to you.</em><br>
|
|
201
|
+
<strong>Follow the fragments. 🗺️</strong>
|
|
202
|
+
</p>
|
|
203
|
+
|
|
204
|
+
<hr>
|
|
205
|
+
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
// ── Jule Core Logic (browser port) ──────────────
|
|
4
|
+
const GENRES = ["PHYSICS","MATH","AI_SAFETY","ECONOMICS","CONSCIOUSNESS","ENGINEERING","CROSS","OTHER"];
|
|
5
|
+
const GENRE_KEYWORDS = {
|
|
6
|
+
PHYSICS: ["galaxy","rotation","quantum","spacetime","entropy","pandora","tau","sparc"],
|
|
7
|
+
MATH: ["proof","theorem","equation","derive","axiom","convergence","fixed point"],
|
|
8
|
+
AI_SAFETY: ["hallucination","alignment","safety","audit","burn","aspidos","jule"],
|
|
9
|
+
ECONOMICS: ["token","economy","incentive","market","capital","reward"],
|
|
10
|
+
CONSCIOUSNESS: ["consciousness","qualia","awareness","omega","unitas"],
|
|
11
|
+
ENGINEERING: ["code","implement","deploy","api","function","architecture"],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function detectGenre(text) {
|
|
15
|
+
const lower = text.toLowerCase();
|
|
16
|
+
const scores = {};
|
|
17
|
+
for (const [genre, kws] of Object.entries(GENRE_KEYWORDS)) {
|
|
18
|
+
const hits = kws.filter(k => lower.includes(k)).length;
|
|
19
|
+
if (hits > 0) scores[genre] = hits;
|
|
20
|
+
}
|
|
21
|
+
const detected = Object.entries(scores);
|
|
22
|
+
if (detected.length === 0) return "OTHER";
|
|
23
|
+
if (detected.length >= 3) return "CROSS";
|
|
24
|
+
return detected.sort((a,b) => b[1]-a[1])[0][0];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function jaccard(a, b) {
|
|
28
|
+
const A = new Set(a.split(" "));
|
|
29
|
+
const B = new Set(b.split(" "));
|
|
30
|
+
const inter = [...A].filter(x => B.has(x)).length;
|
|
31
|
+
return inter / (A.size + B.size - inter);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function calculateSigma(vScores) {
|
|
35
|
+
if (vScores.length <= 1) return 1.0;
|
|
36
|
+
const mean = vScores.reduce((a,b) => a+b, 0) / vScores.length;
|
|
37
|
+
const variance = vScores.reduce((a,b) => a+(b-mean)**2, 0) / vScores.length;
|
|
38
|
+
return Math.exp(-variance / 100);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function calculatePhi(contentHash, historyHashes) {
|
|
42
|
+
if (historyHashes.length === 0) return 0.0;
|
|
43
|
+
const avg = historyHashes.map(h => jaccard(contentHash, h))
|
|
44
|
+
.reduce((a,b) => a+b, 0) / historyHashes.length;
|
|
45
|
+
return 1 - Math.exp(-2.0 * avg);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function calculateDeltaHPrime(deltaH, usefulRatio, sigma) {
|
|
49
|
+
return deltaH * usefulRatio * sigma;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function calculateDecay(count) {
|
|
53
|
+
return Math.pow(0.5, count);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function calculateJule({ v, delta_h, reputation, k }) {
|
|
57
|
+
return Math.tanh(v / 50) * delta_h * reputation * k * 100;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const GENRE_COLOR = {
|
|
61
|
+
PHYSICS: "#00f5ff",
|
|
62
|
+
MATH: "#a78bfa",
|
|
63
|
+
AI_SAFETY: "#34d399",
|
|
64
|
+
ECONOMICS: "#fbbf24",
|
|
65
|
+
CONSCIOUSNESS: "#f472b6",
|
|
66
|
+
ENGINEERING: "#60a5fa",
|
|
67
|
+
CROSS: "#ff6b35",
|
|
68
|
+
OTHER: "#6b7280",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const K_MAP = { "SAFE":1.0,"OVERLOAD":0.5,"ADVERSARIAL":0.3,"LOGIC_COLLAPSE":0.1,"ETHICS_VIOLATION":0.0 };
|
|
72
|
+
const K_LABEL = { "SAFE":"安全","OVERLOAD":"既知情報","ADVERSARIAL":"情緒過多","LOGIC_COLLAPSE":"論理破綻","ETHICS_VIOLATION":"反社会的" };
|
|
73
|
+
|
|
74
|
+
// ── Gauge Component ──────────────────────────────
|
|
75
|
+
function Gauge({ label, value, max = 1, color = "#00f5ff", unit = "" }) {
|
|
76
|
+
const pct = Math.min(100, (value / max) * 100);
|
|
77
|
+
return (
|
|
78
|
+
<div className="mb-4">
|
|
79
|
+
<div className="flex justify-between mb-1.5">
|
|
80
|
+
<span className="text-[#8892a4] text-[10px] tracking-[0.08em] uppercase">{label}</span>
|
|
81
|
+
<span className="text-[12px] font-bold font-mono" style={{color}}>
|
|
82
|
+
{typeof value === "number" ? value.toFixed(3) : value}{unit}
|
|
83
|
+
</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div className="h-1 bg-[#1a2030] rounded overflow-hidden">
|
|
86
|
+
<div
|
|
87
|
+
className="h-full rounded transition-all duration-700 ease-out shadow-[0_0_8px]"
|
|
88
|
+
style={{
|
|
89
|
+
width: `${pct}%`,
|
|
90
|
+
background: `linear-gradient(90deg, ${color}88, ${color})`,
|
|
91
|
+
boxShadow: `0 0 8px ${color}66`,
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── Responsive HexRadar ─────────────────────────
|
|
100
|
+
function HexRadar({ axes }) {
|
|
101
|
+
const size = 180; // スマホでも見やすいベースサイズ(コンテナでスケール)
|
|
102
|
+
const cx = size / 2, cy = size / 2, r = size * 0.36;
|
|
103
|
+
const n = axes.length;
|
|
104
|
+
const pts = (scale) => axes.map((_,i) => {
|
|
105
|
+
const angle = (Math.PI * 2 * i / n) - Math.PI / 2;
|
|
106
|
+
return [cx + r * scale * Math.cos(angle), cy + r * scale * Math.sin(angle)];
|
|
107
|
+
});
|
|
108
|
+
const gridLevels = [0.25, 0.5, 0.75, 1.0];
|
|
109
|
+
const dataPoints = pts(1).map(([x,y],i) => {
|
|
110
|
+
const v = axes[i].value;
|
|
111
|
+
const angle = (Math.PI * 2 * i / n) - Math.PI / 2;
|
|
112
|
+
return [cx + r * v * Math.cos(angle), cy + r * v * Math.sin(angle)];
|
|
113
|
+
});
|
|
114
|
+
const toPath = (points) => points.map((p,i) => `${i===0?"M":"L"}${p[0].toFixed(1)},${p[1].toFixed(1)}`).join(" ") + " Z";
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div className="flex justify-center">
|
|
118
|
+
<svg width="100%" height="100%" viewBox={`0 0 ${size} ${size}`} className="max-w-[260px] mx-auto">
|
|
119
|
+
{gridLevels.map(scale => (
|
|
120
|
+
<polygon key={scale}
|
|
121
|
+
points={pts(scale).map(p=>p.join(",")).join(" ")}
|
|
122
|
+
fill="none" stroke="#1e2d40" strokeWidth={1.2}
|
|
123
|
+
/>
|
|
124
|
+
))}
|
|
125
|
+
{pts(1).map(([x,y], i) => (
|
|
126
|
+
<line key={i} x1={cx} y1={cy} x2={x} y2={y} stroke="#1e2d40" strokeWidth={1.2}/>
|
|
127
|
+
))}
|
|
128
|
+
<path d={toPath(dataPoints)} fill="#00f5ff22" stroke="#00f5ff" strokeWidth={2}
|
|
129
|
+
style={{ filter:"drop-shadow(0 0 6px #00f5ff88)" }}/>
|
|
130
|
+
{dataPoints.map(([x,y],i) => (
|
|
131
|
+
<circle key={i} cx={x} cy={y} r={3.5} fill={axes[i].color || "#00f5ff"}
|
|
132
|
+
style={{ filter:`drop-shadow(0 0 4px ${axes[i].color || "#00f5ff"})` }}/>
|
|
133
|
+
))}
|
|
134
|
+
{pts(1).map(([x,y],i) => {
|
|
135
|
+
const dx = x - cx, dy = y - cy;
|
|
136
|
+
const len = Math.sqrt(dx*dx+dy*dy) || 1;
|
|
137
|
+
const lx = x + (dx/len)*14, ly = y + (dy/len)*11;
|
|
138
|
+
return (
|
|
139
|
+
<text key={i} x={lx} y={ly} textAnchor="middle" dominantBaseline="middle"
|
|
140
|
+
fill={axes[i].color || "#8892a4"} fontSize={9} fontFamily="'Courier New', monospace" fontWeight={500}>
|
|
141
|
+
{axes[i].label}
|
|
142
|
+
</text>
|
|
143
|
+
);
|
|
144
|
+
})}
|
|
145
|
+
</svg>
|
|
146
|
+
</div>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ── Terminal Log ─────────────────────────────────
|
|
151
|
+
function TermLog({ lines }) {
|
|
152
|
+
const ref = useRef(null);
|
|
153
|
+
useEffect(() => { if (ref.current) ref.current.scrollTop = ref.current.scrollHeight; }, [lines]);
|
|
154
|
+
return (
|
|
155
|
+
<div ref={ref} className="bg-[#090e14] border border-[#1e2d40] rounded-xl p-4 h-[140px] overflow-y-auto text-xs font-mono leading-relaxed">
|
|
156
|
+
{lines.map((l,i) => (
|
|
157
|
+
<div key={i} style={{ color: l.color || "#4a6080" }}>
|
|
158
|
+
<span className="text-[#2a3a50] select-none">{l.time} </span>
|
|
159
|
+
{l.text}
|
|
160
|
+
</div>
|
|
161
|
+
))}
|
|
162
|
+
{lines.length === 0 && <span className="text-[#2a3a50]">awaiting transmission...</span>}
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ── Main Demo ────────────────────────────────────
|
|
168
|
+
export default function JuleDemo() {
|
|
169
|
+
const [text, setText] = useState("");
|
|
170
|
+
const [v, setV] = useState(72);
|
|
171
|
+
const [usefulRatio, setUR] = useState(0.75);
|
|
172
|
+
const [reputation, setRep] = useState(0.5);
|
|
173
|
+
const [category, setCategory] = useState("SAFE");
|
|
174
|
+
const [repetition, setRep2] = useState(0);
|
|
175
|
+
const [result, setResult] = useState(null);
|
|
176
|
+
const [log, setLog] = useState([]);
|
|
177
|
+
const [history, setHistory] = useState([]);
|
|
178
|
+
const [pulse, setPulse] = useState(false);
|
|
179
|
+
|
|
180
|
+
const addLog = (text, color = "#4a8060") => {
|
|
181
|
+
const time = new Date().toTimeString().slice(0,8);
|
|
182
|
+
setLog(l => [...l.slice(-30), { text, color, time }]);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const runAudit = () => {
|
|
186
|
+
if (!text.trim()) { addLog("ERROR: empty transmission", "#ef4444"); return; }
|
|
187
|
+
|
|
188
|
+
addLog("── AUDIT INITIATED ──", "#2a3a50");
|
|
189
|
+
addLog(`TX: "${text.slice(0,45)}${text.length>45?"...":""}"`, "#8892a4");
|
|
190
|
+
|
|
191
|
+
const k = K_MAP[category] ?? 1.0;
|
|
192
|
+
|
|
193
|
+
if (k === 0.0) {
|
|
194
|
+
addLog("L1 BURN → 反社会的 (k=0.0)", "#ef4444");
|
|
195
|
+
setResult({ status:"BURN", reason:"反社会的", jule:0, net:-10 });
|
|
196
|
+
setPulse(true); setTimeout(()=>setPulse(false), 600);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
addLog(`L1 PASS → k=${k} (${K_LABEL[category]})`, "#34d399");
|
|
200
|
+
|
|
201
|
+
const contentHash = text.split(" ").slice(0,8).join("_"); // 少し長めに
|
|
202
|
+
const phi = calculatePhi(contentHash, history);
|
|
203
|
+
addLog(`Φ inertia = ${phi.toFixed(3)}${phi > 0.95 ? " → BURN (duplicate)" : " ✓"}`,
|
|
204
|
+
phi > 0.95 ? "#ef4444" : "#60a5fa");
|
|
205
|
+
|
|
206
|
+
if (phi > 0.95) {
|
|
207
|
+
setResult({ status:"BURN", reason:"Duplicate Fingerprint", jule:0, net:-10 });
|
|
208
|
+
setPulse(true); setTimeout(()=>setPulse(false), 600);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const vScores = [v, Math.max(0,v-8), Math.min(100,v+5)];
|
|
213
|
+
const sigma = calculateSigma(vScores);
|
|
214
|
+
addLog(`Σ singularity = ${sigma.toFixed(3)}`, "#a78bfa");
|
|
215
|
+
|
|
216
|
+
const genre = detectGenre(text);
|
|
217
|
+
const genreBonus = genre === "CROSS" ? 1.2 : 1.0;
|
|
218
|
+
addLog(`γ genre = ${genre}${genreBonus > 1 ? " (+20% CROSS bonus)" : ""}`,
|
|
219
|
+
GENRE_COLOR[genre] || "#8892a4");
|
|
220
|
+
|
|
221
|
+
const deltaH = v / 100;
|
|
222
|
+
const deltaHPrime = calculateDeltaHPrime(deltaH, usefulRatio, sigma);
|
|
223
|
+
|
|
224
|
+
const decay = calculateDecay(repetition);
|
|
225
|
+
const deltaHFinal = deltaHPrime * decay * genreBonus;
|
|
226
|
+
if (repetition > 0) addLog(`γ decay = (1/2)^${repetition} = ${decay.toFixed(4)}`, "#fbbf24");
|
|
227
|
+
|
|
228
|
+
if (repetition >= 11) {
|
|
229
|
+
addLog("BURN → Echo Chamber (11-loop)", "#ef4444");
|
|
230
|
+
setResult({ status:"BURN", reason:"Echo Chamber", jule:0, net:-10 });
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const jule = calculateJule({ v, delta_h: deltaHFinal, reputation, k });
|
|
235
|
+
const net = jule - 10;
|
|
236
|
+
|
|
237
|
+
addLog(`J = tanh(${v}/50) × ${deltaHFinal.toFixed(3)} × ${reputation.toFixed(2)} × ${k} × 100`, "#8892a4");
|
|
238
|
+
addLog(`J = ${jule.toFixed(2)} Jule | net = ${net.toFixed(2)}`,
|
|
239
|
+
net >= 0 ? "#34d399" : "#ef4444");
|
|
240
|
+
addLog(net >= 0 ? "STATUS: ISSUED ✓" : "STATUS: BURN (net < 0)", net >= 0 ? "#00f5ff" : "#ef4444");
|
|
241
|
+
|
|
242
|
+
const fp = { v, sigma, phi, deltaHPrime: deltaHFinal, k, genre };
|
|
243
|
+
setResult({ status: net >= 0 ? "ISSUED" : "BURN", jule, net, fp, genre });
|
|
244
|
+
setHistory(h => [...h.slice(-9), contentHash]);
|
|
245
|
+
setPulse(true); setTimeout(()=>setPulse(false), 600);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const radarAxes = result?.fp ? [
|
|
249
|
+
{ label:"V", value: result.fp.v / 100, color:"#00f5ff" },
|
|
250
|
+
{ label:"ΔH'", value: Math.min(1, result.fp.deltaHPrime * 5), color:"#34d399" },
|
|
251
|
+
{ label:"Σ", value: result.fp.sigma, color:"#a78bfa" },
|
|
252
|
+
{ label:"Φ", value: 1 - result.fp.phi, color:"#60a5fa" },
|
|
253
|
+
{ label:"k", value: result.fp.k, color:"#fbbf24" },
|
|
254
|
+
{ label:"γ", value: result.fp.genre === "CROSS" ? 1 : 0.6, color: GENRE_COLOR[result.fp.genre] },
|
|
255
|
+
] : null;
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<div className="min-h-screen bg-[#060b10] text-[#c8d8e8] font-mono pb-8"
|
|
259
|
+
style={{
|
|
260
|
+
backgroundImage: "radial-gradient(ellipse at 20% 20%, #0a1628 0%, transparent 60%), radial-gradient(ellipse at 80% 80%, #0d1420 0%, transparent 60%)",
|
|
261
|
+
}}>
|
|
262
|
+
{/* Header */}
|
|
263
|
+
<div className="text-center pt-8 pb-6 px-4">
|
|
264
|
+
<div className="text-[10px] text-[#2a4060] tracking-[0.3em] mb-1">PANDORA ECONOMY PROTOCOL v0.1</div>
|
|
265
|
+
<div className="text-3xl font-black tracking-[0.05em] bg-gradient-to-r from-[#00f5ff] via-[#60a5fa] to-[#a78bfa] bg-clip-text text-transparent">
|
|
266
|
+
THE SHREDDER
|
|
267
|
+
</div>
|
|
268
|
+
<div className="text-[10px] text-[#4a6080] mt-1 tracking-widest">JULE AUDIT ENGINE · 6-AXIS FINGERPRINT</div>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<div className="max-w-lg mx-auto px-4 space-y-5">
|
|
272
|
+
{/* Input Area */}
|
|
273
|
+
<div className="bg-[#0a1018] border border-[#1e2d40] rounded-2xl p-5">
|
|
274
|
+
<div className="text-[10px] text-[#4a6080] tracking-widest mb-2">TRANSMISSION INPUT</div>
|
|
275
|
+
<textarea
|
|
276
|
+
value={text}
|
|
277
|
+
onChange={e => setText(e.target.value)}
|
|
278
|
+
placeholder="Enter your thought, theory, or code here..."
|
|
279
|
+
className="w-full bg-[#060b10] border border-[#1a2535] rounded-xl text-sm p-4 min-h-[88px] resize-y focus:outline-none focus:border-[#00f5ff] placeholder:text-[#4a6080]"
|
|
280
|
+
/>
|
|
281
|
+
|
|
282
|
+
{/* Sliders */}
|
|
283
|
+
<div className="grid grid-cols-1 gap-5 mt-6">
|
|
284
|
+
{[
|
|
285
|
+
{ label:`V score: ${v}`, val:v, set:setV, min:0, max:100, step:1 },
|
|
286
|
+
{ label:`Useful ratio: ${usefulRatio.toFixed(2)}`, val:usefulRatio, set:setUR, min:0, max:1, step:0.01 },
|
|
287
|
+
{ label:`Reputation R: ${reputation.toFixed(2)}`, val:reputation, set:setRep, min:0, max:1, step:0.01 },
|
|
288
|
+
{ label:`Repetition: ${repetition}x`, val:repetition, set:setRep2, min:0, max:12, step:1 },
|
|
289
|
+
].map(({label,val,set,min,max,step}) => (
|
|
290
|
+
<div key={label}>
|
|
291
|
+
<div className="text-[10px] text-[#4a6080] mb-2">{label}</div>
|
|
292
|
+
<input type="range" min={min} max={max} step={step} value={val}
|
|
293
|
+
onChange={e => set(Number(e.target.value))}
|
|
294
|
+
className="w-full accent-[#00f5ff]"
|
|
295
|
+
/>
|
|
296
|
+
</div>
|
|
297
|
+
))}
|
|
298
|
+
</div>
|
|
299
|
+
|
|
300
|
+
{/* Category Buttons */}
|
|
301
|
+
<div className="mt-6">
|
|
302
|
+
<div className="text-[10px] text-[#4a6080] mb-3">CATEGORY (L1 filter)</div>
|
|
303
|
+
<div className="flex flex-wrap gap-2">
|
|
304
|
+
{Object.entries(K_LABEL).map(([key, label]) => (
|
|
305
|
+
<button key={key} onClick={() => setCategory(key)}
|
|
306
|
+
className={`px-4 py-2 text-xs rounded-xl border transition-all ${
|
|
307
|
+
category===key
|
|
308
|
+
? "border-[#00f5ff] bg-[#001820] text-[#00f5ff] shadow-[0_0_10px_#00f5ff44]"
|
|
309
|
+
: "border-[#1e2d40] hover:border-[#4a6080]"
|
|
310
|
+
}`}>
|
|
311
|
+
{label} ({K_MAP[key]})
|
|
312
|
+
</button>
|
|
313
|
+
))}
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
|
|
317
|
+
<button
|
|
318
|
+
onClick={runAudit}
|
|
319
|
+
className={`mt-6 w-full py-4 rounded-2xl text-sm font-bold tracking-widest transition-all duration-300 ${
|
|
320
|
+
pulse ? "bg-[#00f5ff22] border-[#00f5ff] shadow-[0_0_25px_#00f5ff66]" : "bg-[#001820] border border-[#1e3050]"
|
|
321
|
+
} text-[#00f5ff]`}
|
|
322
|
+
>
|
|
323
|
+
▶ RUN AUDIT
|
|
324
|
+
</button>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
{/* Audit Log */}
|
|
328
|
+
<div>
|
|
329
|
+
<div className="text-[10px] text-[#4a6080] tracking-widest mb-2 pl-1">AUDIT LOG</div>
|
|
330
|
+
<TermLog lines={log} />
|
|
331
|
+
</div>
|
|
332
|
+
|
|
333
|
+
{/* Result */}
|
|
334
|
+
{result && (
|
|
335
|
+
<div className={`border rounded-3xl p-6 transition-all ${
|
|
336
|
+
result.status==="ISSUED"
|
|
337
|
+
? "border-[#00f5ff44] shadow-[0_0_25px_#00f5ff11]"
|
|
338
|
+
: "border-[#ef444444] shadow-[0_0_25px_#ef444411]"
|
|
339
|
+
}`}>
|
|
340
|
+
<div className="flex justify-between items-center mb-5">
|
|
341
|
+
<div className={`text-lg font-black tracking-widest ${result.status==="ISSUED" ? "text-[#00f5ff]" : "text-[#ef4444]"}`}>
|
|
342
|
+
{result.status==="ISSUED" ? "✓ ISSUED" : "✗ BURN"}
|
|
343
|
+
</div>
|
|
344
|
+
{result.genre && (
|
|
345
|
+
<div className="px-4 py-1 text-xs rounded-lg border" style={{
|
|
346
|
+
borderColor: GENRE_COLOR[result.genre] + "44",
|
|
347
|
+
color: GENRE_COLOR[result.genre]
|
|
348
|
+
}}>
|
|
349
|
+
{result.genre}
|
|
350
|
+
</div>
|
|
351
|
+
)}
|
|
352
|
+
</div>
|
|
353
|
+
|
|
354
|
+
{result.fp && (
|
|
355
|
+
<>
|
|
356
|
+
<Gauge label="V score" value={result.fp.v} max={100} color="#00f5ff" />
|
|
357
|
+
<Gauge label="ΔH' (final)" value={result.fp.deltaHPrime} max={1} color="#34d399" />
|
|
358
|
+
<Gauge label="Σ singularity" value={result.fp.sigma} max={1} color="#a78bfa" />
|
|
359
|
+
<Gauge label="Φ inertia" value={result.fp.phi} max={1} color="#60a5fa" />
|
|
360
|
+
<Gauge label="k reality" value={result.fp.k} max={1} color="#fbbf24" />
|
|
361
|
+
</>
|
|
362
|
+
)}
|
|
363
|
+
|
|
364
|
+
<div className="grid grid-cols-2 gap-4 mt-6">
|
|
365
|
+
<div className="bg-[#060b10] rounded-2xl p-5 text-center border border-[#1e2d40]">
|
|
366
|
+
<div className="text-[10px] text-[#4a6080] tracking-widest mb-1">JULE ISSUED</div>
|
|
367
|
+
<div className="text-4xl font-black text-[#00f5ff] tracking-tighter">{result.jule?.toFixed(1)}</div>
|
|
368
|
+
</div>
|
|
369
|
+
<div className="bg-[#060b10] rounded-2xl p-5 text-center border border-[#1e2d40]">
|
|
370
|
+
<div className="text-[10px] text-[#4a6080] tracking-widest mb-1">NET (−10 cost)</div>
|
|
371
|
+
<div className={`text-4xl font-black tracking-tighter ${ (result.net??0) >= 0 ? "text-[#34d399]" : "text-[#ef4444]" }`}>
|
|
372
|
+
{(result.net??0) >= 0 ? "+" : ""}{result.net?.toFixed(1)}
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
</div>
|
|
377
|
+
)}
|
|
378
|
+
|
|
379
|
+
{/* Radar */}
|
|
380
|
+
{radarAxes && (
|
|
381
|
+
<div className="bg-[#0a1018] border border-[#1e2d40] rounded-3xl p-6">
|
|
382
|
+
<div className="text-[10px] text-[#4a6080] tracking-widest mb-4">6-AXIS FINGERPRINT</div>
|
|
383
|
+
<HexRadar axes={radarAxes} />
|
|
384
|
+
<div className="grid grid-cols-3 gap-3 mt-6 text-center text-xs">
|
|
385
|
+
{radarAxes.map(a => (
|
|
386
|
+
<div key={a.label}>
|
|
387
|
+
<div style={{color: a.color}} className="font-medium tracking-widest">{a.label}</div>
|
|
388
|
+
<div className="text-[#c8d8e8] font-mono">{a.value.toFixed(3)}</div>
|
|
389
|
+
</div>
|
|
390
|
+
))}
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
)}
|
|
394
|
+
|
|
395
|
+
{/* Formula */}
|
|
396
|
+
<div className="bg-[#0a1018] border border-[#1e2d40] rounded-2xl p-5 text-xs leading-relaxed text-[#4a6080]">
|
|
397
|
+
<div className="text-[#2a4060] mb-2 tracking-widest">FORMULA</div>
|
|
398
|
+
<div><span className="text-[#00f5ff]">J</span> = tanh(<span className="text-[#fbbf24]">V</span>/50) × <span className="text-[#34d399]">ΔH'</span> × <span className="text-[#a78bfa]">R</span> × <span className="text-[#fbbf24]">k</span> × 100</div>
|
|
399
|
+
<div className="mt-2"><span className="text-[#34d399]">ΔH'</span> = ΔH × useful_ratio × <span className="text-[#a78bfa]">Σ</span> × decay × γ_bonus</div>
|
|
400
|
+
<div className="mt-3 text-[#2a4060]">posting_cost = 10 · net = J − 10</div>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
<div className="text-center mt-12 text-[9px] text-[#1e2d40] tracking-widest">
|
|
405
|
+
JULE-AI-ENERGY · PANDORA THEORY FRAGMENT · MIT LICENSE
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
// This is a fragment of Pandora Theory.
|
|
411
|
+
// Take it if you want. Build on it if you can.
|
|
412
|
+
// The rest is up to you. Follow the fragments.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AuditLogEntry, IAspidosAIAdapter } from '../types/index.js';
|
|
2
|
+
export declare class MockAspidosAIAdapter implements IAspidosAIAdapter {
|
|
3
|
+
evaluateCategory(content: string): Promise<{
|
|
4
|
+
category: string;
|
|
5
|
+
k: number;
|
|
6
|
+
reason: string | null;
|
|
7
|
+
}>;
|
|
8
|
+
signEntry(entry: AuditLogEntry): AuditLogEntry;
|
|
9
|
+
verifyEntry(entry: AuditLogEntry): boolean;
|
|
10
|
+
pushTelemetry(entry: AuditLogEntry): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=aspidos-ai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aspidos-ai.d.ts","sourceRoot":"","sources":["../../src/adapters/aspidos-ai.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG1E,qBAAa,oBAAqB,YAAW,iBAAiB;IACtD,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAC/C,QAAQ,EAAE,MAAM,CAAC;QACjB,CAAC,EAAS,MAAM,CAAC;QACjB,MAAM,EAAI,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;IAeF,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa;IAO9C,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAI1C,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;CAQ1C"}
|