Nico 2d649fa448 v0.15.3: Domain context, iterative plan-execute, FK mappings, ES6 node inspector
Eras Expert domain context:
- Full Heizkostenabrechnung business model (Kunde>Objekte>Nutzeinheiten>Geraete)
- Known PK/FK mappings: kunden.Kundennummer, objekte.KundenID, etc.
- Correct JOIN example in SCHEMA prompt
- PA knows domain hierarchy for better job formulation

Iterative plan-execute in ExpertNode:
- DESCRIBE queries execute first, results injected into re-plan
- Re-plan uses actual column names from DESCRIBE
- Eliminates "Unknown column" errors on first query

Frontend:
- Node inspector: per-node cards with model, tokens, progress, last event
- Graph switcher buttons in top bar
- Clear button in top bar
- Nodes panel 300px wide
- WS reconnect on 1006 (deploy) without showing login
- Model info emitted on context HUD events

Domain context test: 21/21 (hierarchy, JOINs, FK, PA job quality)
Default graph: v4-eras

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 18:34:42 +02:00

91 lines
2.8 KiB
JavaScript

/** Main entry point — wires all modules together. */
import { initAuth, authToken, startLogin } from './auth.js';
import { initTrace, addTrace, clearTrace } from './trace.js';
import { initChat, clearChat } from './chat.js';
import { clearDashboard } from './dashboard.js';
import { clearNodes } from './awareness.js';
import { initGraph } from './graph.js';
import { connect } from './ws.js';
// Init on load
window.addEventListener('load', async () => {
initTrace();
initChat();
await initGraph();
await initAuth(() => {
connect();
loadGraphSwitcher();
});
});
// Clear session
window.clearSession = async () => {
try {
const headers = { 'Content-Type': 'application/json' };
if (authToken) headers['Authorization'] = 'Bearer ' + authToken;
await fetch('/api/clear', { method: 'POST', headers });
clearChat();
clearTrace();
clearDashboard();
clearNodes();
addTrace('runtime', 'cleared', 'session reset');
} catch (e) {
addTrace('runtime', 'error', 'clear failed: ' + e);
}
};
// Graph switcher — loads available graphs and shows buttons in top bar
async function loadGraphSwitcher() {
const container = document.getElementById('graph-switcher');
if (!container) { console.error('[main] no #graph-switcher'); return; }
try {
const headers = {};
if (authToken) headers['Authorization'] = 'Bearer ' + authToken;
const r = await fetch('/api/graph/list', { headers });
if (!r.ok) { console.error('[main] graph/list failed:', r.status); return; }
const data = await r.json();
const graphs = data.graphs || data || [];
console.log('[main] graphs:', graphs.length);
// Get current active graph
let activeGraph = '';
try {
const ar = await fetch('/api/graph/active', { headers });
if (ar.ok) {
const ag = await ar.json();
activeGraph = ag.name || '';
}
} catch (e) {}
container.innerHTML = graphs.map(g => {
const active = g.name === activeGraph;
return `<button class="btn-graph${active ? ' active' : ''}" onclick="switchGraph('${g.name}')" title="${g.description}">${g.name}</button>`;
}).join('');
} catch (e) {}
}
window.switchGraph = async (name) => {
try {
const headers = { 'Content-Type': 'application/json' };
if (authToken) headers['Authorization'] = 'Bearer ' + authToken;
await fetch('/api/graph/switch', {
method: 'POST', headers,
body: JSON.stringify({ name }),
});
addTrace('runtime', 'graph_switch', name);
clearChat();
clearTrace();
clearDashboard();
clearNodes();
addTrace('runtime', 'switched', `graph: ${name}`);
await initGraph();
loadGraphSwitcher();
} catch (e) {
addTrace('runtime', 'error', 'switch failed: ' + e);
}
};
// Login
window.startLogin = startLogin;