@ordewell/core 0.10.9 → 0.10.10
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/{IFileSystem-C9W5mRYA.d.mts → IFileSystem-1PqRCjhu.d.mts} +21 -3
- package/dist/{IFileSystem-B8qRNC_6.d.ts → IFileSystem-lTRL_G9Z.d.ts} +21 -3
- package/dist/{ModeResolver-C1PN5FYG.d.mts → ModeResolver-6TQXVsde.d.mts} +1 -1
- package/dist/{ModeResolver-CaPnoU8N.d.ts → ModeResolver-CoJAJD-f.d.ts} +1 -1
- package/dist/{Task-hFfRS9rN.d.mts → Task-CfBM0wkV.d.mts} +94 -21
- package/dist/{Task-hFfRS9rN.d.ts → Task-CfBM0wkV.d.ts} +94 -21
- package/dist/{chunk-H7QX32BH.mjs → chunk-24EL4Z2W.mjs} +2 -2
- package/dist/{chunk-O6LQU3W6.mjs → chunk-ESKK5I4F.mjs} +138 -21
- package/dist/chunk-ESKK5I4F.mjs.map +1 -0
- package/dist/{chunk-LTHKFBKM.mjs → chunk-KWS3VEER.mjs} +3 -3
- package/dist/{chunk-EEE2GBLG.mjs → chunk-PFH7WFIB.mjs} +1 -1
- package/dist/chunk-PFH7WFIB.mjs.map +1 -0
- package/dist/index.d.mts +119 -17
- package/dist/index.d.ts +119 -17
- package/dist/index.js +521 -88
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +397 -72
- package/dist/index.mjs.map +1 -1
- package/dist/parsing.d.mts +2 -2
- package/dist/parsing.d.ts +2 -2
- package/dist/parsing.js.map +1 -1
- package/dist/parsing.mjs +3 -3
- package/dist/plan-utils.d.mts +4 -4
- package/dist/plan-utils.d.ts +4 -4
- package/dist/plan-utils.js +144 -18
- package/dist/plan-utils.js.map +1 -1
- package/dist/plan-utils.mjs +22 -4
- package/dist/{runSettingsText-rLoYQlUH.d.mts → runSettingsText-C1i9wBG1.d.mts} +26 -15
- package/dist/{runSettingsText-CGKX3aeV.d.ts → runSettingsText-CWNrmF5U.d.ts} +26 -15
- package/dist/testing.d.mts +7 -2
- package/dist/testing.d.ts +7 -2
- package/dist/testing.js +11 -0
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +12 -1
- package/dist/testing.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EEE2GBLG.mjs.map +0 -1
- package/dist/chunk-O6LQU3W6.mjs.map +0 -1
- /package/dist/{chunk-H7QX32BH.mjs.map → chunk-24EL4Z2W.mjs.map} +0 -0
- /package/dist/{chunk-LTHKFBKM.mjs.map → chunk-KWS3VEER.mjs.map} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
looksLikePlanAttempt,
|
|
3
3
|
parsePlanJson,
|
|
4
4
|
validatePlanTasks
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KWS3VEER.mjs";
|
|
6
6
|
import {
|
|
7
7
|
ACT_RISK,
|
|
8
8
|
AUTORUN_RISK,
|
|
@@ -38,7 +38,10 @@ import {
|
|
|
38
38
|
canSplitTask,
|
|
39
39
|
capConflictFiles,
|
|
40
40
|
classifyOutcome,
|
|
41
|
+
contextMeterText,
|
|
42
|
+
contextMeterTitle,
|
|
41
43
|
continuability,
|
|
44
|
+
costText,
|
|
42
45
|
countedSessionCost,
|
|
43
46
|
dependentsNotice,
|
|
44
47
|
diffRows,
|
|
@@ -49,6 +52,8 @@ import {
|
|
|
49
52
|
executionSummary,
|
|
50
53
|
followTaskLog,
|
|
51
54
|
followTurn,
|
|
55
|
+
formatCost,
|
|
56
|
+
formatTokenCount,
|
|
52
57
|
fromTranscript,
|
|
53
58
|
hasHiddenDetail,
|
|
54
59
|
holdPrompt,
|
|
@@ -59,6 +64,7 @@ import {
|
|
|
59
64
|
markRequestFor,
|
|
60
65
|
markdownHtml,
|
|
61
66
|
markdownTokens,
|
|
67
|
+
modelCostTitle,
|
|
62
68
|
namedRepos,
|
|
63
69
|
newTaskFields,
|
|
64
70
|
normalizeAgentArgs,
|
|
@@ -90,6 +96,7 @@ import {
|
|
|
90
96
|
skippedLabel,
|
|
91
97
|
startAttemptUsage,
|
|
92
98
|
stopTurn,
|
|
99
|
+
subagentCostTitle,
|
|
93
100
|
summarizeToolCall,
|
|
94
101
|
supervisorSummary,
|
|
95
102
|
surfacePlan,
|
|
@@ -103,6 +110,7 @@ import {
|
|
|
103
110
|
taskStartedNotice,
|
|
104
111
|
taskStatusKind,
|
|
105
112
|
taskUsageSummary,
|
|
113
|
+
tasksTotalText,
|
|
106
114
|
textHasTaskOps,
|
|
107
115
|
titledRefs,
|
|
108
116
|
toolHeadline,
|
|
@@ -110,8 +118,9 @@ import {
|
|
|
110
118
|
unsendAll,
|
|
111
119
|
unsendLatest,
|
|
112
120
|
usageLine,
|
|
121
|
+
usageText,
|
|
113
122
|
validateTaskEdit
|
|
114
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-ESKK5I4F.mjs";
|
|
115
124
|
import {
|
|
116
125
|
PLAN_ENVELOPE_KEY,
|
|
117
126
|
PlanParseError,
|
|
@@ -137,7 +146,7 @@ import {
|
|
|
137
146
|
runnerModesFrom,
|
|
138
147
|
stripTrailingCommas,
|
|
139
148
|
unavailableTaskModeMessage
|
|
140
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-24EL4Z2W.mjs";
|
|
141
150
|
import {
|
|
142
151
|
SELF_REPO,
|
|
143
152
|
absorbRemoval,
|
|
@@ -190,7 +199,7 @@ import {
|
|
|
190
199
|
waitsForApproval,
|
|
191
200
|
waitsForReset,
|
|
192
201
|
walkPlan
|
|
193
|
-
} from "./chunk-
|
|
202
|
+
} from "./chunk-PFH7WFIB.mjs";
|
|
194
203
|
|
|
195
204
|
// src/models/TaskLog.ts
|
|
196
205
|
var HEAD_LINES = 60;
|
|
@@ -6028,7 +6037,7 @@ var RunnerApprovals = class {
|
|
|
6028
6037
|
},
|
|
6029
6038
|
stop: (sessionId) => {
|
|
6030
6039
|
this.denySession(sessionId);
|
|
6031
|
-
runner.stop(sessionId);
|
|
6040
|
+
return runner.stop(sessionId);
|
|
6032
6041
|
},
|
|
6033
6042
|
stopAll: () => {
|
|
6034
6043
|
this.approvals.clear(isRunnerApproval);
|
|
@@ -9889,6 +9898,14 @@ function canUseToolAnswer({ input, suggestions }, decision) {
|
|
|
9889
9898
|
}
|
|
9890
9899
|
var MODEL_COMMAND = "model";
|
|
9891
9900
|
var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["Agent", "Task"]);
|
|
9901
|
+
var VARIANT_SUFFIX = /^(.*?)(\[[^\]]*\])?$/;
|
|
9902
|
+
function sameModel(a, b) {
|
|
9903
|
+
if (a === void 0 || b === void 0) return false;
|
|
9904
|
+
if (a === b) return true;
|
|
9905
|
+
const [, aBase, aVariant] = VARIANT_SUFFIX.exec(a) ?? [];
|
|
9906
|
+
const [, bBase, bVariant] = VARIANT_SUFFIX.exec(b) ?? [];
|
|
9907
|
+
return aBase === bBase && (aVariant === void 0 || bVariant === void 0 || aVariant === bVariant);
|
|
9908
|
+
}
|
|
9892
9909
|
function usageRecord(usage, model, subagentId) {
|
|
9893
9910
|
const record = {
|
|
9894
9911
|
source: "claude-code",
|
|
@@ -9897,6 +9914,7 @@ function usageRecord(usage, model, subagentId) {
|
|
|
9897
9914
|
if (model) record.model = model;
|
|
9898
9915
|
if (usage.output_tokens !== void 0) record.outputTokens = usage.output_tokens;
|
|
9899
9916
|
if (subagentId) record.subagentId = subagentId;
|
|
9917
|
+
else if (record.inputTokens !== void 0) record.contextTokens = record.inputTokens + (record.outputTokens ?? 0);
|
|
9900
9918
|
return record;
|
|
9901
9919
|
}
|
|
9902
9920
|
function subagentFinalCall(result) {
|
|
@@ -9946,16 +9964,27 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
9946
9964
|
replyRuns = new ReplyRuns();
|
|
9947
9965
|
/** The model answering the planner's current message, and the message's id, as its `message_start` named them. */
|
|
9948
9966
|
plannerModel;
|
|
9967
|
+
/**
|
|
9968
|
+
* The id the turn runs as, as `init` names it. A `[1m]` variant is the
|
|
9969
|
+
* selected id, while a message names the API's canonical id without it.
|
|
9970
|
+
*/
|
|
9971
|
+
sessionModel;
|
|
9972
|
+
billing;
|
|
9949
9973
|
streamingMessage;
|
|
9950
9974
|
/** The message the last `assistant` line was part of, and how many of its blocks the lines have carried. */
|
|
9951
9975
|
lineMessage = null;
|
|
9952
9976
|
/**
|
|
9953
|
-
*
|
|
9954
|
-
*
|
|
9955
|
-
*
|
|
9977
|
+
* What has been counted of the session's running cost: a resume starts from
|
|
9978
|
+
* it, and it is undefined without a kept count — the next result then only
|
|
9979
|
+
* sets the baseline, since the CLI restores spend from turns before it. It
|
|
9980
|
+
* grows by what each result is counted for, never by a total that includes
|
|
9981
|
+
* cost the runner marked unknown, so that spend can be counted when its basis
|
|
9982
|
+
* is reported; and it never lowers, since counted dollars are not un-spent.
|
|
9956
9983
|
*/
|
|
9957
9984
|
reportedCostUsd = 0;
|
|
9958
9985
|
reportedModelCostUsd = /* @__PURE__ */ new Map();
|
|
9986
|
+
/** What this turn's streamed calls already reported, so its result only adds what did not stream. */
|
|
9987
|
+
turnCallUsage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
|
|
9959
9988
|
/**
|
|
9960
9989
|
* Subagents started and not yet finished, keyed by the `Agent` call's id.
|
|
9961
9990
|
* Kept across turns: a backgrounded one reports after its turn has ended.
|
|
@@ -10042,6 +10071,14 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10042
10071
|
if (!sessionId || this.reportedCostUsd === void 0) return null;
|
|
10043
10072
|
return { sessionId, usd: this.reportedCostUsd, modelUsd: Object.fromEntries(this.reportedModelCostUsd) };
|
|
10044
10073
|
}
|
|
10074
|
+
/**
|
|
10075
|
+
* A cleared conversation's totals start again from zero, so what follows is
|
|
10076
|
+
* all new spend, even for a resume that had no count kept.
|
|
10077
|
+
*/
|
|
10078
|
+
restartCount() {
|
|
10079
|
+
this.reportedCostUsd = 0;
|
|
10080
|
+
this.reportedModelCostUsd = /* @__PURE__ */ new Map();
|
|
10081
|
+
}
|
|
10045
10082
|
/** A count kept for another session says nothing of this one's. */
|
|
10046
10083
|
countFrom(sessionId, counted) {
|
|
10047
10084
|
const known = counted?.sessionId === sessionId ? counted : void 0;
|
|
@@ -10115,11 +10152,10 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10115
10152
|
* the alias resolves to now; that id is pinned before the first turn.
|
|
10116
10153
|
*/
|
|
10117
10154
|
async handshake(opts) {
|
|
10118
|
-
if (opts.kind !== "task") return;
|
|
10119
10155
|
const initialized = (await this.control({ subtype: "initialize" }, MODEL_PIN_TIMEOUT_MS))?.response;
|
|
10120
10156
|
this.listedCommands = initialized?.commands ?? [];
|
|
10121
10157
|
this.listedModels = initialized?.models ?? [];
|
|
10122
|
-
if (opts.flags.permissionMode !== "plan" || !opts.model) return;
|
|
10158
|
+
if (opts.kind !== "task" || opts.flags.permissionMode !== "plan" || !opts.model) return;
|
|
10123
10159
|
const resolved = initialized?.models?.find((m) => m.value === opts.model)?.resolvedModel;
|
|
10124
10160
|
if (resolved && resolved !== opts.model) await this.control({ subtype: "set_model", model: resolved }, MODEL_PIN_TIMEOUT_MS);
|
|
10125
10161
|
}
|
|
@@ -10160,6 +10196,15 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10160
10196
|
this.interruptRequested = true;
|
|
10161
10197
|
return (await this.control({ subtype: "interrupt" }, timeoutMs))?.subtype === "success";
|
|
10162
10198
|
}
|
|
10199
|
+
/**
|
|
10200
|
+
* On stdin's end the CLI exits by itself once its turn has closed, and only
|
|
10201
|
+
* an exit of its own saves the session's running totals for a `--resume` to
|
|
10202
|
+
* restore (checked on 2.1.303: about a second later, code 0, or 1 after an
|
|
10203
|
+
* interrupted turn).
|
|
10204
|
+
*/
|
|
10205
|
+
endInput() {
|
|
10206
|
+
this.process?.stdin?.end();
|
|
10207
|
+
}
|
|
10163
10208
|
/**
|
|
10164
10209
|
* A `user` line written mid-turn is Claude Code's own queue (ADR-0023): the
|
|
10165
10210
|
* CLI attaches it to the next tool result, or runs it as a turn of its own
|
|
@@ -10247,6 +10292,7 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10247
10292
|
this.resultHeld = false;
|
|
10248
10293
|
this.turnClosed = false;
|
|
10249
10294
|
this.clearFollowOnTimer();
|
|
10295
|
+
this.plannerModel = void 0;
|
|
10250
10296
|
}
|
|
10251
10297
|
/**
|
|
10252
10298
|
* The echo of a steered message: the model has it. After a closed turn it
|
|
@@ -10301,6 +10347,8 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10301
10347
|
this.permissions.withdraw(msg.request_id, emit);
|
|
10302
10348
|
return;
|
|
10303
10349
|
case "control_response": {
|
|
10350
|
+
const account = msg.response?.response?.account;
|
|
10351
|
+
if (account) this.reportBilling(account.apiKeySource, account.subscriptionType, emit);
|
|
10304
10352
|
const requestId = msg.response?.request_id;
|
|
10305
10353
|
if (requestId) this.pendingControl.get(requestId)?.(msg.response ?? null);
|
|
10306
10354
|
return;
|
|
@@ -10344,12 +10392,24 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10344
10392
|
emit({ type: "tool_result", id, name: "", output: diff || output, success: block.is_error !== true, subagentId });
|
|
10345
10393
|
}
|
|
10346
10394
|
return;
|
|
10395
|
+
// `/clear` (and `/reset`, `/new`) emit this top-level line before their
|
|
10396
|
+
// own result, and a task's chat can send them. The CLI's totals restart.
|
|
10397
|
+
case "conversation_reset": {
|
|
10398
|
+
if (subagentId) return;
|
|
10399
|
+
this.restartCount();
|
|
10400
|
+
const resetModel = this.sessionModel ?? (this.plannerModel !== "<synthetic>" ? this.plannerModel : void 0);
|
|
10401
|
+
emit({ type: "usage", record: { source: "claude-code", ...resetModel ? { model: resetModel } : {}, compacted: true } });
|
|
10402
|
+
return;
|
|
10403
|
+
}
|
|
10347
10404
|
case "system":
|
|
10405
|
+
if (subagentId && (msg.subtype === "init" || msg.subtype === "compact_boundary")) return;
|
|
10348
10406
|
if (msg.subtype === "init") {
|
|
10349
10407
|
this.clearFollowOnTimer();
|
|
10350
10408
|
if (this.refuseOtherMode(msg, emit)) return;
|
|
10409
|
+
if (msg.model && msg.model !== "<synthetic>") this.sessionModel = msg.model;
|
|
10351
10410
|
this.readLoaded(msg, emit);
|
|
10352
10411
|
this.followModel(msg.model, emit);
|
|
10412
|
+
this.reportBilling(msg.apiKeySource, void 0, emit);
|
|
10353
10413
|
}
|
|
10354
10414
|
if (msg.subtype === "commands_changed" && Array.isArray(msg.commands)) this.listedCommands = msg.commands;
|
|
10355
10415
|
if (msg.subtype === "compact_boundary") {
|
|
@@ -10360,6 +10420,8 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10360
10420
|
...typeof meta?.pre_tokens === "number" ? { preTokens: meta.pre_tokens } : {},
|
|
10361
10421
|
...typeof meta?.post_tokens === "number" ? { postTokens: meta.post_tokens } : {}
|
|
10362
10422
|
});
|
|
10423
|
+
const model = this.sessionModel ?? (this.plannerModel !== "<synthetic>" ? this.plannerModel : void 0);
|
|
10424
|
+
emit({ type: "usage", record: { source: "claude-code", ...model ? { model } : {}, compacted: true, ...typeof meta?.post_tokens === "number" ? { contextTokens: meta.post_tokens } : {} } });
|
|
10363
10425
|
}
|
|
10364
10426
|
if (msg.subtype === "background_tasks_changed" && Array.isArray(msg.tasks)) {
|
|
10365
10427
|
this.backgroundTaskCount = msg.tasks.length;
|
|
@@ -10371,6 +10433,7 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10371
10433
|
}
|
|
10372
10434
|
return;
|
|
10373
10435
|
case "result":
|
|
10436
|
+
if (subagentId) return;
|
|
10374
10437
|
this.reportSessionCost(msg, emit);
|
|
10375
10438
|
for (const command of this.modelCommands) command.turnsLeft = Math.max(0, command.turnsLeft - 1);
|
|
10376
10439
|
if (this.interruptRequested && (msg.is_error || msg.subtype !== "success")) {
|
|
@@ -10535,16 +10598,69 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10535
10598
|
*/
|
|
10536
10599
|
handleStreamEvent(event, emit) {
|
|
10537
10600
|
if (event.type === "message_start") {
|
|
10538
|
-
this.plannerModel = event.message?.model;
|
|
10601
|
+
this.plannerModel = this.modelId(event.message?.model);
|
|
10539
10602
|
this.streamingMessage = event.message?.id;
|
|
10540
10603
|
this.followModel(this.plannerModel, emit);
|
|
10541
|
-
} else if (event.type === "message_delta" && event.usage)
|
|
10542
|
-
|
|
10604
|
+
} else if (event.type === "message_delta" && event.usage) {
|
|
10605
|
+
const record = usageRecord(event.usage, this.plannerModel);
|
|
10606
|
+
this.turnCallUsage.inputTokens += record.inputTokens ?? 0;
|
|
10607
|
+
this.turnCallUsage.cachedInputTokens += record.cachedInputTokens ?? 0;
|
|
10608
|
+
this.turnCallUsage.outputTokens += record.outputTokens ?? 0;
|
|
10609
|
+
emit({ type: "usage", record });
|
|
10610
|
+
} else if (event.type === "content_block_delta" && event.delta?.type === "text_delta" && event.delta.text) {
|
|
10543
10611
|
this.replyRuns.delta(`${this.streamingMessage ?? ""}:${event.index ?? 0}`, event.delta.text, emit);
|
|
10544
10612
|
} else if (event.type === "content_block_delta" && event.delta?.type === "thinking_delta" && event.delta.thinking) {
|
|
10545
10613
|
emit({ type: "thinking_delta", text: event.delta.thinking });
|
|
10546
10614
|
}
|
|
10547
10615
|
}
|
|
10616
|
+
/**
|
|
10617
|
+
* The id a reported model runs as. `init` names the selected value — a
|
|
10618
|
+
* `[1m]` variant included — while a message names the API's canonical id
|
|
10619
|
+
* without it. Keeping the variant is what lets the meter find the window
|
|
10620
|
+
* `modelUsage` keys it by, and keeps that window off the base model.
|
|
10621
|
+
*/
|
|
10622
|
+
modelId(reported) {
|
|
10623
|
+
if (!reported) return void 0;
|
|
10624
|
+
if (!sameModel(this.sessionModel, reported)) return reported;
|
|
10625
|
+
return this.sessionModel?.includes("[") ? this.sessionModel : reported;
|
|
10626
|
+
}
|
|
10627
|
+
reportBilling(apiKeySource, plan, emit) {
|
|
10628
|
+
const type = apiKeySource ? apiKeySource === "none" ? "subscription" : "api-key" : plan ? "subscription" : void 0;
|
|
10629
|
+
if (!type) return;
|
|
10630
|
+
const knownPlan = plan ?? (this.billing?.type === type ? this.billing.plan : void 0);
|
|
10631
|
+
this.billing = { type, ...knownPlan ? { plan: knownPlan } : {} };
|
|
10632
|
+
emit({ type: "usage", record: { source: this.agentId, aggregate: true, sessionBilling: this.billing } });
|
|
10633
|
+
}
|
|
10634
|
+
/**
|
|
10635
|
+
* A turn's `result` states its own token sum. Every call that streamed its
|
|
10636
|
+
* `message_delta` usage has already reported, so only the remainder is added:
|
|
10637
|
+
* all of it when nothing streamed (a recording without partial messages), or
|
|
10638
|
+
* a lost call's share. It is a sum across calls, marked `aggregate` so it
|
|
10639
|
+
* never moves the meter — only a call says what the context was left at.
|
|
10640
|
+
*/
|
|
10641
|
+
reportUnstreamedUsage(msg, emit) {
|
|
10642
|
+
const { inputTokens: streamedInput, cachedInputTokens: streamedCached, outputTokens: streamedOutput } = this.turnCallUsage;
|
|
10643
|
+
this.turnCallUsage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
|
|
10644
|
+
if (!msg.usage) return;
|
|
10645
|
+
const models = Object.keys(msg.modelUsage ?? {});
|
|
10646
|
+
const model = this.plannerModel ?? this.mainModel ?? (models.length === 1 ? models[0] : void 0);
|
|
10647
|
+
const total = usageRecord(msg.usage, model);
|
|
10648
|
+
const inputTokens = (total.inputTokens ?? 0) - streamedInput;
|
|
10649
|
+
const cachedInputTokens = (total.cachedInputTokens ?? 0) - streamedCached;
|
|
10650
|
+
const outputTokens = (total.outputTokens ?? 0) - streamedOutput;
|
|
10651
|
+
if (inputTokens <= 0 && outputTokens <= 0) return;
|
|
10652
|
+
emit({
|
|
10653
|
+
type: "usage",
|
|
10654
|
+
record: {
|
|
10655
|
+
source: "claude-code",
|
|
10656
|
+
...model ? { model } : {},
|
|
10657
|
+
aggregate: true,
|
|
10658
|
+
...inputTokens > 0 ? { inputTokens } : {},
|
|
10659
|
+
...inputTokens > 0 && cachedInputTokens > 0 ? { cachedInputTokens } : {},
|
|
10660
|
+
...outputTokens > 0 ? { outputTokens } : {}
|
|
10661
|
+
}
|
|
10662
|
+
});
|
|
10663
|
+
}
|
|
10548
10664
|
/**
|
|
10549
10665
|
* What only the result line knows: the cost, which covers every call the
|
|
10550
10666
|
* session made — subagents included, since none of their lines carries one —
|
|
@@ -10553,24 +10669,54 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
10553
10669
|
* the session before; with no count kept, the first turn only sets the
|
|
10554
10670
|
* baseline: its total includes turns counted before, and a turn's own share
|
|
10555
10671
|
* cannot be told apart from them.
|
|
10672
|
+
*
|
|
10673
|
+
* The running total never lowers: money already reported and counted is not
|
|
10674
|
+
* un-spent because a later or resumed process remembers less of it, and
|
|
10675
|
+
* counting its return would count the same dollars twice. A zero is not a
|
|
10676
|
+
* measurement at all — a crash can end with one — and only `/clear` restarts
|
|
10677
|
+
* the count, through {@link restartCount}. Per-model baselines never lower
|
|
10678
|
+
* either, for the same reason.
|
|
10679
|
+
*
|
|
10680
|
+
* A report without a model breakdown is counted as a session total; one with
|
|
10681
|
+
* a breakdown is counted per model. A breakdown that would count more than
|
|
10682
|
+
* the session total's own growth (the count before it had no model split, or
|
|
10683
|
+
* a lossy report) is counted as that growth alone, so the two shapes
|
|
10684
|
+
* together still add each dollar once.
|
|
10556
10685
|
*/
|
|
10557
10686
|
reportSessionCost(msg, emit) {
|
|
10687
|
+
this.reportUnstreamedUsage(msg, emit);
|
|
10558
10688
|
const total = msg.total_cost_usd;
|
|
10559
10689
|
const canReport = this.reportedCostUsd !== void 0;
|
|
10560
|
-
const modelCosts = Object.entries(msg.modelUsage ?? {}).filter((entry) => typeof entry[1].costUSD === "number");
|
|
10690
|
+
const modelCosts = Object.entries(msg.modelUsage ?? {}).filter((entry) => typeof entry[1].costUSD === "number" && entry[1].costUSD > 0 && entry[1].costBasis !== "unknown");
|
|
10691
|
+
const growth = canReport && typeof total === "number" && total > 0 ? total - this.reportedCostUsd : void 0;
|
|
10692
|
+
let emitted = 0;
|
|
10693
|
+
const emitCost = (record) => {
|
|
10694
|
+
if (!(record.amount > 0)) return;
|
|
10695
|
+
emitted += record.amount;
|
|
10696
|
+
emit({ type: "usage", record: { source: "claude-code", ...record.model ? { model: record.model } : {}, aggregate: true, ...this.billing ? { sessionBilling: this.billing } : {}, reportedCost: { amount: record.amount, currency: "USD", kind: "estimate", ...record.basis ? { basis: record.basis } : {} } } });
|
|
10697
|
+
};
|
|
10561
10698
|
if (modelCosts.length > 0) {
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10699
|
+
const modelGrowth = modelCosts.reduce((sum, [model2, usage]) => sum + Math.max(0, usage.costUSD - (this.reportedModelCostUsd.get(model2) ?? 0)), 0);
|
|
10700
|
+
if (canReport) {
|
|
10701
|
+
if (growth !== void 0 && modelGrowth > growth + 1e-9) {
|
|
10702
|
+
emitCost({ amount: growth });
|
|
10703
|
+
} else {
|
|
10704
|
+
for (const [model2, usage] of modelCosts) emitCost({ model: model2, amount: usage.costUSD - (this.reportedModelCostUsd.get(model2) ?? 0), ...usage.costBasis ? { basis: usage.costBasis } : {} });
|
|
10705
|
+
}
|
|
10567
10706
|
}
|
|
10568
|
-
|
|
10569
|
-
|
|
10707
|
+
for (const [model2, usage] of modelCosts) this.reportedModelCostUsd.set(model2, Math.max(this.reportedModelCostUsd.get(model2) ?? 0, usage.costUSD));
|
|
10708
|
+
} else if (!Object.values(msg.modelUsage ?? {}).some((usage) => usage.costBasis === "unknown") && typeof total === "number" && total > 0 && canReport && total >= this.reportedCostUsd) {
|
|
10709
|
+
emitCost({ amount: total - this.reportedCostUsd });
|
|
10710
|
+
}
|
|
10711
|
+
if (!canReport) {
|
|
10712
|
+
if (typeof total === "number" && total > 0) this.reportedCostUsd = total;
|
|
10713
|
+
else if (modelCosts.length > 0) this.reportedCostUsd = modelCosts.reduce((sum, [, usage]) => sum + usage.costUSD, 0);
|
|
10714
|
+
} else {
|
|
10715
|
+
this.reportedCostUsd = (this.reportedCostUsd ?? 0) + emitted;
|
|
10570
10716
|
}
|
|
10571
|
-
|
|
10572
|
-
const contextWindow =
|
|
10573
|
-
if (contextWindow
|
|
10717
|
+
const model = this.plannerModel && this.plannerModel !== "<synthetic>" ? this.plannerModel : this.sessionModel;
|
|
10718
|
+
const contextWindow = model ? msg.modelUsage?.[model]?.contextWindow : void 0;
|
|
10719
|
+
if (typeof contextWindow === "number" && contextWindow > 0) emit({ type: "usage", record: { source: "claude-code", model, contextWindow } });
|
|
10574
10720
|
}
|
|
10575
10721
|
};
|
|
10576
10722
|
|
|
@@ -11205,9 +11351,13 @@ function mergeCodexRateLimits(known, params) {
|
|
|
11205
11351
|
const id = snapshot.limitId ?? "";
|
|
11206
11352
|
const before = known.get(id);
|
|
11207
11353
|
const next = new Map(known);
|
|
11208
|
-
next.set(id, { limitId: id, primary: snapshot.primary ?? before?.primary, secondary: snapshot.secondary ?? before?.secondary });
|
|
11354
|
+
next.set(id, { limitId: id, planType: snapshot.planType ?? before?.planType, primary: snapshot.primary ?? before?.primary, secondary: snapshot.secondary ?? before?.secondary });
|
|
11209
11355
|
return next;
|
|
11210
11356
|
}
|
|
11357
|
+
function codexSessionBilling(limits) {
|
|
11358
|
+
const plan = [...limits.values()].find((snapshot) => snapshot.planType && snapshot.planType !== "unknown")?.planType;
|
|
11359
|
+
return plan ? { type: "subscription", plan } : void 0;
|
|
11360
|
+
}
|
|
11211
11361
|
function isCodexUsageLimit(error) {
|
|
11212
11362
|
const info = error?.codexErrorInfo;
|
|
11213
11363
|
if (info === void 0 || info === null || info === "other") return void 0;
|
|
@@ -11766,8 +11916,21 @@ ${this.exitMessage()}`);
|
|
|
11766
11916
|
case "thread/tokenUsage/updated":
|
|
11767
11917
|
this.emitUsage(msg.params, emit);
|
|
11768
11918
|
return;
|
|
11919
|
+
case "account/updated": {
|
|
11920
|
+
const account = msg.params;
|
|
11921
|
+
if (account?.authMode === "apikey") emit({ type: "usage", record: { source: this.agentId, aggregate: true, sessionBilling: { type: "api-key" } } });
|
|
11922
|
+
else if (account?.authMode === "chatgpt" || account?.authMode === "chatgptAuthTokens") {
|
|
11923
|
+
const plan = account.planType;
|
|
11924
|
+
emit({ type: "usage", record: { source: this.agentId, aggregate: true, sessionBilling: { type: "subscription", ...plan && plan !== "unknown" ? { plan } : {} } } });
|
|
11925
|
+
}
|
|
11926
|
+
return;
|
|
11927
|
+
}
|
|
11769
11928
|
case "account/rateLimits/updated":
|
|
11770
11929
|
this.rateLimits = mergeCodexRateLimits(this.rateLimits, msg.params);
|
|
11930
|
+
{
|
|
11931
|
+
const sessionBilling = codexSessionBilling(this.rateLimits);
|
|
11932
|
+
if (sessionBilling) emit({ type: "usage", record: { source: this.agentId, aggregate: true, sessionBilling } });
|
|
11933
|
+
}
|
|
11771
11934
|
return;
|
|
11772
11935
|
case "turn/started": {
|
|
11773
11936
|
if (this.subagentOf(msg.params?.threadId)) return;
|
|
@@ -11896,6 +12059,13 @@ ${this.exitMessage()}`);
|
|
|
11896
12059
|
* `last.outputTokens` already includes `reasoningOutputTokens` — the thread
|
|
11897
12060
|
* total is `inputTokens + outputTokens`, not a sum of three — so reasoning is
|
|
11898
12061
|
* not added a second time. Codex reports no price.
|
|
12062
|
+
*
|
|
12063
|
+
* The main thread's context is what Codex itself shows as in its window:
|
|
12064
|
+
* `TokenUsage::tokens_in_context_window`, which is `total_tokens` over
|
|
12065
|
+
* `last` as codex-rs defines it. `total_tokens` is input plus output, and
|
|
12066
|
+
* reasoning is part of output, so this is not `input + output − reasoning`
|
|
12067
|
+
* (checked against codex-rs and codex-cli 0.163.0's token_count events,
|
|
12068
|
+
* where `total_tokens` is `input_tokens + output_tokens`).
|
|
11899
12069
|
*/
|
|
11900
12070
|
emitUsage(params, emit) {
|
|
11901
12071
|
const last = params?.tokenUsage?.last;
|
|
@@ -11923,6 +12093,8 @@ ${this.exitMessage()}`);
|
|
|
11923
12093
|
} else {
|
|
11924
12094
|
const window = params?.tokenUsage?.modelContextWindow;
|
|
11925
12095
|
if (typeof window === "number" && window > 0) record.contextWindow = window;
|
|
12096
|
+
const inContext = last.totalTokens !== void 0 && last.totalTokens > 0 ? last.totalTokens : last.inputTokens !== void 0 ? last.inputTokens + (last.outputTokens ?? 0) : void 0;
|
|
12097
|
+
if (inContext !== void 0) record.contextTokens = Math.max(0, inContext);
|
|
11926
12098
|
}
|
|
11927
12099
|
emit({ type: "usage", record });
|
|
11928
12100
|
}
|
|
@@ -12084,7 +12256,9 @@ ${this.exitMessage()}`);
|
|
|
12084
12256
|
}
|
|
12085
12257
|
switch (item.type) {
|
|
12086
12258
|
case "contextCompaction":
|
|
12087
|
-
if (
|
|
12259
|
+
if (subagentId) return;
|
|
12260
|
+
emit({ type: "compaction", trigger: this.command === "compact" ? "manual" : "auto" });
|
|
12261
|
+
emit({ type: "usage", record: { source: this.agentId, compacted: true } });
|
|
12088
12262
|
return;
|
|
12089
12263
|
// Codex announces the item started and completed; whichever lands first delivers.
|
|
12090
12264
|
case "userMessage":
|
|
@@ -12380,8 +12554,9 @@ function usageRecord2(tokens, call) {
|
|
|
12380
12554
|
if ((prompt.inputTokens ?? 0) + outputTokens === 0) return null;
|
|
12381
12555
|
const record = { source: "opencode", ...prompt, outputTokens };
|
|
12382
12556
|
if (call.model) record.model = call.model;
|
|
12383
|
-
if (typeof call.cost === "number" && call.cost > 0) record.reportedCost = { amount: call.cost, currency: "USD" };
|
|
12557
|
+
if (typeof call.cost === "number" && call.cost > 0) record.reportedCost = { amount: call.cost, currency: "USD", kind: "estimate" };
|
|
12384
12558
|
if (call.subagentId) record.subagentId = call.subagentId;
|
|
12559
|
+
else record.contextTokens = (prompt.inputTokens ?? 0) + outputTokens;
|
|
12385
12560
|
return record;
|
|
12386
12561
|
}
|
|
12387
12562
|
function permissionReply(decision, key) {
|
|
@@ -12944,6 +13119,7 @@ var OpenCodeV2 = class {
|
|
|
12944
13119
|
}
|
|
12945
13120
|
if (frame.type === "session.compaction.ended") {
|
|
12946
13121
|
onEvent({ type: "compaction", trigger: data.reason === "manual" ? "manual" : "auto" });
|
|
13122
|
+
onEvent({ type: "usage", record: { source: "opencode", compacted: true } });
|
|
12947
13123
|
return;
|
|
12948
13124
|
}
|
|
12949
13125
|
if (frame.type === "session.execution.started") {
|
|
@@ -13809,6 +13985,7 @@ var OpenCodeAdapter = class {
|
|
|
13809
13985
|
if (session && session !== this.sessionId && !turn.children.follows(session)) return;
|
|
13810
13986
|
if (frame.type === "session.compacted" && session === this.sessionId) {
|
|
13811
13987
|
onEvent({ type: "compaction", trigger: this.manualCompaction ? "manual" : "auto" });
|
|
13988
|
+
onEvent({ type: "usage", record: { source: "opencode", compacted: true } });
|
|
13812
13989
|
return;
|
|
13813
13990
|
}
|
|
13814
13991
|
if (session === this.sessionId && this.taskTurn) this.followTaskTurn(frame, this.taskTurn, onEvent);
|
|
@@ -17363,6 +17540,7 @@ var PlannerConversation = class {
|
|
|
17363
17540
|
const request = summaryRequest(this.currentPlanLines());
|
|
17364
17541
|
const onProgress = (p) => {
|
|
17365
17542
|
if (p.type === "liveness") this.host.onProgress(p);
|
|
17543
|
+
else if (p.type === "usage" && p.record) this.host.onProgress({ ...p, record: { ...p.record, aggregate: true } });
|
|
17366
17544
|
};
|
|
17367
17545
|
let turn;
|
|
17368
17546
|
if (this.canContinueLive()) {
|
|
@@ -20979,6 +21157,9 @@ function nonPromptingFs(fs18) {
|
|
|
20979
21157
|
}
|
|
20980
21158
|
};
|
|
20981
21159
|
}
|
|
21160
|
+
function withoutContext({ contextTokens: _context, ...record }) {
|
|
21161
|
+
return record;
|
|
21162
|
+
}
|
|
20982
21163
|
async function runLoop(prompt, deps) {
|
|
20983
21164
|
if (deps.signal?.aborted) return "[research agent aborted before starting]";
|
|
20984
21165
|
const fs18 = nonPromptingFs(deps.fs);
|
|
@@ -20986,7 +21167,8 @@ async function runLoop(prompt, deps) {
|
|
|
20986
21167
|
(delta) => deps.onProgress?.({ type: "thinking", text: delta, subagentId: deps.subagentId }),
|
|
20987
21168
|
// The record says who made the call: unstamped, the ledger would read the
|
|
20988
21169
|
// subagent's prompt as the planner's own and measure its context by it.
|
|
20989
|
-
|
|
21170
|
+
// The chat states the context its call leaves; a subagent's is no meter's.
|
|
21171
|
+
(record) => deps.onProgress?.({ type: "usage", record: deps.subagentId ? { ...withoutContext(record), subagentId: deps.subagentId } : record })
|
|
20990
21172
|
);
|
|
20991
21173
|
let turn = await chat.sendMessage(prompt, deps.signal);
|
|
20992
21174
|
for (let step = 0; turn.hasToolCalls && step < SUBAGENT_LIMITS.maxSteps; step++) {
|
|
@@ -21496,7 +21678,8 @@ function usageRecordFrom(usage, model) {
|
|
|
21496
21678
|
model,
|
|
21497
21679
|
...inputTokens !== void 0 ? { inputTokens } : {},
|
|
21498
21680
|
...reportedOutput.length > 0 ? { outputTokens: reportedOutput.reduce((a, b) => a + b, 0) } : {},
|
|
21499
|
-
...tokenCount(usage.cachedContentTokenCount) !== void 0 ? { cachedInputTokens: tokenCount(usage.cachedContentTokenCount) } : {}
|
|
21681
|
+
...tokenCount(usage.cachedContentTokenCount) !== void 0 ? { cachedInputTokens: tokenCount(usage.cachedContentTokenCount) } : {},
|
|
21682
|
+
...inputTokens !== void 0 ? { contextTokens: inputTokens + (answerTokens ?? 0) } : {}
|
|
21500
21683
|
};
|
|
21501
21684
|
const anyReported = record.inputTokens !== void 0 || record.outputTokens !== void 0 || record.cachedInputTokens !== void 0;
|
|
21502
21685
|
return anyReported ? record : void 0;
|
|
@@ -21899,7 +22082,9 @@ var OpenAiResearchChat = class {
|
|
|
21899
22082
|
/**
|
|
21900
22083
|
* The one record for this API call, built only from what the provider
|
|
21901
22084
|
* reported. OpenRouter's `cost` is in USD (its credits are dollar-pegged);
|
|
21902
|
-
* nothing is estimated. A field the provider left out stays absent.
|
|
22085
|
+
* nothing is estimated. A field the provider left out stays absent. The
|
|
22086
|
+
* context the call leaves is its prompt and its completion: the API's own
|
|
22087
|
+
* `total_tokens`, and the reply the next call's prompt carries.
|
|
21903
22088
|
*/
|
|
21904
22089
|
usageRecord(reported) {
|
|
21905
22090
|
if (!reported) return void 0;
|
|
@@ -21918,9 +22103,10 @@ var OpenAiResearchChat = class {
|
|
|
21918
22103
|
hasMeasure = true;
|
|
21919
22104
|
}
|
|
21920
22105
|
if (reported.cost !== void 0) {
|
|
21921
|
-
record.reportedCost = { amount: reported.cost, currency: "USD" };
|
|
22106
|
+
record.reportedCost = { amount: reported.cost, currency: "USD", ...record.source === "openrouter" ? { kind: "billed" } : {} };
|
|
21922
22107
|
hasMeasure = true;
|
|
21923
22108
|
}
|
|
22109
|
+
if (record.inputTokens !== void 0) record.contextTokens = record.inputTokens + (record.outputTokens ?? 0);
|
|
21924
22110
|
return hasMeasure ? record : void 0;
|
|
21925
22111
|
}
|
|
21926
22112
|
};
|
|
@@ -24091,6 +24277,10 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
24091
24277
|
store;
|
|
24092
24278
|
output;
|
|
24093
24279
|
attempts = /* @__PURE__ */ new Map();
|
|
24280
|
+
/** Bumped by every plan load: an ended attempt's wind-down belongs to the scope before it. */
|
|
24281
|
+
planScope = 0;
|
|
24282
|
+
/** Each task's runners still winding down once stopped: a continue waits for them (ADR-0018, L1). */
|
|
24283
|
+
windDowns = /* @__PURE__ */ new Map();
|
|
24094
24284
|
verifier = new VerdictEngine();
|
|
24095
24285
|
/** Changed only by start, stop, a plan load, a usage-limit pause, a move off the limit, and {@link settleRun}. */
|
|
24096
24286
|
runState = "idle";
|
|
@@ -24639,8 +24829,9 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
24639
24829
|
return blockingFailures(this.store.planTasks).get(taskId) ?? [];
|
|
24640
24830
|
}
|
|
24641
24831
|
loadPlan(tasks, planRunners = [...DEFAULT_RUNNERS]) {
|
|
24642
|
-
this.store.load(tasks, planRunners);
|
|
24643
24832
|
const repairs = this.endAllAttempts("load").filter((a) => a.kind.kind === "repair" && a.worktree);
|
|
24833
|
+
this.planScope += 1;
|
|
24834
|
+
this.store.load(tasks, planRunners);
|
|
24644
24835
|
for (const a of repairs) this.unawaited(this.runs.release(a.taskId, { keep: true }, a.integration), `Could not keep the worktree of task "${this.store.get(a.taskId)?.title ?? a.taskId}"`);
|
|
24645
24836
|
this.runs.interrupt({ keepOpen: this.isScheduling });
|
|
24646
24837
|
if (this.runState !== "scheduling") this.runState = "idle";
|
|
@@ -24726,6 +24917,7 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
24726
24917
|
if (reason === "user") this.stopGeneration++;
|
|
24727
24918
|
this.runState = "idle";
|
|
24728
24919
|
this.verifier.reset();
|
|
24920
|
+
for (const attempt of this.attempts.values()) this.stopRunner(attempt);
|
|
24729
24921
|
this.runner.stopAll();
|
|
24730
24922
|
const stopped = [];
|
|
24731
24923
|
for (const a of this.endAllAttempts("stop")) {
|
|
@@ -24839,6 +25031,7 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
24839
25031
|
if (!task || !attempt) return;
|
|
24840
25032
|
attempt.decided = true;
|
|
24841
25033
|
const stoppedMidTurn = endedByExit(verdict) ? saidInFlight(attempt) : null;
|
|
25034
|
+
this.stopRunner(attempt);
|
|
24842
25035
|
console.error(`[TaskOrchestrator] Task ${taskRefOf(this.store.planTasks, task.id) ?? `#${task.order}`} "${task.title}" verdict=${verdict.outcome}`);
|
|
24843
25036
|
console.error(`[TaskOrchestrator] Runner: ${task.assignedRunner}, Model: ${task.assignedModel?.modelId ?? "default"}`);
|
|
24844
25037
|
console.error(`[TaskOrchestrator] Prompt preview: ${(task.prompt ?? "").slice(0, 200)}`);
|
|
@@ -25750,7 +25943,9 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
25750
25943
|
autoResumed: opts.autoResumed === true,
|
|
25751
25944
|
turnError: null,
|
|
25752
25945
|
turnOutputFrom: 0,
|
|
25753
|
-
reminded: false
|
|
25946
|
+
reminded: false,
|
|
25947
|
+
runnerStopped: false,
|
|
25948
|
+
planScope: this.planScope
|
|
25754
25949
|
};
|
|
25755
25950
|
this.spawnCounts.set(task.id, attempt.attempt);
|
|
25756
25951
|
this.attempts.set(task.id, attempt);
|
|
@@ -25787,6 +25982,7 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
25787
25982
|
const manifest = this.registry?.get(attempt.runner)?.manifest;
|
|
25788
25983
|
const unavailable = manifest && unavailableTaskModeMessage(manifest, task.taskMode);
|
|
25789
25984
|
if (unavailable) throw new Error(unavailable);
|
|
25985
|
+
if (kind.kind === "continuation") await this.windDowns.get(task.id);
|
|
25790
25986
|
const { cwd, worktree, previousWork } = await attemptCwd(kind, task, this.runs);
|
|
25791
25987
|
attempt.cwd = cwd;
|
|
25792
25988
|
attempt.worktree = worktree;
|
|
@@ -25842,10 +26038,11 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
25842
26038
|
}
|
|
25843
26039
|
if (takesSkills(kind)) this.store.setTaskAttemptSkills(task.id, [...attempt.skills]);
|
|
25844
26040
|
session.onEvent((event) => {
|
|
25845
|
-
if (event.type !== "usage" || this.attempts.get(task.id) !== attempt) return;
|
|
26041
|
+
if (event.type !== "usage" || attempt.planScope !== this.planScope || this.attempts.get(task.id) !== attempt && !attempt.runnerStopped) return;
|
|
25846
26042
|
this.store.recordAttemptUsage(task.id, attempt.attempt, event.record, (/* @__PURE__ */ new Date()).toISOString());
|
|
25847
26043
|
this.emit("onUsageChanged");
|
|
25848
26044
|
});
|
|
26045
|
+
session.onExit(() => this.woundDown(attempt, session));
|
|
25849
26046
|
this.output.attach(task.id, session);
|
|
25850
26047
|
this.verifier.watch(task, session);
|
|
25851
26048
|
session.onEvent((event) => {
|
|
@@ -26014,10 +26211,35 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
26014
26211
|
if (stopsRunner(reason)) {
|
|
26015
26212
|
const task = this.store.get(taskId);
|
|
26016
26213
|
if (task) this.verifier.clear(task);
|
|
26017
|
-
if (
|
|
26214
|
+
if (attempt) this.stopRunner(attempt);
|
|
26018
26215
|
}
|
|
26019
26216
|
return attempt;
|
|
26020
26217
|
}
|
|
26218
|
+
/**
|
|
26219
|
+
* Let the attempt's runner go the way it ends a turn (ADR-0018, L1): it
|
|
26220
|
+
* winds down on its own time, bounded by its interrupt grace, and nothing
|
|
26221
|
+
* here waits on it but a continue of the same task.
|
|
26222
|
+
*/
|
|
26223
|
+
stopRunner(attempt) {
|
|
26224
|
+
const session = attempt.session;
|
|
26225
|
+
if (!session || attempt.runnerStopped) return;
|
|
26226
|
+
attempt.runnerStopped = true;
|
|
26227
|
+
const { taskId } = attempt;
|
|
26228
|
+
const windDown = Promise.all([this.windDowns.get(taskId), this.runner.stop(session.id)]).catch(() => void 0).then(() => {
|
|
26229
|
+
if (this.windDowns.get(taskId) === windDown) this.windDowns.delete(taskId);
|
|
26230
|
+
});
|
|
26231
|
+
this.windDowns.set(taskId, windDown);
|
|
26232
|
+
}
|
|
26233
|
+
/**
|
|
26234
|
+
* An ended attempt's runner is gone: the count its session ended on is the
|
|
26235
|
+
* one a continue of that session counts from. One still current is ended
|
|
26236
|
+
* with that count instead.
|
|
26237
|
+
*/
|
|
26238
|
+
woundDown(attempt, session) {
|
|
26239
|
+
if (attempt.planScope !== this.planScope || !attempt.runnerStopped || this.attempts.get(attempt.taskId) === attempt) return;
|
|
26240
|
+
this.store.endAttemptUsage(attempt.taskId, attempt.attempt, (/* @__PURE__ */ new Date()).toISOString(), session.sessionCost?.() ?? void 0, session.nativeSessionId() ?? void 0);
|
|
26241
|
+
this.emit("onUsageChanged");
|
|
26242
|
+
}
|
|
26021
26243
|
/** Kept on the task once the attempt ends, so a continue can resume it after a reload (ADR-0018, K1). */
|
|
26022
26244
|
saveNativeSession(taskId, nativeSessionId, runner) {
|
|
26023
26245
|
if (nativeSessionId) this.store.setTaskRunnerSessionId(taskId, nativeSessionId, runner);
|
|
@@ -28752,19 +28974,50 @@ var TaskLogRecorder = class {
|
|
|
28752
28974
|
};
|
|
28753
28975
|
|
|
28754
28976
|
// src/services/ContextWindowFill.ts
|
|
28755
|
-
var
|
|
28756
|
-
constructor(catalog
|
|
28977
|
+
var SessionWindows = class {
|
|
28978
|
+
constructor(catalog = () => void 0) {
|
|
28757
28979
|
this.catalog = catalog;
|
|
28758
|
-
if (last.contextWindow !== void 0) this.known.set(modelKey(last.source, last.model), last.contextWindow);
|
|
28759
28980
|
}
|
|
28760
28981
|
catalog;
|
|
28761
|
-
|
|
28982
|
+
reported = /* @__PURE__ */ new Map();
|
|
28983
|
+
report(source, model, contextWindow) {
|
|
28984
|
+
if (contextWindow > 0) this.reported.set(modelKey(source, model), { source, model, contextWindow });
|
|
28985
|
+
}
|
|
28986
|
+
get(source, model) {
|
|
28987
|
+
return this.reported.get(modelKey(source, model))?.contextWindow;
|
|
28988
|
+
}
|
|
28989
|
+
snapshot() {
|
|
28990
|
+
return [...this.reported.values()];
|
|
28991
|
+
}
|
|
28992
|
+
restore(saved) {
|
|
28993
|
+
this.reported.clear();
|
|
28994
|
+
for (const { source, model, contextWindow } of saved ?? []) this.report(source, model, contextWindow);
|
|
28995
|
+
}
|
|
28996
|
+
clear() {
|
|
28997
|
+
this.reported.clear();
|
|
28998
|
+
}
|
|
28999
|
+
};
|
|
29000
|
+
var ContextWindowFill = class {
|
|
29001
|
+
constructor(windows, last = {}) {
|
|
29002
|
+
this.windows = windows;
|
|
29003
|
+
if (last.contextWindow !== void 0) this.known.set(modelKey(last.source, last.model), last.contextWindow);
|
|
29004
|
+
}
|
|
29005
|
+
windows;
|
|
29006
|
+
/** The window this stream used for each of its models, by reporter and model. */
|
|
28762
29007
|
known = /* @__PURE__ */ new Map();
|
|
28763
29008
|
fill(record) {
|
|
28764
29009
|
if (record.subagentId || record.aggregate) return record;
|
|
28765
29010
|
const key = modelKey(record.source, record.model);
|
|
29011
|
+
if (record.compacted) {
|
|
29012
|
+
if (!record.model) return record;
|
|
29013
|
+
const known = this.windows.get(record.source, record.model) ?? this.known.get(key) ?? positive(this.windows.catalog(record.source, record.model));
|
|
29014
|
+
if (known === void 0) return record;
|
|
29015
|
+
this.known.set(key, known);
|
|
29016
|
+
return { ...record, contextWindow: known };
|
|
29017
|
+
}
|
|
28766
29018
|
const reported = record.contextWindow !== void 0 && record.contextWindow > 0 ? record.contextWindow : void 0;
|
|
28767
|
-
|
|
29019
|
+
if (reported !== void 0 && record.model) this.windows.report(record.source, record.model, reported);
|
|
29020
|
+
const window = reported ?? (record.model ? this.windows.get(record.source, record.model) : void 0) ?? this.known.get(key) ?? (record.model ? positive(this.windows.catalog(record.source, record.model)) : void 0);
|
|
28768
29021
|
if (window !== void 0) this.known.set(key, window);
|
|
28769
29022
|
return window === void 0 || window === record.contextWindow ? record : { ...record, contextWindow: window };
|
|
28770
29023
|
}
|
|
@@ -28772,9 +29025,9 @@ var ContextWindowFill = class {
|
|
|
28772
29025
|
function modelKey(source, model) {
|
|
28773
29026
|
return JSON.stringify([source ?? null, model ?? null]);
|
|
28774
29027
|
}
|
|
28775
|
-
function withContextWindows(runner,
|
|
29028
|
+
function withContextWindows(runner, windows) {
|
|
28776
29029
|
return {
|
|
28777
|
-
spawn: async (opts) => windowedSession(await runner.spawn(opts), new ContextWindowFill(
|
|
29030
|
+
spawn: async (opts) => windowedSession(await runner.spawn(opts), new ContextWindowFill(windows, opts.resumeWindow)),
|
|
28778
29031
|
stop: (sessionId) => runner.stop(sessionId),
|
|
28779
29032
|
stopAll: () => runner.stopAll(),
|
|
28780
29033
|
get activeCount() {
|
|
@@ -28805,12 +29058,12 @@ function positive(n) {
|
|
|
28805
29058
|
|
|
28806
29059
|
// src/services/PlannerUsage.ts
|
|
28807
29060
|
var PlannerUsageLedger = class {
|
|
28808
|
-
/** `
|
|
28809
|
-
constructor(
|
|
28810
|
-
this.
|
|
28811
|
-
this.windows = new ContextWindowFill(
|
|
29061
|
+
/** `sessionWindows` serves the window of a planner model whose backend reports none. */
|
|
29062
|
+
constructor(sessionWindows = new SessionWindows()) {
|
|
29063
|
+
this.sessionWindows = sessionWindows;
|
|
29064
|
+
this.windows = new ContextWindowFill(sessionWindows);
|
|
28812
29065
|
}
|
|
28813
|
-
|
|
29066
|
+
sessionWindows;
|
|
28814
29067
|
usage = { totals: {} };
|
|
28815
29068
|
windows;
|
|
28816
29069
|
/** Fold one model call's record into the totals; returns the running ledger. */
|
|
@@ -28821,16 +29074,16 @@ var PlannerUsageLedger = class {
|
|
|
28821
29074
|
/** Adopt a persisted ledger (a reopened session) or start from zero. */
|
|
28822
29075
|
restore(usage) {
|
|
28823
29076
|
this.usage = usage ?? { totals: {} };
|
|
28824
|
-
this.windows = new ContextWindowFill(this.
|
|
29077
|
+
this.windows = new ContextWindowFill(this.sessionWindows, this.usage);
|
|
28825
29078
|
}
|
|
28826
29079
|
/** Start a fresh session's ledger from zero. */
|
|
28827
29080
|
clear() {
|
|
28828
29081
|
this.usage = { totals: {} };
|
|
28829
|
-
this.windows = new ContextWindowFill(this.
|
|
29082
|
+
this.windows = new ContextWindowFill(this.sessionWindows);
|
|
28830
29083
|
}
|
|
28831
|
-
/** Whether
|
|
29084
|
+
/** Whether the ledger has measures or session billing facts to broadcast. */
|
|
28832
29085
|
get hasUsage() {
|
|
28833
|
-
return isMeasured(this.usage.totals);
|
|
29086
|
+
return isMeasured(this.usage.totals) || this.usage.sessionBilling !== void 0;
|
|
28834
29087
|
}
|
|
28835
29088
|
/** The value persisted onto the plan state. */
|
|
28836
29089
|
snapshot() {
|
|
@@ -30279,7 +30532,7 @@ function createSession(deps) {
|
|
|
30279
30532
|
const backend = new PlannerBackend(deps.aiService ? { pinned: deps.aiService, busy } : { provider: () => deps.config.aiProvider, create: () => createAiService(deps.config, { workspaceRoot: deps.workspaceRoot, mcpServer }), busy });
|
|
30280
30533
|
const aiService = () => backend.current();
|
|
30281
30534
|
const store = new PlanStore();
|
|
30282
|
-
const
|
|
30535
|
+
const windows = new SessionWindows((source, model) => deps.modelResolver.contextWindowFor?.(source, model));
|
|
30283
30536
|
const taskLogs = new TaskLogRecorder({
|
|
30284
30537
|
broadcast: deps.broadcast,
|
|
30285
30538
|
// Read through the Session, whose id and workspace are the ones it saves
|
|
@@ -30312,7 +30565,7 @@ function createSession(deps) {
|
|
|
30312
30565
|
const orchestrator = TaskOrchestrator.compose({
|
|
30313
30566
|
config: deps.config,
|
|
30314
30567
|
notifications: deps.notifications,
|
|
30315
|
-
runner: taskLogs.wrap(runnerApprovals.wrap(withContextWindows(deps.runner,
|
|
30568
|
+
runner: taskLogs.wrap(runnerApprovals.wrap(withContextWindows(deps.runner, windows))),
|
|
30316
30569
|
store,
|
|
30317
30570
|
output: deps.taskOutput,
|
|
30318
30571
|
isolation: deps.isolation,
|
|
@@ -30324,7 +30577,7 @@ function createSession(deps) {
|
|
|
30324
30577
|
runSettings: () => session.planState?.runSettings,
|
|
30325
30578
|
isApproved: (taskId) => session.isApproved(taskId)
|
|
30326
30579
|
});
|
|
30327
|
-
const usage = new PlannerUsageLedger(
|
|
30580
|
+
const usage = new PlannerUsageLedger(windows);
|
|
30328
30581
|
const events = new SessionEventRelay({
|
|
30329
30582
|
broadcast: deps.broadcast,
|
|
30330
30583
|
onNotice: deps.onNotice,
|
|
@@ -30394,6 +30647,7 @@ function createSession(deps) {
|
|
|
30394
30647
|
runs: orchestrator.runs,
|
|
30395
30648
|
events,
|
|
30396
30649
|
usage,
|
|
30650
|
+
windows,
|
|
30397
30651
|
approvals,
|
|
30398
30652
|
approvalPolicy,
|
|
30399
30653
|
taskLogs,
|
|
@@ -30421,6 +30675,7 @@ function configSecrets(config) {
|
|
|
30421
30675
|
var Session = class {
|
|
30422
30676
|
backend;
|
|
30423
30677
|
usage;
|
|
30678
|
+
windows;
|
|
30424
30679
|
events;
|
|
30425
30680
|
planner;
|
|
30426
30681
|
orchestrator;
|
|
@@ -30526,6 +30781,7 @@ var Session = class {
|
|
|
30526
30781
|
this.runs = parts.runs;
|
|
30527
30782
|
this.events = parts.events;
|
|
30528
30783
|
this.usage = parts.usage;
|
|
30784
|
+
this.windows = parts.windows;
|
|
30529
30785
|
this.approvals = parts.approvals;
|
|
30530
30786
|
this.approvalPolicy = parts.approvalPolicy;
|
|
30531
30787
|
this.taskLogs = parts.taskLogs;
|
|
@@ -31004,6 +31260,7 @@ var Session = class {
|
|
|
31004
31260
|
this.syncPlanTasks();
|
|
31005
31261
|
this.plan.isolation = this.runs.planIsolation ?? void 0;
|
|
31006
31262
|
this.plan.plannerUsage = this.usage.snapshot();
|
|
31263
|
+
this.plan.contextWindows = this.windows.snapshot();
|
|
31007
31264
|
this.plan.supervision = this.supervision.snapshot();
|
|
31008
31265
|
this.plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
31009
31266
|
this.save(this.plan, this.goal, this.workspace, this.currentSessionId);
|
|
@@ -31033,6 +31290,7 @@ var Session = class {
|
|
|
31033
31290
|
this.owingEffects.clear();
|
|
31034
31291
|
this.conversation.reset();
|
|
31035
31292
|
this.usage.clear();
|
|
31293
|
+
this.windows.clear();
|
|
31036
31294
|
this.approvals.clear(isPlannerApproval);
|
|
31037
31295
|
if (!keepGrants) this.approvalPolicy.reset();
|
|
31038
31296
|
this.store.clearLog();
|
|
@@ -31373,7 +31631,18 @@ var Session = class {
|
|
|
31373
31631
|
if (!this.plan) throw new ConversationEditError("No planning conversation to condense");
|
|
31374
31632
|
const opening = this.plannerTurnMayOpen(signal);
|
|
31375
31633
|
if (opening) await opening;
|
|
31376
|
-
|
|
31634
|
+
const compaction = await this.conversation.compact(signal);
|
|
31635
|
+
const usage = this.usage.snapshot();
|
|
31636
|
+
if (usage.lastPromptTokens !== void 0) {
|
|
31637
|
+
this.usage.record({
|
|
31638
|
+
source: usage.source ?? this.config.aiProvider,
|
|
31639
|
+
...usage.model ? { model: usage.model } : {},
|
|
31640
|
+
compacted: true
|
|
31641
|
+
});
|
|
31642
|
+
this.persist();
|
|
31643
|
+
this.broadcast(this.usage.message());
|
|
31644
|
+
}
|
|
31645
|
+
return compaction;
|
|
31377
31646
|
}
|
|
31378
31647
|
rewindTargets() {
|
|
31379
31648
|
return this.conversation.rewindTargets();
|
|
@@ -31861,7 +32130,10 @@ var Session = class {
|
|
|
31861
32130
|
if (!plan.approvedTasks && plan.approved) {
|
|
31862
32131
|
plan.approvedTasks = flattenTasks(plan.tasks).map((t) => t.id);
|
|
31863
32132
|
}
|
|
31864
|
-
if (adopting)
|
|
32133
|
+
if (adopting) {
|
|
32134
|
+
this.usage.restore(plan.plannerUsage);
|
|
32135
|
+
this.windows.restore(plan.contextWindows);
|
|
32136
|
+
}
|
|
31865
32137
|
if (opts?.sessionId) this.currentSessionId = opts.sessionId;
|
|
31866
32138
|
if (adopting) {
|
|
31867
32139
|
for (const task of flattenTasks(plan.tasks)) delete task.resumeAt;
|
|
@@ -31948,17 +32220,12 @@ var AbstractRunner = class {
|
|
|
31948
32220
|
get activeCount() {
|
|
31949
32221
|
return this.sessions.size;
|
|
31950
32222
|
}
|
|
32223
|
+
/** A session winding down stays registered until it exits, so a second stop gets the same wind-down. */
|
|
31951
32224
|
stop(sessionId) {
|
|
31952
|
-
|
|
31953
|
-
if (!session) return;
|
|
31954
|
-
session.kill();
|
|
31955
|
-
this.sessions.delete(sessionId);
|
|
32225
|
+
return this.sessions.get(sessionId)?.stop() ?? Promise.resolve();
|
|
31956
32226
|
}
|
|
31957
32227
|
stopAll() {
|
|
31958
|
-
for (const
|
|
31959
|
-
session.kill();
|
|
31960
|
-
}
|
|
31961
|
-
this.sessions.clear();
|
|
32228
|
+
for (const session of this.sessions.values()) void session.stop();
|
|
31962
32229
|
}
|
|
31963
32230
|
registerSession(id, session) {
|
|
31964
32231
|
this.sessions.set(id, session);
|
|
@@ -32116,6 +32383,8 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32116
32383
|
queue = [];
|
|
32117
32384
|
messageCount = 0;
|
|
32118
32385
|
interrupting = null;
|
|
32386
|
+
/** The wind-down once {@link stop} was asked for: the same for every caller, and nothing new is sent meanwhile. */
|
|
32387
|
+
stopping = null;
|
|
32119
32388
|
lastSessionId = null;
|
|
32120
32389
|
lastSessionCost = null;
|
|
32121
32390
|
structuredEmitter = new EventEmitter2();
|
|
@@ -32141,7 +32410,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32141
32410
|
await this.startAttached(this.launch.startOptions);
|
|
32142
32411
|
this.state = "working";
|
|
32143
32412
|
setImmediate(() => {
|
|
32144
|
-
if (!this.exited) this.deliver(prompt);
|
|
32413
|
+
if (!this.exited && !this.stopping) this.deliver(prompt);
|
|
32145
32414
|
});
|
|
32146
32415
|
}
|
|
32147
32416
|
getOutput() {
|
|
@@ -32221,6 +32490,53 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32221
32490
|
this.withdrawPermissions();
|
|
32222
32491
|
this.baseHandleExit(-1);
|
|
32223
32492
|
}
|
|
32493
|
+
stop() {
|
|
32494
|
+
if (this.stopping) return this.stopping;
|
|
32495
|
+
if (this.exited) return Promise.resolve();
|
|
32496
|
+
let woundDown;
|
|
32497
|
+
this.stopping = new Promise((resolve9) => {
|
|
32498
|
+
woundDown = resolve9;
|
|
32499
|
+
});
|
|
32500
|
+
void this.windDown().catch(() => this.kill()).then(woundDown);
|
|
32501
|
+
return this.stopping;
|
|
32502
|
+
}
|
|
32503
|
+
/**
|
|
32504
|
+
* The attempt is over (ADR-0018, L1), so what is still owed goes undelivered
|
|
32505
|
+
* and every tool request unanswered at once. A turn still open is
|
|
32506
|
+
* interrupted, and its close — where Claude Code reports the turn's cost and
|
|
32507
|
+
* its model's window — is waited for; then the runner is told nothing more
|
|
32508
|
+
* is coming and left to exit by itself. All of it within the interrupt
|
|
32509
|
+
* grace: a runner still there once it runs out is killed.
|
|
32510
|
+
*/
|
|
32511
|
+
async windDown() {
|
|
32512
|
+
const adapter = this.adapterAttached ? this.adapter : null;
|
|
32513
|
+
const deadline = Date.now() + this.launch.interruptGraceMs;
|
|
32514
|
+
this.revokeTools();
|
|
32515
|
+
this.undeliverQueued();
|
|
32516
|
+
this.withdrawPermissions();
|
|
32517
|
+
const open = this.turn && !this.turn.ended ? this.turn : null;
|
|
32518
|
+
if (adapter && (!open || await this.turnClosed(open, adapter, deadline)) && adapter.endInput && !this.exited) {
|
|
32519
|
+
adapter.endInput();
|
|
32520
|
+
await this.within(this.gone(), deadline);
|
|
32521
|
+
}
|
|
32522
|
+
if (this.exited) adapter?.dispose();
|
|
32523
|
+
else this.kill();
|
|
32524
|
+
}
|
|
32525
|
+
/** Whether `turn` closed within the deadline once interrupted. */
|
|
32526
|
+
async turnClosed(turn, adapter, deadline) {
|
|
32527
|
+
const closed = new Promise((resolve9) => this.structuredEmitter.once("turnEnd", () => resolve9()));
|
|
32528
|
+
adapter.interrupt(Math.max(0, deadline - Date.now())).catch(() => false);
|
|
32529
|
+
return await this.within(closed, deadline) && turn.ended;
|
|
32530
|
+
}
|
|
32531
|
+
/** Whether `done` settled before the deadline, or the session ended meanwhile. */
|
|
32532
|
+
within(done, deadline) {
|
|
32533
|
+
return settleWithin(done.then(() => true), { timeoutMs: Math.max(0, deadline - Date.now()), onTimeout: () => false, ended: this.gone(), onEnded: () => true });
|
|
32534
|
+
}
|
|
32535
|
+
gone() {
|
|
32536
|
+
const { signal } = this.ended;
|
|
32537
|
+
if (signal.aborted) return Promise.resolve();
|
|
32538
|
+
return new Promise((resolve9) => signal.addEventListener("abort", () => resolve9(), { once: true }));
|
|
32539
|
+
}
|
|
32224
32540
|
turnState() {
|
|
32225
32541
|
return this.state;
|
|
32226
32542
|
}
|
|
@@ -32246,7 +32562,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32246
32562
|
this.messageCount += 1;
|
|
32247
32563
|
const id = `msg-${this.messageCount}`;
|
|
32248
32564
|
const sender2 = opening.from ? { from: opening.from } : {};
|
|
32249
|
-
if (this.exited) this.emitEvent({ type: "message_undelivered", messageId: id, text, ...sender2 });
|
|
32565
|
+
if (this.exited || this.stopping) this.emitEvent({ type: "message_undelivered", messageId: id, text, ...sender2 });
|
|
32250
32566
|
else if (this.state === "idle" && this.adapterStarted && !this.sending) this.deliver(text, opening);
|
|
32251
32567
|
else {
|
|
32252
32568
|
this.state = "working";
|
|
@@ -32301,7 +32617,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32301
32617
|
});
|
|
32302
32618
|
}
|
|
32303
32619
|
runningTurn() {
|
|
32304
|
-
return !this.exited && this.adapter !== null && this.turn !== null && !this.turn.ended;
|
|
32620
|
+
return !this.exited && !this.stopping && this.adapter !== null && this.turn !== null && !this.turn.ended;
|
|
32305
32621
|
}
|
|
32306
32622
|
/** No runner can recall a message once offered to it, so only a queued one comes back. */
|
|
32307
32623
|
removeQueued(id) {
|
|
@@ -32362,7 +32678,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32362
32678
|
if (this.interrupting) return this.interrupting;
|
|
32363
32679
|
const turn = this.turn;
|
|
32364
32680
|
const adapter = this.adapter;
|
|
32365
|
-
if (!turn || turn.ended || !adapter) return Promise.resolve();
|
|
32681
|
+
if (!turn || turn.ended || !adapter || this.stopping) return Promise.resolve();
|
|
32366
32682
|
this.interrupting = this.interruptTurn(turn, adapter).finally(() => {
|
|
32367
32683
|
this.interrupting = null;
|
|
32368
32684
|
this.offerNext();
|
|
@@ -32376,7 +32692,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32376
32692
|
const settled = await settleWithin(ended.then(() => true), { timeoutMs: grace, onTimeout: () => false });
|
|
32377
32693
|
if (settled) return;
|
|
32378
32694
|
}
|
|
32379
|
-
if (turn.ended || this.exited) return;
|
|
32695
|
+
if (turn.ended || this.exited || this.stopping) return;
|
|
32380
32696
|
await this.restartInterrupted(turn);
|
|
32381
32697
|
}
|
|
32382
32698
|
/**
|
|
@@ -32480,7 +32796,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32480
32796
|
offerNext() {
|
|
32481
32797
|
const adapter = this.adapter;
|
|
32482
32798
|
const turn = this.turn;
|
|
32483
|
-
if (!adapter?.steer || !turn || turn.ended || turn.steerRefused || this.interrupting || this.exited) return;
|
|
32799
|
+
if (!adapter?.steer || !turn || turn.ended || turn.steerRefused || this.interrupting || this.exited || this.stopping) return;
|
|
32484
32800
|
if (this.queue.some((m) => m.stage === "steering")) return;
|
|
32485
32801
|
const next = this.queue.find((m) => m.stage === "queued");
|
|
32486
32802
|
if (!next || next.command) return;
|
|
@@ -32555,7 +32871,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32555
32871
|
}
|
|
32556
32872
|
return;
|
|
32557
32873
|
}
|
|
32558
|
-
if (!turn && TURN_OPENING_EVENTS.has(event.type) && !("subagentId" in event && event.subagentId)) {
|
|
32874
|
+
if (!turn && !this.stopping && TURN_OPENING_EVENTS.has(event.type) && !("subagentId" in event && event.subagentId)) {
|
|
32559
32875
|
turn = this.openTurn("");
|
|
32560
32876
|
this.offerNext();
|
|
32561
32877
|
}
|
|
@@ -32626,7 +32942,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
32626
32942
|
* back in Ordewell's hands: while it is on offer or owed, nothing overtakes it.
|
|
32627
32943
|
*/
|
|
32628
32944
|
deliverNext() {
|
|
32629
|
-
if (this.exited || this.sending || this.turn && !this.turn.ended) return;
|
|
32945
|
+
if (this.exited || this.stopping || this.sending || this.turn && !this.turn.ended) return;
|
|
32630
32946
|
const head = this.queue[0];
|
|
32631
32947
|
if (!head || this.queue.some((message) => message.stage !== "queued")) return;
|
|
32632
32948
|
this.queue.shift();
|
|
@@ -33075,7 +33391,10 @@ export {
|
|
|
33075
33391
|
collectProviderCredentials,
|
|
33076
33392
|
commandAllowedBy,
|
|
33077
33393
|
configuredProviders,
|
|
33394
|
+
contextMeterText,
|
|
33395
|
+
contextMeterTitle,
|
|
33078
33396
|
continuability,
|
|
33397
|
+
costText,
|
|
33079
33398
|
countedSessionCost,
|
|
33080
33399
|
createAiService,
|
|
33081
33400
|
createEmptyPlan,
|
|
@@ -33118,7 +33437,9 @@ export {
|
|
|
33118
33437
|
flattenTasksWithParents,
|
|
33119
33438
|
followTaskLog,
|
|
33120
33439
|
followTurn,
|
|
33440
|
+
formatCost,
|
|
33121
33441
|
formatSearchOutput,
|
|
33442
|
+
formatTokenCount,
|
|
33122
33443
|
fromTranscript,
|
|
33123
33444
|
getLatestSession,
|
|
33124
33445
|
getProviderMeta,
|
|
@@ -33170,6 +33491,7 @@ export {
|
|
|
33170
33491
|
migratePlanState,
|
|
33171
33492
|
mintDaemonToken,
|
|
33172
33493
|
mintSessionId,
|
|
33494
|
+
modelCostTitle,
|
|
33173
33495
|
namedRepos,
|
|
33174
33496
|
newTaskFields,
|
|
33175
33497
|
normalizeAgentArgs,
|
|
@@ -33255,6 +33577,7 @@ export {
|
|
|
33255
33577
|
stopTurn,
|
|
33256
33578
|
stripAnsi,
|
|
33257
33579
|
stripModelPrefix,
|
|
33580
|
+
subagentCostTitle,
|
|
33258
33581
|
subtreeIds,
|
|
33259
33582
|
summarizeToolCall,
|
|
33260
33583
|
supervisorSummary,
|
|
@@ -33273,6 +33596,7 @@ export {
|
|
|
33273
33596
|
taskStartedNotice,
|
|
33274
33597
|
taskStatusKind,
|
|
33275
33598
|
taskUsageSummary,
|
|
33599
|
+
tasksTotalText,
|
|
33276
33600
|
textHasTaskOps,
|
|
33277
33601
|
textHasTaskQuery,
|
|
33278
33602
|
titledRefs,
|
|
@@ -33290,6 +33614,7 @@ export {
|
|
|
33290
33614
|
unsendAll,
|
|
33291
33615
|
unsendLatest,
|
|
33292
33616
|
usageLine,
|
|
33617
|
+
usageText,
|
|
33293
33618
|
waitsForApproval,
|
|
33294
33619
|
walkPlan,
|
|
33295
33620
|
wellKnownBinDirs,
|