context-mode 1.0.166 → 1.0.167
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +6 -4
- package/build/adapters/codex/usage.d.ts +107 -0
- package/build/adapters/codex/usage.js +227 -0
- package/build/adapters/gemini-cli/hooks.d.ts +7 -1
- package/build/adapters/gemini-cli/hooks.js +9 -1
- package/build/adapters/gemini-cli/index.js +11 -0
- package/build/adapters/kimi/paths.d.ts +20 -0
- package/build/adapters/kimi/paths.js +41 -1
- package/build/adapters/kimi/usage.d.ts +82 -0
- package/build/adapters/kimi/usage.js +217 -0
- package/build/adapters/omp/plugin.d.ts +6 -0
- package/build/adapters/omp/plugin.js +87 -2
- package/build/adapters/omp/usage.d.ts +49 -0
- package/build/adapters/omp/usage.js +110 -0
- package/build/adapters/openclaw/plugin.d.ts +10 -0
- package/build/adapters/openclaw/plugin.js +57 -0
- package/build/adapters/openclaw/usage.d.ts +34 -0
- package/build/adapters/openclaw/usage.js +52 -0
- package/build/adapters/opencode/plugin.d.ts +17 -0
- package/build/adapters/opencode/plugin.js +40 -1
- package/build/adapters/pi/extension.js +34 -1
- package/build/adapters/qwen-code/index.js +23 -1
- package/build/adapters/qwen-code/usage.d.ts +90 -0
- package/build/adapters/qwen-code/usage.js +222 -0
- package/build/session/db.d.ts +11 -0
- package/build/session/db.js +33 -0
- package/build/session/extract.d.ts +208 -0
- package/build/session/extract.js +670 -43
- package/build/session/model-prices.json +429 -0
- package/build/session/pricing.d.ts +64 -0
- package/build/session/pricing.js +151 -0
- package/cli.bundle.mjs +62 -62
- package/configs/antigravity-cli/plugin.json +1 -1
- package/configs/copilot-cli/.github/plugin/plugin.json +1 -1
- package/configs/gemini-cli/settings.json +11 -0
- package/hooks/codex/stop.mjs +91 -4
- package/hooks/gemini-cli/aftermodel.mjs +70 -0
- package/hooks/kimi/stop.mjs +74 -3
- package/hooks/qwen-code/platform.mjs +1 -0
- package/hooks/qwen-code/stop.mjs +168 -0
- package/hooks/session-db.bundle.mjs +7 -7
- package/hooks/session-extract.bundle.mjs +3 -2
- package/hooks/session-loaders.mjs +9 -1
- package/hooks/stop.mjs +35 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +90 -90
|
@@ -22,6 +22,19 @@ export interface SessionEvent {
|
|
|
22
22
|
* `Fetched and indexed N sections (XKB)` preamble.
|
|
23
23
|
*/
|
|
24
24
|
bytes_avoided?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Optional structured cost/usage fields (Wave 2b). Emitted by
|
|
27
|
+
* extractAgentUsage alongside the colon-string `data` so the forward
|
|
28
|
+
* envelope can spread them to the platform as typed columns instead of an
|
|
29
|
+
* opaque blob. Present only when the source signal is present; cost_usd is
|
|
30
|
+
* omitted on a price miss or a zero-token turn.
|
|
31
|
+
*/
|
|
32
|
+
model_id?: string;
|
|
33
|
+
input_tokens?: number;
|
|
34
|
+
output_tokens?: number;
|
|
35
|
+
cache_read_tokens?: number;
|
|
36
|
+
cache_creation_tokens?: number;
|
|
37
|
+
cost_usd?: number;
|
|
25
38
|
}
|
|
26
39
|
export interface ToolCall {
|
|
27
40
|
toolName: string;
|
|
@@ -43,6 +56,201 @@ export interface HookInput {
|
|
|
43
56
|
is_error?: boolean;
|
|
44
57
|
};
|
|
45
58
|
}
|
|
59
|
+
/** Input shape `buildAgentUsageEvent` consumes — re-exported for parser typing. */
|
|
60
|
+
export interface AgentUsageCounts {
|
|
61
|
+
model_id: string;
|
|
62
|
+
input_tokens: number;
|
|
63
|
+
output_tokens: number;
|
|
64
|
+
cache_creation_tokens: number;
|
|
65
|
+
cache_read_tokens: number;
|
|
66
|
+
native_cost_usd?: number | null;
|
|
67
|
+
}
|
|
68
|
+
export { parseKimiUsage, extractKimiUsageSince } from "../adapters/kimi/usage.js";
|
|
69
|
+
export { parseQwenUsage, extractQwenUsageSince } from "../adapters/qwen-code/usage.js";
|
|
70
|
+
/**
|
|
71
|
+
* Pi (oh-my-pi) per-turn usage parser.
|
|
72
|
+
*
|
|
73
|
+
* Maps a Pi `turn_end` payload (`{ message: AssistantMessage }`) to the
|
|
74
|
+
* `buildAgentUsageEvent` input shape, or null when there is nothing to record.
|
|
75
|
+
*
|
|
76
|
+
* Field provenance (adapter-matrix/pi.md @320261f + cited refs):
|
|
77
|
+
* - usage: AssistantMessage.usage (ai/src/types.ts:521 -> catalog/src/types.ts:100-145)
|
|
78
|
+
* - model_id: AssistantMessage.model (ai/src/types.ts:510; kept "provider/model" — builder normalizes)
|
|
79
|
+
* - input: Usage.input -> input_tokens
|
|
80
|
+
* - output: Usage.output -> output_tokens
|
|
81
|
+
* - cacheWrite: Usage.cacheWrite -> cache_creation_tokens
|
|
82
|
+
* - cacheRead: Usage.cacheRead -> cache_read_tokens
|
|
83
|
+
* - native USD: Usage.cost.total -> native_cost_usd (HIGH confidence; no price-table needed)
|
|
84
|
+
*
|
|
85
|
+
* The event is per-turn incremental (per-response usage; anthropic.ts:1893-1901;
|
|
86
|
+
* "for the turn" catalog/types.ts:103), so each turn_end maps to exactly one
|
|
87
|
+
* agent_usage event with no cross-turn accumulation.
|
|
88
|
+
*
|
|
89
|
+
* Algorithmic + null-safe, NO regex. Accepts either the full TurnEndEvent
|
|
90
|
+
* (`{ message }`) or a bare AssistantMessage (`{ usage, model }`) so callers
|
|
91
|
+
* can pass `event` or `event.message` interchangeably. Returns null when the
|
|
92
|
+
* payload is not an assistant message, carries no usage object, or every token
|
|
93
|
+
* bucket is zero/absent (an all-zero turn emits no event — matches
|
|
94
|
+
* buildAgentUsageEvent's own zero->null contract).
|
|
95
|
+
*/
|
|
96
|
+
export declare function parsePiUsage(payload: unknown): AgentUsageCounts | null;
|
|
97
|
+
/**
|
|
98
|
+
* openclaw `model.usage` diagnostic-event capture — parseOpenclawUsage.
|
|
99
|
+
*
|
|
100
|
+
* openclaw exposes a first-class `model.usage` diagnostic event
|
|
101
|
+
* (`DiagnosticUsageEvent`, refs/platforms/openclaw/src/infra/diagnostic-events.ts:18-47),
|
|
102
|
+
* emitted once per turn and consumed via `onDiagnosticEvent(listener)`
|
|
103
|
+
* (diagnostic-events.ts:1156) — the same bus the first-party diagnostics-otel /
|
|
104
|
+
* diagnostics-prometheus extensions read.
|
|
105
|
+
*
|
|
106
|
+
* Field mapping (openclaw → AgentUsageCounts):
|
|
107
|
+
* evt.usage.input → input_tokens
|
|
108
|
+
* evt.usage.output → output_tokens
|
|
109
|
+
* evt.usage.cacheWrite→ cache_creation_tokens (cache-creation)
|
|
110
|
+
* evt.usage.cacheRead → cache_read_tokens (cache-read)
|
|
111
|
+
* evt.costUsd → native_cost_usd (pre-computed via estimateUsageCost,
|
|
112
|
+
* agent-runner.ts:1995 — preferred over catalog)
|
|
113
|
+
* evt.model → model_id
|
|
114
|
+
*
|
|
115
|
+
* CRITICAL: read `evt.usage` (the PER-TURN TOTAL — "Last Turn Total"
|
|
116
|
+
* agent-runner.ts:943), NEVER `evt.lastCallUsage` (the last-model-call DELTA,
|
|
117
|
+
* diagnostic-events.ts:34-40). Summing both would double-count.
|
|
118
|
+
*
|
|
119
|
+
* Returns AgentUsageCounts (the buildAgentUsageEvent input shape) or null when
|
|
120
|
+
* the event is not a usage event / carries no usage / sums to zero. Pure,
|
|
121
|
+
* null-safe, algorithmic — NO regex.
|
|
122
|
+
*/
|
|
123
|
+
export declare function parseOpenclawUsage(payload: unknown): AgentUsageCounts | null;
|
|
124
|
+
/**
|
|
125
|
+
* opencode per-turn usage parser.
|
|
126
|
+
*
|
|
127
|
+
* Ground truth: context-mode-platform/docs/prds/2026-06-paid-observability/
|
|
128
|
+
* adapter-matrix/opencode.md. opencode tracks usage per *assistant message*; the
|
|
129
|
+
* usage-bearing payload reaches a plugin via the `message.updated` bus event,
|
|
130
|
+
* whose `event.properties.info` is the full Message. The assistant token shape
|
|
131
|
+
* (refs platforms/opencode .../session/message.ts) is:
|
|
132
|
+
* info.tokens = { input, output, reasoning, cache: { read, write } }
|
|
133
|
+
* info.cost = USD cost for this message
|
|
134
|
+
* info.modelID / info.providerID (older refs may expose a single info.model)
|
|
135
|
+
*
|
|
136
|
+
* Field mapping (refs message.ts):
|
|
137
|
+
* tokens.input -> input_tokens
|
|
138
|
+
* tokens.output -> output_tokens
|
|
139
|
+
* tokens.cache.read -> cache_read_tokens
|
|
140
|
+
* tokens.cache.write -> cache_creation_tokens
|
|
141
|
+
* modelID/providerID -> model_id (`${providerID}/${modelID}` when both present)
|
|
142
|
+
* cost -> native_cost_usd
|
|
143
|
+
*
|
|
144
|
+
* LAST-STEP-SNAPSHOT CAVEAT (refs processor.ts:717-718): message-level
|
|
145
|
+
* `.tokens` is OVERWRITTEN every step-finish, so it holds the LAST step's usage
|
|
146
|
+
* — not the turn total. `.cost`, however, ACCUMULATES (`cost += usage.cost`) and
|
|
147
|
+
* is the correct cumulative turn cost. We therefore pass `info.cost` through as
|
|
148
|
+
* native_cost_usd so the billed $ is exact even though the token snapshot is
|
|
149
|
+
* imprecise; the token columns remain best-effort (last-step) telemetry. A true
|
|
150
|
+
* turn-total token sum would require summing per-step Step.Ended parts, which the
|
|
151
|
+
* `message.updated` payload does not carry — out of scope for this snapshot-based
|
|
152
|
+
* capture.
|
|
153
|
+
*
|
|
154
|
+
* Accepts either the bus event (`{ properties: { info } }`), the wrapped
|
|
155
|
+
* `{ event: { properties: { info } } }`, or the bare Message (`info`) so the
|
|
156
|
+
* caller can hand us whatever the SDK surfaces. NO regex — pure algorithmic,
|
|
157
|
+
* null-safe traversal. Returns null when the payload is not an assistant
|
|
158
|
+
* message, carries no tokens object, or every token bucket is zero/absent
|
|
159
|
+
* (mirrors buildAgentUsageEvent's zero->null contract).
|
|
160
|
+
*/
|
|
161
|
+
export declare function parseOpencodeUsage(payload: unknown): AgentUsageCounts | null;
|
|
162
|
+
/**
|
|
163
|
+
* Build a structured `agent_usage` event from summed per-model token counts.
|
|
164
|
+
* Emits the colon-string `data` (human/debug + back-compat) AND the structured
|
|
165
|
+
* top-level fields the forward envelope spreads to the platform. cost_usd via
|
|
166
|
+
* the pricing catalog — omitted on a price miss. Returns null when every token
|
|
167
|
+
* bucket is zero/absent (so an all-zero model emits no event).
|
|
168
|
+
*/
|
|
169
|
+
export declare function buildAgentUsageEvent(counts: {
|
|
170
|
+
model_id: string;
|
|
171
|
+
input_tokens: number;
|
|
172
|
+
output_tokens: number;
|
|
173
|
+
cache_creation_tokens: number;
|
|
174
|
+
cache_read_tokens: number;
|
|
175
|
+
/**
|
|
176
|
+
* Provider-supplied USD cost for this turn. When a finite number, it is
|
|
177
|
+
* preferred over the catalog computation (openclaw / pi / omp / opencode
|
|
178
|
+
* ship a native cost — trust the source over our price table). Omit/null to
|
|
179
|
+
* derive cost_usd from the pricing catalog.
|
|
180
|
+
*/
|
|
181
|
+
native_cost_usd?: number | null;
|
|
182
|
+
}): SessionEvent | null;
|
|
183
|
+
/**
|
|
184
|
+
* gemini-cli AfterModel usage capture — parse ONE AfterModel hook payload into
|
|
185
|
+
* a builder `agent_usage` event (or null). Pure, null-safe, struct-only — NO regex.
|
|
186
|
+
*
|
|
187
|
+
* Refs (docs/prds/2026-06-paid-observability/adapter-matrix/gemini-cli.md):
|
|
188
|
+
* - AfterModel fires per model call inside the gemini-cli stream loop
|
|
189
|
+
* (geminiChat.ts:1213); the hook input carries `llm_request` + `llm_response`
|
|
190
|
+
* (hooks/types.ts:692-695).
|
|
191
|
+
* - `llm_response.usageMetadata` exposes promptTokenCount / candidatesTokenCount
|
|
192
|
+
* / totalTokenCount (hookTranslator.ts:60-64).
|
|
193
|
+
* - model_id = `response.modelVersion || req.model` (loggingContentGenerator.ts:405,553).
|
|
194
|
+
*
|
|
195
|
+
* Mapping → builder shape:
|
|
196
|
+
* promptTokenCount → input_tokens
|
|
197
|
+
* candidatesTokenCount → output_tokens
|
|
198
|
+
* thoughtsTokenCount → ADDED into output_tokens (Gemini bills reasoning as output)
|
|
199
|
+
* cachedContentTokenCount → cache_read_tokens (when present)
|
|
200
|
+
* model_id → response.modelVersion || llm_request.model
|
|
201
|
+
*
|
|
202
|
+
* CAVEAT — the DECOUPLED AfterModel payload (hookTranslator.ts:60-64) forwards
|
|
203
|
+
* only prompt/candidates/total and DROPS cachedContentTokenCount +
|
|
204
|
+
* thoughtsTokenCount. We map those two defensively WHEN PRESENT (richer payload
|
|
205
|
+
* variant / future fix / OTel-fed input) but never depend on them — the common
|
|
206
|
+
* case is input+output only. For full cached/thoughts fidelity the OTel
|
|
207
|
+
* `api_response` exporter or the chat-recording JSON is the source of record.
|
|
208
|
+
*
|
|
209
|
+
* MULTI-CALL TURNS — one user turn that triggers tool calls spans MULTIPLE
|
|
210
|
+
* model calls, each AfterModel cumulative within itself. This fn emits ONE
|
|
211
|
+
* priced event PER AfterModel call (each call is one billed round-trip).
|
|
212
|
+
* Per-userPromptId summation into a single per-turn total is DEFERRED — emitting
|
|
213
|
+
* per-call never double-counts, since each call's usageMetadata is the
|
|
214
|
+
* authoritative total for that call.
|
|
215
|
+
*/
|
|
216
|
+
export declare function parseGeminiUsage(afterModelPayload: unknown): SessionEvent | null;
|
|
217
|
+
/**
|
|
218
|
+
* claude-code MAIN-turn usage capture — the dominant-spend path the Task
|
|
219
|
+
* subagent capture (extractAgentUsage) misses. Parses the session transcript
|
|
220
|
+
* JSONL char-algorithmically (NO regex): each `type:"assistant"` line carries
|
|
221
|
+
* `message.usage` + `message.model`, and usage is a per-turn DELTA, so summing
|
|
222
|
+
* the assistant turns per model = the exact billed total. `isSidechain:true`
|
|
223
|
+
* lines are Task-subagent sidechains written to a SEPARATE transcript (refs:
|
|
224
|
+
* sessionStorage.ts:1042) — excluding them keeps the main-turn sum from
|
|
225
|
+
* double-counting the separate Task-subagent capture. Emits one structured
|
|
226
|
+
* `agent_usage` event per distinct model.
|
|
227
|
+
*/
|
|
228
|
+
export declare function extractTranscriptUsage(transcript: string): SessionEvent[];
|
|
229
|
+
/**
|
|
230
|
+
* Cursor-aware variant of extractTranscriptUsage for the Stop hook.
|
|
231
|
+
*
|
|
232
|
+
* The transcript grows every turn and the forward loop forwards ALL passed
|
|
233
|
+
* events unconditionally, so re-running extractTranscriptUsage on the whole
|
|
234
|
+
* transcript each Stop would double-count every prior turn. This walks only
|
|
235
|
+
* the turns NEW since the last Stop, keyed by a per-session high-water cursor
|
|
236
|
+
* (the `uuid` of the last assistant turn seen).
|
|
237
|
+
*
|
|
238
|
+
* - sinceUuid null/empty → process ALL non-sidechain assistant turns.
|
|
239
|
+
* - sinceUuid found → process only turns AFTER it (exclusive).
|
|
240
|
+
* - sinceUuid set but NOT found (transcript compaction dropped it) → process
|
|
241
|
+
* ONLY THE LAST non-sidechain assistant turn. Bounded by design: we never
|
|
242
|
+
* re-emit the whole history when the cursor falls off the front.
|
|
243
|
+
*
|
|
244
|
+
* `cursor` returns the uuid of the LAST non-sidechain assistant turn in the
|
|
245
|
+
* transcript (whether or not it carried usage), so the next Stop resumes
|
|
246
|
+
* exactly past it. When the transcript has no such turn, the input cursor is
|
|
247
|
+
* returned unchanged. Same char-algorithmic JSONL parse (NO regex), same
|
|
248
|
+
* sidechain exclusion, same buildAgentUsageEvent emission path.
|
|
249
|
+
*/
|
|
250
|
+
export declare function extractTranscriptUsageSince(transcript: string, sinceUuid: string | null): {
|
|
251
|
+
events: SessionEvent[];
|
|
252
|
+
cursor: string | null;
|
|
253
|
+
};
|
|
46
254
|
/** Reset error-resolution state (for testing). */
|
|
47
255
|
export declare function resetErrorResolutionState(): void;
|
|
48
256
|
/** Reset iteration-loop state (for testing). */
|