cawdex 1.35.86 → 1.35.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/command-palette.js +1 -0
- package/dist/command-palette.js.map +1 -1
- package/dist/index.js +21 -12
- package/dist/index.js.map +1 -1
- package/dist/lifespan.d.ts +37 -0
- package/dist/lifespan.js +229 -0
- package/dist/lifespan.js.map +1 -0
- package/dist/query.js +43 -2
- package/dist/query.js.map +1 -1
- package/dist/tools/research-sources.d.ts +5 -0
- package/dist/tools/research-sources.js +72 -0
- package/dist/tools/research-sources.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CawdexConfig, Message } from './types.js';
|
|
2
|
+
export type LifespanLevel = 'low' | 'medium' | 'high';
|
|
3
|
+
export interface LifespanDimension {
|
|
4
|
+
id: 'compression' | 'interference' | 'revision' | 'maintenance';
|
|
5
|
+
label: string;
|
|
6
|
+
score: number;
|
|
7
|
+
level: LifespanLevel;
|
|
8
|
+
evidence: string[];
|
|
9
|
+
actions: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface LifespanReport {
|
|
12
|
+
format: 'cawdex-lifespan-v1';
|
|
13
|
+
version: 1;
|
|
14
|
+
generatedAt: string;
|
|
15
|
+
cwd: string;
|
|
16
|
+
summary: {
|
|
17
|
+
overallScore: number;
|
|
18
|
+
level: LifespanLevel;
|
|
19
|
+
estimatedTokens: number;
|
|
20
|
+
contextWindowTokens: number;
|
|
21
|
+
contextPercent: number;
|
|
22
|
+
messageCount: number;
|
|
23
|
+
userTurns: number;
|
|
24
|
+
assistantTurns: number;
|
|
25
|
+
toolMessages: number;
|
|
26
|
+
toolCalls: number;
|
|
27
|
+
toolErrors: number;
|
|
28
|
+
};
|
|
29
|
+
dimensions: LifespanDimension[];
|
|
30
|
+
nextActions: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface LifespanFormatOptions {
|
|
33
|
+
json: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function parseLifespanArgs(args: string): LifespanFormatOptions;
|
|
36
|
+
export declare function buildLifespanReport(messages: Message[], config: Pick<CawdexConfig, 'model' | 'provider' | 'baseURL' | 'contextWindowTokens' | 'fallbackModel' | 'memory'>, cwd: string, now?: Date): LifespanReport;
|
|
37
|
+
export declare function formatLifespanReport(report: LifespanReport, options?: LifespanFormatOptions): string;
|
package/dist/lifespan.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { estimateTokens, inferContextWindowTokens } from './compaction.js';
|
|
2
|
+
function clampScore(value) {
|
|
3
|
+
if (!Number.isFinite(value))
|
|
4
|
+
return 0;
|
|
5
|
+
return Math.max(0, Math.min(100, Math.round(value)));
|
|
6
|
+
}
|
|
7
|
+
function levelFor(score) {
|
|
8
|
+
if (score >= 67)
|
|
9
|
+
return 'high';
|
|
10
|
+
if (score >= 34)
|
|
11
|
+
return 'medium';
|
|
12
|
+
return 'low';
|
|
13
|
+
}
|
|
14
|
+
function textOf(message) {
|
|
15
|
+
return typeof message.content === 'string' ? message.content : '';
|
|
16
|
+
}
|
|
17
|
+
function countMatches(messages, pattern) {
|
|
18
|
+
let count = 0;
|
|
19
|
+
for (const message of messages) {
|
|
20
|
+
const text = textOf(message);
|
|
21
|
+
if (text && pattern.test(text))
|
|
22
|
+
count++;
|
|
23
|
+
}
|
|
24
|
+
return count;
|
|
25
|
+
}
|
|
26
|
+
function countAllMatches(messages, pattern) {
|
|
27
|
+
let count = 0;
|
|
28
|
+
for (const message of messages) {
|
|
29
|
+
const text = textOf(message);
|
|
30
|
+
if (!text)
|
|
31
|
+
continue;
|
|
32
|
+
const matches = text.match(pattern);
|
|
33
|
+
if (matches)
|
|
34
|
+
count += matches.length;
|
|
35
|
+
}
|
|
36
|
+
return count;
|
|
37
|
+
}
|
|
38
|
+
function lastUserMessage(messages) {
|
|
39
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
40
|
+
if (messages[i].role === 'user')
|
|
41
|
+
return textOf(messages[i]);
|
|
42
|
+
}
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
function firstLines(values, limit) {
|
|
46
|
+
return [...new Set(values.filter(Boolean))].slice(0, limit);
|
|
47
|
+
}
|
|
48
|
+
function compactOneLine(value, limit = 110) {
|
|
49
|
+
const oneLine = value.replace(/\s+/g, ' ').trim();
|
|
50
|
+
return oneLine.length <= limit ? oneLine : `${oneLine.slice(0, Math.max(0, limit - 3))}...`;
|
|
51
|
+
}
|
|
52
|
+
function uniq(values) {
|
|
53
|
+
return [...new Set(values)];
|
|
54
|
+
}
|
|
55
|
+
function dimension(id, label, score, evidence, actions) {
|
|
56
|
+
const normalized = clampScore(score);
|
|
57
|
+
return {
|
|
58
|
+
id,
|
|
59
|
+
label,
|
|
60
|
+
score: normalized,
|
|
61
|
+
level: levelFor(normalized),
|
|
62
|
+
evidence: firstLines(evidence, 5),
|
|
63
|
+
actions: firstLines(actions, 5),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function parseLifespanArgs(args) {
|
|
67
|
+
const parts = args.split(/\s+/).map((part) => part.trim()).filter(Boolean);
|
|
68
|
+
return {
|
|
69
|
+
json: parts.some((part, index) => part === '--json'
|
|
70
|
+
|| part === 'json'
|
|
71
|
+
|| part === 'format=json'
|
|
72
|
+
|| part === '--format=json'
|
|
73
|
+
|| (part === '--format' && parts[index + 1] === 'json')),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function buildLifespanReport(messages, config, cwd, now = new Date()) {
|
|
77
|
+
const estimatedTokens = estimateTokens(messages);
|
|
78
|
+
const contextWindowTokens = inferContextWindowTokens(config);
|
|
79
|
+
const contextPercent = contextWindowTokens > 0 ? estimatedTokens / contextWindowTokens : 0;
|
|
80
|
+
const userTurns = messages.filter((message) => message.role === 'user').length;
|
|
81
|
+
const assistantTurns = messages.filter((message) => message.role === 'assistant').length;
|
|
82
|
+
const toolMessages = messages.filter((message) => message.role === 'tool').length;
|
|
83
|
+
const toolCalls = messages.reduce((sum, message) => sum + (message.tool_calls?.length ?? 0), 0);
|
|
84
|
+
const toolErrors = countMatches(messages, /\b(error|failed|failure|timeout|timed out|exception|traceback|rate limit|429)\b/i);
|
|
85
|
+
const compactedMarkers = countMatches(messages, /(CONVERSATION SUMMARY|context cap|omitted \d+ older messages|compacted \d+)/i);
|
|
86
|
+
const commandTurns = messages.filter((message) => message.role === 'user' && textOf(message).trim().startsWith('/')).length;
|
|
87
|
+
const correctionTurns = countMatches(messages, /\b(actually|instead|change|revise|make it|not that|wrong|should have|shouldn't|doesn't|isn't)\b/i);
|
|
88
|
+
const oldTaskReferences = countAllMatches(messages, /\b(poem|essay|game|config|resume|history|logo|swarm|oauth|openrouter|benchmark|theme)\b/gi);
|
|
89
|
+
const recentUser = compactOneLine(lastUserMessage(messages), 140);
|
|
90
|
+
const providerText = `${config.provider || ''} ${config.baseURL || ''}`.toLowerCase();
|
|
91
|
+
const model = (config.model || '').toLowerCase();
|
|
92
|
+
const isOpenRouter = providerText.includes('openrouter');
|
|
93
|
+
const memoryEnabled = config.memory?.enabled !== false;
|
|
94
|
+
const fallbackEnabled = Boolean(config.fallbackModel && config.fallbackModel !== config.model);
|
|
95
|
+
const dimensions = [];
|
|
96
|
+
const compressionEvidence = [
|
|
97
|
+
`${estimatedTokens.toLocaleString()} estimated tokens across ${messages.length} messages.`,
|
|
98
|
+
`${Math.round(contextPercent * 100)}% of the inferred ${contextWindowTokens.toLocaleString()} token context window is in use.`,
|
|
99
|
+
];
|
|
100
|
+
if (compactedMarkers > 0)
|
|
101
|
+
compressionEvidence.push(`${compactedMarkers} compaction/context-cap marker${compactedMarkers === 1 ? '' : 's'} detected.`);
|
|
102
|
+
if (messages.length > 80)
|
|
103
|
+
compressionEvidence.push('Long message history increases stale-context and cursor recovery risk.');
|
|
104
|
+
const compressionScore = contextPercent * 90
|
|
105
|
+
+ Math.max(0, messages.length - 40) * 0.7
|
|
106
|
+
+ compactedMarkers * 12;
|
|
107
|
+
dimensions.push(dimension('compression', 'Compression aging', compressionScore, compressionEvidence, [
|
|
108
|
+
'/context dossier <current task> before a large patch or benchmark run.',
|
|
109
|
+
'/fork <name> when starting an unrelated task from an old session.',
|
|
110
|
+
'/history to confirm token growth before another provider call.',
|
|
111
|
+
'Use /clear only when the current thread is no longer needed.',
|
|
112
|
+
]));
|
|
113
|
+
const interferenceEvidence = [
|
|
114
|
+
`${userTurns} user turn${userTurns === 1 ? '' : 's'}, ${assistantTurns} assistant turn${assistantTurns === 1 ? '' : 's'}, ${toolMessages} tool message${toolMessages === 1 ? '' : 's'}.`,
|
|
115
|
+
];
|
|
116
|
+
if (oldTaskReferences >= 10)
|
|
117
|
+
interferenceEvidence.push(`Repeated prior task nouns detected (${oldTaskReferences} hits), which can bleed into the next answer.`);
|
|
118
|
+
if (recentUser)
|
|
119
|
+
interferenceEvidence.push(`Latest user turn: "${recentUser}"`);
|
|
120
|
+
if (toolCalls > 20)
|
|
121
|
+
interferenceEvidence.push(`${toolCalls} tool call records are still in the active history.`);
|
|
122
|
+
const interferenceScore = Math.max(0, userTurns - 6) * 4
|
|
123
|
+
+ Math.max(0, oldTaskReferences - 8) * 2
|
|
124
|
+
+ Math.max(0, toolCalls - 12) * 1.5
|
|
125
|
+
+ (recentUser.length > 0 && recentUser.length < 30 && userTurns > 4 ? 12 : 0);
|
|
126
|
+
dimensions.push(dimension('interference', 'Interference aging', interferenceScore, interferenceEvidence, [
|
|
127
|
+
'/fork <name> before switching product goals or benchmark targets.',
|
|
128
|
+
'/back to remove accidental or provider-corrupted turns.',
|
|
129
|
+
'Restate the exact target in one sentence before asking for a long generation.',
|
|
130
|
+
'/context brief to re-anchor on the current repo instead of old chat content.',
|
|
131
|
+
]));
|
|
132
|
+
const revisionEvidence = [
|
|
133
|
+
`${commandTurns} slash-command turn${commandTurns === 1 ? '' : 's'} and ${correctionTurns} correction/revision cue${correctionTurns === 1 ? '' : 's'} detected.`,
|
|
134
|
+
];
|
|
135
|
+
if (correctionTurns > 4)
|
|
136
|
+
revisionEvidence.push('Several correction turns suggest the active state may differ from earlier instructions.');
|
|
137
|
+
if (commandTurns > 8)
|
|
138
|
+
revisionEvidence.push('Many local command turns can make the next model call inherit stale operational context.');
|
|
139
|
+
const revisionScore = correctionTurns * 8 + Math.max(0, commandTurns - 4) * 3;
|
|
140
|
+
dimensions.push(dimension('revision', 'Revision aging', revisionScore, revisionEvidence, [
|
|
141
|
+
'/manifest <target> to state expected files, risks, and verification before edits.',
|
|
142
|
+
'/context dossier <current task> to rebuild a focused local file map.',
|
|
143
|
+
'For UI or behavior rewrites, name the current desired behavior explicitly.',
|
|
144
|
+
'/export md before major rewrites if the prior decisions must be preserved.',
|
|
145
|
+
]));
|
|
146
|
+
const maintenanceEvidence = [
|
|
147
|
+
`Provider: ${config.provider || 'unknown'}; model: ${config.model || 'unknown'}.`,
|
|
148
|
+
`MemPalace memory is ${memoryEnabled ? 'enabled' : 'disabled'}.`,
|
|
149
|
+
];
|
|
150
|
+
if (toolErrors > 0)
|
|
151
|
+
maintenanceEvidence.push(`${toolErrors} error/timeout/rate-limit marker${toolErrors === 1 ? '' : 's'} found in active history.`);
|
|
152
|
+
if (isOpenRouter && !fallbackEnabled)
|
|
153
|
+
maintenanceEvidence.push('OpenRouter is active without a distinct fallback model.');
|
|
154
|
+
if (isOpenRouter && /:free|openrouter\/free|owl-alpha/.test(model))
|
|
155
|
+
maintenanceEvidence.push('Free or experimental OpenRouter model detected; latency and empty responses are more likely.');
|
|
156
|
+
const maintenanceScore = toolErrors * 10
|
|
157
|
+
+ (memoryEnabled ? 0 : 18)
|
|
158
|
+
+ (isOpenRouter && !fallbackEnabled ? 18 : 0)
|
|
159
|
+
+ (isOpenRouter && /:free|openrouter\/free|owl-alpha/.test(model) ? 12 : 0);
|
|
160
|
+
dimensions.push(dimension('maintenance', 'Maintenance aging', maintenanceScore, maintenanceEvidence, [
|
|
161
|
+
'/doctor no-registry for local install/config readiness without npm traffic.',
|
|
162
|
+
'/fallback <model-id> when using OpenRouter for interactive work.',
|
|
163
|
+
'/memory status to confirm project/global memory is available.',
|
|
164
|
+
'/openai-login smoke when Codex OAuth should be the primary provider.',
|
|
165
|
+
]));
|
|
166
|
+
const overallScore = clampScore(dimensions.reduce((sum, item) => sum + item.score, 0) / dimensions.length);
|
|
167
|
+
const nextActions = uniq(dimensions
|
|
168
|
+
.filter((item) => item.level !== 'low')
|
|
169
|
+
.sort((a, b) => b.score - a.score)
|
|
170
|
+
.flatMap((item) => item.actions.slice(0, 2))).slice(0, 6);
|
|
171
|
+
return {
|
|
172
|
+
format: 'cawdex-lifespan-v1',
|
|
173
|
+
version: 1,
|
|
174
|
+
generatedAt: now.toISOString(),
|
|
175
|
+
cwd,
|
|
176
|
+
summary: {
|
|
177
|
+
overallScore,
|
|
178
|
+
level: levelFor(overallScore),
|
|
179
|
+
estimatedTokens,
|
|
180
|
+
contextWindowTokens,
|
|
181
|
+
contextPercent,
|
|
182
|
+
messageCount: messages.length,
|
|
183
|
+
userTurns,
|
|
184
|
+
assistantTurns,
|
|
185
|
+
toolMessages,
|
|
186
|
+
toolCalls,
|
|
187
|
+
toolErrors,
|
|
188
|
+
},
|
|
189
|
+
dimensions,
|
|
190
|
+
nextActions,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function formatPercent(value) {
|
|
194
|
+
return `${Math.round(value * 100)}%`;
|
|
195
|
+
}
|
|
196
|
+
function formatActionBlock(actions) {
|
|
197
|
+
if (actions.length === 0)
|
|
198
|
+
return [' Actions: none required right now.'];
|
|
199
|
+
return [' Actions:', ...actions.map((action) => ` - ${action}`)];
|
|
200
|
+
}
|
|
201
|
+
export function formatLifespanReport(report, options = { json: false }) {
|
|
202
|
+
if (options.json)
|
|
203
|
+
return JSON.stringify(report, null, 2);
|
|
204
|
+
const lines = [
|
|
205
|
+
'',
|
|
206
|
+
' Cawdex Lifespan Diagnostic',
|
|
207
|
+
'',
|
|
208
|
+
` Overall: ${report.summary.level} (${report.summary.overallScore}/100)`,
|
|
209
|
+
` Window: ~${report.summary.estimatedTokens.toLocaleString()} / ${report.summary.contextWindowTokens.toLocaleString()} tokens (${formatPercent(report.summary.contextPercent)})`,
|
|
210
|
+
` Turns: ${report.summary.userTurns} user / ${report.summary.assistantTurns} assistant / ${report.summary.toolMessages} tool`,
|
|
211
|
+
'',
|
|
212
|
+
];
|
|
213
|
+
for (const item of report.dimensions) {
|
|
214
|
+
lines.push(` ${item.label}: ${item.level} (${item.score}/100)`);
|
|
215
|
+
for (const evidence of item.evidence)
|
|
216
|
+
lines.push(` - ${evidence}`);
|
|
217
|
+
lines.push(...formatActionBlock(item.actions.slice(0, item.level === 'low' ? 1 : 3)));
|
|
218
|
+
lines.push('');
|
|
219
|
+
}
|
|
220
|
+
if (report.nextActions.length > 0) {
|
|
221
|
+
lines.push(' Next actions:');
|
|
222
|
+
for (const action of report.nextActions)
|
|
223
|
+
lines.push(` - ${action}`);
|
|
224
|
+
lines.push('');
|
|
225
|
+
}
|
|
226
|
+
lines.push(' Frame: compression, interference, revision, and maintenance aging for long-running agent sessions.');
|
|
227
|
+
return lines.join('\n');
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=lifespan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifespan.js","sourceRoot":"","sources":["../src/lifespan.ts"],"names":[],"mappings":"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"}
|
package/dist/query.js
CHANGED
|
@@ -17,7 +17,7 @@ import { audioCue } from './audio.js';
|
|
|
17
17
|
import { setStatus } from './status.js';
|
|
18
18
|
import { collapseCompletedTurns } from './turn-context.js';
|
|
19
19
|
import * as liveQueue from './live-queue.js';
|
|
20
|
-
import { isFooterActive, setFooterActivity, setFooterCost, writeScrollableLine } from './fixed-footer.js';
|
|
20
|
+
import { activateFooter, buildFooterSnapshot, isFooterActive, setFooterActivity, setFooterCost, shouldUseFixedFooter, writeScrollableLine, } from './fixed-footer.js';
|
|
21
21
|
import { applyQueuedInputChunk, drainQueuedInputBytes, queuedInputBytesToText } from './prompt-buffer.js';
|
|
22
22
|
import { emit as dbgEmit } from './debug.js';
|
|
23
23
|
import { applyAgentToolInstructions } from './agents-md.js';
|
|
@@ -203,6 +203,18 @@ function startWorkingIndicator(startedAtMs, screenReader, turn = 0) {
|
|
|
203
203
|
];
|
|
204
204
|
let frame = 0;
|
|
205
205
|
let stopped = false;
|
|
206
|
+
if (isFooterActive()) {
|
|
207
|
+
setFooterActivity(messages[0], turn, startedAtMs);
|
|
208
|
+
return {
|
|
209
|
+
stop: () => {
|
|
210
|
+
if (stopped)
|
|
211
|
+
return;
|
|
212
|
+
stopped = true;
|
|
213
|
+
if (isFooterActive())
|
|
214
|
+
setFooterActivity('Receiving response', turn, startedAtMs);
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
206
218
|
const paint = () => {
|
|
207
219
|
const message = messages[Math.floor(frame / 8) % messages.length];
|
|
208
220
|
if (isFooterActive()) {
|
|
@@ -232,6 +244,22 @@ function startWorkingIndicator(startedAtMs, screenReader, turn = 0) {
|
|
|
232
244
|
},
|
|
233
245
|
};
|
|
234
246
|
}
|
|
247
|
+
function ensureTurnFooterActive(ctx, screenReader) {
|
|
248
|
+
if (screenReader)
|
|
249
|
+
return;
|
|
250
|
+
if (isFooterActive())
|
|
251
|
+
return;
|
|
252
|
+
if (!shouldUseFixedFooter(ctx.config))
|
|
253
|
+
return;
|
|
254
|
+
activateFooter(buildFooterSnapshot(ctx.config, ctx.mode, { id: ctx.sessionId }, ctx.cwd));
|
|
255
|
+
}
|
|
256
|
+
function clearActiveTurnHandle(streamAbort) {
|
|
257
|
+
const g = globalThis;
|
|
258
|
+
if (g.__turnAbortCtl === streamAbort) {
|
|
259
|
+
g.__turnAbortCtl = null;
|
|
260
|
+
g.__turnCancelCurrent = null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
235
263
|
/**
|
|
236
264
|
* Count how many NON-OVERLAPPING occurrences of the last `windowSize`
|
|
237
265
|
* characters of `fullText` appear in the full string. Bails as soon as
|
|
@@ -1242,6 +1270,7 @@ export async function runQuery(ctx) {
|
|
|
1242
1270
|
// skips the live queue box (NVDA/JAWS would re-read every cursor move
|
|
1243
1271
|
// as new text, drowning the actual response).
|
|
1244
1272
|
const isScreenReader = ctx.config.voice?.accessibility?.screenReader === true;
|
|
1273
|
+
ensureTurnFooterActive(ctx, isScreenReader);
|
|
1245
1274
|
const inputGuard = startInputSuppression(isScreenReader);
|
|
1246
1275
|
let earlyWorkingIndicator = null;
|
|
1247
1276
|
try {
|
|
@@ -1524,12 +1553,20 @@ export async function runQuery(ctx) {
|
|
|
1524
1553
|
const firstTokenTimeoutMs = resolveTurnFirstTokenTimeoutMs(ctx.config, fastDirect);
|
|
1525
1554
|
let streamIdleTimedOut = false;
|
|
1526
1555
|
const streamIdleTimeoutMs = resolveStreamIdleTimeoutMs(fastDirect);
|
|
1556
|
+
let closeCurrentStream = null;
|
|
1527
1557
|
try {
|
|
1528
1558
|
const requestConfig = fastDirect
|
|
1529
1559
|
? { ...ctx.config, maxTokens: Math.min(ctx.config.maxTokens ?? 700, 700) }
|
|
1530
1560
|
: ctx.config;
|
|
1531
1561
|
const stream = streamChat(requestConfig, apiMessages, requestTools, streamAbort.signal);
|
|
1532
1562
|
const iterator = stream[Symbol.asyncIterator]();
|
|
1563
|
+
closeCurrentStream = () => {
|
|
1564
|
+
const close = iterator.return;
|
|
1565
|
+
closeCurrentStream = null;
|
|
1566
|
+
if (typeof close === 'function') {
|
|
1567
|
+
void close.call(iterator, undefined).catch(() => { });
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1533
1570
|
async function waitForNextEvent(nextPromise, waitTimeoutMs) {
|
|
1534
1571
|
if (waitTimeoutMs <= 0)
|
|
1535
1572
|
return nextPromise;
|
|
@@ -1657,10 +1694,11 @@ export async function runQuery(ctx) {
|
|
|
1657
1694
|
streamAbort.abort();
|
|
1658
1695
|
}
|
|
1659
1696
|
catch { /* close any provider socket left open after done */ }
|
|
1660
|
-
|
|
1697
|
+
closeCurrentStream?.();
|
|
1661
1698
|
break;
|
|
1662
1699
|
}
|
|
1663
1700
|
}
|
|
1701
|
+
closeCurrentStream?.();
|
|
1664
1702
|
if (!usageRecorded && (hasOutput || (toolCalls && toolCalls.length > 0))) {
|
|
1665
1703
|
const promptEstimate = Math.max(1, estimateTokens(apiMessages));
|
|
1666
1704
|
const completionEstimate = Math.max(1, Math.ceil(((fullText || '') + (toolCalls ? JSON.stringify(toolCalls) : '')).length / 3.5));
|
|
@@ -1696,6 +1734,8 @@ export async function runQuery(ctx) {
|
|
|
1696
1734
|
// print below shouldn't trail an animated row.
|
|
1697
1735
|
workingIndicator?.stop();
|
|
1698
1736
|
workingIndicator = null;
|
|
1737
|
+
closeCurrentStream?.();
|
|
1738
|
+
clearActiveTurnHandle(streamAbort);
|
|
1699
1739
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1700
1740
|
// Always close the streaming line first so the error doesn't glue to text.
|
|
1701
1741
|
if (hasOutput && !lastCharWasNewline)
|
|
@@ -1845,6 +1885,7 @@ export async function runQuery(ctx) {
|
|
|
1845
1885
|
ctx.messages.push({ role: 'assistant', content: `[API error: ${msg}]` });
|
|
1846
1886
|
break;
|
|
1847
1887
|
}
|
|
1888
|
+
clearActiveTurnHandle(streamAbort);
|
|
1848
1889
|
if (!hasOutput && (!toolCalls || toolCalls.length === 0)) {
|
|
1849
1890
|
const failedModel = ctx.config.model;
|
|
1850
1891
|
const fallback = fallbackModelForTurn(ctx.config, usedFallbackModel);
|