@alook/daemon 0.1.26 → 0.1.28
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/cli/index.js +305 -91
- package/dist/index.js +305 -91
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -16646,6 +16646,7 @@ var communityMachine = sqliteTable("community_machine", {
|
|
|
16646
16646
|
arch: text("arch").notNull().default(""),
|
|
16647
16647
|
osRelease: text("os_release").notNull().default(""),
|
|
16648
16648
|
daemonVersion: text("daemon_version").notNull().default(""),
|
|
16649
|
+
timeZone: text("time_zone"),
|
|
16649
16650
|
metadata: text("metadata"),
|
|
16650
16651
|
availableRuntimes: text("available_runtimes", { mode: "json" }).$type().notNull().default([]),
|
|
16651
16652
|
status: text("status").notNull().default("offline"),
|
|
@@ -17639,6 +17640,7 @@ var HostReadyMessageSchema = exports_external.object({
|
|
|
17639
17640
|
arch: exports_external.string().optional(),
|
|
17640
17641
|
osRelease: exports_external.string().optional(),
|
|
17641
17642
|
daemonVersion: exports_external.string().optional(),
|
|
17643
|
+
timeZone: exports_external.string().min(1).max(128).optional(),
|
|
17642
17644
|
providerQuotas: exports_external.array(ProviderQuotaSnapshotSchema).max(2).optional().default([])
|
|
17643
17645
|
});
|
|
17644
17646
|
var CommunityDaemonReadySchema = exports_external.object({
|
|
@@ -17661,6 +17663,8 @@ var AgentActivityMessageSchema = exports_external.object({
|
|
|
17661
17663
|
type: exports_external.literal("agent_activity"),
|
|
17662
17664
|
agentId: exports_external.string(),
|
|
17663
17665
|
state: exports_external.enum(["idle", "starting", "running", "stopping"]),
|
|
17666
|
+
usageTimeZone: exports_external.string().min(1).max(128).optional(),
|
|
17667
|
+
usageDay: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
17664
17668
|
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(7).optional(),
|
|
17665
17669
|
quota: ProviderQuotaSnapshotSchema.optional()
|
|
17666
17670
|
});
|
|
@@ -17926,6 +17930,42 @@ var BotAuditEventAckFrameSchema = exports_external.strictObject({
|
|
|
17926
17930
|
type: exports_external.literal("bot_audit_event_ack"),
|
|
17927
17931
|
eventId: exports_external.string().min(1).max(128)
|
|
17928
17932
|
});
|
|
17933
|
+
// ../shared/src/utils/day-key.ts
|
|
17934
|
+
function utcDayKey(now) {
|
|
17935
|
+
const d = now instanceof Date ? now : new Date(now);
|
|
17936
|
+
return d.toISOString().slice(0, 10);
|
|
17937
|
+
}
|
|
17938
|
+
function calendarDayKeyDaysAgo(day, days) {
|
|
17939
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(day);
|
|
17940
|
+
if (!match)
|
|
17941
|
+
throw new RangeError("invalid calendar day key");
|
|
17942
|
+
const year = Number(match[1]);
|
|
17943
|
+
const month = Number(match[2]);
|
|
17944
|
+
const date5 = Number(match[3]);
|
|
17945
|
+
const parsed = new Date(Date.UTC(year, month - 1, date5));
|
|
17946
|
+
if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== date5) {
|
|
17947
|
+
throw new RangeError("invalid calendar day key");
|
|
17948
|
+
}
|
|
17949
|
+
parsed.setUTCDate(parsed.getUTCDate() - days);
|
|
17950
|
+
return utcDayKey(parsed);
|
|
17951
|
+
}
|
|
17952
|
+
function dayKeyInTimeZone(now, timeZone) {
|
|
17953
|
+
const date5 = now instanceof Date ? now : new Date(now);
|
|
17954
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
17955
|
+
timeZone,
|
|
17956
|
+
year: "numeric",
|
|
17957
|
+
month: "2-digit",
|
|
17958
|
+
day: "2-digit"
|
|
17959
|
+
}).formatToParts(date5);
|
|
17960
|
+
const values = new Map(parts.map((part) => [part.type, part.value]));
|
|
17961
|
+
const year = values.get("year");
|
|
17962
|
+
const month = values.get("month");
|
|
17963
|
+
const day = values.get("day");
|
|
17964
|
+
if (!year || !month || !day)
|
|
17965
|
+
throw new RangeError("unable to format calendar day key");
|
|
17966
|
+
return `${year}-${month}-${day}`;
|
|
17967
|
+
}
|
|
17968
|
+
|
|
17929
17969
|
// ../shared/src/db/community-schema.ts
|
|
17930
17970
|
var exports_community_schema = {};
|
|
17931
17971
|
__export(exports_community_schema, {
|
|
@@ -20522,6 +20562,66 @@ function buildClaudeArgs(config2) {
|
|
|
20522
20562
|
return args;
|
|
20523
20563
|
}
|
|
20524
20564
|
|
|
20565
|
+
// agent-driver/dist/internal/token-usage.js
|
|
20566
|
+
function validIdentityPart(value) {
|
|
20567
|
+
return value.trim().length > 0 && Buffer.byteLength(value, "utf8") <= 512;
|
|
20568
|
+
}
|
|
20569
|
+
function identityKey(identity) {
|
|
20570
|
+
if (!validIdentityPart(identity.runtime) || !validIdentityPart(identity.backendSessionId) || !validIdentityPart(identity.providerRecordId))
|
|
20571
|
+
return null;
|
|
20572
|
+
return JSON.stringify([identity.runtime, identity.backendSessionId, identity.providerRecordId]);
|
|
20573
|
+
}
|
|
20574
|
+
function metric(value) {
|
|
20575
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
20576
|
+
}
|
|
20577
|
+
function cacheMetric(read, write) {
|
|
20578
|
+
const present = [read, write].filter((value) => value !== undefined);
|
|
20579
|
+
if (present.length === 0)
|
|
20580
|
+
return null;
|
|
20581
|
+
const metrics = present.map(metric);
|
|
20582
|
+
if (metrics.some((value) => value === null))
|
|
20583
|
+
return null;
|
|
20584
|
+
const total = metrics.reduce((sum, value) => sum + value, 0);
|
|
20585
|
+
return Number.isSafeInteger(total) ? total : null;
|
|
20586
|
+
}
|
|
20587
|
+
|
|
20588
|
+
class SettledUsageProjector {
|
|
20589
|
+
active = new Set;
|
|
20590
|
+
project(record2) {
|
|
20591
|
+
const key = identityKey(record2);
|
|
20592
|
+
if (!key || this.active.has(key))
|
|
20593
|
+
return null;
|
|
20594
|
+
this.active.add(key);
|
|
20595
|
+
const cache = cacheMetric(record2.cacheRead, record2.cacheWrite);
|
|
20596
|
+
const rawInput = metric(record2.input);
|
|
20597
|
+
const input = record2.inputIncludesCache ? rawInput !== null && cache !== null && cache <= rawInput ? rawInput - cache : null : rawInput;
|
|
20598
|
+
const rawOutput = metric(record2.output);
|
|
20599
|
+
const reasoning = metric(record2.reasoning);
|
|
20600
|
+
const output = record2.outputIncludesReasoning ? rawOutput : rawOutput !== null && reasoning !== null && Number.isSafeInteger(rawOutput + reasoning) ? rawOutput + reasoning : null;
|
|
20601
|
+
if (input === null && output === null && cache === null) {
|
|
20602
|
+
this.active.delete(key);
|
|
20603
|
+
return null;
|
|
20604
|
+
}
|
|
20605
|
+
return {
|
|
20606
|
+
kind: "telemetry",
|
|
20607
|
+
name: "token_usage",
|
|
20608
|
+
source: record2.source,
|
|
20609
|
+
usage: { input, output, cache }
|
|
20610
|
+
};
|
|
20611
|
+
}
|
|
20612
|
+
release(identity) {
|
|
20613
|
+
const key = identityKey(identity);
|
|
20614
|
+
if (key)
|
|
20615
|
+
this.active.delete(key);
|
|
20616
|
+
}
|
|
20617
|
+
reset() {
|
|
20618
|
+
this.active.clear();
|
|
20619
|
+
}
|
|
20620
|
+
get activeCount() {
|
|
20621
|
+
return this.active.size;
|
|
20622
|
+
}
|
|
20623
|
+
}
|
|
20624
|
+
|
|
20525
20625
|
// agent-driver/dist/internal/utils.js
|
|
20526
20626
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
20527
20627
|
function jsonRpcRequest(method, params, id) {
|
|
@@ -20541,9 +20641,13 @@ var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
|
20541
20641
|
class ClaudeEventNormalizer {
|
|
20542
20642
|
turnProtocol;
|
|
20543
20643
|
currentSession = null;
|
|
20644
|
+
usageProjector = new SettledUsageProjector;
|
|
20544
20645
|
constructor(turnProtocol) {
|
|
20545
20646
|
this.turnProtocol = turnProtocol;
|
|
20546
20647
|
}
|
|
20648
|
+
beginTurn() {
|
|
20649
|
+
this.usageProjector.reset();
|
|
20650
|
+
}
|
|
20547
20651
|
get currentSessionId() {
|
|
20548
20652
|
return this.currentSession;
|
|
20549
20653
|
}
|
|
@@ -20635,7 +20739,7 @@ class ClaudeEventNormalizer {
|
|
|
20635
20739
|
const turnOwner = rawOwner ? this.turnProtocol?.claimResult(rawOwner) ?? (this.turnProtocol ? null : `claude:${rawOwner}`) : null;
|
|
20636
20740
|
if (this.turnProtocol && !turnOwner)
|
|
20637
20741
|
return;
|
|
20638
|
-
const usage = this.buildUsageTelemetry(event);
|
|
20742
|
+
const usage = this.buildUsageTelemetry(event, rawOwner);
|
|
20639
20743
|
if (usage)
|
|
20640
20744
|
out.push(usage);
|
|
20641
20745
|
if (event.is_error || event.subtype === "error_during_execution") {
|
|
@@ -20650,23 +20754,26 @@ class ClaudeEventNormalizer {
|
|
|
20650
20754
|
acceptsTurnWork() {
|
|
20651
20755
|
return this.turnProtocol?.acceptsTurnWork() ?? true;
|
|
20652
20756
|
}
|
|
20653
|
-
buildUsageTelemetry(event) {
|
|
20757
|
+
buildUsageTelemetry(event, rootRequestId) {
|
|
20654
20758
|
const u = event?.usage;
|
|
20655
20759
|
if (!u)
|
|
20656
20760
|
return null;
|
|
20657
|
-
const
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
|
|
20761
|
+
const backendSessionId = event.session_id ?? this.currentSession;
|
|
20762
|
+
if (typeof backendSessionId !== "string" || !backendSessionId)
|
|
20763
|
+
return null;
|
|
20764
|
+
const providerRecordId = rootRequestId ?? (typeof event.request_id === "string" ? event.request_id : "invocation-result");
|
|
20765
|
+
return this.usageProjector.project({
|
|
20766
|
+
runtime: "claude",
|
|
20767
|
+
backendSessionId,
|
|
20768
|
+
providerRecordId,
|
|
20663
20769
|
source: "claude_result_usage",
|
|
20664
|
-
|
|
20665
|
-
|
|
20666
|
-
|
|
20667
|
-
|
|
20668
|
-
|
|
20669
|
-
|
|
20770
|
+
input: u.input_tokens,
|
|
20771
|
+
output: u.output_tokens,
|
|
20772
|
+
cacheRead: u.cache_read_input_tokens,
|
|
20773
|
+
cacheWrite: u.cache_creation_input_tokens,
|
|
20774
|
+
inputIncludesCache: false,
|
|
20775
|
+
outputIncludesReasoning: true
|
|
20776
|
+
});
|
|
20670
20777
|
}
|
|
20671
20778
|
}
|
|
20672
20779
|
|
|
@@ -20869,7 +20976,9 @@ class ClaudeDriver {
|
|
|
20869
20976
|
turnProtocol = new ClaudeTurnProtocol;
|
|
20870
20977
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
20871
20978
|
beginTurn() {
|
|
20872
|
-
|
|
20979
|
+
const receipt = this.turnProtocol.beginTurn();
|
|
20980
|
+
this.eventNormalizer.beginTurn();
|
|
20981
|
+
return receipt;
|
|
20873
20982
|
}
|
|
20874
20983
|
probe(command) {
|
|
20875
20984
|
const explicit = command?.trim();
|
|
@@ -20923,14 +21032,6 @@ class ClaudeDriver {
|
|
|
20923
21032
|
}
|
|
20924
21033
|
|
|
20925
21034
|
// agent-driver/dist/adapters/codex/telemetry.js
|
|
20926
|
-
function metric(value) {
|
|
20927
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
20928
|
-
}
|
|
20929
|
-
function nonCachedInput(input, cached2) {
|
|
20930
|
-
if (typeof input !== "number" || !Number.isSafeInteger(input) || input < 0 || typeof cached2 !== "number" || !Number.isSafeInteger(cached2) || cached2 < 0 || cached2 > input)
|
|
20931
|
-
return null;
|
|
20932
|
-
return input - cached2;
|
|
20933
|
-
}
|
|
20934
21035
|
function canonicalId(value, fallback) {
|
|
20935
21036
|
return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).length <= 64 ? value : fallback;
|
|
20936
21037
|
}
|
|
@@ -21024,28 +21125,24 @@ function mapCodexQuotaSnapshots(snapshots, sourceEpoch) {
|
|
|
21024
21125
|
}
|
|
21025
21126
|
};
|
|
21026
21127
|
}
|
|
21027
|
-
function
|
|
21028
|
-
|
|
21029
|
-
|
|
21030
|
-
|
|
21031
|
-
|
|
21032
|
-
|
|
21033
|
-
|
|
21034
|
-
|
|
21035
|
-
|
|
21036
|
-
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
|
|
21042
|
-
|
|
21043
|
-
|
|
21044
|
-
}
|
|
21045
|
-
if (method === "account/rateLimits/updated") {
|
|
21046
|
-
return [mapCodexQuotaSnapshots([params?.rateLimits ?? params ?? {}], sourceEpoch)];
|
|
21047
|
-
}
|
|
21048
|
-
return [];
|
|
21128
|
+
function mapCodexSettledUsage(params, projector) {
|
|
21129
|
+
const backendSessionId = params?.threadId ?? params?.thread_id;
|
|
21130
|
+
const providerRecordId = params?.responseId ?? params?.response_id;
|
|
21131
|
+
const usage = params?.usage;
|
|
21132
|
+
if (typeof backendSessionId !== "string" || typeof providerRecordId !== "string" || !usage)
|
|
21133
|
+
return null;
|
|
21134
|
+
return projector.project({
|
|
21135
|
+
runtime: "codex",
|
|
21136
|
+
backendSessionId,
|
|
21137
|
+
providerRecordId,
|
|
21138
|
+
source: "codex_raw_response_completed",
|
|
21139
|
+
input: usage.inputTokens ?? usage.input_tokens,
|
|
21140
|
+
output: usage.outputTokens ?? usage.output_tokens,
|
|
21141
|
+
cacheRead: usage.cachedInputTokens ?? usage.cached_input_tokens,
|
|
21142
|
+
cacheWrite: usage.cacheWriteInputTokens ?? usage.cache_write_input_tokens,
|
|
21143
|
+
inputIncludesCache: true,
|
|
21144
|
+
outputIncludesReasoning: true
|
|
21145
|
+
});
|
|
21049
21146
|
}
|
|
21050
21147
|
|
|
21051
21148
|
// agent-driver/dist/adapters/codex/normalizer.js
|
|
@@ -21097,7 +21194,8 @@ class CodexEventNormalizer {
|
|
|
21097
21194
|
rateLimitSnapshots = new Map;
|
|
21098
21195
|
quotaSnapshotInitialized = false;
|
|
21099
21196
|
quotaSourceGeneration = codexQuotaSourceGeneration;
|
|
21100
|
-
|
|
21197
|
+
usageProjector = new SettledUsageProjector;
|
|
21198
|
+
usageRecordsBySessionAndTurn = new Map;
|
|
21101
21199
|
threadId = null;
|
|
21102
21200
|
turnId = null;
|
|
21103
21201
|
terminalTurn = null;
|
|
@@ -21170,7 +21268,8 @@ class CodexEventNormalizer {
|
|
|
21170
21268
|
if (threadId !== this.threadId) {
|
|
21171
21269
|
this.turnId = null;
|
|
21172
21270
|
this.terminalTurn = null;
|
|
21173
|
-
this.
|
|
21271
|
+
this.usageProjector.reset();
|
|
21272
|
+
this.usageRecordsBySessionAndTurn.clear();
|
|
21174
21273
|
}
|
|
21175
21274
|
this.threadId = threadId;
|
|
21176
21275
|
}
|
|
@@ -21219,6 +21318,22 @@ class CodexEventNormalizer {
|
|
|
21219
21318
|
}
|
|
21220
21319
|
handleNotification(method, params) {
|
|
21221
21320
|
const notificationThreadId = typeof params?.threadId === "string" ? params.threadId : null;
|
|
21321
|
+
if (method === "rawResponse/completed")
|
|
21322
|
+
return this.handleSettledUsage(params);
|
|
21323
|
+
if (method === "turn/completed" && notificationThreadId !== null && notificationThreadId !== this.threadId) {
|
|
21324
|
+
const turnId = this.notificationTurnId(params);
|
|
21325
|
+
if (turnId)
|
|
21326
|
+
this.releaseUsageForTurn(notificationThreadId, turnId);
|
|
21327
|
+
return [];
|
|
21328
|
+
}
|
|
21329
|
+
if (method === "item/completed" && notificationThreadId !== null && notificationThreadId !== this.threadId) {
|
|
21330
|
+
const turnId = this.notificationTurnId(params);
|
|
21331
|
+
const itemType = params?.item?.type ?? params?.type;
|
|
21332
|
+
if (turnId && itemType === "contextCompaction") {
|
|
21333
|
+
this.releaseUsageForTurn(notificationThreadId, turnId);
|
|
21334
|
+
}
|
|
21335
|
+
return [];
|
|
21336
|
+
}
|
|
21222
21337
|
if (this.threadId !== null && notificationThreadId !== null && notificationThreadId !== this.threadId)
|
|
21223
21338
|
return [];
|
|
21224
21339
|
if (this.isRootWorkNotification(method) && !this.acceptRootWork(params))
|
|
@@ -21231,7 +21346,6 @@ class CodexEventNormalizer {
|
|
|
21231
21346
|
return [];
|
|
21232
21347
|
this.turnId = params.turn.id;
|
|
21233
21348
|
this.terminalTurn = null;
|
|
21234
|
-
this.pendingTurnUsage = null;
|
|
21235
21349
|
return [
|
|
21236
21350
|
{
|
|
21237
21351
|
kind: "turn_owner",
|
|
@@ -21247,7 +21361,7 @@ class CodexEventNormalizer {
|
|
|
21247
21361
|
case "item/started":
|
|
21248
21362
|
return this.handleItemStarted(params);
|
|
21249
21363
|
case "item/completed":
|
|
21250
|
-
return this.
|
|
21364
|
+
return this.handleItemCompletedAndReleaseUsage(params);
|
|
21251
21365
|
case "rawResponseItem/completed":
|
|
21252
21366
|
return [{ kind: "internal_progress", source: "codex_raw_item", itemType: "rawResponseItem" }];
|
|
21253
21367
|
case "configWarning":
|
|
@@ -21260,30 +21374,24 @@ class CodexEventNormalizer {
|
|
|
21260
21374
|
case "turn/completed":
|
|
21261
21375
|
if (!this.acceptRootTerminal(params))
|
|
21262
21376
|
return [];
|
|
21263
|
-
|
|
21264
|
-
this.pendingTurnUsage = null;
|
|
21377
|
+
this.releaseUsageForTurn(params.threadId, params.turn.id);
|
|
21265
21378
|
if (params.turn.status === "failed") {
|
|
21266
21379
|
return [
|
|
21267
|
-
...usage ? [usage] : [],
|
|
21268
21380
|
{ kind: "error", message: "Codex turn failed" },
|
|
21269
21381
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
21270
21382
|
];
|
|
21271
21383
|
}
|
|
21272
21384
|
if (params.turn.status === "interrupted") {
|
|
21273
|
-
return [
|
|
21385
|
+
return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21274
21386
|
}
|
|
21275
|
-
return [
|
|
21387
|
+
return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21276
21388
|
case "error":
|
|
21277
21389
|
if (params?.willRetry === true) {
|
|
21278
21390
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
21279
21391
|
}
|
|
21280
21392
|
return [{ kind: "error", message: params?.error?.message ?? params?.message ?? "Codex error" }];
|
|
21281
|
-
case "thread/tokenUsage/updated":
|
|
21282
|
-
const usage2 = mapCodexTelemetry(method, params, codexQuotaSourceEpoch)[0];
|
|
21283
|
-
if (usage2)
|
|
21284
|
-
this.pendingTurnUsage = usage2;
|
|
21393
|
+
case "thread/tokenUsage/updated":
|
|
21285
21394
|
return [];
|
|
21286
|
-
}
|
|
21287
21395
|
case "account/rateLimits/updated":
|
|
21288
21396
|
return this.mergeQuotaSnapshots(params);
|
|
21289
21397
|
case "account/updated":
|
|
@@ -21294,6 +21402,42 @@ class CodexEventNormalizer {
|
|
|
21294
21402
|
return [];
|
|
21295
21403
|
}
|
|
21296
21404
|
}
|
|
21405
|
+
handleSettledUsage(params) {
|
|
21406
|
+
const notificationTurnId = this.notificationTurnId(params);
|
|
21407
|
+
if (this.turnId === null && this.terminalTurn?.state === "closed" && notificationTurnId === this.terminalTurn.turnId && params?.threadId === this.terminalTurn.threadId)
|
|
21408
|
+
return [];
|
|
21409
|
+
const backendSessionId = params?.threadId ?? params?.thread_id;
|
|
21410
|
+
const providerRecordId = params?.responseId ?? params?.response_id;
|
|
21411
|
+
if (!notificationTurnId || typeof backendSessionId !== "string" || typeof providerRecordId !== "string")
|
|
21412
|
+
return [];
|
|
21413
|
+
const usage = mapCodexSettledUsage(params, this.usageProjector);
|
|
21414
|
+
if (!usage)
|
|
21415
|
+
return [];
|
|
21416
|
+
const recordsByTurn = this.usageRecordsBySessionAndTurn.get(backendSessionId) ?? new Map;
|
|
21417
|
+
const recordIds = recordsByTurn.get(notificationTurnId) ?? new Set;
|
|
21418
|
+
recordIds.add(providerRecordId);
|
|
21419
|
+
recordsByTurn.set(notificationTurnId, recordIds);
|
|
21420
|
+
this.usageRecordsBySessionAndTurn.set(backendSessionId, recordsByTurn);
|
|
21421
|
+
return [usage];
|
|
21422
|
+
}
|
|
21423
|
+
releaseUsageForTurn(backendSessionId, turnId) {
|
|
21424
|
+
const recordsByTurn = this.usageRecordsBySessionAndTurn.get(backendSessionId);
|
|
21425
|
+
for (const providerRecordId of recordsByTurn?.get(turnId) ?? []) {
|
|
21426
|
+
this.usageProjector.release({ runtime: "codex", backendSessionId, providerRecordId });
|
|
21427
|
+
}
|
|
21428
|
+
recordsByTurn?.delete(turnId);
|
|
21429
|
+
if (recordsByTurn?.size === 0)
|
|
21430
|
+
this.usageRecordsBySessionAndTurn.delete(backendSessionId);
|
|
21431
|
+
}
|
|
21432
|
+
handleItemCompletedAndReleaseUsage(params) {
|
|
21433
|
+
const events = this.handleItemCompleted(params);
|
|
21434
|
+
const turnId = this.notificationTurnId(params);
|
|
21435
|
+
const itemType = params?.item?.type ?? params?.type;
|
|
21436
|
+
if (turnId && itemType === "contextCompaction" && turnId !== this.turnId && typeof params?.threadId === "string") {
|
|
21437
|
+
this.releaseUsageForTurn(params.threadId, turnId);
|
|
21438
|
+
}
|
|
21439
|
+
return events;
|
|
21440
|
+
}
|
|
21297
21441
|
isRootWorkNotification(method) {
|
|
21298
21442
|
return method === "item/reasoning/textDelta" || method === "item/reasoning/summaryTextDelta" || method === "item/agentMessage/delta" || method === "item/started" || method === "item/completed" || method === "rawResponseItem/completed";
|
|
21299
21443
|
}
|
|
@@ -22838,6 +22982,7 @@ class OpenCodeServiceLane {
|
|
|
22838
22982
|
lastDurableSeq = 0;
|
|
22839
22983
|
durableSeqById = new Map;
|
|
22840
22984
|
durableIdBySeq = new Map;
|
|
22985
|
+
usageProjector = new SettledUsageProjector;
|
|
22841
22986
|
toolNames = new Map;
|
|
22842
22987
|
handledPermissions = new Set;
|
|
22843
22988
|
permissionFlights = new Map;
|
|
@@ -23378,7 +23523,8 @@ class OpenCodeServiceLane {
|
|
|
23378
23523
|
const event = record4(value);
|
|
23379
23524
|
const durable = record4(event?.durable);
|
|
23380
23525
|
const data = record4(event?.data);
|
|
23381
|
-
|
|
23526
|
+
const backendSessionId = this.sessionId;
|
|
23527
|
+
if (!event || !backendSessionId || typeof event.id !== "string" || typeof event.type !== "string" || !durable || durable.aggregateID !== this.sessionId || !Number.isInteger(durable.seq) || Number(durable.seq) < 0 || data?.sessionID !== this.sessionId) {
|
|
23382
23528
|
throw new OpenCodeProtocolError("OpenCode session stream emitted an invalid durable event");
|
|
23383
23529
|
}
|
|
23384
23530
|
const seq = Number(durable.seq);
|
|
@@ -23468,21 +23614,27 @@ class OpenCodeServiceLane {
|
|
|
23468
23614
|
});
|
|
23469
23615
|
}
|
|
23470
23616
|
const tokens = record4(data.tokens);
|
|
23471
|
-
if (tokens
|
|
23617
|
+
if (tokens) {
|
|
23472
23618
|
const cache = record4(tokens.cache);
|
|
23473
|
-
const
|
|
23474
|
-
|
|
23475
|
-
|
|
23476
|
-
|
|
23477
|
-
|
|
23478
|
-
|
|
23619
|
+
const identity = {
|
|
23620
|
+
runtime: "opencode",
|
|
23621
|
+
backendSessionId,
|
|
23622
|
+
providerRecordId: event.id
|
|
23623
|
+
};
|
|
23624
|
+
const usage = this.usageProjector.project({
|
|
23625
|
+
...identity,
|
|
23479
23626
|
source: "opencode.v2",
|
|
23480
|
-
|
|
23481
|
-
|
|
23482
|
-
|
|
23483
|
-
|
|
23484
|
-
|
|
23627
|
+
input: tokens.input,
|
|
23628
|
+
output: tokens.output,
|
|
23629
|
+
reasoning: tokens.reasoning,
|
|
23630
|
+
cacheRead: cache?.read,
|
|
23631
|
+
cacheWrite: cache?.write,
|
|
23632
|
+
inputIncludesCache: false,
|
|
23633
|
+
outputIncludesReasoning: false
|
|
23485
23634
|
});
|
|
23635
|
+
if (usage)
|
|
23636
|
+
this.events.emit("runtime_event", usage);
|
|
23637
|
+
this.usageProjector.release(identity);
|
|
23486
23638
|
}
|
|
23487
23639
|
break;
|
|
23488
23640
|
}
|
|
@@ -24201,6 +24353,11 @@ function readPiSdkVersion() {
|
|
|
24201
24353
|
} catch {}
|
|
24202
24354
|
return resolvePiSdkVersionFromPath();
|
|
24203
24355
|
}
|
|
24356
|
+
function piUsageState(state) {
|
|
24357
|
+
state.usageProjector ??= new SettledUsageProjector;
|
|
24358
|
+
state.pendingUsageRecordIds ??= new Set;
|
|
24359
|
+
return { projector: state.usageProjector, pending: state.pendingUsageRecordIds };
|
|
24360
|
+
}
|
|
24204
24361
|
function mapPiSdkEvent(event, sessionId, state) {
|
|
24205
24362
|
if (event?.type === "message_update") {
|
|
24206
24363
|
const d = event.assistantMessageEvent ?? {};
|
|
@@ -24221,6 +24378,35 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
24221
24378
|
}
|
|
24222
24379
|
}
|
|
24223
24380
|
switch (event?.type) {
|
|
24381
|
+
case "message_end": {
|
|
24382
|
+
const message2 = event.message;
|
|
24383
|
+
if (message2?.role !== "assistant" || !message2.usage)
|
|
24384
|
+
return [];
|
|
24385
|
+
state.usageRecordSequence = (state.usageRecordSequence ?? 0) + 1;
|
|
24386
|
+
const providerRecordId = typeof message2.responseId === "string" && message2.responseId ? message2.responseId : `live:${message2.timestamp ?? "unknown"}:${state.usageRecordSequence}`;
|
|
24387
|
+
const { projector, pending } = piUsageState(state);
|
|
24388
|
+
const identity = { runtime: "pi", backendSessionId: sessionId, providerRecordId };
|
|
24389
|
+
const usage = projector.project({
|
|
24390
|
+
...identity,
|
|
24391
|
+
source: "pi_message_end",
|
|
24392
|
+
input: message2.usage.input,
|
|
24393
|
+
output: message2.usage.output,
|
|
24394
|
+
cacheRead: message2.usage.cacheRead,
|
|
24395
|
+
cacheWrite: message2.usage.cacheWrite,
|
|
24396
|
+
inputIncludesCache: false,
|
|
24397
|
+
outputIncludesReasoning: true
|
|
24398
|
+
});
|
|
24399
|
+
pending.add(providerRecordId);
|
|
24400
|
+
return usage ? [usage] : [];
|
|
24401
|
+
}
|
|
24402
|
+
case "turn_end": {
|
|
24403
|
+
const { projector, pending } = piUsageState(state);
|
|
24404
|
+
for (const providerRecordId of pending) {
|
|
24405
|
+
projector.release({ runtime: "pi", backendSessionId: sessionId, providerRecordId });
|
|
24406
|
+
}
|
|
24407
|
+
pending.clear();
|
|
24408
|
+
return [];
|
|
24409
|
+
}
|
|
24224
24410
|
case "auto_retry_start":
|
|
24225
24411
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "pi_auto_retry" }];
|
|
24226
24412
|
case "auto_retry_end":
|
|
@@ -30499,6 +30685,7 @@ class AgentRouter {
|
|
|
30499
30685
|
await this.opts.channel.reportReady(this.buildReady());
|
|
30500
30686
|
}
|
|
30501
30687
|
buildReady() {
|
|
30688
|
+
const timeZone = typeof this.opts.timeZone === "function" ? this.opts.timeZone() : this.opts.timeZone;
|
|
30502
30689
|
return {
|
|
30503
30690
|
runtimeReport: [...this.runtimes.values()],
|
|
30504
30691
|
capabilities: [CONTROL_HEARTBEAT_CAPABILITY],
|
|
@@ -30508,6 +30695,7 @@ class AgentRouter {
|
|
|
30508
30695
|
arch: this.opts.arch,
|
|
30509
30696
|
osRelease: this.opts.osRelease,
|
|
30510
30697
|
daemonVersion: this.opts.daemonVersion,
|
|
30698
|
+
timeZone,
|
|
30511
30699
|
...this.opts.providerQuotas ? { providerQuotas: this.opts.providerQuotas() } : {}
|
|
30512
30700
|
};
|
|
30513
30701
|
}
|
|
@@ -32428,15 +32616,12 @@ class DaemonSelfSleepScheduler {
|
|
|
32428
32616
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32429
32617
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
32430
32618
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32431
|
-
function
|
|
32432
|
-
|
|
32619
|
+
function oldestRetainedDay(at, timeZone) {
|
|
32620
|
+
const today = dayKeyInTimeZone(at, timeZone);
|
|
32621
|
+
return calendarDayKeyDaysAgo(today, 8);
|
|
32433
32622
|
}
|
|
32434
|
-
function
|
|
32435
|
-
|
|
32436
|
-
for (let offset = 0;offset < 7; offset += 1) {
|
|
32437
|
-
days.add(dayKey(new Date(at.getTime() - offset * 86400000)));
|
|
32438
|
-
}
|
|
32439
|
-
return days;
|
|
32623
|
+
function oldestVisibleDay(today) {
|
|
32624
|
+
return calendarDayKeyDaysAgo(today, 6);
|
|
32440
32625
|
}
|
|
32441
32626
|
function isMetric(value) {
|
|
32442
32627
|
return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -32481,16 +32666,25 @@ class DailyTokenUsageStore {
|
|
|
32481
32666
|
loaded = false;
|
|
32482
32667
|
data = { version: 1, bots: {} };
|
|
32483
32668
|
filePath;
|
|
32484
|
-
|
|
32669
|
+
resolveTimeZone;
|
|
32670
|
+
constructor(workingDirectoryBase, now = () => new Date, timeZone = () => Intl.DateTimeFormat().resolvedOptions().timeZone) {
|
|
32485
32671
|
this.now = now;
|
|
32672
|
+
this.resolveTimeZone = typeof timeZone === "string" ? () => timeZone : timeZone;
|
|
32673
|
+
this.timeZone;
|
|
32486
32674
|
this.filePath = join14(workingDirectoryBase, ".telemetry", "daily-token-usage.json");
|
|
32487
32675
|
}
|
|
32676
|
+
get timeZone() {
|
|
32677
|
+
const timeZone = this.resolveTimeZone();
|
|
32678
|
+
dayKeyInTimeZone(0, timeZone);
|
|
32679
|
+
return timeZone;
|
|
32680
|
+
}
|
|
32488
32681
|
record(botId, delta) {
|
|
32489
32682
|
return this.enqueue(async () => {
|
|
32490
32683
|
await this.load();
|
|
32491
32684
|
const at = this.now();
|
|
32492
|
-
this.
|
|
32493
|
-
|
|
32685
|
+
const timeZone = this.timeZone;
|
|
32686
|
+
this.prune(at, timeZone);
|
|
32687
|
+
const day = dayKeyInTimeZone(at, timeZone);
|
|
32494
32688
|
const snapshots = this.data.bots[botId] ?? [];
|
|
32495
32689
|
const existing = snapshots.find((snapshot) => snapshot.day === day);
|
|
32496
32690
|
const next = existing ?? emptySnapshot(botId, day);
|
|
@@ -32507,13 +32701,27 @@ class DailyTokenUsageStore {
|
|
|
32507
32701
|
});
|
|
32508
32702
|
}
|
|
32509
32703
|
snapshots(botId) {
|
|
32704
|
+
return this.usageWindow(botId).then((window2) => window2.snapshots);
|
|
32705
|
+
}
|
|
32706
|
+
usageWindow(botId) {
|
|
32510
32707
|
let result = [];
|
|
32708
|
+
let usageDay = "";
|
|
32709
|
+
let usageTimeZone = "";
|
|
32511
32710
|
return this.enqueue(async () => {
|
|
32512
32711
|
await this.load();
|
|
32513
|
-
|
|
32712
|
+
const at = this.now();
|
|
32713
|
+
const timeZone = this.timeZone;
|
|
32714
|
+
usageTimeZone = timeZone;
|
|
32715
|
+
usageDay = dayKeyInTimeZone(at, timeZone);
|
|
32716
|
+
if (this.prune(at, timeZone))
|
|
32514
32717
|
await this.persist();
|
|
32515
|
-
|
|
32516
|
-
|
|
32718
|
+
const oldestDay = oldestVisibleDay(usageDay);
|
|
32719
|
+
result = (this.data.bots[botId] ?? []).filter((snapshot) => snapshot.day >= oldestDay && snapshot.day <= usageDay).map((snapshot) => structuredClone(snapshot));
|
|
32720
|
+
}).then(() => ({
|
|
32721
|
+
usageDay,
|
|
32722
|
+
usageTimeZone,
|
|
32723
|
+
snapshots: result
|
|
32724
|
+
}));
|
|
32517
32725
|
}
|
|
32518
32726
|
enqueue(operation) {
|
|
32519
32727
|
const result = this.tail.then(operation, operation);
|
|
@@ -32558,11 +32766,11 @@ class DailyTokenUsageStore {
|
|
|
32558
32766
|
this.data = { version: 1, bots: valid };
|
|
32559
32767
|
this.loaded = true;
|
|
32560
32768
|
}
|
|
32561
|
-
prune(at) {
|
|
32562
|
-
const
|
|
32769
|
+
prune(at, timeZone) {
|
|
32770
|
+
const oldestDay = oldestRetainedDay(at, timeZone);
|
|
32563
32771
|
let changed = false;
|
|
32564
32772
|
for (const [botId, snapshots] of Object.entries(this.data.bots)) {
|
|
32565
|
-
const retained = snapshots.filter((snapshot) =>
|
|
32773
|
+
const retained = snapshots.filter((snapshot) => snapshot.day >= oldestDay).sort((a, b) => a.day.localeCompare(b.day));
|
|
32566
32774
|
if (retained.length !== snapshots.length || retained.some((snapshot, index2) => snapshot !== snapshots[index2]))
|
|
32567
32775
|
changed = true;
|
|
32568
32776
|
if (retained.length === 0)
|
|
@@ -32606,6 +32814,7 @@ var WARMUP_CEILING_MS = 30000;
|
|
|
32606
32814
|
var RUNTIME_RAW_TRACE_MAX_BYTES = 8 * 1024 * 1024;
|
|
32607
32815
|
var RUNTIME_RAW_TRACE_AGENT_IDS_ENV = "ALOOK_RUNTIME_RAW_TRACE_AGENT_IDS";
|
|
32608
32816
|
var STATUS_WRITE_INTERVAL_MS = 5000;
|
|
32817
|
+
var TOKEN_USAGE_BACKENDS = new Set(["claude", "codex", "opencode", "pi"]);
|
|
32609
32818
|
function parseRuntimeRawTraceAgentIds(value) {
|
|
32610
32819
|
return new Set((value ?? "").split(",").map((agentId) => agentId.trim()).filter((agentId) => agentId.length > 0 && agentId !== "*"));
|
|
32611
32820
|
}
|
|
@@ -32782,10 +32991,14 @@ async function createDaemon(opts) {
|
|
|
32782
32991
|
recordProviderQuota("claude", observed);
|
|
32783
32992
|
}
|
|
32784
32993
|
const quota = backendId === "claude" || backendId === "codex" ? providerQuotaByBackend.get(backendId) : undefined;
|
|
32785
|
-
const
|
|
32994
|
+
const usageWindow = backendId && TOKEN_USAGE_BACKENDS.has(backendId) ? await dailyTokenUsage2.usageWindow(info.agentId) : null;
|
|
32786
32995
|
return {
|
|
32787
32996
|
...info,
|
|
32788
|
-
...
|
|
32997
|
+
...usageWindow ? {
|
|
32998
|
+
usageTimeZone: usageWindow.usageTimeZone,
|
|
32999
|
+
usageDay: usageWindow.usageDay,
|
|
33000
|
+
...usageWindow.snapshots.length > 0 ? { dailyUsage: usageWindow.snapshots } : {}
|
|
33001
|
+
} : {},
|
|
32789
33002
|
...quota ? { quota: structuredClone(quota) } : {}
|
|
32790
33003
|
};
|
|
32791
33004
|
};
|
|
@@ -33197,6 +33410,7 @@ async function createDaemon(opts) {
|
|
|
33197
33410
|
arch: opts.arch,
|
|
33198
33411
|
osRelease: opts.osRelease,
|
|
33199
33412
|
daemonVersion: opts.daemonVersion,
|
|
33413
|
+
timeZone: () => dailyTokenUsage2.timeZone,
|
|
33200
33414
|
providerQuotas: providerQuotaSnapshots,
|
|
33201
33415
|
resyncActivities: async () => {
|
|
33202
33416
|
const activities = await Promise.all(manager.liveAgentActivities().map((info) => activityPayload(info)));
|
package/dist/index.js
CHANGED
|
@@ -1125,6 +1125,66 @@ function buildClaudeArgs(config) {
|
|
|
1125
1125
|
return args;
|
|
1126
1126
|
}
|
|
1127
1127
|
|
|
1128
|
+
// agent-driver/dist/internal/token-usage.js
|
|
1129
|
+
function validIdentityPart(value) {
|
|
1130
|
+
return value.trim().length > 0 && Buffer.byteLength(value, "utf8") <= 512;
|
|
1131
|
+
}
|
|
1132
|
+
function identityKey(identity) {
|
|
1133
|
+
if (!validIdentityPart(identity.runtime) || !validIdentityPart(identity.backendSessionId) || !validIdentityPart(identity.providerRecordId))
|
|
1134
|
+
return null;
|
|
1135
|
+
return JSON.stringify([identity.runtime, identity.backendSessionId, identity.providerRecordId]);
|
|
1136
|
+
}
|
|
1137
|
+
function metric(value) {
|
|
1138
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
1139
|
+
}
|
|
1140
|
+
function cacheMetric(read, write) {
|
|
1141
|
+
const present = [read, write].filter((value) => value !== undefined);
|
|
1142
|
+
if (present.length === 0)
|
|
1143
|
+
return null;
|
|
1144
|
+
const metrics = present.map(metric);
|
|
1145
|
+
if (metrics.some((value) => value === null))
|
|
1146
|
+
return null;
|
|
1147
|
+
const total = metrics.reduce((sum, value) => sum + value, 0);
|
|
1148
|
+
return Number.isSafeInteger(total) ? total : null;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
class SettledUsageProjector {
|
|
1152
|
+
active = new Set;
|
|
1153
|
+
project(record) {
|
|
1154
|
+
const key = identityKey(record);
|
|
1155
|
+
if (!key || this.active.has(key))
|
|
1156
|
+
return null;
|
|
1157
|
+
this.active.add(key);
|
|
1158
|
+
const cache = cacheMetric(record.cacheRead, record.cacheWrite);
|
|
1159
|
+
const rawInput = metric(record.input);
|
|
1160
|
+
const input = record.inputIncludesCache ? rawInput !== null && cache !== null && cache <= rawInput ? rawInput - cache : null : rawInput;
|
|
1161
|
+
const rawOutput = metric(record.output);
|
|
1162
|
+
const reasoning = metric(record.reasoning);
|
|
1163
|
+
const output = record.outputIncludesReasoning ? rawOutput : rawOutput !== null && reasoning !== null && Number.isSafeInteger(rawOutput + reasoning) ? rawOutput + reasoning : null;
|
|
1164
|
+
if (input === null && output === null && cache === null) {
|
|
1165
|
+
this.active.delete(key);
|
|
1166
|
+
return null;
|
|
1167
|
+
}
|
|
1168
|
+
return {
|
|
1169
|
+
kind: "telemetry",
|
|
1170
|
+
name: "token_usage",
|
|
1171
|
+
source: record.source,
|
|
1172
|
+
usage: { input, output, cache }
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
release(identity) {
|
|
1176
|
+
const key = identityKey(identity);
|
|
1177
|
+
if (key)
|
|
1178
|
+
this.active.delete(key);
|
|
1179
|
+
}
|
|
1180
|
+
reset() {
|
|
1181
|
+
this.active.clear();
|
|
1182
|
+
}
|
|
1183
|
+
get activeCount() {
|
|
1184
|
+
return this.active.size;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1128
1188
|
// agent-driver/dist/internal/utils.js
|
|
1129
1189
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1130
1190
|
function jsonRpcRequest(method, params, id) {
|
|
@@ -1144,9 +1204,13 @@ var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
|
1144
1204
|
class ClaudeEventNormalizer {
|
|
1145
1205
|
turnProtocol;
|
|
1146
1206
|
currentSession = null;
|
|
1207
|
+
usageProjector = new SettledUsageProjector;
|
|
1147
1208
|
constructor(turnProtocol) {
|
|
1148
1209
|
this.turnProtocol = turnProtocol;
|
|
1149
1210
|
}
|
|
1211
|
+
beginTurn() {
|
|
1212
|
+
this.usageProjector.reset();
|
|
1213
|
+
}
|
|
1150
1214
|
get currentSessionId() {
|
|
1151
1215
|
return this.currentSession;
|
|
1152
1216
|
}
|
|
@@ -1238,7 +1302,7 @@ class ClaudeEventNormalizer {
|
|
|
1238
1302
|
const turnOwner = rawOwner ? this.turnProtocol?.claimResult(rawOwner) ?? (this.turnProtocol ? null : `claude:${rawOwner}`) : null;
|
|
1239
1303
|
if (this.turnProtocol && !turnOwner)
|
|
1240
1304
|
return;
|
|
1241
|
-
const usage = this.buildUsageTelemetry(event);
|
|
1305
|
+
const usage = this.buildUsageTelemetry(event, rawOwner);
|
|
1242
1306
|
if (usage)
|
|
1243
1307
|
out.push(usage);
|
|
1244
1308
|
if (event.is_error || event.subtype === "error_during_execution") {
|
|
@@ -1253,23 +1317,26 @@ class ClaudeEventNormalizer {
|
|
|
1253
1317
|
acceptsTurnWork() {
|
|
1254
1318
|
return this.turnProtocol?.acceptsTurnWork() ?? true;
|
|
1255
1319
|
}
|
|
1256
|
-
buildUsageTelemetry(event) {
|
|
1320
|
+
buildUsageTelemetry(event, rootRequestId) {
|
|
1257
1321
|
const u = event?.usage;
|
|
1258
1322
|
if (!u)
|
|
1259
1323
|
return null;
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1324
|
+
const backendSessionId = event.session_id ?? this.currentSession;
|
|
1325
|
+
if (typeof backendSessionId !== "string" || !backendSessionId)
|
|
1326
|
+
return null;
|
|
1327
|
+
const providerRecordId = rootRequestId ?? (typeof event.request_id === "string" ? event.request_id : "invocation-result");
|
|
1328
|
+
return this.usageProjector.project({
|
|
1329
|
+
runtime: "claude",
|
|
1330
|
+
backendSessionId,
|
|
1331
|
+
providerRecordId,
|
|
1266
1332
|
source: "claude_result_usage",
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1333
|
+
input: u.input_tokens,
|
|
1334
|
+
output: u.output_tokens,
|
|
1335
|
+
cacheRead: u.cache_read_input_tokens,
|
|
1336
|
+
cacheWrite: u.cache_creation_input_tokens,
|
|
1337
|
+
inputIncludesCache: false,
|
|
1338
|
+
outputIncludesReasoning: true
|
|
1339
|
+
});
|
|
1273
1340
|
}
|
|
1274
1341
|
}
|
|
1275
1342
|
|
|
@@ -1472,7 +1539,9 @@ class ClaudeDriver {
|
|
|
1472
1539
|
turnProtocol = new ClaudeTurnProtocol;
|
|
1473
1540
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
1474
1541
|
beginTurn() {
|
|
1475
|
-
|
|
1542
|
+
const receipt = this.turnProtocol.beginTurn();
|
|
1543
|
+
this.eventNormalizer.beginTurn();
|
|
1544
|
+
return receipt;
|
|
1476
1545
|
}
|
|
1477
1546
|
probe(command) {
|
|
1478
1547
|
const explicit = command?.trim();
|
|
@@ -1526,14 +1595,6 @@ class ClaudeDriver {
|
|
|
1526
1595
|
}
|
|
1527
1596
|
|
|
1528
1597
|
// agent-driver/dist/adapters/codex/telemetry.js
|
|
1529
|
-
function metric(value) {
|
|
1530
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
1531
|
-
}
|
|
1532
|
-
function nonCachedInput(input, cached) {
|
|
1533
|
-
if (typeof input !== "number" || !Number.isSafeInteger(input) || input < 0 || typeof cached !== "number" || !Number.isSafeInteger(cached) || cached < 0 || cached > input)
|
|
1534
|
-
return null;
|
|
1535
|
-
return input - cached;
|
|
1536
|
-
}
|
|
1537
1598
|
function canonicalId(value, fallback) {
|
|
1538
1599
|
return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).length <= 64 ? value : fallback;
|
|
1539
1600
|
}
|
|
@@ -1627,28 +1688,24 @@ function mapCodexQuotaSnapshots(snapshots, sourceEpoch) {
|
|
|
1627
1688
|
}
|
|
1628
1689
|
};
|
|
1629
1690
|
}
|
|
1630
|
-
function
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
}
|
|
1648
|
-
if (method === "account/rateLimits/updated") {
|
|
1649
|
-
return [mapCodexQuotaSnapshots([params?.rateLimits ?? params ?? {}], sourceEpoch)];
|
|
1650
|
-
}
|
|
1651
|
-
return [];
|
|
1691
|
+
function mapCodexSettledUsage(params, projector) {
|
|
1692
|
+
const backendSessionId = params?.threadId ?? params?.thread_id;
|
|
1693
|
+
const providerRecordId = params?.responseId ?? params?.response_id;
|
|
1694
|
+
const usage = params?.usage;
|
|
1695
|
+
if (typeof backendSessionId !== "string" || typeof providerRecordId !== "string" || !usage)
|
|
1696
|
+
return null;
|
|
1697
|
+
return projector.project({
|
|
1698
|
+
runtime: "codex",
|
|
1699
|
+
backendSessionId,
|
|
1700
|
+
providerRecordId,
|
|
1701
|
+
source: "codex_raw_response_completed",
|
|
1702
|
+
input: usage.inputTokens ?? usage.input_tokens,
|
|
1703
|
+
output: usage.outputTokens ?? usage.output_tokens,
|
|
1704
|
+
cacheRead: usage.cachedInputTokens ?? usage.cached_input_tokens,
|
|
1705
|
+
cacheWrite: usage.cacheWriteInputTokens ?? usage.cache_write_input_tokens,
|
|
1706
|
+
inputIncludesCache: true,
|
|
1707
|
+
outputIncludesReasoning: true
|
|
1708
|
+
});
|
|
1652
1709
|
}
|
|
1653
1710
|
|
|
1654
1711
|
// agent-driver/dist/adapters/codex/normalizer.js
|
|
@@ -1700,7 +1757,8 @@ class CodexEventNormalizer {
|
|
|
1700
1757
|
rateLimitSnapshots = new Map;
|
|
1701
1758
|
quotaSnapshotInitialized = false;
|
|
1702
1759
|
quotaSourceGeneration = codexQuotaSourceGeneration;
|
|
1703
|
-
|
|
1760
|
+
usageProjector = new SettledUsageProjector;
|
|
1761
|
+
usageRecordsBySessionAndTurn = new Map;
|
|
1704
1762
|
threadId = null;
|
|
1705
1763
|
turnId = null;
|
|
1706
1764
|
terminalTurn = null;
|
|
@@ -1773,7 +1831,8 @@ class CodexEventNormalizer {
|
|
|
1773
1831
|
if (threadId !== this.threadId) {
|
|
1774
1832
|
this.turnId = null;
|
|
1775
1833
|
this.terminalTurn = null;
|
|
1776
|
-
this.
|
|
1834
|
+
this.usageProjector.reset();
|
|
1835
|
+
this.usageRecordsBySessionAndTurn.clear();
|
|
1777
1836
|
}
|
|
1778
1837
|
this.threadId = threadId;
|
|
1779
1838
|
}
|
|
@@ -1822,6 +1881,22 @@ class CodexEventNormalizer {
|
|
|
1822
1881
|
}
|
|
1823
1882
|
handleNotification(method, params) {
|
|
1824
1883
|
const notificationThreadId = typeof params?.threadId === "string" ? params.threadId : null;
|
|
1884
|
+
if (method === "rawResponse/completed")
|
|
1885
|
+
return this.handleSettledUsage(params);
|
|
1886
|
+
if (method === "turn/completed" && notificationThreadId !== null && notificationThreadId !== this.threadId) {
|
|
1887
|
+
const turnId = this.notificationTurnId(params);
|
|
1888
|
+
if (turnId)
|
|
1889
|
+
this.releaseUsageForTurn(notificationThreadId, turnId);
|
|
1890
|
+
return [];
|
|
1891
|
+
}
|
|
1892
|
+
if (method === "item/completed" && notificationThreadId !== null && notificationThreadId !== this.threadId) {
|
|
1893
|
+
const turnId = this.notificationTurnId(params);
|
|
1894
|
+
const itemType = params?.item?.type ?? params?.type;
|
|
1895
|
+
if (turnId && itemType === "contextCompaction") {
|
|
1896
|
+
this.releaseUsageForTurn(notificationThreadId, turnId);
|
|
1897
|
+
}
|
|
1898
|
+
return [];
|
|
1899
|
+
}
|
|
1825
1900
|
if (this.threadId !== null && notificationThreadId !== null && notificationThreadId !== this.threadId)
|
|
1826
1901
|
return [];
|
|
1827
1902
|
if (this.isRootWorkNotification(method) && !this.acceptRootWork(params))
|
|
@@ -1834,7 +1909,6 @@ class CodexEventNormalizer {
|
|
|
1834
1909
|
return [];
|
|
1835
1910
|
this.turnId = params.turn.id;
|
|
1836
1911
|
this.terminalTurn = null;
|
|
1837
|
-
this.pendingTurnUsage = null;
|
|
1838
1912
|
return [
|
|
1839
1913
|
{
|
|
1840
1914
|
kind: "turn_owner",
|
|
@@ -1850,7 +1924,7 @@ class CodexEventNormalizer {
|
|
|
1850
1924
|
case "item/started":
|
|
1851
1925
|
return this.handleItemStarted(params);
|
|
1852
1926
|
case "item/completed":
|
|
1853
|
-
return this.
|
|
1927
|
+
return this.handleItemCompletedAndReleaseUsage(params);
|
|
1854
1928
|
case "rawResponseItem/completed":
|
|
1855
1929
|
return [{ kind: "internal_progress", source: "codex_raw_item", itemType: "rawResponseItem" }];
|
|
1856
1930
|
case "configWarning":
|
|
@@ -1863,30 +1937,24 @@ class CodexEventNormalizer {
|
|
|
1863
1937
|
case "turn/completed":
|
|
1864
1938
|
if (!this.acceptRootTerminal(params))
|
|
1865
1939
|
return [];
|
|
1866
|
-
|
|
1867
|
-
this.pendingTurnUsage = null;
|
|
1940
|
+
this.releaseUsageForTurn(params.threadId, params.turn.id);
|
|
1868
1941
|
if (params.turn.status === "failed") {
|
|
1869
1942
|
return [
|
|
1870
|
-
...usage ? [usage] : [],
|
|
1871
1943
|
{ kind: "error", message: "Codex turn failed" },
|
|
1872
1944
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
1873
1945
|
];
|
|
1874
1946
|
}
|
|
1875
1947
|
if (params.turn.status === "interrupted") {
|
|
1876
|
-
return [
|
|
1948
|
+
return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
1877
1949
|
}
|
|
1878
|
-
return [
|
|
1950
|
+
return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
1879
1951
|
case "error":
|
|
1880
1952
|
if (params?.willRetry === true) {
|
|
1881
1953
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
1882
1954
|
}
|
|
1883
1955
|
return [{ kind: "error", message: params?.error?.message ?? params?.message ?? "Codex error" }];
|
|
1884
|
-
case "thread/tokenUsage/updated":
|
|
1885
|
-
const usage2 = mapCodexTelemetry(method, params, codexQuotaSourceEpoch)[0];
|
|
1886
|
-
if (usage2)
|
|
1887
|
-
this.pendingTurnUsage = usage2;
|
|
1956
|
+
case "thread/tokenUsage/updated":
|
|
1888
1957
|
return [];
|
|
1889
|
-
}
|
|
1890
1958
|
case "account/rateLimits/updated":
|
|
1891
1959
|
return this.mergeQuotaSnapshots(params);
|
|
1892
1960
|
case "account/updated":
|
|
@@ -1897,6 +1965,42 @@ class CodexEventNormalizer {
|
|
|
1897
1965
|
return [];
|
|
1898
1966
|
}
|
|
1899
1967
|
}
|
|
1968
|
+
handleSettledUsage(params) {
|
|
1969
|
+
const notificationTurnId = this.notificationTurnId(params);
|
|
1970
|
+
if (this.turnId === null && this.terminalTurn?.state === "closed" && notificationTurnId === this.terminalTurn.turnId && params?.threadId === this.terminalTurn.threadId)
|
|
1971
|
+
return [];
|
|
1972
|
+
const backendSessionId = params?.threadId ?? params?.thread_id;
|
|
1973
|
+
const providerRecordId = params?.responseId ?? params?.response_id;
|
|
1974
|
+
if (!notificationTurnId || typeof backendSessionId !== "string" || typeof providerRecordId !== "string")
|
|
1975
|
+
return [];
|
|
1976
|
+
const usage = mapCodexSettledUsage(params, this.usageProjector);
|
|
1977
|
+
if (!usage)
|
|
1978
|
+
return [];
|
|
1979
|
+
const recordsByTurn = this.usageRecordsBySessionAndTurn.get(backendSessionId) ?? new Map;
|
|
1980
|
+
const recordIds = recordsByTurn.get(notificationTurnId) ?? new Set;
|
|
1981
|
+
recordIds.add(providerRecordId);
|
|
1982
|
+
recordsByTurn.set(notificationTurnId, recordIds);
|
|
1983
|
+
this.usageRecordsBySessionAndTurn.set(backendSessionId, recordsByTurn);
|
|
1984
|
+
return [usage];
|
|
1985
|
+
}
|
|
1986
|
+
releaseUsageForTurn(backendSessionId, turnId) {
|
|
1987
|
+
const recordsByTurn = this.usageRecordsBySessionAndTurn.get(backendSessionId);
|
|
1988
|
+
for (const providerRecordId of recordsByTurn?.get(turnId) ?? []) {
|
|
1989
|
+
this.usageProjector.release({ runtime: "codex", backendSessionId, providerRecordId });
|
|
1990
|
+
}
|
|
1991
|
+
recordsByTurn?.delete(turnId);
|
|
1992
|
+
if (recordsByTurn?.size === 0)
|
|
1993
|
+
this.usageRecordsBySessionAndTurn.delete(backendSessionId);
|
|
1994
|
+
}
|
|
1995
|
+
handleItemCompletedAndReleaseUsage(params) {
|
|
1996
|
+
const events = this.handleItemCompleted(params);
|
|
1997
|
+
const turnId = this.notificationTurnId(params);
|
|
1998
|
+
const itemType = params?.item?.type ?? params?.type;
|
|
1999
|
+
if (turnId && itemType === "contextCompaction" && turnId !== this.turnId && typeof params?.threadId === "string") {
|
|
2000
|
+
this.releaseUsageForTurn(params.threadId, turnId);
|
|
2001
|
+
}
|
|
2002
|
+
return events;
|
|
2003
|
+
}
|
|
1900
2004
|
isRootWorkNotification(method) {
|
|
1901
2005
|
return method === "item/reasoning/textDelta" || method === "item/reasoning/summaryTextDelta" || method === "item/agentMessage/delta" || method === "item/started" || method === "item/completed" || method === "rawResponseItem/completed";
|
|
1902
2006
|
}
|
|
@@ -3441,6 +3545,7 @@ class OpenCodeServiceLane {
|
|
|
3441
3545
|
lastDurableSeq = 0;
|
|
3442
3546
|
durableSeqById = new Map;
|
|
3443
3547
|
durableIdBySeq = new Map;
|
|
3548
|
+
usageProjector = new SettledUsageProjector;
|
|
3444
3549
|
toolNames = new Map;
|
|
3445
3550
|
handledPermissions = new Set;
|
|
3446
3551
|
permissionFlights = new Map;
|
|
@@ -3981,7 +4086,8 @@ class OpenCodeServiceLane {
|
|
|
3981
4086
|
const event = record3(value);
|
|
3982
4087
|
const durable = record3(event?.durable);
|
|
3983
4088
|
const data = record3(event?.data);
|
|
3984
|
-
|
|
4089
|
+
const backendSessionId = this.sessionId;
|
|
4090
|
+
if (!event || !backendSessionId || typeof event.id !== "string" || typeof event.type !== "string" || !durable || durable.aggregateID !== this.sessionId || !Number.isInteger(durable.seq) || Number(durable.seq) < 0 || data?.sessionID !== this.sessionId) {
|
|
3985
4091
|
throw new OpenCodeProtocolError("OpenCode session stream emitted an invalid durable event");
|
|
3986
4092
|
}
|
|
3987
4093
|
const seq = Number(durable.seq);
|
|
@@ -4071,21 +4177,27 @@ class OpenCodeServiceLane {
|
|
|
4071
4177
|
});
|
|
4072
4178
|
}
|
|
4073
4179
|
const tokens = record3(data.tokens);
|
|
4074
|
-
if (tokens
|
|
4180
|
+
if (tokens) {
|
|
4075
4181
|
const cache = record3(tokens.cache);
|
|
4076
|
-
const
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4182
|
+
const identity = {
|
|
4183
|
+
runtime: "opencode",
|
|
4184
|
+
backendSessionId,
|
|
4185
|
+
providerRecordId: event.id
|
|
4186
|
+
};
|
|
4187
|
+
const usage = this.usageProjector.project({
|
|
4188
|
+
...identity,
|
|
4082
4189
|
source: "opencode.v2",
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4190
|
+
input: tokens.input,
|
|
4191
|
+
output: tokens.output,
|
|
4192
|
+
reasoning: tokens.reasoning,
|
|
4193
|
+
cacheRead: cache?.read,
|
|
4194
|
+
cacheWrite: cache?.write,
|
|
4195
|
+
inputIncludesCache: false,
|
|
4196
|
+
outputIncludesReasoning: false
|
|
4088
4197
|
});
|
|
4198
|
+
if (usage)
|
|
4199
|
+
this.events.emit("runtime_event", usage);
|
|
4200
|
+
this.usageProjector.release(identity);
|
|
4089
4201
|
}
|
|
4090
4202
|
break;
|
|
4091
4203
|
}
|
|
@@ -4804,6 +4916,11 @@ function readPiSdkVersion() {
|
|
|
4804
4916
|
} catch {}
|
|
4805
4917
|
return resolvePiSdkVersionFromPath();
|
|
4806
4918
|
}
|
|
4919
|
+
function piUsageState(state) {
|
|
4920
|
+
state.usageProjector ??= new SettledUsageProjector;
|
|
4921
|
+
state.pendingUsageRecordIds ??= new Set;
|
|
4922
|
+
return { projector: state.usageProjector, pending: state.pendingUsageRecordIds };
|
|
4923
|
+
}
|
|
4807
4924
|
function mapPiSdkEvent(event, sessionId, state) {
|
|
4808
4925
|
if (event?.type === "message_update") {
|
|
4809
4926
|
const d = event.assistantMessageEvent ?? {};
|
|
@@ -4824,6 +4941,35 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
4824
4941
|
}
|
|
4825
4942
|
}
|
|
4826
4943
|
switch (event?.type) {
|
|
4944
|
+
case "message_end": {
|
|
4945
|
+
const message = event.message;
|
|
4946
|
+
if (message?.role !== "assistant" || !message.usage)
|
|
4947
|
+
return [];
|
|
4948
|
+
state.usageRecordSequence = (state.usageRecordSequence ?? 0) + 1;
|
|
4949
|
+
const providerRecordId = typeof message.responseId === "string" && message.responseId ? message.responseId : `live:${message.timestamp ?? "unknown"}:${state.usageRecordSequence}`;
|
|
4950
|
+
const { projector, pending } = piUsageState(state);
|
|
4951
|
+
const identity = { runtime: "pi", backendSessionId: sessionId, providerRecordId };
|
|
4952
|
+
const usage = projector.project({
|
|
4953
|
+
...identity,
|
|
4954
|
+
source: "pi_message_end",
|
|
4955
|
+
input: message.usage.input,
|
|
4956
|
+
output: message.usage.output,
|
|
4957
|
+
cacheRead: message.usage.cacheRead,
|
|
4958
|
+
cacheWrite: message.usage.cacheWrite,
|
|
4959
|
+
inputIncludesCache: false,
|
|
4960
|
+
outputIncludesReasoning: true
|
|
4961
|
+
});
|
|
4962
|
+
pending.add(providerRecordId);
|
|
4963
|
+
return usage ? [usage] : [];
|
|
4964
|
+
}
|
|
4965
|
+
case "turn_end": {
|
|
4966
|
+
const { projector, pending } = piUsageState(state);
|
|
4967
|
+
for (const providerRecordId of pending) {
|
|
4968
|
+
projector.release({ runtime: "pi", backendSessionId: sessionId, providerRecordId });
|
|
4969
|
+
}
|
|
4970
|
+
pending.clear();
|
|
4971
|
+
return [];
|
|
4972
|
+
}
|
|
4827
4973
|
case "auto_retry_start":
|
|
4828
4974
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "pi_auto_retry" }];
|
|
4829
4975
|
case "auto_retry_end":
|
|
@@ -26874,6 +27020,7 @@ var communityMachine = sqliteTable("community_machine", {
|
|
|
26874
27020
|
arch: text("arch").notNull().default(""),
|
|
26875
27021
|
osRelease: text("os_release").notNull().default(""),
|
|
26876
27022
|
daemonVersion: text("daemon_version").notNull().default(""),
|
|
27023
|
+
timeZone: text("time_zone"),
|
|
26877
27024
|
metadata: text("metadata"),
|
|
26878
27025
|
availableRuntimes: text("available_runtimes", { mode: "json" }).$type().notNull().default([]),
|
|
26879
27026
|
status: text("status").notNull().default("offline"),
|
|
@@ -27225,6 +27372,7 @@ class AgentRouter {
|
|
|
27225
27372
|
await this.opts.channel.reportReady(this.buildReady());
|
|
27226
27373
|
}
|
|
27227
27374
|
buildReady() {
|
|
27375
|
+
const timeZone = typeof this.opts.timeZone === "function" ? this.opts.timeZone() : this.opts.timeZone;
|
|
27228
27376
|
return {
|
|
27229
27377
|
runtimeReport: [...this.runtimes.values()],
|
|
27230
27378
|
capabilities: [CONTROL_HEARTBEAT_CAPABILITY],
|
|
@@ -27234,6 +27382,7 @@ class AgentRouter {
|
|
|
27234
27382
|
arch: this.opts.arch,
|
|
27235
27383
|
osRelease: this.opts.osRelease,
|
|
27236
27384
|
daemonVersion: this.opts.daemonVersion,
|
|
27385
|
+
timeZone,
|
|
27237
27386
|
...this.opts.providerQuotas ? { providerQuotas: this.opts.providerQuotas() } : {}
|
|
27238
27387
|
};
|
|
27239
27388
|
}
|
|
@@ -28951,6 +29100,7 @@ var HostReadyMessageSchema = exports_external.object({
|
|
|
28951
29100
|
arch: exports_external.string().optional(),
|
|
28952
29101
|
osRelease: exports_external.string().optional(),
|
|
28953
29102
|
daemonVersion: exports_external.string().optional(),
|
|
29103
|
+
timeZone: exports_external.string().min(1).max(128).optional(),
|
|
28954
29104
|
providerQuotas: exports_external.array(ProviderQuotaSnapshotSchema).max(2).optional().default([])
|
|
28955
29105
|
});
|
|
28956
29106
|
var CommunityDaemonReadySchema = exports_external.object({
|
|
@@ -28973,6 +29123,8 @@ var AgentActivityMessageSchema = exports_external.object({
|
|
|
28973
29123
|
type: exports_external.literal("agent_activity"),
|
|
28974
29124
|
agentId: exports_external.string(),
|
|
28975
29125
|
state: exports_external.enum(["idle", "starting", "running", "stopping"]),
|
|
29126
|
+
usageTimeZone: exports_external.string().min(1).max(128).optional(),
|
|
29127
|
+
usageDay: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
28976
29128
|
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(7).optional(),
|
|
28977
29129
|
quota: ProviderQuotaSnapshotSchema.optional()
|
|
28978
29130
|
});
|
|
@@ -29238,6 +29390,42 @@ var BotAuditEventAckFrameSchema = exports_external.strictObject({
|
|
|
29238
29390
|
type: exports_external.literal("bot_audit_event_ack"),
|
|
29239
29391
|
eventId: exports_external.string().min(1).max(128)
|
|
29240
29392
|
});
|
|
29393
|
+
// ../shared/src/utils/day-key.ts
|
|
29394
|
+
function utcDayKey(now) {
|
|
29395
|
+
const d = now instanceof Date ? now : new Date(now);
|
|
29396
|
+
return d.toISOString().slice(0, 10);
|
|
29397
|
+
}
|
|
29398
|
+
function calendarDayKeyDaysAgo(day, days) {
|
|
29399
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(day);
|
|
29400
|
+
if (!match)
|
|
29401
|
+
throw new RangeError("invalid calendar day key");
|
|
29402
|
+
const year = Number(match[1]);
|
|
29403
|
+
const month = Number(match[2]);
|
|
29404
|
+
const date5 = Number(match[3]);
|
|
29405
|
+
const parsed = new Date(Date.UTC(year, month - 1, date5));
|
|
29406
|
+
if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== date5) {
|
|
29407
|
+
throw new RangeError("invalid calendar day key");
|
|
29408
|
+
}
|
|
29409
|
+
parsed.setUTCDate(parsed.getUTCDate() - days);
|
|
29410
|
+
return utcDayKey(parsed);
|
|
29411
|
+
}
|
|
29412
|
+
function dayKeyInTimeZone(now, timeZone) {
|
|
29413
|
+
const date5 = now instanceof Date ? now : new Date(now);
|
|
29414
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
29415
|
+
timeZone,
|
|
29416
|
+
year: "numeric",
|
|
29417
|
+
month: "2-digit",
|
|
29418
|
+
day: "2-digit"
|
|
29419
|
+
}).formatToParts(date5);
|
|
29420
|
+
const values = new Map(parts.map((part) => [part.type, part.value]));
|
|
29421
|
+
const year = values.get("year");
|
|
29422
|
+
const month = values.get("month");
|
|
29423
|
+
const day = values.get("day");
|
|
29424
|
+
if (!year || !month || !day)
|
|
29425
|
+
throw new RangeError("unable to format calendar day key");
|
|
29426
|
+
return `${year}-${month}-${day}`;
|
|
29427
|
+
}
|
|
29428
|
+
|
|
29241
29429
|
// ../shared/src/db/community-schema.ts
|
|
29242
29430
|
var exports_community_schema = {};
|
|
29243
29431
|
__export(exports_community_schema, {
|
|
@@ -32726,15 +32914,12 @@ class DaemonSelfSleepScheduler {
|
|
|
32726
32914
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32727
32915
|
import { dirname as dirname5, join as join14 } from "node:path";
|
|
32728
32916
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32729
|
-
function
|
|
32730
|
-
|
|
32917
|
+
function oldestRetainedDay(at, timeZone) {
|
|
32918
|
+
const today = dayKeyInTimeZone(at, timeZone);
|
|
32919
|
+
return calendarDayKeyDaysAgo(today, 8);
|
|
32731
32920
|
}
|
|
32732
|
-
function
|
|
32733
|
-
|
|
32734
|
-
for (let offset = 0;offset < 7; offset += 1) {
|
|
32735
|
-
days.add(dayKey(new Date(at.getTime() - offset * 86400000)));
|
|
32736
|
-
}
|
|
32737
|
-
return days;
|
|
32921
|
+
function oldestVisibleDay(today) {
|
|
32922
|
+
return calendarDayKeyDaysAgo(today, 6);
|
|
32738
32923
|
}
|
|
32739
32924
|
function isMetric(value) {
|
|
32740
32925
|
return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -32779,16 +32964,25 @@ class DailyTokenUsageStore {
|
|
|
32779
32964
|
loaded = false;
|
|
32780
32965
|
data = { version: 1, bots: {} };
|
|
32781
32966
|
filePath;
|
|
32782
|
-
|
|
32967
|
+
resolveTimeZone;
|
|
32968
|
+
constructor(workingDirectoryBase, now = () => new Date, timeZone = () => Intl.DateTimeFormat().resolvedOptions().timeZone) {
|
|
32783
32969
|
this.now = now;
|
|
32970
|
+
this.resolveTimeZone = typeof timeZone === "string" ? () => timeZone : timeZone;
|
|
32971
|
+
this.timeZone;
|
|
32784
32972
|
this.filePath = join14(workingDirectoryBase, ".telemetry", "daily-token-usage.json");
|
|
32785
32973
|
}
|
|
32974
|
+
get timeZone() {
|
|
32975
|
+
const timeZone = this.resolveTimeZone();
|
|
32976
|
+
dayKeyInTimeZone(0, timeZone);
|
|
32977
|
+
return timeZone;
|
|
32978
|
+
}
|
|
32786
32979
|
record(botId, delta) {
|
|
32787
32980
|
return this.enqueue(async () => {
|
|
32788
32981
|
await this.load();
|
|
32789
32982
|
const at = this.now();
|
|
32790
|
-
this.
|
|
32791
|
-
|
|
32983
|
+
const timeZone = this.timeZone;
|
|
32984
|
+
this.prune(at, timeZone);
|
|
32985
|
+
const day = dayKeyInTimeZone(at, timeZone);
|
|
32792
32986
|
const snapshots = this.data.bots[botId] ?? [];
|
|
32793
32987
|
const existing = snapshots.find((snapshot) => snapshot.day === day);
|
|
32794
32988
|
const next = existing ?? emptySnapshot(botId, day);
|
|
@@ -32805,13 +32999,27 @@ class DailyTokenUsageStore {
|
|
|
32805
32999
|
});
|
|
32806
33000
|
}
|
|
32807
33001
|
snapshots(botId) {
|
|
33002
|
+
return this.usageWindow(botId).then((window2) => window2.snapshots);
|
|
33003
|
+
}
|
|
33004
|
+
usageWindow(botId) {
|
|
32808
33005
|
let result = [];
|
|
33006
|
+
let usageDay = "";
|
|
33007
|
+
let usageTimeZone = "";
|
|
32809
33008
|
return this.enqueue(async () => {
|
|
32810
33009
|
await this.load();
|
|
32811
|
-
|
|
33010
|
+
const at = this.now();
|
|
33011
|
+
const timeZone = this.timeZone;
|
|
33012
|
+
usageTimeZone = timeZone;
|
|
33013
|
+
usageDay = dayKeyInTimeZone(at, timeZone);
|
|
33014
|
+
if (this.prune(at, timeZone))
|
|
32812
33015
|
await this.persist();
|
|
32813
|
-
|
|
32814
|
-
|
|
33016
|
+
const oldestDay = oldestVisibleDay(usageDay);
|
|
33017
|
+
result = (this.data.bots[botId] ?? []).filter((snapshot) => snapshot.day >= oldestDay && snapshot.day <= usageDay).map((snapshot) => structuredClone(snapshot));
|
|
33018
|
+
}).then(() => ({
|
|
33019
|
+
usageDay,
|
|
33020
|
+
usageTimeZone,
|
|
33021
|
+
snapshots: result
|
|
33022
|
+
}));
|
|
32815
33023
|
}
|
|
32816
33024
|
enqueue(operation) {
|
|
32817
33025
|
const result = this.tail.then(operation, operation);
|
|
@@ -32856,11 +33064,11 @@ class DailyTokenUsageStore {
|
|
|
32856
33064
|
this.data = { version: 1, bots: valid };
|
|
32857
33065
|
this.loaded = true;
|
|
32858
33066
|
}
|
|
32859
|
-
prune(at) {
|
|
32860
|
-
const
|
|
33067
|
+
prune(at, timeZone) {
|
|
33068
|
+
const oldestDay = oldestRetainedDay(at, timeZone);
|
|
32861
33069
|
let changed = false;
|
|
32862
33070
|
for (const [botId, snapshots] of Object.entries(this.data.bots)) {
|
|
32863
|
-
const retained = snapshots.filter((snapshot) =>
|
|
33071
|
+
const retained = snapshots.filter((snapshot) => snapshot.day >= oldestDay).sort((a, b) => a.day.localeCompare(b.day));
|
|
32864
33072
|
if (retained.length !== snapshots.length || retained.some((snapshot, index2) => snapshot !== snapshots[index2]))
|
|
32865
33073
|
changed = true;
|
|
32866
33074
|
if (retained.length === 0)
|
|
@@ -32904,6 +33112,7 @@ var WARMUP_CEILING_MS = 30000;
|
|
|
32904
33112
|
var RUNTIME_RAW_TRACE_MAX_BYTES = 8 * 1024 * 1024;
|
|
32905
33113
|
var RUNTIME_RAW_TRACE_AGENT_IDS_ENV = "ALOOK_RUNTIME_RAW_TRACE_AGENT_IDS";
|
|
32906
33114
|
var STATUS_WRITE_INTERVAL_MS = 5000;
|
|
33115
|
+
var TOKEN_USAGE_BACKENDS = new Set(["claude", "codex", "opencode", "pi"]);
|
|
32907
33116
|
function parseRuntimeRawTraceAgentIds(value) {
|
|
32908
33117
|
return new Set((value ?? "").split(",").map((agentId) => agentId.trim()).filter((agentId) => agentId.length > 0 && agentId !== "*"));
|
|
32909
33118
|
}
|
|
@@ -33080,10 +33289,14 @@ async function createDaemon(opts) {
|
|
|
33080
33289
|
recordProviderQuota("claude", observed);
|
|
33081
33290
|
}
|
|
33082
33291
|
const quota = backendId === "claude" || backendId === "codex" ? providerQuotaByBackend.get(backendId) : undefined;
|
|
33083
|
-
const
|
|
33292
|
+
const usageWindow = backendId && TOKEN_USAGE_BACKENDS.has(backendId) ? await dailyTokenUsage2.usageWindow(info.agentId) : null;
|
|
33084
33293
|
return {
|
|
33085
33294
|
...info,
|
|
33086
|
-
...
|
|
33295
|
+
...usageWindow ? {
|
|
33296
|
+
usageTimeZone: usageWindow.usageTimeZone,
|
|
33297
|
+
usageDay: usageWindow.usageDay,
|
|
33298
|
+
...usageWindow.snapshots.length > 0 ? { dailyUsage: usageWindow.snapshots } : {}
|
|
33299
|
+
} : {},
|
|
33087
33300
|
...quota ? { quota: structuredClone(quota) } : {}
|
|
33088
33301
|
};
|
|
33089
33302
|
};
|
|
@@ -33495,6 +33708,7 @@ async function createDaemon(opts) {
|
|
|
33495
33708
|
arch: opts.arch,
|
|
33496
33709
|
osRelease: opts.osRelease,
|
|
33497
33710
|
daemonVersion: opts.daemonVersion,
|
|
33711
|
+
timeZone: () => dailyTokenUsage2.timeZone,
|
|
33498
33712
|
providerQuotas: providerQuotaSnapshots,
|
|
33499
33713
|
resyncActivities: async () => {
|
|
33500
33714
|
const activities = await Promise.all(manager.liveAgentActivities().map((info) => activityPayload(info)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alook/daemon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.28",
|
|
4
4
|
"description": "Alook agent daemon — host-side runtime backend, process manager, credential proxy, and control plane.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/alookai/alook#readme",
|