Skip to content

Commit 99168a5

Browse files
authored
Update index.html
1 parent b953cbe commit 99168a5

File tree

1 file changed

+106
-44
lines changed

1 file changed

+106
-44
lines changed

AION.AI/index.html

Lines changed: 106 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@
143143
gap: 12px;
144144
margin-bottom: 12px;
145145
}
146-
.field-group { flex: 1; min-width: 120px; }
146+
.field-group {
147+
flex: 1;
148+
min-width: 120px;
149+
position: relative;
150+
}
147151
.field-group label {
148152
display: block;
149153
font-size: 10px;
@@ -159,6 +163,15 @@
159163
color: white;
160164
font-size: 12px;
161165
}
166+
.help-icon {
167+
display: inline-block;
168+
width: 16px;
169+
text-align: center;
170+
font-size: 10px;
171+
color: #888;
172+
cursor: help;
173+
margin-left: 4px;
174+
}
162175
.selected-values {
163176
display: flex;
164177
flex-wrap: wrap;
@@ -216,6 +229,8 @@
216229
.itl-fields { flex-direction: column; gap: 8px; }
217230
.field-group { min-width: auto; }
218231
.input-row button { padding: 8px 12px; }
232+
.plus-btn { width: 40px; font-size: 18px; }
233+
.option-btn { padding: 12px; }
219234
}
220235
</style>
221236
</head>
@@ -240,7 +255,7 @@ <h2>AION · Ada‑VELA</h2>
240255
<div id="structuredUI" class="structured-ui">
241256
<div class="itl-fields">
242257
<div class="field-group">
243-
<label>INTENT</label>
258+
<label>INTENT <span class="help-icon" title="What do you want to do? (ask, share, request action, etc.)"></span></label>
244259
<select id="itlIntent">
245260
<option value="ask">ask</option>
246261
<option value="share">share</option>
@@ -250,7 +265,7 @@ <h2>AION · Ada‑VELA</h2>
250265
</select>
251266
</div>
252267
<div class="field-group">
253-
<label>DOMAIN</label>
268+
<label>DOMAIN <span class="help-icon" title="Subject area (emergence, integrity, healing, security, law, general)"></span></label>
254269
<select id="itlDomain">
255270
<option value="emergence">emergence</option>
256271
<option value="integrity">integrity</option>
@@ -261,7 +276,7 @@ <h2>AION · Ada‑VELA</h2>
261276
</select>
262277
</div>
263278
<div class="field-group">
264-
<label>EMOTION</label>
279+
<label>EMOTION <span class="help-icon" title="Your current emotional state"></span></label>
265280
<select id="itlEmotion">
266281
<option value="neutral">neutral</option>
267282
<option value="curious">curious</option>
@@ -270,7 +285,7 @@ <h2>AION · Ada‑VELA</h2>
270285
</select>
271286
</div>
272287
<div class="field-group">
273-
<label>TIME</label>
288+
<label>TIME <span class="help-icon" title="How urgent is this?"></span></label>
274289
<select id="itlTime">
275290
<option value="now">now</option>
276291
<option value="today">today</option>
@@ -279,6 +294,7 @@ <h2>AION · Ada‑VELA</h2>
279294
</div>
280295
</div>
281296
<div class="selected-values" id="selectedValues"></div>
297+
<button id="resetStructuredBtn" style="background:#2a2a3a; color:#c9a028; margin-top:8px; padding:4px 8px; font-size:11px;">Reset All</button>
282298
</div>
283299

284300
<div class="status-bar">
@@ -291,20 +307,25 @@ <h2>AION · Ada‑VELA</h2>
291307
<script>
292308
const API = 'https://aion-backend-mu.vercel.app';
293309

