sidekick-shared 0.28.3 → 0.29.1
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/CHANGELOG.md +86 -0
- package/README.md +188 -27
- package/dist/aggregation/EventAggregator.d.ts +19 -0
- package/dist/aggregation/EventAggregator.js +174 -35
- package/dist/aggregation/snapshot.d.ts +37 -8
- package/dist/aggregation/snapshot.js +31 -9
- package/dist/aggregation/types.d.ts +13 -0
- package/dist/authStatus.d.ts +54 -0
- package/dist/authStatus.js +91 -0
- package/dist/browser.d.ts +16 -6
- package/dist/browser.js +24 -2
- package/dist/codex.d.ts +23 -0
- package/dist/codex.js +44 -0
- package/dist/codexProfiles.d.ts +1 -0
- package/dist/codexProfiles.js +8 -11
- package/dist/context/sessionContext.js +4 -0
- package/dist/esm/aggregation/EventAggregator.js +174 -35
- package/dist/esm/aggregation/snapshot.js +31 -9
- package/dist/esm/authStatus.js +87 -0
- package/dist/esm/browser.js +5 -2
- package/dist/esm/codex.js +18 -0
- package/dist/esm/codexProfiles.js +8 -11
- package/dist/esm/context/sessionContext.js +4 -0
- package/dist/esm/formatters/toolSummary.js +4 -1
- package/dist/esm/formatting.js +10 -1
- package/dist/esm/index.js +11 -6
- package/dist/esm/modelCatalog.js +7 -5
- package/dist/esm/modelContext.js +4 -3
- package/dist/esm/modelInfo.js +425 -47
- package/dist/esm/node.js +9 -3
- package/dist/esm/observedContextWindows.js +2 -1
- package/dist/esm/ownKey.js +26 -0
- package/dist/esm/parsers/codexParser.js +351 -54
- package/dist/esm/parsers/codexRolloutOrigin.js +107 -0
- package/dist/esm/parsers/openCodeParser.js +85 -22
- package/dist/esm/parsers/subagentScanner.js +33 -12
- package/dist/esm/parsers/subagentTraceParser.js +97 -37
- package/dist/esm/pricing.js +18 -0
- package/dist/esm/pricingCatalog.js +17 -9
- package/dist/esm/promptHistory.js +66 -4
- package/dist/esm/providerFailure.js +124 -3
- package/dist/esm/providers/claudeCode.js +10 -2
- package/dist/esm/providers/codex.js +84 -62
- package/dist/esm/providers/codexDatabase.js +3 -19
- package/dist/esm/providers/codexRollouts.js +24 -1
- package/dist/esm/providers/openCode.js +9 -17
- package/dist/esm/report/htmlReportGenerator.js +42 -5
- package/dist/esm/report/transcriptParser.js +13 -11
- package/dist/esm/schemas/providerFailure.js +3 -1
- package/dist/esm/schemas/sessionEvent.js +35 -14
- package/dist/esm/schemas/transcript.js +4 -0
- package/dist/esm/sessionPromptHistory.js +2 -2
- package/dist/esm/statusline/payload.js +9 -0
- package/dist/esm/subagentSpawn.js +163 -0
- package/dist/esm/testing/credentialGuard.js +87 -5
- package/dist/esm/toolCallOrigins.js +310 -0
- package/dist/esm/transcript.js +46 -3
- package/dist/esm/turns/assistantTurn.js +3 -2
- package/dist/esm/usage/claudeUsageDedupe.js +68 -0
- package/dist/esm/usage/usageEvents.js +146 -17
- package/dist/esm/usage/usageReports.js +39 -6
- package/dist/esm/watchers/eventBridge.js +15 -0
- package/dist/esm/watchers/factory.js +5 -3
- package/dist/esm/watchers/jsonlTail.js +442 -58
- package/dist/esm/watchers/jsonlWatcher.js +51 -4
- package/dist/esm/watchers/providerReaderWatcher.js +13 -0
- package/dist/esm/zaiQuota.js +2 -1
- package/dist/formatters/toolSummary.js +4 -1
- package/dist/formatting.d.ts +26 -1
- package/dist/formatting.js +11 -1
- package/dist/index.d.ts +22 -11
- package/dist/index.js +44 -12
- package/dist/modelCatalog.js +7 -5
- package/dist/modelContext.js +4 -3
- package/dist/modelInfo.d.ts +185 -16
- package/dist/modelInfo.js +434 -49
- package/dist/node.d.ts +16 -5
- package/dist/node.js +33 -2
- package/dist/observedContextWindows.js +2 -1
- package/dist/ownKey.d.ts +16 -0
- package/dist/ownKey.js +30 -0
- package/dist/parsers/codexParser.d.ts +118 -0
- package/dist/parsers/codexParser.js +352 -54
- package/dist/parsers/codexRolloutOrigin.d.ts +49 -0
- package/dist/parsers/codexRolloutOrigin.js +111 -0
- package/dist/parsers/openCodeParser.d.ts +38 -0
- package/dist/parsers/openCodeParser.js +88 -22
- package/dist/parsers/subagentScanner.d.ts +19 -6
- package/dist/parsers/subagentScanner.js +33 -12
- package/dist/parsers/subagentTraceParser.d.ts +25 -5
- package/dist/parsers/subagentTraceParser.js +97 -37
- package/dist/pricing.d.ts +22 -0
- package/dist/pricing.js +50 -0
- package/dist/pricingCatalog.d.ts +10 -0
- package/dist/pricingCatalog.js +16 -8
- package/dist/promptHistory.d.ts +65 -4
- package/dist/promptHistory.js +68 -5
- package/dist/providerFailure.d.ts +44 -0
- package/dist/providerFailure.js +126 -4
- package/dist/providers/claudeCode.js +9 -1
- package/dist/providers/codex.d.ts +3 -22
- package/dist/providers/codex.js +85 -64
- package/dist/providers/codexDatabase.d.ts +3 -2
- package/dist/providers/codexDatabase.js +4 -22
- package/dist/providers/codexRollouts.d.ts +22 -0
- package/dist/providers/codexRollouts.js +24 -0
- package/dist/providers/openCode.js +8 -16
- package/dist/providers/types.d.ts +14 -0
- package/dist/report/htmlReportGenerator.js +42 -5
- package/dist/report/transcriptParser.d.ts +10 -1
- package/dist/report/transcriptParser.js +13 -11
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/providerFailure.d.ts +39 -0
- package/dist/schemas/providerFailure.js +2 -0
- package/dist/schemas/sessionEvent.d.ts +27 -10
- package/dist/schemas/sessionEvent.js +35 -14
- package/dist/schemas/transcript.d.ts +2 -0
- package/dist/schemas/transcript.js +4 -0
- package/dist/sessionPromptHistory.d.ts +7 -1
- package/dist/sessionPromptHistory.js +1 -1
- package/dist/statusline/payload.d.ts +10 -0
- package/dist/statusline/payload.js +14 -0
- package/dist/subagentSpawn.d.ts +80 -0
- package/dist/subagentSpawn.js +174 -0
- package/dist/testing/credentialGuard.d.ts +14 -0
- package/dist/testing/credentialGuard.js +87 -5
- package/dist/toolCallOrigins.d.ts +70 -0
- package/dist/toolCallOrigins.js +346 -0
- package/dist/transcript.d.ts +12 -0
- package/dist/transcript.js +46 -3
- package/dist/turns/assistantTurn.d.ts +1 -0
- package/dist/turns/assistantTurn.js +3 -2
- package/dist/types/opencode.d.ts +2 -0
- package/dist/usage/claudeUsageDedupe.d.ts +31 -0
- package/dist/usage/claudeUsageDedupe.js +68 -0
- package/dist/usage/usageEvents.d.ts +54 -6
- package/dist/usage/usageEvents.js +146 -17
- package/dist/usage/usageReports.d.ts +35 -4
- package/dist/usage/usageReports.js +39 -6
- package/dist/watchers/eventBridge.js +15 -0
- package/dist/watchers/factory.d.ts +6 -0
- package/dist/watchers/factory.js +5 -3
- package/dist/watchers/jsonlTail.d.ts +124 -4
- package/dist/watchers/jsonlTail.js +446 -59
- package/dist/watchers/jsonlWatcher.d.ts +18 -1
- package/dist/watchers/jsonlWatcher.js +50 -3
- package/dist/watchers/providerReaderWatcher.d.ts +7 -0
- package/dist/watchers/providerReaderWatcher.js +13 -0
- package/dist/watchers/types.d.ts +12 -0
- package/dist/zaiQuota.js +2 -1
- package/package.json +41 -1
|
@@ -6,10 +6,13 @@
|
|
|
6
6
|
* (not just stats) for drill-down trace visualization. Applies noise classification
|
|
7
7
|
* and tool summary formatting from the formatters module.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* 1.
|
|
11
|
-
* 2.
|
|
12
|
-
*
|
|
9
|
+
* Parent-child linking, exact links first:
|
|
10
|
+
* 1. Meta `parentAgentId` (Claude Code writes it for nested spawns)
|
|
11
|
+
* 2. The child's spawning tool_use id (meta `toolUseId`) found in another
|
|
12
|
+
* trace's `Agent` / `Task` calls
|
|
13
|
+
* Only traces without that spawn metadata (older Claude Code) fall back to:
|
|
14
|
+
* 3. Team summary: parse <teammate-message> XML blocks
|
|
15
|
+
* 4. Positional fallback: timestamp ordering + proximity
|
|
13
16
|
*
|
|
14
17
|
* @module parsers/subagentTraceParser
|
|
15
18
|
*/
|
|
@@ -55,6 +58,8 @@ const noiseClassifier_1 = require("../formatters/noiseClassifier");
|
|
|
55
58
|
const claudeUsageDedupe_1 = require("../usage/claudeUsageDedupe");
|
|
56
59
|
const subagentUsage_1 = require("../usage/subagentUsage");
|
|
57
60
|
const subagentScanner_1 = require("./subagentScanner");
|
|
61
|
+
const subagentSpawn_1 = require("../subagentSpawn");
|
|
62
|
+
const ownKey_1 = require("../ownKey");
|
|
58
63
|
// ── Constants ──
|
|
59
64
|
const AGENT_FILE_PATTERN = /^agent-(.+)\.jsonl$/;
|
|
60
65
|
// ── Public API ──
|
|
@@ -86,10 +91,8 @@ function scanSubagentTraces(sessionDir, sessionId) {
|
|
|
86
91
|
if (trace)
|
|
87
92
|
traces.push(trace);
|
|
88
93
|
}
|
|
89
|
-
// Link parent-child relationships
|
|
90
|
-
linkTraces(traces);
|
|
91
|
-
// Return only top-level traces (those without parents)
|
|
92
|
-
return traces.filter((t) => !t.parentToolUseId);
|
|
94
|
+
// Link parent-child relationships; returns the traces with no parent agent.
|
|
95
|
+
return linkTraces(traces);
|
|
93
96
|
}
|
|
94
97
|
catch {
|
|
95
98
|
return [];
|
|
@@ -169,8 +172,8 @@ function parseAgentTrace(filePath, agentId) {
|
|
|
169
172
|
input: block.input || {},
|
|
170
173
|
timestamp,
|
|
171
174
|
});
|
|
172
|
-
// Extract agent info from Task
|
|
173
|
-
if (block.name
|
|
175
|
+
// Extract agent info from an Agent/Task spawn
|
|
176
|
+
if ((0, subagentSpawn_1.isSubagentSpawnTool)(block.name) && block.input) {
|
|
174
177
|
if (block.input.subagent_type && !agentType) {
|
|
175
178
|
agentType = String(block.input.subagent_type);
|
|
176
179
|
}
|
|
@@ -207,6 +210,14 @@ function parseAgentTrace(filePath, agentId) {
|
|
|
207
210
|
agentId,
|
|
208
211
|
agentType,
|
|
209
212
|
description,
|
|
213
|
+
filePath,
|
|
214
|
+
...(meta.toolUseId
|
|
215
|
+
? { spawnToolUseId: meta.toolUseId, parentToolUseId: meta.toolUseId }
|
|
216
|
+
: {}),
|
|
217
|
+
...(meta.parentAgentId ? { parentAgentId: meta.parentAgentId } : {}),
|
|
218
|
+
...(meta.requestShape ? { background: meta.requestShape === 'background' } : {}),
|
|
219
|
+
...(meta.finished !== undefined ? { finished: meta.finished } : {}),
|
|
220
|
+
...(meta.stoppedByUser !== undefined ? { stoppedByUser: meta.stoppedByUser } : {}),
|
|
210
221
|
events,
|
|
211
222
|
children: [],
|
|
212
223
|
stats: {
|
|
@@ -231,23 +242,61 @@ function parseAgentTrace(filePath, agentId) {
|
|
|
231
242
|
}
|
|
232
243
|
}
|
|
233
244
|
// ── Parent-Child Linking ──
|
|
245
|
+
/**
|
|
246
|
+
* Nests child traces under their parents and returns the traces with no
|
|
247
|
+
* parent agent. Exact metadata links come first; the heuristics only place
|
|
248
|
+
* traces Claude Code recorded no spawn metadata for.
|
|
249
|
+
*/
|
|
234
250
|
function linkTraces(traces) {
|
|
235
251
|
const traceById = new Map();
|
|
236
252
|
for (const trace of traces) {
|
|
237
253
|
traceById.set(trace.agentId, trace);
|
|
238
254
|
}
|
|
239
|
-
|
|
240
|
-
|
|
255
|
+
const parentOf = new Map();
|
|
256
|
+
const attach = (parent, child) => {
|
|
257
|
+
if (parent === child || parentOf.has(child))
|
|
258
|
+
return false;
|
|
259
|
+
// Never nest an agent under its own descendant (malformed metadata).
|
|
260
|
+
for (let up = parent; up; up = parentOf.get(up)) {
|
|
261
|
+
if (up === child)
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
parentOf.set(child, parent);
|
|
265
|
+
parent.children.push(child);
|
|
266
|
+
return true;
|
|
267
|
+
};
|
|
268
|
+
// Phase 1: the meta file names the parent agent
|
|
269
|
+
for (const child of traces) {
|
|
270
|
+
const parent = child.parentAgentId ? traceById.get(child.parentAgentId) : undefined;
|
|
271
|
+
if (parent)
|
|
272
|
+
attach(parent, child);
|
|
273
|
+
}
|
|
274
|
+
// Phase 2: the child's spawning call is in another trace
|
|
275
|
+
const spawnOwner = new Map();
|
|
241
276
|
for (const trace of traces) {
|
|
242
|
-
for (const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// The tool_use_id from this call should appear as a result in the parent
|
|
246
|
-
// but we can link via timestamp proximity to child traces
|
|
247
|
-
}
|
|
277
|
+
for (const id of spawnToolUseIdsOf(trace)) {
|
|
278
|
+
if (!spawnOwner.has(id))
|
|
279
|
+
spawnOwner.set(id, trace);
|
|
248
280
|
}
|
|
249
281
|
}
|
|
250
|
-
|
|
282
|
+
for (const child of traces) {
|
|
283
|
+
if (parentOf.has(child) || !child.spawnToolUseId)
|
|
284
|
+
continue;
|
|
285
|
+
const parent = spawnOwner.get(child.spawnToolUseId);
|
|
286
|
+
if (parent && attach(parent, child))
|
|
287
|
+
child.parentAgentId ??= parent.agentId;
|
|
288
|
+
}
|
|
289
|
+
// Heuristic links set parentAgentId and, as before, parentToolUseId to the
|
|
290
|
+
// parent's agent id.
|
|
291
|
+
const unresolved = (trace) => !parentOf.has(trace) && !trace.spawnToolUseId && !trace.parentAgentId;
|
|
292
|
+
const linkHeuristically = (parent, child) => {
|
|
293
|
+
if (!attach(parent, child))
|
|
294
|
+
return false;
|
|
295
|
+
child.parentAgentId = parent.agentId;
|
|
296
|
+
child.parentToolUseId = parent.agentId;
|
|
297
|
+
return true;
|
|
298
|
+
};
|
|
299
|
+
// Phase 3: Team summary linking
|
|
251
300
|
for (const trace of traces) {
|
|
252
301
|
for (const traceEvent of trace.events) {
|
|
253
302
|
const content = traceEvent.event.message?.content;
|
|
@@ -255,45 +304,56 @@ function linkTraces(traces) {
|
|
|
255
304
|
// Parse teammate agent IDs from XML blocks
|
|
256
305
|
const matches = content.matchAll(/agent[_-]id['":\s]+([a-f0-9]+)/gi);
|
|
257
306
|
for (const match of matches) {
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
child.parentToolUseId = trace.agentId;
|
|
262
|
-
trace.children.push(child);
|
|
263
|
-
}
|
|
307
|
+
const child = traceById.get(match[1]);
|
|
308
|
+
if (child && unresolved(child))
|
|
309
|
+
linkHeuristically(trace, child);
|
|
264
310
|
}
|
|
265
311
|
}
|
|
266
312
|
}
|
|
267
313
|
}
|
|
268
|
-
// Phase
|
|
314
|
+
// Phase 4: Positional fallback — timestamp proximity
|
|
269
315
|
// Traces without parents that fall within another trace's time window
|
|
270
|
-
const
|
|
271
|
-
for (const child of parentless) {
|
|
316
|
+
for (const child of traces.filter(unresolved)) {
|
|
272
317
|
if (!child.stats.startTime)
|
|
273
318
|
continue;
|
|
274
319
|
const childStart = child.stats.startTime.getTime();
|
|
275
|
-
// Find a trace that
|
|
320
|
+
// Find a top-level trace that spawned an agent right before this child started
|
|
276
321
|
for (const potential of traces) {
|
|
277
|
-
if (potential === child)
|
|
322
|
+
if (potential === child || parentOf.has(potential))
|
|
278
323
|
continue;
|
|
279
|
-
if (potential.parentToolUseId)
|
|
280
|
-
continue; // Already linked
|
|
281
324
|
for (const traceEvent of potential.events) {
|
|
282
325
|
const evt = traceEvent.event;
|
|
283
|
-
if (evt.type === 'assistant' && evt.tool?.name
|
|
326
|
+
if (evt.type === 'assistant' && (0, subagentSpawn_1.isSubagentSpawnTool)(evt.tool?.name)) {
|
|
284
327
|
const taskTime = new Date(evt.timestamp).getTime();
|
|
285
328
|
// Within 2 seconds before child start
|
|
286
329
|
if (taskTime <= childStart && childStart - taskTime < 2000) {
|
|
287
|
-
child
|
|
288
|
-
potential.children.push(child);
|
|
330
|
+
linkHeuristically(potential, child);
|
|
289
331
|
break;
|
|
290
332
|
}
|
|
291
333
|
}
|
|
292
334
|
}
|
|
293
|
-
if (child
|
|
335
|
+
if (parentOf.has(child))
|
|
294
336
|
break;
|
|
295
337
|
}
|
|
296
338
|
}
|
|
339
|
+
return traces.filter((trace) => !parentOf.has(trace));
|
|
340
|
+
}
|
|
341
|
+
/** Ids of the `Agent` / `Task` calls a trace made. */
|
|
342
|
+
function spawnToolUseIdsOf(trace) {
|
|
343
|
+
const ids = [];
|
|
344
|
+
for (const traceEvent of trace.events) {
|
|
345
|
+
const content = traceEvent.event.message?.content;
|
|
346
|
+
if (!Array.isArray(content))
|
|
347
|
+
continue;
|
|
348
|
+
for (const block of content) {
|
|
349
|
+
if (block?.type === 'tool_use' &&
|
|
350
|
+
typeof block.id === 'string' &&
|
|
351
|
+
(0, subagentSpawn_1.isSubagentSpawnTool)(block.name)) {
|
|
352
|
+
ids.push(block.id);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return ids;
|
|
297
357
|
}
|
|
298
358
|
// ── Helpers ──
|
|
299
359
|
function rawToSessionEvent(raw) {
|
|
@@ -308,7 +368,7 @@ function rawToSessionEvent(raw) {
|
|
|
308
368
|
tool_result: 'tool_result',
|
|
309
369
|
summary: 'summary',
|
|
310
370
|
};
|
|
311
|
-
const mappedType = typeMap
|
|
371
|
+
const mappedType = (0, ownKey_1.ownValue)(typeMap, type);
|
|
312
372
|
if (!mappedType)
|
|
313
373
|
return null;
|
|
314
374
|
const message = raw.message;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sidekick-shared/pricing` — model pricing, model-id identity, usage
|
|
3
|
+
* normalization and cost, cost provenance, cost/token formatting, and text
|
|
4
|
+
* token estimates, as one small pure entry (no filesystem, network, or Zod).
|
|
5
|
+
*
|
|
6
|
+
* For hosts that price usage or format costs without session reading: it
|
|
7
|
+
* loads a handful of modules instead of the full browser surface. LiteLLM
|
|
8
|
+
* catalog hydration stays Node-only in `sidekick-shared/node`
|
|
9
|
+
* (`hydratePricingCatalog`); once hydrated, lookups here see the catalog.
|
|
10
|
+
* Everything here is also exported from the package root and
|
|
11
|
+
* `sidekick-shared/browser`.
|
|
12
|
+
*
|
|
13
|
+
* @module pricing
|
|
14
|
+
*/
|
|
15
|
+
export { MODEL_PROVIDER_IDS, canonicalModelId, isMovingModelAlias, parseModelId, compareModelIds, sortModelIds, shortModelName, getModelDisplayInfo, getModelInfo, getModelPricing, resolveModelPricing, registerModelPricing, clearRegisteredModelPricing, getPricingCatalogInfo, calculateCost, calculateCostWithPricing, calculateCostWithProvenance, mergeCostSources, costSourceFromPricingProvenance, mergeCostComponents, formatCost, } from './modelInfo';
|
|
16
|
+
export type { ModelPricing, ModelPricingSource, ModelPricingMatch, ModelPricingProvenance, ResolvedModelPricing, ResolveModelPricingOptions, RegisterModelPricingOptions, PricingCatalogSource, PricingCatalogInfo, CostComponent, CostTokenUsage, ModelProvider, ParsedModelId, ModelInfo, CostSource, CostProvenanceInput, CostWithProvenance, ModelDisplayInfo, FormatCostOptions, } from './modelInfo';
|
|
17
|
+
export { normalizeProviderUsage, extractNormalizedUsage, calculateNormalizedUsageCost, } from './usageNormalization';
|
|
18
|
+
export type { UsageProvider, UsageSemantics, UsageNormalizationProvenance, AnthropicUsageInput, OpenAIUsageInput, SidekickUsageInput, ProviderUsageInput, NormalizedUsage, PricingProvenance, NormalizedUsageCostInput, NormalizedUsageCost, } from './usageNormalization';
|
|
19
|
+
export { formatTokenCount, formatDurationMs } from './formatting';
|
|
20
|
+
export type { FormatTokenCountOptions, FormatDurationMsOptions } from './formatting';
|
|
21
|
+
export { ASCII_CHARS_PER_TOKEN, estimateTextTokens, estimateSerializedTokens, } from './tokenEstimation';
|
|
22
|
+
export type { TokenEstimationMethod, TokenEstimationConfidence, ExactTokenCounterContext, ExactTokenCounter, TokenEstimationOptions, TokenEstimate, } from './tokenEstimation';
|
package/dist/pricing.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `sidekick-shared/pricing` — model pricing, model-id identity, usage
|
|
4
|
+
* normalization and cost, cost provenance, cost/token formatting, and text
|
|
5
|
+
* token estimates, as one small pure entry (no filesystem, network, or Zod).
|
|
6
|
+
*
|
|
7
|
+
* For hosts that price usage or format costs without session reading: it
|
|
8
|
+
* loads a handful of modules instead of the full browser surface. LiteLLM
|
|
9
|
+
* catalog hydration stays Node-only in `sidekick-shared/node`
|
|
10
|
+
* (`hydratePricingCatalog`); once hydrated, lookups here see the catalog.
|
|
11
|
+
* Everything here is also exported from the package root and
|
|
12
|
+
* `sidekick-shared/browser`.
|
|
13
|
+
*
|
|
14
|
+
* @module pricing
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.estimateSerializedTokens = exports.estimateTextTokens = exports.ASCII_CHARS_PER_TOKEN = exports.formatDurationMs = exports.formatTokenCount = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = exports.formatCost = exports.mergeCostComponents = exports.costSourceFromPricingProvenance = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getPricingCatalogInfo = exports.clearRegisteredModelPricing = exports.registerModelPricing = exports.resolveModelPricing = exports.getModelPricing = exports.getModelInfo = exports.getModelDisplayInfo = exports.shortModelName = exports.sortModelIds = exports.compareModelIds = exports.parseModelId = exports.isMovingModelAlias = exports.canonicalModelId = exports.MODEL_PROVIDER_IDS = void 0;
|
|
18
|
+
var modelInfo_1 = require("./modelInfo");
|
|
19
|
+
Object.defineProperty(exports, "MODEL_PROVIDER_IDS", { enumerable: true, get: function () { return modelInfo_1.MODEL_PROVIDER_IDS; } });
|
|
20
|
+
Object.defineProperty(exports, "canonicalModelId", { enumerable: true, get: function () { return modelInfo_1.canonicalModelId; } });
|
|
21
|
+
Object.defineProperty(exports, "isMovingModelAlias", { enumerable: true, get: function () { return modelInfo_1.isMovingModelAlias; } });
|
|
22
|
+
Object.defineProperty(exports, "parseModelId", { enumerable: true, get: function () { return modelInfo_1.parseModelId; } });
|
|
23
|
+
Object.defineProperty(exports, "compareModelIds", { enumerable: true, get: function () { return modelInfo_1.compareModelIds; } });
|
|
24
|
+
Object.defineProperty(exports, "sortModelIds", { enumerable: true, get: function () { return modelInfo_1.sortModelIds; } });
|
|
25
|
+
Object.defineProperty(exports, "shortModelName", { enumerable: true, get: function () { return modelInfo_1.shortModelName; } });
|
|
26
|
+
Object.defineProperty(exports, "getModelDisplayInfo", { enumerable: true, get: function () { return modelInfo_1.getModelDisplayInfo; } });
|
|
27
|
+
Object.defineProperty(exports, "getModelInfo", { enumerable: true, get: function () { return modelInfo_1.getModelInfo; } });
|
|
28
|
+
Object.defineProperty(exports, "getModelPricing", { enumerable: true, get: function () { return modelInfo_1.getModelPricing; } });
|
|
29
|
+
Object.defineProperty(exports, "resolveModelPricing", { enumerable: true, get: function () { return modelInfo_1.resolveModelPricing; } });
|
|
30
|
+
Object.defineProperty(exports, "registerModelPricing", { enumerable: true, get: function () { return modelInfo_1.registerModelPricing; } });
|
|
31
|
+
Object.defineProperty(exports, "clearRegisteredModelPricing", { enumerable: true, get: function () { return modelInfo_1.clearRegisteredModelPricing; } });
|
|
32
|
+
Object.defineProperty(exports, "getPricingCatalogInfo", { enumerable: true, get: function () { return modelInfo_1.getPricingCatalogInfo; } });
|
|
33
|
+
Object.defineProperty(exports, "calculateCost", { enumerable: true, get: function () { return modelInfo_1.calculateCost; } });
|
|
34
|
+
Object.defineProperty(exports, "calculateCostWithPricing", { enumerable: true, get: function () { return modelInfo_1.calculateCostWithPricing; } });
|
|
35
|
+
Object.defineProperty(exports, "calculateCostWithProvenance", { enumerable: true, get: function () { return modelInfo_1.calculateCostWithProvenance; } });
|
|
36
|
+
Object.defineProperty(exports, "mergeCostSources", { enumerable: true, get: function () { return modelInfo_1.mergeCostSources; } });
|
|
37
|
+
Object.defineProperty(exports, "costSourceFromPricingProvenance", { enumerable: true, get: function () { return modelInfo_1.costSourceFromPricingProvenance; } });
|
|
38
|
+
Object.defineProperty(exports, "mergeCostComponents", { enumerable: true, get: function () { return modelInfo_1.mergeCostComponents; } });
|
|
39
|
+
Object.defineProperty(exports, "formatCost", { enumerable: true, get: function () { return modelInfo_1.formatCost; } });
|
|
40
|
+
var usageNormalization_1 = require("./usageNormalization");
|
|
41
|
+
Object.defineProperty(exports, "normalizeProviderUsage", { enumerable: true, get: function () { return usageNormalization_1.normalizeProviderUsage; } });
|
|
42
|
+
Object.defineProperty(exports, "extractNormalizedUsage", { enumerable: true, get: function () { return usageNormalization_1.extractNormalizedUsage; } });
|
|
43
|
+
Object.defineProperty(exports, "calculateNormalizedUsageCost", { enumerable: true, get: function () { return usageNormalization_1.calculateNormalizedUsageCost; } });
|
|
44
|
+
var formatting_1 = require("./formatting");
|
|
45
|
+
Object.defineProperty(exports, "formatTokenCount", { enumerable: true, get: function () { return formatting_1.formatTokenCount; } });
|
|
46
|
+
Object.defineProperty(exports, "formatDurationMs", { enumerable: true, get: function () { return formatting_1.formatDurationMs; } });
|
|
47
|
+
var tokenEstimation_1 = require("./tokenEstimation");
|
|
48
|
+
Object.defineProperty(exports, "ASCII_CHARS_PER_TOKEN", { enumerable: true, get: function () { return tokenEstimation_1.ASCII_CHARS_PER_TOKEN; } });
|
|
49
|
+
Object.defineProperty(exports, "estimateTextTokens", { enumerable: true, get: function () { return tokenEstimation_1.estimateTextTokens; } });
|
|
50
|
+
Object.defineProperty(exports, "estimateSerializedTokens", { enumerable: true, get: function () { return tokenEstimation_1.estimateSerializedTokens; } });
|
package/dist/pricingCatalog.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ export interface HydrateResult {
|
|
|
51
51
|
contextWindowEntries: number;
|
|
52
52
|
/** ISO timestamp of the fetch that produced the cache. */
|
|
53
53
|
fetchedAt: string;
|
|
54
|
+
/**
|
|
55
|
+
* `getPricingCatalogInfo().digest` after hydration: a stable fingerprint of
|
|
56
|
+
* every active pricing table, so callers can record which prices produced
|
|
57
|
+
* an estimate. See `getPricingCatalogInfo()` for the source and staleness.
|
|
58
|
+
*/
|
|
59
|
+
digest: string;
|
|
54
60
|
}
|
|
55
61
|
export declare const LITELLM_CATALOG_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
|
|
56
62
|
/**
|
|
@@ -61,6 +67,10 @@ export declare const LITELLM_CATALOG_URL = "https://raw.githubusercontent.com/Be
|
|
|
61
67
|
* 2. Otherwise attempt a network fetch; on success, persist + apply.
|
|
62
68
|
* 3. On any failure, load a stale cache if present; else leave overrides empty.
|
|
63
69
|
*
|
|
70
|
+
* `getPricingCatalogInfo().source` afterwards reads `litellm` for a fresh fetch
|
|
71
|
+
* or a cache within `ttlMs`, and `stale-cache` for a cache older than `ttlMs`
|
|
72
|
+
* — whether the refresh failed or `offline` skipped it.
|
|
73
|
+
*
|
|
64
74
|
* Always resolves — never throws. Offline-safe.
|
|
65
75
|
*/
|
|
66
76
|
export declare function hydratePricingCatalog(options?: HydrateOptions): Promise<HydrateResult>;
|
package/dist/pricingCatalog.js
CHANGED
|
@@ -59,6 +59,7 @@ const node_fs_1 = require("node:fs");
|
|
|
59
59
|
const path = __importStar(require("node:path"));
|
|
60
60
|
const modelContext_1 = require("./modelContext");
|
|
61
61
|
const modelInfo_1 = require("./modelInfo");
|
|
62
|
+
const ownKey_1 = require("./ownKey");
|
|
62
63
|
const paths_1 = require("./paths");
|
|
63
64
|
const atomic_1 = require("./writers/atomic");
|
|
64
65
|
// ── Constants ──
|
|
@@ -75,6 +76,10 @@ const DEFAULT_TIMEOUT_MS = 3_000;
|
|
|
75
76
|
* 2. Otherwise attempt a network fetch; on success, persist + apply.
|
|
76
77
|
* 3. On any failure, load a stale cache if present; else leave overrides empty.
|
|
77
78
|
*
|
|
79
|
+
* `getPricingCatalogInfo().source` afterwards reads `litellm` for a fresh fetch
|
|
80
|
+
* or a cache within `ttlMs`, and `stale-cache` for a cache older than `ttlMs`
|
|
81
|
+
* — whether the refresh failed or `offline` skipped it.
|
|
82
|
+
*
|
|
78
83
|
* Always resolves — never throws. Offline-safe.
|
|
79
84
|
*/
|
|
80
85
|
async function hydratePricingCatalog(options = {}) {
|
|
@@ -83,8 +88,9 @@ async function hydratePricingCatalog(options = {}) {
|
|
|
83
88
|
const now = Date.now();
|
|
84
89
|
// 1. Fresh cache? (Offline callers take any cache, however old.)
|
|
85
90
|
const cached = await readCache(cachePath);
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
const cacheFresh = cached !== null && now - Date.parse(cached.fetchedAt) < ttlMs;
|
|
92
|
+
if (cached && (offline || cacheFresh)) {
|
|
93
|
+
return applyCacheFile(cached, 'cache', cacheFresh ? 'litellm' : 'stale-cache');
|
|
88
94
|
}
|
|
89
95
|
// 2. Try network.
|
|
90
96
|
if (fetchImpl && !offline) {
|
|
@@ -97,12 +103,12 @@ async function hydratePricingCatalog(options = {}) {
|
|
|
97
103
|
contextWindows: normalizeLiteLlmContextWindows(fetched),
|
|
98
104
|
};
|
|
99
105
|
await writeCache(cachePath, payload, logger);
|
|
100
|
-
return applyCacheFile(payload, 'network');
|
|
106
|
+
return applyCacheFile(payload, 'network', 'litellm');
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
// 3. Fall back to stale cache if present.
|
|
104
110
|
if (cached) {
|
|
105
|
-
return applyCacheFile(cached, 'cache');
|
|
111
|
+
return applyCacheFile(cached, 'cache', 'stale-cache');
|
|
106
112
|
}
|
|
107
113
|
// 4. Nothing we can do — stay on static tables.
|
|
108
114
|
return {
|
|
@@ -110,6 +116,7 @@ async function hydratePricingCatalog(options = {}) {
|
|
|
110
116
|
entries: 0,
|
|
111
117
|
contextWindowEntries: 0,
|
|
112
118
|
fetchedAt: new Date(now).toISOString(),
|
|
119
|
+
digest: (0, modelInfo_1.getPricingCatalogInfo)().digest,
|
|
113
120
|
};
|
|
114
121
|
}
|
|
115
122
|
/**
|
|
@@ -117,9 +124,9 @@ async function hydratePricingCatalog(options = {}) {
|
|
|
117
124
|
* `contextWindows` is absent on caches written before context hydration; those
|
|
118
125
|
* contribute no overrides rather than clearing whatever is already loaded.
|
|
119
126
|
*/
|
|
120
|
-
function applyCacheFile(cache, source) {
|
|
127
|
+
function applyCacheFile(cache, source, basis) {
|
|
121
128
|
const contextWindows = cache.contextWindows ?? {};
|
|
122
|
-
(0, modelInfo_1._setPricingOverrides)(cache.overrides);
|
|
129
|
+
(0, modelInfo_1._setPricingOverrides)(cache.overrides, { source: basis, fetchedAt: cache.fetchedAt });
|
|
123
130
|
if (Object.keys(contextWindows).length > 0) {
|
|
124
131
|
(0, modelContext_1._setCatalogContextWindows)(contextWindows);
|
|
125
132
|
}
|
|
@@ -128,6 +135,7 @@ function applyCacheFile(cache, source) {
|
|
|
128
135
|
entries: Object.keys(cache.overrides).length,
|
|
129
136
|
contextWindowEntries: Object.keys(contextWindows).length,
|
|
130
137
|
fetchedAt: cache.fetchedAt,
|
|
138
|
+
digest: (0, modelInfo_1.getPricingCatalogInfo)().digest,
|
|
131
139
|
};
|
|
132
140
|
}
|
|
133
141
|
/**
|
|
@@ -149,7 +157,7 @@ function normalizeLiteLlmCatalog(raw) {
|
|
|
149
157
|
continue;
|
|
150
158
|
// Catalog keys use both `provider/model` and bare `model` forms. Record both
|
|
151
159
|
// the raw key and the bare-model form so lookups work regardless of caller.
|
|
152
|
-
out
|
|
160
|
+
(0, ownKey_1.setOwnValue)(out, key, pricing);
|
|
153
161
|
const bare = stripProviderPrefix(key);
|
|
154
162
|
if (bare && bare !== key && !out[bare]) {
|
|
155
163
|
out[bare] = pricing;
|
|
@@ -186,7 +194,7 @@ function normalizeLiteLlmContextWindows(raw) {
|
|
|
186
194
|
const window = entry.max_input_tokens;
|
|
187
195
|
if (typeof window !== 'number' || !Number.isFinite(window) || window <= 0)
|
|
188
196
|
continue;
|
|
189
|
-
out
|
|
197
|
+
(0, ownKey_1.setOwnValue)(out, key, window);
|
|
190
198
|
const bare = stripProviderPrefix(key);
|
|
191
199
|
if (bare && bare !== key) {
|
|
192
200
|
const seen = aliasWindows.get(bare) ?? new Set();
|
package/dist/promptHistory.d.ts
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
* record over `maxRecordBytes` is skipped without being buffered and reported
|
|
15
15
|
* in `exclusions`, the only way a record is permanently left out.
|
|
16
16
|
*
|
|
17
|
+
* `includeText: false` returns the same entries, ordinals, timestamps,
|
|
18
|
+
* metadata, exclusions, and cursor without prompt text, for consumers that
|
|
19
|
+
* only count or attribute prompts. Cursors are interchangeable between modes.
|
|
20
|
+
*
|
|
17
21
|
* A prompt can be written before its answer. The cursor then keeps the byte
|
|
18
22
|
* offset of that prompt's line and its answer-tracking state (never text), and
|
|
19
23
|
* the prompt is returned again under the same identity once its first
|
|
@@ -34,8 +38,14 @@ export interface PromptHistoryBounds {
|
|
|
34
38
|
/** Bytes read across all files in this call. Default 256 MiB. */
|
|
35
39
|
maxTotalBytes?: number;
|
|
36
40
|
/**
|
|
37
|
-
* Largest single log record that is parsed. Default 16 MiB
|
|
38
|
-
*
|
|
41
|
+
* Largest single log record that is parsed. Default 16 MiB
|
|
42
|
+
* (`PROMPT_HISTORY_ORDINAL_MAX_RECORD_BYTES`). A longer record is skipped
|
|
43
|
+
* without being buffered and reported in `exclusions`.
|
|
44
|
+
*
|
|
45
|
+
* Ordinals depend on this bound: a prompt inside a skipped record is never
|
|
46
|
+
* seen, so later prompts in that file do not count it. Ordinals are only
|
|
47
|
+
* stable across runs and across consumers (for example usage events'
|
|
48
|
+
* `promptOrdinal`) when every reader uses the default.
|
|
39
49
|
*/
|
|
40
50
|
maxRecordBytes?: number;
|
|
41
51
|
/** Entries returned by one call. Default 10 000. */
|
|
@@ -139,8 +149,10 @@ export interface PromptHistoryEntry {
|
|
|
139
149
|
ordinal: number;
|
|
140
150
|
/** ISO timestamp from the log line; never synthesized. */
|
|
141
151
|
timestamp: string;
|
|
142
|
-
/** Full prompt text, untruncated
|
|
152
|
+
/** Full prompt text, untruncated; `''` when the call passed `includeText: false`. */
|
|
143
153
|
text: string;
|
|
154
|
+
/** Set when `text` was left out by `includeText: false`; the prompt was not empty. */
|
|
155
|
+
textOmitted?: true;
|
|
144
156
|
/** Realpath of the working directory; always inside an allowed root. */
|
|
145
157
|
cwd: string;
|
|
146
158
|
gitBranch?: string;
|
|
@@ -170,7 +182,9 @@ export interface PromptHistorySessionRef {
|
|
|
170
182
|
/**
|
|
171
183
|
* A log record permanently left out. Records over `maxRecordBytes` and lines
|
|
172
184
|
* that are not valid JSON are never parsed, so any prompt inside is lost, and
|
|
173
|
-
* the ordinals of later prompts in that file do not count it.
|
|
185
|
+
* the ordinals of later prompts in that file do not count it. Because of
|
|
186
|
+
* that, ordinals are only stable across runs and consumers that all use the
|
|
187
|
+
* default `maxRecordBytes` (`PROMPT_HISTORY_ORDINAL_MAX_RECORD_BYTES`).
|
|
174
188
|
*/
|
|
175
189
|
export interface PromptHistoryExclusion {
|
|
176
190
|
provider: PromptHistoryProvider;
|
|
@@ -213,6 +227,14 @@ export interface CollectPromptHistoryOptions {
|
|
|
213
227
|
cursor?: PromptHistoryCursor;
|
|
214
228
|
bounds?: PromptHistoryBounds;
|
|
215
229
|
signal?: AbortSignal;
|
|
230
|
+
/**
|
|
231
|
+
* Return prompt text. Default true. With `false`, entries keep their
|
|
232
|
+
* ordinal, timestamp, cwd, branch, and answer metadata but carry `text: ''`
|
|
233
|
+
* and `textOmitted: true`, and no prompt text is kept past classifying its
|
|
234
|
+
* line. Ordinals, timestamps, exclusions, and the cursor are identical in
|
|
235
|
+
* both modes, so a cursor written in one mode resumes in the other.
|
|
236
|
+
*/
|
|
237
|
+
includeText?: boolean;
|
|
216
238
|
}
|
|
217
239
|
export interface PromptHistoryResult {
|
|
218
240
|
/** Ordered by provider, session, then ordinal. */
|
|
@@ -235,6 +257,13 @@ export interface PromptHistoryResult {
|
|
|
235
257
|
/** Realpaths of the roots scanned, after worktree expansion. */
|
|
236
258
|
roots?: string[];
|
|
237
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* The default `maxRecordBytes` (16 MiB). Prompt ordinals are only comparable
|
|
262
|
+
* between readers that skip the same records, so every reader that publishes
|
|
263
|
+
* or joins on ordinals (prompt history, session prompt history, usage events'
|
|
264
|
+
* `promptOrdinal`) uses this bound.
|
|
265
|
+
*/
|
|
266
|
+
export declare const PROMPT_HISTORY_ORDINAL_MAX_RECORD_BYTES: number;
|
|
238
267
|
/** @internal */
|
|
239
268
|
export declare const DEFAULT_BOUNDS: Required<PromptHistoryBounds>;
|
|
240
269
|
/** Test hooks; not part of the public entry points. */
|
|
@@ -257,6 +286,17 @@ export type RecordObserver = (record: Record<string, unknown>, info: {
|
|
|
257
286
|
ordinal: number;
|
|
258
287
|
lineOffset: number;
|
|
259
288
|
}) => void;
|
|
289
|
+
/**
|
|
290
|
+
* Sees every human prompt as it is given its ordinal, before the timestamp and
|
|
291
|
+
* scope checks, so prompts that are not returned are seen too. `timestamp` is
|
|
292
|
+
* undefined when the line has no usable one.
|
|
293
|
+
* @internal
|
|
294
|
+
*/
|
|
295
|
+
export type PromptObserver = (prompt: {
|
|
296
|
+
ordinal: number;
|
|
297
|
+
timestamp: string | undefined;
|
|
298
|
+
lineOffset: number;
|
|
299
|
+
}) => void;
|
|
260
300
|
/** @internal */
|
|
261
301
|
export interface ScanContext {
|
|
262
302
|
roots: string[];
|
|
@@ -269,6 +309,9 @@ export interface ScanContext {
|
|
|
269
309
|
entriesSoFar: () => number;
|
|
270
310
|
exclude: (exclusion: PromptHistoryExclusion) => void;
|
|
271
311
|
observe?: RecordObserver;
|
|
312
|
+
onPrompt?: PromptObserver;
|
|
313
|
+
/** Keep prompt text on entries. Default true. */
|
|
314
|
+
includeText?: boolean;
|
|
272
315
|
}
|
|
273
316
|
/** @internal */
|
|
274
317
|
export interface FileBudget {
|
|
@@ -293,6 +336,24 @@ export interface FileOutcome {
|
|
|
293
336
|
}
|
|
294
337
|
/** Collect human-typed prompts from Claude Code and Codex logs under the given roots. */
|
|
295
338
|
export declare function collectPromptHistory(options: CollectPromptHistoryOptions): Promise<PromptHistoryResult>;
|
|
339
|
+
/** One human prompt of a session file: its ordinal and parsed timestamp. @internal */
|
|
340
|
+
export interface PromptOrdinalMark {
|
|
341
|
+
ordinal: number;
|
|
342
|
+
/** Prompt line timestamp, ms since epoch. */
|
|
343
|
+
timestampMs: number;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Every human prompt of one session file with its ordinal and timestamp, read
|
|
347
|
+
* whole in one pass with the default record bound, so the ordinals are the
|
|
348
|
+
* ones `collectPromptHistory()` returns with default bounds. No scope check
|
|
349
|
+
* and no text: prompts are counted wherever their cwd points. Prompts whose
|
|
350
|
+
* line has no usable timestamp still take an ordinal but are left out. A
|
|
351
|
+
* non-interactive Codex session (subagent, fork, unknown source) has none.
|
|
352
|
+
* In file order. Rejects when the file cannot be opened or changes while its
|
|
353
|
+
* head is read.
|
|
354
|
+
* @internal
|
|
355
|
+
*/
|
|
356
|
+
export declare function readPromptOrdinalMarks(provider: PromptHistoryProvider, sessionId: string, filePath: string): Promise<PromptOrdinalMark[]>;
|
|
296
357
|
/** @internal */
|
|
297
358
|
export declare function emptyStats(): PromptHistoryStats;
|
|
298
359
|
/**
|