@agent-finops/core 0.1.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.
@@ -0,0 +1,5 @@
1
+ import { type UsageRecord } from "./schema.js";
2
+ export declare const sampleFiles: readonly ["samples/openai-usage.csv", "samples/anthropic-usage.csv"];
3
+ export declare function loadSampleUsageData(rootDir?: string): Promise<UsageRecord[]>;
4
+ export declare function parseUsageCsv(contents: string): UsageRecord[];
5
+ //# sourceMappingURL=sampleData.d.ts.map
@@ -0,0 +1,59 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { usageRecordSchema } from "./schema.js";
5
+ // One level up from dist/ = the package root, where samples/ ships (see
6
+ // "files" in package.json). Must survive npm installation — never resolve
7
+ // relative to the repo.
8
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
9
+ export const sampleFiles = [
10
+ "samples/openai-usage.csv",
11
+ "samples/anthropic-usage.csv"
12
+ ];
13
+ export async function loadSampleUsageData(rootDir = packageRoot) {
14
+ const records = await Promise.all(sampleFiles.map((file) => loadUsageCsv(resolve(rootDir, file))));
15
+ return records.flat().sort((left, right) => left.timestamp.localeCompare(right.timestamp));
16
+ }
17
+ async function loadUsageCsv(path) {
18
+ const contents = await readFile(path, "utf8");
19
+ return parseUsageCsv(contents);
20
+ }
21
+ export function parseUsageCsv(contents) {
22
+ const lines = contents.trim().split(/\r?\n/).filter(Boolean);
23
+ const [headerLine, ...recordLines] = lines;
24
+ if (!headerLine) {
25
+ return [];
26
+ }
27
+ const headers = headerLine.split(",").map((header) => header.trim());
28
+ return recordLines.map((line) => {
29
+ const values = line.split(",");
30
+ const row = Object.fromEntries(headers.map((header, index) => [header, values[index]?.trim() ?? ""]));
31
+ return usageRecordSchema.parse({
32
+ id: row.id,
33
+ timestamp: row.timestamp,
34
+ source: {
35
+ id: row.source_id,
36
+ name: row.source_name,
37
+ provider: row.provider,
38
+ confidence: row.source_confidence,
39
+ observedFrom: row.observed_from
40
+ },
41
+ model: row.model,
42
+ inputTokens: Number(row.input_tokens),
43
+ outputTokens: Number(row.output_tokens),
44
+ amountUsd: row.amount_usd === "" ? null : Number(row.amount_usd),
45
+ costConfidence: row.cost_confidence,
46
+ clientId: optionalValue(row.client_id),
47
+ projectId: optionalValue(row.project_id),
48
+ agentId: optionalValue(row.agent_id),
49
+ userId: optionalValue(row.user_id),
50
+ workspaceId: optionalValue(row.workspace_id),
51
+ apiKeyId: optionalValue(row.api_key_id),
52
+ operation: optionalValue(row.operation)
53
+ });
54
+ });
55
+ }
56
+ function optionalValue(value) {
57
+ return value === "" ? undefined : value;
58
+ }
59
+ //# sourceMappingURL=sampleData.js.map
@@ -0,0 +1,431 @@
1
+ import { z } from "zod";
2
+ export declare const costConfidenceValues: readonly ["verified", "estimated", "detected_unverified", "missing"];
3
+ export declare const costConfidenceSchema: z.ZodEnum<{
4
+ verified: "verified";
5
+ estimated: "estimated";
6
+ detected_unverified: "detected_unverified";
7
+ missing: "missing";
8
+ }>;
9
+ export type CostConfidence = z.infer<typeof costConfidenceSchema>;
10
+ export declare const spendSourceSchema: z.ZodObject<{
11
+ id: z.ZodString;
12
+ name: z.ZodString;
13
+ provider: z.ZodString;
14
+ confidence: z.ZodEnum<{
15
+ verified: "verified";
16
+ estimated: "estimated";
17
+ detected_unverified: "detected_unverified";
18
+ missing: "missing";
19
+ }>;
20
+ observedFrom: z.ZodString;
21
+ }, z.core.$strip>;
22
+ export type SpendSource = z.infer<typeof spendSourceSchema>;
23
+ export declare const usageRecordSchema: z.ZodObject<{
24
+ id: z.ZodString;
25
+ timestamp: z.ZodString;
26
+ source: z.ZodObject<{
27
+ id: z.ZodString;
28
+ name: z.ZodString;
29
+ provider: z.ZodString;
30
+ confidence: z.ZodEnum<{
31
+ verified: "verified";
32
+ estimated: "estimated";
33
+ detected_unverified: "detected_unverified";
34
+ missing: "missing";
35
+ }>;
36
+ observedFrom: z.ZodString;
37
+ }, z.core.$strip>;
38
+ model: z.ZodString;
39
+ inputTokens: z.ZodNumber;
40
+ outputTokens: z.ZodNumber;
41
+ amountUsd: z.ZodNullable<z.ZodNumber>;
42
+ costConfidence: z.ZodEnum<{
43
+ verified: "verified";
44
+ estimated: "estimated";
45
+ detected_unverified: "detected_unverified";
46
+ missing: "missing";
47
+ }>;
48
+ clientId: z.ZodOptional<z.ZodString>;
49
+ projectId: z.ZodOptional<z.ZodString>;
50
+ userId: z.ZodOptional<z.ZodString>;
51
+ apiKeyId: z.ZodOptional<z.ZodString>;
52
+ workspaceId: z.ZodOptional<z.ZodString>;
53
+ providerCostType: z.ZodOptional<z.ZodString>;
54
+ quantity: z.ZodOptional<z.ZodNumber>;
55
+ agentId: z.ZodOptional<z.ZodString>;
56
+ operation: z.ZodOptional<z.ZodString>;
57
+ }, z.core.$strip>;
58
+ export type UsageRecord = z.infer<typeof usageRecordSchema>;
59
+ export declare const attributionCandidateSchema: z.ZodObject<{
60
+ entityType: z.ZodEnum<{
61
+ client: "client";
62
+ project: "project";
63
+ agent: "agent";
64
+ user: "user";
65
+ workspace: "workspace";
66
+ api_key: "api_key";
67
+ }>;
68
+ entityId: z.ZodString;
69
+ confidence: z.ZodNumber;
70
+ evidence: z.ZodArray<z.ZodString>;
71
+ }, z.core.$strip>;
72
+ export type AttributionCandidate = z.infer<typeof attributionCandidateSchema>;
73
+ export declare const attributionMappingSchema: z.ZodObject<{
74
+ usageRecordId: z.ZodString;
75
+ candidates: z.ZodArray<z.ZodObject<{
76
+ entityType: z.ZodEnum<{
77
+ client: "client";
78
+ project: "project";
79
+ agent: "agent";
80
+ user: "user";
81
+ workspace: "workspace";
82
+ api_key: "api_key";
83
+ }>;
84
+ entityId: z.ZodString;
85
+ confidence: z.ZodNumber;
86
+ evidence: z.ZodArray<z.ZodString>;
87
+ }, z.core.$strip>>;
88
+ selected: z.ZodOptional<z.ZodObject<{
89
+ entityType: z.ZodEnum<{
90
+ client: "client";
91
+ project: "project";
92
+ agent: "agent";
93
+ user: "user";
94
+ workspace: "workspace";
95
+ api_key: "api_key";
96
+ }>;
97
+ entityId: z.ZodString;
98
+ confidence: z.ZodNumber;
99
+ evidence: z.ZodArray<z.ZodString>;
100
+ }, z.core.$strip>>;
101
+ status: z.ZodEnum<{
102
+ auto_mapped: "auto_mapped";
103
+ needs_confirmation: "needs_confirmation";
104
+ needs_question: "needs_question";
105
+ unmapped: "unmapped";
106
+ }>;
107
+ evidence: z.ZodArray<z.ZodString>;
108
+ }, z.core.$strip>;
109
+ export type AttributionMapping = z.infer<typeof attributionMappingSchema>;
110
+ export declare const spendBreakdownEntrySchema: z.ZodObject<{
111
+ key: z.ZodString;
112
+ amountUsd: z.ZodNumber;
113
+ recordCount: z.ZodNumber;
114
+ confidence: z.ZodEnum<{
115
+ verified: "verified";
116
+ estimated: "estimated";
117
+ detected_unverified: "detected_unverified";
118
+ missing: "missing";
119
+ }>;
120
+ }, z.core.$strip>;
121
+ export type SpendBreakdownEntry = z.infer<typeof spendBreakdownEntrySchema>;
122
+ export declare const spendAnomalySchema: z.ZodObject<{
123
+ kind: z.ZodEnum<{
124
+ day_over_day_spike: "day_over_day_spike";
125
+ week_over_week_spike: "week_over_week_spike";
126
+ }>;
127
+ key: z.ZodString;
128
+ previousAmountUsd: z.ZodNumber;
129
+ currentAmountUsd: z.ZodNumber;
130
+ multiplier: z.ZodNumber;
131
+ confidence: z.ZodEnum<{
132
+ verified: "verified";
133
+ estimated: "estimated";
134
+ detected_unverified: "detected_unverified";
135
+ missing: "missing";
136
+ }>;
137
+ }, z.core.$strip>;
138
+ export type SpendAnomaly = z.infer<typeof spendAnomalySchema>;
139
+ export declare const workflowWatchEntrySchema: z.ZodObject<{
140
+ id: z.ZodString;
141
+ clientId: z.ZodString;
142
+ projectId: z.ZodString;
143
+ workflowKey: z.ZodString;
144
+ agentId: z.ZodString;
145
+ amountUsd: z.ZodNumber;
146
+ shareOfSpend: z.ZodNumber;
147
+ recordCount: z.ZodNumber;
148
+ confidence: z.ZodEnum<{
149
+ verified: "verified";
150
+ estimated: "estimated";
151
+ detected_unverified: "detected_unverified";
152
+ missing: "missing";
153
+ }>;
154
+ estimatedMarginRiskUsd: z.ZodNumber;
155
+ estimatedSavingsUsd: z.ZodNumber;
156
+ suggestedOptimization: z.ZodString;
157
+ applyArtifact: z.ZodString;
158
+ verificationPlan: z.ZodString;
159
+ }, z.core.$strip>;
160
+ export type WorkflowWatchEntry = z.infer<typeof workflowWatchEntrySchema>;
161
+ export declare const recommendationSchema: z.ZodObject<{
162
+ id: z.ZodString;
163
+ title: z.ZodString;
164
+ rationale: z.ZodString;
165
+ whyItMatters: z.ZodString;
166
+ nextAction: z.ZodString;
167
+ priority: z.ZodEnum<{
168
+ high: "high";
169
+ medium: "medium";
170
+ low: "low";
171
+ }>;
172
+ estimatedImpactUsd: z.ZodNumber;
173
+ confidence: z.ZodEnum<{
174
+ verified: "verified";
175
+ estimated: "estimated";
176
+ detected_unverified: "detected_unverified";
177
+ missing: "missing";
178
+ }>;
179
+ relatedKeys: z.ZodArray<z.ZodString>;
180
+ }, z.core.$strip>;
181
+ export type Recommendation = z.infer<typeof recommendationSchema>;
182
+ export declare const evidenceItemSchema: z.ZodObject<{
183
+ label: z.ZodString;
184
+ value: z.ZodString;
185
+ detail: z.ZodOptional<z.ZodString>;
186
+ }, z.core.$strip>;
187
+ export type EvidenceItem = z.infer<typeof evidenceItemSchema>;
188
+ export declare const spendInsightSchema: z.ZodObject<{
189
+ id: z.ZodString;
190
+ kind: z.ZodEnum<{
191
+ spike_explanation: "spike_explanation";
192
+ margin_risk: "margin_risk";
193
+ agent_runaway: "agent_runaway";
194
+ model_misuse: "model_misuse";
195
+ context_bloat: "context_bloat";
196
+ unmapped_spend: "unmapped_spend";
197
+ connector_gap: "connector_gap";
198
+ optimization_opportunity: "optimization_opportunity";
199
+ }>;
200
+ severity: z.ZodEnum<{
201
+ high: "high";
202
+ medium: "medium";
203
+ low: "low";
204
+ critical: "critical";
205
+ }>;
206
+ title: z.ZodString;
207
+ summary: z.ZodString;
208
+ evidence: z.ZodArray<z.ZodObject<{
209
+ label: z.ZodString;
210
+ value: z.ZodString;
211
+ detail: z.ZodOptional<z.ZodString>;
212
+ }, z.core.$strip>>;
213
+ affectedClients: z.ZodArray<z.ZodString>;
214
+ affectedProjects: z.ZodArray<z.ZodString>;
215
+ affectedAgents: z.ZodArray<z.ZodString>;
216
+ affectedModels: z.ZodArray<z.ZodString>;
217
+ estimatedImpactUsd: z.ZodNumber;
218
+ confidence: z.ZodEnum<{
219
+ verified: "verified";
220
+ estimated: "estimated";
221
+ detected_unverified: "detected_unverified";
222
+ missing: "missing";
223
+ }>;
224
+ recommendedAction: z.ZodString;
225
+ verificationNeeded: z.ZodOptional<z.ZodString>;
226
+ }, z.core.$strip>;
227
+ export type SpendInsight = z.infer<typeof spendInsightSchema>;
228
+ export declare const spendSummarySchema: z.ZodObject<{
229
+ totalUsd: z.ZodNumber;
230
+ recordCount: z.ZodNumber;
231
+ confidence: z.ZodEnum<{
232
+ verified: "verified";
233
+ estimated: "estimated";
234
+ detected_unverified: "detected_unverified";
235
+ missing: "missing";
236
+ }>;
237
+ confidenceBreakdown: z.ZodRecord<z.ZodEnum<{
238
+ verified: "verified";
239
+ estimated: "estimated";
240
+ detected_unverified: "detected_unverified";
241
+ missing: "missing";
242
+ }>, z.ZodNumber>;
243
+ bySource: z.ZodArray<z.ZodObject<{
244
+ key: z.ZodString;
245
+ amountUsd: z.ZodNumber;
246
+ recordCount: z.ZodNumber;
247
+ confidence: z.ZodEnum<{
248
+ verified: "verified";
249
+ estimated: "estimated";
250
+ detected_unverified: "detected_unverified";
251
+ missing: "missing";
252
+ }>;
253
+ }, z.core.$strip>>;
254
+ byModel: z.ZodArray<z.ZodObject<{
255
+ key: z.ZodString;
256
+ amountUsd: z.ZodNumber;
257
+ recordCount: z.ZodNumber;
258
+ confidence: z.ZodEnum<{
259
+ verified: "verified";
260
+ estimated: "estimated";
261
+ detected_unverified: "detected_unverified";
262
+ missing: "missing";
263
+ }>;
264
+ }, z.core.$strip>>;
265
+ byClient: z.ZodArray<z.ZodObject<{
266
+ key: z.ZodString;
267
+ amountUsd: z.ZodNumber;
268
+ recordCount: z.ZodNumber;
269
+ confidence: z.ZodEnum<{
270
+ verified: "verified";
271
+ estimated: "estimated";
272
+ detected_unverified: "detected_unverified";
273
+ missing: "missing";
274
+ }>;
275
+ }, z.core.$strip>>;
276
+ byProject: z.ZodArray<z.ZodObject<{
277
+ key: z.ZodString;
278
+ amountUsd: z.ZodNumber;
279
+ recordCount: z.ZodNumber;
280
+ confidence: z.ZodEnum<{
281
+ verified: "verified";
282
+ estimated: "estimated";
283
+ detected_unverified: "detected_unverified";
284
+ missing: "missing";
285
+ }>;
286
+ }, z.core.$strip>>;
287
+ byAgent: z.ZodArray<z.ZodObject<{
288
+ key: z.ZodString;
289
+ amountUsd: z.ZodNumber;
290
+ recordCount: z.ZodNumber;
291
+ confidence: z.ZodEnum<{
292
+ verified: "verified";
293
+ estimated: "estimated";
294
+ detected_unverified: "detected_unverified";
295
+ missing: "missing";
296
+ }>;
297
+ }, z.core.$strip>>;
298
+ byUser: z.ZodDefault<z.ZodArray<z.ZodObject<{
299
+ key: z.ZodString;
300
+ amountUsd: z.ZodNumber;
301
+ recordCount: z.ZodNumber;
302
+ confidence: z.ZodEnum<{
303
+ verified: "verified";
304
+ estimated: "estimated";
305
+ detected_unverified: "detected_unverified";
306
+ missing: "missing";
307
+ }>;
308
+ }, z.core.$strip>>>;
309
+ byWorkspace: z.ZodDefault<z.ZodArray<z.ZodObject<{
310
+ key: z.ZodString;
311
+ amountUsd: z.ZodNumber;
312
+ recordCount: z.ZodNumber;
313
+ confidence: z.ZodEnum<{
314
+ verified: "verified";
315
+ estimated: "estimated";
316
+ detected_unverified: "detected_unverified";
317
+ missing: "missing";
318
+ }>;
319
+ }, z.core.$strip>>>;
320
+ byApiKey: z.ZodDefault<z.ZodArray<z.ZodObject<{
321
+ key: z.ZodString;
322
+ amountUsd: z.ZodNumber;
323
+ recordCount: z.ZodNumber;
324
+ confidence: z.ZodEnum<{
325
+ verified: "verified";
326
+ estimated: "estimated";
327
+ detected_unverified: "detected_unverified";
328
+ missing: "missing";
329
+ }>;
330
+ }, z.core.$strip>>>;
331
+ workflowWatch: z.ZodArray<z.ZodObject<{
332
+ id: z.ZodString;
333
+ clientId: z.ZodString;
334
+ projectId: z.ZodString;
335
+ workflowKey: z.ZodString;
336
+ agentId: z.ZodString;
337
+ amountUsd: z.ZodNumber;
338
+ shareOfSpend: z.ZodNumber;
339
+ recordCount: z.ZodNumber;
340
+ confidence: z.ZodEnum<{
341
+ verified: "verified";
342
+ estimated: "estimated";
343
+ detected_unverified: "detected_unverified";
344
+ missing: "missing";
345
+ }>;
346
+ estimatedMarginRiskUsd: z.ZodNumber;
347
+ estimatedSavingsUsd: z.ZodNumber;
348
+ suggestedOptimization: z.ZodString;
349
+ applyArtifact: z.ZodString;
350
+ verificationPlan: z.ZodString;
351
+ }, z.core.$strip>>;
352
+ anomalies: z.ZodArray<z.ZodObject<{
353
+ kind: z.ZodEnum<{
354
+ day_over_day_spike: "day_over_day_spike";
355
+ week_over_week_spike: "week_over_week_spike";
356
+ }>;
357
+ key: z.ZodString;
358
+ previousAmountUsd: z.ZodNumber;
359
+ currentAmountUsd: z.ZodNumber;
360
+ multiplier: z.ZodNumber;
361
+ confidence: z.ZodEnum<{
362
+ verified: "verified";
363
+ estimated: "estimated";
364
+ detected_unverified: "detected_unverified";
365
+ missing: "missing";
366
+ }>;
367
+ }, z.core.$strip>>;
368
+ recommendations: z.ZodArray<z.ZodObject<{
369
+ id: z.ZodString;
370
+ title: z.ZodString;
371
+ rationale: z.ZodString;
372
+ whyItMatters: z.ZodString;
373
+ nextAction: z.ZodString;
374
+ priority: z.ZodEnum<{
375
+ high: "high";
376
+ medium: "medium";
377
+ low: "low";
378
+ }>;
379
+ estimatedImpactUsd: z.ZodNumber;
380
+ confidence: z.ZodEnum<{
381
+ verified: "verified";
382
+ estimated: "estimated";
383
+ detected_unverified: "detected_unverified";
384
+ missing: "missing";
385
+ }>;
386
+ relatedKeys: z.ZodArray<z.ZodString>;
387
+ }, z.core.$strip>>;
388
+ insights: z.ZodDefault<z.ZodArray<z.ZodObject<{
389
+ id: z.ZodString;
390
+ kind: z.ZodEnum<{
391
+ spike_explanation: "spike_explanation";
392
+ margin_risk: "margin_risk";
393
+ agent_runaway: "agent_runaway";
394
+ model_misuse: "model_misuse";
395
+ context_bloat: "context_bloat";
396
+ unmapped_spend: "unmapped_spend";
397
+ connector_gap: "connector_gap";
398
+ optimization_opportunity: "optimization_opportunity";
399
+ }>;
400
+ severity: z.ZodEnum<{
401
+ high: "high";
402
+ medium: "medium";
403
+ low: "low";
404
+ critical: "critical";
405
+ }>;
406
+ title: z.ZodString;
407
+ summary: z.ZodString;
408
+ evidence: z.ZodArray<z.ZodObject<{
409
+ label: z.ZodString;
410
+ value: z.ZodString;
411
+ detail: z.ZodOptional<z.ZodString>;
412
+ }, z.core.$strip>>;
413
+ affectedClients: z.ZodArray<z.ZodString>;
414
+ affectedProjects: z.ZodArray<z.ZodString>;
415
+ affectedAgents: z.ZodArray<z.ZodString>;
416
+ affectedModels: z.ZodArray<z.ZodString>;
417
+ estimatedImpactUsd: z.ZodNumber;
418
+ confidence: z.ZodEnum<{
419
+ verified: "verified";
420
+ estimated: "estimated";
421
+ detected_unverified: "detected_unverified";
422
+ missing: "missing";
423
+ }>;
424
+ recommendedAction: z.ZodString;
425
+ verificationNeeded: z.ZodOptional<z.ZodString>;
426
+ }, z.core.$strip>>>;
427
+ }, z.core.$strip>;
428
+ export type SpendSummary = z.infer<typeof spendSummarySchema>;
429
+ export declare function parseUsageRecord(value: unknown): UsageRecord;
430
+ export declare function parseSpendSummary(value: unknown): SpendSummary;
431
+ //# sourceMappingURL=schema.d.ts.map
package/dist/schema.js ADDED
@@ -0,0 +1,158 @@
1
+ import { z } from "zod";
2
+ export const costConfidenceValues = [
3
+ "verified",
4
+ "estimated",
5
+ "detected_unverified",
6
+ "missing"
7
+ ];
8
+ export const costConfidenceSchema = z.enum(costConfidenceValues);
9
+ export const spendSourceSchema = z.object({
10
+ id: z.string().min(1),
11
+ name: z.string().min(1),
12
+ provider: z.string().min(1),
13
+ confidence: costConfidenceSchema,
14
+ observedFrom: z.string().min(1)
15
+ });
16
+ export const usageRecordSchema = z.object({
17
+ id: z.string().min(1),
18
+ timestamp: z.string().datetime({ offset: true }),
19
+ source: spendSourceSchema,
20
+ model: z.string().min(1),
21
+ inputTokens: z.number().int().nonnegative(),
22
+ outputTokens: z.number().int().nonnegative(),
23
+ amountUsd: z.number().nonnegative().nullable(),
24
+ costConfidence: costConfidenceSchema,
25
+ clientId: z.string().min(1).optional(),
26
+ projectId: z.string().min(1).optional(),
27
+ userId: z.string().min(1).optional(),
28
+ apiKeyId: z.string().min(1).optional(),
29
+ workspaceId: z.string().min(1).optional(),
30
+ providerCostType: z.string().min(1).optional(),
31
+ quantity: z.number().nonnegative().optional(),
32
+ agentId: z.string().min(1).optional(),
33
+ operation: z.string().min(1).optional()
34
+ }).superRefine((record, context) => {
35
+ if (record.costConfidence === "missing" && record.amountUsd !== null) {
36
+ context.addIssue({
37
+ code: "custom",
38
+ path: ["amountUsd"],
39
+ message: "Records with missing cost confidence must not include a cost."
40
+ });
41
+ }
42
+ if (record.costConfidence !== "missing" && record.amountUsd === null) {
43
+ context.addIssue({
44
+ code: "custom",
45
+ path: ["amountUsd"],
46
+ message: "Records with cost confidence require a cost amount."
47
+ });
48
+ }
49
+ });
50
+ export const attributionCandidateSchema = z.object({
51
+ entityType: z.enum(["client", "project", "agent", "user", "workspace", "api_key"]),
52
+ entityId: z.string().min(1),
53
+ confidence: z.number().min(0).max(1),
54
+ evidence: z.array(z.string().min(1)).min(1)
55
+ });
56
+ export const attributionMappingSchema = z.object({
57
+ usageRecordId: z.string().min(1),
58
+ candidates: z.array(attributionCandidateSchema),
59
+ selected: attributionCandidateSchema.optional(),
60
+ status: z.enum(["auto_mapped", "needs_confirmation", "needs_question", "unmapped"]),
61
+ evidence: z.array(z.string().min(1))
62
+ });
63
+ export const spendBreakdownEntrySchema = z.object({
64
+ key: z.string().min(1),
65
+ amountUsd: z.number().nonnegative(),
66
+ recordCount: z.number().int().nonnegative(),
67
+ confidence: costConfidenceSchema
68
+ });
69
+ export const spendAnomalySchema = z.object({
70
+ kind: z.enum(["day_over_day_spike", "week_over_week_spike"]),
71
+ key: z.string().min(1),
72
+ previousAmountUsd: z.number().nonnegative(),
73
+ currentAmountUsd: z.number().nonnegative(),
74
+ multiplier: z.number().nonnegative(),
75
+ confidence: costConfidenceSchema
76
+ });
77
+ export const workflowWatchEntrySchema = z.object({
78
+ id: z.string().min(1),
79
+ clientId: z.string().min(1),
80
+ projectId: z.string().min(1),
81
+ workflowKey: z.string().min(1),
82
+ agentId: z.string().min(1),
83
+ amountUsd: z.number().nonnegative(),
84
+ shareOfSpend: z.number().min(0).max(1),
85
+ recordCount: z.number().int().nonnegative(),
86
+ confidence: costConfidenceSchema,
87
+ estimatedMarginRiskUsd: z.number().nonnegative(),
88
+ estimatedSavingsUsd: z.number().nonnegative(),
89
+ suggestedOptimization: z.string().min(1),
90
+ applyArtifact: z.string().min(1),
91
+ verificationPlan: z.string().min(1)
92
+ });
93
+ export const recommendationSchema = z.object({
94
+ id: z.string().min(1),
95
+ title: z.string().min(1),
96
+ rationale: z.string().min(1),
97
+ whyItMatters: z.string().min(1),
98
+ nextAction: z.string().min(1),
99
+ priority: z.enum(["high", "medium", "low"]),
100
+ estimatedImpactUsd: z.number().nonnegative(),
101
+ confidence: costConfidenceSchema,
102
+ relatedKeys: z.array(z.string().min(1))
103
+ });
104
+ export const evidenceItemSchema = z.object({
105
+ label: z.string().min(1),
106
+ value: z.string().min(1),
107
+ detail: z.string().min(1).optional()
108
+ });
109
+ export const spendInsightSchema = z.object({
110
+ id: z.string().min(1),
111
+ kind: z.enum([
112
+ "spike_explanation",
113
+ "margin_risk",
114
+ "agent_runaway",
115
+ "model_misuse",
116
+ "context_bloat",
117
+ "unmapped_spend",
118
+ "connector_gap",
119
+ "optimization_opportunity"
120
+ ]),
121
+ severity: z.enum(["critical", "high", "medium", "low"]),
122
+ title: z.string().min(1),
123
+ summary: z.string().min(1),
124
+ evidence: z.array(evidenceItemSchema).min(1),
125
+ affectedClients: z.array(z.string().min(1)),
126
+ affectedProjects: z.array(z.string().min(1)),
127
+ affectedAgents: z.array(z.string().min(1)),
128
+ affectedModels: z.array(z.string().min(1)),
129
+ estimatedImpactUsd: z.number().nonnegative(),
130
+ confidence: costConfidenceSchema,
131
+ recommendedAction: z.string().min(1),
132
+ verificationNeeded: z.string().min(1).optional()
133
+ });
134
+ export const spendSummarySchema = z.object({
135
+ totalUsd: z.number().nonnegative(),
136
+ recordCount: z.number().int().nonnegative(),
137
+ confidence: costConfidenceSchema,
138
+ confidenceBreakdown: z.record(costConfidenceSchema, z.number().nonnegative()),
139
+ bySource: z.array(spendBreakdownEntrySchema),
140
+ byModel: z.array(spendBreakdownEntrySchema),
141
+ byClient: z.array(spendBreakdownEntrySchema),
142
+ byProject: z.array(spendBreakdownEntrySchema),
143
+ byAgent: z.array(spendBreakdownEntrySchema),
144
+ byUser: z.array(spendBreakdownEntrySchema).default([]),
145
+ byWorkspace: z.array(spendBreakdownEntrySchema).default([]),
146
+ byApiKey: z.array(spendBreakdownEntrySchema).default([]),
147
+ workflowWatch: z.array(workflowWatchEntrySchema),
148
+ anomalies: z.array(spendAnomalySchema),
149
+ recommendations: z.array(recommendationSchema),
150
+ insights: z.array(spendInsightSchema).default([])
151
+ });
152
+ export function parseUsageRecord(value) {
153
+ return usageRecordSchema.parse(value);
154
+ }
155
+ export function parseSpendSummary(value) {
156
+ return spendSummarySchema.parse(value);
157
+ }
158
+ //# sourceMappingURL=schema.js.map