laohuang 0.8.7 → 0.8.9
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/bin.js +197 -112
- package/dist/bin.js.map +4 -4
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -7,13 +7,177 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
|
|
8
8
|
// ../../packages/session/session-context/dist/conversation-history.js
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
|
+
|
|
11
|
+
// ../../packages/session/session-context/dist/token-estimator.js
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
var TEXT_BYTES_PER_TOKEN = 4;
|
|
14
|
+
var BLOCK_OVERHEAD = 4;
|
|
15
|
+
var MESSAGE_OVERHEAD = 4;
|
|
16
|
+
var DefaultTokenEstimator = class {
|
|
17
|
+
estimateMessages(messages) {
|
|
18
|
+
return messages.reduce((total, message) => total + this.estimateMessage(message), 0);
|
|
19
|
+
}
|
|
20
|
+
estimateTools(tools) {
|
|
21
|
+
if (tools.length === 0) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
return this.estimateText(canonicalJson(tools.map(({ name, description, parameters }) => ({ name, description, parameters })))) + BLOCK_OVERHEAD;
|
|
25
|
+
}
|
|
26
|
+
estimateText(text2) {
|
|
27
|
+
return Math.ceil(Buffer.byteLength(text2, "utf8") / TEXT_BYTES_PER_TOKEN);
|
|
28
|
+
}
|
|
29
|
+
measure(input) {
|
|
30
|
+
const anchor = input.anchor ?? null;
|
|
31
|
+
if (anchor !== null && this.isValidAnchor(input, anchor)) {
|
|
32
|
+
const trailingEntries = input.entries.filter((entry) => entry.seq > anchor.throughSeq);
|
|
33
|
+
const trailingTokens = this.estimateMessages(messagesForEntries(trailingEntries));
|
|
34
|
+
return {
|
|
35
|
+
totalTokens: anchor.contextTokens + trailingTokens,
|
|
36
|
+
anchorTokens: anchor.contextTokens,
|
|
37
|
+
trailingTokens,
|
|
38
|
+
source: "provider_usage"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const totalTokens = this.estimateMessages(input.messages) + this.estimateTools(input.tools);
|
|
42
|
+
return {
|
|
43
|
+
totalTokens,
|
|
44
|
+
anchorTokens: 0,
|
|
45
|
+
trailingTokens: totalTokens,
|
|
46
|
+
source: "estimated"
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
estimateMessage(message) {
|
|
50
|
+
if (message.role === "system" && message.toolDefinitions !== void 0)
|
|
51
|
+
return 0;
|
|
52
|
+
if (message.role === "system" || message.role === "user") {
|
|
53
|
+
return MESSAGE_OVERHEAD + BLOCK_OVERHEAD + this.estimateText(message.content);
|
|
54
|
+
}
|
|
55
|
+
if (message.role === "tool-result") {
|
|
56
|
+
return MESSAGE_OVERHEAD + BLOCK_OVERHEAD + this.estimateText(message.content);
|
|
57
|
+
}
|
|
58
|
+
return MESSAGE_OVERHEAD + message.content.reduce((total, block) => {
|
|
59
|
+
if (block.type === "text" || block.type === "reasoning") {
|
|
60
|
+
return total + BLOCK_OVERHEAD + this.estimateText(block.text);
|
|
61
|
+
}
|
|
62
|
+
return total + BLOCK_OVERHEAD + this.estimateText(`${block.call.name}${canonicalJson(block.call.arguments)}`);
|
|
63
|
+
}, 0);
|
|
64
|
+
}
|
|
65
|
+
isValidAnchor(input, anchor) {
|
|
66
|
+
return anchor.provider === input.provider && anchor.model === input.model && anchor.systemFingerprint === input.systemFingerprint && anchor.projectInstructionsFingerprint === input.projectInstructionsFingerprint && anchor.toolsFingerprint === input.toolsFingerprint && input.entries.some((entry) => entry.id === anchor.throughEntryId && entry.seq === anchor.throughSeq);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
function normalizeProviderUsage(usage) {
|
|
70
|
+
return usage.inputTokens + (usage.cacheReadTokens ?? 0) + (usage.cacheWriteTokens ?? 0) + usage.outputTokens;
|
|
71
|
+
}
|
|
72
|
+
function fingerprintContextPart(value) {
|
|
73
|
+
return createHash("sha256").update(canonicalJson(value)).digest("hex");
|
|
74
|
+
}
|
|
75
|
+
function canonicalJson(value) {
|
|
76
|
+
return JSON.stringify(sortStable(value));
|
|
77
|
+
}
|
|
78
|
+
function sortStable(value) {
|
|
79
|
+
if (Array.isArray(value)) {
|
|
80
|
+
return value.map(sortStable);
|
|
81
|
+
}
|
|
82
|
+
if (value !== null && typeof value === "object") {
|
|
83
|
+
const record = value;
|
|
84
|
+
const sorted = {};
|
|
85
|
+
for (const key of Object.keys(record).sort()) {
|
|
86
|
+
sorted[key] = sortStable(record[key]);
|
|
87
|
+
}
|
|
88
|
+
return sorted;
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
function messagesForEntries(entries) {
|
|
93
|
+
return entries.flatMap((entry) => {
|
|
94
|
+
if (entry.entryType === "tool_definitions" || entry.entryType === "tool_catalog")
|
|
95
|
+
return [entry.payload.message];
|
|
96
|
+
if (entry.entryType === "system_context") {
|
|
97
|
+
return [entry.payload.message];
|
|
98
|
+
}
|
|
99
|
+
if (entry.entryType === "project_instructions" || entry.entryType === "user_message" || entry.entryType === "reminder") {
|
|
100
|
+
return [entry.payload.message];
|
|
101
|
+
}
|
|
102
|
+
if (entry.entryType === "assistant_message") {
|
|
103
|
+
return [entry.payload.message];
|
|
104
|
+
}
|
|
105
|
+
if (entry.entryType === "tool_result") {
|
|
106
|
+
return [entry.payload.message];
|
|
107
|
+
}
|
|
108
|
+
return [];
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ../../packages/session/session-context/dist/context-usage.js
|
|
113
|
+
var ContextUsage = class {
|
|
114
|
+
#tokens = 0;
|
|
115
|
+
constructor(entries = []) {
|
|
116
|
+
for (const entry of entries)
|
|
117
|
+
this.append(entry);
|
|
118
|
+
}
|
|
119
|
+
get tokens() {
|
|
120
|
+
return this.#tokens;
|
|
121
|
+
}
|
|
122
|
+
/** Histories are append-only and ordered; process each committed entry once. */
|
|
123
|
+
append(entry) {
|
|
124
|
+
if (entry.entryType === "compaction") {
|
|
125
|
+
this.#tokens = null;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (entry.entryType === "assistant_message") {
|
|
129
|
+
const usage = validUsageTokens(entry.payload.usage);
|
|
130
|
+
if (usage !== null) {
|
|
131
|
+
this.#tokens = usage;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (this.#tokens === null)
|
|
136
|
+
return;
|
|
137
|
+
if (entry.entryType === "user_message" || entry.entryType === "assistant_message" || entry.entryType === "tool_result" || entry.entryType === "reminder") {
|
|
138
|
+
this.#tokens += estimateMessage(entry.payload.message);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
function validUsageTokens(usage) {
|
|
143
|
+
if (usage === void 0 || usage === null)
|
|
144
|
+
return null;
|
|
145
|
+
const fields = [
|
|
146
|
+
usage.inputTokens,
|
|
147
|
+
usage.outputTokens,
|
|
148
|
+
usage.cacheReadTokens ?? 0,
|
|
149
|
+
usage.cacheWriteTokens ?? 0
|
|
150
|
+
];
|
|
151
|
+
if (!fields.every((value) => Number.isSafeInteger(value) && value >= 0))
|
|
152
|
+
return null;
|
|
153
|
+
const total = normalizeProviderUsage(usage);
|
|
154
|
+
return Number.isSafeInteger(total) && total > 0 ? total : null;
|
|
155
|
+
}
|
|
156
|
+
function estimateMessage(message) {
|
|
157
|
+
if (message.role === "system")
|
|
158
|
+
return 0;
|
|
159
|
+
if (message.role !== "assistant")
|
|
160
|
+
return Math.ceil(message.content.length / 4);
|
|
161
|
+
const chars = message.content.reduce((sum, block) => {
|
|
162
|
+
if (block.type === "tool-call") {
|
|
163
|
+
return sum + block.call.name.length + JSON.stringify(block.call.arguments).length;
|
|
164
|
+
}
|
|
165
|
+
return sum + block.text.length;
|
|
166
|
+
}, 0);
|
|
167
|
+
return Math.ceil(chars / 4);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ../../packages/session/session-context/dist/conversation-history.js
|
|
10
171
|
var ConversationHistory = class _ConversationHistory {
|
|
11
172
|
#journal;
|
|
12
173
|
#entries;
|
|
13
174
|
#staged = /* @__PURE__ */ new Map();
|
|
175
|
+
#contextUsage;
|
|
176
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
14
177
|
constructor(entries, journal) {
|
|
15
178
|
this.#entries = [...entries];
|
|
16
179
|
this.#journal = journal;
|
|
180
|
+
this.#contextUsage = new ContextUsage(entries);
|
|
17
181
|
}
|
|
18
182
|
static fromReplay(replay, journal) {
|
|
19
183
|
const history = new _ConversationHistory(replay.items.filter((item) => item.kind === "entry"), journal);
|
|
@@ -126,9 +290,21 @@ var ConversationHistory = class _ConversationHistory {
|
|
|
126
290
|
entries() {
|
|
127
291
|
return [...this.#entries];
|
|
128
292
|
}
|
|
293
|
+
get contextTokens() {
|
|
294
|
+
return this.#contextUsage.tokens;
|
|
295
|
+
}
|
|
296
|
+
onChange(listener) {
|
|
297
|
+
this.#listeners.add(listener);
|
|
298
|
+
return () => {
|
|
299
|
+
this.#listeners.delete(listener);
|
|
300
|
+
};
|
|
301
|
+
}
|
|
129
302
|
append(input) {
|
|
130
303
|
const entry = this.#journal.appendEntry(input);
|
|
131
304
|
this.#entries.push(entry);
|
|
305
|
+
this.#contextUsage.append(entry);
|
|
306
|
+
for (const listener of this.#listeners)
|
|
307
|
+
listener();
|
|
132
308
|
return entry;
|
|
133
309
|
}
|
|
134
310
|
};
|
|
@@ -517,104 +693,6 @@ function validateToolPairs(selected) {
|
|
|
517
693
|
}
|
|
518
694
|
}
|
|
519
695
|
|
|
520
|
-
// ../../packages/session/session-context/dist/token-estimator.js
|
|
521
|
-
import { createHash } from "node:crypto";
|
|
522
|
-
var TEXT_BYTES_PER_TOKEN = 4;
|
|
523
|
-
var BLOCK_OVERHEAD = 4;
|
|
524
|
-
var MESSAGE_OVERHEAD = 4;
|
|
525
|
-
var DefaultTokenEstimator = class {
|
|
526
|
-
estimateMessages(messages) {
|
|
527
|
-
return messages.reduce((total, message) => total + this.estimateMessage(message), 0);
|
|
528
|
-
}
|
|
529
|
-
estimateTools(tools) {
|
|
530
|
-
if (tools.length === 0) {
|
|
531
|
-
return 0;
|
|
532
|
-
}
|
|
533
|
-
return this.estimateText(canonicalJson(tools.map(({ name, description, parameters }) => ({ name, description, parameters })))) + BLOCK_OVERHEAD;
|
|
534
|
-
}
|
|
535
|
-
estimateText(text2) {
|
|
536
|
-
return Math.ceil(Buffer.byteLength(text2, "utf8") / TEXT_BYTES_PER_TOKEN);
|
|
537
|
-
}
|
|
538
|
-
measure(input) {
|
|
539
|
-
const anchor = input.anchor ?? null;
|
|
540
|
-
if (anchor !== null && this.isValidAnchor(input, anchor)) {
|
|
541
|
-
const trailingEntries = input.entries.filter((entry) => entry.seq > anchor.throughSeq);
|
|
542
|
-
const trailingTokens = this.estimateMessages(messagesForEntries(trailingEntries));
|
|
543
|
-
return {
|
|
544
|
-
totalTokens: anchor.contextTokens + trailingTokens,
|
|
545
|
-
anchorTokens: anchor.contextTokens,
|
|
546
|
-
trailingTokens,
|
|
547
|
-
source: "provider_usage"
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
const totalTokens = this.estimateMessages(input.messages) + this.estimateTools(input.tools);
|
|
551
|
-
return {
|
|
552
|
-
totalTokens,
|
|
553
|
-
anchorTokens: 0,
|
|
554
|
-
trailingTokens: totalTokens,
|
|
555
|
-
source: "estimated"
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
estimateMessage(message) {
|
|
559
|
-
if (message.role === "system" && message.toolDefinitions !== void 0)
|
|
560
|
-
return 0;
|
|
561
|
-
if (message.role === "system" || message.role === "user") {
|
|
562
|
-
return MESSAGE_OVERHEAD + BLOCK_OVERHEAD + this.estimateText(message.content);
|
|
563
|
-
}
|
|
564
|
-
if (message.role === "tool-result") {
|
|
565
|
-
return MESSAGE_OVERHEAD + BLOCK_OVERHEAD + this.estimateText(message.content);
|
|
566
|
-
}
|
|
567
|
-
return MESSAGE_OVERHEAD + message.content.reduce((total, block) => {
|
|
568
|
-
if (block.type === "text" || block.type === "reasoning") {
|
|
569
|
-
return total + BLOCK_OVERHEAD + this.estimateText(block.text);
|
|
570
|
-
}
|
|
571
|
-
return total + BLOCK_OVERHEAD + this.estimateText(`${block.call.name}${canonicalJson(block.call.arguments)}`);
|
|
572
|
-
}, 0);
|
|
573
|
-
}
|
|
574
|
-
isValidAnchor(input, anchor) {
|
|
575
|
-
return anchor.provider === input.provider && anchor.model === input.model && anchor.systemFingerprint === input.systemFingerprint && anchor.projectInstructionsFingerprint === input.projectInstructionsFingerprint && anchor.toolsFingerprint === input.toolsFingerprint && input.entries.some((entry) => entry.id === anchor.throughEntryId && entry.seq === anchor.throughSeq);
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
function fingerprintContextPart(value) {
|
|
579
|
-
return createHash("sha256").update(canonicalJson(value)).digest("hex");
|
|
580
|
-
}
|
|
581
|
-
function canonicalJson(value) {
|
|
582
|
-
return JSON.stringify(sortStable(value));
|
|
583
|
-
}
|
|
584
|
-
function sortStable(value) {
|
|
585
|
-
if (Array.isArray(value)) {
|
|
586
|
-
return value.map(sortStable);
|
|
587
|
-
}
|
|
588
|
-
if (value !== null && typeof value === "object") {
|
|
589
|
-
const record = value;
|
|
590
|
-
const sorted = {};
|
|
591
|
-
for (const key of Object.keys(record).sort()) {
|
|
592
|
-
sorted[key] = sortStable(record[key]);
|
|
593
|
-
}
|
|
594
|
-
return sorted;
|
|
595
|
-
}
|
|
596
|
-
return value;
|
|
597
|
-
}
|
|
598
|
-
function messagesForEntries(entries) {
|
|
599
|
-
return entries.flatMap((entry) => {
|
|
600
|
-
if (entry.entryType === "tool_definitions" || entry.entryType === "tool_catalog")
|
|
601
|
-
return [entry.payload.message];
|
|
602
|
-
if (entry.entryType === "system_context") {
|
|
603
|
-
return [entry.payload.message];
|
|
604
|
-
}
|
|
605
|
-
if (entry.entryType === "project_instructions" || entry.entryType === "user_message" || entry.entryType === "reminder") {
|
|
606
|
-
return [entry.payload.message];
|
|
607
|
-
}
|
|
608
|
-
if (entry.entryType === "assistant_message") {
|
|
609
|
-
return [entry.payload.message];
|
|
610
|
-
}
|
|
611
|
-
if (entry.entryType === "tool_result") {
|
|
612
|
-
return [entry.payload.message];
|
|
613
|
-
}
|
|
614
|
-
return [];
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
|
|
618
696
|
// ../../packages/session/session-context/dist/summary-prompt.js
|
|
619
697
|
var COMPACTION_SYSTEM_PROMPT = "Summarize the conversation for continuation. Preserve user goals, explicit constraints, completed work, modified files, architectural decisions, tool outcomes, failures, current TODOs, and concrete state needed to continue. Do not include credentials. Do not invent results.";
|
|
620
698
|
|
|
@@ -8686,7 +8764,6 @@ var UIEventReducer = class _UIEventReducer {
|
|
|
8686
8764
|
}
|
|
8687
8765
|
if (kind === "model.request_started") {
|
|
8688
8766
|
this.state.sessionState = "RUNNING_MODEL";
|
|
8689
|
-
this.#updateContextUsage(payload);
|
|
8690
8767
|
this.state.activeResponse = {
|
|
8691
8768
|
requestId: correlationId,
|
|
8692
8769
|
text: "",
|
|
@@ -8785,7 +8862,6 @@ var UIEventReducer = class _UIEventReducer {
|
|
|
8785
8862
|
if (kind === "model.switched") {
|
|
8786
8863
|
this.state.provider = String("provider" in payload ? payload.provider : this.state.provider);
|
|
8787
8864
|
this.state.model = String("model" in payload ? payload.model : this.state.model);
|
|
8788
|
-
this.#updateContextUsage(payload);
|
|
8789
8865
|
return createUpdate(kind, { payload });
|
|
8790
8866
|
}
|
|
8791
8867
|
return null;
|
|
@@ -8800,7 +8876,7 @@ var UIEventReducer = class _UIEventReducer {
|
|
|
8800
8876
|
}
|
|
8801
8877
|
#updateContextUsage(payload) {
|
|
8802
8878
|
if ("context_tokens" in payload) {
|
|
8803
|
-
this.state.contextTokens = toInt(payload.context_tokens);
|
|
8879
|
+
this.state.contextTokens = payload.context_tokens === null ? null : toInt(payload.context_tokens);
|
|
8804
8880
|
}
|
|
8805
8881
|
if ("context_window" in payload) {
|
|
8806
8882
|
this.state.contextWindow = toInt(payload.context_window);
|
|
@@ -9466,6 +9542,8 @@ function contextUsageLabel(tokens, contextWindow) {
|
|
|
9466
9542
|
if (window <= 0) {
|
|
9467
9543
|
return null;
|
|
9468
9544
|
}
|
|
9545
|
+
if (tokens === null)
|
|
9546
|
+
return `context: ? (?/${formatCompactCount(window)})`;
|
|
9469
9547
|
const used = normalizedCount(tokens);
|
|
9470
9548
|
const ratio = Math.min(100, used / window * 100);
|
|
9471
9549
|
const percent = ratio > 0 && ratio < 0.1 ? "<0.1" : formatScaled(ratio);
|
|
@@ -12335,12 +12413,15 @@ var TerminalUI = class {
|
|
|
12335
12413
|
Object.assign(this.capabilities, capabilities);
|
|
12336
12414
|
}
|
|
12337
12415
|
setSessionId(sessionId) {
|
|
12416
|
+
if (sessionId !== this.#sessionId)
|
|
12417
|
+
this.state.contextTokens = 0;
|
|
12338
12418
|
this.#sessionId = sessionId;
|
|
12339
12419
|
this.#loop?.requestRender();
|
|
12340
12420
|
}
|
|
12341
12421
|
setContextUsage(tokens, contextWindow) {
|
|
12342
12422
|
this.publishEvent({
|
|
12343
12423
|
kind: "ui.context_usage",
|
|
12424
|
+
session_id: this.#sessionId,
|
|
12344
12425
|
payload: { context_tokens: tokens, context_window: contextWindow }
|
|
12345
12426
|
});
|
|
12346
12427
|
}
|
|
@@ -12529,6 +12610,8 @@ var TerminalUI = class {
|
|
|
12529
12610
|
}
|
|
12530
12611
|
/** Reduce a projected event and apply its append-only block change. */
|
|
12531
12612
|
applyProjectedEvent(event) {
|
|
12613
|
+
if (event.kind === "ui.context_usage" && event.session_id !== this.#sessionId)
|
|
12614
|
+
return;
|
|
12532
12615
|
for (const projected of this.#displayPolicy.project(event)) {
|
|
12533
12616
|
this.#applyDisplayEvent(projected);
|
|
12534
12617
|
}
|
|
@@ -16562,7 +16645,8 @@ Authentication failed for ${this.options.provider}. Run /login ${this.options.pr
|
|
|
16562
16645
|
});
|
|
16563
16646
|
if (!history.commitAssistant(result.message, {
|
|
16564
16647
|
requestId,
|
|
16565
|
-
finishReason: result.finishReason
|
|
16648
|
+
finishReason: result.finishReason,
|
|
16649
|
+
...toolCalls.length > 0 || textOf(result.message) !== "" ? { usage: result.usage } : {}
|
|
16566
16650
|
})) {
|
|
16567
16651
|
this.emit("model_response_aborted", {
|
|
16568
16652
|
round: modelRound,
|
|
@@ -16767,7 +16851,8 @@ var HistoryCommitter = class {
|
|
|
16767
16851
|
this.conversationHistory?.appendAssistant({
|
|
16768
16852
|
message,
|
|
16769
16853
|
requestId: metadata.requestId,
|
|
16770
|
-
finishReason: metadata.finishReason
|
|
16854
|
+
finishReason: metadata.finishReason,
|
|
16855
|
+
...metadata.usage === void 0 ? {} : { usage: metadata.usage }
|
|
16771
16856
|
});
|
|
16772
16857
|
}
|
|
16773
16858
|
this.messages.push(message);
|
|
@@ -16778,7 +16863,8 @@ var HistoryCommitter = class {
|
|
|
16778
16863
|
this.conversationHistory?.appendAssistant({
|
|
16779
16864
|
message,
|
|
16780
16865
|
requestId: metadata.requestId,
|
|
16781
|
-
finishReason: metadata.finishReason
|
|
16866
|
+
finishReason: metadata.finishReason,
|
|
16867
|
+
...metadata.usage === void 0 ? {} : { usage: metadata.usage }
|
|
16782
16868
|
});
|
|
16783
16869
|
}
|
|
16784
16870
|
this.messages.push(message);
|
|
@@ -17385,24 +17471,22 @@ function createSessionRuntime(options) {
|
|
|
17385
17471
|
if (notify === void 0) {
|
|
17386
17472
|
return;
|
|
17387
17473
|
}
|
|
17388
|
-
const entries = options.sessionController.history?.entries() ?? [];
|
|
17389
|
-
const context = new ContextBuilder().build({
|
|
17390
|
-
entries,
|
|
17391
|
-
currentProvider: route.provider,
|
|
17392
|
-
currentModel: route.model
|
|
17393
|
-
});
|
|
17394
|
-
const estimator = new DefaultTokenEstimator();
|
|
17395
17474
|
notify({
|
|
17396
|
-
contextTokens:
|
|
17475
|
+
contextTokens: options.sessionController.history === null ? 0 : options.sessionController.history.contextTokens,
|
|
17397
17476
|
contextWindow: selectedModel.contextWindow
|
|
17398
17477
|
});
|
|
17399
17478
|
};
|
|
17479
|
+
let unsubscribeHistory;
|
|
17400
17480
|
const refreshSession = () => {
|
|
17401
17481
|
const sessionId = options.sessionController.currentSessionId;
|
|
17402
17482
|
const history = options.sessionController.history;
|
|
17403
17483
|
if (sessionId === null || history === null) {
|
|
17404
17484
|
throw new Error("no active session");
|
|
17405
17485
|
}
|
|
17486
|
+
unsubscribeHistory?.();
|
|
17487
|
+
unsubscribeHistory = history.onChange(() => {
|
|
17488
|
+
if (options.sessionController.history === history) refreshContextUsage();
|
|
17489
|
+
});
|
|
17406
17490
|
session.setSessionId(sessionId);
|
|
17407
17491
|
options.presentation?.sessionChanged?.(sessionId);
|
|
17408
17492
|
let entries = history.entries();
|
|
@@ -17470,6 +17554,7 @@ function createSessionRuntime(options) {
|
|
|
17470
17554
|
compact: () => options.sessionController.compact(),
|
|
17471
17555
|
refreshContextUsage,
|
|
17472
17556
|
async close() {
|
|
17557
|
+
unsubscribeHistory?.();
|
|
17473
17558
|
try {
|
|
17474
17559
|
await recorder.close();
|
|
17475
17560
|
} finally {
|