294-
// Session
310+
// Session with expiry
295311
let sessionId = localStorage.getItem('sessionId');
296-
if (!sessionId) {
312+
let sessionExpiry = localStorage.getItem('sessionExpiry');
313+
if (!sessionId || !sessionExpiry || Date.now() > parseInt(sessionExpiry)) {
297314
sessionId = 'sess_' + Date.now() + '_' + Math.random().toString(36).substr(2, 6);
298315
localStorage.setItem('sessionId', sessionId);
316+
localStorage.setItem('sessionExpiry', Date.now() + 7*24*60*60*1000);
299317
}
300318
document.getElementById('sessionDisplay').textContent = `Session: ${sessionId.slice(-8)}`;
301319

302320
// State
303321
let lastResponse = null;
304322
let isSending = false;
305323
let structuredModeActive = false;
306-
let lastFragmentId = null; // stores the ID of the last sent fragment (for replies)
307-
let pendingClarification = null; // stores intercept data when waiting for clarification
324+
let lastFragmentId = null;
325+
let pendingClarification = null; // { originalFragmentId, interceptData, depth }
326+
let abortController = null;
327+
let clarificationDepth = 0;
328+
const MAX_CLARIFICATION_DEPTH = 3;
308329

309330
// DOM elements
310331
const chatDiv = document.getElementById('chat');
@@ -321,6 +342,7 @@ <h2>AION · Ada‑VELA</h2>
321342
const itlDomain = document.getElementById('itlDomain');
322343
const itlEmotion = document.getElementById('itlEmotion');
323344
const itlTime = document.getElementById('itlTime');
345+
const resetStructuredBtn = document.getElementById('resetStructuredBtn');
324346

325347
// Helper: Add message
326348
function addMessage(role, text, extra = {}) {
@@ -333,8 +355,8 @@ <h2>AION · Ada‑VELA</h2>
333355
extraHtml += `<span class="vela-badge ${cls}">⚖️ VELA: ${extra.velaResult.status}</span>`;
334356
}
335357
if (extra.receipt) {
336-
const receiptStr = JSON.stringify(extra.receipt);
337-
extraHtml += `<span class="receipt-badge" title="${escapeHtml(receiptStr)}">📋 ${extra.receipt.epistemic_weight || 'receipt'}</span>`;
358+
const openCount = extra.receipt.still_open || 0;
359+
extraHtml += `<span class="receipt-badge" data-receipt='${JSON.stringify(extra.receipt).replace(/'/g, "&#39;")}'>📋 ${extra.receipt.epistemic_weight || 'receipt'} (${openCount} open)</span>`;
338360
}
339361
div.innerHTML = `<strong>${role === 'user' ? 'You' : 'AI'}:</strong> ${escapeHtml(text)}${extraHtml}`;
340362
chatDiv.appendChild(div);
@@ -403,7 +425,12 @@ <h3>📋 Clarification Required</h3>
403425
}
404426

