Files
boc/EOS/runtime-trace.mjs
T
Bernt 05ed037fe8 pilot.landvex.com: HTTPS + Full Stack Verified
- DNS: pilot.landvex.com -> 16.170.83.169
- TLS: Let's Encrypt certificate (expires 2026-09-30)
- Nginx: reverse proxy with SSL termination
- API: https://pilot.landvex.com/api/v1/missions
- UI: https://pilot.landvex.com/
- Upload: POST /api/v1/missions/import (multipart/form-data)

Verified:
 https://pilot.landvex.com/health
 https://pilot.landvex.com/version
 https://pilot.landvex.com/api/v1/missions (list)
 https://pilot.landvex.com/api/v1/missions/:id (get)
 POST /api/v1/missions/import (video upload)
 UI loads with title 'LandveX Intelligence Lab'

Next: Pilot 001 — Break the system!
2026-07-02 17:34:19 +00:00

230 lines
6.1 KiB
JavaScript

#!/usr/bin/env node
// ═══════════════════════════════════════════════════════════════════════════
// Runtime Trace — Graf över agentens resonemang
// "När något går fel ska man kunna spela upp exakt hur agenten resonerade"
// ═══════════════════════════════════════════════════════════════════════════
class RuntimeTrace {
constructor(taskId) {
this.taskId = taskId;
this.nodes = [];
this.edges = [];
this.startTime = Date.now();
}
/**
* Lägg till en nod i tracen
*/
addNode(phase, data = {}) {
const node = {
id: `${phase}-${this.nodes.length}`,
phase,
timestamp: Date.now() - this.startTime,
data,
status: 'running'
};
this.nodes.push(node);
// Skapa edge från föregående nod
if (this.nodes.length > 1) {
const prevNode = this.nodes[this.nodes.length - 2];
this.edges.push({
from: prevNode.id,
to: node.id,
type: 'sequence'
});
}
return node;
}
/**
* Markera nod som klar
*/
completeNode(nodeId, result = {}) {
const node = this.nodes.find(n => n.id === nodeId);
if (node) {
node.status = 'completed';
node.result = result;
node.duration = Date.now() - this.startTime - node.timestamp;
}
return node;
}
/**
* Markera nod som blockerad
*/
blockNode(nodeId, reason) {
const node = this.nodes.find(n => n.id === nodeId);
if (node) {
node.status = 'blocked';
node.blockReason = reason;
node.duration = Date.now() - this.startTime - node.timestamp;
}
return node;
}
/**
* Markera nod som eskalerad
*/
escalateNode(nodeId, reason) {
const node = this.nodes.find(n => n.id === nodeId);
if (node) {
node.status = 'escalated';
node.escalationReason = reason;
node.duration = Date.now() - this.startTime - node.timestamp;
}
return node;
}
/**
* Generera textuell representation
*/
toText() {
const lines = [
`Task: ${this.taskId}`,
`Duration: ${Date.now() - this.startTime}ms`,
`Nodes: ${this.nodes.length}`,
''
];
for (const node of this.nodes) {
const status = node.status === 'completed' ? '✅' :
node.status === 'blocked' ? '❌' :
node.status === 'escalated' ? '⚠️' : '⏳';
lines.push(`${status} ${node.phase} (${node.timestamp}ms)`);
if (node.duration) {
lines.push(` Duration: ${node.duration}ms`);
}
if (node.result) {
lines.push(` Result: ${JSON.stringify(node.result)}`);
}
if (node.blockReason) {
lines.push(` Blocked: ${node.blockReason}`);
}
if (node.escalationReason) {
lines.push(` Escalated: ${node.escalationReason}`);
}
if (node.data && Object.keys(node.data).length > 0) {
lines.push(` Data: ${JSON.stringify(node.data)}`);
}
}
return lines.join('\n');
}
/**
* Generera JSON-representation
*/
toJSON() {
return {
taskId: this.taskId,
startTime: this.startTime,
endTime: Date.now(),
duration: Date.now() - this.startTime,
nodes: this.nodes,
edges: this.edges
};
}
/**
* Spela upp tracen steg för steg
*/
async replay(delayMs = 1000) {
console.log(`\n=== Replaying Trace: ${this.taskId} ===\n`);
for (const node of this.nodes) {
const status = node.status === 'completed' ? '✅' :
node.status === 'blocked' ? '❌' :
node.status === 'escalated' ? '⚠️' : '⏳';
console.log(`${status} ${node.phase}`);
if (node.blockReason) {
console.log(` ❌ Blocked: ${node.blockReason}`);
}
if (node.escalationReason) {
console.log(` ⚠️ Escalated: ${node.escalationReason}`);
}
await new Promise(resolve => setTimeout(resolve, delayMs));
}
console.log('\n=== Replay Complete ===');
}
/**
* Hitta vägen till en specifik nod
*/
findPathTo(targetPhase) {
const targetNode = this.nodes.find(n => n.phase === targetPhase);
if (!targetNode) return null;
const path = [];
let current = targetNode;
while (current) {
path.unshift(current);
const incomingEdge = this.edges.find(e => e.to === current.id);
current = incomingEdge ? this.nodes.find(n => n.id === incomingEdge.from) : null;
}
return path;
}
/**
* Hitta alla blockeringar
*/
findBlocks() {
return this.nodes.filter(n => n.status === 'blocked');
}
/**
* Hitta alla eskaleringar
*/
findEscalations() {
return this.nodes.filter(n => n.status === 'escalated');
}
}
// Exempel
if (process.argv[1] === new URL(import.meta.url).pathname) {
const trace = new RuntimeTrace('test-task');
// Simulera ett flöde
const planner = trace.addNode('PLANNER', { steps: 3 });
trace.completeNode(planner.id, { plan: ['step1', 'step2', 'step3'] });
const context = trace.addNode('CONTEXT', { docs: 5 });
trace.completeNode(context.id, { confidence: 0.8 });
const memory = trace.addNode('MEMORY', { queries: 2 });
trace.completeNode(memory.id, { results: 3 });
const eos = trace.addNode('EOS', { rules: 12 });
trace.completeNode(eos.id, { passed: 12, failed: 0 });
const developer = trace.addNode('DEVELOPER', { files: 1 });
trace.completeNode(developer.id, { changed: 1 });
const reviewer = trace.addNode('REVIEWER', { checks: 5 });
trace.completeNode(reviewer.id, { passed: 5 });
const commit = trace.addNode('COMMIT');
trace.completeNode(commit.id, { hash: 'abc123' });
console.log(trace.toText());
console.log('\n=== JSON ===');
console.log(JSON.stringify(trace.toJSON(), null, 2));
}
export { RuntimeTrace };