@cabane/companion 0.6.114 → 0.6.116
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.js +81 -11
- package/dist/runtime.js +81 -11
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -2877,6 +2877,14 @@ function apiErrorCode(err) {
|
|
|
2877
2877
|
const body = err.body;
|
|
2878
2878
|
return typeof body === "object" && body !== null && typeof body.error === "string" ? body.error : null;
|
|
2879
2879
|
}
|
|
2880
|
+
function apiErrorMessage(err) {
|
|
2881
|
+
const body = err instanceof ApiError ? err.body : void 0;
|
|
2882
|
+
if (body !== null && typeof body === "object") {
|
|
2883
|
+
const message = body.message;
|
|
2884
|
+
if (typeof message === "string" && message.length > 0) return message;
|
|
2885
|
+
}
|
|
2886
|
+
return err instanceof Error ? err.message : String(err);
|
|
2887
|
+
}
|
|
2880
2888
|
function leaseRefusal(err) {
|
|
2881
2889
|
const code = apiErrorCode(err);
|
|
2882
2890
|
if (code && LEASE_REFUSALS.has(code)) return code;
|
|
@@ -6839,6 +6847,16 @@ function readUsage(ev) {
|
|
|
6839
6847
|
cacheCreationTokens: num(usage.cache_write_input_tokens)
|
|
6840
6848
|
};
|
|
6841
6849
|
}
|
|
6850
|
+
function codexUsageDelta(cumulative, baseline) {
|
|
6851
|
+
if (!baseline) return cumulative;
|
|
6852
|
+
const sub = (a, b) => Math.max(0, a - b);
|
|
6853
|
+
return {
|
|
6854
|
+
inputTokens: sub(cumulative.inputTokens, baseline.inputTokens),
|
|
6855
|
+
outputTokens: sub(cumulative.outputTokens, baseline.outputTokens),
|
|
6856
|
+
cacheReadTokens: sub(cumulative.cacheReadTokens, baseline.cacheReadTokens),
|
|
6857
|
+
cacheCreationTokens: sub(cumulative.cacheCreationTokens, baseline.cacheCreationTokens)
|
|
6858
|
+
};
|
|
6859
|
+
}
|
|
6842
6860
|
function toStatus(v) {
|
|
6843
6861
|
return v === "completed" || v === "failed" ? v : "in_progress";
|
|
6844
6862
|
}
|
|
@@ -6913,9 +6931,26 @@ function decideResume3(stored, currentCwd) {
|
|
|
6913
6931
|
}
|
|
6914
6932
|
return {
|
|
6915
6933
|
resume: state.threadId,
|
|
6916
|
-
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null
|
|
6934
|
+
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null,
|
|
6935
|
+
usageBaseline: readUsageBaseline(state.usageBaseline)
|
|
6917
6936
|
};
|
|
6918
6937
|
}
|
|
6938
|
+
function readUsageBaseline(raw) {
|
|
6939
|
+
if (!raw || typeof raw !== "object") return null;
|
|
6940
|
+
const rec2 = raw;
|
|
6941
|
+
const read = (key) => {
|
|
6942
|
+
const v = rec2[key];
|
|
6943
|
+
return typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : null;
|
|
6944
|
+
};
|
|
6945
|
+
const inputTokens = read("inputTokens");
|
|
6946
|
+
const outputTokens = read("outputTokens");
|
|
6947
|
+
const cacheReadTokens = read("cacheReadTokens");
|
|
6948
|
+
const cacheCreationTokens = read("cacheCreationTokens");
|
|
6949
|
+
if (inputTokens === null || outputTokens === null || cacheReadTokens === null || cacheCreationTokens === null) {
|
|
6950
|
+
return null;
|
|
6951
|
+
}
|
|
6952
|
+
return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
|
|
6953
|
+
}
|
|
6919
6954
|
|
|
6920
6955
|
// packages/agent-runtime/src/codex/loop.ts
|
|
6921
6956
|
async function* decodeCodexStream(events, ctx) {
|
|
@@ -6927,6 +6962,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6927
6962
|
let ok = false;
|
|
6928
6963
|
let reason;
|
|
6929
6964
|
let usage;
|
|
6965
|
+
let cumulativeUsage;
|
|
6966
|
+
let threadIdForSession = ctx.resumedThreadId;
|
|
6930
6967
|
let settled = false;
|
|
6931
6968
|
function* flushInterim() {
|
|
6932
6969
|
const sealed = sealHeld2(held, false);
|
|
@@ -6937,11 +6974,17 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6937
6974
|
if (ctx.signal.aborted) return;
|
|
6938
6975
|
if (ev.type === "thread.started") {
|
|
6939
6976
|
const threadId = readThreadId(ev);
|
|
6977
|
+
if (threadId) threadIdForSession = threadId;
|
|
6940
6978
|
if (threadId && !sessionEmitted) {
|
|
6941
6979
|
const state = encodeSession3({
|
|
6942
6980
|
threadId,
|
|
6943
6981
|
cwd: ctx.cwd ?? "",
|
|
6944
|
-
promptFingerprint: ctx.promptFingerprint ?? null
|
|
6982
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
6983
|
+
// CT1645: the baseline this turn INHERITED, carried through unchanged.
|
|
6984
|
+
// This early write exists so a turn that dies mid-stream still leaves
|
|
6985
|
+
// the thread id recorded; it cannot yet know what this turn will spend.
|
|
6986
|
+
// The closing write below records the new baseline.
|
|
6987
|
+
usageBaseline: ctx.usageBaseline ?? null
|
|
6945
6988
|
});
|
|
6946
6989
|
if (threadId !== ctx.resumedThreadId || state !== ctx.storedState) {
|
|
6947
6990
|
sessionEmitted = true;
|
|
@@ -7016,7 +7059,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
7016
7059
|
const sealed = sealHeld2(held, true);
|
|
7017
7060
|
held = null;
|
|
7018
7061
|
if (sealed) yield sealed;
|
|
7019
|
-
|
|
7062
|
+
cumulativeUsage = readUsage(ev);
|
|
7063
|
+
usage = cumulativeUsage ? codexUsageDelta(cumulativeUsage, ctx.usageBaseline ?? null) : void 0;
|
|
7020
7064
|
ok = true;
|
|
7021
7065
|
settled = true;
|
|
7022
7066
|
break;
|
|
@@ -7042,6 +7086,15 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
7042
7086
|
if (sealed) yield sealed;
|
|
7043
7087
|
reason = "no_terminal";
|
|
7044
7088
|
}
|
|
7089
|
+
if (ok && cumulativeUsage && threadIdForSession) {
|
|
7090
|
+
const closing = encodeSession3({
|
|
7091
|
+
threadId: threadIdForSession,
|
|
7092
|
+
cwd: ctx.cwd ?? "",
|
|
7093
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
7094
|
+
usageBaseline: cumulativeUsage
|
|
7095
|
+
});
|
|
7096
|
+
yield { type: "session", state: closing };
|
|
7097
|
+
}
|
|
7045
7098
|
const resolvedConfig = ctx.resolvedReasoningEffort ? { reasoningEffort: ctx.resolvedReasoningEffort } : void 0;
|
|
7046
7099
|
yield {
|
|
7047
7100
|
type: "result",
|
|
@@ -7340,6 +7393,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
7340
7393
|
const decision = decideResume3(req.session, directory);
|
|
7341
7394
|
const resumeThreadId = "resume" in decision ? decision.resume : null;
|
|
7342
7395
|
const threadPromptFingerprint = "resume" in decision ? decision.promptFingerprint : null;
|
|
7396
|
+
const threadUsageBaseline = "resume" in decision ? decision.usageBaseline : null;
|
|
7343
7397
|
if ("fresh" in decision && decision.reason === "cwd_mismatch") {
|
|
7344
7398
|
deps.onWarn?.(
|
|
7345
7399
|
"codex adapter: stored session directory no longer matches the current environment \u2014 starting a fresh thread (SJ527-analogue guard)",
|
|
@@ -7399,6 +7453,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
7399
7453
|
// was actually sent.
|
|
7400
7454
|
promptFingerprint: spec.promptRidesInput ? spec.promptFingerprint : threadPromptFingerprint,
|
|
7401
7455
|
storedState: req.session,
|
|
7456
|
+
usageBaseline: threadUsageBaseline,
|
|
7402
7457
|
// CT601: Codex reports no model in-stream, so record what the thread was
|
|
7403
7458
|
// started with (null on the default token). Same for the reasoning effort.
|
|
7404
7459
|
resolvedModel: spec.model,
|
|
@@ -7489,9 +7544,9 @@ var OP_FAILURE = {
|
|
|
7489
7544
|
message: "files.read returned more than the result ceiling"
|
|
7490
7545
|
}
|
|
7491
7546
|
};
|
|
7492
|
-
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT)) => ({
|
|
7547
|
+
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT), usageBaseline = null) => ({
|
|
7493
7548
|
type: "session",
|
|
7494
|
-
state: encodeSession3({ threadId, cwd, promptFingerprint }),
|
|
7549
|
+
state: encodeSession3({ threadId, cwd, promptFingerprint, usageBaseline }),
|
|
7495
7550
|
...degraded ? { degraded: true } : {}
|
|
7496
7551
|
});
|
|
7497
7552
|
var CODEX_CONFORMANCE_FIXTURES = [
|
|
@@ -7519,6 +7574,16 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7519
7574
|
expected: [
|
|
7520
7575
|
sessionEvent3(NEW_THREAD_ID),
|
|
7521
7576
|
{ type: "text", body: "Hello there.", terminal: true },
|
|
7577
|
+
// CT1645: the closing session write — the thread's ending totals, recorded
|
|
7578
|
+
// as the baseline the NEXT turn subtracts. This is a fresh thread, so the
|
|
7579
|
+
// `result` usage below is the frame verbatim (nothing to subtract yet);
|
|
7580
|
+
// what makes it per-turn is this figure being carried into turn two.
|
|
7581
|
+
sessionEvent3(NEW_THREAD_ID, DIR2, false, fingerprintPrompt(PROMPT), {
|
|
7582
|
+
inputTokens: 100,
|
|
7583
|
+
outputTokens: 50,
|
|
7584
|
+
cacheReadTokens: 20,
|
|
7585
|
+
cacheCreationTokens: 5
|
|
7586
|
+
}),
|
|
7522
7587
|
{
|
|
7523
7588
|
type: "result",
|
|
7524
7589
|
ok: true,
|
|
@@ -8244,7 +8309,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
8244
8309
|
session: encodeSession3({
|
|
8245
8310
|
threadId: "th1",
|
|
8246
8311
|
cwd: DIR2,
|
|
8247
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
8312
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
8313
|
+
usageBaseline: null
|
|
8248
8314
|
})
|
|
8249
8315
|
}),
|
|
8250
8316
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -8289,7 +8355,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
8289
8355
|
session: encodeSession3({
|
|
8290
8356
|
threadId: "th1",
|
|
8291
8357
|
cwd: DIR2,
|
|
8292
|
-
promptFingerprint: fingerprintPrompt("an older composed prompt")
|
|
8358
|
+
promptFingerprint: fingerprintPrompt("an older composed prompt"),
|
|
8359
|
+
usageBaseline: null
|
|
8293
8360
|
})
|
|
8294
8361
|
}),
|
|
8295
8362
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -8314,7 +8381,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
8314
8381
|
session: encodeSession3({
|
|
8315
8382
|
threadId: "old",
|
|
8316
8383
|
cwd: "/env/gone",
|
|
8317
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
8384
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
8385
|
+
usageBaseline: null
|
|
8318
8386
|
})
|
|
8319
8387
|
}),
|
|
8320
8388
|
nativeStream: [
|
|
@@ -8421,12 +8489,12 @@ async function performAct(acts, act) {
|
|
|
8421
8489
|
);
|
|
8422
8490
|
} catch (err) {
|
|
8423
8491
|
if (err instanceof ApiError) {
|
|
8424
|
-
if (err.status === 409) {
|
|
8492
|
+
if (err.status === 409 && apiErrorCode(err) === "no_active_turn") {
|
|
8425
8493
|
return toolError(
|
|
8426
8494
|
"No active turn: this turn has already settled, so the act was not performed."
|
|
8427
8495
|
);
|
|
8428
8496
|
}
|
|
8429
|
-
return toolError(`The act was refused (${err.status}): ${err
|
|
8497
|
+
return toolError(`The act was refused (${err.status}): ${apiErrorMessage(err)}`);
|
|
8430
8498
|
}
|
|
8431
8499
|
const message = err instanceof Error ? err.message : String(err);
|
|
8432
8500
|
return toolError(
|
|
@@ -9480,6 +9548,7 @@ var DEFAULT_LEASE_RENEWAL_MS = 3e4;
|
|
|
9480
9548
|
function initialOutcome() {
|
|
9481
9549
|
return {
|
|
9482
9550
|
sessionWritten: false,
|
|
9551
|
+
lastSessionStateWritten: null,
|
|
9483
9552
|
sessionDegraded: false,
|
|
9484
9553
|
sessionWriteRejected: false,
|
|
9485
9554
|
okResult: false,
|
|
@@ -10269,8 +10338,9 @@ var TurnExecution = class {
|
|
|
10269
10338
|
if (event.type === "session") {
|
|
10270
10339
|
o.latestSessionState = event.state;
|
|
10271
10340
|
if (event.degraded) o.sessionDegraded = true;
|
|
10272
|
-
if (
|
|
10341
|
+
if (o.lastSessionStateWritten !== event.state) {
|
|
10273
10342
|
o.sessionWritten = true;
|
|
10343
|
+
o.lastSessionStateWritten = event.state;
|
|
10274
10344
|
try {
|
|
10275
10345
|
await this.opts.api.setActiveRun(
|
|
10276
10346
|
workspaceId,
|
package/dist/runtime.js
CHANGED
|
@@ -2211,6 +2211,14 @@ function apiErrorCode(err) {
|
|
|
2211
2211
|
const body = err.body;
|
|
2212
2212
|
return typeof body === "object" && body !== null && typeof body.error === "string" ? body.error : null;
|
|
2213
2213
|
}
|
|
2214
|
+
function apiErrorMessage(err) {
|
|
2215
|
+
const body = err instanceof ApiError ? err.body : void 0;
|
|
2216
|
+
if (body !== null && typeof body === "object") {
|
|
2217
|
+
const message = body.message;
|
|
2218
|
+
if (typeof message === "string" && message.length > 0) return message;
|
|
2219
|
+
}
|
|
2220
|
+
return err instanceof Error ? err.message : String(err);
|
|
2221
|
+
}
|
|
2214
2222
|
function leaseRefusal(err) {
|
|
2215
2223
|
const code = apiErrorCode(err);
|
|
2216
2224
|
if (code && LEASE_REFUSALS.has(code)) return code;
|
|
@@ -6252,6 +6260,16 @@ function readUsage(ev) {
|
|
|
6252
6260
|
cacheCreationTokens: num(usage.cache_write_input_tokens)
|
|
6253
6261
|
};
|
|
6254
6262
|
}
|
|
6263
|
+
function codexUsageDelta(cumulative, baseline) {
|
|
6264
|
+
if (!baseline) return cumulative;
|
|
6265
|
+
const sub = (a, b) => Math.max(0, a - b);
|
|
6266
|
+
return {
|
|
6267
|
+
inputTokens: sub(cumulative.inputTokens, baseline.inputTokens),
|
|
6268
|
+
outputTokens: sub(cumulative.outputTokens, baseline.outputTokens),
|
|
6269
|
+
cacheReadTokens: sub(cumulative.cacheReadTokens, baseline.cacheReadTokens),
|
|
6270
|
+
cacheCreationTokens: sub(cumulative.cacheCreationTokens, baseline.cacheCreationTokens)
|
|
6271
|
+
};
|
|
6272
|
+
}
|
|
6255
6273
|
function toStatus(v) {
|
|
6256
6274
|
return v === "completed" || v === "failed" ? v : "in_progress";
|
|
6257
6275
|
}
|
|
@@ -6326,9 +6344,26 @@ function decideResume3(stored, currentCwd) {
|
|
|
6326
6344
|
}
|
|
6327
6345
|
return {
|
|
6328
6346
|
resume: state.threadId,
|
|
6329
|
-
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null
|
|
6347
|
+
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null,
|
|
6348
|
+
usageBaseline: readUsageBaseline(state.usageBaseline)
|
|
6330
6349
|
};
|
|
6331
6350
|
}
|
|
6351
|
+
function readUsageBaseline(raw) {
|
|
6352
|
+
if (!raw || typeof raw !== "object") return null;
|
|
6353
|
+
const rec = raw;
|
|
6354
|
+
const read = (key) => {
|
|
6355
|
+
const v = rec[key];
|
|
6356
|
+
return typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : null;
|
|
6357
|
+
};
|
|
6358
|
+
const inputTokens = read("inputTokens");
|
|
6359
|
+
const outputTokens = read("outputTokens");
|
|
6360
|
+
const cacheReadTokens = read("cacheReadTokens");
|
|
6361
|
+
const cacheCreationTokens = read("cacheCreationTokens");
|
|
6362
|
+
if (inputTokens === null || outputTokens === null || cacheReadTokens === null || cacheCreationTokens === null) {
|
|
6363
|
+
return null;
|
|
6364
|
+
}
|
|
6365
|
+
return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
|
|
6366
|
+
}
|
|
6332
6367
|
|
|
6333
6368
|
// packages/agent-runtime/src/codex/loop.ts
|
|
6334
6369
|
async function* decodeCodexStream(events, ctx) {
|
|
@@ -6340,6 +6375,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6340
6375
|
let ok = false;
|
|
6341
6376
|
let reason;
|
|
6342
6377
|
let usage;
|
|
6378
|
+
let cumulativeUsage;
|
|
6379
|
+
let threadIdForSession = ctx.resumedThreadId;
|
|
6343
6380
|
let settled = false;
|
|
6344
6381
|
function* flushInterim() {
|
|
6345
6382
|
const sealed = sealHeld2(held, false);
|
|
@@ -6350,11 +6387,17 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6350
6387
|
if (ctx.signal.aborted) return;
|
|
6351
6388
|
if (ev.type === "thread.started") {
|
|
6352
6389
|
const threadId = readThreadId(ev);
|
|
6390
|
+
if (threadId) threadIdForSession = threadId;
|
|
6353
6391
|
if (threadId && !sessionEmitted) {
|
|
6354
6392
|
const state = encodeSession3({
|
|
6355
6393
|
threadId,
|
|
6356
6394
|
cwd: ctx.cwd ?? "",
|
|
6357
|
-
promptFingerprint: ctx.promptFingerprint ?? null
|
|
6395
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
6396
|
+
// CT1645: the baseline this turn INHERITED, carried through unchanged.
|
|
6397
|
+
// This early write exists so a turn that dies mid-stream still leaves
|
|
6398
|
+
// the thread id recorded; it cannot yet know what this turn will spend.
|
|
6399
|
+
// The closing write below records the new baseline.
|
|
6400
|
+
usageBaseline: ctx.usageBaseline ?? null
|
|
6358
6401
|
});
|
|
6359
6402
|
if (threadId !== ctx.resumedThreadId || state !== ctx.storedState) {
|
|
6360
6403
|
sessionEmitted = true;
|
|
@@ -6429,7 +6472,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6429
6472
|
const sealed = sealHeld2(held, true);
|
|
6430
6473
|
held = null;
|
|
6431
6474
|
if (sealed) yield sealed;
|
|
6432
|
-
|
|
6475
|
+
cumulativeUsage = readUsage(ev);
|
|
6476
|
+
usage = cumulativeUsage ? codexUsageDelta(cumulativeUsage, ctx.usageBaseline ?? null) : void 0;
|
|
6433
6477
|
ok = true;
|
|
6434
6478
|
settled = true;
|
|
6435
6479
|
break;
|
|
@@ -6455,6 +6499,15 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6455
6499
|
if (sealed) yield sealed;
|
|
6456
6500
|
reason = "no_terminal";
|
|
6457
6501
|
}
|
|
6502
|
+
if (ok && cumulativeUsage && threadIdForSession) {
|
|
6503
|
+
const closing = encodeSession3({
|
|
6504
|
+
threadId: threadIdForSession,
|
|
6505
|
+
cwd: ctx.cwd ?? "",
|
|
6506
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
6507
|
+
usageBaseline: cumulativeUsage
|
|
6508
|
+
});
|
|
6509
|
+
yield { type: "session", state: closing };
|
|
6510
|
+
}
|
|
6458
6511
|
const resolvedConfig = ctx.resolvedReasoningEffort ? { reasoningEffort: ctx.resolvedReasoningEffort } : void 0;
|
|
6459
6512
|
yield {
|
|
6460
6513
|
type: "result",
|
|
@@ -6753,6 +6806,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
6753
6806
|
const decision = decideResume3(req.session, directory);
|
|
6754
6807
|
const resumeThreadId = "resume" in decision ? decision.resume : null;
|
|
6755
6808
|
const threadPromptFingerprint = "resume" in decision ? decision.promptFingerprint : null;
|
|
6809
|
+
const threadUsageBaseline = "resume" in decision ? decision.usageBaseline : null;
|
|
6756
6810
|
if ("fresh" in decision && decision.reason === "cwd_mismatch") {
|
|
6757
6811
|
deps.onWarn?.(
|
|
6758
6812
|
"codex adapter: stored session directory no longer matches the current environment \u2014 starting a fresh thread (SJ527-analogue guard)",
|
|
@@ -6812,6 +6866,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
6812
6866
|
// was actually sent.
|
|
6813
6867
|
promptFingerprint: spec.promptRidesInput ? spec.promptFingerprint : threadPromptFingerprint,
|
|
6814
6868
|
storedState: req.session,
|
|
6869
|
+
usageBaseline: threadUsageBaseline,
|
|
6815
6870
|
// CT601: Codex reports no model in-stream, so record what the thread was
|
|
6816
6871
|
// started with (null on the default token). Same for the reasoning effort.
|
|
6817
6872
|
resolvedModel: spec.model,
|
|
@@ -6902,9 +6957,9 @@ var OP_FAILURE = {
|
|
|
6902
6957
|
message: "files.read returned more than the result ceiling"
|
|
6903
6958
|
}
|
|
6904
6959
|
};
|
|
6905
|
-
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT)) => ({
|
|
6960
|
+
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT), usageBaseline = null) => ({
|
|
6906
6961
|
type: "session",
|
|
6907
|
-
state: encodeSession3({ threadId, cwd, promptFingerprint }),
|
|
6962
|
+
state: encodeSession3({ threadId, cwd, promptFingerprint, usageBaseline }),
|
|
6908
6963
|
...degraded ? { degraded: true } : {}
|
|
6909
6964
|
});
|
|
6910
6965
|
var CODEX_CONFORMANCE_FIXTURES = [
|
|
@@ -6932,6 +6987,16 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
6932
6987
|
expected: [
|
|
6933
6988
|
sessionEvent3(NEW_THREAD_ID),
|
|
6934
6989
|
{ type: "text", body: "Hello there.", terminal: true },
|
|
6990
|
+
// CT1645: the closing session write — the thread's ending totals, recorded
|
|
6991
|
+
// as the baseline the NEXT turn subtracts. This is a fresh thread, so the
|
|
6992
|
+
// `result` usage below is the frame verbatim (nothing to subtract yet);
|
|
6993
|
+
// what makes it per-turn is this figure being carried into turn two.
|
|
6994
|
+
sessionEvent3(NEW_THREAD_ID, DIR2, false, fingerprintPrompt(PROMPT), {
|
|
6995
|
+
inputTokens: 100,
|
|
6996
|
+
outputTokens: 50,
|
|
6997
|
+
cacheReadTokens: 20,
|
|
6998
|
+
cacheCreationTokens: 5
|
|
6999
|
+
}),
|
|
6935
7000
|
{
|
|
6936
7001
|
type: "result",
|
|
6937
7002
|
ok: true,
|
|
@@ -7657,7 +7722,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7657
7722
|
session: encodeSession3({
|
|
7658
7723
|
threadId: "th1",
|
|
7659
7724
|
cwd: DIR2,
|
|
7660
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
7725
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
7726
|
+
usageBaseline: null
|
|
7661
7727
|
})
|
|
7662
7728
|
}),
|
|
7663
7729
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -7702,7 +7768,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7702
7768
|
session: encodeSession3({
|
|
7703
7769
|
threadId: "th1",
|
|
7704
7770
|
cwd: DIR2,
|
|
7705
|
-
promptFingerprint: fingerprintPrompt("an older composed prompt")
|
|
7771
|
+
promptFingerprint: fingerprintPrompt("an older composed prompt"),
|
|
7772
|
+
usageBaseline: null
|
|
7706
7773
|
})
|
|
7707
7774
|
}),
|
|
7708
7775
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -7727,7 +7794,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7727
7794
|
session: encodeSession3({
|
|
7728
7795
|
threadId: "old",
|
|
7729
7796
|
cwd: "/env/gone",
|
|
7730
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
7797
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
7798
|
+
usageBaseline: null
|
|
7731
7799
|
})
|
|
7732
7800
|
}),
|
|
7733
7801
|
nativeStream: [
|
|
@@ -7844,12 +7912,12 @@ async function performAct(acts, act) {
|
|
|
7844
7912
|
);
|
|
7845
7913
|
} catch (err) {
|
|
7846
7914
|
if (err instanceof ApiError) {
|
|
7847
|
-
if (err.status === 409) {
|
|
7915
|
+
if (err.status === 409 && apiErrorCode(err) === "no_active_turn") {
|
|
7848
7916
|
return toolError(
|
|
7849
7917
|
"No active turn: this turn has already settled, so the act was not performed."
|
|
7850
7918
|
);
|
|
7851
7919
|
}
|
|
7852
|
-
return toolError(`The act was refused (${err.status}): ${err
|
|
7920
|
+
return toolError(`The act was refused (${err.status}): ${apiErrorMessage(err)}`);
|
|
7853
7921
|
}
|
|
7854
7922
|
const message = err instanceof Error ? err.message : String(err);
|
|
7855
7923
|
return toolError(
|
|
@@ -8903,6 +8971,7 @@ var DEFAULT_LEASE_RENEWAL_MS = 3e4;
|
|
|
8903
8971
|
function initialOutcome() {
|
|
8904
8972
|
return {
|
|
8905
8973
|
sessionWritten: false,
|
|
8974
|
+
lastSessionStateWritten: null,
|
|
8906
8975
|
sessionDegraded: false,
|
|
8907
8976
|
sessionWriteRejected: false,
|
|
8908
8977
|
okResult: false,
|
|
@@ -9692,8 +9761,9 @@ var TurnExecution = class {
|
|
|
9692
9761
|
if (event.type === "session") {
|
|
9693
9762
|
o.latestSessionState = event.state;
|
|
9694
9763
|
if (event.degraded) o.sessionDegraded = true;
|
|
9695
|
-
if (
|
|
9764
|
+
if (o.lastSessionStateWritten !== event.state) {
|
|
9696
9765
|
o.sessionWritten = true;
|
|
9766
|
+
o.lastSessionStateWritten = event.state;
|
|
9697
9767
|
try {
|
|
9698
9768
|
await this.opts.api.setActiveRun(
|
|
9699
9769
|
workspaceId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.116",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Cabane Companion (headless): connect a coding agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prepublishOnly": "pnpm build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
33
|
-
"@openai/codex-sdk": "0.
|
|
32
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.280",
|
|
33
|
+
"@openai/codex-sdk": "0.155.1",
|
|
34
34
|
"@hono/node-server": "1.19.14",
|
|
35
35
|
"@inquirer/prompts": "7.10.1",
|
|
36
36
|
"commander": "12.1.0",
|