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.
Files changed (45) hide show
  1. package/README.md +188 -188
  2. package/dist/command-palette.js +5 -4
  3. package/dist/command-palette.js.map +1 -1
  4. package/dist/config.d.ts +1 -1
  5. package/dist/config.js +20 -13
  6. package/dist/config.js.map +1 -1
  7. package/dist/curator.d.ts +2 -2
  8. package/dist/curator.js +2 -2
  9. package/dist/fixed-footer.d.ts +29 -0
  10. package/dist/fixed-footer.js +383 -0
  11. package/dist/fixed-footer.js.map +1 -0
  12. package/dist/hooks.d.ts +1 -1
  13. package/dist/hooks.js +7 -7
  14. package/dist/hooks.js.map +1 -1
  15. package/dist/index.js +352 -57
  16. package/dist/index.js.map +1 -1
  17. package/dist/instant-answer.d.ts +6 -1
  18. package/dist/instant-answer.js +32 -1
  19. package/dist/instant-answer.js.map +1 -1
  20. package/dist/live-queue.d.ts +0 -32
  21. package/dist/live-queue.js +15 -0
  22. package/dist/live-queue.js.map +1 -1
  23. package/dist/modes.d.ts +2 -1
  24. package/dist/modes.js +368 -361
  25. package/dist/modes.js.map +1 -1
  26. package/dist/query.d.ts +1 -0
  27. package/dist/query.js +163 -44
  28. package/dist/query.js.map +1 -1
  29. package/dist/swarm.d.ts +8 -3
  30. package/dist/swarm.js +39 -14
  31. package/dist/swarm.js.map +1 -1
  32. package/dist/system-prompt.js +14 -14
  33. package/dist/system-prompt.js.map +1 -1
  34. package/dist/theme.d.ts +4 -0
  35. package/dist/theme.js +22 -0
  36. package/dist/theme.js.map +1 -1
  37. package/dist/tools/skill.d.ts +2 -2
  38. package/dist/tools/skill.js +2 -2
  39. package/dist/types.d.ts +15 -0
  40. package/dist/types.js.map +1 -1
  41. package/dist/updater.d.ts +16 -0
  42. package/dist/updater.js +157 -0
  43. package/dist/updater.js.map +1 -0
  44. package/dist/walkthrough.js +7 -7
  45. 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":"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"}
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[15~' ||
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(?:'|’)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,
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
- console.log(theme.dim(` submitted to ${config.provider} · ${config.model}. Waiting for the first model event; Esc or F5 cancels.`));
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)} esc to interrupt)`;
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 line = formatWorkingIndicatorFrame(Date.now() - startedAtMs, frame, messages[Math.floor(frame / 8) % messages.length]);
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
- process.stdout.write('\r\x1b[K');
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 Hermes audit's deterministic rule
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 hermes mode; we don't
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
- const firstTokenTimer = firstTokenTimeoutMs > 0
1431
- ? setTimeout(() => {
1432
- if (!firstTokenSeen) {
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
- for await (const event of streamChat(requestConfig, apiMessages, requestTools, streamAbort.signal)) {
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 (firstTokenTimer)
1453
- clearTimeout(firstTokenTimer);
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 (firstTokenTimer)
1513
- clearTimeout(firstTokenTimer);
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 (firstTokenTimer)
1523
- clearTimeout(firstTokenTimer);
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(' The request was cancelled so the prompt can recover. Try /openrouter-free or /model <known-good-model>.'));
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(' Try /openrouter-free or /model <known-good-model>.'));
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)} · ${turns} ${turns === 1 ? 'turn' : 'turns'}`));
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 (Hermes audit, M2 item 2) ─────────
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 (Hermes audit's exact wording);
1817
- // we count instead. Fires at most once per chain in hermes mode, and
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 hermes mode, this is silent — keeps the noise floor
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(` [hermes] graduation candidate: ${reason}.`));
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
  }