Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions app/lib/jsonl-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,13 @@ export class TraceBuilder {
fs.appendFileSync(TRACES, JSON.stringify(summary) + "\n");
}
}


/** Append a single JSON record to a JSONL file in the trace dir.
* Used by the comments API route (POST /api/comments → comments.jsonl)
* and any other lightweight append-only event log the dashboard owns. */
export function appendJsonl<T>(filename: string, record: T): void {
fs.mkdirSync(TRACE_DIR, { recursive: true });
const target = path.join(TRACE_DIR, filename);
fs.appendFileSync(target, JSON.stringify(record) + "\n");
}
70 changes: 70 additions & 0 deletions app/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,73 @@ export type Contrib = {
agents: string[];
qids: string[];
};

// ─── Signal / comment / alert types ──────────────────────────────────────
//
// Used by the dashboard's alerts + signals + comments surfaces. Shapes
// derived from the only authoritative usage site: app/lib/signals.ts
// (detector pipeline) and app/api/comments/route.ts (POST handler).
// Kept narrow on purpose — these surfaces are still in flux; better
// to widen later than to over-specify and lock in the wrong shape.

/** What kind of failure/event a signal flags. Keep this in sync with
* SIGNAL_LABEL / SIGNAL_TONE in app/lib/signals.ts. */
export type SignalKind =
| "forgetting"
| "task_failure"
| "frustration"
| "nsfw"
| "jailbreak"
| "laziness"
| "win"
| "asr_low_confidence"
| "dead_air"
| "barge_in_mishandled"
| "broken_link"
| "tool_error"
| "loop"
| "hallucination";

export type Severity = "low" | "med" | "high";

export type Modality = "chat" | "voice" | "agent" | "rag";

/** One detected event on a span. Built by detectors in
* app/lib/signals.ts; consumed by the timeline / alerts views. */
export type Signal = {
id: string;
trace_id: string;
span_id: string;
kind: SignalKind;
severity: Severity;
source: "builtin" | "user";
title: string;
evidence: string;
ts: number;
modality: Modality;
};

/** A comment pinned to a specific span (not a whole trace). Append-only
* via POST /api/comments. */
export type SpanComment = {
id: string;
trace_id: string;
span_id: string;
author: string;
text: string;
ts: number;
};

/** A historical record of an alert rule firing. Read by the dashboard's
* /alerts page; written by whatever evaluates rules (not yet wired in
* this branch — the page falls back to computing live `eligible` rules
* off loadSignals()). */
export type AlertFiring = {
id: string;
kind: SignalKind;
count: number;
threshold: number;
window_min: number;
channel: string;
ts: number;
};
Loading