{"version":3,"file":"usage-budget.d.ts","sourceRoot":"","sources":["../../../../src/runs/shared/usage-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAA0B,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAgBtH,wBAAgB,yBAAyB,CACxC,KAAK,EAAE,OAAO,EACd,KAAK,SAAgB,GACnB;IAAE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAmBhD;AAgBD,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,iBAAiB,GAAG,SAAS,EACrC,MAAM,EAAE,WAAW,GAAG,SAAS,GAC7B,gBAAgB,GAAG,SAAS,CAgB9B;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAM1E","sourcesContent":["import type { CostSummary, UsageBudgetConfig, UsageBudgetLimitConfig, UsageBudgetState } from \"../../shared/types.ts\";\n\nfunction validateLimit(value: unknown, label: string): { limit?: UsageBudgetLimitConfig; error?: string } {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return { error: `${label} must be an object.` };\n\tconst raw = value as Record<string, unknown>;\n\tconst unknown = Object.keys(raw).find((key) => key !== \"soft\" && key !== \"hard\");\n\tif (unknown) return { error: `${label}.${unknown} is not supported.` };\n\tif (typeof raw.hard !== \"number\" || !Number.isFinite(raw.hard) || raw.hard <= 0)\n\t\treturn { error: `${label}.hard must be a positive number.` };\n\tif (raw.soft !== undefined && (typeof raw.soft !== \"number\" || !Number.isFinite(raw.soft) || raw.soft <= 0))\n\t\treturn { error: `${label}.soft must be a positive number.` };\n\tif (typeof raw.soft === \"number\" && raw.soft > raw.hard)\n\t\treturn { error: `${label}.soft must be less than or equal to ${label}.hard.` };\n\treturn { limit: { ...(typeof raw.soft === \"number\" ? { soft: raw.soft } : {}), hard: raw.hard } };\n}\n\nexport function validateUsageBudgetConfig(\n\tvalue: unknown,\n\tlabel = \"usageBudget\",\n): { budget?: UsageBudgetConfig; error?: string } {\n\tif (value === undefined) return {};\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return { error: `${label} must be an object.` };\n\tconst raw = value as Record<string, unknown>;\n\tconst unknown = Object.keys(raw).find((key) => key !== \"tokens\" && key !== \"costUsd\");\n\tif (unknown) return { error: `${label}.${unknown} is not supported.` };\n\tconst budget: UsageBudgetConfig = {};\n\tif (raw.tokens !== undefined) {\n\t\tconst tokens = validateLimit(raw.tokens, `${label}.tokens`);\n\t\tif (tokens.error) return { error: tokens.error };\n\t\tbudget.tokens = tokens.limit;\n\t}\n\tif (raw.costUsd !== undefined) {\n\t\tconst costUsd = validateLimit(raw.costUsd, `${label}.costUsd`);\n\t\tif (costUsd.error) return { error: costUsd.error };\n\t\tbudget.costUsd = costUsd.limit;\n\t}\n\tif (!budget.tokens && !budget.costUsd) return { error: `${label} must include tokens or costUsd.` };\n\treturn { budget };\n}\n\nfunction metricState(limit: UsageBudgetLimitConfig | undefined, used: number): UsageBudgetState[\"tokens\"] {\n\tif (!limit) return undefined;\n\treturn {\n\t\t...limit,\n\t\tused,\n\t\toutcome:\n\t\t\tused >= limit.hard\n\t\t\t\t? \"hard-exceeded\"\n\t\t\t\t: limit.soft !== undefined && used >= limit.soft\n\t\t\t\t\t? \"soft-exceeded\"\n\t\t\t\t\t: \"within-budget\",\n\t};\n}\n\nexport function usageBudgetState(\n\tconfig: UsageBudgetConfig | undefined,\n\ttotals: CostSummary | undefined,\n): UsageBudgetState | undefined {\n\tif (!config) return undefined;\n\tconst inputTokens = totals?.inputTokens ?? 0;\n\tconst outputTokens = totals?.outputTokens ?? 0;\n\tconst tokens = metricState(config.tokens, inputTokens + outputTokens);\n\tconst costUsd = metricState(config.costUsd, totals?.costUsd ?? 0);\n\tconst reason =\n\t\ttokens?.outcome === \"hard-exceeded\" ? \"tokens\" : costUsd?.outcome === \"hard-exceeded\" ? \"costUsd\" : undefined;\n\treturn {\n\t\tversion: 1,\n\t\tsource: \"reported\",\n\t\t...(tokens ? { tokens } : {}),\n\t\t...(costUsd ? { costUsd } : {}),\n\t\texhausted: reason !== undefined,\n\t\t...(reason ? { reason } : {}),\n\t};\n}\n\nexport function usageBudgetExceededMessage(state: UsageBudgetState): string {\n\tif (state.reason === \"tokens\" && state.tokens)\n\t\treturn `Usage budget exhausted: reported tokens ${state.tokens.used} reached hard limit ${state.tokens.hard}.`;\n\tif (state.reason === \"costUsd\" && state.costUsd)\n\t\treturn `Usage budget exhausted: reported cost $${state.costUsd.used.toFixed(6)} reached hard limit $${state.costUsd.hard.toFixed(6)}.`;\n\treturn \"Usage budget exhausted.\";\n}\n"]}