cawdex 1.35.68 → 1.35.73
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 +188 -188
- package/dist/command-palette.js +5 -4
- package/dist/command-palette.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +20 -13
- package/dist/config.js.map +1 -1
- package/dist/curator.d.ts +2 -2
- package/dist/curator.js +2 -2
- package/dist/fixed-footer.d.ts +29 -0
- package/dist/fixed-footer.js +383 -0
- package/dist/fixed-footer.js.map +1 -0
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +7 -7
- package/dist/hooks.js.map +1 -1
- package/dist/index.js +362 -66
- package/dist/index.js.map +1 -1
- package/dist/instant-answer.d.ts +6 -1
- package/dist/instant-answer.js +35 -1
- package/dist/instant-answer.js.map +1 -1
- package/dist/live-queue.d.ts +0 -32
- package/dist/live-queue.js +15 -0
- package/dist/live-queue.js.map +1 -1
- package/dist/modes.d.ts +2 -1
- package/dist/modes.js +368 -361
- package/dist/modes.js.map +1 -1
- package/dist/query.d.ts +1 -0
- package/dist/query.js +162 -42
- package/dist/query.js.map +1 -1
- package/dist/swarm.d.ts +8 -3
- package/dist/swarm.js +39 -14
- package/dist/swarm.js.map +1 -1
- package/dist/system-prompt.js +14 -14
- package/dist/system-prompt.js.map +1 -1
- package/dist/theme.d.ts +4 -0
- package/dist/theme.js +22 -0
- package/dist/theme.js.map +1 -1
- package/dist/tools/skill.d.ts +2 -2
- package/dist/tools/skill.js +2 -2
- package/dist/types.d.ts +15 -0
- package/dist/types.js.map +1 -1
- package/dist/updater.d.ts +16 -0
- package/dist/updater.js +157 -0
- package/dist/updater.js.map +1 -0
- package/dist/walkthrough.js +7 -7
- package/package.json +1 -2
package/dist/modes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modes.js","sourceRoot":"","sources":["../src/modes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,CAAC,MAAM,KAAK,GAA6B;IAC7C,GAAG,EAAE;QACH,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,qDAAqD;QAClE,oBAAoB,EAAE;;;;;;;oCAOU;QAChC,cAAc,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC;KACjF;IAED,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,oDAAoD;QACjE,oBAAoB,EAAE;;;;;;;;;;uFAU6D;QACnF,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KACtD;IAED,GAAG,EAAE;QACH,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,wCAAwC;QACrD,oBAAoB,EAAE;;;;;;;;;;;4FAWkE;QACxF,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,CAAC;QAChE,WAAW,EAAE,GAAG;KACjB;IAED,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,kDAAkD;QAC/D,oBAAoB,EAAE;;;;;;;;;gDASsB;QAC5C,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC;QACtE,WAAW,EAAE,GAAG;KACjB;IAED,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,2CAA2C;QACxD,oBAAoB,EAAE;;;;;;;;;;iEAUuC;QAC7D,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC;QACzD,WAAW,EAAE,GAAG;KACjB;IAED,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,gCAAgC;QAC7C,oBAAoB,EAAE;;;;;;;;;;;2CAWiB;QACvC,cAAc,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC;QAClE,WAAW,EAAE,GAAG;KACjB;IAED,SAAS,EAAE;QACT,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,iGAAiG;QAC9G,oBAAoB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sEAyD4C;QAClE,cAAc,EAAE,CAAC,MAAM,EAAE,mBAAmB,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,oBAAoB,CAAC;QACrN,WAAW,EAAE,GAAG;KACjB;IAED,SAAS,EAAE;QACT,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,0CAA0C;QACvD,oBAAoB,EAAE;;;;;;;;;;;;;0DAagC;QACtD,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC;QACtE,WAAW,EAAE,GAAG;KACjB;IAED,
|
|
1
|
+
{"version":3,"file":"modes.js","sourceRoot":"","sources":["../src/modes.ts"],"names":[],"mappings":"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"}
|
package/dist/query.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as readline from 'node:readline/promises';
|
|
|
2
2
|
import type { Message, CawdexConfig } from './types.js';
|
|
3
3
|
import type { Mode } from './modes.js';
|
|
4
4
|
export declare function resolveFirstTokenTimeoutMs(config: Pick<CawdexConfig, 'model' | 'provider'>): number;
|
|
5
|
+
export declare function resolveStreamIdleTimeoutMs(fastDirect?: boolean): number;
|
|
5
6
|
export declare function isKnownFlakyOpenRouterModel(config: Pick<CawdexConfig, 'model' | 'provider'>): boolean;
|
|
6
7
|
export declare function fallbackModelForKnownFlakyTurn(config: CawdexConfig, usedFallbackModel?: boolean): string | null;
|
|
7
8
|
export declare function isTurnCancelKeySequence(chunk: Buffer): boolean;
|
package/dist/query.js
CHANGED
|
@@ -10,13 +10,14 @@ import { runHooks } from './hooks.js';
|
|
|
10
10
|
import { scanToolCall, printSecurityWarning } from './security.js';
|
|
11
11
|
import { trackUsage } from './cost-tracker.js';
|
|
12
12
|
import { shouldCompact, compactMessages, quickCompact, buildCompactionConfig, contextCapTokens, enforceContextCap, inferContextWindowTokens, } from './compaction.js';
|
|
13
|
-
import { theme, sym, printToolRun, printToolResult, printThinkingOpen, printThinkingText, printThinkingClose, printCost, printApiError, formatDuration, categorizeApiError } from './theme.js';
|
|
13
|
+
import { assistantTranscriptPrefix, theme, sym, printToolRun, printToolResult, printThinkingOpen, printThinkingText, printThinkingClose, printCost, printApiError, formatDuration, categorizeApiError } from './theme.js';
|
|
14
14
|
import { isVoiceEnabled, getTtsConfig, getAccessibilityConfig, speakAssistantResponse, speak, speakUserEcho, } from './voice.js';
|
|
15
15
|
import { isLikelyDestructive, describeDestructive, countWords, summarize } from './accessibility.js';
|
|
16
16
|
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
21
|
import { applyQueuedInputChunk, drainQueuedInputBytes, queuedInputBytesToText } from './prompt-buffer.js';
|
|
21
22
|
import { emit as dbgEmit } from './debug.js';
|
|
22
23
|
import { buildBenchmarkCompletionReminder, buildBenchmarkTrajectorySystemBlock, makeBenchmarkInvalidToolActionEvent, makeBenchmarkTraceEvent, writeBenchmarkTrace, } from './benchmark-trace.js';
|
|
@@ -34,6 +35,9 @@ const INTERACTIVE_FLAKY_FIRST_TOKEN_TIMEOUT_MS = 6_000;
|
|
|
34
35
|
const NON_INTERACTIVE_FIRST_TOKEN_TIMEOUT_MS = 60_000;
|
|
35
36
|
const NON_INTERACTIVE_FLAKY_FIRST_TOKEN_TIMEOUT_MS = 20_000;
|
|
36
37
|
const FAST_DIRECT_FIRST_TOKEN_TIMEOUT_MS = 8_000;
|
|
38
|
+
const INTERACTIVE_STREAM_IDLE_TIMEOUT_MS = 45_000;
|
|
39
|
+
const NON_INTERACTIVE_STREAM_IDLE_TIMEOUT_MS = 120_000;
|
|
40
|
+
const FAST_DIRECT_STREAM_IDLE_TIMEOUT_MS = 20_000;
|
|
37
41
|
const KNOWN_FLAKY_OPENROUTER_MODEL_PATTERNS = [
|
|
38
42
|
'owl-alpha',
|
|
39
43
|
'horizon-alpha',
|
|
@@ -41,6 +45,7 @@ const KNOWN_FLAKY_OPENROUTER_MODEL_PATTERNS = [
|
|
|
41
45
|
'optimus-alpha',
|
|
42
46
|
'quasar-alpha',
|
|
43
47
|
'deepseek-v4-flash',
|
|
48
|
+
'deepseek-v4-pro',
|
|
44
49
|
];
|
|
45
50
|
function envTimeoutMs(name, fallback) {
|
|
46
51
|
const raw = process.env[name];
|
|
@@ -59,6 +64,14 @@ export function resolveFirstTokenTimeoutMs(config) {
|
|
|
59
64
|
: (flaky ? INTERACTIVE_FLAKY_FIRST_TOKEN_TIMEOUT_MS : INTERACTIVE_FIRST_TOKEN_TIMEOUT_MS);
|
|
60
65
|
return envTimeoutMs('CAWDEX_FIRST_TOKEN_TIMEOUT_MS', fallback);
|
|
61
66
|
}
|
|
67
|
+
export function resolveStreamIdleTimeoutMs(fastDirect = false) {
|
|
68
|
+
const fallback = process.env.CAWDEX_NON_INTERACTIVE === '1'
|
|
69
|
+
? NON_INTERACTIVE_STREAM_IDLE_TIMEOUT_MS
|
|
70
|
+
: fastDirect
|
|
71
|
+
? FAST_DIRECT_STREAM_IDLE_TIMEOUT_MS
|
|
72
|
+
: INTERACTIVE_STREAM_IDLE_TIMEOUT_MS;
|
|
73
|
+
return envTimeoutMs('CAWDEX_STREAM_IDLE_TIMEOUT_MS', fallback);
|
|
74
|
+
}
|
|
62
75
|
export function isKnownFlakyOpenRouterModel(config) {
|
|
63
76
|
const model = String(config.model || '').toLowerCase();
|
|
64
77
|
const provider = String(config.provider || '').toLowerCase();
|
|
@@ -80,7 +93,10 @@ export function fallbackModelForKnownFlakyTurn(config, usedFallbackModel = false
|
|
|
80
93
|
}
|
|
81
94
|
export function isTurnCancelKeySequence(chunk) {
|
|
82
95
|
const seq = chunk.toString('utf8');
|
|
83
|
-
return (seq === '\x1b
|
|
96
|
+
return (seq === '\x1b' ||
|
|
97
|
+
seq === '\x1b\x1b' ||
|
|
98
|
+
/^\x1b\[27(?:;\d+)*~$/.test(seq) ||
|
|
99
|
+
seq === '\x1b[15~' ||
|
|
84
100
|
seq === '\x1b[15;2~' ||
|
|
85
101
|
seq === '\x1b[15;5~' ||
|
|
86
102
|
seq === '\x1b[15;6~' ||
|
|
@@ -90,6 +106,10 @@ const FAST_DIRECT_SYSTEM_PROMPT = 'You are Cawdex. Answer the user directly and
|
|
|
90
106
|
'Do not mention tools, repositories, or implementation steps unless the user asks.';
|
|
91
107
|
const FAST_DIRECT_POSITIVE = [
|
|
92
108
|
/^(hi|hello|hey|thanks|thank you)\b/i,
|
|
109
|
+
/^(?:i\s+)?(?:need|want)\s+(?:your\s+)?help\b/i,
|
|
110
|
+
/^(?:help me|can you help|could you help|would you help)\b/i,
|
|
111
|
+
/^(?:i|we)\s+(?:like|love|hate|prefer|think|feel|am|are)\b/i,
|
|
112
|
+
/^(?:sorry,?\s*)?(?:make|rewrite|revise|adjust|redo|try)\s+(?:it|that|this)\b/i,
|
|
93
113
|
/^(what|who|when|where|why|how|which)\b/i,
|
|
94
114
|
/^(?:please\s+)?(?:can|could|would|will)\s+you\s+(?:please\s+)?(?:explain|define|summarize|translate|calculate|compute|write|draft|make|create|tell|give)\b/i,
|
|
95
115
|
/^(?:please\s+)?(?:tell|give)\s+me\b/i,
|
|
@@ -125,14 +145,20 @@ function printInteractiveTurnAccepted(config) {
|
|
|
125
145
|
return;
|
|
126
146
|
if (!process.stdout.isTTY)
|
|
127
147
|
return;
|
|
128
|
-
|
|
148
|
+
const line = theme.dim(` submitted to ${config.provider} · ${config.model}. Waiting for model events; Esc or F5 cancels.`);
|
|
149
|
+
if (isFooterActive()) {
|
|
150
|
+
writeScrollableLine(line);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log(line);
|
|
154
|
+
}
|
|
129
155
|
}
|
|
130
156
|
export function formatWorkingIndicatorFrame(elapsedMs, frameIndex = 0, message = 'Working') {
|
|
131
|
-
const frames = ['
|
|
157
|
+
const frames = ['\u25e6', '\u25c7', '\u25c6', '\u25c7'];
|
|
132
158
|
const frame = frames[Math.abs(frameIndex) % frames.length];
|
|
133
|
-
return ` ${frame} ${message} (${formatDuration(elapsedMs)}
|
|
159
|
+
return ` ${frame} ${message} (${formatDuration(elapsedMs)} \u2022 esc to interrupt)`;
|
|
134
160
|
}
|
|
135
|
-
function startWorkingIndicator(startedAtMs, screenReader) {
|
|
161
|
+
function startWorkingIndicator(startedAtMs, screenReader, turn = 0) {
|
|
136
162
|
if (screenReader)
|
|
137
163
|
return null;
|
|
138
164
|
if (process.env.CAWDEX_NON_INTERACTIVE === '1')
|
|
@@ -140,7 +166,7 @@ function startWorkingIndicator(startedAtMs, screenReader) {
|
|
|
140
166
|
if (!process.stdout.isTTY)
|
|
141
167
|
return null;
|
|
142
168
|
const messages = [
|
|
143
|
-
'Working',
|
|
169
|
+
'Working hard on your request',
|
|
144
170
|
'Sumi ink settling',
|
|
145
171
|
'Edo lanterns lit',
|
|
146
172
|
'Kamon crest aligned',
|
|
@@ -149,7 +175,13 @@ function startWorkingIndicator(startedAtMs, screenReader) {
|
|
|
149
175
|
let frame = 0;
|
|
150
176
|
let stopped = false;
|
|
151
177
|
const paint = () => {
|
|
152
|
-
const
|
|
178
|
+
const message = messages[Math.floor(frame / 8) % messages.length];
|
|
179
|
+
if (isFooterActive()) {
|
|
180
|
+
setFooterActivity(message, turn, startedAtMs);
|
|
181
|
+
frame++;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const line = formatWorkingIndicatorFrame(Date.now() - startedAtMs, frame, message);
|
|
153
185
|
process.stdout.write('\r\x1b[K' + theme.dim(line));
|
|
154
186
|
frame++;
|
|
155
187
|
};
|
|
@@ -163,7 +195,10 @@ function startWorkingIndicator(startedAtMs, screenReader) {
|
|
|
163
195
|
return;
|
|
164
196
|
stopped = true;
|
|
165
197
|
clearInterval(timer);
|
|
166
|
-
|
|
198
|
+
if (isFooterActive())
|
|
199
|
+
setFooterActivity('Receiving response', turn, startedAtMs);
|
|
200
|
+
else
|
|
201
|
+
process.stdout.write('\r\x1b[K');
|
|
167
202
|
},
|
|
168
203
|
};
|
|
169
204
|
}
|
|
@@ -278,6 +313,15 @@ function startInputSuppression(screenReader = false) {
|
|
|
278
313
|
}
|
|
279
314
|
return;
|
|
280
315
|
}
|
|
316
|
+
if (detached && isTurnCancelKeySequence(chunk)) {
|
|
317
|
+
if (steerHandler) {
|
|
318
|
+
try {
|
|
319
|
+
steerHandler();
|
|
320
|
+
}
|
|
321
|
+
catch { /* never break input on a cancel error */ }
|
|
322
|
+
}
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
281
325
|
// Esc (0x1B) → Steer trigger, but only for a BARE Esc (chunk of
|
|
282
326
|
// exactly one byte). Multi-byte chunks starting with 0x1B are ANSI
|
|
283
327
|
// escape sequences for arrow keys / function keys / Alt+letter, and
|
|
@@ -438,7 +482,7 @@ export function buildStateBlock(messages) {
|
|
|
438
482
|
const olderCount = actions.length - recent.length;
|
|
439
483
|
const lines = [
|
|
440
484
|
'<task_state>',
|
|
441
|
-
`Original goal: ${goal}${goal.length >= STATE_BLOCK_GOAL_MAX_CHARS ? '
|
|
485
|
+
`Original goal: ${goal}${goal.length >= STATE_BLOCK_GOAL_MAX_CHARS ? '\u2026' : ''}`,
|
|
442
486
|
`Actions completed: ${actions.length}`,
|
|
443
487
|
];
|
|
444
488
|
if (olderCount > 0) {
|
|
@@ -448,7 +492,7 @@ export function buildStateBlock(messages) {
|
|
|
448
492
|
lines.push(`Actions:`);
|
|
449
493
|
}
|
|
450
494
|
recent.forEach((a, i) => {
|
|
451
|
-
lines.push(` ${i + 1}. ${a.tool}(${a.argsPreview}${a.argsPreview.length >= 80 ? '
|
|
495
|
+
lines.push(` ${i + 1}. ${a.tool}(${a.argsPreview}${a.argsPreview.length >= 80 ? '\u2026' : ''})`);
|
|
452
496
|
});
|
|
453
497
|
lines.push('');
|
|
454
498
|
lines.push('Stay focused on the goal. Do not re-issue actions you have already completed — refer to their results in the conversation above.');
|
|
@@ -1091,7 +1135,7 @@ export async function runQuery(ctx) {
|
|
|
1091
1135
|
const failedModel = ctx.config.model;
|
|
1092
1136
|
ctx.config.model = immediateFallback;
|
|
1093
1137
|
resetClient();
|
|
1094
|
-
console.log(theme.warning(` ${sym.warn} ${failedModel} is
|
|
1138
|
+
console.log(theme.warning(` ${sym.warn} ${failedModel} is known to stall in interactive OpenRouter sessions; switching this turn to ${immediateFallback}.`));
|
|
1095
1139
|
console.log(theme.dim(' Override only if you really want it: CAWDEX_ALLOW_FLAKY_MODELS=1'));
|
|
1096
1140
|
}
|
|
1097
1141
|
if (!chainFastDirect) {
|
|
@@ -1103,12 +1147,12 @@ export async function runQuery(ctx) {
|
|
|
1103
1147
|
// because we only care about "in this whole exchange did we see any
|
|
1104
1148
|
// reasoning at all".
|
|
1105
1149
|
let sawAnyThinking = false;
|
|
1106
|
-
// Skill-graduation telemetry. The
|
|
1150
|
+
// Skill-graduation telemetry. The Sentience audit's deterministic rule
|
|
1107
1151
|
// for "this work was worth remembering" — the model is a bad judge of
|
|
1108
1152
|
// its own complexity, so the dispatcher counts and decides. Thresholds:
|
|
1109
1153
|
// - 5+ tool calls in this chain → complex task
|
|
1110
1154
|
// - any tool errored then recovered → learned-from-failure
|
|
1111
|
-
// Only used to inform a chain-end suggestion in
|
|
1155
|
+
// Only used to inform a chain-end suggestion in sentience mode; we don't
|
|
1112
1156
|
// auto-create skills (which would burn an extra LLM call). We surface
|
|
1113
1157
|
// the opportunity with a one-line nudge so the user can /skill-create
|
|
1114
1158
|
// or /learn if they want.
|
|
@@ -1278,6 +1322,7 @@ export async function runQuery(ctx) {
|
|
|
1278
1322
|
let hasOutput = false;
|
|
1279
1323
|
let thinkingActive = false;
|
|
1280
1324
|
let leadingTrimmed = false; // strip leading whitespace from the model's first text chunk
|
|
1325
|
+
let assistantPrefixed = false;
|
|
1281
1326
|
let lastCharWasNewline = false; // collapse 3+ consecutive newlines down to 2
|
|
1282
1327
|
let consecutiveNewlines = 0;
|
|
1283
1328
|
const turnStart = Date.now();
|
|
@@ -1320,6 +1365,10 @@ export async function runQuery(ctx) {
|
|
|
1320
1365
|
if (out.length === 0)
|
|
1321
1366
|
return;
|
|
1322
1367
|
lastCharWasNewline = out.endsWith('\n');
|
|
1368
|
+
if (!assistantPrefixed) {
|
|
1369
|
+
process.stdout.write(assistantTranscriptPrefix());
|
|
1370
|
+
assistantPrefixed = true;
|
|
1371
|
+
}
|
|
1323
1372
|
process.stdout.write(theme.primary(out));
|
|
1324
1373
|
fullText += out;
|
|
1325
1374
|
// ── Loop detection ────────────────────────────────────
|
|
@@ -1406,7 +1455,7 @@ export async function runQuery(ctx) {
|
|
|
1406
1455
|
// Live waiting indicator on the response line. It keeps elapsed time
|
|
1407
1456
|
// and the interrupt hint visible while still clearing itself before
|
|
1408
1457
|
// the first model event writes real output.
|
|
1409
|
-
let workingIndicator = startWorkingIndicator(turnStart, isScreenReader);
|
|
1458
|
+
let workingIndicator = startWorkingIndicator(turnStart, isScreenReader, turns);
|
|
1410
1459
|
// Slow-model warning and first-token watchdog. The warning is a
|
|
1411
1460
|
// UX hint; the watchdog is the hard recovery path for providers
|
|
1412
1461
|
// that accept a request but then never produce a stream event.
|
|
@@ -1418,7 +1467,7 @@ export async function runQuery(ctx) {
|
|
|
1418
1467
|
workingIndicator = null;
|
|
1419
1468
|
console.log(chalk.yellow(` ⏳ model is taking longer than 30s. Shift+F5 cancels, Ctrl+C exits. Often means the model returned no tokens (try /model <other> if this hangs).`));
|
|
1420
1469
|
if (!firstTokenSeen) {
|
|
1421
|
-
workingIndicator = startWorkingIndicator(turnStart, isScreenReader);
|
|
1470
|
+
workingIndicator = startWorkingIndicator(turnStart, isScreenReader, turns);
|
|
1422
1471
|
}
|
|
1423
1472
|
}
|
|
1424
1473
|
}, 30_000);
|
|
@@ -1426,30 +1475,63 @@ export async function runQuery(ctx) {
|
|
|
1426
1475
|
const firstTokenTimeoutMs = fastDirect
|
|
1427
1476
|
? Math.min(resolveFirstTokenTimeoutMs(ctx.config), FAST_DIRECT_FIRST_TOKEN_TIMEOUT_MS)
|
|
1428
1477
|
: resolveFirstTokenTimeoutMs(ctx.config);
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
firstTokenTimedOut = true;
|
|
1433
|
-
try {
|
|
1434
|
-
streamAbort.abort();
|
|
1435
|
-
}
|
|
1436
|
-
catch { /* noop */ }
|
|
1437
|
-
}
|
|
1438
|
-
}, firstTokenTimeoutMs)
|
|
1439
|
-
: null;
|
|
1478
|
+
let streamIdleTimedOut = false;
|
|
1479
|
+
const streamIdleTimeoutMs = resolveStreamIdleTimeoutMs(fastDirect);
|
|
1480
|
+
let streamWaitTimer = null;
|
|
1440
1481
|
try {
|
|
1441
1482
|
const requestConfig = fastDirect
|
|
1442
1483
|
? { ...ctx.config, maxTokens: Math.min(ctx.config.maxTokens ?? 700, 700) }
|
|
1443
1484
|
: ctx.config;
|
|
1444
1485
|
const requestTools = fastDirect ? [] : ALL_TOOLS;
|
|
1445
|
-
|
|
1486
|
+
const stream = streamChat(requestConfig, apiMessages, requestTools, streamAbort.signal);
|
|
1487
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
1488
|
+
while (true) {
|
|
1489
|
+
const nextPromise = iterator.next();
|
|
1490
|
+
let next;
|
|
1491
|
+
const waitTimeoutMs = !firstTokenSeen ? firstTokenTimeoutMs : streamIdleTimeoutMs;
|
|
1492
|
+
if (waitTimeoutMs > 0) {
|
|
1493
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1494
|
+
streamWaitTimer = setTimeout(() => {
|
|
1495
|
+
try {
|
|
1496
|
+
streamAbort.abort();
|
|
1497
|
+
}
|
|
1498
|
+
catch { /* noop */ }
|
|
1499
|
+
if (!firstTokenSeen) {
|
|
1500
|
+
firstTokenTimedOut = true;
|
|
1501
|
+
reject(new Error('__CAWDEX_FIRST_TOKEN_TIMEOUT__'));
|
|
1502
|
+
}
|
|
1503
|
+
else {
|
|
1504
|
+
streamIdleTimedOut = true;
|
|
1505
|
+
reject(new Error('__CAWDEX_STREAM_IDLE_TIMEOUT__'));
|
|
1506
|
+
}
|
|
1507
|
+
}, waitTimeoutMs);
|
|
1508
|
+
});
|
|
1509
|
+
try {
|
|
1510
|
+
next = await Promise.race([nextPromise, timeoutPromise]);
|
|
1511
|
+
}
|
|
1512
|
+
catch (err) {
|
|
1513
|
+
nextPromise.catch(() => { });
|
|
1514
|
+
throw err;
|
|
1515
|
+
}
|
|
1516
|
+
finally {
|
|
1517
|
+
if (streamWaitTimer)
|
|
1518
|
+
clearTimeout(streamWaitTimer);
|
|
1519
|
+
streamWaitTimer = null;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
else {
|
|
1523
|
+
next = await nextPromise;
|
|
1524
|
+
}
|
|
1525
|
+
if (next.done)
|
|
1526
|
+
break;
|
|
1527
|
+
const event = next.value;
|
|
1446
1528
|
// First event of any kind — model is alive. Cancel the slow-
|
|
1447
1529
|
// model warning timer; subsequent events are normal streaming.
|
|
1448
1530
|
if (!firstTokenSeen) {
|
|
1449
1531
|
firstTokenSeen = true;
|
|
1450
1532
|
clearTimeout(slowTimer);
|
|
1451
|
-
if (
|
|
1452
|
-
clearTimeout(
|
|
1533
|
+
if (streamWaitTimer)
|
|
1534
|
+
clearTimeout(streamWaitTimer);
|
|
1453
1535
|
// Tear down the live waiting indicator so the next print
|
|
1454
1536
|
// (thinking header, response text, or tool call) lands cleanly.
|
|
1455
1537
|
workingIndicator?.stop();
|
|
@@ -1499,17 +1581,24 @@ export async function runQuery(ctx) {
|
|
|
1499
1581
|
totalTokens: u.total || u.prompt + u.completion,
|
|
1500
1582
|
estimatedCostUsd: cost,
|
|
1501
1583
|
});
|
|
1584
|
+
setFooterCost(cost, u.prompt, u.completion);
|
|
1502
1585
|
// Single newline separator if we just streamed text, then the
|
|
1503
1586
|
// compact telemetry line.
|
|
1504
1587
|
if (hasOutput && !lastCharWasNewline)
|
|
1505
1588
|
process.stdout.write('\n');
|
|
1506
1589
|
printCost(u.prompt, u.completion, cost, warning, Date.now() - turnStart);
|
|
1507
1590
|
}
|
|
1591
|
+
try {
|
|
1592
|
+
streamAbort.abort();
|
|
1593
|
+
}
|
|
1594
|
+
catch { /* close any provider socket left open after done */ }
|
|
1595
|
+
void iterator.return?.(undefined).catch(() => { });
|
|
1596
|
+
break;
|
|
1508
1597
|
}
|
|
1509
1598
|
}
|
|
1510
1599
|
clearTimeout(slowTimer);
|
|
1511
|
-
if (
|
|
1512
|
-
clearTimeout(
|
|
1600
|
+
if (streamWaitTimer)
|
|
1601
|
+
clearTimeout(streamWaitTimer);
|
|
1513
1602
|
workingIndicator?.stop();
|
|
1514
1603
|
workingIndicator = null;
|
|
1515
1604
|
}
|
|
@@ -1518,8 +1607,8 @@ export async function runQuery(ctx) {
|
|
|
1518
1607
|
// timer so its 30s callback doesn't fire after the error is
|
|
1519
1608
|
// already on stdout (would look like a false positive).
|
|
1520
1609
|
clearTimeout(slowTimer);
|
|
1521
|
-
if (
|
|
1522
|
-
clearTimeout(
|
|
1610
|
+
if (streamWaitTimer)
|
|
1611
|
+
clearTimeout(streamWaitTimer);
|
|
1523
1612
|
// Tear down the waiting indicator if it's still ticking — error
|
|
1524
1613
|
// print below shouldn't trail an animated row.
|
|
1525
1614
|
workingIndicator?.stop();
|
|
@@ -1542,10 +1631,40 @@ export async function runQuery(ctx) {
|
|
|
1542
1631
|
}
|
|
1543
1632
|
const timeoutMsg = `${failedModel} produced no stream events for ${formatDuration(firstTokenTimeoutMs)}`;
|
|
1544
1633
|
console.log(theme.error(` ${sym.warn} ${timeoutMsg}.`));
|
|
1545
|
-
console.log(theme.dim('
|
|
1634
|
+
console.log(theme.dim(' No fallback is configured, so the request was cancelled and the prompt can recover.'));
|
|
1635
|
+
console.log(theme.dim(' Use /fallback <model-id> to enable automatic retry, or /model <known-good-model> to switch primary models.'));
|
|
1546
1636
|
ctx.messages.push({ role: 'assistant', content: `[Provider timeout: ${timeoutMsg}]` });
|
|
1547
1637
|
break;
|
|
1548
1638
|
}
|
|
1639
|
+
if (streamIdleTimedOut) {
|
|
1640
|
+
const failedModel = ctx.config.model;
|
|
1641
|
+
const timeoutMsg = `${failedModel} stream stalled for ${formatDuration(streamIdleTimeoutMs)} after the first event`;
|
|
1642
|
+
const fallback = !hasOutput && !toolCalls
|
|
1643
|
+
? fallbackModelForTurn(ctx.config, usedFallbackModel)
|
|
1644
|
+
: null;
|
|
1645
|
+
if (fallback) {
|
|
1646
|
+
usedFallbackModel = true;
|
|
1647
|
+
ctx.config.model = fallback;
|
|
1648
|
+
resetClient();
|
|
1649
|
+
console.log(theme.warning(` ${sym.warn} ${timeoutMsg} — retrying once with fallback model ${fallback}.`));
|
|
1650
|
+
console.log(theme.dim(' Configure with /fallback <model-id>, disable with /fallback off, or switch now with /openrouter-free.'));
|
|
1651
|
+
turns--;
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
if (fullText.trim()) {
|
|
1655
|
+
const partial = `${fullText.trimEnd()}\n[Provider timeout: stream stalled before completion]`;
|
|
1656
|
+
console.log(theme.warning(` ${sym.warn} stream stalled before completion; returning the partial response.`));
|
|
1657
|
+
accumulatedAssistantText += (accumulatedAssistantText ? '\n\n' : '') + partial;
|
|
1658
|
+
ctx.messages.push({ role: 'assistant', content: partial });
|
|
1659
|
+
}
|
|
1660
|
+
else {
|
|
1661
|
+
console.log(theme.error(` ${sym.warn} ${timeoutMsg}.`));
|
|
1662
|
+
console.log(theme.dim(' The request was cancelled so the prompt can recover instead of hanging indefinitely.'));
|
|
1663
|
+
console.log(theme.dim(' Use /fallback <model-id> to enable automatic retry, or /model <known-good-model> to switch primary models.'));
|
|
1664
|
+
ctx.messages.push({ role: 'assistant', content: `[Provider timeout: ${timeoutMsg}]` });
|
|
1665
|
+
}
|
|
1666
|
+
break;
|
|
1667
|
+
}
|
|
1549
1668
|
// ── User cancel path (graceful — not an error) ─────────
|
|
1550
1669
|
// If the user pressed Ctrl+G / Esc / F5 during streaming, the
|
|
1551
1670
|
// AbortController fired and the OpenAI SDK threw something like
|
|
@@ -1648,7 +1767,8 @@ export async function runQuery(ctx) {
|
|
|
1648
1767
|
}
|
|
1649
1768
|
const emptyMsg = `${failedModel} returned an empty response`;
|
|
1650
1769
|
console.log(theme.error(` ${sym.warn} ${emptyMsg}.`));
|
|
1651
|
-
console.log(theme.dim('
|
|
1770
|
+
console.log(theme.dim(' No fallback is configured, so this empty response was not retried.'));
|
|
1771
|
+
console.log(theme.dim(' Use /fallback <model-id> to enable automatic retry, or /model <known-good-model> to switch primary models.'));
|
|
1652
1772
|
ctx.messages.push({ role: 'assistant', content: `[Provider empty response: ${emptyMsg}]` });
|
|
1653
1773
|
break;
|
|
1654
1774
|
}
|
|
@@ -1810,10 +1930,10 @@ export async function runQuery(ctx) {
|
|
|
1810
1930
|
console.log(theme.dim(` Reasoning models (DeepSeek-R1, o1, Claude with extended thinking) emit them; most general-purpose models don't.`));
|
|
1811
1931
|
console.log(theme.dim(` Hide this hint with /thinking (toggles off).`));
|
|
1812
1932
|
}
|
|
1813
|
-
// ── Skill graduation hint (
|
|
1933
|
+
// ── Skill graduation hint (Sentience audit, M2 item 2) ─────────
|
|
1814
1934
|
// Deterministic "this work was worth remembering" trigger. The model
|
|
1815
|
-
// is a bad judge of its own complexity (
|
|
1816
|
-
// we count instead. Fires at most once per chain in
|
|
1935
|
+
// is a bad judge of its own complexity (Sentience audit's exact wording);
|
|
1936
|
+
// we count instead. Fires at most once per chain in sentience mode, and
|
|
1817
1937
|
// only when a clear threshold was crossed:
|
|
1818
1938
|
//
|
|
1819
1939
|
// - 5+ tool calls → complex multi-step task
|
|
@@ -1821,9 +1941,9 @@ export async function runQuery(ctx) {
|
|
|
1821
1941
|
//
|
|
1822
1942
|
// We don't auto-execute /skill-create (it would burn another LLM call
|
|
1823
1943
|
// and might extract noise); we surface the opportunity so the user can
|
|
1824
|
-
// decide. Outside
|
|
1944
|
+
// decide. Outside sentience mode, this is silent — keeps the noise floor
|
|
1825
1945
|
// low for regular dev/review/debug sessions.
|
|
1826
|
-
if (ctx.mode === 'hermes') {
|
|
1946
|
+
if (ctx.mode === 'sentience' || ctx.mode === 'hermes') {
|
|
1827
1947
|
const complex = chainStats.toolCallCount >= 5;
|
|
1828
1948
|
const learnedFromFailure = chainStats.sawToolError && chainStats.sawToolRecovery;
|
|
1829
1949
|
if (complex || learnedFromFailure) {
|
|
@@ -1832,7 +1952,7 @@ export async function runQuery(ctx) {
|
|
|
1832
1952
|
: complex
|
|
1833
1953
|
? `${chainStats.toolCallCount} tools — complex enough that a learned pattern might save time next time`
|
|
1834
1954
|
: `recovered from a tool error — the working path is worth banking`;
|
|
1835
|
-
console.log(theme.dim(` [
|
|
1955
|
+
console.log(theme.dim(` [sentience] graduation candidate: ${reason}.`));
|
|
1836
1956
|
console.log(theme.dim(` Run /skill-create or /learn to bank it. Skip if it was one-off.`));
|
|
1837
1957
|
}
|
|
1838
1958
|
}
|