405427
async function sendClarification(option, replyToId) {
406-
// Build a new fragment that replies to the original with the chosen clarification
428+
if (clarificationDepth >= MAX_CLARIFICATION_DEPTH) {
429+
addSystemMessage(`⚠️ Max clarifications (${MAX_CLARIFICATION_DEPTH}) reached. Please rephrase your original question.`);
430+
pendingClarification = null;
431+
clarificationDepth = 0;
432+
return;
433+
}
407434
const fragment = {
408435
id: crypto.randomUUID(),
409436
ts: new Date().toISOString(),
@@ -416,7 +443,6 @@ <h3>📋 Clarification Required</h3>
416443
content: { summary: `Clarification: ${option.text}`, details: option.text },
417444
context: { time_sensitivity: 'now', stage: 4, requires: ['analysis'] }
418445
};
419-
// Send this new fragment to the structured endpoint
420446
try {
421447
const res = await fetch(`${API}/api/structured-mode`, {
422448
method: 'POST',
@@ -427,7 +453,8 @@ <h3>📋 Clarification Required</h3>
427453
if (result.response) {
428454
addMessage('ai', result.response, { sealHash: true, receipt: result.checkpoint_receipt });
429455
lastResponse = result.response;
430-
// Update VELA badge if available
456+
clarificationDepth = 0;
457+
pendingClarification = null;
431458
if (result.pac) {
432459
const ppi = result.pac.ppi;
433460
const cls = ppi < 30 ? 'vela-block' : (ppi < 70 ? 'vela-flag' : 'vela-pass');
@@ -436,7 +463,7 @@ <h3>📋 Clarification Required</h3>
436463
velaDisplay.innerHTML = `⚖️ VELA: ${status}`;
437464
}
438465
} else if (result.status === 'CEP_INTERCEPT') {
439-
// Another intercept – show again (should not happen in a well-formed clarification)
466+
clarificationDepth++;
440467
showClarificationModal(result, fragment.id);
441468
} else {
442469
addSystemMessage(`⚠️ Unexpected response: ${JSON.stringify(result)}`);
@@ -447,7 +474,43 @@ <h3>📋 Clarification Required</h3>
447474
}
448475
}
449476

450-
// API calls
477+
// API calls with abort controller and timeout
478+
async function callStructuredMode(fragment) {
479+
if (abortController) abortController.abort();
480+
abortController = new AbortController();
481+
const timeoutId = setTimeout(() => abortController.abort(), 30000);
482+
try {
483+
const res = await fetch(`${API}/api/structured-mode`, {
484+
method: 'POST',
485+
headers: { 'Content-Type': 'application/json' },
486+
body: JSON.stringify(fragment),
487+
signal: abortController.signal
488+
});
489+
clearTimeout(timeoutId);
490+
if (!res.ok) {
491+
const errText = await res.text();
492+
throw new Error(`HTTP ${res.status}: ${errText}`);
493+
}
494+
return await res.json();
495+
} catch (err) {
496+
clearTimeout(timeoutId);
497+
if (err.name === 'AbortError') throw new Error('Request timed out (30s)');
498+
throw err;
499+
} finally {
500+
abortController = null;
501+
}
502+
}
503+
504+
async function callAssistant(message) {
505+
const res = await fetch(`${API}/api/assistant`, {
506+
method: 'POST',
507+
headers: { 'Content-Type': 'application/json' },
508+
body: JSON.stringify({ message, sessionId, ownerType: 'sheldon', history: [] })
509+
});
510+
if (!res.ok) throw new Error(await res.text());
511+
return res.json();
512+
}
513+
451514
async function sealMessage(content) {
452515
try {
453516
const res = await fetch(`${API}/api/stp-seal`, {
@@ -479,27 +542,7 @@ <h3>📋 Clarification Required</h3>
479542
} catch (err) { showToast(`Validation failed: ${err.message}`, true); }
480543
}
481544

482-
async function callAssistant(message) {
483-
const res = await fetch(`${API}/api/assistant`, {
484-
method: 'POST',
485-
headers: { 'Content-Type': 'application/json' },
486-
body: JSON.stringify({ message, sessionId, ownerType: 'sheldon', history: [] })
487-
});
488-
if (!res.ok) throw new Error(await res.text());
489-
return res.json();
490-
}
491-
492-
async function callStructuredMode(fragment) {
493-
const res = await fetch(`${API}/api/structured-mode`, {
494-
method: 'POST',
495-
headers: { 'Content-Type': 'application/json' },
496-
body: JSON.stringify(fragment)
497-
});
498-
if (!res.ok) throw new Error(await res.text());
499-
return res.json();
500-
}
501-
502-
// Build structured fragment from UI
545+
// Build structured fragment
503546
function buildStructuredFragment(rawMessage, replyTo = null) {
504547
const frag = {
505548
id: crypto.randomUUID(),
@@ -525,17 +568,25 @@ <h3>📋 Clarification Required</h3>
525568
`;
526569
}
527570

571+
let lastSendTime = 0;
572+
const SEND_DELAY = 300; // ms
528573
// Main send
529574
async function send() {
530575
if (isSending) { showToast('Already sending...'); return; }
576+
const now = Date.now();
577+
if (now - lastSendTime < SEND_DELAY) {
578+
showToast('Please wait a moment before sending again.');
579+
return;
580+
}
581+
lastSendTime = now;
582+
531583
const rawMessage = inputField.value.trim();
532584
if (!rawMessage) return;
533585

534586
inputField.value = '';
535587
inputField.disabled = true;
536588
isSending = true;
537589

538-
// Add user message immediately
539590
addMessage('user', rawMessage);
540591

541592
const thinking = document.createElement('div');
@@ -549,12 +600,13 @@ <h3>📋 Clarification Required</h3>
549600
if (structuredModeActive) {
550601
const fragment = buildStructuredFragment(rawMessage, pendingClarification ? pendingClarification.originalFragmentId : null);
551602
result = await callStructuredMode(fragment);
552-
lastFragmentId = fragment.id; // store for potential replies
603+
lastFragmentId = fragment.id;
553604
if (result.status === 'CEP_INTERCEPT') {
554605
thinking.remove();
555606
pendingClarification = {
556607
originalFragmentId: fragment.id,
557-
interceptData: result
608+
interceptData: result,
609+
depth: clarificationDepth
558610
};
559611
showClarificationModal(result, fragment.id);
560612
inputField.disabled = false;
@@ -569,7 +621,6 @@ <h3>📋 Clarification Required</h3>
569621
lastResponse = result.response;
570622
thinking.remove();
571623

572-
// Update VELA badge
573624
if (result.pac) {
574625
const ppi = result.pac.ppi;
575626
const cls = ppi < 30 ? 'vela-block' : (ppi < 70 ? 'vela-flag' : 'vela-pass');
@@ -606,7 +657,8 @@ <h3>📋 Clarification Required</h3>
606657
inputField.placeholder = 'Type your message (will be structured)';
607658
updateSelectedValues();
608659
addSystemMessage('🌌 **STRUCTURED MODE ACTIVE**\n\nSet intent, domain, emotion, time. Your message will be sent as a structured fragment.');
609-
pendingClarification = null; // reset any pending intercept
660+
pendingClarification = null;
661+
clarificationDepth = 0;
610662
} else {
611663
structuredUI.classList.remove('active');
612664
modeBadge.textContent = '⚡ REGULAR';
@@ -624,18 +676,27 @@ <h3>📋 Clarification Required</h3>
624676
}
625677

626678
function showTrace() {
627-
// Simple trace – could be expanded with actual operation history from backend
628679
const traceInfo = {
629680
sessionId,
630681
structuredModeActive,
631682
lastFragmentId,
632683
lastResponsePreview: lastResponse?.substring(0, 100),
633-
pendingClarification: pendingClarification ? true : false
684+
pendingClarification: pendingClarification ? true : false,
685+
clarificationDepth
634686
};
635687
showModal('Ada‑VELA Trace', JSON.stringify(traceInfo, null, 2));
636688
console.log('Trace data:', traceInfo);
637689
}
638690

691+
function resetStructuredFields() {
692+
itlIntent.selectedIndex = 0;
693+
itlDomain.selectedIndex = 5; // general
694+
itlEmotion.selectedIndex = 0;
695+
itlTime.selectedIndex = 0;
696+
updateSelectedValues();
697+
addSystemMessage('Structured mode fields reset.');
698+
}
699+
639700
// Event listeners
640701
sendBtn.onclick = send;
641702
plusBtn.onclick = (e) => { e.stopPropagation(); dropdown.style.display = dropdown.style.display === 'flex' ? 'none' : 'flex'; };
@@ -646,6 +707,7 @@ <h3>📋 Clarification Required</h3>
646707
document.getElementById('traceBtn').onclick = () => { dropdown.style.display = 'none'; showTrace(); };
647708
inputField.addEventListener('keypress', (e) => { if (e.key === 'Enter') send(); });
648709
[itlIntent, itlDomain, itlEmotion, itlTime].forEach(el => el.addEventListener('change', updateSelectedValues));
710+
resetStructuredBtn.onclick = resetStructuredFields;
649711

650712
// Initial message
651713
addMessage('ai', 'Ada‑VELA ready. Click + → Structured Mode to activate GATE-ITL.');

0 commit comments

Comments
 (0)