oasis_test_v2 2.2.53 → 2.2.54
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/index.js +425 -109
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3799,6 +3799,64 @@ function accumulateClaudeUsage(acc, p2) {
|
|
|
3799
3799
|
if (acc.finalUsage || acc.costUsd != null) acc.saw = true;
|
|
3800
3800
|
}
|
|
3801
3801
|
}
|
|
3802
|
+
function newClaudeRunningUsage() {
|
|
3803
|
+
return { byMessage: /* @__PURE__ */ new Map(), currentMessageId: null, lastKey: "" };
|
|
3804
|
+
}
|
|
3805
|
+
function mergeMessageMax(acc, messageId, snapshot) {
|
|
3806
|
+
if (!snapshot) return;
|
|
3807
|
+
const prev = acc.byMessage.get(messageId) ?? { input: 0, output: 0, cacheRead: 0, cacheCreation: 0 };
|
|
3808
|
+
acc.byMessage.set(messageId, {
|
|
3809
|
+
input: Math.max(prev.input, snapshot.input ?? 0),
|
|
3810
|
+
output: Math.max(prev.output, snapshot.output ?? 0),
|
|
3811
|
+
cacheRead: Math.max(prev.cacheRead, snapshot.cacheRead ?? 0),
|
|
3812
|
+
cacheCreation: Math.max(prev.cacheCreation, snapshot.cacheCreation ?? 0)
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
function observeClaudeRunningUsage(acc, p2) {
|
|
3816
|
+
if (stringOf(p2["parent_tool_use_id"])) return void 0;
|
|
3817
|
+
if (p2["type"] === "assistant") {
|
|
3818
|
+
const msg = objectOf(p2["message"]);
|
|
3819
|
+
const id = stringOf(msg?.id);
|
|
3820
|
+
if (!id) return void 0;
|
|
3821
|
+
mergeMessageMax(acc, id, parseResultUsage(msg?.usage));
|
|
3822
|
+
const model = stringOf(msg?.model);
|
|
3823
|
+
if (model) acc.model = model;
|
|
3824
|
+
} else if (p2["type"] === "stream_event") {
|
|
3825
|
+
const event = objectOf(p2["event"]);
|
|
3826
|
+
if (event?.type === "message_start") {
|
|
3827
|
+
const msg = objectOf(event.message);
|
|
3828
|
+
const id = stringOf(msg?.id);
|
|
3829
|
+
if (!id) return void 0;
|
|
3830
|
+
acc.currentMessageId = id;
|
|
3831
|
+
mergeMessageMax(acc, id, parseResultUsage(msg?.usage));
|
|
3832
|
+
} else if (event?.type === "message_delta" && acc.currentMessageId) {
|
|
3833
|
+
mergeMessageMax(acc, acc.currentMessageId, parseResultUsage(event.usage));
|
|
3834
|
+
} else {
|
|
3835
|
+
return void 0;
|
|
3836
|
+
}
|
|
3837
|
+
} else {
|
|
3838
|
+
return void 0;
|
|
3839
|
+
}
|
|
3840
|
+
if (acc.byMessage.size === 0) return void 0;
|
|
3841
|
+
let input = 0, output = 0, cacheRead = 0, cacheCreation = 0;
|
|
3842
|
+
for (const b2 of acc.byMessage.values()) {
|
|
3843
|
+
input += b2.input;
|
|
3844
|
+
output += b2.output;
|
|
3845
|
+
cacheRead += b2.cacheRead;
|
|
3846
|
+
cacheCreation += b2.cacheCreation;
|
|
3847
|
+
}
|
|
3848
|
+
const key2 = `${input}/${output}/${cacheRead}/${cacheCreation}`;
|
|
3849
|
+
if (key2 === acc.lastKey || input + output + cacheRead + cacheCreation === 0) return void 0;
|
|
3850
|
+
acc.lastKey = key2;
|
|
3851
|
+
return {
|
|
3852
|
+
inputTokens: input,
|
|
3853
|
+
outputTokens: output,
|
|
3854
|
+
totalTokens: input + output,
|
|
3855
|
+
cacheReadTokens: cacheRead,
|
|
3856
|
+
cacheCreationTokens: cacheCreation,
|
|
3857
|
+
costUsdMicros: null
|
|
3858
|
+
};
|
|
3859
|
+
}
|
|
3802
3860
|
function buildClaudeUsage(acc) {
|
|
3803
3861
|
if (!acc.saw) return void 0;
|
|
3804
3862
|
const input = acc.finalUsage?.input ?? acc.input;
|
|
@@ -4117,6 +4175,8 @@ var init_claude_code = __esm({
|
|
|
4117
4175
|
const STDERR_MAX_LINES = 40;
|
|
4118
4176
|
const STDERR_MAX_BYTES = 4e3;
|
|
4119
4177
|
const usageAcc = newClaudeUsageAcc();
|
|
4178
|
+
const runningUsage = newClaudeRunningUsage();
|
|
4179
|
+
const usageCheckpointCbs = [];
|
|
4120
4180
|
let sessionModel;
|
|
4121
4181
|
const outputCbs = [];
|
|
4122
4182
|
const liveParser = createClaudeLiveParserState(`claude-live:${id}`, { readSubagentCalls: readSubagentTranscriptCalls });
|
|
@@ -4149,6 +4209,11 @@ var init_claude_code = __esm({
|
|
|
4149
4209
|
maybeCloseInputOnResult();
|
|
4150
4210
|
}
|
|
4151
4211
|
accumulateClaudeUsage(usageAcc, p2);
|
|
4212
|
+
const running = observeClaudeRunningUsage(runningUsage, p2);
|
|
4213
|
+
if (running) {
|
|
4214
|
+
const model = runningUsage.model ?? sessionModel;
|
|
4215
|
+
for (const cb of usageCheckpointCbs) cb({ usage: running, ...model ? { model } : {} });
|
|
4216
|
+
}
|
|
4152
4217
|
if (!sessionModel) {
|
|
4153
4218
|
if (p2["type"] === "system" && typeof p2["model"] === "string" && p2["model"]) sessionModel = p2["model"];
|
|
4154
4219
|
else if (p2["type"] === "assistant") {
|
|
@@ -4300,6 +4365,9 @@ var init_claude_code = __esm({
|
|
|
4300
4365
|
onLiveEvent(cb) {
|
|
4301
4366
|
liveEventCbs.push(cb);
|
|
4302
4367
|
},
|
|
4368
|
+
onUsageCheckpoint(cb) {
|
|
4369
|
+
usageCheckpointCbs.push(cb);
|
|
4370
|
+
},
|
|
4303
4371
|
// ADR-0093 对话追加:把这条 user 输入作为一条 stream-json 消息续写进 stdin(同会话下一回合)。
|
|
4304
4372
|
// 非 appendMode → unsupported;已退出/已在关 stdin → session-closing。
|
|
4305
4373
|
get canAppendInput() {
|
|
@@ -4384,6 +4452,7 @@ function withResilience(inner, cfg = {}) {
|
|
|
4384
4452
|
const telemetryCbs = [];
|
|
4385
4453
|
const liveEventCbs = [];
|
|
4386
4454
|
const normalizedCbs = [];
|
|
4455
|
+
const usageCheckpointCbs = [];
|
|
4387
4456
|
let supportsNormalized = false;
|
|
4388
4457
|
const exitCbs = [];
|
|
4389
4458
|
let outerId = null;
|
|
@@ -4451,6 +4520,9 @@ function withResilience(inner, cfg = {}) {
|
|
|
4451
4520
|
bumpIdle();
|
|
4452
4521
|
for (const cb of normalizedCbs) cb(event);
|
|
4453
4522
|
});
|
|
4523
|
+
handle.onUsageCheckpoint?.((checkpoint) => {
|
|
4524
|
+
for (const cb of usageCheckpointCbs) cb(checkpoint);
|
|
4525
|
+
});
|
|
4454
4526
|
handle.onExit((info) => {
|
|
4455
4527
|
if (done) return;
|
|
4456
4528
|
done = true;
|
|
@@ -4531,6 +4603,11 @@ function withResilience(inner, cfg = {}) {
|
|
|
4531
4603
|
onNormalizedProviderEvent: (cb) => {
|
|
4532
4604
|
normalizedCbs.push(cb);
|
|
4533
4605
|
},
|
|
4606
|
+
// 运行中用量检查点:同四条流,走本层扇出——重跑换手后新 attempt 的检查点照样送到同一个订阅者。
|
|
4607
|
+
// 换手后新 attempt 从 0 重新累计,与它最终交出的终值同口径(终值也只是最后一个 attempt 的)。
|
|
4608
|
+
onUsageCheckpoint: (cb) => {
|
|
4609
|
+
usageCheckpointCbs.push(cb);
|
|
4610
|
+
},
|
|
4534
4611
|
finishNormalizedTurn: (signal) => {
|
|
4535
4612
|
activeHandle?.finishNormalizedTurn?.(signal);
|
|
4536
4613
|
},
|
|
@@ -5806,6 +5883,8 @@ async function runProtocolSession(job, cfg) {
|
|
|
5806
5883
|
const outputCbs = [];
|
|
5807
5884
|
const telemetryCbs = [];
|
|
5808
5885
|
const liveCbs = [];
|
|
5886
|
+
const usageCbs = [];
|
|
5887
|
+
let lastUsageKey = "";
|
|
5809
5888
|
const appendByKey = /* @__PURE__ */ new Map();
|
|
5810
5889
|
const exitCbs = [];
|
|
5811
5890
|
const state = cfg.createState();
|
|
@@ -5881,6 +5960,14 @@ async function runProtocolSession(job, cfg) {
|
|
|
5881
5960
|
const event = { kind: line2.kind, payload: line2.payload, seq: ++eventSeq, ts: (/* @__PURE__ */ new Date()).toISOString() };
|
|
5882
5961
|
for (const cb of telemetryCbs) cb(event);
|
|
5883
5962
|
}
|
|
5963
|
+
if (cfg.runningUsage && usageCbs.length) {
|
|
5964
|
+
const checkpoint = cfg.runningUsage(state);
|
|
5965
|
+
const key2 = checkpoint ? JSON.stringify(checkpoint.usage) : "";
|
|
5966
|
+
if (checkpoint && key2 !== lastUsageKey) {
|
|
5967
|
+
lastUsageKey = key2;
|
|
5968
|
+
for (const cb of usageCbs) cb(checkpoint);
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5884
5971
|
if (!started) pendingTurnMessages.push(message);
|
|
5885
5972
|
else completeTurn(message);
|
|
5886
5973
|
};
|
|
@@ -5974,6 +6061,9 @@ async function runProtocolSession(job, cfg) {
|
|
|
5974
6061
|
onLiveEvent(cb) {
|
|
5975
6062
|
liveCbs.push(cb);
|
|
5976
6063
|
},
|
|
6064
|
+
...cfg.runningUsage ? { onUsageCheckpoint(cb) {
|
|
6065
|
+
usageCbs.push(cb);
|
|
6066
|
+
} } : {},
|
|
5977
6067
|
get canAppendInput() {
|
|
5978
6068
|
return !closing && started && !exited;
|
|
5979
6069
|
},
|
|
@@ -6045,8 +6135,15 @@ function addCodexBuckets(acc, add) {
|
|
|
6045
6135
|
acc.cacheWrite += add.cacheWrite;
|
|
6046
6136
|
acc.output += add.output;
|
|
6047
6137
|
}
|
|
6048
|
-
function
|
|
6049
|
-
|
|
6138
|
+
function codexRunUsage(usageByTurn, runTurnIds) {
|
|
6139
|
+
const usage = { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 };
|
|
6140
|
+
let sawUsage = false;
|
|
6141
|
+
for (const entry of usageByTurn) {
|
|
6142
|
+
if (entry.turnId !== void 0 && !runTurnIds.has(entry.turnId)) continue;
|
|
6143
|
+
addCodexBuckets(usage, entry.buckets);
|
|
6144
|
+
sawUsage = true;
|
|
6145
|
+
}
|
|
6146
|
+
return sawUsage ? usageFromBuckets(usage) : void 0;
|
|
6050
6147
|
}
|
|
6051
6148
|
function parseCodexSessionId(lines) {
|
|
6052
6149
|
const first = lines[0];
|
|
@@ -6092,30 +6189,16 @@ function parseCodexTokenUsage(lines, sinceMs) {
|
|
|
6092
6189
|
let sawWindowed = false;
|
|
6093
6190
|
let sawTimestamp = false;
|
|
6094
6191
|
for (const line2 of lines) {
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
} catch {
|
|
6100
|
-
continue;
|
|
6101
|
-
}
|
|
6102
|
-
if (o?.type !== "event_msg" || o.payload?.type !== "token_count") continue;
|
|
6103
|
-
const info = o.payload.info;
|
|
6104
|
-
if (!info) continue;
|
|
6105
|
-
const total = bucketsOf(info.total_token_usage);
|
|
6106
|
-
if (total) lastTotal = total;
|
|
6107
|
-
const turn = bucketsOf(info.last_token_usage);
|
|
6108
|
-
if (turn) lastTurn = turn;
|
|
6192
|
+
const row = readCodexTokenCountLine(line2);
|
|
6193
|
+
if (!row) continue;
|
|
6194
|
+
if (row.total) lastTotal = row.total;
|
|
6195
|
+
if (row.turn) lastTurn = row.turn;
|
|
6109
6196
|
if (sinceMs === void 0) continue;
|
|
6110
|
-
|
|
6111
|
-
if (!Number.isFinite(ts3)) continue;
|
|
6197
|
+
if (!Number.isFinite(row.ts)) continue;
|
|
6112
6198
|
sawTimestamp = true;
|
|
6113
|
-
if (
|
|
6199
|
+
if (row.ts < sinceMs || !row.turn) continue;
|
|
6114
6200
|
sawWindowed = true;
|
|
6115
|
-
windowed.
|
|
6116
|
-
windowed.cacheRead += turn.cacheRead;
|
|
6117
|
-
windowed.cacheWrite += turn.cacheWrite;
|
|
6118
|
-
windowed.output += turn.output;
|
|
6201
|
+
addCodexBuckets(windowed, row.turn);
|
|
6119
6202
|
}
|
|
6120
6203
|
if (sinceMs !== void 0 && sawTimestamp) {
|
|
6121
6204
|
return sawWindowed ? usageFromBuckets(windowed) : void 0;
|
|
@@ -6123,6 +6206,25 @@ function parseCodexTokenUsage(lines, sinceMs) {
|
|
|
6123
6206
|
if (sinceMs !== void 0 && lastTurn) return usageFromBuckets(lastTurn);
|
|
6124
6207
|
return lastTotal ? usageFromBuckets(lastTotal) : void 0;
|
|
6125
6208
|
}
|
|
6209
|
+
function readCodexTokenCountLine(line2) {
|
|
6210
|
+
if (!line2 || line2.indexOf("token_count") === -1) return void 0;
|
|
6211
|
+
let o;
|
|
6212
|
+
try {
|
|
6213
|
+
o = JSON.parse(line2);
|
|
6214
|
+
} catch {
|
|
6215
|
+
return void 0;
|
|
6216
|
+
}
|
|
6217
|
+
if (o?.type !== "event_msg" || o.payload?.type !== "token_count") return void 0;
|
|
6218
|
+
const info = o.payload.info;
|
|
6219
|
+
if (!info) return void 0;
|
|
6220
|
+
const total = bucketsOf(info.total_token_usage);
|
|
6221
|
+
const turn = bucketsOf(info.last_token_usage);
|
|
6222
|
+
return {
|
|
6223
|
+
ts: typeof o.timestamp === "string" ? Date.parse(o.timestamp) : Number.NaN,
|
|
6224
|
+
...turn ? { turn } : {},
|
|
6225
|
+
...total ? { total } : {}
|
|
6226
|
+
};
|
|
6227
|
+
}
|
|
6126
6228
|
function parseCodexModel(lines) {
|
|
6127
6229
|
let model;
|
|
6128
6230
|
for (const line2 of lines) {
|
|
@@ -6210,46 +6312,47 @@ function telemetryFromRolloutLines(lines, sinceMs) {
|
|
|
6210
6312
|
}
|
|
6211
6313
|
function scanCodexTelemetry(workdir, sinceMs, sessionsRoot = codexSessionsRoot(), preferSessionId) {
|
|
6212
6314
|
try {
|
|
6213
|
-
const
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6315
|
+
const found2 = locateCodexRollout(workdir, sinceMs, sessionsRoot, preferSessionId);
|
|
6316
|
+
if (found2) return telemetryFromRolloutLines(found2.lines, sinceMs);
|
|
6317
|
+
} catch {
|
|
6318
|
+
}
|
|
6319
|
+
return {};
|
|
6320
|
+
}
|
|
6321
|
+
function locateCodexRollout(workdir, sinceMs, sessionsRoot = codexSessionsRoot(), preferSessionId) {
|
|
6322
|
+
const files = listRecentRollouts(sessionsRoot, sinceMs);
|
|
6323
|
+
const readLines = (f2) => {
|
|
6324
|
+
try {
|
|
6325
|
+
return fs8.readFileSync(f2, "utf8").split("\n");
|
|
6326
|
+
} catch {
|
|
6327
|
+
return null;
|
|
6328
|
+
}
|
|
6329
|
+
};
|
|
6330
|
+
for (const f2 of files) {
|
|
6331
|
+
const lines = readLines(f2);
|
|
6332
|
+
if (!lines) continue;
|
|
6333
|
+
let meta;
|
|
6334
|
+
try {
|
|
6335
|
+
meta = JSON.parse(lines[0] ?? "");
|
|
6336
|
+
} catch {
|
|
6337
|
+
continue;
|
|
6338
|
+
}
|
|
6339
|
+
if (meta?.type === "session_meta" && meta.payload?.cwd === workdir) return { file: f2, lines };
|
|
6340
|
+
}
|
|
6341
|
+
if (preferSessionId) {
|
|
6342
|
+
const suffix = `-${preferSessionId}.jsonl`;
|
|
6221
6343
|
for (const f2 of files) {
|
|
6344
|
+
const byName = f2.endsWith(suffix);
|
|
6222
6345
|
const lines = readLines(f2);
|
|
6223
6346
|
if (!lines) continue;
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
meta = JSON.parse(lines[0] ?? "");
|
|
6227
|
-
} catch {
|
|
6228
|
-
continue;
|
|
6229
|
-
}
|
|
6230
|
-
if (meta?.type === "session_meta" && meta.payload?.cwd === workdir) {
|
|
6231
|
-
return telemetryFromRolloutLines(lines, sinceMs);
|
|
6232
|
-
}
|
|
6347
|
+
const sid = parseCodexSessionId(lines);
|
|
6348
|
+
if (byName || sid === preferSessionId) return { file: f2, lines };
|
|
6233
6349
|
}
|
|
6234
|
-
|
|
6235
|
-
const
|
|
6236
|
-
|
|
6237
|
-
const byName = f2.endsWith(suffix);
|
|
6238
|
-
const lines = readLines(f2);
|
|
6239
|
-
if (!lines) continue;
|
|
6240
|
-
const sid = parseCodexSessionId(lines);
|
|
6241
|
-
if (byName || sid === preferSessionId) {
|
|
6242
|
-
return telemetryFromRolloutLines(lines, sinceMs);
|
|
6243
|
-
}
|
|
6244
|
-
}
|
|
6245
|
-
for (const f2 of findRolloutsBySessionId(sessionsRoot, preferSessionId)) {
|
|
6246
|
-
const lines = readLines(f2);
|
|
6247
|
-
if (lines) return telemetryFromRolloutLines(lines, sinceMs);
|
|
6248
|
-
}
|
|
6350
|
+
for (const f2 of findRolloutsBySessionId(sessionsRoot, preferSessionId)) {
|
|
6351
|
+
const lines = readLines(f2);
|
|
6352
|
+
if (lines) return { file: f2, lines };
|
|
6249
6353
|
}
|
|
6250
|
-
} catch {
|
|
6251
6354
|
}
|
|
6252
|
-
return
|
|
6355
|
+
return void 0;
|
|
6253
6356
|
}
|
|
6254
6357
|
function createCodexNormalizeState() {
|
|
6255
6358
|
return {
|
|
@@ -6465,7 +6568,7 @@ function codexTurnErrorMessage(value2) {
|
|
|
6465
6568
|
const detail = typeof error2?.additionalDetails === "string" ? error2.additionalDetails.trim() : "";
|
|
6466
6569
|
return [summary, detail].filter(Boolean).join("\n").slice(0, 4e3);
|
|
6467
6570
|
}
|
|
6468
|
-
var import_node_child_process7, import_node_crypto9, fs8, os5, path10, readline2, CODEX_BLOCKED_FLAGS, CODEX_ARGV_PROMPT_MAX_BYTES, CODEX_APP_SERVER_BLOCKED_FLAGS, CodexAdapter;
|
|
6571
|
+
var import_node_child_process7, import_node_crypto9, fs8, os5, path10, readline2, CODEX_BLOCKED_FLAGS, CODEX_ARGV_PROMPT_MAX_BYTES, CodexRolloutUsageTail, CODEX_APP_SERVER_BLOCKED_FLAGS, CodexAdapter;
|
|
6469
6572
|
var init_codex = __esm({
|
|
6470
6573
|
"../adapters/src/codex/index.ts"() {
|
|
6471
6574
|
"use strict";
|
|
@@ -6503,6 +6606,46 @@ var init_codex = __esm({
|
|
|
6503
6606
|
// Multica 实证:codex --listen stdio:// 是 daemon↔CLI 传输协议;改会断链
|
|
6504
6607
|
]);
|
|
6505
6608
|
CODEX_ARGV_PROMPT_MAX_BYTES = 1e5;
|
|
6609
|
+
CodexRolloutUsageTail = class {
|
|
6610
|
+
constructor(file, sinceMs) {
|
|
6611
|
+
this.file = file;
|
|
6612
|
+
this.sinceMs = sinceMs;
|
|
6613
|
+
}
|
|
6614
|
+
offset = 0;
|
|
6615
|
+
rest = "";
|
|
6616
|
+
acc = { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 };
|
|
6617
|
+
saw = false;
|
|
6618
|
+
/** 读新追加的行,返回当前窗内累计;还没有任何窗内轮次返回 undefined。读失败抛给调用方(调用方吞)。 */
|
|
6619
|
+
poll() {
|
|
6620
|
+
const fd = fs8.openSync(this.file, "r");
|
|
6621
|
+
try {
|
|
6622
|
+
const size = fs8.fstatSync(fd).size;
|
|
6623
|
+
if (size < this.offset) {
|
|
6624
|
+
this.offset = 0;
|
|
6625
|
+
this.rest = "";
|
|
6626
|
+
this.saw = false;
|
|
6627
|
+
this.acc.input = this.acc.cacheRead = this.acc.cacheWrite = this.acc.output = 0;
|
|
6628
|
+
}
|
|
6629
|
+
if (size > this.offset) {
|
|
6630
|
+
const buf = Buffer.alloc(size - this.offset);
|
|
6631
|
+
const n = fs8.readSync(fd, buf, 0, buf.length, this.offset);
|
|
6632
|
+
this.offset += n;
|
|
6633
|
+
const text6 = this.rest + buf.subarray(0, n).toString("utf8");
|
|
6634
|
+
const lines = text6.split("\n");
|
|
6635
|
+
this.rest = lines.pop() ?? "";
|
|
6636
|
+
for (const line2 of lines) {
|
|
6637
|
+
const row = readCodexTokenCountLine(line2);
|
|
6638
|
+
if (!row?.turn || !Number.isFinite(row.ts) || row.ts < this.sinceMs) continue;
|
|
6639
|
+
addCodexBuckets(this.acc, row.turn);
|
|
6640
|
+
this.saw = true;
|
|
6641
|
+
}
|
|
6642
|
+
}
|
|
6643
|
+
} finally {
|
|
6644
|
+
fs8.closeSync(fd);
|
|
6645
|
+
}
|
|
6646
|
+
return this.saw ? usageFromBuckets(this.acc) : void 0;
|
|
6647
|
+
}
|
|
6648
|
+
};
|
|
6506
6649
|
CODEX_APP_SERVER_BLOCKED_FLAGS = /* @__PURE__ */ new Map([
|
|
6507
6650
|
["app-server", "boolean"],
|
|
6508
6651
|
["--stdio", "boolean"],
|
|
@@ -6713,18 +6856,21 @@ ${task}` : task;
|
|
|
6713
6856
|
}
|
|
6714
6857
|
}
|
|
6715
6858
|
model ??= state.threadModel ?? resolvedModel2;
|
|
6716
|
-
const usage =
|
|
6717
|
-
let sawUsage = false;
|
|
6718
|
-
for (const entry of state.usageByTurn) {
|
|
6719
|
-
if (entry.turnId !== void 0 && !state.runTurnIds.has(entry.turnId)) continue;
|
|
6720
|
-
addCodexBuckets(usage, entry.buckets);
|
|
6721
|
-
sawUsage = true;
|
|
6722
|
-
}
|
|
6859
|
+
const usage = codexRunUsage(state.usageByTurn, state.runTurnIds);
|
|
6723
6860
|
return {
|
|
6724
|
-
...
|
|
6861
|
+
...usage ? { usage } : {},
|
|
6725
6862
|
...model ? { model } : {}
|
|
6726
6863
|
};
|
|
6727
6864
|
},
|
|
6865
|
+
// 运行中净累计(ADR usage-statistics-ledger D2):与上面终值**同一个函数**算——同一套「只算本次
|
|
6866
|
+
// run 发起的轮次」过滤、同一套累加,所以检查点永远 ≤ 终值、不会因为口径差推出负的段。
|
|
6867
|
+
// 重放的上一轮通知先到、本轮 turnId 后才登记时,这一拍先不计它,登记后的下一拍补上(只增不减)。
|
|
6868
|
+
runningUsage: (state) => {
|
|
6869
|
+
const usage = codexRunUsage(state.usageByTurn, state.runTurnIds);
|
|
6870
|
+
if (!usage) return void 0;
|
|
6871
|
+
const model = state.threadModel ?? resolvedModel2;
|
|
6872
|
+
return { usage, ...model ? { model } : {} };
|
|
6873
|
+
},
|
|
6728
6874
|
async append(input, state, send) {
|
|
6729
6875
|
if (!state.threadId || !state.turnId || !state.active) return { accepted: false, reason: "session-closing" };
|
|
6730
6876
|
if (input.interrupt) {
|
|
@@ -6935,8 +7081,39 @@ ${task}` : task;
|
|
|
6935
7081
|
const callbacks = [];
|
|
6936
7082
|
let exited;
|
|
6937
7083
|
let killReason = null;
|
|
7084
|
+
const usageCheckpointCbs = [];
|
|
7085
|
+
let usageTail;
|
|
7086
|
+
let usagePoll = null;
|
|
7087
|
+
let lastUsageKey = "";
|
|
7088
|
+
let locateAttemptsLeft = 8;
|
|
7089
|
+
const pollRolloutUsage = () => {
|
|
7090
|
+
if (exited || !usageCheckpointCbs.length) return;
|
|
7091
|
+
try {
|
|
7092
|
+
if (!usageTail) {
|
|
7093
|
+
if (locateAttemptsLeft <= 0) return;
|
|
7094
|
+
locateAttemptsLeft--;
|
|
7095
|
+
const found2 = locateCodexRollout(dir, startedAtMs, codexSessionsRoot(), job.runtimeSessionId);
|
|
7096
|
+
if (!found2) return;
|
|
7097
|
+
usageTail = new CodexRolloutUsageTail(found2.file, startedAtMs);
|
|
7098
|
+
}
|
|
7099
|
+
const usage = usageTail.poll();
|
|
7100
|
+
const key2 = usage ? JSON.stringify(usage) : "";
|
|
7101
|
+
if (!usage || key2 === lastUsageKey) return;
|
|
7102
|
+
lastUsageKey = key2;
|
|
7103
|
+
const model = job.model ?? this.opts.model;
|
|
7104
|
+
for (const cb of usageCheckpointCbs) cb({ usage, ...model ? { model } : {} });
|
|
7105
|
+
} catch {
|
|
7106
|
+
}
|
|
7107
|
+
};
|
|
7108
|
+
const stopUsagePoll = () => {
|
|
7109
|
+
if (usagePoll) {
|
|
7110
|
+
clearInterval(usagePoll);
|
|
7111
|
+
usagePoll = null;
|
|
7112
|
+
}
|
|
7113
|
+
};
|
|
6938
7114
|
const finish = (info) => {
|
|
6939
7115
|
if (exited) return;
|
|
7116
|
+
stopUsagePoll();
|
|
6940
7117
|
if (job.workdirKey) {
|
|
6941
7118
|
unlockWorkdir(dir);
|
|
6942
7119
|
touchMetaExit(dir, { at: (/* @__PURE__ */ new Date()).toISOString(), ...info.reason ? { reason: info.reason } : {}, runId: id });
|
|
@@ -7017,6 +7194,14 @@ ${task}` : task;
|
|
|
7017
7194
|
},
|
|
7018
7195
|
onTelemetry(cb) {
|
|
7019
7196
|
telemetryCbs.push(cb);
|
|
7197
|
+
},
|
|
7198
|
+
onUsageCheckpoint: (cb) => {
|
|
7199
|
+
usageCheckpointCbs.push(cb);
|
|
7200
|
+
const pollMs = this.opts.usagePollMs ?? 15e3;
|
|
7201
|
+
if (!usagePoll && !exited && pollMs > 0) {
|
|
7202
|
+
usagePoll = setInterval(pollRolloutUsage, pollMs);
|
|
7203
|
+
usagePoll.unref?.();
|
|
7204
|
+
}
|
|
7020
7205
|
}
|
|
7021
7206
|
};
|
|
7022
7207
|
}
|
|
@@ -136609,11 +136794,11 @@ function headRejected(model, id) {
|
|
|
136609
136794
|
function pinnedReviewerOf(model, artifactId, role) {
|
|
136610
136795
|
let best = null;
|
|
136611
136796
|
for (const attempt of model.concludeAttempts.get(artifactId) ?? []) {
|
|
136612
|
-
const
|
|
136797
|
+
const bucket2 = attempt.gate?.requirements.find(
|
|
136613
136798
|
(r) => r.source === "type" && (r.roles ?? []).includes(role)
|
|
136614
136799
|
);
|
|
136615
|
-
if (!
|
|
136616
|
-
const eligible = new Set(
|
|
136800
|
+
if (!bucket2) continue;
|
|
136801
|
+
const eligible = new Set(bucket2.eligible);
|
|
136617
136802
|
for (const rev of revisionsOf(model, artifactId)) {
|
|
136618
136803
|
for (const v2 of model.reviews.get(rev.id) ?? []) {
|
|
136619
136804
|
if (v2.seq <= attempt.seq) continue;
|
|
@@ -143140,9 +143325,9 @@ function groupRequirementsForPreview(rows) {
|
|
|
143140
143325
|
const groups = /* @__PURE__ */ new Map();
|
|
143141
143326
|
for (const r of rows) {
|
|
143142
143327
|
const key2 = r.reviewGroup ?? (r.source === "manual" || r.source === "closure" ? r.actor : "default");
|
|
143143
|
-
const
|
|
143144
|
-
if (
|
|
143145
|
-
if (!
|
|
143328
|
+
const bucket2 = groups.get(key2);
|
|
143329
|
+
if (bucket2) {
|
|
143330
|
+
if (!bucket2.eligible.includes(r.actor)) bucket2.eligible.push(r.actor);
|
|
143146
143331
|
} else {
|
|
143147
143332
|
groups.set(key2, { source: r.source, eligible: [r.actor] });
|
|
143148
143333
|
}
|
|
@@ -214031,8 +214216,8 @@ var init_memory_trace_store = __esm({
|
|
|
214031
214216
|
cost
|
|
214032
214217
|
);
|
|
214033
214218
|
}
|
|
214034
|
-
accumulateRow(actorId, instanceId, runtimeKind, model,
|
|
214035
|
-
const key2 = `${actorId}|${instanceId ?? ""}|${model ?? ""}|${
|
|
214219
|
+
accumulateRow(actorId, instanceId, runtimeKind, model, bucket2, granularity, input, output, total, cacheRead, cacheCreation, cost) {
|
|
214220
|
+
const key2 = `${actorId}|${instanceId ?? ""}|${model ?? ""}|${bucket2}|${granularity}`;
|
|
214036
214221
|
const existing = this.usageAggregates.get(key2);
|
|
214037
214222
|
if (existing) {
|
|
214038
214223
|
existing.runCount += 1;
|
|
@@ -214048,7 +214233,7 @@ var init_memory_trace_store = __esm({
|
|
|
214048
214233
|
runtimeInstanceId: instanceId,
|
|
214049
214234
|
runtimeKind,
|
|
214050
214235
|
effectiveModel: model,
|
|
214051
|
-
bucket,
|
|
214236
|
+
bucket: bucket2,
|
|
214052
214237
|
granularity,
|
|
214053
214238
|
runCount: 1,
|
|
214054
214239
|
inputTokens: input,
|
|
@@ -233099,9 +233284,9 @@ function buildOrganizationUsageSummary(input) {
|
|
|
233099
233284
|
addUsage(total, usage);
|
|
233100
233285
|
const key2 = bucketKey(formatter, run.startedAt, input.bucketKind);
|
|
233101
233286
|
if (key2) {
|
|
233102
|
-
const
|
|
233103
|
-
addUsage(
|
|
233104
|
-
buckets.set(key2,
|
|
233287
|
+
const bucket2 = buckets.get(key2) ?? { key: key2, ...emptyUsage() };
|
|
233288
|
+
addUsage(bucket2, usage);
|
|
233289
|
+
buckets.set(key2, bucket2);
|
|
233105
233290
|
}
|
|
233106
233291
|
const workspace = run.artifactId ? workspaceByArtifact.get(run.artifactId) : void 0;
|
|
233107
233292
|
const workorder = workspace ? workorderById.get(workspace) : void 0;
|
|
@@ -233703,9 +233888,9 @@ function buildUsageOverview(input) {
|
|
|
233703
233888
|
for (let i = a; i <= b2 && i < partial2.length; i += 1) partial2[i] = true;
|
|
233704
233889
|
}
|
|
233705
233890
|
}
|
|
233706
|
-
const trend = input.resolved.buckets.map((
|
|
233707
|
-
start:
|
|
233708
|
-
end:
|
|
233891
|
+
const trend = input.resolved.buckets.map((bucket2, i) => ({
|
|
233892
|
+
start: bucket2.start,
|
|
233893
|
+
end: bucket2.end,
|
|
233709
233894
|
amount: trendAcc[i].toAmount(),
|
|
233710
233895
|
partial: partial2[i]
|
|
233711
233896
|
}));
|
|
@@ -234788,9 +234973,9 @@ function collabDomain(opts) {
|
|
|
234788
234973
|
}
|
|
234789
234974
|
const from = req.query.get("from");
|
|
234790
234975
|
const to = req.query.get("to");
|
|
234791
|
-
const
|
|
234976
|
+
const bucket2 = req.query.get("bucket");
|
|
234792
234977
|
const timeZone = req.query.get("timeZone") ?? "UTC";
|
|
234793
|
-
if (!from || !to ||
|
|
234978
|
+
if (!from || !to || bucket2 !== "hour" && bucket2 !== "day") {
|
|
234794
234979
|
return { status: 400, body: { error: { code: "bad_request", message: "from / to / bucket(hour|day) \u5FC5\u586B" } } };
|
|
234795
234980
|
}
|
|
234796
234981
|
const fromMs = Date.parse(from);
|
|
@@ -234821,7 +235006,7 @@ function collabDomain(opts) {
|
|
|
234821
235006
|
}
|
|
234822
235007
|
return {
|
|
234823
235008
|
status: 200,
|
|
234824
|
-
body: buildOrganizationUsageSummary({ model: kernel.model, runs, bucketKind:
|
|
235009
|
+
body: buildOrganizationUsageSummary({ model: kernel.model, runs, bucketKind: bucket2, timeZone, runtimeHostnames, runtimeNodeNames })
|
|
234825
235010
|
};
|
|
234826
235011
|
});
|
|
234827
235012
|
const usageCompanyOf = (req) => req.auth.companyId ?? opts.defaultCompanyId;
|
|
@@ -237998,10 +238183,10 @@ function runtimeUsageBucket(startedAt, granularity) {
|
|
|
237998
238183
|
function bucketRuntimeRuns(runtimeInstanceId, runs, granularity) {
|
|
237999
238184
|
const rows = /* @__PURE__ */ new Map();
|
|
238000
238185
|
for (const run of runs) {
|
|
238001
|
-
const
|
|
238002
|
-
if (!
|
|
238186
|
+
const bucket2 = runtimeUsageBucket(run.startedAt, granularity);
|
|
238187
|
+
if (!bucket2) continue;
|
|
238003
238188
|
const model = resolvedModel(run.effectiveModel);
|
|
238004
|
-
const key2 = `${
|
|
238189
|
+
const key2 = `${bucket2}\0${run.actorId}\0${model ?? ""}`;
|
|
238005
238190
|
let row = rows.get(key2);
|
|
238006
238191
|
if (!row) {
|
|
238007
238192
|
row = {
|
|
@@ -238009,7 +238194,7 @@ function bucketRuntimeRuns(runtimeInstanceId, runs, granularity) {
|
|
|
238009
238194
|
runtimeInstanceId,
|
|
238010
238195
|
runtimeKind: run.runtimeKind,
|
|
238011
238196
|
effectiveModel: model,
|
|
238012
|
-
bucket,
|
|
238197
|
+
bucket: bucket2,
|
|
238013
238198
|
runCount: 0,
|
|
238014
238199
|
inputTokens: 0,
|
|
238015
238200
|
outputTokens: 0,
|
|
@@ -238078,9 +238263,9 @@ function runtimeUsageFromLedger(runtimeInstanceId, slice) {
|
|
|
238078
238263
|
const rows = /* @__PURE__ */ new Map();
|
|
238079
238264
|
const runById = new Map(slice.runs.map((r) => [r.id, r]));
|
|
238080
238265
|
const rowOf = (bucketIndex2, run) => {
|
|
238081
|
-
const
|
|
238266
|
+
const bucket2 = bucketLabelOf(slice, bucketIndex2);
|
|
238082
238267
|
const model = resolvedModel(run.effectiveModel);
|
|
238083
|
-
const key2 = `${
|
|
238268
|
+
const key2 = `${bucket2}\0${run.actorId}\0${model ?? ""}`;
|
|
238084
238269
|
let row = rows.get(key2);
|
|
238085
238270
|
if (!row) {
|
|
238086
238271
|
row = {
|
|
@@ -238088,7 +238273,7 @@ function runtimeUsageFromLedger(runtimeInstanceId, slice) {
|
|
|
238088
238273
|
runtimeInstanceId,
|
|
238089
238274
|
runtimeKind: run.runtimeKind,
|
|
238090
238275
|
effectiveModel: model,
|
|
238091
|
-
bucket,
|
|
238276
|
+
bucket: bucket2,
|
|
238092
238277
|
runCount: 0,
|
|
238093
238278
|
inputTokens: 0,
|
|
238094
238279
|
outputTokens: 0,
|
|
@@ -267494,15 +267679,15 @@ async function deadlineClockTick(deps, dedupe3) {
|
|
|
267494
267679
|
const overdue = deps.now - deadline;
|
|
267495
267680
|
if (overdue > result.oldestDueDelayMs) result.oldestDueDelayMs = overdue;
|
|
267496
267681
|
const phase = overdue >= 0 ? "due" : "early";
|
|
267497
|
-
const
|
|
267498
|
-
if (dedupe3.has(c.workorderId,
|
|
267682
|
+
const bucket2 = `${c.workId}@${deadline}@${phase}`;
|
|
267683
|
+
if (dedupe3.has(c.workorderId, bucket2)) {
|
|
267499
267684
|
result.deduped++;
|
|
267500
267685
|
continue;
|
|
267501
267686
|
}
|
|
267502
267687
|
const buckets = toPing.get(c.workorderId) ?? [];
|
|
267503
|
-
buckets.push(
|
|
267688
|
+
buckets.push(bucket2);
|
|
267504
267689
|
toPing.set(c.workorderId, buckets);
|
|
267505
|
-
dedupe3.mark(c.workorderId,
|
|
267690
|
+
dedupe3.mark(c.workorderId, bucket2);
|
|
267506
267691
|
}
|
|
267507
267692
|
if (page.nextCursor) result.backlog = toPing.size + result.deduped;
|
|
267508
267693
|
for (const [workorderId, buckets] of toPing) {
|
|
@@ -274788,8 +274973,8 @@ async function startServe(opts) {
|
|
|
274788
274973
|
const live = engineRouter.liveEntries().find((x2) => x2.engine.kernel.model.artifacts.has(artifactId));
|
|
274789
274974
|
const engine2 = live?.engine ?? await getEngine(defaultCompanyId);
|
|
274790
274975
|
if (!engine2.kernel.model.artifacts.has(artifactId)) continue;
|
|
274791
|
-
const
|
|
274792
|
-
if (
|
|
274976
|
+
const bucket2 = byEngine.get(engine2);
|
|
274977
|
+
if (bucket2) bucket2.push(artifactId);
|
|
274793
274978
|
else byEngine.set(engine2, [artifactId]);
|
|
274794
274979
|
}
|
|
274795
274980
|
for (const [engine2, ids2] of byEngine) {
|
|
@@ -277295,6 +277480,108 @@ function isSessionLocked(lockPath) {
|
|
|
277295
277480
|
init_src();
|
|
277296
277481
|
init_src2();
|
|
277297
277482
|
init_src8();
|
|
277483
|
+
|
|
277484
|
+
// ../cli/src/daemon/usage-checkpoints.ts
|
|
277485
|
+
var USAGE_CHECKPOINT_MIN_INTERVAL_MS = 3e4;
|
|
277486
|
+
function bucket(value2) {
|
|
277487
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : null;
|
|
277488
|
+
}
|
|
277489
|
+
function maxBucket(a, b2) {
|
|
277490
|
+
const x2 = bucket(a);
|
|
277491
|
+
const y = bucket(b2);
|
|
277492
|
+
if (x2 === null) return y;
|
|
277493
|
+
if (y === null) return x2;
|
|
277494
|
+
return Math.max(x2, y);
|
|
277495
|
+
}
|
|
277496
|
+
function mergeMonotonicUsage(prev, next) {
|
|
277497
|
+
if (!prev) return next;
|
|
277498
|
+
const inputTokens = maxBucket(prev.inputTokens, next.inputTokens);
|
|
277499
|
+
const outputTokens = maxBucket(prev.outputTokens, next.outputTokens);
|
|
277500
|
+
return {
|
|
277501
|
+
inputTokens,
|
|
277502
|
+
outputTokens,
|
|
277503
|
+
totalTokens: inputTokens === null && outputTokens === null ? null : (inputTokens ?? 0) + (outputTokens ?? 0),
|
|
277504
|
+
cacheReadTokens: maxBucket(prev.cacheReadTokens, next.cacheReadTokens),
|
|
277505
|
+
cacheCreationTokens: maxBucket(prev.cacheCreationTokens, next.cacheCreationTokens),
|
|
277506
|
+
costUsdMicros: maxBucket(prev.costUsdMicros, next.costUsdMicros)
|
|
277507
|
+
};
|
|
277508
|
+
}
|
|
277509
|
+
var UsageCheckpointEmitter = class {
|
|
277510
|
+
constructor(deps) {
|
|
277511
|
+
this.deps = deps;
|
|
277512
|
+
this.minIntervalMs = deps.minIntervalMs ?? USAGE_CHECKPOINT_MIN_INTERVAL_MS;
|
|
277513
|
+
this.now = deps.now ?? Date.now;
|
|
277514
|
+
}
|
|
277515
|
+
usageSeq = 0;
|
|
277516
|
+
latest = null;
|
|
277517
|
+
lastSentKey = "";
|
|
277518
|
+
lastSentAt = Number.NEGATIVE_INFINITY;
|
|
277519
|
+
timer = null;
|
|
277520
|
+
closed = false;
|
|
277521
|
+
minIntervalMs;
|
|
277522
|
+
now;
|
|
277523
|
+
/** adapter 报来一次累计值。observedAt 取报来的这一刻——窗口末尾才发出去时,时刻仍是它被观测到的那一刻。 */
|
|
277524
|
+
observe(checkpoint) {
|
|
277525
|
+
if (this.closed) return;
|
|
277526
|
+
const usage = mergeMonotonicUsage(this.latest?.usage ?? null, checkpoint.usage);
|
|
277527
|
+
const model = checkpoint.model ?? this.latest?.model;
|
|
277528
|
+
const changed = JSON.stringify(usage) !== JSON.stringify(this.latest?.usage ?? null);
|
|
277529
|
+
if (!changed && model === this.latest?.model) return;
|
|
277530
|
+
this.latest = { usage, ...model ? { model } : {}, observedAt: changed ? this.now() : this.latest.observedAt };
|
|
277531
|
+
this.pump();
|
|
277532
|
+
}
|
|
277533
|
+
/** 退出前补发:还有没发出去的最新值就立刻发(不受节流),之后本 run 不再发任何检查点。 */
|
|
277534
|
+
flush() {
|
|
277535
|
+
if (this.closed) return;
|
|
277536
|
+
this.clearTimer();
|
|
277537
|
+
if (this.hasUnsent() && this.deps.accepts()) this.emit();
|
|
277538
|
+
this.closed = true;
|
|
277539
|
+
}
|
|
277540
|
+
/** 已发出的检查点帧数(观测/测试用)。 */
|
|
277541
|
+
get sent() {
|
|
277542
|
+
return this.usageSeq;
|
|
277543
|
+
}
|
|
277544
|
+
hasUnsent() {
|
|
277545
|
+
return this.latest !== null && JSON.stringify(this.latest.usage) !== this.lastSentKey;
|
|
277546
|
+
}
|
|
277547
|
+
pump() {
|
|
277548
|
+
if (this.closed || !this.hasUnsent() || !this.deps.accepts()) return;
|
|
277549
|
+
const wait = this.lastSentAt + this.minIntervalMs - this.now();
|
|
277550
|
+
if (wait <= 0) {
|
|
277551
|
+
this.clearTimer();
|
|
277552
|
+
this.emit();
|
|
277553
|
+
return;
|
|
277554
|
+
}
|
|
277555
|
+
if (this.timer) return;
|
|
277556
|
+
this.timer = setTimeout(() => {
|
|
277557
|
+
this.timer = null;
|
|
277558
|
+
this.pump();
|
|
277559
|
+
}, wait);
|
|
277560
|
+
this.timer.unref?.();
|
|
277561
|
+
}
|
|
277562
|
+
emit() {
|
|
277563
|
+
const latest = this.latest;
|
|
277564
|
+
const frame = {
|
|
277565
|
+
type: "session_usage",
|
|
277566
|
+
dispatchId: this.deps.dispatchId,
|
|
277567
|
+
usageSeq: ++this.usageSeq,
|
|
277568
|
+
observedAt: new Date(latest.observedAt).toISOString(),
|
|
277569
|
+
usage: latest.usage,
|
|
277570
|
+
...latest.model ? { model: latest.model } : {}
|
|
277571
|
+
};
|
|
277572
|
+
this.lastSentKey = JSON.stringify(latest.usage);
|
|
277573
|
+
this.lastSentAt = this.now();
|
|
277574
|
+
this.deps.send(frame);
|
|
277575
|
+
}
|
|
277576
|
+
clearTimer() {
|
|
277577
|
+
if (this.timer) {
|
|
277578
|
+
clearTimeout(this.timer);
|
|
277579
|
+
this.timer = null;
|
|
277580
|
+
}
|
|
277581
|
+
}
|
|
277582
|
+
};
|
|
277583
|
+
|
|
277584
|
+
// ../cli/src/daemon/session-runner.ts
|
|
277298
277585
|
async function preflightOasisAccess(job) {
|
|
277299
277586
|
const base = job.server.url.replace(/\/+$/, "");
|
|
277300
277587
|
try {
|
|
@@ -277351,12 +277638,21 @@ async function runSession(dispatchId, job, deps) {
|
|
|
277351
277638
|
deps.sink.stream({ type: "session_live_event", dispatchId, event });
|
|
277352
277639
|
normalizer.onLiveEvent(event);
|
|
277353
277640
|
});
|
|
277641
|
+
const acceptsUsageCheckpoints = deps.sink.acceptsUsageCheckpoints?.bind(deps.sink);
|
|
277642
|
+
const usageCheckpoints = acceptsUsageCheckpoints && handle.onUsageCheckpoint ? new UsageCheckpointEmitter({
|
|
277643
|
+
dispatchId,
|
|
277644
|
+
accepts: acceptsUsageCheckpoints,
|
|
277645
|
+
send: (frame) => deps.sink.stream(frame),
|
|
277646
|
+
...deps.usageCheckpointIntervalMs !== void 0 ? { minIntervalMs: deps.usageCheckpointIntervalMs } : {}
|
|
277647
|
+
}) : null;
|
|
277648
|
+
if (usageCheckpoints) handle.onUsageCheckpoint((checkpoint) => usageCheckpoints.observe(checkpoint));
|
|
277354
277649
|
let restoreFailedBeforeStart = false;
|
|
277355
277650
|
handle.onExit((info) => {
|
|
277356
277651
|
if (info.fileRestoreError) restoreFailedBeforeStart = true;
|
|
277357
277652
|
normalizer.turnFinished(isHealthySessionExit(info) ? "completed" : "failed");
|
|
277358
277653
|
log2("[node-cli]", ` \u25A0 session_exited id=${handle.id} code=${info.code ?? "killed"} total=${Date.now() - t0}ms`);
|
|
277359
277654
|
if (info.transcriptRef) log2("[node-cli]", ` transcript: ${info.transcriptRef}`);
|
|
277655
|
+
usageCheckpoints?.flush();
|
|
277360
277656
|
deps.sink.keyFrame({ type: "session_exited", dispatchId, sessionId: handle.id, info });
|
|
277361
277657
|
deps.onExited?.();
|
|
277362
277658
|
});
|
|
@@ -277459,6 +277755,11 @@ var SessionProcessState = class {
|
|
|
277459
277755
|
frameSeq = 0;
|
|
277460
277756
|
/** 收到过带 `ackSeq` 的 ack = 本服务端会按帧号去重;只有它为真,重连才敢重放**全部**帧(含输出)。 */
|
|
277461
277757
|
serverSupportsDedup = false;
|
|
277758
|
+
/**
|
|
277759
|
+
* 当前这根连接上的服务端 ping 声明过 `acceptsUsageCheckpoints`(ADR usage-statistics-ledger D2)。
|
|
277760
|
+
* **按连接记**:连上/断开都清零,等这根连接上的下一个 ping 再说——重连到的可能是没升级的服务端。
|
|
277761
|
+
*/
|
|
277762
|
+
serverAcceptsUsageCheckpoints = false;
|
|
277462
277763
|
/** append_input 串行链——保证回帧次序 = 到达次序(server 侧按 FIFO 认领等待者)。 */
|
|
277463
277764
|
appendChain = Promise.resolve();
|
|
277464
277765
|
async run() {
|
|
@@ -277472,8 +277773,10 @@ var SessionProcessState = class {
|
|
|
277472
277773
|
preflight: this.spec.preflight,
|
|
277473
277774
|
sink: {
|
|
277474
277775
|
keyFrame: (m2) => this.sendKeyFrame(m2),
|
|
277475
|
-
stream: (m2) => this.sendStream(m2)
|
|
277776
|
+
stream: (m2) => this.sendStream(m2),
|
|
277777
|
+
acceptsUsageCheckpoints: () => this.connected && this.serverAcceptsUsageCheckpoints
|
|
277476
277778
|
},
|
|
277779
|
+
...this.spec.limits?.usageCheckpointIntervalMs !== void 0 ? { usageCheckpointIntervalMs: this.spec.limits.usageCheckpointIntervalMs } : {},
|
|
277477
277780
|
onHandle: (h) => {
|
|
277478
277781
|
this.handle = h;
|
|
277479
277782
|
if (this.stopping) {
|
|
@@ -277513,6 +277816,7 @@ var SessionProcessState = class {
|
|
|
277513
277816
|
this.ws = ws;
|
|
277514
277817
|
ws.on("open", () => {
|
|
277515
277818
|
this.connected = true;
|
|
277819
|
+
this.serverAcceptsUsageCheckpoints = false;
|
|
277516
277820
|
this.unreachableSince = null;
|
|
277517
277821
|
this.reconnectMs = RECONNECT_MIN_MS;
|
|
277518
277822
|
log2("[session]", `${this.spec.dispatchId}: \u6570\u636E\u9762\u5DF2\u8FDE\u4E0A ${this.spec.auth.gatewayUrl}`);
|
|
@@ -277548,6 +277852,7 @@ var SessionProcessState = class {
|
|
|
277548
277852
|
});
|
|
277549
277853
|
ws.on("close", () => {
|
|
277550
277854
|
this.connected = false;
|
|
277855
|
+
this.serverAcceptsUsageCheckpoints = false;
|
|
277551
277856
|
this.unreachableSince ??= Date.now();
|
|
277552
277857
|
if (this.stopping) return;
|
|
277553
277858
|
setTimeout(() => this.connect(), this.reconnectMs).unref?.();
|
|
@@ -277594,6 +277899,7 @@ var SessionProcessState = class {
|
|
|
277594
277899
|
if (this.outbox.length === 0) this.exitAckResolve?.();
|
|
277595
277900
|
return;
|
|
277596
277901
|
case "ping":
|
|
277902
|
+
this.serverAcceptsUsageCheckpoints = msg.acceptsUsageCheckpoints === true;
|
|
277597
277903
|
this.rawSend({ type: "pong" });
|
|
277598
277904
|
return;
|
|
277599
277905
|
default:
|
|
@@ -277696,21 +278002,21 @@ var import_node_os9 = require("node:os");
|
|
|
277696
278002
|
function object6(value2) {
|
|
277697
278003
|
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : {};
|
|
277698
278004
|
}
|
|
277699
|
-
function window2(
|
|
278005
|
+
function window2(bucket2, minutes, used, reset) {
|
|
277700
278006
|
if (typeof minutes !== "number" || !Number.isFinite(minutes) || minutes <= 0 || typeof used !== "number" || !Number.isFinite(used) || used < 0 || used > 100) return [];
|
|
277701
278007
|
const ms = typeof reset === "number" ? reset * 1e3 : typeof reset === "string" ? Date.parse(reset) : NaN;
|
|
277702
278008
|
const resetsAt = Number.isFinite(ms) && Math.abs(ms) < 864e13 ? new Date(ms).toISOString() : void 0;
|
|
277703
|
-
return [{ bucket, windowMinutes: minutes, usedPercent: used, ...resetsAt ? { resetsAt } : {} }];
|
|
278009
|
+
return [{ bucket: bucket2, windowMinutes: minutes, usedPercent: used, ...resetsAt ? { resetsAt } : {} }];
|
|
277704
278010
|
}
|
|
277705
278011
|
function parseCodexQuota(value2) {
|
|
277706
278012
|
const response = object6(value2);
|
|
277707
278013
|
const buckets = response.rateLimitsByLimitId !== null && response.rateLimitsByLimitId !== void 0 ? object6(response.rateLimitsByLimitId) : { codex: response.rateLimits };
|
|
277708
|
-
return Object.entries(buckets).slice(0, 16).flatMap(([
|
|
277709
|
-
if (!/^[a-zA-Z0-9_.-]{1,80}$/.test(
|
|
278014
|
+
return Object.entries(buckets).slice(0, 16).flatMap(([bucket2, raw]) => {
|
|
278015
|
+
if (!/^[a-zA-Z0-9_.-]{1,80}$/.test(bucket2)) return [];
|
|
277710
278016
|
const limits = object6(raw);
|
|
277711
278017
|
return [limits.primary, limits.secondary].flatMap((v2) => {
|
|
277712
278018
|
const w2 = object6(v2);
|
|
277713
|
-
return window2(
|
|
278019
|
+
return window2(bucket2, w2.windowDurationMins, w2.usedPercent, w2.resetsAt);
|
|
277714
278020
|
});
|
|
277715
278021
|
});
|
|
277716
278022
|
}
|
|
@@ -278508,6 +278814,12 @@ var DaemonWsClient = class {
|
|
|
278508
278814
|
this.stop();
|
|
278509
278815
|
}
|
|
278510
278816
|
serverSupportsChunkedMessages = false;
|
|
278817
|
+
/**
|
|
278818
|
+
* 当前控制面连接上的服务端 ping 声明过 `acceptsUsageCheckpoints`(ADR usage-statistics-ledger D2)。
|
|
278819
|
+
* 与 serverSupportsChunkedMessages 同口径:按连接记,新连接清零、等它自己的 ping。
|
|
278820
|
+
* 只影响本进程内跑的会话(没有 sessionAuth 的回落路径);独立会话进程看它自己那根连接。
|
|
278821
|
+
*/
|
|
278822
|
+
serverAcceptsUsageCheckpoints = false;
|
|
278511
278823
|
connect() {
|
|
278512
278824
|
if (this.stopped) return;
|
|
278513
278825
|
const ws = new import_websocket.default(this.serverUrl, {
|
|
@@ -278522,6 +278834,7 @@ var DaemonWsClient = class {
|
|
|
278522
278834
|
});
|
|
278523
278835
|
this.ws = ws;
|
|
278524
278836
|
this.serverSupportsChunkedMessages = false;
|
|
278837
|
+
this.serverAcceptsUsageCheckpoints = false;
|
|
278525
278838
|
ws.on("open", () => {
|
|
278526
278839
|
log2("[node-cli]", `connected id=${this.daemonId}`);
|
|
278527
278840
|
this.authRejectStreak = 0;
|
|
@@ -278559,6 +278872,7 @@ var DaemonWsClient = class {
|
|
|
278559
278872
|
clearInterval(this.pingTimer);
|
|
278560
278873
|
this.pingTimer = null;
|
|
278561
278874
|
}
|
|
278875
|
+
this.serverAcceptsUsageCheckpoints = false;
|
|
278562
278876
|
if (this.stopped) return;
|
|
278563
278877
|
const authRejected = this.lastErrorWasAuthReject;
|
|
278564
278878
|
this.lastErrorWasAuthReject = false;
|
|
@@ -278624,7 +278938,8 @@ var DaemonWsClient = class {
|
|
|
278624
278938
|
sink: {
|
|
278625
278939
|
keyFrame: (m2) => this.sendKeyFrame(dispatchId, m2),
|
|
278626
278940
|
// 流帧走 sendStream:断链期间有界暂存、重连补发(serve 重启窗口内的输出不再静默丢)。
|
|
278627
|
-
stream: (m2) => this.sendStream(m2)
|
|
278941
|
+
stream: (m2) => this.sendStream(m2),
|
|
278942
|
+
acceptsUsageCheckpoints: () => this.ws?.readyState === import_websocket.default.OPEN && this.serverAcceptsUsageCheckpoints
|
|
278628
278943
|
},
|
|
278629
278944
|
onHandle: (handle) => {
|
|
278630
278945
|
this.sessions.register(dispatchId, handle, {
|
|
@@ -278668,6 +278983,7 @@ var DaemonWsClient = class {
|
|
|
278668
278983
|
}
|
|
278669
278984
|
case "ping":
|
|
278670
278985
|
this.serverSupportsChunkedMessages = msg.supportsChunkedMessages === true;
|
|
278986
|
+
this.serverAcceptsUsageCheckpoints = msg.acceptsUsageCheckpoints === true;
|
|
278671
278987
|
this.send({ type: "pong" });
|
|
278672
278988
|
break;
|
|
278673
278989
|
case "ack":
|
|
@@ -282023,10 +282339,10 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
282023
282339
|
const byLabel = items.filter((x2) => (x2.label ?? "").toLowerCase() === lower);
|
|
282024
282340
|
const byId = items.filter((x2) => x2.id.startsWith(ref2) || x2.id.replace(/-/g, "").startsWith(ref2));
|
|
282025
282341
|
const byExpert = items.filter((x2) => (x2.expertName ?? "").toLowerCase() === lower || x2.expertActorId === ref2 || x2.expertActorId.endsWith(`:${ref2}`));
|
|
282026
|
-
for (const
|
|
282027
|
-
if (
|
|
282028
|
-
if (
|
|
282029
|
-
const lines = ["`" + ref2 + "` \u649E\u5230\u591A\u4E2A\u59D4\u6D3E\uFF0C\u6311\u4E00\u4E2A\u66F4\u5177\u4F53\u7684\u91CD\u53D1\uFF08\u7528 label \u6216 id \u524D\u7F00\uFF09\uFF1A", ...
|
|
282342
|
+
for (const bucket2 of [byLabel, byId, byExpert]) {
|
|
282343
|
+
if (bucket2.length === 1) return bucket2[0];
|
|
282344
|
+
if (bucket2.length > 1) {
|
|
282345
|
+
const lines = ["`" + ref2 + "` \u649E\u5230\u591A\u4E2A\u59D4\u6D3E\uFF0C\u6311\u4E00\u4E2A\u66F4\u5177\u4F53\u7684\u91CD\u53D1\uFF08\u7528 label \u6216 id \u524D\u7F00\uFF09\uFF1A", ...bucket2.map(describe)];
|
|
282030
282346
|
throw new Error(lines.join("\n"));
|
|
282031
282347
|
}
|
|
282032
282348
|
}
|
|
@@ -284918,7 +285234,7 @@ function shimScript() {
|
|
|
284918
285234
|
}
|
|
284919
285235
|
|
|
284920
285236
|
// src/index.ts
|
|
284921
|
-
var PKG_VERSION = true ? "2.2.
|
|
285237
|
+
var PKG_VERSION = true ? "2.2.54" : "dev";
|
|
284922
285238
|
var LOCAL_BIN = localBin();
|
|
284923
285239
|
var NPM_PREFIX = npmPrefix();
|
|
284924
285240
|
var INSTANCE = DEFAULT_INSTANCE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oasis_test_v2",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.54",
|
|
4
4
|
"description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
|
|
5
5
|
"bin": {
|
|
6
6
|
"oasis": "./dist/index.js"
|
|
@@ -26,6 +26,6 @@
|
|
|
26
26
|
"node": ">=20"
|
|
27
27
|
},
|
|
28
28
|
"oasisRelease": {
|
|
29
|
-
"sourceHead": "
|
|
29
|
+
"sourceHead": "f63f447c49d3571103041e7a042fca92fe0ab371"
|
|
30
30
|
}
|
|
31
31
|
}
|