Add Path Tracer onion timeline fork/merge with ghost branches and Seer feed.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Operators fork at hop N to run persona ensembles in parallel on the target agent until mining links; winners merge back into the canonical SQLite-persisted session with WS and Seer events plus mermaid branch graphs in the UI.
This commit is contained in:
107
server/web/src/help/pathTracerTimeline.ts
Normal file
107
server/web/src/help/pathTracerTimeline.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Onion timeline fork/merge helpers for Path Tracer UI + Seer/AI context.
|
||||
*/
|
||||
|
||||
export type TimelineBranchStatus =
|
||||
| 'canonical'
|
||||
| 'running'
|
||||
| 'won'
|
||||
| 'lost'
|
||||
| 'merged'
|
||||
| 'failed'
|
||||
| 'aborted';
|
||||
|
||||
export interface PathTraceTimelineBranch {
|
||||
id: string;
|
||||
parent_id?: string;
|
||||
fork_hop_index: number;
|
||||
target_agent_id?: string;
|
||||
target_agent_name?: string;
|
||||
persona?: string;
|
||||
spread_lanes?: string[];
|
||||
status: TimelineBranchStatus;
|
||||
mining_linked?: boolean;
|
||||
hashrate?: number;
|
||||
active_tier?: string;
|
||||
error?: string;
|
||||
is_ghost: boolean;
|
||||
created_at?: string;
|
||||
merged_at?: string;
|
||||
}
|
||||
|
||||
export interface PathTraceTimelineWS {
|
||||
session_id: string;
|
||||
event: string;
|
||||
branch?: PathTraceTimelineBranch;
|
||||
branches?: PathTraceTimelineBranch[];
|
||||
mermaid?: string;
|
||||
target_agent_id?: string;
|
||||
}
|
||||
|
||||
export function branchStatusLabel(status: TimelineBranchStatus): string {
|
||||
switch (status) {
|
||||
case 'canonical':
|
||||
return 'canonical';
|
||||
case 'running':
|
||||
return 'exploring';
|
||||
case 'won':
|
||||
return 'mining linked';
|
||||
case 'merged':
|
||||
return 'merged';
|
||||
case 'lost':
|
||||
return 'lost';
|
||||
case 'failed':
|
||||
return 'failed';
|
||||
case 'aborted':
|
||||
return 'aborted';
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
export function branchStatusClass(status: TimelineBranchStatus): string {
|
||||
switch (status) {
|
||||
case 'won':
|
||||
case 'merged':
|
||||
return 'won';
|
||||
case 'running':
|
||||
return 'running';
|
||||
case 'failed':
|
||||
case 'lost':
|
||||
case 'aborted':
|
||||
return 'failed';
|
||||
case 'canonical':
|
||||
return 'canonical';
|
||||
default:
|
||||
return 'ghost';
|
||||
}
|
||||
}
|
||||
|
||||
/** Ghost branches grouped under fork hop index for tree rendering. */
|
||||
export function ghostBranchesByHop(branches: PathTraceTimelineBranch[]): Map<number, PathTraceTimelineBranch[]> {
|
||||
const map = new Map<number, PathTraceTimelineBranch[]>();
|
||||
for (const b of branches) {
|
||||
if (!b.is_ghost) continue;
|
||||
const list = map.get(b.fork_hop_index) ?? [];
|
||||
list.push(b);
|
||||
map.set(b.fork_hop_index, list);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function pickMergeCandidate(branches: PathTraceTimelineBranch[]): PathTraceTimelineBranch | null {
|
||||
const ghosts = branches.filter((b) => b.is_ghost);
|
||||
const won = ghosts.find((b) => b.status === 'won' || b.mining_linked);
|
||||
if (won) return won;
|
||||
const running = ghosts.find((b) => b.status === 'running');
|
||||
return running ?? null;
|
||||
}
|
||||
|
||||
export function mergeMermaidStyles(mermaid: string): string {
|
||||
const styles = `classDef won fill:#0a3d2e,stroke:#00ffaa,color:#00ffaa
|
||||
classDef running fill:#3d320a,stroke:#ffc800,color:#ffc800
|
||||
classDef failed fill:#3d0a0a,stroke:#ff5050,color:#ff5050
|
||||
classDef ghost fill:#1a1a2e,stroke:#888,color:#ccc`;
|
||||
if (mermaid.includes('classDef won')) return mermaid;
|
||||
return `${mermaid.trim()}\n${styles}`;
|
||||
}
|
||||
Reference in New Issue
Block a user