@codexhost/cli-darwin-x64 0.13.0 → 0.13.2
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/README.md +1 -1
- package/THIRD_PARTY_NOTICES.txt +1 -1
- package/app/codexhost-distribution.json +1 -1
- package/app/console-server.mjs +88 -44
- package/app/console-web.js +3681 -3948
- package/app/desktop-controller.mjs +8 -1
- package/app/host-runtime.mjs +927 -236
- package/app/plugins/antigravity/plugin.mjs +8 -1
- package/app/plugins/claude-code/plugin.mjs +33031 -22328
- package/app/plugins/codebuddy/plugin.mjs +47 -4
- package/app/plugins/codex-usage/plugin.mjs +657 -27
- package/app/plugins/cursor-cli/plugin.mjs +8 -1
- package/app/plugins/deepseek-harness/plugin.mjs +28 -3
- package/app/plugins/grok/plugin.mjs +43 -8
- package/app/plugins/hermes/plugin.mjs +192 -41
- package/app/plugins/kimi-code/plugin.mjs +8 -1
- package/app/plugins/kiro-cli/plugin.mjs +8 -1
- package/app/plugins/omp/plugin.mjs +31 -7
- package/app/plugins/opencode/plugin.mjs +34 -4
- package/app/plugins/pi/plugin.mjs +84 -43
- package/app/plugins/qoder/plugin.mjs +54 -4
- package/app/plugins/qoder-cn/plugin.mjs +54 -4
- package/app/plugins/workbuddy/plugin.mjs +47 -4
- package/app/plugins/zcode/plugin.mjs +37 -4
- package/app/renderer-extension.js +11574 -7264
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/package.json +1 -1
|
@@ -14676,6 +14676,8 @@ var usageStatisticsSessionSchema = external_exports.strictObject({
|
|
|
14676
14676
|
harness,
|
|
14677
14677
|
sessionId: external_exports.string().min(1).max(512),
|
|
14678
14678
|
project: project.nullable(),
|
|
14679
|
+
/** Persisted Desktop title for a mapped Session, otherwise its native name; may be absent. */
|
|
14680
|
+
title: external_exports.string().min(1).max(200).optional(),
|
|
14679
14681
|
/** Models the session used, most requests first. */
|
|
14680
14682
|
models: external_exports.array(model).max(16),
|
|
14681
14683
|
firstAtMs: count,
|
|
@@ -14742,7 +14744,12 @@ var usageStatisticsResultSchema = external_exports.strictObject({
|
|
|
14742
14744
|
* The sessions that spent the most, by cost and by tokens without cache, all filters applied;
|
|
14743
14745
|
* requests without a native session are not listed here but count everywhere else.
|
|
14744
14746
|
*/
|
|
14745
|
-
sessions: external_exports.array(usageStatisticsSessionSchema).max(100)
|
|
14747
|
+
sessions: external_exports.array(usageStatisticsSessionSchema).max(100),
|
|
14748
|
+
/**
|
|
14749
|
+
* The sessions last active in the range, newest first, all filters applied. Optional for older
|
|
14750
|
+
* Hosts; missing is treated as no list rather than no sessions.
|
|
14751
|
+
*/
|
|
14752
|
+
recentSessions: external_exports.array(usageStatisticsSessionSchema).max(100).optional()
|
|
14746
14753
|
});
|
|
14747
14754
|
|
|
14748
14755
|
// ../../shared-contracts/dist/ids.js
|
|
@@ -15862,8 +15869,24 @@ import path from "node:path";
|
|
|
15862
15869
|
import { setImmediate as yieldToEventLoop } from "node:timers/promises";
|
|
15863
15870
|
|
|
15864
15871
|
// ../../harness-adapter/dist/usage-statistics.js
|
|
15872
|
+
import { createReadStream } from "node:fs";
|
|
15873
|
+
import { createInterface } from "node:readline";
|
|
15865
15874
|
var MAX_SESSION_ID_LENGTH = 512;
|
|
15866
15875
|
var MAX_CWD_LENGTH = 4096;
|
|
15876
|
+
var MAX_SESSION_TITLE_LENGTH = 200;
|
|
15877
|
+
function usageSessionTitle(value) {
|
|
15878
|
+
if (typeof value !== "string")
|
|
15879
|
+
return void 0;
|
|
15880
|
+
const normalized = value.replaceAll("\0", "").replaceAll(/\s+/gu, " ").trim();
|
|
15881
|
+
if (!normalized)
|
|
15882
|
+
return void 0;
|
|
15883
|
+
if (normalized.length <= MAX_SESSION_TITLE_LENGTH)
|
|
15884
|
+
return normalized;
|
|
15885
|
+
const characters = [...normalized];
|
|
15886
|
+
if (characters.length <= MAX_SESSION_TITLE_LENGTH)
|
|
15887
|
+
return normalized;
|
|
15888
|
+
return `${characters.slice(0, MAX_SESSION_TITLE_LENGTH - 1).join("").trimEnd()}…`;
|
|
15889
|
+
}
|
|
15867
15890
|
function sessionIdOk(value) {
|
|
15868
15891
|
return typeof value === "string" && value.length > 0 && value.length <= MAX_SESSION_ID_LENGTH;
|
|
15869
15892
|
}
|
|
@@ -15873,12 +15896,14 @@ function cwdOk(value) {
|
|
|
15873
15896
|
function withUsageSession(entry, session) {
|
|
15874
15897
|
const sessionId = sessionIdOk(session.sessionId) ? session.sessionId : void 0;
|
|
15875
15898
|
const cwd = cwdOk(session.cwd) ? session.cwd : void 0;
|
|
15899
|
+
const sessionTitle = sessionId !== void 0 ? usageSessionTitle(session.title) : void 0;
|
|
15876
15900
|
if (sessionId === void 0 && cwd === void 0)
|
|
15877
15901
|
return entry;
|
|
15878
15902
|
return {
|
|
15879
15903
|
...entry,
|
|
15880
15904
|
...sessionId !== void 0 ? { sessionId } : {},
|
|
15881
|
-
...cwd !== void 0 ? { cwd } : {}
|
|
15905
|
+
...cwd !== void 0 ? { cwd } : {},
|
|
15906
|
+
...sessionTitle !== void 0 ? { sessionTitle } : {}
|
|
15882
15907
|
};
|
|
15883
15908
|
}
|
|
15884
15909
|
function tokenCount(value) {
|
|
@@ -15918,6 +15943,12 @@ function parseHarnessUsageEntry(value) {
|
|
|
15918
15943
|
return null;
|
|
15919
15944
|
if (entry.cwd !== void 0 && !cwdOk(entry.cwd))
|
|
15920
15945
|
return null;
|
|
15946
|
+
if (entry.sessionTitle !== void 0) {
|
|
15947
|
+
const sessionTitle = usageSessionTitle(entry.sessionTitle);
|
|
15948
|
+
if (sessionTitle === void 0)
|
|
15949
|
+
return null;
|
|
15950
|
+
entry.sessionTitle = sessionTitle;
|
|
15951
|
+
}
|
|
15921
15952
|
if (entry.tokensUnknown !== void 0 && entry.tokensUnknown !== true)
|
|
15922
15953
|
return null;
|
|
15923
15954
|
if (entry.costUsd !== void 0 && (typeof entry.costUsd !== "number" || !Number.isFinite(entry.costUsd) || entry.costUsd < 0)) {
|
|
@@ -15928,6 +15959,25 @@ function parseHarnessUsageEntry(value) {
|
|
|
15928
15959
|
}
|
|
15929
15960
|
return entry;
|
|
15930
15961
|
}
|
|
15962
|
+
async function* jsonlRecords(file2, marker, signal) {
|
|
15963
|
+
const lines = createInterface({
|
|
15964
|
+
input: createReadStream(file2, { encoding: "utf8", signal }),
|
|
15965
|
+
crlfDelay: Infinity
|
|
15966
|
+
});
|
|
15967
|
+
for await (const line of lines) {
|
|
15968
|
+
if (!line.includes(marker))
|
|
15969
|
+
continue;
|
|
15970
|
+
let value;
|
|
15971
|
+
try {
|
|
15972
|
+
value = JSON.parse(line);
|
|
15973
|
+
} catch {
|
|
15974
|
+
continue;
|
|
15975
|
+
}
|
|
15976
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
15977
|
+
yield value;
|
|
15978
|
+
}
|
|
15979
|
+
}
|
|
15980
|
+
}
|
|
15931
15981
|
function nativeTimeMs(value) {
|
|
15932
15982
|
const time3 = typeof value === "number" ? value : typeof value === "string" ? Date.parse(value) : Number.NaN;
|
|
15933
15983
|
return Number.isFinite(time3) && time3 > 0 ? Math.floor(time3) : null;
|
|
@@ -16336,7 +16386,7 @@ var CodexCounters = class {
|
|
|
16336
16386
|
};
|
|
16337
16387
|
|
|
16338
16388
|
// dist/rollout-io.js
|
|
16339
|
-
import { createReadStream } from "node:fs";
|
|
16389
|
+
import { createReadStream as createReadStream2 } from "node:fs";
|
|
16340
16390
|
import { StringDecoder } from "node:string_decoder";
|
|
16341
16391
|
import { promisify } from "node:util";
|
|
16342
16392
|
import { zstdDecompress } from "node:zlib";
|
|
@@ -16401,7 +16451,7 @@ function frameSize(data) {
|
|
|
16401
16451
|
}
|
|
16402
16452
|
async function* rolloutBytes(file2, signal) {
|
|
16403
16453
|
signal.throwIfAborted();
|
|
16404
|
-
const stream =
|
|
16454
|
+
const stream = createReadStream2(file2, { signal });
|
|
16405
16455
|
let pending = Buffer.alloc(0);
|
|
16406
16456
|
try {
|
|
16407
16457
|
for await (const value of stream) {
|
|
@@ -16493,32 +16543,84 @@ async function copyRelation(a, b, signal) {
|
|
|
16493
16543
|
// dist/usage-statistics.js
|
|
16494
16544
|
var ROLLOUT = /^rollout-.*?([0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})(?:[_-][0-9a-f-]+)?\.jsonl(?:\.zst)?$/iu;
|
|
16495
16545
|
var text = (value) => typeof value === "string" ? value : "";
|
|
16546
|
+
var ROW_KINDS = /* @__PURE__ */ new Set([
|
|
16547
|
+
"session_meta",
|
|
16548
|
+
"turn_context",
|
|
16549
|
+
"token_usage_record",
|
|
16550
|
+
"compacted",
|
|
16551
|
+
"event_msg",
|
|
16552
|
+
"response_item"
|
|
16553
|
+
]);
|
|
16554
|
+
var HEAD_TYPE = /"type"\s*:\s*"([^"]+)"/u;
|
|
16555
|
+
var TAIL_TYPE = /"type"\s*:\s*"([^"]+)"\s*\}\s*$/u;
|
|
16556
|
+
function rowKind(line) {
|
|
16557
|
+
const head = HEAD_TYPE.exec(line.slice(0, 1024))?.[1];
|
|
16558
|
+
if (head && ROW_KINDS.has(head))
|
|
16559
|
+
return head;
|
|
16560
|
+
return TAIL_TYPE.exec(line.slice(-1024))?.[1] ?? head;
|
|
16561
|
+
}
|
|
16496
16562
|
async function stamp(file2) {
|
|
16497
16563
|
const s = await lstat(file2, { bigint: true });
|
|
16498
16564
|
if (!s.isFile())
|
|
16499
16565
|
throw new Error("Codex rollout is not a regular file");
|
|
16500
16566
|
return `${s.dev}:${s.ino}:${s.size}:${s.mtimeNs}:${s.ctimeNs}`;
|
|
16501
16567
|
}
|
|
16502
|
-
function fingerprint(files) {
|
|
16503
|
-
return createHash("sha256").update(JSON.stringify(files)).digest("hex");
|
|
16568
|
+
function fingerprint(files, extra = "") {
|
|
16569
|
+
return createHash("sha256").update(JSON.stringify(files)).update(extra).digest("hex");
|
|
16504
16570
|
}
|
|
16505
|
-
|
|
16571
|
+
function typedPrompt(value) {
|
|
16572
|
+
if (typeof value !== "string")
|
|
16573
|
+
return void 0;
|
|
16574
|
+
const text2 = value.trim();
|
|
16575
|
+
if (!text2 || text2.startsWith("<") || text2.startsWith("# AGENTS.md") || text2.startsWith("<!--")) {
|
|
16576
|
+
return void 0;
|
|
16577
|
+
}
|
|
16578
|
+
return usageSessionTitle(text2);
|
|
16579
|
+
}
|
|
16580
|
+
function userItemPrompt(payload) {
|
|
16581
|
+
if (!payload || payload.type !== "message" || payload.role !== "user")
|
|
16582
|
+
return void 0;
|
|
16583
|
+
if (!Array.isArray(payload.content))
|
|
16584
|
+
return typedPrompt(payload.content);
|
|
16585
|
+
for (const part of payload.content) {
|
|
16586
|
+
if (typeof part !== "object" || part === null)
|
|
16587
|
+
continue;
|
|
16588
|
+
const block = part;
|
|
16589
|
+
if (block.type === "input_text" || block.type === "text") {
|
|
16590
|
+
const prompt = typedPrompt(block.text);
|
|
16591
|
+
if (prompt)
|
|
16592
|
+
return prompt;
|
|
16593
|
+
}
|
|
16594
|
+
}
|
|
16595
|
+
return void 0;
|
|
16596
|
+
}
|
|
16597
|
+
async function readThreadNames(home, signal) {
|
|
16598
|
+
const names = /* @__PURE__ */ new Map();
|
|
16599
|
+
try {
|
|
16600
|
+
for await (const line of jsonlRecords(path.join(home, "session_index.jsonl"), '"thread_name"', signal)) {
|
|
16601
|
+
const id = text(line.id);
|
|
16602
|
+
const name = usageSessionTitle(line.thread_name);
|
|
16603
|
+
if (id && name)
|
|
16604
|
+
names.set(id, name);
|
|
16605
|
+
}
|
|
16606
|
+
} catch (error51) {
|
|
16607
|
+
if (error51.code !== "ENOENT")
|
|
16608
|
+
throw error51;
|
|
16609
|
+
}
|
|
16610
|
+
return names;
|
|
16611
|
+
}
|
|
16612
|
+
async function readCodexRollouts(files, thread, signal, options = {}) {
|
|
16506
16613
|
const counters = new CodexCounters();
|
|
16507
|
-
let model2 = "", cwd = "", ownFrom = null, firstMeta = false, forkAt = 0, seen = 0;
|
|
16614
|
+
let model2 = "", cwd = "", ownFrom = null, firstMeta = false, forkAt = 0, seen = 0, firstPrompt;
|
|
16508
16615
|
for (const file2 of files) {
|
|
16509
16616
|
for await (const line of rolloutLines(file2, signal)) {
|
|
16510
16617
|
signal.throwIfAborted();
|
|
16511
16618
|
if (++seen % 128 === 0)
|
|
16512
16619
|
await yieldToEventLoop(void 0, { signal });
|
|
16513
|
-
const kind =
|
|
16514
|
-
if (!kind
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
"token_usage_record",
|
|
16518
|
-
"compacted",
|
|
16519
|
-
"event_msg",
|
|
16520
|
-
"response_item"
|
|
16521
|
-
].includes(kind))
|
|
16620
|
+
const kind = rowKind(line);
|
|
16621
|
+
if (!kind && line.trim())
|
|
16622
|
+
options.onIncomplete?.();
|
|
16623
|
+
if (!kind || !ROW_KINDS.has(kind))
|
|
16522
16624
|
continue;
|
|
16523
16625
|
if (kind === "response_item" && !/"role"\s*:\s*"user"/u.test(line.slice(0, 1024)))
|
|
16524
16626
|
continue;
|
|
@@ -16528,19 +16630,24 @@ async function readCodexRollouts(files, thread, signal) {
|
|
|
16528
16630
|
try {
|
|
16529
16631
|
row = object2(JSON.parse(line));
|
|
16530
16632
|
} catch {
|
|
16633
|
+
options.onIncomplete?.();
|
|
16531
16634
|
continue;
|
|
16532
16635
|
}
|
|
16533
16636
|
const p = object2(row?.payload);
|
|
16534
16637
|
const at = nativeTimeMs(row?.timestamp);
|
|
16535
|
-
if (!row || !p || at === null)
|
|
16638
|
+
if (!row || !p || at === null) {
|
|
16639
|
+
options.onIncomplete?.();
|
|
16536
16640
|
continue;
|
|
16641
|
+
}
|
|
16537
16642
|
switch (row.type) {
|
|
16538
16643
|
case "session_meta": {
|
|
16539
16644
|
if (!firstMeta) {
|
|
16540
16645
|
if (text(p.id) !== thread)
|
|
16541
16646
|
throw new Error("Codex rollout identity does not match its source");
|
|
16542
|
-
if (p.forked_from_id || p.parent_thread_id || p.subagent_history_start_ordinal)
|
|
16647
|
+
if (p.forked_from_id || p.parent_thread_id || p.subagent_history_start_ordinal) {
|
|
16543
16648
|
forkAt = nativeTimeMs(p.timestamp) ?? at;
|
|
16649
|
+
options.onIncomplete?.();
|
|
16650
|
+
}
|
|
16544
16651
|
cwd = text(p.cwd);
|
|
16545
16652
|
firstMeta = true;
|
|
16546
16653
|
}
|
|
@@ -16554,30 +16661,41 @@ async function readCodexRollouts(files, thread, signal) {
|
|
|
16554
16661
|
counters.context("", text(p.turn_id), model2);
|
|
16555
16662
|
break;
|
|
16556
16663
|
case "token_usage_record":
|
|
16664
|
+
if (!usage(p.usage) || !text(p.response_id))
|
|
16665
|
+
options.onIncomplete?.();
|
|
16557
16666
|
counters.record(at, model2, p);
|
|
16558
16667
|
break;
|
|
16559
16668
|
case "compacted": {
|
|
16560
16669
|
const record2 = object2(p.latest_token_usage_record);
|
|
16561
|
-
if (record2 && p.compaction_response_id && record2.response_id === p.compaction_response_id)
|
|
16670
|
+
if (record2 && p.compaction_response_id && record2.response_id === p.compaction_response_id) {
|
|
16671
|
+
if (!usage(record2.usage))
|
|
16672
|
+
options.onIncomplete?.();
|
|
16562
16673
|
counters.record(at, model2, record2, true);
|
|
16674
|
+
}
|
|
16563
16675
|
break;
|
|
16564
16676
|
}
|
|
16565
16677
|
case "response_item":
|
|
16566
16678
|
counters.boundary();
|
|
16679
|
+
firstPrompt ??= userItemPrompt(p);
|
|
16567
16680
|
break;
|
|
16568
16681
|
case "event_msg":
|
|
16569
16682
|
if (p.type === "task_started") {
|
|
16570
16683
|
counters.context("", text(p.turn_id), "");
|
|
16571
16684
|
counters.boundary();
|
|
16572
16685
|
}
|
|
16573
|
-
if (p.type === "user_message")
|
|
16686
|
+
if (p.type === "user_message") {
|
|
16574
16687
|
counters.boundary();
|
|
16688
|
+
firstPrompt ??= typedPrompt(p.message);
|
|
16689
|
+
}
|
|
16575
16690
|
if (p.type === "thread_settings_applied") {
|
|
16576
16691
|
model2 = text(object2(p.thread_settings)?.model) || model2;
|
|
16577
16692
|
counters.context("", "", model2);
|
|
16578
16693
|
}
|
|
16579
16694
|
if (p.type === "token_count") {
|
|
16580
16695
|
const info = object2(p.info);
|
|
16696
|
+
options.onTokenCount?.(info);
|
|
16697
|
+
if (info && !usage(info.total_token_usage))
|
|
16698
|
+
options.onIncomplete?.();
|
|
16581
16699
|
if (info)
|
|
16582
16700
|
counters.count(at, model2, usage(info.total_token_usage), usage(info.last_token_usage));
|
|
16583
16701
|
}
|
|
@@ -16604,12 +16722,22 @@ async function readCodexRollouts(files, thread, signal) {
|
|
|
16604
16722
|
...v.usage.known & 8 ? { cacheWriteInputTokens: written } : {},
|
|
16605
16723
|
...v.usage.known & 16 ? { reasoningOutputTokens: reasoning } : {}
|
|
16606
16724
|
});
|
|
16607
|
-
return entry ? [withUsageSession(entry, { sessionId: thread, cwd })] : [];
|
|
16725
|
+
return entry ? [withUsageSession(entry, { sessionId: thread, cwd, title: firstPrompt })] : [];
|
|
16608
16726
|
});
|
|
16609
16727
|
}
|
|
16610
|
-
function createCodexUsageStatistics(environment) {
|
|
16728
|
+
function createCodexUsageStatistics(environment, options = {}) {
|
|
16611
16729
|
const home = path.resolve(environment.CODEX_HOME || path.join(environment.HOME || environment.USERPROFILE || os.homedir(), ".codex"));
|
|
16612
16730
|
const groups = /* @__PURE__ */ new Map();
|
|
16731
|
+
let names = /* @__PURE__ */ new Map();
|
|
16732
|
+
let namesStamp = "";
|
|
16733
|
+
async function threadNames(signal) {
|
|
16734
|
+
const current = await stamp(path.join(home, "session_index.jsonl")).catch(() => "-");
|
|
16735
|
+
if (namesStamp === current)
|
|
16736
|
+
return names;
|
|
16737
|
+
names = await readThreadNames(home, signal);
|
|
16738
|
+
namesStamp = current;
|
|
16739
|
+
return names;
|
|
16740
|
+
}
|
|
16613
16741
|
return {
|
|
16614
16742
|
async listSources(signal) {
|
|
16615
16743
|
const found = /* @__PURE__ */ new Map();
|
|
@@ -16628,7 +16756,7 @@ function createCodexUsageStatistics(environment) {
|
|
|
16628
16756
|
if (!entry.isFile())
|
|
16629
16757
|
continue;
|
|
16630
16758
|
const thread = ROLLOUT.exec(entry.name)?.[1];
|
|
16631
|
-
if (!thread)
|
|
16759
|
+
if (!thread || options.sessionId && thread !== options.sessionId)
|
|
16632
16760
|
continue;
|
|
16633
16761
|
const list = found.get(thread) ?? [];
|
|
16634
16762
|
list.push({ file: file2, fingerprint: await stamp(file2) });
|
|
@@ -16637,13 +16765,14 @@ function createCodexUsageStatistics(environment) {
|
|
|
16637
16765
|
}
|
|
16638
16766
|
await visit(path.join(home, "sessions"), 0);
|
|
16639
16767
|
await visit(path.join(home, "archived_sessions"), 0);
|
|
16768
|
+
const indexStamp = options.sessionId ? "" : await stamp(path.join(home, "session_index.jsonl")).catch(() => "-");
|
|
16640
16769
|
const result = [];
|
|
16641
16770
|
groups.clear();
|
|
16642
16771
|
for (const [thread, files] of found) {
|
|
16643
16772
|
files.sort((a, b) => path.basename(a.file).localeCompare(path.basename(b.file)) || a.file.localeCompare(b.file));
|
|
16644
16773
|
const id = path.join(home, `usage-thread-${thread}`);
|
|
16645
16774
|
groups.set(id, { thread, files });
|
|
16646
|
-
result.push({ id, fingerprint: fingerprint(files) });
|
|
16775
|
+
result.push({ id, fingerprint: fingerprint(files, indexStamp) });
|
|
16647
16776
|
}
|
|
16648
16777
|
return result;
|
|
16649
16778
|
},
|
|
@@ -16674,11 +16803,511 @@ function createCodexUsageStatistics(environment) {
|
|
|
16674
16803
|
if (!duplicate)
|
|
16675
16804
|
kept.push(candidate);
|
|
16676
16805
|
}
|
|
16677
|
-
const entries = await readCodexRollouts(kept.map(({ file: file2 }) => file2), group.thread, signal);
|
|
16806
|
+
const entries = await readCodexRollouts(kept.map(({ file: file2 }) => file2), group.thread, signal, options);
|
|
16678
16807
|
for (const file2 of group.files)
|
|
16679
16808
|
if (await stamp(file2.file) !== file2.fingerprint)
|
|
16680
16809
|
throw new Error("Codex rollout changed while reading; refresh to retry");
|
|
16681
|
-
|
|
16810
|
+
const named = options.sessionId ? void 0 : (await threadNames(signal)).get(group.thread);
|
|
16811
|
+
return named ? entries.map((entry) => withUsageSession(entry, {
|
|
16812
|
+
sessionId: entry.sessionId,
|
|
16813
|
+
cwd: entry.cwd,
|
|
16814
|
+
title: named
|
|
16815
|
+
})) : entries;
|
|
16816
|
+
}
|
|
16817
|
+
};
|
|
16818
|
+
}
|
|
16819
|
+
|
|
16820
|
+
// dist/session-usage.js
|
|
16821
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
16822
|
+
|
|
16823
|
+
// ../../harness-adapter/dist/usage.js
|
|
16824
|
+
var tokenFields = [
|
|
16825
|
+
"inputTokens",
|
|
16826
|
+
"cachedInputTokens",
|
|
16827
|
+
"cacheWriteInputTokens",
|
|
16828
|
+
"outputTokens",
|
|
16829
|
+
"reasoningOutputTokens",
|
|
16830
|
+
"totalTokens",
|
|
16831
|
+
"contextWindowTokens",
|
|
16832
|
+
"contextUsedTokens"
|
|
16833
|
+
];
|
|
16834
|
+
var safeIntegerFields = [
|
|
16835
|
+
"planFiveHourResetsAtUnix",
|
|
16836
|
+
"planSevenDayResetsAtUnix",
|
|
16837
|
+
"timeToFirstOutputMs"
|
|
16838
|
+
];
|
|
16839
|
+
var percentFields = [
|
|
16840
|
+
"cacheHitRatePercent",
|
|
16841
|
+
"sessionCacheHitRatePercent",
|
|
16842
|
+
"planFiveHourUsedPercent",
|
|
16843
|
+
"planSevenDayUsedPercent"
|
|
16844
|
+
];
|
|
16845
|
+
var usageFields = /* @__PURE__ */ new Set([
|
|
16846
|
+
...tokenFields,
|
|
16847
|
+
...safeIntegerFields,
|
|
16848
|
+
...percentFields,
|
|
16849
|
+
"sessionCacheUsage",
|
|
16850
|
+
"totalCostUsd",
|
|
16851
|
+
"totalCredits",
|
|
16852
|
+
"contextUsagePercent",
|
|
16853
|
+
"outputTokensPerSecond",
|
|
16854
|
+
"apiOutputTokensPerSecond",
|
|
16855
|
+
"costSource",
|
|
16856
|
+
"unpricedModels"
|
|
16857
|
+
]);
|
|
16858
|
+
function isRecord(value) {
|
|
16859
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16860
|
+
}
|
|
16861
|
+
function parseHostUsage(value) {
|
|
16862
|
+
if (!isRecord(value))
|
|
16863
|
+
throw new Error("Harness Usage must be an object");
|
|
16864
|
+
const keys = Object.keys(value);
|
|
16865
|
+
if (keys.length === 0)
|
|
16866
|
+
throw new Error("Harness Usage must contain a reliable field");
|
|
16867
|
+
for (const key2 of keys) {
|
|
16868
|
+
if (!usageFields.has(key2)) {
|
|
16869
|
+
throw new Error(`Harness Usage contains unknown field '${key2}'`);
|
|
16870
|
+
}
|
|
16871
|
+
}
|
|
16872
|
+
for (const field of [
|
|
16873
|
+
"totalCredits",
|
|
16874
|
+
"contextUsagePercent",
|
|
16875
|
+
"apiOutputTokensPerSecond"
|
|
16876
|
+
]) {
|
|
16877
|
+
const candidate = value[field];
|
|
16878
|
+
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
|
|
16879
|
+
throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
|
|
16880
|
+
}
|
|
16881
|
+
}
|
|
16882
|
+
for (const field of tokenFields) {
|
|
16883
|
+
const candidate = value[field];
|
|
16884
|
+
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
|
|
16885
|
+
throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
|
|
16886
|
+
}
|
|
16887
|
+
}
|
|
16888
|
+
for (const field of safeIntegerFields) {
|
|
16889
|
+
const candidate = value[field];
|
|
16890
|
+
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
|
|
16891
|
+
throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
|
|
16892
|
+
}
|
|
16893
|
+
}
|
|
16894
|
+
if (value.outputTokensPerSecond !== void 0 && (typeof value.outputTokensPerSecond !== "number" || !Number.isFinite(value.outputTokensPerSecond) || value.outputTokensPerSecond < 0)) {
|
|
16895
|
+
throw new Error("Harness Usage 'outputTokensPerSecond' must be a finite non-negative number");
|
|
16896
|
+
}
|
|
16897
|
+
if (value.totalCostUsd !== void 0 && (typeof value.totalCostUsd !== "number" || !Number.isFinite(value.totalCostUsd) || value.totalCostUsd < 0)) {
|
|
16898
|
+
throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
|
|
16899
|
+
}
|
|
16900
|
+
for (const field of percentFields) {
|
|
16901
|
+
const candidate = value[field];
|
|
16902
|
+
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
|
|
16903
|
+
throw new Error(`Harness Usage '${field}' must be between 0 and 100`);
|
|
16904
|
+
}
|
|
16905
|
+
}
|
|
16906
|
+
if (value.sessionCacheUsage !== void 0) {
|
|
16907
|
+
const totals2 = value.sessionCacheUsage;
|
|
16908
|
+
if (!isRecord(totals2) || Object.keys(totals2).some((key2) => key2 !== "inputTokens" && key2 !== "cachedInputTokens") || typeof totals2.inputTokens !== "number" || !Number.isSafeInteger(totals2.inputTokens) || totals2.inputTokens < 0 || typeof totals2.cachedInputTokens !== "number" || !Number.isSafeInteger(totals2.cachedInputTokens) || totals2.cachedInputTokens < 0 || totals2.cachedInputTokens > totals2.inputTokens) {
|
|
16909
|
+
throw new Error("Harness Usage 'sessionCacheUsage' must contain complete bounded token totals");
|
|
16910
|
+
}
|
|
16911
|
+
}
|
|
16912
|
+
const hasContextUsed = value.contextUsedTokens !== void 0;
|
|
16913
|
+
const hasContextWindow = value.contextWindowTokens !== void 0;
|
|
16914
|
+
if (hasContextUsed !== hasContextWindow) {
|
|
16915
|
+
throw new Error("Harness Usage context fields must be provided together");
|
|
16916
|
+
}
|
|
16917
|
+
if (hasContextWindow && value.contextWindowTokens === 0) {
|
|
16918
|
+
throw new Error("Harness Usage 'contextWindowTokens' must be greater than zero");
|
|
16919
|
+
}
|
|
16920
|
+
if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
|
|
16921
|
+
throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
|
|
16922
|
+
}
|
|
16923
|
+
if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
|
|
16924
|
+
throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
|
|
16925
|
+
}
|
|
16926
|
+
if (value.costSource !== void 0) {
|
|
16927
|
+
if (value.costSource !== "publicPrice" && value.costSource !== "native") {
|
|
16928
|
+
throw new Error("Harness Usage 'costSource' must be 'publicPrice' or 'native'");
|
|
16929
|
+
}
|
|
16930
|
+
if (value.totalCostUsd === void 0) {
|
|
16931
|
+
throw new Error("Harness Usage 'costSource' must be provided with 'totalCostUsd'");
|
|
16932
|
+
}
|
|
16933
|
+
}
|
|
16934
|
+
if (value.unpricedModels !== void 0) {
|
|
16935
|
+
const models = value.unpricedModels;
|
|
16936
|
+
if (!Array.isArray(models) || models.length === 0 || !models.every((model2) => typeof model2 === "string" && model2.length > 0)) {
|
|
16937
|
+
throw new Error("Harness Usage 'unpricedModels' must be a non-empty list of Model IDs");
|
|
16938
|
+
}
|
|
16939
|
+
if (value.costSource !== "publicPrice") {
|
|
16940
|
+
throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
|
|
16941
|
+
}
|
|
16942
|
+
return { ...value, unpricedModels: [...models] };
|
|
16943
|
+
}
|
|
16944
|
+
return { ...value };
|
|
16945
|
+
}
|
|
16946
|
+
var requestTokenFields = [
|
|
16947
|
+
"inputTokens",
|
|
16948
|
+
"cachedInputTokens",
|
|
16949
|
+
"cacheWriteInputTokens",
|
|
16950
|
+
"cacheWrite1hInputTokens",
|
|
16951
|
+
"outputTokens",
|
|
16952
|
+
"reasoningOutputTokens",
|
|
16953
|
+
"startedAtMs",
|
|
16954
|
+
"completedAtMs"
|
|
16955
|
+
];
|
|
16956
|
+
var requestFields = /* @__PURE__ */ new Set([
|
|
16957
|
+
...requestTokenFields,
|
|
16958
|
+
"requestId",
|
|
16959
|
+
"historical",
|
|
16960
|
+
"model",
|
|
16961
|
+
"provider"
|
|
16962
|
+
]);
|
|
16963
|
+
function parseHostUsageRequest(value) {
|
|
16964
|
+
if (!isRecord(value))
|
|
16965
|
+
throw new Error("Harness Usage request must be an object");
|
|
16966
|
+
for (const key2 of Object.keys(value)) {
|
|
16967
|
+
if (!requestFields.has(key2)) {
|
|
16968
|
+
throw new Error(`Harness Usage request contains unknown field '${key2}'`);
|
|
16969
|
+
}
|
|
16970
|
+
}
|
|
16971
|
+
if (typeof value.requestId !== "string" || value.requestId.length === 0) {
|
|
16972
|
+
throw new Error("Harness Usage request 'requestId' must be a non-empty string");
|
|
16973
|
+
}
|
|
16974
|
+
for (const field of ["model", "provider"]) {
|
|
16975
|
+
const candidate = value[field];
|
|
16976
|
+
if (candidate !== void 0 && (typeof candidate !== "string" || candidate.length === 0)) {
|
|
16977
|
+
throw new Error(`Harness Usage request '${field}' must be a non-empty string`);
|
|
16978
|
+
}
|
|
16979
|
+
}
|
|
16980
|
+
if (value.historical !== void 0 && typeof value.historical !== "boolean") {
|
|
16981
|
+
throw new Error("Harness Usage request 'historical' must be a boolean");
|
|
16982
|
+
}
|
|
16983
|
+
for (const field of requestTokenFields) {
|
|
16984
|
+
const candidate = value[field];
|
|
16985
|
+
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
|
|
16986
|
+
throw new Error(`Harness Usage request '${field}' must be a non-negative safe integer`);
|
|
16987
|
+
}
|
|
16988
|
+
}
|
|
16989
|
+
if (value.inputTokens === void 0 || value.outputTokens === void 0) {
|
|
16990
|
+
throw new Error("Harness Usage request must contain 'inputTokens' and 'outputTokens'");
|
|
16991
|
+
}
|
|
16992
|
+
const request = value;
|
|
16993
|
+
if ((request.cachedInputTokens ?? 0) + (request.cacheWriteInputTokens ?? 0) > request.inputTokens) {
|
|
16994
|
+
throw new Error("Harness Usage request cache Tokens must not exceed 'inputTokens'");
|
|
16995
|
+
}
|
|
16996
|
+
if ((request.reasoningOutputTokens ?? 0) > request.outputTokens) {
|
|
16997
|
+
throw new Error("Harness Usage request 'reasoningOutputTokens' must not exceed 'outputTokens'");
|
|
16998
|
+
}
|
|
16999
|
+
if (request.cacheWrite1hInputTokens !== void 0 && request.cacheWrite1hInputTokens > (request.cacheWriteInputTokens ?? -1)) {
|
|
17000
|
+
throw new Error("Harness Usage request 'cacheWrite1hInputTokens' must not exceed 'cacheWriteInputTokens'");
|
|
17001
|
+
}
|
|
17002
|
+
if (request.startedAtMs === void 0 !== (request.completedAtMs === void 0)) {
|
|
17003
|
+
throw new Error("Harness Usage request timing fields must be provided together");
|
|
17004
|
+
}
|
|
17005
|
+
if (request.startedAtMs !== void 0 && request.completedAtMs !== void 0 && request.completedAtMs < request.startedAtMs) {
|
|
17006
|
+
throw new Error("Harness Usage request 'completedAtMs' must not precede 'startedAtMs'");
|
|
17007
|
+
}
|
|
17008
|
+
return { ...request };
|
|
17009
|
+
}
|
|
17010
|
+
|
|
17011
|
+
// dist/session-observation.js
|
|
17012
|
+
var integer2 = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
17013
|
+
function tokenSnapshot(value) {
|
|
17014
|
+
const token = object2(value);
|
|
17015
|
+
if (!token)
|
|
17016
|
+
return null;
|
|
17017
|
+
const total = object2(token.total);
|
|
17018
|
+
const last = object2(token.last);
|
|
17019
|
+
const result = {};
|
|
17020
|
+
for (const field of [
|
|
17021
|
+
"totalTokens",
|
|
17022
|
+
"inputTokens",
|
|
17023
|
+
"cachedInputTokens",
|
|
17024
|
+
"cacheWriteInputTokens",
|
|
17025
|
+
"outputTokens",
|
|
17026
|
+
"reasoningOutputTokens"
|
|
17027
|
+
]) {
|
|
17028
|
+
const n = integer2(total?.[field]);
|
|
17029
|
+
if (n !== void 0)
|
|
17030
|
+
result[field] = n;
|
|
17031
|
+
}
|
|
17032
|
+
const used = integer2(last?.totalTokens);
|
|
17033
|
+
const window = integer2(token.modelContextWindow);
|
|
17034
|
+
if (used !== void 0 && window !== void 0 && window > 0) {
|
|
17035
|
+
result.contextUsedTokens = used;
|
|
17036
|
+
result.contextWindowTokens = window;
|
|
17037
|
+
}
|
|
17038
|
+
const input = integer2(last?.inputTokens);
|
|
17039
|
+
const cached2 = integer2(last?.cachedInputTokens);
|
|
17040
|
+
if (input && cached2 !== void 0 && cached2 <= input)
|
|
17041
|
+
result.cacheHitRatePercent = cached2 / input * 100;
|
|
17042
|
+
if (result.inputTokens && result.cachedInputTokens !== void 0) {
|
|
17043
|
+
result.sessionCacheUsage = {
|
|
17044
|
+
inputTokens: result.inputTokens,
|
|
17045
|
+
cachedInputTokens: result.cachedInputTokens
|
|
17046
|
+
};
|
|
17047
|
+
}
|
|
17048
|
+
try {
|
|
17049
|
+
return Object.keys(result).length ? parseHostUsage(result) : null;
|
|
17050
|
+
} catch {
|
|
17051
|
+
return null;
|
|
17052
|
+
}
|
|
17053
|
+
}
|
|
17054
|
+
function observeSessionUsage(message) {
|
|
17055
|
+
const frame = object2(message);
|
|
17056
|
+
const params = object2(frame?.params);
|
|
17057
|
+
if (!params || typeof params.threadId !== "string" || !params.threadId)
|
|
17058
|
+
return null;
|
|
17059
|
+
const sessionId = params.threadId;
|
|
17060
|
+
if (frame?.method === "thread/tokenUsage/updated") {
|
|
17061
|
+
const usage2 = tokenSnapshot(params.tokenUsage);
|
|
17062
|
+
return usage2 ? { sessionId, usage: usage2 } : null;
|
|
17063
|
+
}
|
|
17064
|
+
if (frame?.method === "turn/started" || frame?.method === "turn/completed") {
|
|
17065
|
+
const turn = object2(params.turn);
|
|
17066
|
+
return typeof turn?.id === "string" && turn.id ? {
|
|
17067
|
+
sessionId,
|
|
17068
|
+
turn: { id: turn.id, phase: frame.method === "turn/started" ? "started" : "completed" }
|
|
17069
|
+
} : null;
|
|
17070
|
+
}
|
|
17071
|
+
if (typeof params.turnId !== "string" || !params.turnId)
|
|
17072
|
+
return null;
|
|
17073
|
+
if ([
|
|
17074
|
+
"item/agentMessage/delta",
|
|
17075
|
+
"item/reasoning/textDelta",
|
|
17076
|
+
"item/reasoning/summaryTextDelta"
|
|
17077
|
+
].includes(String(frame?.method)) && typeof params.delta === "string" && params.delta.length > 0) {
|
|
17078
|
+
return { sessionId, turn: { id: params.turnId, phase: "output" } };
|
|
17079
|
+
}
|
|
17080
|
+
return null;
|
|
17081
|
+
}
|
|
17082
|
+
function rolloutTokenSnapshot(info) {
|
|
17083
|
+
const record2 = object2(info);
|
|
17084
|
+
if (!record2)
|
|
17085
|
+
return null;
|
|
17086
|
+
const convert = (value) => {
|
|
17087
|
+
const u = object2(value);
|
|
17088
|
+
return u && {
|
|
17089
|
+
totalTokens: u.total_tokens,
|
|
17090
|
+
inputTokens: u.input_tokens,
|
|
17091
|
+
cachedInputTokens: u.cached_input_tokens,
|
|
17092
|
+
cacheWriteInputTokens: u.cache_write_input_tokens,
|
|
17093
|
+
outputTokens: u.output_tokens,
|
|
17094
|
+
reasoningOutputTokens: u.reasoning_output_tokens
|
|
17095
|
+
};
|
|
17096
|
+
};
|
|
17097
|
+
return tokenSnapshot({
|
|
17098
|
+
total: convert(record2.total_token_usage),
|
|
17099
|
+
last: convert(record2.last_token_usage),
|
|
17100
|
+
modelContextWindow: record2.model_context_window
|
|
17101
|
+
});
|
|
17102
|
+
}
|
|
17103
|
+
|
|
17104
|
+
// dist/response-timing.js
|
|
17105
|
+
var nonNegativeInteger = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
17106
|
+
var CodexResponseTiming = class {
|
|
17107
|
+
#turns = /* @__PURE__ */ new Map();
|
|
17108
|
+
reset() {
|
|
17109
|
+
this.#turns.clear();
|
|
17110
|
+
}
|
|
17111
|
+
observe(message, now) {
|
|
17112
|
+
const frame = object2(message);
|
|
17113
|
+
const params = object2(frame?.params);
|
|
17114
|
+
if (!params || typeof params.threadId !== "string")
|
|
17115
|
+
return null;
|
|
17116
|
+
const sessionId = params.threadId;
|
|
17117
|
+
const turn = object2(params.turn);
|
|
17118
|
+
if (frame?.method === "turn/started" && typeof turn?.id === "string") {
|
|
17119
|
+
if (this.#turns.get(sessionId)?.id !== turn.id) {
|
|
17120
|
+
this.#turns.set(sessionId, {
|
|
17121
|
+
id: turn.id,
|
|
17122
|
+
pending: false,
|
|
17123
|
+
unavailable: false,
|
|
17124
|
+
seen: /* @__PURE__ */ new Set()
|
|
17125
|
+
});
|
|
17126
|
+
}
|
|
17127
|
+
return null;
|
|
17128
|
+
}
|
|
17129
|
+
const state = this.#turns.get(sessionId);
|
|
17130
|
+
if (!state)
|
|
17131
|
+
return null;
|
|
17132
|
+
const unavailable = () => {
|
|
17133
|
+
state.unavailable = true;
|
|
17134
|
+
return { sessionId, timingUnavailable: { turnId: state.id } };
|
|
17135
|
+
};
|
|
17136
|
+
if (frame?.method === "thread/closed") {
|
|
17137
|
+
this.#turns.delete(sessionId);
|
|
17138
|
+
return unavailable();
|
|
17139
|
+
}
|
|
17140
|
+
if (frame?.method === "turn/completed" && turn?.id === state.id) {
|
|
17141
|
+
this.#turns.delete(sessionId);
|
|
17142
|
+
return state.pending || state.unavailable ? unavailable() : null;
|
|
17143
|
+
}
|
|
17144
|
+
if (params.turnId !== state.id)
|
|
17145
|
+
return null;
|
|
17146
|
+
if (frame?.method === "error")
|
|
17147
|
+
return unavailable();
|
|
17148
|
+
if (frame?.method === "rawResponse/completed") {
|
|
17149
|
+
const id = params.responseId;
|
|
17150
|
+
if (typeof id !== "string" || !id)
|
|
17151
|
+
return unavailable();
|
|
17152
|
+
if (state.seen.has(id))
|
|
17153
|
+
return null;
|
|
17154
|
+
state.seen.add(id);
|
|
17155
|
+
const usage2 = object2(params.usage);
|
|
17156
|
+
const startedAtMs = state.firstOutputAtMs;
|
|
17157
|
+
state.firstOutputAtMs = void 0;
|
|
17158
|
+
state.pending = false;
|
|
17159
|
+
if (state.unavailable || startedAtMs === void 0 || !nonNegativeInteger(now) || now <= startedAtMs || !nonNegativeInteger(usage2?.outputTokens) || usage2.reasoningOutputTokens != null && (!nonNegativeInteger(usage2.reasoningOutputTokens) || usage2.reasoningOutputTokens > usage2.outputTokens)) {
|
|
17160
|
+
return unavailable();
|
|
17161
|
+
}
|
|
17162
|
+
return {
|
|
17163
|
+
sessionId,
|
|
17164
|
+
requestTiming: {
|
|
17165
|
+
requestId: id,
|
|
17166
|
+
turnId: state.id,
|
|
17167
|
+
outputTokens: usage2.outputTokens,
|
|
17168
|
+
startedAtMs,
|
|
17169
|
+
completedAtMs: now
|
|
17170
|
+
}
|
|
17171
|
+
};
|
|
17172
|
+
}
|
|
17173
|
+
if (frame?.method === "rawResponseItem/completed") {
|
|
17174
|
+
const item = object2(params.item);
|
|
17175
|
+
if (item?.type === "message" && item.role === "assistant" || [
|
|
17176
|
+
"reasoning",
|
|
17177
|
+
"function_call",
|
|
17178
|
+
"custom_tool_call",
|
|
17179
|
+
"local_shell_call",
|
|
17180
|
+
"web_search_call",
|
|
17181
|
+
"image_generation_call",
|
|
17182
|
+
"tool_search_call"
|
|
17183
|
+
].includes(String(item?.type)))
|
|
17184
|
+
state.pending = true;
|
|
17185
|
+
return null;
|
|
17186
|
+
}
|
|
17187
|
+
if (frame?.method === "item/started") {
|
|
17188
|
+
const item = object2(params.item);
|
|
17189
|
+
if (item?.type === "agentMessage" || item?.type === "reasoning" || item?.type === "plan") {
|
|
17190
|
+
state.pending = true;
|
|
17191
|
+
state.firstOutputAtMs ??= now;
|
|
17192
|
+
}
|
|
17193
|
+
return null;
|
|
17194
|
+
}
|
|
17195
|
+
const reasoning = frame?.method === "item/reasoning/textDelta" || frame?.method === "item/reasoning/summaryTextDelta";
|
|
17196
|
+
if ((reasoning || frame?.method === "item/agentMessage/delta" || frame?.method === "item/plan/delta") && typeof params.delta === "string" && params.delta.length > 0) {
|
|
17197
|
+
state.pending = true;
|
|
17198
|
+
state.firstOutputAtMs ??= now;
|
|
17199
|
+
}
|
|
17200
|
+
return null;
|
|
17201
|
+
}
|
|
17202
|
+
};
|
|
17203
|
+
|
|
17204
|
+
// dist/session-usage.js
|
|
17205
|
+
function createCodexSessionUsage(environment, closed) {
|
|
17206
|
+
const timing = new CodexResponseTiming();
|
|
17207
|
+
const rawCompleted = "rawResponse/completed";
|
|
17208
|
+
let hideRawCompleted = false;
|
|
17209
|
+
const live = /* @__PURE__ */ new Map();
|
|
17210
|
+
const cache = /* @__PURE__ */ new Map();
|
|
17211
|
+
return {
|
|
17212
|
+
requestOptions({ method, params, initializeParams }) {
|
|
17213
|
+
if (closed.aborted)
|
|
17214
|
+
return null;
|
|
17215
|
+
if (method === "initialize") {
|
|
17216
|
+
const capabilities2 = object2(params.capabilities);
|
|
17217
|
+
const excluded2 = capabilities2?.optOutNotificationMethods;
|
|
17218
|
+
hideRawCompleted = false;
|
|
17219
|
+
if (capabilities2?.experimentalApi !== true || !Array.isArray(excluded2))
|
|
17220
|
+
return null;
|
|
17221
|
+
if (!excluded2.includes(rawCompleted))
|
|
17222
|
+
return null;
|
|
17223
|
+
hideRawCompleted = true;
|
|
17224
|
+
return {
|
|
17225
|
+
capabilities: {
|
|
17226
|
+
...capabilities2,
|
|
17227
|
+
optOutNotificationMethods: excluded2.filter((method2) => method2 !== rawCompleted)
|
|
17228
|
+
}
|
|
17229
|
+
};
|
|
17230
|
+
}
|
|
17231
|
+
const capabilities = object2(initializeParams?.capabilities);
|
|
17232
|
+
const excluded = capabilities?.optOutNotificationMethods;
|
|
17233
|
+
return method === "thread/start" && capabilities?.experimentalApi === true && !(Array.isArray(excluded) && excluded.includes(rawCompleted)) && (params.experimentalRawEvents === void 0 || params.experimentalRawEvents === false) ? { experimentalRawEvents: true } : null;
|
|
17234
|
+
},
|
|
17235
|
+
shouldForwardNotification(message) {
|
|
17236
|
+
return closed.aborted || !hideRawCompleted || object2(message)?.method !== rawCompleted;
|
|
17237
|
+
},
|
|
17238
|
+
reset() {
|
|
17239
|
+
timing.reset();
|
|
17240
|
+
},
|
|
17241
|
+
observe(message, observedAtMs = Date.now()) {
|
|
17242
|
+
if (closed.aborted)
|
|
17243
|
+
return null;
|
|
17244
|
+
const observation = observeSessionUsage(message);
|
|
17245
|
+
const measured = timing.observe(message, observedAtMs);
|
|
17246
|
+
if (observation?.usage)
|
|
17247
|
+
live.set(observation.sessionId, observation.usage);
|
|
17248
|
+
return measured ? { ...observation, ...measured } : observation;
|
|
17249
|
+
},
|
|
17250
|
+
async read(sessionId, signal) {
|
|
17251
|
+
signal = AbortSignal.any([signal, closed]);
|
|
17252
|
+
signal.throwIfAborted();
|
|
17253
|
+
for (let attempt = 0; ; attempt++) {
|
|
17254
|
+
let snapshot = null;
|
|
17255
|
+
let complete = true;
|
|
17256
|
+
const reader = createCodexUsageStatistics(environment, {
|
|
17257
|
+
sessionId,
|
|
17258
|
+
onTokenCount: (info) => {
|
|
17259
|
+
snapshot = rolloutTokenSnapshot(info) ?? snapshot;
|
|
17260
|
+
},
|
|
17261
|
+
onIncomplete: () => {
|
|
17262
|
+
complete = false;
|
|
17263
|
+
}
|
|
17264
|
+
});
|
|
17265
|
+
const sources = await reader.listSources(signal);
|
|
17266
|
+
const source = sources[0];
|
|
17267
|
+
if (!source)
|
|
17268
|
+
return null;
|
|
17269
|
+
let history = cache.get(sessionId);
|
|
17270
|
+
if (history?.fingerprint !== source.fingerprint) {
|
|
17271
|
+
const entries = await reader.readSource(source.id, signal);
|
|
17272
|
+
const requests = entries.map((entry) => parseHostUsageRequest({
|
|
17273
|
+
requestId: entry.id,
|
|
17274
|
+
historical: true,
|
|
17275
|
+
...entry.model ? { model: entry.model } : {},
|
|
17276
|
+
inputTokens: entry.inputTokens,
|
|
17277
|
+
outputTokens: entry.outputTokens,
|
|
17278
|
+
...entry.cachedInputTokens !== void 0 ? { cachedInputTokens: entry.cachedInputTokens } : {},
|
|
17279
|
+
// Codex/OpenAI cache has no separately billed cache creation bucket.
|
|
17280
|
+
cacheWriteInputTokens: entry.cacheWriteInputTokens ?? 0,
|
|
17281
|
+
...entry.reasoningOutputTokens !== void 0 ? { reasoningOutputTokens: entry.reasoningOutputTokens } : {}
|
|
17282
|
+
}));
|
|
17283
|
+
const inputTokens = requests.reduce((sum, r) => sum + r.inputTokens, 0);
|
|
17284
|
+
const outputTokens = requests.reduce((sum, r) => sum + r.outputTokens, 0);
|
|
17285
|
+
const cachedInputTokens = requests.every((r) => r.cachedInputTokens !== void 0) ? requests.reduce((sum, r) => sum + (r.cachedInputTokens ?? 0), 0) : void 0;
|
|
17286
|
+
const last = requests.at(-1);
|
|
17287
|
+
const usage2 = requests.length ? parseHostUsage({
|
|
17288
|
+
...snapshot ?? {},
|
|
17289
|
+
inputTokens,
|
|
17290
|
+
outputTokens,
|
|
17291
|
+
totalTokens: inputTokens + outputTokens,
|
|
17292
|
+
...cachedInputTokens !== void 0 ? { cachedInputTokens } : {},
|
|
17293
|
+
...complete && cachedInputTokens !== void 0 ? { sessionCacheUsage: { inputTokens, cachedInputTokens } } : {},
|
|
17294
|
+
...last?.inputTokens && last.cachedInputTokens !== void 0 ? { cacheHitRatePercent: last.cachedInputTokens / last.inputTokens * 100 } : {}
|
|
17295
|
+
}) : snapshot;
|
|
17296
|
+
history = {
|
|
17297
|
+
fingerprint: source.fingerprint,
|
|
17298
|
+
history: { usage: usage2, requests, complete: complete && requests.length > 0 }
|
|
17299
|
+
};
|
|
17300
|
+
cache.set(sessionId, history);
|
|
17301
|
+
}
|
|
17302
|
+
const result = history.history;
|
|
17303
|
+
const latest = live.get(sessionId);
|
|
17304
|
+
const caughtUp = !latest || (latest.inputTokens ?? 0) <= (result.usage?.inputTokens ?? 0) && (latest.outputTokens ?? 0) <= (result.usage?.outputTokens ?? 0);
|
|
17305
|
+
if (!caughtUp && attempt < 2) {
|
|
17306
|
+
await delay(50 * (attempt + 1), void 0, { signal });
|
|
17307
|
+
continue;
|
|
17308
|
+
}
|
|
17309
|
+
return { ...result, complete: result.complete && caughtUp };
|
|
17310
|
+
}
|
|
16682
17311
|
}
|
|
16683
17312
|
};
|
|
16684
17313
|
}
|
|
@@ -16689,6 +17318,7 @@ function createUsageStatisticsAdapter(context) {
|
|
|
16689
17318
|
const reader = createCodexUsageStatistics(context.environment);
|
|
16690
17319
|
return {
|
|
16691
17320
|
harnessId: harnessIdSchema.parse("codex-usage"),
|
|
17321
|
+
sessionUsage: createCodexSessionUsage(context.environment, abort.signal),
|
|
16692
17322
|
usageStatistics: {
|
|
16693
17323
|
listSources: (signal) => reader.listSources(AbortSignal.any([signal, abort.signal])),
|
|
16694
17324
|
readSource: (id, signal) => reader.readSource(id, AbortSignal.any([signal, abort.signal]))
|