cawdex 1.35.69 → 1.35.74
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 +352 -57
- package/dist/index.js.map +1 -1
- package/dist/instant-answer.d.ts +6 -1
- package/dist/instant-answer.js +32 -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 +163 -44
- 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',
|
|
@@ -60,6 +64,14 @@ export function resolveFirstTokenTimeoutMs(config) {
|
|
|
60
64
|
: (flaky ? INTERACTIVE_FLAKY_FIRST_TOKEN_TIMEOUT_MS : INTERACTIVE_FIRST_TOKEN_TIMEOUT_MS);
|
|
61
65
|
return envTimeoutMs('CAWDEX_FIRST_TOKEN_TIMEOUT_MS', fallback);
|
|
62
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
|
+
}
|
|
63
75
|
export function isKnownFlakyOpenRouterModel(config) {
|
|
64
76
|
const model = String(config.model || '').toLowerCase();
|
|
65
77
|
const provider = String(config.provider || '').toLowerCase();
|
|
@@ -81,7 +93,10 @@ export function fallbackModelForKnownFlakyTurn(config, usedFallbackModel = false
|
|
|
81
93
|
}
|
|
82
94
|
export function isTurnCancelKeySequence(chunk) {
|
|
83
95
|
const seq = chunk.toString('utf8');
|
|
84
|
-
return (seq === '\x1b
|
|
96
|
+
return (seq === '\x1b' ||
|
|
97
|
+
seq === '\x1b\x1b' ||
|
|
98
|
+
/^\x1b\[27(?:;\d+)*~$/.test(seq) ||
|
|
99
|
+
seq === '\x1b[15~' ||
|
|
85
100
|
seq === '\x1b[15;2~' ||
|
|
86
101
|
seq === '\x1b[15;5~' ||
|
|
87
102
|
seq === '\x1b[15;6~' ||
|
|
@@ -91,17 +106,21 @@ const FAST_DIRECT_SYSTEM_PROMPT = 'You are Cawdex. Answer the user directly and
|
|
|
91
106
|
'Do not mention tools, repositories, or implementation steps unless the user asks.';
|
|
92
107
|
const FAST_DIRECT_POSITIVE = [
|
|
93
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,
|
|
94
113
|
/^(what|who|when|where|why|how|which)\b/i,
|
|
95
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,
|
|
96
115
|
/^(?:please\s+)?(?:tell|give)\s+me\b/i,
|
|
97
116
|
/^please\s+(?:explain|define|summarize|translate|calculate|compute|write|draft|make|create)\b/i,
|
|
98
|
-
/^(?:i\s+need|i(?:'
|
|
117
|
+
/^(?:i\s+need|i(?:'|\u2019)d\s+like|i\s+would\s+like)\s+(?:you\s+to\s+)?(?:explain|define|summarize|translate|calculate|compute|write|draft|make|create)\b/i,
|
|
99
118
|
/^(explain|define|summarize|translate|calculate|compute)\b/i,
|
|
100
119
|
/^(?:write|draft|make|create)\s+(?:a|an|the)?\s*(?:short\s+)?(?:poem|haiku|joke|story|paragraph|message|email)\b/i,
|
|
101
120
|
/\b(square root|sqrt)\b/i,
|
|
102
121
|
/\?$/,
|
|
103
122
|
];
|
|
104
|
-
const FAST_DIRECT_REPO_OR_TOOL = /\b(repo|repository|codebase|workspace|file|folder|directory|path|terminal|powershell|shell|command|npm|node|python|typescript|javascript|git|commit|diff|pr|pull request|branch|test|build|lint|install|package|debug|error|stack trace|log|fix|implement|refactor|review|audit|security|benchmark|run|execute|read|search|grep|edit|patch|write[- ]file)\b/i;
|
|
123
|
+
const FAST_DIRECT_REPO_OR_TOOL = /\b(repo|repository|codebase|workspace|file|folder|directory|path|terminal|powershell|shell|command|npm|node|python|typescript|javascript|git|commit|diff|pr|pull request|branch|test|build|lint|install|package|debug|error|stack trace|log|fix|implement|refactor|review|audit|security|benchmark|run|execute|read|search|grep|edit|patch|write[- ]file|website|web\s*site|site|portfolio|landing\s+page|web\s+page|html|css|react|vue|svelte|vite|next\.?js|single[- ]file|dashboard|component|form|desktop|save|hireable|resume)\b/i;
|
|
105
124
|
const FAST_DIRECT_CONTEXTUAL = /^(?:(?:please\s+)?(?:can|could|would|will)\s+you\s+(?:please\s+)?|please\s+)?(continue|carry on|resume|do it|same|again|that|this|those|these|it)\b/i;
|
|
106
125
|
export function shouldUseFastDirectReply(userQuery, mode, env = process.env) {
|
|
107
126
|
if (env.CAWDEX_FAST_DIRECT === '0')
|
|
@@ -126,14 +145,20 @@ function printInteractiveTurnAccepted(config) {
|
|
|
126
145
|
return;
|
|
127
146
|
if (!process.stdout.isTTY)
|
|
128
147
|
return;
|
|
129
|
-
|
|
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
|
+
}
|
|
130
155
|
}
|
|
131
156
|
export function formatWorkingIndicatorFrame(elapsedMs, frameIndex = 0, message = 'Working') {
|
|
132
|
-
const frames = ['
|
|
157
|
+
const frames = ['\u25e6', '\u25c7', '\u25c6', '\u25c7'];
|
|
133
158
|
const frame = frames[Math.abs(frameIndex) % frames.length];
|
|
134
|
-
return ` ${frame} ${message} (${formatDuration(elapsedMs)}
|
|
159
|
+
return ` ${frame} ${message} (${formatDuration(elapsedMs)} \u2022 esc to interrupt)`;
|
|
135
160
|
}
|
|
136
|
-
function startWorkingIndicator(startedAtMs, screenReader) {
|
|
161
|
+
function startWorkingIndicator(startedAtMs, screenReader, turn = 0) {
|
|
137
162
|
if (screenReader)
|
|
138
163
|
return null;
|
|
139
164
|
if (process.env.CAWDEX_NON_INTERACTIVE === '1')
|
|
@@ -141,7 +166,7 @@ function startWorkingIndicator(startedAtMs, screenReader) {
|
|
|
141
166
|
if (!process.stdout.isTTY)
|
|
142
167
|
return null;
|
|
143
168
|
const messages = [
|
|
144
|
-
'Working',
|
|
169
|
+
'Working hard on your request',
|
|
145
170
|
'Sumi ink settling',
|
|
146
171
|
'Edo lanterns lit',
|
|
147
172
|
'Kamon crest aligned',
|
|
@@ -150,7 +175,13 @@ function startWorkingIndicator(startedAtMs, screenReader) {
|
|
|
150
175
|
let frame = 0;
|
|
151
176
|
let stopped = false;
|
|
152
177
|
const paint = () => {
|
|
153
|
-
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);
|
|
154
185
|
process.stdout.write('\r\x1b[K' + theme.dim(line));
|
|
155
186
|
frame++;
|
|
156
187
|
};
|
|
@@ -164,7 +195,10 @@ function startWorkingIndicator(startedAtMs, screenReader) {
|
|
|
164
195
|
return;
|
|
165
196
|
stopped = true;
|
|
166
197
|
clearInterval(timer);
|
|
167
|
-
|
|
198
|
+
if (isFooterActive())
|
|
199
|
+
setFooterActivity('Receiving response', turn, startedAtMs);
|
|
200
|
+
else
|
|
201
|
+
process.stdout.write('\r\x1b[K');
|
|
168
202
|
},
|
|
169
203
|
};
|
|
170
204
|
}
|
|
@@ -279,6 +313,15 @@ function startInputSuppression(screenReader = false) {
|
|
|
279
313
|
}
|
|
280
314
|
return;
|
|
281
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
|
+
}
|
|
282
325
|
// Esc (0x1B) → Steer trigger, but only for a BARE Esc (chunk of
|
|
283
326
|
// exactly one byte). Multi-byte chunks starting with 0x1B are ANSI
|
|
284
327
|
// escape sequences for arrow keys / function keys / Alt+letter, and
|
|
@@ -439,7 +482,7 @@ export function buildStateBlock(messages) {
|
|
|
439
482
|
const olderCount = actions.length - recent.length;
|
|
440
483
|
const lines = [
|
|
441
484
|
'<task_state>',
|
|
442
|
-
`Original goal: ${goal}${goal.length >= STATE_BLOCK_GOAL_MAX_CHARS ? '
|
|
485
|
+
`Original goal: ${goal}${goal.length >= STATE_BLOCK_GOAL_MAX_CHARS ? '\u2026' : ''}`,
|
|
443
486
|
`Actions completed: ${actions.length}`,
|
|
444
487
|
];
|
|
445
488
|
if (olderCount > 0) {
|
|
@@ -449,7 +492,7 @@ export function buildStateBlock(messages) {
|
|
|
449
492
|
lines.push(`Actions:`);
|
|
450
493
|
}
|
|
451
494
|
recent.forEach((a, i) => {
|
|
452
|
-
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' : ''})`);
|
|
453
496
|
});
|
|
454
497
|
lines.push('');
|
|
455
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.');
|
|
@@ -1104,12 +1147,12 @@ export async function runQuery(ctx) {
|
|
|
1104
1147
|
// because we only care about "in this whole exchange did we see any
|
|
1105
1148
|
// reasoning at all".
|
|
1106
1149
|
let sawAnyThinking = false;
|
|
1107
|
-
// Skill-graduation telemetry. The
|
|
1150
|
+
// Skill-graduation telemetry. The Sentience audit's deterministic rule
|
|
1108
1151
|
// for "this work was worth remembering" — the model is a bad judge of
|
|
1109
1152
|
// its own complexity, so the dispatcher counts and decides. Thresholds:
|
|
1110
1153
|
// - 5+ tool calls in this chain → complex task
|
|
1111
1154
|
// - any tool errored then recovered → learned-from-failure
|
|
1112
|
-
// Only used to inform a chain-end suggestion in
|
|
1155
|
+
// Only used to inform a chain-end suggestion in sentience mode; we don't
|
|
1113
1156
|
// auto-create skills (which would burn an extra LLM call). We surface
|
|
1114
1157
|
// the opportunity with a one-line nudge so the user can /skill-create
|
|
1115
1158
|
// or /learn if they want.
|
|
@@ -1279,6 +1322,7 @@ export async function runQuery(ctx) {
|
|
|
1279
1322
|
let hasOutput = false;
|
|
1280
1323
|
let thinkingActive = false;
|
|
1281
1324
|
let leadingTrimmed = false; // strip leading whitespace from the model's first text chunk
|
|
1325
|
+
let assistantPrefixed = false;
|
|
1282
1326
|
let lastCharWasNewline = false; // collapse 3+ consecutive newlines down to 2
|
|
1283
1327
|
let consecutiveNewlines = 0;
|
|
1284
1328
|
const turnStart = Date.now();
|
|
@@ -1321,6 +1365,10 @@ export async function runQuery(ctx) {
|
|
|
1321
1365
|
if (out.length === 0)
|
|
1322
1366
|
return;
|
|
1323
1367
|
lastCharWasNewline = out.endsWith('\n');
|
|
1368
|
+
if (!assistantPrefixed) {
|
|
1369
|
+
process.stdout.write(assistantTranscriptPrefix());
|
|
1370
|
+
assistantPrefixed = true;
|
|
1371
|
+
}
|
|
1324
1372
|
process.stdout.write(theme.primary(out));
|
|
1325
1373
|
fullText += out;
|
|
1326
1374
|
// ── Loop detection ────────────────────────────────────
|
|
@@ -1407,7 +1455,7 @@ export async function runQuery(ctx) {
|
|
|
1407
1455
|
// Live waiting indicator on the response line. It keeps elapsed time
|
|
1408
1456
|
// and the interrupt hint visible while still clearing itself before
|
|
1409
1457
|
// the first model event writes real output.
|
|
1410
|
-
let workingIndicator = startWorkingIndicator(turnStart, isScreenReader);
|
|
1458
|
+
let workingIndicator = startWorkingIndicator(turnStart, isScreenReader, turns);
|
|
1411
1459
|
// Slow-model warning and first-token watchdog. The warning is a
|
|
1412
1460
|
// UX hint; the watchdog is the hard recovery path for providers
|
|
1413
1461
|
// that accept a request but then never produce a stream event.
|
|
@@ -1419,7 +1467,7 @@ export async function runQuery(ctx) {
|
|
|
1419
1467
|
workingIndicator = null;
|
|
1420
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).`));
|
|
1421
1469
|
if (!firstTokenSeen) {
|
|
1422
|
-
workingIndicator = startWorkingIndicator(turnStart, isScreenReader);
|
|
1470
|
+
workingIndicator = startWorkingIndicator(turnStart, isScreenReader, turns);
|
|
1423
1471
|
}
|
|
1424
1472
|
}
|
|
1425
1473
|
}, 30_000);
|
|
@@ -1427,30 +1475,63 @@ export async function runQuery(ctx) {
|
|
|
1427
1475
|
const firstTokenTimeoutMs = fastDirect
|
|
1428
1476
|
? Math.min(resolveFirstTokenTimeoutMs(ctx.config), FAST_DIRECT_FIRST_TOKEN_TIMEOUT_MS)
|
|
1429
1477
|
: resolveFirstTokenTimeoutMs(ctx.config);
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
firstTokenTimedOut = true;
|
|
1434
|
-
try {
|
|
1435
|
-
streamAbort.abort();
|
|
1436
|
-
}
|
|
1437
|
-
catch { /* noop */ }
|
|
1438
|
-
}
|
|
1439
|
-
}, firstTokenTimeoutMs)
|
|
1440
|
-
: null;
|
|
1478
|
+
let streamIdleTimedOut = false;
|
|
1479
|
+
const streamIdleTimeoutMs = resolveStreamIdleTimeoutMs(fastDirect);
|
|
1480
|
+
let streamWaitTimer = null;
|
|
1441
1481
|
try {
|
|
1442
1482
|
const requestConfig = fastDirect
|
|
1443
1483
|
? { ...ctx.config, maxTokens: Math.min(ctx.config.maxTokens ?? 700, 700) }
|
|
1444
1484
|
: ctx.config;
|
|
1445
1485
|
const requestTools = fastDirect ? [] : ALL_TOOLS;
|
|
1446
|
-
|
|
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;
|
|
1447
1528
|
// First event of any kind — model is alive. Cancel the slow-
|
|
1448
1529
|
// model warning timer; subsequent events are normal streaming.
|
|
1449
1530
|
if (!firstTokenSeen) {
|
|
1450
1531
|
firstTokenSeen = true;
|
|
1451
1532
|
clearTimeout(slowTimer);
|
|
1452
|
-
if (
|
|
1453
|
-
clearTimeout(
|
|
1533
|
+
if (streamWaitTimer)
|
|
1534
|
+
clearTimeout(streamWaitTimer);
|
|
1454
1535
|
// Tear down the live waiting indicator so the next print
|
|
1455
1536
|
// (thinking header, response text, or tool call) lands cleanly.
|
|
1456
1537
|
workingIndicator?.stop();
|
|
@@ -1500,17 +1581,24 @@ export async function runQuery(ctx) {
|
|
|
1500
1581
|
totalTokens: u.total || u.prompt + u.completion,
|
|
1501
1582
|
estimatedCostUsd: cost,
|
|
1502
1583
|
});
|
|
1584
|
+
setFooterCost(cost, u.prompt, u.completion);
|
|
1503
1585
|
// Single newline separator if we just streamed text, then the
|
|
1504
1586
|
// compact telemetry line.
|
|
1505
1587
|
if (hasOutput && !lastCharWasNewline)
|
|
1506
1588
|
process.stdout.write('\n');
|
|
1507
1589
|
printCost(u.prompt, u.completion, cost, warning, Date.now() - turnStart);
|
|
1508
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;
|
|
1509
1597
|
}
|
|
1510
1598
|
}
|
|
1511
1599
|
clearTimeout(slowTimer);
|
|
1512
|
-
if (
|
|
1513
|
-
clearTimeout(
|
|
1600
|
+
if (streamWaitTimer)
|
|
1601
|
+
clearTimeout(streamWaitTimer);
|
|
1514
1602
|
workingIndicator?.stop();
|
|
1515
1603
|
workingIndicator = null;
|
|
1516
1604
|
}
|
|
@@ -1519,8 +1607,8 @@ export async function runQuery(ctx) {
|
|
|
1519
1607
|
// timer so its 30s callback doesn't fire after the error is
|
|
1520
1608
|
// already on stdout (would look like a false positive).
|
|
1521
1609
|
clearTimeout(slowTimer);
|
|
1522
|
-
if (
|
|
1523
|
-
clearTimeout(
|
|
1610
|
+
if (streamWaitTimer)
|
|
1611
|
+
clearTimeout(streamWaitTimer);
|
|
1524
1612
|
// Tear down the waiting indicator if it's still ticking — error
|
|
1525
1613
|
// print below shouldn't trail an animated row.
|
|
1526
1614
|
workingIndicator?.stop();
|
|
@@ -1543,10 +1631,40 @@ export async function runQuery(ctx) {
|
|
|
1543
1631
|
}
|
|
1544
1632
|
const timeoutMsg = `${failedModel} produced no stream events for ${formatDuration(firstTokenTimeoutMs)}`;
|
|
1545
1633
|
console.log(theme.error(` ${sym.warn} ${timeoutMsg}.`));
|
|
1546
|
-
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.'));
|
|
1547
1636
|
ctx.messages.push({ role: 'assistant', content: `[Provider timeout: ${timeoutMsg}]` });
|
|
1548
1637
|
break;
|
|
1549
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
|
+
}
|
|
1550
1668
|
// ── User cancel path (graceful — not an error) ─────────
|
|
1551
1669
|
// If the user pressed Ctrl+G / Esc / F5 during streaming, the
|
|
1552
1670
|
// AbortController fired and the OpenAI SDK threw something like
|
|
@@ -1649,7 +1767,8 @@ export async function runQuery(ctx) {
|
|
|
1649
1767
|
}
|
|
1650
1768
|
const emptyMsg = `${failedModel} returned an empty response`;
|
|
1651
1769
|
console.log(theme.error(` ${sym.warn} ${emptyMsg}.`));
|
|
1652
|
-
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.'));
|
|
1653
1772
|
ctx.messages.push({ role: 'assistant', content: `[Provider empty response: ${emptyMsg}]` });
|
|
1654
1773
|
break;
|
|
1655
1774
|
}
|
|
@@ -1795,7 +1914,7 @@ export async function runQuery(ctx) {
|
|
|
1795
1914
|
// Only show if there was meaningful work — multi-second chains. Sub-second
|
|
1796
1915
|
// chains (slash command rejects, instant returns) don't need a chain line.
|
|
1797
1916
|
if (chainMs > 1500) {
|
|
1798
|
-
console.log(theme.dim(` chain ${formatDuration(chainMs)}
|
|
1917
|
+
console.log(theme.dim(` chain ${formatDuration(chainMs)} | ${turns} ${turns === 1 ? 'turn' : 'turns'}`));
|
|
1799
1918
|
}
|
|
1800
1919
|
// /thinking visibility hint. If the user has thinking enabled but the
|
|
1801
1920
|
// model didn't emit any reasoning tokens this turn AND we haven't
|
|
@@ -1811,10 +1930,10 @@ export async function runQuery(ctx) {
|
|
|
1811
1930
|
console.log(theme.dim(` Reasoning models (DeepSeek-R1, o1, Claude with extended thinking) emit them; most general-purpose models don't.`));
|
|
1812
1931
|
console.log(theme.dim(` Hide this hint with /thinking (toggles off).`));
|
|
1813
1932
|
}
|
|
1814
|
-
// ── Skill graduation hint (
|
|
1933
|
+
// ── Skill graduation hint (Sentience audit, M2 item 2) ─────────
|
|
1815
1934
|
// Deterministic "this work was worth remembering" trigger. The model
|
|
1816
|
-
// is a bad judge of its own complexity (
|
|
1817
|
-
// 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
|
|
1818
1937
|
// only when a clear threshold was crossed:
|
|
1819
1938
|
//
|
|
1820
1939
|
// - 5+ tool calls → complex multi-step task
|
|
@@ -1822,9 +1941,9 @@ export async function runQuery(ctx) {
|
|
|
1822
1941
|
//
|
|
1823
1942
|
// We don't auto-execute /skill-create (it would burn another LLM call
|
|
1824
1943
|
// and might extract noise); we surface the opportunity so the user can
|
|
1825
|
-
// decide. Outside
|
|
1944
|
+
// decide. Outside sentience mode, this is silent — keeps the noise floor
|
|
1826
1945
|
// low for regular dev/review/debug sessions.
|
|
1827
|
-
if (ctx.mode === 'hermes') {
|
|
1946
|
+
if (ctx.mode === 'sentience' || ctx.mode === 'hermes') {
|
|
1828
1947
|
const complex = chainStats.toolCallCount >= 5;
|
|
1829
1948
|
const learnedFromFailure = chainStats.sawToolError && chainStats.sawToolRecovery;
|
|
1830
1949
|
if (complex || learnedFromFailure) {
|
|
@@ -1833,7 +1952,7 @@ export async function runQuery(ctx) {
|
|
|
1833
1952
|
: complex
|
|
1834
1953
|
? `${chainStats.toolCallCount} tools — complex enough that a learned pattern might save time next time`
|
|
1835
1954
|
: `recovered from a tool error — the working path is worth banking`;
|
|
1836
|
-
console.log(theme.dim(` [
|
|
1955
|
+
console.log(theme.dim(` [sentience] graduation candidate: ${reason}.`));
|
|
1837
1956
|
console.log(theme.dim(` Run /skill-create or /learn to bank it. Skip if it was one-off.`));
|
|
1838
1957
|
}
|
|
1839
1958
|
}
|