sidekick-shared 0.27.6 → 0.28.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/CHANGELOG.md +28 -0
- package/README.md +58 -18
- package/dist/browser.d.ts +13 -2
- package/dist/browser.js +30 -2
- package/dist/claudePaths.d.ts +11 -0
- package/dist/claudePaths.js +61 -0
- package/dist/claudeProfiles.d.ts +2 -9
- package/dist/claudeProfiles.js +10 -25
- package/dist/codexPaths.d.ts +22 -0
- package/dist/codexPaths.js +67 -0
- package/dist/codexProfiles.d.ts +1 -4
- package/dist/codexProfiles.js +5 -43
- package/dist/doctor.js +2 -2
- package/dist/esm/accountChangeSignal.js +15 -0
- package/dist/esm/accountChanges.js +152 -0
- package/dist/esm/accountHealth.js +288 -0
- package/dist/esm/accountLaunch.js +145 -0
- package/dist/esm/accountLease.js +60 -0
- package/dist/esm/accountManager.js +606 -0
- package/dist/esm/accountRegistry.js +214 -0
- package/dist/esm/accountStatus.js +51 -0
- package/dist/esm/accountSwitch.js +74 -0
- package/dist/esm/accountSync.js +156 -0
- package/dist/esm/accountSyncTypes.js +4 -0
- package/dist/esm/accounts.js +1291 -0
- package/dist/esm/aggregation/EventAggregator.js +2034 -0
- package/dist/esm/aggregation/FrequencyTracker.js +69 -0
- package/dist/esm/aggregation/HeatmapTracker.js +89 -0
- package/dist/esm/aggregation/PatternExtractor.js +168 -0
- package/dist/esm/aggregation/costProvenance.js +31 -0
- package/dist/esm/aggregation/snapshot.js +161 -0
- package/dist/esm/aggregation/types.js +5 -0
- package/dist/esm/analytics/codeImpact.js +18 -0
- package/dist/esm/analytics/compactionLedger.js +37 -0
- package/dist/esm/analytics/qualityScore.js +112 -0
- package/dist/esm/autoSwitch.js +185 -0
- package/dist/esm/browser.js +34 -0
- package/dist/esm/claudeCredentialDoctor.js +239 -0
- package/dist/esm/claudeCredentialLedger.js +91 -0
- package/dist/esm/claudeCredentials.js +111 -0
- package/dist/esm/claudeLiveGuard.js +43 -0
- package/dist/esm/claudePaths.js +22 -0
- package/dist/esm/claudeProfiles.js +142 -0
- package/dist/esm/claudeRefreshLock.js +106 -0
- package/dist/esm/codexAuth.js +101 -0
- package/dist/esm/codexCredentialDoctor.js +265 -0
- package/dist/esm/codexCredentialStore.js +164 -0
- package/dist/esm/codexKeepAlive.js +112 -0
- package/dist/esm/codexPaths.js +172 -0
- package/dist/esm/codexProfiles.js +1251 -0
- package/dist/esm/codexQuota.js +564 -0
- package/dist/esm/codexQuotaWatcher.js +363 -0
- package/dist/esm/context/composer.js +71 -0
- package/dist/esm/context/sessionContext.js +546 -0
- package/dist/esm/credentialIO.js +283 -0
- package/dist/esm/credentials.js +49 -0
- package/dist/esm/doctor.js +305 -0
- package/dist/esm/ensureDefaultAccounts.js +62 -0
- package/dist/esm/errorHistory.js +56 -0
- package/dist/esm/extractors/errorTaxonomy.js +43 -0
- package/dist/esm/extractors/gatherAssets.js +32 -0
- package/dist/esm/extractors/sessionAssets.js +176 -0
- package/dist/esm/extractors/sources/claudeAssets.js +158 -0
- package/dist/esm/extractors/sources/codexAssets.js +234 -0
- package/dist/esm/extractors/tokenUsage.js +41 -0
- package/dist/esm/extractors/toolCall.js +142 -0
- package/dist/esm/failingTools.js +65 -0
- package/dist/esm/fileHead.js +27 -0
- package/dist/esm/formatters/eventHighlighter.js +332 -0
- package/dist/esm/formatters/noiseClassifier.js +209 -0
- package/dist/esm/formatters/sessionDump.js +328 -0
- package/dist/esm/formatters/toolSummary.js +226 -0
- package/dist/esm/formatting.js +82 -0
- package/dist/esm/handoffUrl.js +23 -0
- package/dist/esm/historicalStore.js +305 -0
- package/dist/esm/humanPrompt.js +88 -0
- package/dist/esm/index.js +213 -0
- package/dist/esm/keepAlive.js +189 -0
- package/dist/esm/liveCredentialGuard.js +33 -0
- package/dist/esm/modelAliases.js +51 -0
- package/dist/esm/modelCatalog.js +139 -0
- package/dist/esm/modelContext.js +280 -0
- package/dist/esm/modelInfo.js +832 -0
- package/dist/esm/multiProviderQuotaService.js +450 -0
- package/dist/esm/node.js +46 -0
- package/dist/esm/observedContextWindows.js +165 -0
- package/dist/esm/observedSessionCollector.js +939 -0
- package/dist/esm/parsers/changelogParser.js +71 -0
- package/dist/esm/parsers/codexHistory.js +89 -0
- package/dist/esm/parsers/codexParser.js +906 -0
- package/dist/esm/parsers/debugLogParser.js +126 -0
- package/dist/esm/parsers/jsonl.js +66 -0
- package/dist/esm/parsers/mcpToolName.js +28 -0
- package/dist/esm/parsers/openCodeParser.js +625 -0
- package/dist/esm/parsers/planExtractor.js +335 -0
- package/dist/esm/parsers/sessionActivityDetector.js +246 -0
- package/dist/esm/parsers/sessionPathResolver.js +713 -0
- package/dist/esm/parsers/subagentScanner.js +360 -0
- package/dist/esm/parsers/subagentStatsCache.js +45 -0
- package/dist/esm/parsers/subagentTraceParser.js +325 -0
- package/dist/esm/paths.js +134 -0
- package/dist/esm/peakHours.js +194 -0
- package/dist/esm/phrases.js +1330 -0
- package/dist/esm/pricingCatalog.js +247 -0
- package/dist/esm/processDetection.js +200 -0
- package/dist/esm/projectMigration.js +59 -0
- package/dist/esm/promptHistory.js +1221 -0
- package/dist/esm/providerFailure.js +362 -0
- package/dist/esm/providerIds.js +6 -0
- package/dist/esm/providerQuota.js +1 -0
- package/dist/esm/providerServiceStatus.js +145 -0
- package/dist/esm/providerServiceStatusTypes.js +1 -0
- package/dist/esm/providerStatus.js +117 -0
- package/dist/esm/providers/claudeCode.js +575 -0
- package/dist/esm/providers/claudeListing.js +121 -0
- package/dist/esm/providers/codex.js +1034 -0
- package/dist/esm/providers/codexDatabase.js +297 -0
- package/dist/esm/providers/codexRollouts.js +215 -0
- package/dist/esm/providers/detect.js +185 -0
- package/dist/esm/providers/diagnostics.js +83 -0
- package/dist/esm/providers/directoryListingCache.js +206 -0
- package/dist/esm/providers/factory.js +54 -0
- package/dist/esm/providers/openCode.js +2008 -0
- package/dist/esm/providers/openCodeDatabase.js +419 -0
- package/dist/esm/providers/rolloutWalker.js +252 -0
- package/dist/esm/providers/types.js +12 -0
- package/dist/esm/quota.js +182 -0
- package/dist/esm/quotaHistory.js +364 -0
- package/dist/esm/quotaPoller.js +230 -0
- package/dist/esm/quotaPresentation.js +97 -0
- package/dist/esm/quotaResolver.js +231 -0
- package/dist/esm/quotaSnapshots.js +130 -0
- package/dist/esm/quotaThresholds.js +85 -0
- package/dist/esm/readers/decisions.js +24 -0
- package/dist/esm/readers/handoff.js +20 -0
- package/dist/esm/readers/helpers.js +27 -0
- package/dist/esm/readers/history.js +9 -0
- package/dist/esm/readers/notes.js +48 -0
- package/dist/esm/readers/plans.js +225 -0
- package/dist/esm/readers/tasks.js +19 -0
- package/dist/esm/report/htmlHelpers.js +280 -0
- package/dist/esm/report/htmlReportGenerator.js +704 -0
- package/dist/esm/report/index.js +7 -0
- package/dist/esm/report/logo.js +2 -0
- package/dist/esm/report/openBrowser.js +19 -0
- package/dist/esm/report/sessionReportInputs.js +33 -0
- package/dist/esm/report/transcriptParser.js +83 -0
- package/dist/esm/report/types.js +4 -0
- package/dist/esm/schemas/accountManager.js +204 -0
- package/dist/esm/schemas/accountStatus.js +25 -0
- package/dist/esm/schemas/assistantTurn.js +74 -0
- package/dist/esm/schemas/index.js +25 -0
- package/dist/esm/schemas/observedSessionV1.js +77 -0
- package/dist/esm/schemas/providerFailure.js +37 -0
- package/dist/esm/schemas/quota.js +132 -0
- package/dist/esm/schemas/quotaHistory.js +40 -0
- package/dist/esm/schemas/sessionEvent.js +216 -0
- package/dist/esm/schemas/stateFile.js +75 -0
- package/dist/esm/schemas/tokenEstimation.js +7 -0
- package/dist/esm/schemas/transcript.js +86 -0
- package/dist/esm/schemas/usageNormalization.js +38 -0
- package/dist/esm/search/advancedFilter.js +197 -0
- package/dist/esm/search/sessionSearch.js +66 -0
- package/dist/esm/sessionFingerprint.js +40 -0
- package/dist/esm/sessionMonitor.js +198 -0
- package/dist/esm/sessionPreviews.js +522 -0
- package/dist/esm/sessionPromptHistory.js +254 -0
- package/dist/esm/sessionPromptSignals.js +364 -0
- package/dist/esm/sessionStats.js +160 -0
- package/dist/esm/sessionTokenTotals.js +98 -0
- package/dist/esm/sessionTranscripts.js +49 -0
- package/dist/esm/stateFile.js +119 -0
- package/dist/esm/statusline/BurnRateCalculator.js +40 -0
- package/dist/esm/statusline/claudeStatuslinePayload.js +148 -0
- package/dist/esm/statusline/formatter.js +122 -0
- package/dist/esm/statusline/index.js +8 -0
- package/dist/esm/terminalSync.js +95 -0
- package/dist/esm/testing/credentialGuard.js +197 -0
- package/dist/esm/testing/index.js +12 -0
- package/dist/esm/testing/sessionLogFixtures.js +128 -0
- package/dist/esm/tokenEstimation.js +67 -0
- package/dist/esm/tokenSummary.js +113 -0
- package/dist/esm/toolCategory.js +82 -0
- package/dist/esm/transcript.js +257 -0
- package/dist/esm/turns/assistantTurn.js +373 -0
- package/dist/esm/types/codex.js +23 -0
- package/dist/esm/types/decisionLog.js +5 -0
- package/dist/esm/types/historicalData.js +47 -0
- package/dist/esm/types/knowledgeNote.js +15 -0
- package/dist/esm/types/observedSessionV1.js +257 -0
- package/dist/esm/types/opencode.js +12 -0
- package/dist/esm/types/plan.js +7 -0
- package/dist/esm/types/sessionEvent.js +10 -0
- package/dist/esm/types/taskPersistence.js +12 -0
- package/dist/esm/usage/billingBlocks.js +148 -0
- package/dist/esm/usage/claudeUsageDedupe.js +189 -0
- package/dist/esm/usage/importSessionHistory.js +84 -0
- package/dist/esm/usage/subagentUsage.js +18 -0
- package/dist/esm/usage/usageEvents.js +402 -0
- package/dist/esm/usage/usageReports.js +202 -0
- package/dist/esm/usageNormalization.js +95 -0
- package/dist/esm/watchers/eventBridge.js +219 -0
- package/dist/esm/watchers/factory.js +63 -0
- package/dist/esm/watchers/jsonlTail.js +289 -0
- package/dist/esm/watchers/jsonlWatcher.js +435 -0
- package/dist/esm/watchers/providerReaderWatcher.js +118 -0
- package/dist/esm/watchers/sqliteWatcher.js +285 -0
- package/dist/esm/watchers/types.js +4 -0
- package/dist/esm/workspaceRoots.js +56 -0
- package/dist/esm/writers/atomic.js +375 -0
- package/dist/esm/writers/decisions.js +51 -0
- package/dist/esm/writers/notes.js +46 -0
- package/dist/esm/writers/tasks.js +63 -0
- package/dist/esm/zaiQuota.js +323 -0
- package/dist/esm/zaiQuotaApi.js +271 -0
- package/dist/esm/zaiQuotaWatcher.js +265 -0
- package/dist/fileHead.d.ts +22 -0
- package/dist/fileHead.js +33 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +49 -15
- package/dist/node.d.ts +13 -1
- package/dist/node.js +43 -2
- package/dist/parsers/codexHistory.js +2 -2
- package/dist/parsers/codexParser.d.ts +12 -0
- package/dist/parsers/codexParser.js +34 -12
- package/dist/parsers/debugLogParser.js +2 -2
- package/dist/parsers/sessionPathResolver.js +5 -4
- package/dist/promptHistory.d.ts +32 -0
- package/dist/promptHistory.js +115 -59
- package/dist/providerFailure.d.ts +12 -6
- package/dist/providerFailure.js +45 -0
- package/dist/providers/claudeCode.js +7 -99
- package/dist/providers/claudeListing.d.ts +22 -0
- package/dist/providers/claudeListing.js +158 -0
- package/dist/providers/codex.d.ts +3 -1
- package/dist/providers/codex.js +26 -227
- package/dist/providers/codexRollouts.d.ts +44 -0
- package/dist/providers/codexRollouts.js +261 -0
- package/dist/providers/detect.js +4 -4
- package/dist/readers/plans.js +3 -3
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.js +7 -2
- package/dist/schemas/providerFailure.d.ts +154 -0
- package/dist/schemas/providerFailure.js +40 -0
- package/dist/sessionPromptHistory.d.ts +12 -7
- package/dist/sessionPromptHistory.js +15 -3
- package/dist/sessionPromptSignals.d.ts +9 -0
- package/dist/sessionPromptSignals.js +13 -0
- package/dist/testing/credentialGuard.d.ts +23 -0
- package/dist/testing/credentialGuard.js +233 -0
- package/dist/testing/index.d.ts +14 -0
- package/dist/testing/index.js +22 -0
- package/dist/testing/sessionLogFixtures.d.ts +28 -0
- package/dist/testing/sessionLogFixtures.js +169 -0
- package/dist/tokenEstimation.d.ts +2 -0
- package/dist/tokenEstimation.js +21 -11
- package/dist/toolCategory.d.ts +18 -0
- package/dist/toolCategory.js +86 -0
- package/dist/types/codex.d.ts +4 -0
- package/dist/usage/usageEvents.d.ts +16 -0
- package/dist/usage/usageEvents.js +53 -9
- package/dist/watchers/jsonlTail.d.ts +26 -1
- package/dist/watchers/jsonlTail.js +136 -28
- package/dist/watchers/jsonlWatcher.js +7 -0
- package/dist/watchers/providerReaderWatcher.js +1 -0
- package/dist/watchers/types.d.ts +6 -0
- package/dist/workspaceRoots.d.ts +23 -0
- package/dist/workspaceRoots.js +93 -0
- package/package.json +22 -2
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for runtime validation of quota state.
|
|
3
|
+
*
|
|
4
|
+
* These schemas mirror the TypeScript interfaces in `quota.ts`,
|
|
5
|
+
* `peakHours.ts`, `quotaPresentation.ts`, and `providerQuota.ts` (keep in
|
|
6
|
+
* sync when those change). They let consumers validate quota payloads at
|
|
7
|
+
* process/IPC boundaries without hand-mirroring the interfaces.
|
|
8
|
+
*
|
|
9
|
+
* @module schemas/quota
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { QUOTA_PROVIDER_IDS, RUNTIME_QUOTA_PROVIDER_IDS } from '../providerIds';
|
|
13
|
+
// ── QuotaWindow ──
|
|
14
|
+
export const quotaWindowSchema = z.object({
|
|
15
|
+
utilization: z.number(),
|
|
16
|
+
resetsAt: z.string(),
|
|
17
|
+
});
|
|
18
|
+
// ── QuotaState ──
|
|
19
|
+
export const quotaFailureKindSchema = z.enum([
|
|
20
|
+
'auth',
|
|
21
|
+
'network',
|
|
22
|
+
'rate_limit',
|
|
23
|
+
'server',
|
|
24
|
+
'unknown',
|
|
25
|
+
]);
|
|
26
|
+
export const quotaProviderIdSchema = z.enum(QUOTA_PROVIDER_IDS);
|
|
27
|
+
export const quotaSourceSchema = z.enum([
|
|
28
|
+
'api',
|
|
29
|
+
'session',
|
|
30
|
+
'cache',
|
|
31
|
+
'statusline',
|
|
32
|
+
]);
|
|
33
|
+
export const quotaCapturedSourceSchema = z.enum([
|
|
34
|
+
'api',
|
|
35
|
+
'session',
|
|
36
|
+
'statusline',
|
|
37
|
+
]);
|
|
38
|
+
export const quotaFreshnessSchema = z.enum(['fresh', 'aging', 'stale']);
|
|
39
|
+
export const codexResetCreditSchema = z.object({
|
|
40
|
+
title: z.string().optional(),
|
|
41
|
+
status: z.string(),
|
|
42
|
+
resetType: z.string().optional(),
|
|
43
|
+
expiresAt: z.string(),
|
|
44
|
+
grantedAt: z.string().optional(),
|
|
45
|
+
});
|
|
46
|
+
export const codexResetCreditsSnapshotSchema = z.object({
|
|
47
|
+
availableCount: z.number(),
|
|
48
|
+
totalEarnedCount: z.number().optional(),
|
|
49
|
+
credits: z.array(codexResetCreditSchema),
|
|
50
|
+
source: z.enum(['api', 'cache']).optional(),
|
|
51
|
+
capturedAt: z.string().optional(),
|
|
52
|
+
});
|
|
53
|
+
export const quotaStateSchema = z.object({
|
|
54
|
+
fiveHour: quotaWindowSchema,
|
|
55
|
+
sevenDay: quotaWindowSchema,
|
|
56
|
+
available: z.boolean(),
|
|
57
|
+
error: z.string().optional(),
|
|
58
|
+
failureKind: quotaFailureKindSchema.optional(),
|
|
59
|
+
httpStatus: z.number().optional(),
|
|
60
|
+
retryAfterMs: z.number().optional(),
|
|
61
|
+
projectedFiveHour: z.number().optional(),
|
|
62
|
+
projectedSevenDay: z.number().optional(),
|
|
63
|
+
providerId: quotaProviderIdSchema.optional(),
|
|
64
|
+
source: quotaSourceSchema.optional(),
|
|
65
|
+
capturedSource: quotaCapturedSourceSchema.optional(),
|
|
66
|
+
capturedAt: z.string().optional(),
|
|
67
|
+
stale: z.boolean().optional(),
|
|
68
|
+
ageMs: z.number().finite().nonnegative().optional(),
|
|
69
|
+
freshness: quotaFreshnessSchema.optional(),
|
|
70
|
+
fiveHourLabel: z.string().optional(),
|
|
71
|
+
sevenDayLabel: z.string().optional(),
|
|
72
|
+
limitId: z.string().optional(),
|
|
73
|
+
limitName: z.string().optional(),
|
|
74
|
+
credits: z.unknown().optional(),
|
|
75
|
+
resetCredits: codexResetCreditsSnapshotSchema.optional(),
|
|
76
|
+
planType: z.string().optional(),
|
|
77
|
+
rateLimitReachedType: z.string().optional(),
|
|
78
|
+
});
|
|
79
|
+
// ── PeakHoursState ──
|
|
80
|
+
export const peakHoursStateSchema = z.object({
|
|
81
|
+
status: z.enum(['peak', 'off_peak', 'unknown']),
|
|
82
|
+
isPeak: z.boolean(),
|
|
83
|
+
sessionLimitSpeed: z.enum(['normal', 'faster', 'unknown']),
|
|
84
|
+
label: z.string(),
|
|
85
|
+
peakHoursDescription: z.string(),
|
|
86
|
+
nextChange: z.string().nullable(),
|
|
87
|
+
minutesUntilChange: z.number().nullable(),
|
|
88
|
+
note: z.string(),
|
|
89
|
+
updatedAt: z.string(),
|
|
90
|
+
unavailable: z.boolean(),
|
|
91
|
+
notApplicable: z.boolean().optional(),
|
|
92
|
+
source: z.enum(['promoclock', 'schedule']).optional(),
|
|
93
|
+
});
|
|
94
|
+
// ── QuotaFailureDescriptor ──
|
|
95
|
+
export const quotaFailureDescriptorSchema = z.object({
|
|
96
|
+
severity: z.enum(['info', 'warning', 'error']),
|
|
97
|
+
title: z.string(),
|
|
98
|
+
message: z.string(),
|
|
99
|
+
detail: z.string().optional(),
|
|
100
|
+
alertKey: z.string(),
|
|
101
|
+
isRetryable: z.boolean(),
|
|
102
|
+
});
|
|
103
|
+
// ── ProviderQuotaState / ProviderQuotaMap ──
|
|
104
|
+
export const runtimeQuotaProviderSchema = z.enum(RUNTIME_QUOTA_PROVIDER_IDS);
|
|
105
|
+
/** Fields ProviderQuotaState adds on top of QuotaState, minus the provider tag. */
|
|
106
|
+
const providerQuotaExtensionShape = {
|
|
107
|
+
accountLabel: z.string().optional(),
|
|
108
|
+
accountDetail: z.string().optional(),
|
|
109
|
+
peakHours: peakHoursStateSchema.nullable().optional(),
|
|
110
|
+
failure: quotaFailureDescriptorSchema.nullable().optional(),
|
|
111
|
+
};
|
|
112
|
+
export const providerQuotaStateSchema = quotaStateSchema.extend({
|
|
113
|
+
runtimeProvider: runtimeQuotaProviderSchema,
|
|
114
|
+
...providerQuotaExtensionShape,
|
|
115
|
+
});
|
|
116
|
+
export const claudeProviderQuotaStateSchema = quotaStateSchema.extend({
|
|
117
|
+
runtimeProvider: z.literal('claude'),
|
|
118
|
+
...providerQuotaExtensionShape,
|
|
119
|
+
});
|
|
120
|
+
export const codexProviderQuotaStateSchema = quotaStateSchema.extend({
|
|
121
|
+
runtimeProvider: z.literal('codex'),
|
|
122
|
+
...providerQuotaExtensionShape,
|
|
123
|
+
});
|
|
124
|
+
export const zaiProviderQuotaStateSchema = quotaStateSchema.extend({
|
|
125
|
+
runtimeProvider: z.literal('zai'),
|
|
126
|
+
...providerQuotaExtensionShape,
|
|
127
|
+
});
|
|
128
|
+
export const providerQuotaMapSchema = z.object({
|
|
129
|
+
claude: claudeProviderQuotaStateSchema.optional(),
|
|
130
|
+
codex: codexProviderQuotaStateSchema.optional(),
|
|
131
|
+
zai: zaiProviderQuotaStateSchema.optional(),
|
|
132
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for runtime validation of quota history records.
|
|
3
|
+
*
|
|
4
|
+
* These schemas mirror the TypeScript interfaces in `quotaHistory.ts`
|
|
5
|
+
* (keep in sync when those change). They let consumers validate quota
|
|
6
|
+
* history payloads at process/IPC boundaries without hand-mirroring
|
|
7
|
+
* the interfaces.
|
|
8
|
+
*
|
|
9
|
+
* @module schemas/quotaHistory
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
// ── QuotaHistoryRuntimeProvider ──
|
|
13
|
+
export const quotaHistoryRuntimeProviderSchema = z.enum([
|
|
14
|
+
'claude',
|
|
15
|
+
'codex',
|
|
16
|
+
'zai',
|
|
17
|
+
]);
|
|
18
|
+
// ── QuotaHistorySample ──
|
|
19
|
+
export const quotaHistorySampleSchema = z.object({
|
|
20
|
+
timestamp: z.string(),
|
|
21
|
+
runtimeProvider: quotaHistoryRuntimeProviderSchema,
|
|
22
|
+
providerId: z.string(),
|
|
23
|
+
workspaceId: z.string(),
|
|
24
|
+
fiveHour: z.object({ utilization: z.number(), resetsAt: z.string() }),
|
|
25
|
+
sevenDay: z.object({ utilization: z.number(), resetsAt: z.string() }),
|
|
26
|
+
available: z.boolean(),
|
|
27
|
+
error: z.string().optional(),
|
|
28
|
+
source: z.enum(['session', 'cache', 'api', 'statusline']).optional(),
|
|
29
|
+
stale: z.boolean().optional(),
|
|
30
|
+
});
|
|
31
|
+
// ── QuotaHistoryDailyBucket ──
|
|
32
|
+
export const quotaHistoryDailyBucketSchema = z.object({
|
|
33
|
+
date: z.string(),
|
|
34
|
+
samples: z.number(),
|
|
35
|
+
maxUtilizationFiveHour: z.number(),
|
|
36
|
+
maxUtilizationSevenDay: z.number(),
|
|
37
|
+
avgUtilizationFiveHour: z.number(),
|
|
38
|
+
avgUtilizationSevenDay: z.number(),
|
|
39
|
+
anyUnavailable: z.boolean(),
|
|
40
|
+
});
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for runtime validation of session events.
|
|
3
|
+
*
|
|
4
|
+
* These schemas mirror the TypeScript interfaces in `types/sessionEvent.ts`
|
|
5
|
+
* and can be used to validate raw JSONL data before processing.
|
|
6
|
+
*
|
|
7
|
+
* @module schemas/sessionEvent
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { normalizedUsageSchema } from './usageNormalization';
|
|
11
|
+
// ── MessageUsage ──
|
|
12
|
+
export const messageUsageSchema = z.object({
|
|
13
|
+
input_tokens: z.number(),
|
|
14
|
+
output_tokens: z.number(),
|
|
15
|
+
cache_creation_input_tokens: z.number().optional(),
|
|
16
|
+
cache_read_input_tokens: z.number().optional(),
|
|
17
|
+
reported_cost: z.number().optional(),
|
|
18
|
+
reasoning_tokens: z.number().optional(),
|
|
19
|
+
});
|
|
20
|
+
// ── SessionMessage ──
|
|
21
|
+
export const sessionMessageSchema = z.object({
|
|
22
|
+
role: z.string(),
|
|
23
|
+
id: z.string().optional(),
|
|
24
|
+
sourceLabel: z.string().optional(),
|
|
25
|
+
model: z.string().optional(),
|
|
26
|
+
usage: messageUsageSchema.optional(),
|
|
27
|
+
normalizedUsage: normalizedUsageSchema.optional(),
|
|
28
|
+
usageKind: z.enum(['call', 'correction']).optional(),
|
|
29
|
+
content: z.unknown().optional(),
|
|
30
|
+
// Streaming lines can carry `stop_reason: null`; rejecting it dropped the
|
|
31
|
+
// whole event (text, tools, and usage), so normalize it to absent.
|
|
32
|
+
stop_reason: z
|
|
33
|
+
.string()
|
|
34
|
+
.nullish()
|
|
35
|
+
.transform((value) => value ?? undefined),
|
|
36
|
+
});
|
|
37
|
+
// ── PermissionMode ──
|
|
38
|
+
export const permissionModeSchema = z.enum([
|
|
39
|
+
'default',
|
|
40
|
+
'acceptEdits',
|
|
41
|
+
'bypassPermissions',
|
|
42
|
+
'plan',
|
|
43
|
+
]);
|
|
44
|
+
// ── SessionEvent ──
|
|
45
|
+
const eventBaseShape = {
|
|
46
|
+
timestamp: z.string(),
|
|
47
|
+
entrypoint: z.string().optional(),
|
|
48
|
+
isMeta: z.boolean().optional(),
|
|
49
|
+
isSidechain: z.boolean().optional(),
|
|
50
|
+
isCompactSummary: z.boolean().optional(),
|
|
51
|
+
origin: z.object({ kind: z.string().optional() }).optional(),
|
|
52
|
+
promptSource: z.string().optional(),
|
|
53
|
+
cwd: z.string().optional(),
|
|
54
|
+
gitBranch: z.string().optional(),
|
|
55
|
+
permissionMode: permissionModeSchema.optional(),
|
|
56
|
+
rateLimits: z
|
|
57
|
+
.object({
|
|
58
|
+
primary: z
|
|
59
|
+
.object({
|
|
60
|
+
usedPercent: z.number(),
|
|
61
|
+
windowMinutes: z.number(),
|
|
62
|
+
resetsAt: z.number(),
|
|
63
|
+
})
|
|
64
|
+
.optional(),
|
|
65
|
+
secondary: z
|
|
66
|
+
.object({
|
|
67
|
+
usedPercent: z.number(),
|
|
68
|
+
windowMinutes: z.number(),
|
|
69
|
+
resetsAt: z.number(),
|
|
70
|
+
})
|
|
71
|
+
.optional(),
|
|
72
|
+
})
|
|
73
|
+
.optional(),
|
|
74
|
+
compaction: z
|
|
75
|
+
.object({
|
|
76
|
+
tokensBefore: z.number().nonnegative(),
|
|
77
|
+
tokensAfter: z.number().nonnegative(),
|
|
78
|
+
})
|
|
79
|
+
.optional(),
|
|
80
|
+
providerMetadata: z
|
|
81
|
+
.object({
|
|
82
|
+
providerId: z.string().optional(),
|
|
83
|
+
source: z.string().optional(),
|
|
84
|
+
retryAttempts: z.array(z.number()).optional(),
|
|
85
|
+
finishReasons: z.array(z.string()).optional(),
|
|
86
|
+
providerError: z
|
|
87
|
+
.object({
|
|
88
|
+
type: z.string().optional(),
|
|
89
|
+
message: z.string().optional(),
|
|
90
|
+
code: z.union([z.string(), z.number()]).optional(),
|
|
91
|
+
})
|
|
92
|
+
.optional(),
|
|
93
|
+
})
|
|
94
|
+
.optional(),
|
|
95
|
+
};
|
|
96
|
+
const compactionSchema = z
|
|
97
|
+
.object({
|
|
98
|
+
tokensBefore: z.number().finite().int().nonnegative(),
|
|
99
|
+
tokensAfter: z.number().finite().int().nonnegative(),
|
|
100
|
+
})
|
|
101
|
+
.refine((value) => value.tokensAfter <= value.tokensBefore, {
|
|
102
|
+
message: 'tokensAfter must not exceed tokensBefore',
|
|
103
|
+
});
|
|
104
|
+
export const userSessionEventSchema = z.object({
|
|
105
|
+
type: z.literal('user'),
|
|
106
|
+
message: sessionMessageSchema,
|
|
107
|
+
...eventBaseShape,
|
|
108
|
+
});
|
|
109
|
+
export const assistantSessionEventSchema = z.object({
|
|
110
|
+
type: z.literal('assistant'),
|
|
111
|
+
message: sessionMessageSchema,
|
|
112
|
+
...eventBaseShape,
|
|
113
|
+
});
|
|
114
|
+
const summaryWithMessageSchema = z.object({
|
|
115
|
+
type: z.literal('summary'),
|
|
116
|
+
message: sessionMessageSchema,
|
|
117
|
+
summary: z.string().min(1).optional(),
|
|
118
|
+
...eventBaseShape,
|
|
119
|
+
compaction: compactionSchema.optional(),
|
|
120
|
+
});
|
|
121
|
+
const summaryWithTextSchema = z.object({
|
|
122
|
+
type: z.literal('summary'),
|
|
123
|
+
message: sessionMessageSchema.optional(),
|
|
124
|
+
summary: z.string().min(1),
|
|
125
|
+
...eventBaseShape,
|
|
126
|
+
compaction: compactionSchema.optional(),
|
|
127
|
+
});
|
|
128
|
+
const summaryWithCompactionSchema = z.object({
|
|
129
|
+
type: z.literal('summary'),
|
|
130
|
+
message: sessionMessageSchema.optional(),
|
|
131
|
+
summary: z.string().min(1).optional(),
|
|
132
|
+
...eventBaseShape,
|
|
133
|
+
compaction: compactionSchema,
|
|
134
|
+
});
|
|
135
|
+
export const summarySessionEventSchema = z.union([
|
|
136
|
+
summaryWithMessageSchema,
|
|
137
|
+
summaryWithTextSchema,
|
|
138
|
+
summaryWithCompactionSchema,
|
|
139
|
+
]);
|
|
140
|
+
export const systemSessionEventSchema = z.object({
|
|
141
|
+
type: z.literal('system'),
|
|
142
|
+
message: sessionMessageSchema.optional(),
|
|
143
|
+
...eventBaseShape,
|
|
144
|
+
});
|
|
145
|
+
export const toolUseSessionEventSchema = z.object({
|
|
146
|
+
type: z.literal('tool_use'),
|
|
147
|
+
message: sessionMessageSchema.optional(),
|
|
148
|
+
...eventBaseShape,
|
|
149
|
+
tool: z.object({ name: z.string(), input: z.record(z.string(), z.unknown()) }),
|
|
150
|
+
});
|
|
151
|
+
export const toolResultSessionEventSchema = z.object({
|
|
152
|
+
type: z.literal('tool_result'),
|
|
153
|
+
message: sessionMessageSchema.optional(),
|
|
154
|
+
...eventBaseShape,
|
|
155
|
+
result: z.object({
|
|
156
|
+
tool_use_id: z.string(),
|
|
157
|
+
output: z.unknown().optional(),
|
|
158
|
+
is_error: z.boolean().optional(),
|
|
159
|
+
}),
|
|
160
|
+
});
|
|
161
|
+
export const sessionEventSchema = z.union([
|
|
162
|
+
userSessionEventSchema,
|
|
163
|
+
assistantSessionEventSchema,
|
|
164
|
+
summarySessionEventSchema,
|
|
165
|
+
systemSessionEventSchema,
|
|
166
|
+
toolUseSessionEventSchema,
|
|
167
|
+
toolResultSessionEventSchema,
|
|
168
|
+
]);
|
|
169
|
+
// ── Progress unwrapping ──
|
|
170
|
+
/** Recursion bound for nested progress envelopes; real data nests 1 level. */
|
|
171
|
+
const MAX_PROGRESS_DEPTH = 8;
|
|
172
|
+
/**
|
|
173
|
+
* Extracts canonical SessionEvents from a raw JSONL value.
|
|
174
|
+
*
|
|
175
|
+
* Claude Code wraps subagent/SDK events as
|
|
176
|
+
* `{ type: 'progress', data: { message: <SessionEvent> } }`, which
|
|
177
|
+
* `sessionEventSchema` alone rejects. This helper tries a direct parse,
|
|
178
|
+
* then unwraps progress envelopes (recursively, in case of nesting).
|
|
179
|
+
* Returns zero events for unrecognized input — never throws.
|
|
180
|
+
*/
|
|
181
|
+
export function extractSessionEvents(raw, depth = 0) {
|
|
182
|
+
return extractSessionEventsWithProvenance(raw, depth, {});
|
|
183
|
+
}
|
|
184
|
+
function extractSessionEventsWithProvenance(raw, depth, inherited) {
|
|
185
|
+
const direct = sessionEventSchema.safeParse(raw);
|
|
186
|
+
if (direct.success)
|
|
187
|
+
return [{ ...inherited, ...direct.data }];
|
|
188
|
+
if (depth >= MAX_PROGRESS_DEPTH)
|
|
189
|
+
return [];
|
|
190
|
+
if (typeof raw === 'object' && raw !== null && raw.type === 'progress') {
|
|
191
|
+
const provenance = { ...inherited, ...progressProvenance(raw) };
|
|
192
|
+
const data = raw.data;
|
|
193
|
+
if (typeof data === 'object' && data !== null) {
|
|
194
|
+
const message = data.message;
|
|
195
|
+
if (typeof message === 'object' && message !== null) {
|
|
196
|
+
return extractSessionEventsWithProvenance(message, depth + 1, provenance);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return [];
|
|
201
|
+
}
|
|
202
|
+
function progressProvenance(raw) {
|
|
203
|
+
const value = raw;
|
|
204
|
+
const provenance = {};
|
|
205
|
+
if (typeof value.entrypoint === 'string')
|
|
206
|
+
provenance.entrypoint = value.entrypoint;
|
|
207
|
+
if (typeof value.isMeta === 'boolean')
|
|
208
|
+
provenance.isMeta = value.isMeta;
|
|
209
|
+
if (typeof value.isSidechain === 'boolean')
|
|
210
|
+
provenance.isSidechain = value.isSidechain;
|
|
211
|
+
if (typeof value.cwd === 'string')
|
|
212
|
+
provenance.cwd = value.cwd;
|
|
213
|
+
if (typeof value.gitBranch === 'string')
|
|
214
|
+
provenance.gitBranch = value.gitBranch;
|
|
215
|
+
return provenance;
|
|
216
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema for the public `state.json` contract (`schemaVersion: 1`).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the interfaces in `stateFile.ts` (keep in sync when those change;
|
|
5
|
+
* fields are only ever added). Consumers validating the file from another
|
|
6
|
+
* process import this from `sidekick-shared/schemas`.
|
|
7
|
+
*
|
|
8
|
+
* @module schemas/stateFile
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
export const stateFileWriterSchema = z.enum([
|
|
12
|
+
'statusline',
|
|
13
|
+
'cli-dashboard',
|
|
14
|
+
'vscode-dashboard',
|
|
15
|
+
]);
|
|
16
|
+
export const stateFileQuotaWindowSchema = z.object({
|
|
17
|
+
utilization: z.number(),
|
|
18
|
+
resetsAt: z.string(),
|
|
19
|
+
});
|
|
20
|
+
export const stateFileQuotaSchema = z.object({
|
|
21
|
+
fiveHour: stateFileQuotaWindowSchema,
|
|
22
|
+
sevenDay: stateFileQuotaWindowSchema,
|
|
23
|
+
source: z.enum(['api', 'session', 'cache', 'statusline']).nullable(),
|
|
24
|
+
capturedSource: z.enum(['api', 'session', 'statusline']).nullable(),
|
|
25
|
+
capturedAt: z.string().nullable(),
|
|
26
|
+
ageMs: z.number().nullable(),
|
|
27
|
+
freshness: z.enum(['fresh', 'aging', 'stale']).nullable(),
|
|
28
|
+
});
|
|
29
|
+
export const stateFileAccountSchema = z.object({
|
|
30
|
+
providerId: z.enum(['claude-code', 'codex']),
|
|
31
|
+
id: z.string().nullable(),
|
|
32
|
+
label: z.string().nullable(),
|
|
33
|
+
});
|
|
34
|
+
export const stateFileContextSchema = z.object({
|
|
35
|
+
usedPercentage: z.number().nullable(),
|
|
36
|
+
contextWindowSize: z.number().nullable(),
|
|
37
|
+
totalInputTokens: z.number().nullable(),
|
|
38
|
+
totalOutputTokens: z.number().nullable(),
|
|
39
|
+
totalTokens: z.number().nullable().optional(),
|
|
40
|
+
});
|
|
41
|
+
export const stateFileSessionSchema = z.object({
|
|
42
|
+
sessionId: z.string().nullable(),
|
|
43
|
+
cwd: z.string().nullable(),
|
|
44
|
+
model: z.string().nullable(),
|
|
45
|
+
costUsd: z.number().nullable(),
|
|
46
|
+
durationMs: z.number().nullable(),
|
|
47
|
+
linesAdded: z.number().nullable(),
|
|
48
|
+
linesRemoved: z.number().nullable(),
|
|
49
|
+
promptCacheHitRatio: z.number().nullable(),
|
|
50
|
+
});
|
|
51
|
+
export const stateFileBillingBlockSchema = z.object({
|
|
52
|
+
start: z.string(),
|
|
53
|
+
end: z.string(),
|
|
54
|
+
isActive: z.boolean(),
|
|
55
|
+
tokens: z.number(),
|
|
56
|
+
costUsd: z.number(),
|
|
57
|
+
costProvenance: z.enum(['reported', 'estimated', 'mixed', 'unpriced', 'none']),
|
|
58
|
+
burnRatePerMinute: z.number(),
|
|
59
|
+
projectedTokens: z.number(),
|
|
60
|
+
projectedCostUsd: z.number(),
|
|
61
|
+
remainingMs: z.number(),
|
|
62
|
+
});
|
|
63
|
+
export const sidekickStateFileSchema = z.object({
|
|
64
|
+
schemaVersion: z.literal(1),
|
|
65
|
+
writtenAt: z.string(),
|
|
66
|
+
writer: stateFileWriterSchema,
|
|
67
|
+
account: stateFileAccountSchema.nullable(),
|
|
68
|
+
quota: z.object({
|
|
69
|
+
claude: stateFileQuotaSchema.nullable(),
|
|
70
|
+
codex: stateFileQuotaSchema.nullable(),
|
|
71
|
+
}),
|
|
72
|
+
context: stateFileContextSchema.nullable(),
|
|
73
|
+
session: stateFileSessionSchema.nullable(),
|
|
74
|
+
billingBlock: stateFileBillingBlockSchema.nullable(),
|
|
75
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { normalizedUsageCostSchema, normalizedUsageSchema } from './usageNormalization';
|
|
3
|
+
export const transcriptSourceProvenanceSchema = z.object({
|
|
4
|
+
provider: z.string().optional(),
|
|
5
|
+
sessionId: z.string().optional(),
|
|
6
|
+
sourcePath: z.string().optional(),
|
|
7
|
+
source: z.string().optional(),
|
|
8
|
+
entrypoint: z.string().optional(),
|
|
9
|
+
isMeta: z.boolean().optional(),
|
|
10
|
+
isSidechain: z.boolean().optional(),
|
|
11
|
+
originalRole: z.string().optional(),
|
|
12
|
+
eventIndex: z.number().int().nonnegative(),
|
|
13
|
+
eventType: z.enum(['user', 'assistant', 'tool_use', 'tool_result', 'summary', 'system']),
|
|
14
|
+
eventId: z.string().optional(),
|
|
15
|
+
});
|
|
16
|
+
export const canonicalTranscriptBlockSchema = z.object({
|
|
17
|
+
type: z.enum(['text', 'thinking', 'tool_use', 'tool_result', 'image', 'unknown']),
|
|
18
|
+
text: z.string().optional(),
|
|
19
|
+
toolName: z.string().optional(),
|
|
20
|
+
toolUseId: z.string().optional(),
|
|
21
|
+
input: z.unknown().optional(),
|
|
22
|
+
output: z.unknown().optional(),
|
|
23
|
+
isError: z.boolean().optional(),
|
|
24
|
+
command: z.string().optional(),
|
|
25
|
+
truncated: z.boolean().optional(),
|
|
26
|
+
raw: z.unknown().optional(),
|
|
27
|
+
});
|
|
28
|
+
export const canonicalToolCallSchema = z.object({
|
|
29
|
+
id: z.string().optional(),
|
|
30
|
+
name: z.string(),
|
|
31
|
+
timestamp: z.string(),
|
|
32
|
+
input: z.unknown().optional(),
|
|
33
|
+
output: z.unknown().optional(),
|
|
34
|
+
isError: z.boolean().optional(),
|
|
35
|
+
command: z.string().optional(),
|
|
36
|
+
source: transcriptSourceProvenanceSchema,
|
|
37
|
+
});
|
|
38
|
+
export const canonicalTranscriptMessageSchema = z.object({
|
|
39
|
+
id: z.string().optional(),
|
|
40
|
+
role: z.enum(['user', 'assistant', 'system', 'summary', 'tool']),
|
|
41
|
+
timestamp: z.string(),
|
|
42
|
+
model: z.string().optional(),
|
|
43
|
+
sourceLabel: z.string().optional(),
|
|
44
|
+
content: z.array(canonicalTranscriptBlockSchema),
|
|
45
|
+
text: z.string(),
|
|
46
|
+
usage: normalizedUsageSchema.optional(),
|
|
47
|
+
cost: normalizedUsageCostSchema.optional(),
|
|
48
|
+
tools: z.array(canonicalToolCallSchema),
|
|
49
|
+
commands: z.array(z.string()),
|
|
50
|
+
source: transcriptSourceProvenanceSchema,
|
|
51
|
+
});
|
|
52
|
+
export const canonicalSessionTranscriptSchema = z.object({
|
|
53
|
+
provider: z.string().optional(),
|
|
54
|
+
sessionId: z.string().optional(),
|
|
55
|
+
sourcePath: z.string().optional(),
|
|
56
|
+
cwd: z.string().optional(),
|
|
57
|
+
gitBranch: z.string().optional(),
|
|
58
|
+
startedAt: z.string().optional(),
|
|
59
|
+
endedAt: z.string().optional(),
|
|
60
|
+
models: z.array(z.string()),
|
|
61
|
+
messages: z.array(canonicalTranscriptMessageSchema),
|
|
62
|
+
tools: z.array(canonicalToolCallSchema),
|
|
63
|
+
commands: z.array(z.string()),
|
|
64
|
+
usage: z.object({
|
|
65
|
+
events: z.array(normalizedUsageSchema),
|
|
66
|
+
costs: z.array(normalizedUsageCostSchema),
|
|
67
|
+
totals: z.object({
|
|
68
|
+
uncachedInputTokens: z.number().finite().nonnegative(),
|
|
69
|
+
cacheReadTokens: z.number().finite().nonnegative(),
|
|
70
|
+
cacheWriteTokens: z.number().finite().nonnegative(),
|
|
71
|
+
outputTokens: z.number().finite().nonnegative(),
|
|
72
|
+
reasoningTokens: z.number().finite().nonnegative(),
|
|
73
|
+
cacheInclusiveInputTokens: z.number().finite().nonnegative(),
|
|
74
|
+
billableOutputTokens: z.number().finite().nonnegative(),
|
|
75
|
+
totalTokens: z.number().finite().nonnegative(),
|
|
76
|
+
}),
|
|
77
|
+
totalCostUsd: z.number().finite().nonnegative().nullable(),
|
|
78
|
+
pricedCostUsd: z.number().finite().nonnegative(),
|
|
79
|
+
unpricedEvents: z.number().int().nonnegative(),
|
|
80
|
+
}),
|
|
81
|
+
provenance: z.object({
|
|
82
|
+
source: z.literal('session-events'),
|
|
83
|
+
fidelity: z.enum(['snippet', 'full']),
|
|
84
|
+
eventCount: z.number().int().nonnegative(),
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const normalizedUsageObjectSchema = z.object({
|
|
3
|
+
uncachedInputTokens: z.number().finite().nonnegative(),
|
|
4
|
+
cacheReadTokens: z.number().finite().nonnegative(),
|
|
5
|
+
cacheWriteTokens: z.number().finite().nonnegative(),
|
|
6
|
+
outputTokens: z.number().finite().nonnegative(),
|
|
7
|
+
reasoningTokens: z.number().finite().nonnegative(),
|
|
8
|
+
reasoningIncludedInOutput: z.boolean(),
|
|
9
|
+
cacheInclusiveInputTokens: z.number().finite().nonnegative(),
|
|
10
|
+
billableOutputTokens: z.number().finite().nonnegative(),
|
|
11
|
+
totalTokens: z.number().finite().nonnegative(),
|
|
12
|
+
model: z.string().optional(),
|
|
13
|
+
reportedCostUsd: z.number().finite().nonnegative().optional(),
|
|
14
|
+
provenance: z.object({
|
|
15
|
+
provider: z.string().optional(),
|
|
16
|
+
semantics: z.enum(['anthropic-additive-cache', 'openai-inclusive-cache', 'sidekick-disjoint']),
|
|
17
|
+
source: z.string().optional(),
|
|
18
|
+
}),
|
|
19
|
+
});
|
|
20
|
+
export const normalizedUsageSchema = normalizedUsageObjectSchema.superRefine((usage, context) => {
|
|
21
|
+
const expectedInput = usage.uncachedInputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
22
|
+
const expectedOutput = usage.outputTokens + (usage.reasoningIncludedInOutput ? 0 : usage.reasoningTokens);
|
|
23
|
+
if (usage.cacheInclusiveInputTokens !== expectedInput) {
|
|
24
|
+
context.addIssue({ code: 'custom', message: 'cacheInclusiveInputTokens is inconsistent' });
|
|
25
|
+
}
|
|
26
|
+
if (usage.billableOutputTokens !== expectedOutput) {
|
|
27
|
+
context.addIssue({ code: 'custom', message: 'billableOutputTokens is inconsistent' });
|
|
28
|
+
}
|
|
29
|
+
if (usage.totalTokens !== expectedInput + expectedOutput) {
|
|
30
|
+
context.addIssue({ code: 'custom', message: 'totalTokens is inconsistent' });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
export const normalizedUsageCostSchema = z.object({
|
|
34
|
+
costUsd: z.number().finite().nonnegative().nullable(),
|
|
35
|
+
source: z.enum(['provider-reported', 'explicit-pricing', 'model-catalog', 'unpriced']),
|
|
36
|
+
modelId: z.string().optional(),
|
|
37
|
+
usage: normalizedUsageSchema,
|
|
38
|
+
});
|