@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/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
|