@titan-design/session-analytics 0.5.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -1
- package/dist/index.d.ts +553 -1
- package/dist/index.js +959 -38
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Db } from '@titan-design/store-sqlite';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { EpisodeRow, SessionGraph } from '@titan-design/session-graph';
|
|
4
|
+
import { ToolFamily, NormalizedSessionObservation } from '@titan-design/session-read';
|
|
5
|
+
export { ToolFamily } from '@titan-design/session-read';
|
|
4
6
|
|
|
5
7
|
/** USD per million tokens. Fitted against 392 `cost-state` rows in the 2026-09-20 audit. */
|
|
6
8
|
interface PriceRow {
|
|
@@ -242,6 +244,7 @@ declare const reviewerSchema: z.ZodObject<{
|
|
|
242
244
|
sessions: z.ZodNumber;
|
|
243
245
|
requestsPerPr: z.ZodNumber;
|
|
244
246
|
requestsFrom: z.ZodString;
|
|
247
|
+
requestsFromSessions: z.ZodNumber;
|
|
245
248
|
costUsd: z.ZodNumber;
|
|
246
249
|
}, z.core.$strip>>;
|
|
247
250
|
standing: z.ZodArray<z.ZodObject<{
|
|
@@ -250,6 +253,7 @@ declare const reviewerSchema: z.ZodObject<{
|
|
|
250
253
|
sessions: z.ZodNumber;
|
|
251
254
|
requestsPerPr: z.ZodNumber;
|
|
252
255
|
requestsFrom: z.ZodString;
|
|
256
|
+
requestsFromSessions: z.ZodNumber;
|
|
253
257
|
costUsd: z.ZodNumber;
|
|
254
258
|
}, z.core.$strip>>;
|
|
255
259
|
}, z.core.$strip>;
|
|
@@ -322,6 +326,7 @@ declare const handoffThresholdSchema: z.ZodObject<{
|
|
|
322
326
|
sessions: z.ZodNumber;
|
|
323
327
|
requestsPerPr: z.ZodNumber;
|
|
324
328
|
requestsFrom: z.ZodString;
|
|
329
|
+
requestsFromSessions: z.ZodNumber;
|
|
325
330
|
costUsd: z.ZodNumber;
|
|
326
331
|
}, z.core.$strip>>;
|
|
327
332
|
standing: z.ZodArray<z.ZodObject<{
|
|
@@ -330,6 +335,7 @@ declare const handoffThresholdSchema: z.ZodObject<{
|
|
|
330
335
|
sessions: z.ZodNumber;
|
|
331
336
|
requestsPerPr: z.ZodNumber;
|
|
332
337
|
requestsFrom: z.ZodString;
|
|
338
|
+
requestsFromSessions: z.ZodNumber;
|
|
333
339
|
costUsd: z.ZodNumber;
|
|
334
340
|
}, z.core.$strip>>;
|
|
335
341
|
}, z.core.$strip>;
|
|
@@ -657,6 +663,7 @@ declare const costReportSchema: z.ZodObject<{
|
|
|
657
663
|
sessions: z.ZodNumber;
|
|
658
664
|
requestsPerPr: z.ZodNumber;
|
|
659
665
|
requestsFrom: z.ZodString;
|
|
666
|
+
requestsFromSessions: z.ZodNumber;
|
|
660
667
|
costUsd: z.ZodNumber;
|
|
661
668
|
}, z.core.$strip>>;
|
|
662
669
|
standing: z.ZodArray<z.ZodObject<{
|
|
@@ -665,6 +672,7 @@ declare const costReportSchema: z.ZodObject<{
|
|
|
665
672
|
sessions: z.ZodNumber;
|
|
666
673
|
requestsPerPr: z.ZodNumber;
|
|
667
674
|
requestsFrom: z.ZodString;
|
|
675
|
+
requestsFromSessions: z.ZodNumber;
|
|
668
676
|
costUsd: z.ZodNumber;
|
|
669
677
|
}, z.core.$strip>>;
|
|
670
678
|
}, z.core.$strip>;
|
|
@@ -1132,11 +1140,15 @@ interface DenialRecord {
|
|
|
1132
1140
|
/** What the refused call was doing, from its tool input; the reason label alone is loose. */
|
|
1133
1141
|
action: string;
|
|
1134
1142
|
tool: string;
|
|
1143
|
+
/** The refused call's id; a forked or resumed transcript repeats it, so it is counted once. */
|
|
1144
|
+
toolUseId?: string;
|
|
1135
1145
|
}
|
|
1136
1146
|
/** Classifies a refused call by what it did; MCP tools keep their own short name. */
|
|
1137
1147
|
declare function classifyDeniedAction(tool: string, input: unknown): string;
|
|
1138
1148
|
/** Scans transcript JSONL for classifier refusals and joins each to the tool call it refused. */
|
|
1139
1149
|
declare function parseDenials(lines: Iterable<string>, seat: string): DenialRecord[];
|
|
1150
|
+
/** One denial per refused call; a record without a tool_use_id cannot be matched and is kept. */
|
|
1151
|
+
declare function dedupeDenials(denials: readonly DenialRecord[]): DenialRecord[];
|
|
1140
1152
|
|
|
1141
1153
|
/** A seat journal line that states its implementer slot count, and why it did not fill a free slot. */
|
|
1142
1154
|
interface SlotTick {
|
|
@@ -1374,4 +1386,544 @@ declare function blockedFlowReport(input: BlockedFlowInput): BlockedFlowReport;
|
|
|
1374
1386
|
/** Each table's title names the JSON field its numbers come from; the sources close the report. */
|
|
1375
1387
|
declare function renderBlockedFlowText(report: BlockedFlowReport): string;
|
|
1376
1388
|
|
|
1377
|
-
|
|
1389
|
+
/** One agent-chat broker.log entry and the 1-based line it came from, so each finding can cite it. */
|
|
1390
|
+
interface BrokerEntry {
|
|
1391
|
+
line: number;
|
|
1392
|
+
ts: string;
|
|
1393
|
+
event: string;
|
|
1394
|
+
fields: Record<string, unknown>;
|
|
1395
|
+
}
|
|
1396
|
+
/** Broker log lines to entries; a line that is not a JSON object with `ts` and `event` is skipped but still counted. */
|
|
1397
|
+
declare function parseBrokerLog(lines: Iterable<string>): BrokerEntry[];
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* How a route missed a recipient: `failed` is a `delivered:false` the broker dropped, `partial` reached
|
|
1401
|
+
* others but not this name, and `queued` is a `delivered:false` the broker kept for later delivery.
|
|
1402
|
+
*/
|
|
1403
|
+
type RouteMissKind = "failed" | "partial" | "queued";
|
|
1404
|
+
/** One recipient a routed message did not reach when it was sent. */
|
|
1405
|
+
interface RouteMiss {
|
|
1406
|
+
line: number;
|
|
1407
|
+
at: string;
|
|
1408
|
+
recipient: string;
|
|
1409
|
+
from: string;
|
|
1410
|
+
kind: string;
|
|
1411
|
+
miss: RouteMissKind;
|
|
1412
|
+
}
|
|
1413
|
+
interface RouteFailureRow {
|
|
1414
|
+
recipient: string;
|
|
1415
|
+
failed: number;
|
|
1416
|
+
partial: number;
|
|
1417
|
+
queued: number;
|
|
1418
|
+
first: string;
|
|
1419
|
+
last: string;
|
|
1420
|
+
lines: number[];
|
|
1421
|
+
}
|
|
1422
|
+
/** Each recipient named in `to` that a route did not reach. */
|
|
1423
|
+
declare function routeMisses(entries: readonly BrokerEntry[]): RouteMiss[];
|
|
1424
|
+
/** Misses grouped by recipient, most first. */
|
|
1425
|
+
declare function routeFailureRows(misses: readonly RouteMiss[]): RouteFailureRow[];
|
|
1426
|
+
declare function countMisses(misses: readonly RouteMiss[]): Record<RouteMissKind, number>;
|
|
1427
|
+
|
|
1428
|
+
/** A seat off the broker for longer than this is dark; a teleport hand-off takes seconds. */
|
|
1429
|
+
declare const DARK_MIN = 5;
|
|
1430
|
+
/** A name deregistered from the broker until it registered again, or until asOf if it never did, without exiting in between. */
|
|
1431
|
+
interface DarkGap {
|
|
1432
|
+
seat: string;
|
|
1433
|
+
from: string;
|
|
1434
|
+
to: string | null;
|
|
1435
|
+
minutes: number;
|
|
1436
|
+
/** A teleport of this name started after its last registration and before the gap closed. */
|
|
1437
|
+
teleport: boolean;
|
|
1438
|
+
/** Routes to the seat during the gap logged `delivered:false` and dropped. */
|
|
1439
|
+
failedRoutes: number;
|
|
1440
|
+
/** Routes during the gap that reached other recipients but not the seat. */
|
|
1441
|
+
partialRoutes: number;
|
|
1442
|
+
/** Routes the broker held or queued in the seat's inbox for delivery when it returned. */
|
|
1443
|
+
queuedRoutes: number;
|
|
1444
|
+
/** The deregistered and registered lines, then any teleport lines. */
|
|
1445
|
+
lines: number[];
|
|
1446
|
+
routeLines: number[];
|
|
1447
|
+
}
|
|
1448
|
+
/** Gaps longer than DARK_MIN, skipping a clean exit and later resume; one still open at asOf counts only if a route missed the seat in it. */
|
|
1449
|
+
declare function darkGaps(entries: readonly BrokerEntry[], misses: readonly RouteMiss[], asOf: string): DarkGap[];
|
|
1450
|
+
|
|
1451
|
+
/** An `agent_spawned` row of agent-chat's events table: the agent id and the profile it ran under. */
|
|
1452
|
+
interface SpawnRecord {
|
|
1453
|
+
eventId: number;
|
|
1454
|
+
agentId: string;
|
|
1455
|
+
name: string;
|
|
1456
|
+
profile: string | null;
|
|
1457
|
+
}
|
|
1458
|
+
/** An agent the broker saw exit without reporting to its spawner. */
|
|
1459
|
+
interface UnreportedExit {
|
|
1460
|
+
at: string;
|
|
1461
|
+
line: number;
|
|
1462
|
+
agentId: string;
|
|
1463
|
+
name: string;
|
|
1464
|
+
spawner: string;
|
|
1465
|
+
lastAction: string;
|
|
1466
|
+
/** The `agent_spawned` row the profile came from, or null when none matched the agent id. */
|
|
1467
|
+
spawnEventId: number | null;
|
|
1468
|
+
}
|
|
1469
|
+
interface UnreportedExitRow {
|
|
1470
|
+
profile: string;
|
|
1471
|
+
count: number;
|
|
1472
|
+
exits: UnreportedExit[];
|
|
1473
|
+
}
|
|
1474
|
+
declare const UNKNOWN_PROFILE = "unknown";
|
|
1475
|
+
/** Broker `unreported-exit` lines grouped by the profile the agent was spawned with, most first. */
|
|
1476
|
+
declare function unreportedExitRows(entries: readonly BrokerEntry[], spawns: readonly SpawnRecord[]): UnreportedExitRow[];
|
|
1477
|
+
|
|
1478
|
+
/** A prompt this old with nothing after it from the agent is a hang, not a pause for the owner. */
|
|
1479
|
+
declare const PROMPT_STALE_MIN = 10;
|
|
1480
|
+
/** The newest events-table row an actor wrote before asOf. */
|
|
1481
|
+
interface LastEventRecord {
|
|
1482
|
+
eventId: number;
|
|
1483
|
+
at: string;
|
|
1484
|
+
actor: string;
|
|
1485
|
+
kind: string;
|
|
1486
|
+
/** `meta.tool_name` of an approval request. */
|
|
1487
|
+
tool: string | null;
|
|
1488
|
+
/** A `resolution` row whose `ref` is this request's msg_id, written before asOf. */
|
|
1489
|
+
resolutionEventId: number | null;
|
|
1490
|
+
/** An `agent_exited` or `agent_retired` row for this actor after the request and before asOf. */
|
|
1491
|
+
endEventId: number | null;
|
|
1492
|
+
}
|
|
1493
|
+
interface StalePromptRow {
|
|
1494
|
+
agent: string;
|
|
1495
|
+
at: string;
|
|
1496
|
+
ageMin: number;
|
|
1497
|
+
tool: string | null;
|
|
1498
|
+
eventId: number;
|
|
1499
|
+
resolutionEventId: number | null;
|
|
1500
|
+
}
|
|
1501
|
+
/** Live agents whose last event is an approval request older than PROMPT_STALE_MIN, oldest first; resolved ones included. */
|
|
1502
|
+
declare function stalePromptRows(lastEvents: readonly LastEventRecord[], broker: readonly BrokerEntry[], asOf: string): StalePromptRow[];
|
|
1503
|
+
|
|
1504
|
+
/** Where each section's findings come from: the command that re-reads them and the field it reads. */
|
|
1505
|
+
declare const LIVENESS_SOURCES: {
|
|
1506
|
+
readonly registrations: {
|
|
1507
|
+
readonly command: "grep -nE '\"event\":\"(registered|deregistered|agent_exited|teleport_started|teleport_completed|teleport_failed|teleport_aborted)\"' <broker.log>";
|
|
1508
|
+
readonly field: "ts, event, name; cited as broker.log line numbers; a gap with a clean agent_exited (code 0, not inferred) and no teleport is a resume";
|
|
1509
|
+
};
|
|
1510
|
+
readonly routes: {
|
|
1511
|
+
readonly command: "grep -n '\"event\":\"route\"' <broker.log>";
|
|
1512
|
+
readonly field: "to, delivered, recipients";
|
|
1513
|
+
};
|
|
1514
|
+
readonly exits: {
|
|
1515
|
+
readonly command: "grep -n '\"event\":\"unreported-exit\"' <broker.log>";
|
|
1516
|
+
readonly field: "agentId, name, spawner, lastAction";
|
|
1517
|
+
};
|
|
1518
|
+
readonly spawns: {
|
|
1519
|
+
readonly command: "sqlite3 -readonly <events.db> \"SELECT id, msg_id, target, json_extract(meta,'$.profile') FROM events WHERE kind='agent_spawned'\"";
|
|
1520
|
+
readonly field: "events.msg_id (agent id), events.meta.profile";
|
|
1521
|
+
};
|
|
1522
|
+
readonly prompts: {
|
|
1523
|
+
readonly command: "sqlite3 -readonly <events.db> \"SELECT e.* FROM events e JOIN (SELECT actor, max(id) id FROM events WHERE ts < <asOf> AND kind != 'resolution' GROUP BY actor) l ON e.id = l.id WHERE e.kind='approval_request'\"";
|
|
1524
|
+
readonly field: "events.ts, events.actor, events.meta.tool_name; a resolution row's events.ref; skipped after the actor's agent_exited or agent_retired, or a broker_started it never re-registered after";
|
|
1525
|
+
};
|
|
1526
|
+
};
|
|
1527
|
+
type LivenessSource = keyof typeof LIVENESS_SOURCES;
|
|
1528
|
+
interface LivenessInput {
|
|
1529
|
+
broker: readonly BrokerEntry[];
|
|
1530
|
+
spawns: readonly SpawnRecord[];
|
|
1531
|
+
lastEvents: readonly LastEventRecord[];
|
|
1532
|
+
/** Gaps still open and prompt ages are measured to here; later entries are ignored. */
|
|
1533
|
+
asOf: string;
|
|
1534
|
+
/** A finding is kept when it starts inside the window; a prompt from a live agent still unanswered at asOf is kept however old. */
|
|
1535
|
+
window?: {
|
|
1536
|
+
since?: string;
|
|
1537
|
+
until?: string;
|
|
1538
|
+
};
|
|
1539
|
+
/** Keeps only findings about these names: the dark seat, route recipient, exiting agent or its spawner, prompting agent. */
|
|
1540
|
+
seats?: readonly string[];
|
|
1541
|
+
}
|
|
1542
|
+
declare const livenessSchema: z.ZodObject<{
|
|
1543
|
+
asOf: z.ZodString;
|
|
1544
|
+
window: z.ZodObject<{
|
|
1545
|
+
since: z.ZodOptional<z.ZodString>;
|
|
1546
|
+
until: z.ZodOptional<z.ZodString>;
|
|
1547
|
+
}, z.core.$strip>;
|
|
1548
|
+
thresholds: z.ZodObject<{
|
|
1549
|
+
darkMin: z.ZodNumber;
|
|
1550
|
+
promptStaleMin: z.ZodNumber;
|
|
1551
|
+
}, z.core.$strip>;
|
|
1552
|
+
sources: z.ZodRecord<z.ZodEnum<{
|
|
1553
|
+
exits: "exits";
|
|
1554
|
+
registrations: "registrations";
|
|
1555
|
+
routes: "routes";
|
|
1556
|
+
spawns: "spawns";
|
|
1557
|
+
prompts: "prompts";
|
|
1558
|
+
}>, z.ZodObject<{
|
|
1559
|
+
command: z.ZodString;
|
|
1560
|
+
field: z.ZodString;
|
|
1561
|
+
}, z.core.$strip>>;
|
|
1562
|
+
darkSeats: z.ZodObject<{
|
|
1563
|
+
cites: z.ZodArray<z.ZodEnum<{
|
|
1564
|
+
exits: "exits";
|
|
1565
|
+
registrations: "registrations";
|
|
1566
|
+
routes: "routes";
|
|
1567
|
+
spawns: "spawns";
|
|
1568
|
+
prompts: "prompts";
|
|
1569
|
+
}>>;
|
|
1570
|
+
withTeleport: z.ZodNumber;
|
|
1571
|
+
withoutTeleport: z.ZodNumber;
|
|
1572
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
1573
|
+
seat: z.ZodString;
|
|
1574
|
+
from: z.ZodString;
|
|
1575
|
+
to: z.ZodNullable<z.ZodString>;
|
|
1576
|
+
minutes: z.ZodNumber;
|
|
1577
|
+
teleport: z.ZodBoolean;
|
|
1578
|
+
failedRoutes: z.ZodNumber;
|
|
1579
|
+
partialRoutes: z.ZodNumber;
|
|
1580
|
+
queuedRoutes: z.ZodNumber;
|
|
1581
|
+
lines: z.ZodArray<z.ZodNumber>;
|
|
1582
|
+
routeLines: z.ZodArray<z.ZodNumber>;
|
|
1583
|
+
}, z.core.$strip>>;
|
|
1584
|
+
}, z.core.$strip>;
|
|
1585
|
+
routeFailures: z.ZodObject<{
|
|
1586
|
+
cites: z.ZodArray<z.ZodEnum<{
|
|
1587
|
+
exits: "exits";
|
|
1588
|
+
registrations: "registrations";
|
|
1589
|
+
routes: "routes";
|
|
1590
|
+
spawns: "spawns";
|
|
1591
|
+
prompts: "prompts";
|
|
1592
|
+
}>>;
|
|
1593
|
+
failed: z.ZodNumber;
|
|
1594
|
+
partial: z.ZodNumber;
|
|
1595
|
+
queued: z.ZodNumber;
|
|
1596
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
1597
|
+
recipient: z.ZodString;
|
|
1598
|
+
failed: z.ZodNumber;
|
|
1599
|
+
partial: z.ZodNumber;
|
|
1600
|
+
queued: z.ZodNumber;
|
|
1601
|
+
first: z.ZodString;
|
|
1602
|
+
last: z.ZodString;
|
|
1603
|
+
lines: z.ZodArray<z.ZodNumber>;
|
|
1604
|
+
}, z.core.$strip>>;
|
|
1605
|
+
}, z.core.$strip>;
|
|
1606
|
+
unreportedExits: z.ZodObject<{
|
|
1607
|
+
cites: z.ZodArray<z.ZodEnum<{
|
|
1608
|
+
exits: "exits";
|
|
1609
|
+
registrations: "registrations";
|
|
1610
|
+
routes: "routes";
|
|
1611
|
+
spawns: "spawns";
|
|
1612
|
+
prompts: "prompts";
|
|
1613
|
+
}>>;
|
|
1614
|
+
total: z.ZodNumber;
|
|
1615
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
1616
|
+
profile: z.ZodString;
|
|
1617
|
+
count: z.ZodNumber;
|
|
1618
|
+
exits: z.ZodArray<z.ZodObject<{
|
|
1619
|
+
at: z.ZodString;
|
|
1620
|
+
line: z.ZodNumber;
|
|
1621
|
+
agentId: z.ZodString;
|
|
1622
|
+
name: z.ZodString;
|
|
1623
|
+
spawner: z.ZodString;
|
|
1624
|
+
lastAction: z.ZodString;
|
|
1625
|
+
spawnEventId: z.ZodNullable<z.ZodNumber>;
|
|
1626
|
+
}, z.core.$strip>>;
|
|
1627
|
+
}, z.core.$strip>>;
|
|
1628
|
+
}, z.core.$strip>;
|
|
1629
|
+
stalePrompts: z.ZodObject<{
|
|
1630
|
+
cites: z.ZodArray<z.ZodEnum<{
|
|
1631
|
+
exits: "exits";
|
|
1632
|
+
registrations: "registrations";
|
|
1633
|
+
routes: "routes";
|
|
1634
|
+
spawns: "spawns";
|
|
1635
|
+
prompts: "prompts";
|
|
1636
|
+
}>>;
|
|
1637
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
1638
|
+
agent: z.ZodString;
|
|
1639
|
+
at: z.ZodString;
|
|
1640
|
+
ageMin: z.ZodNumber;
|
|
1641
|
+
tool: z.ZodNullable<z.ZodString>;
|
|
1642
|
+
eventId: z.ZodNumber;
|
|
1643
|
+
resolutionEventId: z.ZodNullable<z.ZodNumber>;
|
|
1644
|
+
}, z.core.$strip>>;
|
|
1645
|
+
resolvedRows: z.ZodArray<z.ZodObject<{
|
|
1646
|
+
agent: z.ZodString;
|
|
1647
|
+
at: z.ZodString;
|
|
1648
|
+
ageMin: z.ZodNumber;
|
|
1649
|
+
tool: z.ZodNullable<z.ZodString>;
|
|
1650
|
+
eventId: z.ZodNumber;
|
|
1651
|
+
resolutionEventId: z.ZodNullable<z.ZodNumber>;
|
|
1652
|
+
}, z.core.$strip>>;
|
|
1653
|
+
}, z.core.$strip>;
|
|
1654
|
+
}, z.core.$strip>;
|
|
1655
|
+
type LivenessReport = z.infer<typeof livenessSchema>;
|
|
1656
|
+
/** Seats dark past DARK_MIN, routes that missed their recipient, unreported exits and agents stuck on a prompt. */
|
|
1657
|
+
declare function livenessReport(input: LivenessInput): LivenessReport;
|
|
1658
|
+
/** Each table's title names the JSON field its rows come from; the sources and the shared caveat close the report. */
|
|
1659
|
+
declare function renderLivenessText(report: LivenessReport): string;
|
|
1660
|
+
|
|
1661
|
+
/** Bump when a field is removed or changes meaning. Adding a field keeps the version. */
|
|
1662
|
+
declare const SESSION_TIMELINE_VERSION = 1;
|
|
1663
|
+
/** Idle time between two events that counts as a gap. */
|
|
1664
|
+
declare const TIMELINE_GAP_MIN_MS: number;
|
|
1665
|
+
/** Default cap on each message text. The byte offset still points at the full record. */
|
|
1666
|
+
declare const TIMELINE_TEXT_CAP = 4000;
|
|
1667
|
+
/** `prompt` is typed or sent text, `injected` is a harness block, `compaction` is a continuation summary, `none` is activity before any user message. */
|
|
1668
|
+
type TimelineTurnOrigin = "prompt" | "injected" | "compaction" | "none";
|
|
1669
|
+
/** `unknown` is a result whose source did not report an error state; `pending` has no result yet. */
|
|
1670
|
+
type TimelineToolOutcome = "success" | "error" | "unknown" | "pending";
|
|
1671
|
+
interface TimelineMessage {
|
|
1672
|
+
role: "user" | "assistant";
|
|
1673
|
+
/** Source order across the whole session; sort a turn's messages and tool calls by it to interleave them. */
|
|
1674
|
+
seq: number;
|
|
1675
|
+
atMs: number | null;
|
|
1676
|
+
text: string;
|
|
1677
|
+
/** True when `text` was cut at the cap. */
|
|
1678
|
+
truncated: boolean;
|
|
1679
|
+
/** Offset of the transcript line, for reading the full record. */
|
|
1680
|
+
byteOffset: number;
|
|
1681
|
+
}
|
|
1682
|
+
interface TimelineToolCall {
|
|
1683
|
+
/** The harness's own call id, unique within the session. */
|
|
1684
|
+
id: string;
|
|
1685
|
+
seq: number;
|
|
1686
|
+
turnIndex: number;
|
|
1687
|
+
name: string;
|
|
1688
|
+
family: ToolFamily;
|
|
1689
|
+
atMs: number | null;
|
|
1690
|
+
/** When the result arrived; null while pending. */
|
|
1691
|
+
endMs: number | null;
|
|
1692
|
+
/** Observed call-to-result span, not harness execution time. */
|
|
1693
|
+
durationMs: number | null;
|
|
1694
|
+
outcome: TimelineToolOutcome;
|
|
1695
|
+
errorMessage: string | null;
|
|
1696
|
+
/** One line naming what the call acted on: a path, a command, a pattern or a description. */
|
|
1697
|
+
inputSummary: string;
|
|
1698
|
+
filePath: string | null;
|
|
1699
|
+
sidechain: boolean;
|
|
1700
|
+
byteOffset: number;
|
|
1701
|
+
}
|
|
1702
|
+
/** Prompt-side counts are disjoint: `input` excludes cache reads and cache writes. */
|
|
1703
|
+
interface TimelineTokens {
|
|
1704
|
+
input: number;
|
|
1705
|
+
cacheRead: number;
|
|
1706
|
+
/** All cache writes, `cacheWrite5m + cacheWrite1h`. */
|
|
1707
|
+
cacheWrite: number;
|
|
1708
|
+
/** Writes at the 5m rate, including a total the source reported without a split. */
|
|
1709
|
+
cacheWrite5m: number;
|
|
1710
|
+
/** Writes at the 1h rate. */
|
|
1711
|
+
cacheWrite1h: number;
|
|
1712
|
+
output: number;
|
|
1713
|
+
}
|
|
1714
|
+
interface TimelineTurn {
|
|
1715
|
+
index: number;
|
|
1716
|
+
origin: TimelineTurnOrigin;
|
|
1717
|
+
/** The session-read injected-marker name when `origin` is `injected` or `compaction`. */
|
|
1718
|
+
injectedMarker: string | null;
|
|
1719
|
+
startMs: number | null;
|
|
1720
|
+
endMs: number | null;
|
|
1721
|
+
/** Idle time before this turn when it is `TIMELINE_GAP_MIN_MS` or more, else null. */
|
|
1722
|
+
gapBeforeMs: number | null;
|
|
1723
|
+
/** The message that opened the turn; null when `origin` is `none`. */
|
|
1724
|
+
user: TimelineMessage | null;
|
|
1725
|
+
assistant: TimelineMessage[];
|
|
1726
|
+
toolCalls: TimelineToolCall[];
|
|
1727
|
+
errorCount: number;
|
|
1728
|
+
tokens: TimelineTokens;
|
|
1729
|
+
costUsd: number;
|
|
1730
|
+
}
|
|
1731
|
+
/** One UTC clock minute that held activity. Minutes with none are omitted. */
|
|
1732
|
+
interface TimelineMinuteBucket {
|
|
1733
|
+
/** Start of the minute. */
|
|
1734
|
+
minuteMs: number;
|
|
1735
|
+
/** Messages, tool calls and tool results. */
|
|
1736
|
+
events: number;
|
|
1737
|
+
messages: number;
|
|
1738
|
+
toolCalls: number;
|
|
1739
|
+
errors: number;
|
|
1740
|
+
outputTokens: number;
|
|
1741
|
+
costUsd: number;
|
|
1742
|
+
/** Set on the first bucket after a gap. */
|
|
1743
|
+
gapBeforeMs: number | null;
|
|
1744
|
+
}
|
|
1745
|
+
/** An idle stretch. Time spent waiting on a tool call that later returned is not idle, so it is never a gap. */
|
|
1746
|
+
interface TimelineGap {
|
|
1747
|
+
startMs: number;
|
|
1748
|
+
endMs: number;
|
|
1749
|
+
durationMs: number;
|
|
1750
|
+
}
|
|
1751
|
+
/** One API request. Points are in source order and cumulative fields run over that order. */
|
|
1752
|
+
interface TimelineTokenPoint {
|
|
1753
|
+
atMs: number;
|
|
1754
|
+
turnIndex: number | null;
|
|
1755
|
+
model: string | null;
|
|
1756
|
+
/** The prompt size of this request: input plus cache read plus cache write. Null when the source omitted a count. */
|
|
1757
|
+
contextTokens: number | null;
|
|
1758
|
+
outputTokens: number;
|
|
1759
|
+
cumulativeOutputTokens: number;
|
|
1760
|
+
costUsd: number;
|
|
1761
|
+
cumulativeCostUsd: number;
|
|
1762
|
+
/** False when no price row covers the model; `costUsd` is then 0. */
|
|
1763
|
+
priced: boolean;
|
|
1764
|
+
/** True on the first request after a compaction. */
|
|
1765
|
+
afterCompaction: boolean;
|
|
1766
|
+
}
|
|
1767
|
+
interface CompactionMark {
|
|
1768
|
+
atMs: number | null;
|
|
1769
|
+
turnIndex: number | null;
|
|
1770
|
+
byteOffset: number;
|
|
1771
|
+
summary: string | null;
|
|
1772
|
+
summaryTruncated: boolean;
|
|
1773
|
+
}
|
|
1774
|
+
interface ModelRequests {
|
|
1775
|
+
model: string;
|
|
1776
|
+
requests: number;
|
|
1777
|
+
}
|
|
1778
|
+
interface TokenTimeline {
|
|
1779
|
+
/** `delta` has per-request points. A `snapshot` source reports running totals only: `points` is empty and nothing is priced, so every `costUsd` is 0. */
|
|
1780
|
+
basis: "delta" | "snapshot" | "unreported";
|
|
1781
|
+
points: TimelineTokenPoint[];
|
|
1782
|
+
compactions: CompactionMark[];
|
|
1783
|
+
/** Most requests first. */
|
|
1784
|
+
models: ModelRequests[];
|
|
1785
|
+
}
|
|
1786
|
+
interface ToolNameCount {
|
|
1787
|
+
name: string;
|
|
1788
|
+
family: ToolFamily;
|
|
1789
|
+
calls: number;
|
|
1790
|
+
errors: number;
|
|
1791
|
+
durationMs: number;
|
|
1792
|
+
}
|
|
1793
|
+
interface ToolFamilyCount {
|
|
1794
|
+
family: ToolFamily;
|
|
1795
|
+
calls: number;
|
|
1796
|
+
errors: number;
|
|
1797
|
+
/** Call start times, ascending, for `countAtOrBefore`. */
|
|
1798
|
+
atMs: number[];
|
|
1799
|
+
}
|
|
1800
|
+
interface TimelineToolBreakdown {
|
|
1801
|
+
/** Most calls first. */
|
|
1802
|
+
byName: ToolNameCount[];
|
|
1803
|
+
byFamily: ToolFamilyCount[];
|
|
1804
|
+
/** Every call start time, ascending. */
|
|
1805
|
+
atMs: number[];
|
|
1806
|
+
}
|
|
1807
|
+
interface TimelineFileTouch {
|
|
1808
|
+
path: string;
|
|
1809
|
+
access: "read" | "write";
|
|
1810
|
+
/** First touch of this path with this access. */
|
|
1811
|
+
atMs: number | null;
|
|
1812
|
+
calls: number;
|
|
1813
|
+
}
|
|
1814
|
+
interface TimelineFileBreakdown {
|
|
1815
|
+
/** One row per path and access, ordered by first touch. */
|
|
1816
|
+
touches: TimelineFileTouch[];
|
|
1817
|
+
readCount: number;
|
|
1818
|
+
writeCount: number;
|
|
1819
|
+
}
|
|
1820
|
+
interface TimelineError {
|
|
1821
|
+
callId: string;
|
|
1822
|
+
toolName: string;
|
|
1823
|
+
turnIndex: number;
|
|
1824
|
+
/** When the failing result arrived. */
|
|
1825
|
+
atMs: number | null;
|
|
1826
|
+
message: string;
|
|
1827
|
+
sidechain: boolean;
|
|
1828
|
+
}
|
|
1829
|
+
interface TimelineErrorBreakdown {
|
|
1830
|
+
/** Failed calls over all calls; 0 with no calls. */
|
|
1831
|
+
rate: number;
|
|
1832
|
+
items: TimelineError[];
|
|
1833
|
+
atMs: number[];
|
|
1834
|
+
}
|
|
1835
|
+
/** A subagent dispatch, from its tool call to that call's result. */
|
|
1836
|
+
interface TimelineAgentSpan {
|
|
1837
|
+
callId: string;
|
|
1838
|
+
label: string;
|
|
1839
|
+
startMs: number | null;
|
|
1840
|
+
endMs: number | null;
|
|
1841
|
+
outcome: TimelineToolOutcome;
|
|
1842
|
+
}
|
|
1843
|
+
interface TimelineTotals {
|
|
1844
|
+
turns: number;
|
|
1845
|
+
userMessages: number;
|
|
1846
|
+
assistantMessages: number;
|
|
1847
|
+
toolCalls: number;
|
|
1848
|
+
errors: number;
|
|
1849
|
+
compactions: number;
|
|
1850
|
+
/** API requests with usage. Null on a `snapshot` basis, which cannot count them. */
|
|
1851
|
+
requests: number | null;
|
|
1852
|
+
unpricedRequests: number;
|
|
1853
|
+
tokens: TimelineTokens;
|
|
1854
|
+
/** 0 on a `snapshot` basis, which has no per-request usage to price. */
|
|
1855
|
+
costUsd: number;
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Everything a session view reads, as plain JSON. Every `*Ms` field is epoch milliseconds,
|
|
1859
|
+
* so the model holds no time zone and a renderer picks one.
|
|
1860
|
+
*/
|
|
1861
|
+
interface SessionTimeline {
|
|
1862
|
+
version: typeof SESSION_TIMELINE_VERSION;
|
|
1863
|
+
sessionId: string | null;
|
|
1864
|
+
harness: string | null;
|
|
1865
|
+
startMs: number | null;
|
|
1866
|
+
endMs: number | null;
|
|
1867
|
+
durationMs: number;
|
|
1868
|
+
totals: TimelineTotals;
|
|
1869
|
+
turns: TimelineTurn[];
|
|
1870
|
+
buckets: TimelineMinuteBucket[];
|
|
1871
|
+
gaps: TimelineGap[];
|
|
1872
|
+
tokens: TokenTimeline;
|
|
1873
|
+
tools: TimelineToolBreakdown;
|
|
1874
|
+
files: TimelineFileBreakdown;
|
|
1875
|
+
errors: TimelineErrorBreakdown;
|
|
1876
|
+
agents: TimelineAgentSpan[];
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
interface SessionTimelineOptions {
|
|
1880
|
+
/** Idle time that counts as a gap. Defaults to `TIMELINE_GAP_MIN_MS`. */
|
|
1881
|
+
gapMinMs?: number;
|
|
1882
|
+
/** Cap on each message and compaction summary. Defaults to `TIMELINE_TEXT_CAP`. */
|
|
1883
|
+
maxTextChars?: number;
|
|
1884
|
+
/** Price rows for the cost series. Defaults to `PRICE_TABLE`. */
|
|
1885
|
+
prices?: readonly PriceRow[];
|
|
1886
|
+
}
|
|
1887
|
+
/** Storage-free fold for a streamed read: `add` each observation, then `result`, which returns a fresh copy each time. */
|
|
1888
|
+
declare class SessionTimelineAccumulator {
|
|
1889
|
+
private readonly turns;
|
|
1890
|
+
private readonly tokens;
|
|
1891
|
+
private readonly gapMinMs;
|
|
1892
|
+
private conversation;
|
|
1893
|
+
private startMs;
|
|
1894
|
+
private endMs;
|
|
1895
|
+
constructor(options?: SessionTimelineOptions);
|
|
1896
|
+
add(observation: NormalizedSessionObservation): void;
|
|
1897
|
+
result(): SessionTimeline;
|
|
1898
|
+
private claim;
|
|
1899
|
+
/** A record with no usable timestamp takes the latest one seen, so it still lands in order. */
|
|
1900
|
+
private clock;
|
|
1901
|
+
}
|
|
1902
|
+
/** The read model behind every session view: turns, minute buckets, the token and cost series, and tool, file and error breakdowns. */
|
|
1903
|
+
declare function buildSessionTimeline(observations: Iterable<NormalizedSessionObservation>, options?: SessionTimelineOptions): SessionTimeline;
|
|
1904
|
+
|
|
1905
|
+
/** How many of the ascending `sortedMs` are at or before `targetMs`, by binary search. */
|
|
1906
|
+
declare function countAtOrBefore(sortedMs: readonly number[], targetMs: number): number;
|
|
1907
|
+
|
|
1908
|
+
declare const reviewFillSchema: z.ZodObject<{
|
|
1909
|
+
window: z.ZodObject<{
|
|
1910
|
+
since: z.ZodNullable<z.ZodString>;
|
|
1911
|
+
until: z.ZodNullable<z.ZodString>;
|
|
1912
|
+
}, z.core.$strip>;
|
|
1913
|
+
unfilled: z.ZodNumber;
|
|
1914
|
+
unresolved: z.ZodNumber;
|
|
1915
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
1916
|
+
band: z.ZodString;
|
|
1917
|
+
model: z.ZodString;
|
|
1918
|
+
verdicts: z.ZodNumber;
|
|
1919
|
+
changesRequested: z.ZodNumber;
|
|
1920
|
+
changesRate: z.ZodNullable<z.ZodNumber>;
|
|
1921
|
+
verdictErrors: z.ZodNumber;
|
|
1922
|
+
errorRate: z.ZodNullable<z.ZodNumber>;
|
|
1923
|
+
}, z.core.$strip>>;
|
|
1924
|
+
}, z.core.$strip>;
|
|
1925
|
+
type ReviewFillReport = z.infer<typeof reviewFillSchema>;
|
|
1926
|
+
/** Review verdicts in the window by the reviewer's context fill when it issued them, and how often an approve was contradicted. */
|
|
1927
|
+
declare function reviewFillReport(db: Db, window: ReportWindow): ReviewFillReport;
|
|
1928
|
+
|
|
1929
|
+
export { ACTION_CLASSES, AGENT_LIFECYCLE, ALL_REPOS, type ActionCall, type ActionClass, type ActionRule, type AgentNameRow, BLOCKED_FLOW_SOURCES, BOOT_TOOL, type Band, type BlockedFlowInput, type BlockedFlowReport, type BlockedFlowSource, type BrokerEntry, CHANNEL_CLUSTER_MS, CONTEXT_BANDS, CONTEXT_RESET_TOKENS, COORDINATOR_MERGE_DEDUPE_REQUESTS, COORDINATOR_MIN_EPISODE_REQUESTS, COORDINATOR_WAVE_QUIET_REQUESTS, COST_REPORT_SECTIONS, type CacheTtlBucket, type CacheTtlWhatIf, type CompactionMark, type CostBucket, type CostReport, type CostReportOptions, type CostReportSection, type CycleParams, DARK_MIN, DEFAULT_ACTION_RULES, DEFAULT_CONFIGURED_K, DEFAULT_EPISODE_ROLES, DEFAULT_K_SWEEP, DEFAULT_MECHANICAL_CLASSES, DEFAULT_NO_ACTION_CLASSES, DEFAULT_REVIEWER_PRS, DEFAULT_REVIEWER_ROLE, DEFAULT_STANDING_ROLE, type DarkGap, type DenialRecord, type EpisodeInbound, type EpisodeInput, type EpisodeNames, type EpisodeRequest, type EpisodeRequestRow, type EpisodeSignal, GAP_BANDS, HEURISTIC_VERSIONS, type HandoffCohort, type HandoffOptions, type HandoffRequestRow, type HandoffSession, type HandoffTeleport, type HandoffThreshold, type Heuristic, type HumanRole, IDLE_GAP_MS, type IdleSlotRow, type KSweep, LIST_PRICE_CAVEAT, LIVENESS_SOURCES, type LastEventRecord, type LatencyRow, type LatencyStats, type LivenessInput, type LivenessReport, type LivenessSource, type MechanicalShare, type MergeOutcome, type MergeStatus, type ModelRequests, POOLED_REVIEWERS, PRICE_TABLE, PRICE_TABLE_VERSION, PROFILE_ROLES, PROMPT_STALE_MIN, type ParsedVerdict, type PriceRow, type PricedRequest, type PullState, REBUILD_GAP_BANDS, type ReportScope, type ReportWindow, type RequestTokens, type ReviewFillReport, type ReviewerComparison, type RoleActions, type RouteFailureRow, type RouteMiss, type RouteMissKind, SESSION_TIMELINE_VERSION, STANDING_PEER_MIN_ASSIGNMENTS, STANDING_PEER_MIN_HOURS, type SeatJournal, type SessionClass, type SessionClassification, type SessionFacts, type SessionOrigin, type SessionTimeline, SessionTimelineAccumulator, type SessionTimelineOptions, type SlotTick, type SpawnRecord, type StalePromptRow, TELEPORT_EVENT, TICK_HOLD_MAX_MIN, TIMELINE_GAP_MIN_MS, TIMELINE_TEXT_CAP, TOKEN_CLASSES, type TaskInitiative, type TeleportEvent, type TimelineAgentSpan, type TimelineError, type TimelineErrorBreakdown, type TimelineFileBreakdown, type TimelineFileTouch, type TimelineGap, type TimelineMessage, type TimelineMinuteBucket, type TimelineTokenPoint, type TimelineTokens, type TimelineToolBreakdown, type TimelineToolCall, type TimelineToolOutcome, type TimelineTotals, type TimelineTurn, type TimelineTurnOrigin, type TokenClass, type TokenTimeline, type ToolFamilyCount, type ToolNameCount, type TtlRequestRow, UNKNOWN_PROFILE, UNSTATED_REASON, type UnreportedExit, type UnreportedExitRow, type VerdictRecord, WAKE_FROM_KINDS, type WakeCauseBucket, type WakeCauseEpisodes, type WakeEpisode, type WakeEpisodes, type WakeEventRow, type WakeFromKind, type WakeGapCell, type WakePair, type WorkerFacts, type WorkerRole, type WrittenEpisodes, assignmentCount, bandOf, blockedFlowReport, blockedFlowSchema, buildEpisodes, buildSessionTimeline, buildWakeEpisodes, cacheTtlReport, cacheTtlWhatIf, cacheTtlWhatIfSchema, classifyDeniedAction, classifyRequest, classifySession, contextBand, costPerRequest, costReport, costReportSchema, countAtOrBefore, countMisses, darkGaps, dedupeDenials, episodeNames, findPrice, gapBand, handoffThreshold, handoffThresholdSchema, heuristicFor, idleSlotMinutes, initiativeFromCwd, isBootAction, latencyStats, latencyStatsSchema, livenessReport, livenessSchema, mergeOutcomes, parseBrokerLog, parseDenials, parseSeatJournal, parseTeleportEvents, parseVerdict, prKey, priceRequest, readEpisodeInput, readRequestToolCalls, readTtlRows, renderBlockedFlowText, renderCacheTtlText, renderCostReportSections, renderCostReportText, renderLivenessText, reviewFillReport, reviewFillSchema, roleFromProfile, routeFailureRows, routeMisses, scopeFilter, sessionInitiative, sessionRole, stalePromptRows, summarizeWakeEpisodes, sweepK, unreportedExitRows, wakeEpisodesSchema, workerRole, writeEpisodes };
|