@cat-factory/spend 0.12.18 → 0.12.20
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/dist/SpendService.d.ts +36 -18
- package/dist/SpendService.d.ts.map +1 -1
- package/dist/SpendService.js +49 -60
- package/dist/SpendService.js.map +1 -1
- package/package.json +8 -5
package/dist/SpendService.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BudgetCaps, OpenRouterModelMeta, SpendStatus } from '@cat-factory/contracts';
|
|
2
2
|
import type { AgentTokenUsage } from '@cat-factory/kernel';
|
|
3
3
|
import type { Clock, IdGenerator } from '@cat-factory/kernel';
|
|
4
|
-
import type { AccountRepository, TokenUsageRepository, UsageBilling, UsageBreakdownRow, UserSettingsRepository, WorkspaceSettingsRepository } from '@cat-factory/kernel';
|
|
4
|
+
import type { AccountRepository, BudgetLimitCacheValue, GroupCacheHandle, TokenUsageRepository, UsageBilling, UsageBreakdownRow, UserSettingsRepository, WorkspaceSettingsCacheValue, WorkspaceSettingsRepository } from '@cat-factory/kernel';
|
|
5
5
|
import { type SpendPricing } from './pricing.js';
|
|
6
6
|
export interface SpendServiceDependencies {
|
|
7
7
|
tokenUsageRepository: TokenUsageRepository;
|
|
@@ -36,6 +36,18 @@ export interface SpendServiceDependencies {
|
|
|
36
36
|
* the static table is used (the fallback price applies to uncatalogued slugs).
|
|
37
37
|
*/
|
|
38
38
|
dynamicPricesFor?: (workspaceId: string) => Promise<OpenRouterModelMeta[]>;
|
|
39
|
+
/**
|
|
40
|
+
* The shared {@link AppCaches.workspaceSettings} slice, through which the hot
|
|
41
|
+
* {@link SpendService.resolvePricing} read resolves a workspace's budget overrides —
|
|
42
|
+
* folding what used to be a per-service homebrew TTL `Map` into the app cache seam, so a
|
|
43
|
+
* budget edit invalidates coherently across replicas (the `Map` served stale peers for
|
|
44
|
+
* its TTL). Absent ⇒ the settings row is read live per call (standalone tests).
|
|
45
|
+
*/
|
|
46
|
+
workspaceSettingsCache?: GroupCacheHandle<WorkspaceSettingsCacheValue>;
|
|
47
|
+
/** The shared {@link AppCaches.accountBudgetLimit} slice (see `workspaceSettingsCache`). */
|
|
48
|
+
accountBudgetLimitCache?: GroupCacheHandle<BudgetLimitCacheValue>;
|
|
49
|
+
/** The shared {@link AppCaches.userBudgetLimit} slice (see `workspaceSettingsCache`). */
|
|
50
|
+
userBudgetLimitCache?: GroupCacheHandle<BudgetLimitCacheValue>;
|
|
39
51
|
}
|
|
40
52
|
/** Details of a single metered LLM call, handed in by the execution engine. */
|
|
41
53
|
export interface RecordUsageInput {
|
|
@@ -74,8 +86,9 @@ export interface BudgetTierScope {
|
|
|
74
86
|
* workspace's currency/monthly-limit overrides onto the built-in base table; the account
|
|
75
87
|
* and user tiers compare their own rollup against a configured limit clamped by the
|
|
76
88
|
* operator env cap. A run is over budget when ANY applicable tier is exhausted.
|
|
77
|
-
*
|
|
78
|
-
* settings per
|
|
89
|
+
* The workspace-pricing and per-tier-limit reads resolve through the app cache seam
|
|
90
|
+
* ({@link AppCaches}) so the hot {@link isOverBudget} gate doesn't re-read settings per
|
|
91
|
+
* step; a budget edit invalidates the relevant slice so it takes effect immediately.
|
|
79
92
|
*/
|
|
80
93
|
export declare class SpendService {
|
|
81
94
|
private readonly tokenUsageRepository;
|
|
@@ -86,28 +99,33 @@ export declare class SpendService {
|
|
|
86
99
|
private readonly accountRepository?;
|
|
87
100
|
private readonly userSettingsRepository?;
|
|
88
101
|
private readonly dynamicPricesFor?;
|
|
89
|
-
private readonly
|
|
90
|
-
private readonly
|
|
91
|
-
private readonly
|
|
92
|
-
constructor({ tokenUsageRepository, idGenerator, clock, pricing, workspaceSettingsRepository, accountRepository, userSettingsRepository, dynamicPricesFor, }: SpendServiceDependencies);
|
|
102
|
+
private readonly workspaceSettingsCache?;
|
|
103
|
+
private readonly accountBudgetLimitCache?;
|
|
104
|
+
private readonly userBudgetLimitCache?;
|
|
105
|
+
constructor({ tokenUsageRepository, idGenerator, clock, pricing, workspaceSettingsRepository, accountRepository, userSettingsRepository, dynamicPricesFor, workspaceSettingsCache, accountBudgetLimitCache, userBudgetLimitCache, }: SpendServiceDependencies);
|
|
93
106
|
/** Parse a `provider:model` identifier into a {@link ModelRef}. */
|
|
94
107
|
private parseModel;
|
|
95
108
|
/**
|
|
96
|
-
* The workspace's effective pricing (base table overlaid with its budget overrides)
|
|
97
|
-
*
|
|
98
|
-
*
|
|
109
|
+
* The workspace's effective pricing (base table overlaid with its budget overrides).
|
|
110
|
+
* The underlying settings row is read through the shared `workspaceSettings` cache slice
|
|
111
|
+
* (invalidated by `WorkspaceSettingsService.update`, so a budget edit takes effect on the
|
|
112
|
+
* next call). Falls back to the base table when no settings repository is wired.
|
|
99
113
|
*/
|
|
100
114
|
private resolvePricing;
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Invalidate a cached account effective limit (called after an account-budget edit, via
|
|
117
|
+
* `AccountService`'s budget-change callback). A no-op when no cache is wired.
|
|
118
|
+
*/
|
|
119
|
+
invalidateAccountLimit(accountId: string): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Invalidate a cached user effective limit (called after a user-budget edit, via
|
|
122
|
+
* `UserSettingsService`'s budget-change callback). A no-op when no cache is wired.
|
|
123
|
+
*/
|
|
124
|
+
invalidateUserLimit(userId: string): Promise<void>;
|
|
107
125
|
/**
|
|
108
126
|
* The account tier's effective monthly limit: the configured account limit clamped by
|
|
109
|
-
* the operator env cap. `Infinity` when the tier is inactive (neither set).
|
|
110
|
-
*
|
|
127
|
+
* the operator env cap. `Infinity` when the tier is inactive (neither set). The configured
|
|
128
|
+
* limit is read through the shared `accountBudgetLimit` cache slice.
|
|
111
129
|
*/
|
|
112
130
|
private resolveAccountLimit;
|
|
113
131
|
/** The user tier's effective monthly limit (configured user limit clamped by the env cap). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpendService.d.ts","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAC1F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAE1D,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC5B,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"SpendService.d.ts","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"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"}
|
package/dist/SpendService.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { readCachedWorkspaceSettings } from '@cat-factory/kernel';
|
|
1
2
|
import { effectiveTierLimit, estimateCost, mergeSpendPricing, startOfMonthUtc, withDynamicPrices, } from './pricing.js';
|
|
2
|
-
/** How long a workspace's resolved pricing is cached before reloading (ms). */
|
|
3
|
-
const PRICING_CACHE_TTL_MS = 30_000;
|
|
4
3
|
/**
|
|
5
4
|
* The spend safeguard. It meters token usage into a persistent ledger, prices
|
|
6
5
|
* each call into a single currency, and reports the current billing period's
|
|
@@ -12,8 +11,9 @@ const PRICING_CACHE_TTL_MS = 30_000;
|
|
|
12
11
|
* workspace's currency/monthly-limit overrides onto the built-in base table; the account
|
|
13
12
|
* and user tiers compare their own rollup against a configured limit clamped by the
|
|
14
13
|
* operator env cap. A run is over budget when ANY applicable tier is exhausted.
|
|
15
|
-
*
|
|
16
|
-
* settings per
|
|
14
|
+
* The workspace-pricing and per-tier-limit reads resolve through the app cache seam
|
|
15
|
+
* ({@link AppCaches}) so the hot {@link isOverBudget} gate doesn't re-read settings per
|
|
16
|
+
* step; a budget edit invalidates the relevant slice so it takes effect immediately.
|
|
17
17
|
*/
|
|
18
18
|
export class SpendService {
|
|
19
19
|
tokenUsageRepository;
|
|
@@ -24,10 +24,10 @@ export class SpendService {
|
|
|
24
24
|
accountRepository;
|
|
25
25
|
userSettingsRepository;
|
|
26
26
|
dynamicPricesFor;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
constructor({ tokenUsageRepository, idGenerator, clock, pricing, workspaceSettingsRepository, accountRepository, userSettingsRepository, dynamicPricesFor, }) {
|
|
27
|
+
workspaceSettingsCache;
|
|
28
|
+
accountBudgetLimitCache;
|
|
29
|
+
userBudgetLimitCache;
|
|
30
|
+
constructor({ tokenUsageRepository, idGenerator, clock, pricing, workspaceSettingsRepository, accountRepository, userSettingsRepository, dynamicPricesFor, workspaceSettingsCache, accountBudgetLimitCache, userBudgetLimitCache, }) {
|
|
31
31
|
this.tokenUsageRepository = tokenUsageRepository;
|
|
32
32
|
this.idGenerator = idGenerator;
|
|
33
33
|
this.clock = clock;
|
|
@@ -36,6 +36,9 @@ export class SpendService {
|
|
|
36
36
|
this.accountRepository = accountRepository;
|
|
37
37
|
this.userSettingsRepository = userSettingsRepository;
|
|
38
38
|
this.dynamicPricesFor = dynamicPricesFor;
|
|
39
|
+
this.workspaceSettingsCache = workspaceSettingsCache;
|
|
40
|
+
this.accountBudgetLimitCache = accountBudgetLimitCache;
|
|
41
|
+
this.userBudgetLimitCache = userBudgetLimitCache;
|
|
39
42
|
}
|
|
40
43
|
/** Parse a `provider:model` identifier into a {@link ModelRef}. */
|
|
41
44
|
parseModel(model) {
|
|
@@ -45,76 +48,62 @@ export class SpendService {
|
|
|
45
48
|
return { provider: model.slice(0, idx), model: model.slice(idx + 1) };
|
|
46
49
|
}
|
|
47
50
|
/**
|
|
48
|
-
* The workspace's effective pricing (base table overlaid with its budget overrides)
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
+
* The workspace's effective pricing (base table overlaid with its budget overrides).
|
|
52
|
+
* The underlying settings row is read through the shared `workspaceSettings` cache slice
|
|
53
|
+
* (invalidated by `WorkspaceSettingsService.update`, so a budget edit takes effect on the
|
|
54
|
+
* next call). Falls back to the base table when no settings repository is wired.
|
|
51
55
|
*/
|
|
52
56
|
async resolvePricing(workspaceId) {
|
|
53
57
|
if (!this.workspaceSettingsRepository)
|
|
54
58
|
return this.pricing;
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
if (cached && cached.expiresAt > now)
|
|
58
|
-
return cached.value;
|
|
59
|
-
const settings = await this.workspaceSettingsRepository.get(workspaceId);
|
|
60
|
-
const value = mergeSpendPricing(this.pricing, settings);
|
|
61
|
-
this.pricingCache.set(workspaceId, { value, expiresAt: now + PRICING_CACHE_TTL_MS });
|
|
62
|
-
return value;
|
|
59
|
+
const settings = await readCachedWorkspaceSettings(this.workspaceSettingsCache, this.workspaceSettingsRepository, workspaceId);
|
|
60
|
+
return mergeSpendPricing(this.pricing, settings);
|
|
63
61
|
}
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.accountLimitCache.delete(accountId);
|
|
62
|
+
/**
|
|
63
|
+
* Invalidate a cached account effective limit (called after an account-budget edit, via
|
|
64
|
+
* `AccountService`'s budget-change callback). A no-op when no cache is wired.
|
|
65
|
+
*/
|
|
66
|
+
async invalidateAccountLimit(accountId) {
|
|
67
|
+
await this.accountBudgetLimitCache?.invalidate(accountId, accountId);
|
|
71
68
|
}
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Invalidate a cached user effective limit (called after a user-budget edit, via
|
|
71
|
+
* `UserSettingsService`'s budget-change callback). A no-op when no cache is wired.
|
|
72
|
+
*/
|
|
73
|
+
async invalidateUserLimit(userId) {
|
|
74
|
+
await this.userBudgetLimitCache?.invalidate(userId, userId);
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* The account tier's effective monthly limit: the configured account limit clamped by
|
|
78
|
-
* the operator env cap. `Infinity` when the tier is inactive (neither set).
|
|
79
|
-
*
|
|
78
|
+
* the operator env cap. `Infinity` when the tier is inactive (neither set). The configured
|
|
79
|
+
* limit is read through the shared `accountBudgetLimit` cache slice.
|
|
80
80
|
*/
|
|
81
81
|
async resolveAccountLimit(accountId) {
|
|
82
82
|
const cap = this.pricing.accountMonthlyLimitCap;
|
|
83
|
-
|
|
83
|
+
const repository = this.accountRepository;
|
|
84
|
+
if (!repository)
|
|
84
85
|
return effectiveTierLimit(null, cap);
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const account = await this.accountRepository.get(accountId);
|
|
93
|
-
configured = account?.spendMonthlyLimit ?? null;
|
|
94
|
-
this.accountLimitCache.set(accountId, {
|
|
95
|
-
value: configured,
|
|
96
|
-
expiresAt: now + PRICING_CACHE_TTL_MS,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return effectiveTierLimit(configured, cap);
|
|
86
|
+
const load = async () => ({
|
|
87
|
+
limit: (await repository.get(accountId))?.spendMonthlyLimit ?? null,
|
|
88
|
+
});
|
|
89
|
+
const { limit } = this.accountBudgetLimitCache
|
|
90
|
+
? await this.accountBudgetLimitCache.get(accountId, accountId, load)
|
|
91
|
+
: await load();
|
|
92
|
+
return effectiveTierLimit(limit, cap);
|
|
100
93
|
}
|
|
101
94
|
/** The user tier's effective monthly limit (configured user limit clamped by the env cap). */
|
|
102
95
|
async resolveUserLimit(userId) {
|
|
103
96
|
const cap = this.pricing.userMonthlyLimitCap;
|
|
104
|
-
|
|
97
|
+
const repository = this.userSettingsRepository;
|
|
98
|
+
if (!repository)
|
|
105
99
|
return effectiveTierLimit(null, cap);
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const settings = await this.userSettingsRepository.get(userId);
|
|
114
|
-
configured = settings?.spendMonthlyLimit ?? null;
|
|
115
|
-
this.userLimitCache.set(userId, { value: configured, expiresAt: now + PRICING_CACHE_TTL_MS });
|
|
116
|
-
}
|
|
117
|
-
return effectiveTierLimit(configured, cap);
|
|
100
|
+
const load = async () => ({
|
|
101
|
+
limit: (await repository.get(userId))?.spendMonthlyLimit ?? null,
|
|
102
|
+
});
|
|
103
|
+
const { limit } = this.userBudgetLimitCache
|
|
104
|
+
? await this.userBudgetLimitCache.get(userId, userId, load)
|
|
105
|
+
: await load();
|
|
106
|
+
return effectiveTierLimit(limit, cap);
|
|
118
107
|
}
|
|
119
108
|
/** Meter and persist one LLM call; returns its estimated cost. */
|
|
120
109
|
async record(input) {
|
package/dist/SpendService.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpendService.js","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SpendService.js","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/spend",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.20",
|
|
4
4
|
"description": "Pricing tables and spend metering for the Agent Architecture Board.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,14 +24,17 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@cat-factory/contracts": "0.127.
|
|
28
|
-
"@cat-factory/kernel": "0.121.
|
|
27
|
+
"@cat-factory/contracts": "0.127.1",
|
|
28
|
+
"@cat-factory/kernel": "0.121.6"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"typescript": "7.0.
|
|
31
|
+
"typescript": "7.0.2",
|
|
32
|
+
"vitest": "^4.1.10"
|
|
32
33
|
},
|
|
33
34
|
"scripts": {
|
|
34
35
|
"build": "tsc -b tsconfig.build.json",
|
|
35
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
36
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
|
+
"test": "vitest",
|
|
38
|
+
"test:run": "vitest run"
|
|
36
39
|
}
|
|
37
40
|
}
|