@titan-design/session-analytics 0.6.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 +271 -1
- package/dist/index.js +616 -2
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@ reads a session graph through a read-only connection and never writes it; `write
|
|
|
6
6
|
the one function here that writes.
|
|
7
7
|
|
|
8
8
|
Tier 2 of the titan-platform DAG. It depends on `@titan-design/session-graph` for table
|
|
9
|
-
names
|
|
9
|
+
names, on `@titan-design/store-sqlite` for the `Db` type, and on `@titan-design/session-read`
|
|
10
|
+
and `@titan-design/agent-protocol` for the observations the session timeline folds. `zod` is a
|
|
11
|
+
peer dependency.
|
|
10
12
|
|
|
11
13
|
```ts
|
|
12
14
|
import { classifySession, contextBand, priceRequest } from "@titan-design/session-analytics";
|
|
@@ -63,6 +65,9 @@ priceRequest(
|
|
|
63
65
|
segmentation, written through session-graph's `replaceEpisodes`.
|
|
64
66
|
- `initiativeFromCwd(cwd)`, `sessionInitiative(tasks, cwd)` — a session's initiative from its
|
|
65
67
|
task edges, falling back to the `cf_analyze.py` cwd rule.
|
|
68
|
+
- `buildSessionTimeline(observations, options?)`, `SessionTimelineAccumulator`,
|
|
69
|
+
`countAtOrBefore(sortedMs, targetMs)` and the `SessionTimeline` types — the read model behind
|
|
70
|
+
a session view; see "Session timeline" below.
|
|
66
71
|
|
|
67
72
|
```ts
|
|
68
73
|
import { openDatabase } from "@titan-design/store-sqlite";
|
|
@@ -72,6 +77,57 @@ const report = costReport(openDatabase(graphPath, { readonly: true }), { days: 7
|
|
|
72
77
|
process.stdout.write(renderCostReportText(report));
|
|
73
78
|
```
|
|
74
79
|
|
|
80
|
+
## Session timeline
|
|
81
|
+
|
|
82
|
+
`buildSessionTimeline(observations, { gapMinMs, maxTextChars, prices })` is a pure fold over
|
|
83
|
+
session-read's normalized observations, so it reads Claude Code and Codex sessions alike and
|
|
84
|
+
needs no graph. It returns one `SessionTimeline`, plain JSON that a daemon can send as it is:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { claudeSourceFromPath, readSessionObservations } from "@titan-design/session-read";
|
|
88
|
+
import { SessionTimelineAccumulator, countAtOrBefore } from "@titan-design/session-analytics";
|
|
89
|
+
|
|
90
|
+
const accumulator = new SessionTimelineAccumulator();
|
|
91
|
+
for await (const observation of readSessionObservations(claudeSourceFromPath(file, namespace))) {
|
|
92
|
+
accumulator.add(observation);
|
|
93
|
+
}
|
|
94
|
+
const timeline = accumulator.result();
|
|
95
|
+
countAtOrBefore(timeline.tools.atMs, scrubbedMs); // tool calls made by that time
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| Field | What it holds |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `turns` | `TimelineTurn[]`. A user message opens a turn. Each has `user`, `assistant` messages, `toolCalls`, `errorCount`, `tokens`, `costUsd` and `gapBeforeMs`. Sort a turn's messages and tool calls by `seq` to interleave them. |
|
|
101
|
+
| `buckets` | `TimelineMinuteBucket[]`, one per clock minute that held activity, with event, message, tool call and error counts, output tokens and cost. |
|
|
102
|
+
| `gaps` | `TimelineGap[]`: each idle stretch of `TIMELINE_GAP_MIN_MS` (10 minutes) or more. The bucket and the turn after a gap carry `gapBeforeMs`. The wait on a tool call that later returned is not idle and is never a gap. |
|
|
103
|
+
| `tokens` | `TokenTimeline`: one `TimelineTokenPoint` per API request (prompt size, output, cost, running totals, `afterCompaction`), the `CompactionMark`s and the models used. |
|
|
104
|
+
| `tools`, `files`, `errors`, `agents` | Calls by name and by session-read tool family, first touch of each file by access, failed calls, and subagent dispatch spans. Each carries ascending `atMs` arrays for `countAtOrBefore`. |
|
|
105
|
+
| `totals` | Counts, the four disjoint token classes and the cost. |
|
|
106
|
+
|
|
107
|
+
Every `*Ms` field is epoch milliseconds. The model holds no time zone, so a session that
|
|
108
|
+
crosses midnight is one unbroken run of buckets and the renderer picks the zone. Text is capped
|
|
109
|
+
at `TIMELINE_TEXT_CAP` characters with `truncated` set, and each message and tool call keeps the
|
|
110
|
+
`byteOffset` of its transcript line for reading the full record. `SESSION_TIMELINE_VERSION`
|
|
111
|
+
changes when a field is removed or changes meaning.
|
|
112
|
+
|
|
113
|
+
A turn's `origin` is `prompt`, `injected` (a harness block such as a channel message or a task
|
|
114
|
+
notification, named in `injectedMarker`), `compaction` (a continuation summary) or `none`
|
|
115
|
+
(activity before any user message). It is read from the head of the opening text with
|
|
116
|
+
session-read's injected markers, so a typed prompt that the harness prefixed with a reminder
|
|
117
|
+
block reads as `injected`.
|
|
118
|
+
|
|
119
|
+
Cost comes from `priceRequest` over `PRICE_TABLE`. The normalized usage has no 5m and 1h split
|
|
120
|
+
of cache writes, so every cache write is priced at the 5m rate and the figure under-reads a
|
|
121
|
+
session that wrote 1h caches. A source that reports only running totals (`basis: "snapshot"`)
|
|
122
|
+
gets token totals and no points, and nothing is priced: `totals.costUsd` and every turn's
|
|
123
|
+
`costUsd` are 0, and `totals.requests` is null.
|
|
124
|
+
|
|
125
|
+
Claude Code writes one compaction as a boundary line and then a summary line. The timeline
|
|
126
|
+
reports it as one `CompactionMark`, at the boundary's time, with the summary.
|
|
127
|
+
|
|
128
|
+
`result()` returns a fresh copy each time, so a result is safe to keep while more observations
|
|
129
|
+
are added. `ToolFamily`, the type of a tool call's `family`, is re-exported from session-read.
|
|
130
|
+
|
|
75
131
|
## Wake episodes
|
|
76
132
|
|
|
77
133
|
An episode is one arrival that wakes a session and the requests after it, up to the next
|
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 {
|
|
@@ -1656,4 +1658,272 @@ declare function livenessReport(input: LivenessInput): LivenessReport;
|
|
|
1656
1658
|
/** Each table's title names the JSON field its rows come from; the sources and the shared caveat close the report. */
|
|
1657
1659
|
declare function renderLivenessText(report: LivenessReport): string;
|
|
1658
1660
|
|
|
1659
|
-
|
|
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 };
|