Files
PaperClipAI/packages/shared/src/validators/cost.ts
T
DottaandPaperclip 2c96f76780 feat(connections): add model-backed prompt injection prevention
Add opt-in OpenRouter checks at existing tool-result boundaries with regex fallback, service accounting, and settings on Connections. Make migration 0362 safe to replay over existing or partially applied schema state.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 11:32:25 -05:00

46 lines
2.0 KiB
TypeScript

import { exactCentsSchema, pricingProvenanceSchema } from "../accounting.js";
import { z } from "zod";
import { BILLING_TYPES, COST_STATUSES } from "../constants.js";
const costEventFields = z.object({
idempotencyKey: z.string().trim().min(1).max(200).optional().nullable(),
agentId: z.string().guid(),
issueId: z.string().guid().optional().nullable(),
projectId: z.string().guid().optional().nullable(),
goalId: z.string().guid().optional().nullable(),
heartbeatRunId: z.string().guid().optional().nullable(),
billingCode: z.string().optional().nullable(),
provider: z.string().min(1),
biller: z.string().min(1).optional(),
billingType: z.enum(BILLING_TYPES).optional().default("unknown"),
costStatus: z.enum(COST_STATUSES).optional().default("reported"),
model: z.string().min(1),
inputTokens: z.number().int().nonnegative().max(2_147_483_647).optional().default(0),
cachedInputTokens: z.number().int().nonnegative().max(2_147_483_647).optional().default(0),
outputTokens: z.number().int().nonnegative().max(2_147_483_647).optional().default(0),
costCents: exactCentsSchema,
providerRequestId: z.string().min(1).max(250).nullable().optional(),
pricingProvenance: pricingProvenanceSchema.nullable().optional(),
occurredAt: z.string().datetime(),
});
export const createCostEventSchema = costEventFields.transform((value) => ({
...value,
biller: value.biller ?? value.provider,
}));
/** Internal service receipts; the public reporting endpoint retains its required agent. */
export const createServiceCostEventSchema = costEventFields.extend({
agentId: z.string().uuid().nullable(),
usageKind: z.enum(["decision", "fast_response", "prompt_injection"]),
responsibleUserId: z.string().nullable(),
}).transform(value => ({ ...value, biller: value.biller ?? value.provider }));
export type CreateCostEvent = z.input<typeof createCostEventSchema>;
export const updateBudgetSchema = z.object({
budgetMonthlyCents: z.number().int().nonnegative(),
});
export type UpdateBudget = z.infer<typeof updateBudgetSchema>;