crewly 1.20.187 → 1.20.188
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/config/skills/agent/core/project-tickets/SKILL.md +3 -2
- package/config/skills/agent/core/project-tickets/execute.sh +4 -4
- package/config/skills/agent/core/project-tickets/execute.test.sh +2 -2
- package/dist/backend/backend/src/constants.d.ts +70 -12
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +70 -12
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +5 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +1 -1
- package/dist/backend/backend/src/controllers/system/usage.controller.d.ts +46 -0
- package/dist/backend/backend/src/controllers/system/usage.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/system/usage.controller.js +181 -0
- package/dist/backend/backend/src/controllers/system/usage.controller.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts +7 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +59 -4
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.js +3 -3
- package/dist/backend/backend/src/routes/modules/system.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +7 -7
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts +4 -2
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js +6 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +2 -2
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +4 -2
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts +130 -0
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js +274 -0
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts +152 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js +311 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +53 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js +51 -3
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +4 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +4 -3
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +7 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +40 -9
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +68 -20
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap-command.d.ts +48 -18
- package/dist/backend/backend/src/services/spend/spend-cap-command.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap-command.js +195 -62
- package/dist/backend/backend/src/services/spend/spend-cap-command.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.gate.d.ts +11 -15
- package/dist/backend/backend/src/services/spend/spend-cap.gate.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.gate.js +8 -13
- package/dist/backend/backend/src/services/spend/spend-cap.gate.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts +179 -64
- package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.service.js +406 -149
- package/dist/backend/backend/src/services/spend/spend-cap.service.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts +52 -11
- package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.store.js +67 -21
- package/dist/backend/backend/src/services/spend/spend-cap.store.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts +3 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.js +21 -7
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-ledger.service.d.ts +57 -36
- package/dist/backend/backend/src/services/spend/spend-ledger.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-ledger.service.js +80 -55
- package/dist/backend/backend/src/services/spend/spend-ledger.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/work-item-usage.d.ts +10 -1
- package/dist/backend/backend/src/services/task-pool/work-item-usage.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/work-item-usage.js +2 -0
- package/dist/backend/backend/src/services/task-pool/work-item-usage.js.map +1 -1
- package/dist/backend/backend/src/services/usage/token-format.d.ts +49 -0
- package/dist/backend/backend/src/services/usage/token-format.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage/token-format.js +81 -0
- package/dist/backend/backend/src/services/usage/token-format.js.map +1 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.d.ts +132 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.js +226 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.js.map +1 -0
- package/dist/backend/backend/src/types/decision.types.d.ts +2 -2
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts +24 -7
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/ticket-autopilot.types.js +29 -13
- package/dist/backend/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +70 -12
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +70 -12
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +7 -7
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts +4 -2
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js +6 -1
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.js +2 -2
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js +4 -2
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +53 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js +51 -3
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/cli/backend/src/services/spend/spend-cap.gate.d.ts +11 -15
- package/dist/cli/backend/src/services/spend/spend-cap.gate.d.ts.map +1 -1
- package/dist/cli/backend/src/services/spend/spend-cap.gate.js +8 -13
- package/dist/cli/backend/src/services/spend/spend-cap.gate.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/work-item-usage.d.ts +10 -1
- package/dist/cli/backend/src/services/task-pool/work-item-usage.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/work-item-usage.js +2 -0
- package/dist/cli/backend/src/services/task-pool/work-item-usage.js.map +1 -1
- package/dist/cli/backend/src/services/usage/token-format.d.ts +49 -0
- package/dist/cli/backend/src/services/usage/token-format.d.ts.map +1 -0
- package/dist/cli/backend/src/services/usage/token-format.js +81 -0
- package/dist/cli/backend/src/services/usage/token-format.js.map +1 -0
- package/dist/cli/backend/src/types/decision.types.d.ts +2 -2
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts +24 -7
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/ticket-autopilot.types.js +29 -13
- package/dist/cli/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/frontend/dist/assets/{index-15c2faf2.js → index-49f50b45.js} +276 -276
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/dist/backend/backend/src/controllers/system/spend.controller.d.ts +0 -32
- package/dist/backend/backend/src/controllers/system/spend.controller.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/system/spend.controller.js +0 -100
- package/dist/backend/backend/src/controllers/system/spend.controller.js.map +0 -1
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Usage ledger — how many tokens each agent used, per local day.
|
|
3
3
|
*
|
|
4
4
|
* Reads the shared token ledger (`~/.crewly/token-usage.json`, held in
|
|
5
|
-
* memory by {@link TokenUsageService}).
|
|
6
|
-
* there: the in-process Crewly Agent runtime
|
|
7
|
-
*
|
|
8
|
-
* turn with its cache split. Each event is priced with {@link eventCostUsd},
|
|
9
|
-
* the same computation the ticket autopilot budget and the team budget gate
|
|
10
|
-
* use through `getSessionUsageSince` — there is no second cost formula here.
|
|
5
|
+
* memory by {@link TokenUsageService}). Every source of agent usage lands
|
|
6
|
+
* there: the in-process Crewly Agent runtime (DeepSeek etc.), the Claude
|
|
7
|
+
* transcript sync, the Codex rollout sync and the Antigravity sync.
|
|
11
8
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* The unit is TOKENS (owner, 2026-10-02): {@link eventTokens} is the one
|
|
10
|
+
* formula — input (fresh + cached) + output. Subscription and API billing
|
|
11
|
+
* are not told apart. The USD figure ({@link eventCostUsd}) stays available
|
|
12
|
+
* to code that needs it but nothing owner-facing shows it.
|
|
14
13
|
*
|
|
15
14
|
* specs/2026-10-02-spend-cap.md
|
|
16
15
|
*
|
|
@@ -21,43 +20,47 @@ import { type TokenUsageEvent } from '../monitoring/token-usage.service.js';
|
|
|
21
20
|
export interface SpendEventSource {
|
|
22
21
|
forEachEvent(visit: (sessionName: string, event: TokenUsageEvent) => void, since?: Date): void;
|
|
23
22
|
getSessionUsageSince(sessionName: string, since: Date, until?: Date): {
|
|
24
|
-
|
|
23
|
+
totalTokens: number;
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
|
-
/** One local day of
|
|
26
|
+
/** One local day of usage. */
|
|
28
27
|
export interface SpendDay {
|
|
29
28
|
/** `YYYY-MM-DD`, local */
|
|
30
29
|
date: string;
|
|
31
|
-
|
|
32
|
-
/** Session →
|
|
30
|
+
totalTokens: number;
|
|
31
|
+
/** Session → tokens */
|
|
33
32
|
byAgent: Record<string, number>;
|
|
34
|
-
/** Runtime →
|
|
33
|
+
/** Runtime → tokens */
|
|
35
34
|
byRuntime: Record<string, number>;
|
|
36
35
|
}
|
|
37
36
|
/** One agent across the window. */
|
|
38
37
|
export interface SpendAgentRow {
|
|
39
38
|
session: string;
|
|
40
|
-
/** Runtimes its usage came from
|
|
39
|
+
/** Runtimes its usage came from */
|
|
41
40
|
runtimes: string[];
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/**
|
|
41
|
+
todayTokens: number;
|
|
42
|
+
windowTokens: number;
|
|
43
|
+
/** Of {@link windowTokens}, the cached input */
|
|
44
|
+
windowCachedTokens: number;
|
|
45
|
+
/** Tokens per day, oldest first, aligned with {@link SpendSummary.days} */
|
|
45
46
|
daily: number[];
|
|
46
47
|
}
|
|
47
|
-
/** What
|
|
48
|
+
/** What the ledger summarises (before cap info is added). */
|
|
48
49
|
export interface SpendSummary {
|
|
49
50
|
/** Local day of `now` */
|
|
50
51
|
today: string;
|
|
51
52
|
/** Oldest first; the last one is today */
|
|
52
53
|
days: SpendDay[];
|
|
53
|
-
/**
|
|
54
|
+
/** Most tokens first */
|
|
54
55
|
agents: SpendAgentRow[];
|
|
55
|
-
/** Runtime →
|
|
56
|
+
/** Runtime → tokens over the window */
|
|
56
57
|
byRuntime: Record<string, number>;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
totalTokens: number;
|
|
59
|
+
/** Of {@link totalTokens}, the cached input */
|
|
60
|
+
cachedTokens: number;
|
|
61
|
+
todayTokens: number;
|
|
62
|
+
/** 90th percentile of per-agent daily tokens (agent-days with any usage) */
|
|
63
|
+
p90AgentDayTokens: number;
|
|
61
64
|
}
|
|
62
65
|
/**
|
|
63
66
|
* The runtime a usage event came from, inferred from its model id.
|
|
@@ -70,6 +73,13 @@ export interface SpendSummary {
|
|
|
70
73
|
* runtimeOfModel('claude-sonnet-5') // 'claude-code'
|
|
71
74
|
*/
|
|
72
75
|
export declare function runtimeOfModel(model: string): string;
|
|
76
|
+
/**
|
|
77
|
+
* The runtime of an event: the one its source recorded, else inferred.
|
|
78
|
+
*
|
|
79
|
+
* @param event - Usage event
|
|
80
|
+
* @returns Runtime id
|
|
81
|
+
*/
|
|
82
|
+
export declare function runtimeOfEvent(event: Pick<TokenUsageEvent, 'model' | 'runtime'>): string;
|
|
73
83
|
/**
|
|
74
84
|
* Nearest-rank percentile.
|
|
75
85
|
*
|
|
@@ -79,14 +89,18 @@ export declare function runtimeOfModel(model: string): string;
|
|
|
79
89
|
*/
|
|
80
90
|
export declare function percentile(values: number[], p: number): number;
|
|
81
91
|
/**
|
|
82
|
-
*
|
|
92
|
+
* Local day keys of the last `days` days (today last), and the start of the first.
|
|
83
93
|
*
|
|
84
|
-
* @param
|
|
85
|
-
* @
|
|
94
|
+
* @param now - Clock reading
|
|
95
|
+
* @param days - Window length (clamped to 1…MAX_DAYS)
|
|
96
|
+
* @returns Keys and the window start
|
|
86
97
|
*/
|
|
87
|
-
export declare function
|
|
98
|
+
export declare function windowDays(now: Date, days: number): {
|
|
99
|
+
keys: string[];
|
|
100
|
+
since: Date;
|
|
101
|
+
};
|
|
88
102
|
/**
|
|
89
|
-
* Per-agent / per-runtime / per-day
|
|
103
|
+
* Per-agent / per-runtime / per-day token usage.
|
|
90
104
|
*/
|
|
91
105
|
export declare class SpendLedger {
|
|
92
106
|
private readonly source;
|
|
@@ -98,23 +112,30 @@ export declare class SpendLedger {
|
|
|
98
112
|
*/
|
|
99
113
|
constructor(source: SpendEventSource, now?: () => Date);
|
|
100
114
|
/**
|
|
101
|
-
*
|
|
115
|
+
* Tokens a session used since local midnight.
|
|
102
116
|
*
|
|
103
117
|
* @param session - Agent session
|
|
104
|
-
* @returns
|
|
118
|
+
* @returns Tokens
|
|
119
|
+
*/
|
|
120
|
+
usedToday(session: string): number;
|
|
121
|
+
/**
|
|
122
|
+
* Tokens a group of sessions (a team) used since local midnight.
|
|
123
|
+
*
|
|
124
|
+
* @param sessions - Agent sessions
|
|
125
|
+
* @returns Tokens
|
|
105
126
|
*/
|
|
106
|
-
|
|
127
|
+
groupToday(sessions: readonly string[]): number;
|
|
107
128
|
/**
|
|
108
|
-
*
|
|
129
|
+
* Tokens every agent together used since local midnight. Cached briefly:
|
|
109
130
|
* the delivery gate asks on every message.
|
|
110
131
|
*
|
|
111
|
-
* @returns
|
|
132
|
+
* @returns Tokens
|
|
112
133
|
*/
|
|
113
134
|
totalToday(): number;
|
|
114
135
|
/** Forget the cached total (after new usage is known). */
|
|
115
136
|
invalidate(): void;
|
|
116
137
|
/**
|
|
117
|
-
*
|
|
138
|
+
* Usage over the last `days` local days, today included.
|
|
118
139
|
*
|
|
119
140
|
* @param days - Window length (clamped to 1…MAX_DAYS)
|
|
120
141
|
* @returns Summary
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spend-ledger.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/spend/spend-ledger.service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"spend-ledger.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/spend/spend-ledger.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Usage ledger — how many tokens each agent used, per local day.
|
|
3
3
|
*
|
|
4
4
|
* Reads the shared token ledger (`~/.crewly/token-usage.json`, held in
|
|
5
|
-
* memory by {@link TokenUsageService}).
|
|
6
|
-
* there: the in-process Crewly Agent runtime
|
|
7
|
-
*
|
|
8
|
-
* turn with its cache split. Each event is priced with {@link eventCostUsd},
|
|
9
|
-
* the same computation the ticket autopilot budget and the team budget gate
|
|
10
|
-
* use through `getSessionUsageSince` — there is no second cost formula here.
|
|
5
|
+
* memory by {@link TokenUsageService}). Every source of agent usage lands
|
|
6
|
+
* there: the in-process Crewly Agent runtime (DeepSeek etc.), the Claude
|
|
7
|
+
* transcript sync, the Codex rollout sync and the Antigravity sync.
|
|
11
8
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* The unit is TOKENS (owner, 2026-10-02): {@link eventTokens} is the one
|
|
10
|
+
* formula — input (fresh + cached) + output. Subscription and API billing
|
|
11
|
+
* are not told apart. The USD figure ({@link eventCostUsd}) stays available
|
|
12
|
+
* to code that needs it but nothing owner-facing shows it.
|
|
14
13
|
*
|
|
15
14
|
* specs/2026-10-02-spend-cap.md
|
|
16
15
|
*
|
|
17
16
|
* @module services/spend/spend-ledger.service
|
|
18
17
|
*/
|
|
19
18
|
import { SPEND_CAP_CONSTANTS, RUNTIME_TYPES } from '../../constants.js';
|
|
20
|
-
import {
|
|
19
|
+
import { eventTokens } from '../monitoring/token-usage.service.js';
|
|
21
20
|
import { localDateKey, localMidnight } from '../project-tickets/ticket-autopilot-decision.js';
|
|
22
21
|
/**
|
|
23
22
|
* The runtime a usage event came from, inferred from its model id.
|
|
@@ -45,6 +44,15 @@ export function runtimeOfModel(model) {
|
|
|
45
44
|
return RUNTIME_TYPES.GEMINI_CLI;
|
|
46
45
|
return 'other';
|
|
47
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* The runtime of an event: the one its source recorded, else inferred.
|
|
49
|
+
*
|
|
50
|
+
* @param event - Usage event
|
|
51
|
+
* @returns Runtime id
|
|
52
|
+
*/
|
|
53
|
+
export function runtimeOfEvent(event) {
|
|
54
|
+
return event.runtime || runtimeOfModel(event.model);
|
|
55
|
+
}
|
|
48
56
|
/**
|
|
49
57
|
* Nearest-rank percentile.
|
|
50
58
|
*
|
|
@@ -60,16 +68,26 @@ export function percentile(values, p) {
|
|
|
60
68
|
return sorted[Math.min(sorted.length, Math.max(1, rank)) - 1];
|
|
61
69
|
}
|
|
62
70
|
/**
|
|
63
|
-
*
|
|
71
|
+
* Local day keys of the last `days` days (today last), and the start of the first.
|
|
64
72
|
*
|
|
65
|
-
* @param
|
|
66
|
-
* @
|
|
73
|
+
* @param now - Clock reading
|
|
74
|
+
* @param days - Window length (clamped to 1…MAX_DAYS)
|
|
75
|
+
* @returns Keys and the window start
|
|
67
76
|
*/
|
|
68
|
-
export function
|
|
69
|
-
|
|
77
|
+
export function windowDays(now, days) {
|
|
78
|
+
const n = Math.min(SPEND_CAP_CONSTANTS.MAX_DAYS, Math.max(1, Math.floor(Number.isFinite(days) ? days : SPEND_CAP_CONSTANTS.DEFAULT_DAYS)));
|
|
79
|
+
const keys = [];
|
|
80
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
81
|
+
const d = new Date(now.getTime());
|
|
82
|
+
d.setDate(d.getDate() - i);
|
|
83
|
+
keys.push(localDateKey(d));
|
|
84
|
+
}
|
|
85
|
+
const first = new Date(now.getTime());
|
|
86
|
+
first.setDate(first.getDate() - (n - 1));
|
|
87
|
+
return { keys, since: localMidnight(first) };
|
|
70
88
|
}
|
|
71
89
|
/**
|
|
72
|
-
* Per-agent / per-runtime / per-day
|
|
90
|
+
* Per-agent / per-runtime / per-day token usage.
|
|
73
91
|
*/
|
|
74
92
|
export class SpendLedger {
|
|
75
93
|
source;
|
|
@@ -84,105 +102,112 @@ export class SpendLedger {
|
|
|
84
102
|
this.now = now;
|
|
85
103
|
}
|
|
86
104
|
/**
|
|
87
|
-
*
|
|
105
|
+
* Tokens a session used since local midnight.
|
|
88
106
|
*
|
|
89
107
|
* @param session - Agent session
|
|
90
|
-
* @returns
|
|
108
|
+
* @returns Tokens
|
|
91
109
|
*/
|
|
92
|
-
|
|
110
|
+
usedToday(session) {
|
|
93
111
|
try {
|
|
94
|
-
return this.source.getSessionUsageSince(session, localMidnight(this.now())).
|
|
112
|
+
return this.source.getSessionUsageSince(session, localMidnight(this.now())).totalTokens;
|
|
95
113
|
}
|
|
96
114
|
catch {
|
|
97
115
|
return 0;
|
|
98
116
|
}
|
|
99
117
|
}
|
|
100
118
|
/**
|
|
101
|
-
*
|
|
119
|
+
* Tokens a group of sessions (a team) used since local midnight.
|
|
120
|
+
*
|
|
121
|
+
* @param sessions - Agent sessions
|
|
122
|
+
* @returns Tokens
|
|
123
|
+
*/
|
|
124
|
+
groupToday(sessions) {
|
|
125
|
+
let n = 0;
|
|
126
|
+
for (const s of new Set(sessions))
|
|
127
|
+
n += this.usedToday(s);
|
|
128
|
+
return n;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Tokens every agent together used since local midnight. Cached briefly:
|
|
102
132
|
* the delivery gate asks on every message.
|
|
103
133
|
*
|
|
104
|
-
* @returns
|
|
134
|
+
* @returns Tokens
|
|
105
135
|
*/
|
|
106
136
|
totalToday() {
|
|
107
137
|
const now = this.now();
|
|
108
138
|
const dayStart = localMidnight(now).getTime();
|
|
109
139
|
const c = this.totalCache;
|
|
110
140
|
if (c && c.dayStart === dayStart && now.getTime() - c.at < SPEND_CAP_CONSTANTS.TOTAL_CACHE_MS)
|
|
111
|
-
return c.
|
|
112
|
-
let
|
|
141
|
+
return c.tokens;
|
|
142
|
+
let tokens = 0;
|
|
113
143
|
try {
|
|
114
144
|
this.source.forEachEvent((_s, e) => {
|
|
115
|
-
|
|
145
|
+
tokens += eventTokens(e).total;
|
|
116
146
|
}, new Date(dayStart));
|
|
117
147
|
}
|
|
118
148
|
catch {
|
|
119
|
-
|
|
149
|
+
tokens = 0;
|
|
120
150
|
}
|
|
121
|
-
this.totalCache = { at: now.getTime(), dayStart,
|
|
122
|
-
return
|
|
151
|
+
this.totalCache = { at: now.getTime(), dayStart, tokens };
|
|
152
|
+
return tokens;
|
|
123
153
|
}
|
|
124
154
|
/** Forget the cached total (after new usage is known). */
|
|
125
155
|
invalidate() {
|
|
126
156
|
this.totalCache = null;
|
|
127
157
|
}
|
|
128
158
|
/**
|
|
129
|
-
*
|
|
159
|
+
* Usage over the last `days` local days, today included.
|
|
130
160
|
*
|
|
131
161
|
* @param days - Window length (clamped to 1…MAX_DAYS)
|
|
132
162
|
* @returns Summary
|
|
133
163
|
*/
|
|
134
164
|
summarize(days = SPEND_CAP_CONSTANTS.DEFAULT_DAYS) {
|
|
135
|
-
const
|
|
136
|
-
const now = this.now();
|
|
137
|
-
const keys = [];
|
|
138
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
139
|
-
const d = new Date(now.getTime());
|
|
140
|
-
d.setDate(d.getDate() - i);
|
|
141
|
-
keys.push(localDateKey(d));
|
|
142
|
-
}
|
|
143
|
-
const first = new Date(now.getTime());
|
|
144
|
-
first.setDate(first.getDate() - (n - 1));
|
|
145
|
-
const since = localMidnight(first);
|
|
165
|
+
const { keys, since } = windowDays(this.now(), days);
|
|
146
166
|
const index = new Map(keys.map((k, i) => [k, i]));
|
|
147
|
-
const dayRows = keys.map((date) => ({ date,
|
|
167
|
+
const dayRows = keys.map((date) => ({ date, totalTokens: 0, byAgent: {}, byRuntime: {} }));
|
|
148
168
|
const agents = new Map();
|
|
149
169
|
const byRuntime = {};
|
|
170
|
+
let cachedTokens = 0;
|
|
150
171
|
this.source.forEachEvent((session, e) => {
|
|
151
172
|
const i = index.get(localDateKey(new Date(e.timestamp)));
|
|
152
173
|
if (i === undefined)
|
|
153
174
|
return;
|
|
154
|
-
const
|
|
155
|
-
const runtime =
|
|
175
|
+
const t = eventTokens(e);
|
|
176
|
+
const runtime = runtimeOfEvent(e);
|
|
156
177
|
const day = dayRows[i];
|
|
157
|
-
day.
|
|
158
|
-
day.byAgent[session] = (day.byAgent[session] ?? 0) +
|
|
159
|
-
day.byRuntime[runtime] = (day.byRuntime[runtime] ?? 0) +
|
|
160
|
-
byRuntime[runtime] = (byRuntime[runtime] ?? 0) +
|
|
178
|
+
day.totalTokens += t.total;
|
|
179
|
+
day.byAgent[session] = (day.byAgent[session] ?? 0) + t.total;
|
|
180
|
+
day.byRuntime[runtime] = (day.byRuntime[runtime] ?? 0) + t.total;
|
|
181
|
+
byRuntime[runtime] = (byRuntime[runtime] ?? 0) + t.total;
|
|
182
|
+
cachedTokens += t.cachedInput;
|
|
161
183
|
let a = agents.get(session);
|
|
162
184
|
if (!a) {
|
|
163
|
-
a = { runtimes: new Set(), daily: keys.map(() => 0) };
|
|
185
|
+
a = { runtimes: new Set(), daily: keys.map(() => 0), cached: 0 };
|
|
164
186
|
agents.set(session, a);
|
|
165
187
|
}
|
|
166
188
|
a.runtimes.add(runtime);
|
|
167
|
-
a.daily[i] +=
|
|
189
|
+
a.daily[i] += t.total;
|
|
190
|
+
a.cached += t.cachedInput;
|
|
168
191
|
}, since);
|
|
169
192
|
const rows = [...agents].map(([session, a]) => ({
|
|
170
193
|
session,
|
|
171
194
|
runtimes: [...a.runtimes].sort(),
|
|
172
|
-
|
|
173
|
-
|
|
195
|
+
todayTokens: a.daily[a.daily.length - 1],
|
|
196
|
+
windowTokens: a.daily.reduce((s, v) => s + v, 0),
|
|
197
|
+
windowCachedTokens: a.cached,
|
|
174
198
|
daily: a.daily,
|
|
175
199
|
}));
|
|
176
|
-
rows.sort((x, y) => y.
|
|
200
|
+
rows.sort((x, y) => y.windowTokens - x.windowTokens);
|
|
177
201
|
const agentDays = rows.flatMap((r) => r.daily.filter((v) => v > 0));
|
|
178
202
|
return {
|
|
179
203
|
today: keys[keys.length - 1],
|
|
180
204
|
days: dayRows,
|
|
181
205
|
agents: rows,
|
|
182
206
|
byRuntime,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
207
|
+
totalTokens: dayRows.reduce((s, d) => s + d.totalTokens, 0),
|
|
208
|
+
cachedTokens,
|
|
209
|
+
todayTokens: dayRows[dayRows.length - 1].totalTokens,
|
|
210
|
+
p90AgentDayTokens: percentile(agentDays, 90),
|
|
186
211
|
};
|
|
187
212
|
}
|
|
188
213
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spend-ledger.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/spend/spend-ledger.service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"spend-ledger.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/spend/spend-ledger.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,8 +17,15 @@ export interface WorkItemUsage {
|
|
|
17
17
|
inputTokens: number;
|
|
18
18
|
/** Output tokens the session generated while the item ran */
|
|
19
19
|
outputTokens: number;
|
|
20
|
-
/** Cost in USD of that usage */
|
|
20
|
+
/** Cost in USD of that usage (internal; owners see tokens) */
|
|
21
21
|
cost: number;
|
|
22
|
+
/**
|
|
23
|
+
* Tokens in the owner-facing unit (input incl. cached + output, see
|
|
24
|
+
* `eventTokens`); 0 when the source does not report it
|
|
25
|
+
*/
|
|
26
|
+
totalTokens: number;
|
|
27
|
+
/** Of {@link totalTokens}, the cached input */
|
|
28
|
+
cachedInputTokens: number;
|
|
22
29
|
}
|
|
23
30
|
/** The slice of TokenUsageService this helper needs (windowed session usage). */
|
|
24
31
|
export interface SessionUsageWindowSource {
|
|
@@ -26,6 +33,8 @@ export interface SessionUsageWindowSource {
|
|
|
26
33
|
inputTokens: number;
|
|
27
34
|
outputTokens: number;
|
|
28
35
|
cost: number;
|
|
36
|
+
totalTokens?: number;
|
|
37
|
+
cachedInputTokens?: number;
|
|
29
38
|
};
|
|
30
39
|
}
|
|
31
40
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-item-usage.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/work-item-usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAElE,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,
|
|
1
|
+
{"version":3,"file":"work-item-usage.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/work-item-usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAElE,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,iFAAiF;AACjF,MAAM,WAAW,wBAAwB;IACvC,oBAAoB,CAClB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,IAAI,EACX,KAAK,CAAC,EAAE,IAAI,GACX;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,WAAW,GAAG,aAAa,CAAC,EAC/D,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,wBAAwB,EAChC,GAAG,GAAE,IAAiB,GACrB,aAAa,GAAG,IAAI,CAYtB"}
|
|
@@ -32,6 +32,8 @@ export function computeWorkItemUsage(item, sessionName, source, now = new Date()
|
|
|
32
32
|
inputTokens: usage.inputTokens,
|
|
33
33
|
outputTokens: usage.outputTokens,
|
|
34
34
|
cost: usage.cost,
|
|
35
|
+
totalTokens: usage.totalTokens ?? 0,
|
|
36
|
+
cachedInputTokens: usage.cachedInputTokens ?? 0,
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
//# sourceMappingURL=work-item-usage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-item-usage.js","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/work-item-usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"work-item-usage.js","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/work-item-usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA8BH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAA+D,EAC/D,WAAmB,EACnB,MAAgC,EAChC,MAAY,IAAI,IAAI,EAAE;IAEtB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAChE,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC;IAC7F,MAAM,KAAK,GAAG,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACnE,OAAO;QACL,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC;QACnC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,IAAI,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token amounts for owners: "12.4M tokens" out, "20M" / "500k" / "2000万" in.
|
|
3
|
+
*
|
|
4
|
+
* specs/2026-10-02-spend-cap.md §Token unit
|
|
5
|
+
*
|
|
6
|
+
* @module services/usage/token-format
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Short token count: `950`, `12.4K`, `12.4M`, `1.2B`.
|
|
10
|
+
*
|
|
11
|
+
* @param tokens - Token count
|
|
12
|
+
* @returns Compact text (no unit)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* compactTokens(12_400_000) // '12.4M'
|
|
16
|
+
*/
|
|
17
|
+
export declare function compactTokens(tokens: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Token count for owner text.
|
|
20
|
+
*
|
|
21
|
+
* @param tokens - Token count
|
|
22
|
+
* @returns e.g. `12.4M tokens`
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatTokens(tokens: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* Parse a token amount the owner typed.
|
|
27
|
+
*
|
|
28
|
+
* Accepts a plain number, `K`/`M`/`B` suffixes (any case, `mil`/`million`
|
|
29
|
+
* too), Chinese `万` (10k) / `亿` (100M), commas, and an optional trailing
|
|
30
|
+
* `tokens` / `token`.
|
|
31
|
+
*
|
|
32
|
+
* @param text - Amount text
|
|
33
|
+
* @returns Whole tokens, or null when it is not a positive amount
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* parseTokenAmount('20M') // 20_000_000
|
|
37
|
+
* parseTokenAmount('2000万') // 20_000_000
|
|
38
|
+
* parseTokenAmount('1.5b tokens') // 1_500_000_000
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseTokenAmount(text: unknown): number | null;
|
|
41
|
+
/**
|
|
42
|
+
* Convert a USD setting to tokens with the documented migration rate
|
|
43
|
+
* ({@link USAGE_CONSTANTS.TOKENS_PER_USD}), rounded to a whole thousand.
|
|
44
|
+
*
|
|
45
|
+
* @param usd - Dollars
|
|
46
|
+
* @returns Tokens
|
|
47
|
+
*/
|
|
48
|
+
export declare function usdToTokens(usd: number): number;
|
|
49
|
+
//# sourceMappingURL=token-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-format.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/usage/token-format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAepD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAS7D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token amounts for owners: "12.4M tokens" out, "20M" / "500k" / "2000万" in.
|
|
3
|
+
*
|
|
4
|
+
* specs/2026-10-02-spend-cap.md §Token unit
|
|
5
|
+
*
|
|
6
|
+
* @module services/usage/token-format
|
|
7
|
+
*/
|
|
8
|
+
import { USAGE_CONSTANTS } from '../../constants.js';
|
|
9
|
+
/**
|
|
10
|
+
* Short token count: `950`, `12.4K`, `12.4M`, `1.2B`.
|
|
11
|
+
*
|
|
12
|
+
* @param tokens - Token count
|
|
13
|
+
* @returns Compact text (no unit)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* compactTokens(12_400_000) // '12.4M'
|
|
17
|
+
*/
|
|
18
|
+
export function compactTokens(tokens) {
|
|
19
|
+
const n = Math.max(0, Math.round(Number.isFinite(tokens) ? tokens : 0));
|
|
20
|
+
const units = [
|
|
21
|
+
[1e9, 'B'],
|
|
22
|
+
[1e6, 'M'],
|
|
23
|
+
[1e3, 'K'],
|
|
24
|
+
];
|
|
25
|
+
for (const [size, suffix] of units) {
|
|
26
|
+
if (n >= size) {
|
|
27
|
+
const v = n / size;
|
|
28
|
+
const text = v >= 100 ? v.toFixed(0) : v.toFixed(1).replace(/\.0$/, '');
|
|
29
|
+
return `${text}${suffix}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return String(n);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Token count for owner text.
|
|
36
|
+
*
|
|
37
|
+
* @param tokens - Token count
|
|
38
|
+
* @returns e.g. `12.4M tokens`
|
|
39
|
+
*/
|
|
40
|
+
export function formatTokens(tokens) {
|
|
41
|
+
return `${compactTokens(tokens)} tokens`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parse a token amount the owner typed.
|
|
45
|
+
*
|
|
46
|
+
* Accepts a plain number, `K`/`M`/`B` suffixes (any case, `mil`/`million`
|
|
47
|
+
* too), Chinese `万` (10k) / `亿` (100M), commas, and an optional trailing
|
|
48
|
+
* `tokens` / `token`.
|
|
49
|
+
*
|
|
50
|
+
* @param text - Amount text
|
|
51
|
+
* @returns Whole tokens, or null when it is not a positive amount
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* parseTokenAmount('20M') // 20_000_000
|
|
55
|
+
* parseTokenAmount('2000万') // 20_000_000
|
|
56
|
+
* parseTokenAmount('1.5b tokens') // 1_500_000_000
|
|
57
|
+
*/
|
|
58
|
+
export function parseTokenAmount(text) {
|
|
59
|
+
if (typeof text === 'number')
|
|
60
|
+
return Number.isFinite(text) && text > 0 ? Math.round(text) : null;
|
|
61
|
+
if (typeof text !== 'string')
|
|
62
|
+
return null;
|
|
63
|
+
const t = text.trim().toLowerCase().replace(/,/g, '').replace(/\s*(?:tokens?|个)?\s*$/u, '');
|
|
64
|
+
const m = /^(\d+(?:\.\d+)?)\s*(k|m|mil|million|b|bn|billion|万|亿)?$/u.exec(t);
|
|
65
|
+
if (!m)
|
|
66
|
+
return null;
|
|
67
|
+
const mult = { k: 1e3, m: 1e6, mil: 1e6, million: 1e6, b: 1e9, bn: 1e9, billion: 1e9, 万: 1e4, 亿: 1e8 };
|
|
68
|
+
const n = Number(m[1]) * (m[2] ? mult[m[2]] : 1);
|
|
69
|
+
return Number.isFinite(n) && n >= 1 ? Math.round(n) : null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Convert a USD setting to tokens with the documented migration rate
|
|
73
|
+
* ({@link USAGE_CONSTANTS.TOKENS_PER_USD}), rounded to a whole thousand.
|
|
74
|
+
*
|
|
75
|
+
* @param usd - Dollars
|
|
76
|
+
* @returns Tokens
|
|
77
|
+
*/
|
|
78
|
+
export function usdToTokens(usd) {
|
|
79
|
+
return Math.max(1000, Math.round((usd * USAGE_CONSTANTS.TOKENS_PER_USD) / 1000) * 1000);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=token-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-format.js","sourceRoot":"","sources":["../../../../../../backend/src/services/usage/token-format.ts"],"names":[],"mappings":"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"}
|