erosolar-cli 1.7.394 → 1.7.396
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/preferences.d.ts +1 -0
- package/dist/core/preferences.d.ts.map +1 -1
- package/dist/core/preferences.js +7 -0
- package/dist/core/preferences.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +35 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +575 -125
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/shellApp.js +1 -1
- package/dist/shell/shellApp.js.map +1 -1
- package/dist/shell/terminalInput.d.ts +18 -1
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +120 -9
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +14 -0
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +14 -0
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/shell/updateManager.d.ts +8 -1
- package/dist/shell/updateManager.d.ts.map +1 -1
- package/dist/shell/updateManager.js +4 -2
- package/dist/shell/updateManager.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts +6 -1
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +26 -5
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/shortcutsHelp.d.ts.map +1 -1
- package/dist/ui/shortcutsHelp.js +1 -0
- package/dist/ui/shortcutsHelp.js.map +1 -1
- package/dist/ui/unified/index.d.ts +2 -2
- package/dist/ui/unified/index.d.ts.map +1 -1
- package/dist/ui/unified/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { stdin as input, stdout as output, exit } from 'node:process';
|
|
2
2
|
import { exec } from 'node:child_process';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
|
+
import { createInterface } from 'node:readline/promises';
|
|
4
5
|
import { display } from '../ui/display.js';
|
|
5
6
|
import { theme } from '../ui/theme.js';
|
|
6
7
|
import { getContextWindowTokens } from '../core/contextWindow.js';
|
|
7
|
-
import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
|
|
8
|
+
import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, MissingSecretError, maskSecret, setSecretValue, } from '../core/secretStore.js';
|
|
8
9
|
import { saveActiveProfilePreference, saveModelPreference, loadToolSettings, saveToolSettings, clearToolSettings, clearActiveProfilePreference, loadSessionPreferences, saveSessionPreferences, loadFeatureFlags, saveFeatureFlags, toggleFeatureFlag, FEATURE_FLAG_INFO, } from '../core/preferences.js';
|
|
9
10
|
import { getLearningSummary, getRecentLearning, commitLearning, exportAllLearning, getLearningDir, } from '../core/learningPersistence.js';
|
|
10
11
|
import { buildEnabledToolSet, evaluateToolPermissions, getToolToggleOptions, } from '../capabilities/toolRegistry.js';
|
|
@@ -35,7 +36,6 @@ import { generateTestFlows, detectBugs, detectUIUpdates, saveTestFlows, saveBugR
|
|
|
35
36
|
import { TerminalInputAdapter } from './terminalInputAdapter.js';
|
|
36
37
|
import { renderSessionFrame } from '../ui/unified/layout.js';
|
|
37
38
|
import { isUpdateInProgress, maybeOfferCliUpdate } from './updateManager.js';
|
|
38
|
-
import { writeLock } from '../ui/writeLock.js';
|
|
39
39
|
import { enterStreamingMode, exitStreamingMode } from '../ui/globalWriteLock.js';
|
|
40
40
|
import { setGlobalAIEnhancer } from '../tools/localExplore.js';
|
|
41
41
|
import { createProvider } from '../providers/providerFactory.js';
|
|
@@ -119,6 +119,7 @@ export class InteractiveShell {
|
|
|
119
119
|
statusSubscription = null;
|
|
120
120
|
followUpQueue = [];
|
|
121
121
|
isDrainingQueue = false;
|
|
122
|
+
apiKeyGateActive = false;
|
|
122
123
|
activeContextWindowTokens = null;
|
|
123
124
|
latestTokenUsage = { used: null, limit: null };
|
|
124
125
|
planApprovalBridgeRegistered = false;
|
|
@@ -128,6 +129,8 @@ export class InteractiveShell {
|
|
|
128
129
|
autosaveEnabled;
|
|
129
130
|
autoContinueEnabled;
|
|
130
131
|
verificationEnabled = true;
|
|
132
|
+
alphaZeroModeEnabled;
|
|
133
|
+
alphaZeroVerificationSnapshot = null;
|
|
131
134
|
editGuardMode = 'display-edits';
|
|
132
135
|
pendingPermissionInput = null;
|
|
133
136
|
pendingHistoryLoad = null;
|
|
@@ -149,6 +152,13 @@ export class InteractiveShell {
|
|
|
149
152
|
lastUserQuery = '';
|
|
150
153
|
lastFailure = null;
|
|
151
154
|
lastAutoTestRun = null;
|
|
155
|
+
runIdCounter = 0;
|
|
156
|
+
lastRunLog = null;
|
|
157
|
+
lastReflectedRunId = null;
|
|
158
|
+
skipNextAutoReflection = false;
|
|
159
|
+
alphaZeroAutoImproveActive = false;
|
|
160
|
+
alphaZeroAutoImproveIterations = 0;
|
|
161
|
+
alphaZeroAutoImproveMaxIterations = 6;
|
|
152
162
|
// Auto-build tracking
|
|
153
163
|
autoBuildInFlight = false;
|
|
154
164
|
lastAutoBuildRun = null;
|
|
@@ -161,10 +171,12 @@ export class InteractiveShell {
|
|
|
161
171
|
lastStreamingElapsedSeconds = null; // Preserve final elapsed time
|
|
162
172
|
statusLineState = null;
|
|
163
173
|
statusMessageOverride = null;
|
|
174
|
+
hasShownThoughtProcess = false;
|
|
164
175
|
promptRefreshTimer = null;
|
|
165
176
|
launchPaletteShown = false;
|
|
166
177
|
version;
|
|
167
178
|
alternateScreenEnabled;
|
|
179
|
+
inputInitialized = false;
|
|
168
180
|
constructor(config) {
|
|
169
181
|
this.profile = config.profile;
|
|
170
182
|
this.profileLabel = config.profileLabel;
|
|
@@ -176,6 +188,7 @@ export class InteractiveShell {
|
|
|
176
188
|
this.thinkingMode = this.sessionPreferences.thinkingMode;
|
|
177
189
|
this.autosaveEnabled = this.sessionPreferences.autosave;
|
|
178
190
|
this.autoContinueEnabled = this.sessionPreferences.autoContinue;
|
|
191
|
+
this.alphaZeroModeEnabled = this.sessionPreferences.alphaZeroMode;
|
|
179
192
|
this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
|
|
180
193
|
this._enabledPlugins = config.enabledPlugins ?? [];
|
|
181
194
|
this.version = config.version ?? '0.0.0';
|
|
@@ -231,6 +244,11 @@ export class InteractiveShell {
|
|
|
231
244
|
description: 'AlphaZero offensive security run (start/status/next)',
|
|
232
245
|
category: 'automation',
|
|
233
246
|
});
|
|
247
|
+
this.slashCommands.push({
|
|
248
|
+
command: '/alphazero',
|
|
249
|
+
description: 'Toggle AlphaZero RL mode with full-cycle verification',
|
|
250
|
+
category: 'mode',
|
|
251
|
+
});
|
|
234
252
|
this.statusTracker = config.statusTracker;
|
|
235
253
|
this.ui = config.ui;
|
|
236
254
|
this.uiAdapter = config.ui.adapter;
|
|
@@ -242,7 +260,11 @@ export class InteractiveShell {
|
|
|
242
260
|
});
|
|
243
261
|
// Set up tool status callback to update status during tool execution
|
|
244
262
|
this.uiAdapter.setToolStatusCallback((status) => {
|
|
245
|
-
|
|
263
|
+
const statusText = status?.text ?? null;
|
|
264
|
+
if (statusText) {
|
|
265
|
+
this.terminalInput.recordRecentAction(`[tool] ${statusText}`);
|
|
266
|
+
}
|
|
267
|
+
this.updateStatusMessage(statusText, { logRecent: false });
|
|
246
268
|
});
|
|
247
269
|
this.skillRepository = new SkillRepository({
|
|
248
270
|
workingDir: this.workingDir,
|
|
@@ -262,14 +284,13 @@ export class InteractiveShell {
|
|
|
262
284
|
onToggleVerify: () => this.toggleVerificationMode(),
|
|
263
285
|
onToggleAutoContinue: () => this.toggleAutoContinueMode(),
|
|
264
286
|
onToggleThinking: () => this.cycleThinkingMode(),
|
|
287
|
+
onToggleAlphaZero: () => this.toggleAlphaZeroMode('shortcut'),
|
|
265
288
|
onClearContext: () => this.handleClearContext(),
|
|
266
289
|
});
|
|
267
290
|
// Initialize Alpha Zero 2 metrics tracking
|
|
268
291
|
this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
|
|
269
292
|
this.setupStatusTracking();
|
|
270
293
|
this.refreshContextGauge();
|
|
271
|
-
// Start terminal input (sets up handlers)
|
|
272
|
-
this.terminalInput.start();
|
|
273
294
|
// Allow planning tools (e.g., ProposePlan) to open the interactive approval UI just like Codex CLI
|
|
274
295
|
this.registerPlanApprovalBridge();
|
|
275
296
|
// Capture display output into the scrollback/chat log so system messages
|
|
@@ -287,9 +308,6 @@ export class InteractiveShell {
|
|
|
287
308
|
// Stream banner first - this sets up scroll region dynamically
|
|
288
309
|
const banner = this.buildBanner();
|
|
289
310
|
this.terminalInput.streamContent(banner + '\n\n');
|
|
290
|
-
// Render chat box after banner is streamed
|
|
291
|
-
this.refreshControlBar();
|
|
292
|
-
this.terminalInput.forceRender();
|
|
293
311
|
this.rebuildAgent();
|
|
294
312
|
this.setupHandlers();
|
|
295
313
|
this.refreshBannerSessionInfo();
|
|
@@ -304,7 +322,13 @@ export class InteractiveShell {
|
|
|
304
322
|
this.parallelAgentDisplayLines = manager.formatDisplay();
|
|
305
323
|
// Trigger UI refresh if streaming
|
|
306
324
|
if (this.streamingHeartbeatStart) {
|
|
307
|
-
this.
|
|
325
|
+
this.uiUpdates.enqueue({
|
|
326
|
+
lane: 'stream',
|
|
327
|
+
mode: ['streaming', 'processing'],
|
|
328
|
+
coalesceKey: 'parallel-agents',
|
|
329
|
+
description: 'parallel agent status',
|
|
330
|
+
run: () => this.displayParallelAgents(),
|
|
331
|
+
});
|
|
308
332
|
}
|
|
309
333
|
};
|
|
310
334
|
manager.on('agent:started', updateDisplay);
|
|
@@ -375,17 +399,88 @@ export class InteractiveShell {
|
|
|
375
399
|
this.sessionResumeNotice = null;
|
|
376
400
|
}
|
|
377
401
|
async start(initialPrompt) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
void maybeOfferCliUpdate(this.version);
|
|
381
|
-
}
|
|
402
|
+
await this.runStartupUpdatePrompt();
|
|
403
|
+
this.ensureInputInitialized();
|
|
382
404
|
if (initialPrompt) {
|
|
383
405
|
await this.processInputBlock(initialPrompt);
|
|
384
406
|
return;
|
|
385
407
|
}
|
|
386
408
|
this.showLaunchCommandPalette();
|
|
387
409
|
// Ensure the terminal input is visible
|
|
388
|
-
this.
|
|
410
|
+
this.renderPromptArea();
|
|
411
|
+
}
|
|
412
|
+
async runStartupUpdatePrompt() {
|
|
413
|
+
if (this.version) {
|
|
414
|
+
try {
|
|
415
|
+
await maybeOfferCliUpdate(this.version, {
|
|
416
|
+
prompt: (context) => this.promptForCliUpdate(context),
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
catch {
|
|
420
|
+
// Ignore update check failures at startup
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
this.showStartupSecretGuidance();
|
|
424
|
+
}
|
|
425
|
+
ensureInputInitialized() {
|
|
426
|
+
if (this.inputInitialized) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
this.terminalInput.start();
|
|
430
|
+
this.refreshControlBar();
|
|
431
|
+
this.renderPromptArea(true);
|
|
432
|
+
this.inputInitialized = true;
|
|
433
|
+
}
|
|
434
|
+
async promptForCliUpdate(context) {
|
|
435
|
+
if (!input.isTTY || !output.isTTY) {
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
const lines = [
|
|
439
|
+
theme.gradient.primary('⬆️ Update available'),
|
|
440
|
+
`${theme.ui.muted('Current')}: ${theme.info(context.currentVersion)}`,
|
|
441
|
+
`${theme.ui.muted('Latest')}: ${theme.success(context.latestVersion)}`,
|
|
442
|
+
'',
|
|
443
|
+
`${theme.primary('>')} Update now (recommended)`,
|
|
444
|
+
`${theme.ui.muted(' Skip for now')}`,
|
|
445
|
+
'',
|
|
446
|
+
'Press Enter to accept the highlighted option, or type Y/n (1/2).',
|
|
447
|
+
];
|
|
448
|
+
display.showSystemMessage(lines.join('\n'));
|
|
449
|
+
const prompt = createInterface({ input, output });
|
|
450
|
+
try {
|
|
451
|
+
const raw = (await prompt.question('> ')).trim().toLowerCase();
|
|
452
|
+
if (!raw || raw === 'y' || raw === 'yes' || raw === '1' || raw === 'update') {
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
455
|
+
if (raw === 'n' || raw === 'no' || raw === '2' || raw === 'skip') {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
finally {
|
|
461
|
+
prompt.close();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
showStartupSecretGuidance() {
|
|
465
|
+
const definitions = listSecretDefinitions();
|
|
466
|
+
const providerSecret = definitions.find((definition) => definition.providers.includes(this.sessionState.provider));
|
|
467
|
+
const missingProviderKey = providerSecret ? !getSecretValue(providerSecret.id) : false;
|
|
468
|
+
const hasSearchKey = Boolean(getSecretValue('TAVILY_API_KEY')) ||
|
|
469
|
+
Boolean(getSecretValue('BRAVE_SEARCH_API_KEY')) ||
|
|
470
|
+
Boolean(getSecretValue('SERPAPI_API_KEY'));
|
|
471
|
+
if (!missingProviderKey && hasSearchKey) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const lines = [];
|
|
475
|
+
lines.push(theme.gradient.primary('Quick setup needed:'));
|
|
476
|
+
if (missingProviderKey && providerSecret) {
|
|
477
|
+
lines.push(`${theme.primary('•')} Set ${providerSecret.label} to use ${this.providerLabel(this.sessionState.provider)}.`);
|
|
478
|
+
}
|
|
479
|
+
if (!hasSearchKey) {
|
|
480
|
+
lines.push(`${theme.primary('•')} Add a web search API key (Tavily recommended) for web tools.`);
|
|
481
|
+
}
|
|
482
|
+
lines.push(theme.ui.muted('Run /secrets to configure keys now. Stored values override env vars.'));
|
|
483
|
+
display.showSystemMessage(lines.join('\n'));
|
|
389
484
|
}
|
|
390
485
|
showLaunchCommandPalette() {
|
|
391
486
|
// Disabled: Quick commands palette takes up too much space
|
|
@@ -482,6 +577,7 @@ export class InteractiveShell {
|
|
|
482
577
|
// Mode toggles
|
|
483
578
|
'/thinking',
|
|
484
579
|
'/autocontinue',
|
|
580
|
+
'/alphazero',
|
|
485
581
|
// Discovery and plugins
|
|
486
582
|
'/local', '/discover',
|
|
487
583
|
'/plugins',
|
|
@@ -533,7 +629,7 @@ export class InteractiveShell {
|
|
|
533
629
|
display.showSystemMessage('✏️ Display edits mode enabled.');
|
|
534
630
|
}
|
|
535
631
|
}
|
|
536
|
-
this.
|
|
632
|
+
this.renderPromptArea();
|
|
537
633
|
}
|
|
538
634
|
toggleVerificationMode() {
|
|
539
635
|
this.setVerificationMode(!this.verificationEnabled, 'shortcut');
|
|
@@ -570,6 +666,37 @@ export class InteractiveShell {
|
|
|
570
666
|
: 'The model will not be auto-prompted to continue.') +
|
|
571
667
|
' Toggle with Ctrl+Shift+C.');
|
|
572
668
|
}
|
|
669
|
+
toggleAlphaZeroMode(source = 'shortcut') {
|
|
670
|
+
this.setAlphaZeroMode(!this.alphaZeroModeEnabled, source);
|
|
671
|
+
}
|
|
672
|
+
setAlphaZeroMode(enabled, source) {
|
|
673
|
+
const changed = this.alphaZeroModeEnabled !== enabled;
|
|
674
|
+
this.alphaZeroModeEnabled = enabled;
|
|
675
|
+
saveSessionPreferences({ alphaZeroMode: this.alphaZeroModeEnabled });
|
|
676
|
+
// Force verification on while AlphaZero mode is active to guarantee deep checks
|
|
677
|
+
if (enabled) {
|
|
678
|
+
if (this.alphaZeroVerificationSnapshot === null) {
|
|
679
|
+
this.alphaZeroVerificationSnapshot = this.verificationEnabled;
|
|
680
|
+
}
|
|
681
|
+
if (!this.verificationEnabled) {
|
|
682
|
+
this.setVerificationMode(true, 'command');
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
else if (this.alphaZeroVerificationSnapshot !== null) {
|
|
686
|
+
this.setVerificationMode(this.alphaZeroVerificationSnapshot, 'command');
|
|
687
|
+
this.alphaZeroVerificationSnapshot = null;
|
|
688
|
+
}
|
|
689
|
+
this.refreshControlBar();
|
|
690
|
+
if (!changed && source === 'shortcut') {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (enabled) {
|
|
694
|
+
display.showSystemMessage('♞ AlphaZero RL mode enabled. Difficult prompts will use the duel/self-critique playbook with full lifecycle verification.');
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
display.showInfo('AlphaZero RL mode disabled. Returning to standard flow.');
|
|
698
|
+
}
|
|
699
|
+
}
|
|
573
700
|
/**
|
|
574
701
|
* Cycle through thinking modes (Ctrl+Shift+T keyboard shortcut).
|
|
575
702
|
*/
|
|
@@ -647,7 +774,7 @@ export class InteractiveShell {
|
|
|
647
774
|
if (['n', 'no', 'cancel', '/cancel'].includes(lower)) {
|
|
648
775
|
this.pendingPermissionInput = null;
|
|
649
776
|
display.showInfo('Request cancelled.');
|
|
650
|
-
this.
|
|
777
|
+
this.renderPromptArea();
|
|
651
778
|
return null;
|
|
652
779
|
}
|
|
653
780
|
// Treat any other input as a replacement request that also needs confirmation
|
|
@@ -665,7 +792,7 @@ export class InteractiveShell {
|
|
|
665
792
|
]
|
|
666
793
|
.filter(Boolean)
|
|
667
794
|
.join('\n'));
|
|
668
|
-
this.
|
|
795
|
+
this.renderPromptArea();
|
|
669
796
|
}
|
|
670
797
|
/**
|
|
671
798
|
* Handle Ctrl+C presses in three stages:
|
|
@@ -680,7 +807,7 @@ export class InteractiveShell {
|
|
|
680
807
|
this.clearChatInput();
|
|
681
808
|
const prefix = hadBuffer ? 'Input cleared.' : 'Nothing to clear.';
|
|
682
809
|
display.showSystemMessage(`${prefix} Press Ctrl+C again to pause the AI; a third time quits.`);
|
|
683
|
-
this.
|
|
810
|
+
this.renderPromptArea();
|
|
684
811
|
return;
|
|
685
812
|
}
|
|
686
813
|
if (this.ctrlCPressCount === 2) {
|
|
@@ -781,8 +908,11 @@ export class InteractiveShell {
|
|
|
781
908
|
/**
|
|
782
909
|
* Update status bar message
|
|
783
910
|
*/
|
|
784
|
-
updateStatusMessage(message) {
|
|
911
|
+
updateStatusMessage(message, options = {}) {
|
|
785
912
|
this.statusMessageOverride = message;
|
|
913
|
+
if (message && options.logRecent !== false) {
|
|
914
|
+
this.terminalInput.recordRecentAction(`[status] ${message}`);
|
|
915
|
+
}
|
|
786
916
|
// During streaming we still want the spinner prefix; when idle force a fast refresh.
|
|
787
917
|
this.refreshStatusLine(!this.isProcessing);
|
|
788
918
|
}
|
|
@@ -794,26 +924,26 @@ export class InteractiveShell {
|
|
|
794
924
|
const trimmed = input.trim();
|
|
795
925
|
if (!trimmed) {
|
|
796
926
|
display.showWarning('Enter a number, "save", "defaults", or "cancel".');
|
|
797
|
-
this.
|
|
927
|
+
this.renderPromptArea();
|
|
798
928
|
return;
|
|
799
929
|
}
|
|
800
930
|
const normalized = trimmed.toLowerCase();
|
|
801
931
|
if (normalized === 'cancel') {
|
|
802
932
|
this.pendingInteraction = null;
|
|
803
933
|
display.showInfo('Tool selection cancelled.');
|
|
804
|
-
this.
|
|
934
|
+
this.renderPromptArea();
|
|
805
935
|
return;
|
|
806
936
|
}
|
|
807
937
|
if (normalized === 'defaults') {
|
|
808
938
|
pending.selection = buildEnabledToolSet(null);
|
|
809
939
|
this.renderToolMenu(pending);
|
|
810
|
-
this.
|
|
940
|
+
this.renderPromptArea();
|
|
811
941
|
return;
|
|
812
942
|
}
|
|
813
943
|
if (normalized === 'save') {
|
|
814
944
|
await this.persistToolSelection(pending);
|
|
815
945
|
this.pendingInteraction = null;
|
|
816
|
-
this.
|
|
946
|
+
this.renderPromptArea();
|
|
817
947
|
return;
|
|
818
948
|
}
|
|
819
949
|
const choice = Number.parseInt(trimmed, 10);
|
|
@@ -831,11 +961,11 @@ export class InteractiveShell {
|
|
|
831
961
|
}
|
|
832
962
|
this.renderToolMenu(pending);
|
|
833
963
|
}
|
|
834
|
-
this.
|
|
964
|
+
this.renderPromptArea();
|
|
835
965
|
return;
|
|
836
966
|
}
|
|
837
967
|
display.showWarning('Enter a number, "save", "defaults", or "cancel".');
|
|
838
|
-
this.
|
|
968
|
+
this.renderPromptArea();
|
|
839
969
|
}
|
|
840
970
|
async persistToolSelection(interaction) {
|
|
841
971
|
if (setsEqual(interaction.selection, interaction.initialSelection)) {
|
|
@@ -862,36 +992,36 @@ export class InteractiveShell {
|
|
|
862
992
|
if (!this.agentMenu) {
|
|
863
993
|
this.pendingInteraction = null;
|
|
864
994
|
display.showWarning('Agent selection is unavailable in this CLI.');
|
|
865
|
-
this.
|
|
995
|
+
this.renderPromptArea();
|
|
866
996
|
return;
|
|
867
997
|
}
|
|
868
998
|
const trimmed = input.trim();
|
|
869
999
|
if (!trimmed) {
|
|
870
1000
|
display.showWarning('Enter a number or type "cancel".');
|
|
871
|
-
this.
|
|
1001
|
+
this.renderPromptArea();
|
|
872
1002
|
return;
|
|
873
1003
|
}
|
|
874
1004
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
875
1005
|
this.pendingInteraction = null;
|
|
876
1006
|
display.showInfo('Agent selection cancelled.');
|
|
877
|
-
this.
|
|
1007
|
+
this.renderPromptArea();
|
|
878
1008
|
return;
|
|
879
1009
|
}
|
|
880
1010
|
const choice = Number.parseInt(trimmed, 10);
|
|
881
1011
|
if (!Number.isFinite(choice)) {
|
|
882
1012
|
display.showWarning('Please enter a valid number.');
|
|
883
|
-
this.
|
|
1013
|
+
this.renderPromptArea();
|
|
884
1014
|
return;
|
|
885
1015
|
}
|
|
886
1016
|
const option = pending.options[choice - 1];
|
|
887
1017
|
if (!option) {
|
|
888
1018
|
display.showWarning('That option is not available.');
|
|
889
|
-
this.
|
|
1019
|
+
this.renderPromptArea();
|
|
890
1020
|
return;
|
|
891
1021
|
}
|
|
892
1022
|
await this.persistAgentSelection(option.name);
|
|
893
1023
|
this.pendingInteraction = null;
|
|
894
|
-
this.
|
|
1024
|
+
this.renderPromptArea();
|
|
895
1025
|
}
|
|
896
1026
|
async persistAgentSelection(profileName) {
|
|
897
1027
|
if (!this.agentMenu) {
|
|
@@ -964,7 +1094,7 @@ export class InteractiveShell {
|
|
|
964
1094
|
lines.push(` ${theme.primary('[text]')} Submit your own solution instead`);
|
|
965
1095
|
lines.push('');
|
|
966
1096
|
display.showSystemMessage(lines.join('\n'));
|
|
967
|
-
this.
|
|
1097
|
+
this.renderPromptArea();
|
|
968
1098
|
}
|
|
969
1099
|
async handlePlanApprovalInput(input) {
|
|
970
1100
|
const pending = this.pendingInteraction;
|
|
@@ -973,7 +1103,7 @@ export class InteractiveShell {
|
|
|
973
1103
|
const trimmed = input.trim();
|
|
974
1104
|
if (!trimmed) {
|
|
975
1105
|
display.showWarning('Enter a command or your own solution.');
|
|
976
|
-
this.
|
|
1106
|
+
this.renderPromptArea();
|
|
977
1107
|
return;
|
|
978
1108
|
}
|
|
979
1109
|
const lower = trimmed.toLowerCase();
|
|
@@ -981,7 +1111,7 @@ export class InteractiveShell {
|
|
|
981
1111
|
if (lower === 'cancel' || lower === 'c') {
|
|
982
1112
|
this.pendingInteraction = null;
|
|
983
1113
|
display.showInfo('Plan cancelled. You can continue with a different approach.');
|
|
984
|
-
this.
|
|
1114
|
+
this.renderPromptArea();
|
|
985
1115
|
return;
|
|
986
1116
|
}
|
|
987
1117
|
// Select all
|
|
@@ -1001,7 +1131,7 @@ export class InteractiveShell {
|
|
|
1001
1131
|
const selectedSteps = pending.steps.filter(s => pending.selectedSteps.has(s.id));
|
|
1002
1132
|
if (selectedSteps.length === 0) {
|
|
1003
1133
|
display.showWarning('No steps selected. Select steps or enter your own solution.');
|
|
1004
|
-
this.
|
|
1134
|
+
this.renderPromptArea();
|
|
1005
1135
|
return;
|
|
1006
1136
|
}
|
|
1007
1137
|
this.pendingInteraction = null;
|
|
@@ -1034,15 +1164,18 @@ export class InteractiveShell {
|
|
|
1034
1164
|
return;
|
|
1035
1165
|
}
|
|
1036
1166
|
display.showWarning('Invalid input. Enter a step number, command (go/cancel/all/none), or your own solution.');
|
|
1037
|
-
this.
|
|
1167
|
+
this.renderPromptArea();
|
|
1038
1168
|
}
|
|
1039
1169
|
setupHandlers() {
|
|
1040
1170
|
// Handle terminal resize
|
|
1041
1171
|
output.on('resize', () => {
|
|
1172
|
+
if (!this.inputInitialized) {
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
this.terminalInput.resetContentPosition();
|
|
1042
1176
|
this.terminalInput.handleResize();
|
|
1177
|
+
this.terminalInput.forceRender();
|
|
1043
1178
|
});
|
|
1044
|
-
// Show initial input UI
|
|
1045
|
-
this.terminalInput.render();
|
|
1046
1179
|
}
|
|
1047
1180
|
/**
|
|
1048
1181
|
* Set up command autocomplete with all available slash commands.
|
|
@@ -1073,6 +1206,14 @@ export class InteractiveShell {
|
|
|
1073
1206
|
catch {
|
|
1074
1207
|
// Custom commands are optional
|
|
1075
1208
|
}
|
|
1209
|
+
// Add manual commands that are not yet in the schema
|
|
1210
|
+
if (!commands.some((cmd) => cmd.command === '/alphazero')) {
|
|
1211
|
+
commands.push({
|
|
1212
|
+
command: '/alphazero',
|
|
1213
|
+
description: 'Toggle AlphaZero RL mode',
|
|
1214
|
+
category: 'mode',
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1076
1217
|
// Sort commands alphabetically
|
|
1077
1218
|
commands.sort((a, b) => a.command.localeCompare(b.command));
|
|
1078
1219
|
this.terminalInput.setAvailableCommands(commands);
|
|
@@ -1153,23 +1294,51 @@ export class InteractiveShell {
|
|
|
1153
1294
|
autoContinueHotkey: 'ctrl+shift+c',
|
|
1154
1295
|
thinkingModeLabel: this.thinkingMode,
|
|
1155
1296
|
thinkingHotkey: 'ctrl+shift+t',
|
|
1297
|
+
alphaZeroEnabled: this.alphaZeroModeEnabled,
|
|
1298
|
+
alphaZeroHotkey: 'ctrl+shift+a',
|
|
1299
|
+
alphaZeroLabel: 'AlphaZero RL',
|
|
1156
1300
|
});
|
|
1157
1301
|
this.refreshStatusLine();
|
|
1158
|
-
this.
|
|
1302
|
+
this.renderPromptArea();
|
|
1159
1303
|
}
|
|
1160
1304
|
writeLocked(content) {
|
|
1161
1305
|
if (!content) {
|
|
1162
1306
|
return;
|
|
1163
1307
|
}
|
|
1164
|
-
//
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1308
|
+
// Route through display stream so scroll regions and streaming locks stay in sync
|
|
1309
|
+
display.stream(content);
|
|
1310
|
+
}
|
|
1311
|
+
isStreamingUiActive() {
|
|
1312
|
+
return this.streamingHeartbeatStart !== null;
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Render the prompt/control bar. During streaming, rely on the streaming frame
|
|
1316
|
+
* renderer and enqueue through the UIUpdateCoordinator to avoid fighting the
|
|
1317
|
+
* scroll region or duplicating the prompt.
|
|
1318
|
+
*/
|
|
1319
|
+
renderPromptArea(force = false) {
|
|
1320
|
+
if (this.isStreamingUiActive()) {
|
|
1321
|
+
this.uiUpdates.enqueue({
|
|
1322
|
+
lane: 'prompt',
|
|
1323
|
+
mode: ['streaming', 'processing'],
|
|
1324
|
+
coalesceKey: 'prompt:streaming-frame',
|
|
1325
|
+
description: 'render streaming prompt frame',
|
|
1326
|
+
run: () => {
|
|
1327
|
+
if (force) {
|
|
1328
|
+
this.terminalInput.renderStreamingFrame(true);
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
this.terminalInput.renderStreamingFrame();
|
|
1332
|
+
},
|
|
1333
|
+
});
|
|
1168
1334
|
return;
|
|
1169
1335
|
}
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1336
|
+
if (force) {
|
|
1337
|
+
this.terminalInput.forceRender();
|
|
1338
|
+
}
|
|
1339
|
+
else {
|
|
1340
|
+
this.terminalInput.render();
|
|
1341
|
+
}
|
|
1173
1342
|
}
|
|
1174
1343
|
/**
|
|
1175
1344
|
* Refresh the status line in the persistent input area.
|
|
@@ -1215,7 +1384,7 @@ export class InteractiveShell {
|
|
|
1215
1384
|
provider: this.providerLabel(this.sessionState.provider),
|
|
1216
1385
|
});
|
|
1217
1386
|
if (forceRender) {
|
|
1218
|
-
this.
|
|
1387
|
+
this.renderPromptArea(true);
|
|
1219
1388
|
}
|
|
1220
1389
|
}
|
|
1221
1390
|
/**
|
|
@@ -1252,7 +1421,7 @@ export class InteractiveShell {
|
|
|
1252
1421
|
* Ensure the terminal input is ready for interactive input.
|
|
1253
1422
|
*/
|
|
1254
1423
|
ensureReadlineReady() {
|
|
1255
|
-
this.
|
|
1424
|
+
this.renderPromptArea();
|
|
1256
1425
|
}
|
|
1257
1426
|
/**
|
|
1258
1427
|
* Log user prompt to the scroll region so it's part of the conversation flow.
|
|
@@ -1274,7 +1443,7 @@ export class InteractiveShell {
|
|
|
1274
1443
|
}
|
|
1275
1444
|
requestPromptRefresh(force = false) {
|
|
1276
1445
|
if (force) {
|
|
1277
|
-
this.
|
|
1446
|
+
this.renderPromptArea(true);
|
|
1278
1447
|
return;
|
|
1279
1448
|
}
|
|
1280
1449
|
if (this.promptRefreshTimer) {
|
|
@@ -1282,7 +1451,7 @@ export class InteractiveShell {
|
|
|
1282
1451
|
}
|
|
1283
1452
|
this.promptRefreshTimer = setTimeout(() => {
|
|
1284
1453
|
this.promptRefreshTimer = null;
|
|
1285
|
-
this.
|
|
1454
|
+
this.renderPromptArea();
|
|
1286
1455
|
}, 48);
|
|
1287
1456
|
}
|
|
1288
1457
|
clearPromptRefreshTimer() {
|
|
@@ -1291,6 +1460,25 @@ export class InteractiveShell {
|
|
|
1291
1460
|
this.promptRefreshTimer = null;
|
|
1292
1461
|
}
|
|
1293
1462
|
}
|
|
1463
|
+
async withStreamingUi(label, run) {
|
|
1464
|
+
if (this.isStreamingUiActive()) {
|
|
1465
|
+
return run();
|
|
1466
|
+
}
|
|
1467
|
+
this.terminalInput.setStreaming(true);
|
|
1468
|
+
this.startStreamingHeartbeat(label);
|
|
1469
|
+
try {
|
|
1470
|
+
return await run();
|
|
1471
|
+
}
|
|
1472
|
+
finally {
|
|
1473
|
+
this.stopStreamingHeartbeat();
|
|
1474
|
+
this.terminalInput.setStreaming(false);
|
|
1475
|
+
const nextMode = this.isProcessing ? 'processing' : 'idle';
|
|
1476
|
+
this.uiUpdates.setMode(nextMode);
|
|
1477
|
+
if (nextMode === 'processing') {
|
|
1478
|
+
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1294
1482
|
startStreamingHeartbeat(label = 'Streaming') {
|
|
1295
1483
|
this.stopStreamingHeartbeat();
|
|
1296
1484
|
// Enter global streaming mode - blocks all non-streaming UI output
|
|
@@ -1371,7 +1559,7 @@ export class InteractiveShell {
|
|
|
1371
1559
|
else {
|
|
1372
1560
|
this.setIdleStatus();
|
|
1373
1561
|
}
|
|
1374
|
-
this.
|
|
1562
|
+
this.renderPromptArea();
|
|
1375
1563
|
}
|
|
1376
1564
|
enqueueFollowUpAction(action) {
|
|
1377
1565
|
this.followUpQueue.push(action);
|
|
@@ -1390,14 +1578,21 @@ export class InteractiveShell {
|
|
|
1390
1578
|
this.refreshQueueIndicators();
|
|
1391
1579
|
this.scheduleQueueProcessing();
|
|
1392
1580
|
// Re-show the prompt so user can continue typing more follow-ups
|
|
1393
|
-
this.
|
|
1581
|
+
this.renderPromptArea();
|
|
1394
1582
|
}
|
|
1395
1583
|
scheduleQueueProcessing() {
|
|
1396
1584
|
if (!this.followUpQueue.length) {
|
|
1397
1585
|
this.refreshQueueIndicators();
|
|
1398
1586
|
return;
|
|
1399
1587
|
}
|
|
1588
|
+
if (this.apiKeyGateActive) {
|
|
1589
|
+
this.refreshQueueIndicators();
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1400
1592
|
queueMicrotask(() => {
|
|
1593
|
+
if (this.apiKeyGateActive) {
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1401
1596
|
void this.processQueuedActions();
|
|
1402
1597
|
});
|
|
1403
1598
|
}
|
|
@@ -1405,12 +1600,12 @@ export class InteractiveShell {
|
|
|
1405
1600
|
* Process queued follow-up actions.
|
|
1406
1601
|
*/
|
|
1407
1602
|
async processQueuedActions() {
|
|
1408
|
-
if (this.isDrainingQueue || this.isProcessing || !this.followUpQueue.length) {
|
|
1603
|
+
if (this.apiKeyGateActive || this.isDrainingQueue || this.isProcessing || !this.followUpQueue.length) {
|
|
1409
1604
|
return;
|
|
1410
1605
|
}
|
|
1411
1606
|
this.isDrainingQueue = true;
|
|
1412
1607
|
try {
|
|
1413
|
-
while (!this.isProcessing && this.followUpQueue.length) {
|
|
1608
|
+
while (!this.isProcessing && !this.apiKeyGateActive && this.followUpQueue.length) {
|
|
1414
1609
|
const next = this.followUpQueue.shift();
|
|
1415
1610
|
const remaining = this.followUpQueue.length;
|
|
1416
1611
|
const label = next.type === 'continuous' ? 'continuous command' : 'follow-up';
|
|
@@ -1445,12 +1640,12 @@ export class InteractiveShell {
|
|
|
1445
1640
|
}
|
|
1446
1641
|
if (lower === 'clear') {
|
|
1447
1642
|
display.clear();
|
|
1448
|
-
this.
|
|
1643
|
+
this.renderPromptArea();
|
|
1449
1644
|
return;
|
|
1450
1645
|
}
|
|
1451
1646
|
if (lower === 'help') {
|
|
1452
1647
|
this.showHelp();
|
|
1453
|
-
this.
|
|
1648
|
+
this.renderPromptArea();
|
|
1454
1649
|
return;
|
|
1455
1650
|
}
|
|
1456
1651
|
if (trimmed.startsWith('/')) {
|
|
@@ -1460,12 +1655,12 @@ export class InteractiveShell {
|
|
|
1460
1655
|
// Check for continuous/infinite loop commands
|
|
1461
1656
|
if (this.isContinuousCommand(trimmed)) {
|
|
1462
1657
|
await this.processContinuousRequest(trimmed);
|
|
1463
|
-
this.
|
|
1658
|
+
this.renderPromptArea();
|
|
1464
1659
|
return;
|
|
1465
1660
|
}
|
|
1466
1661
|
// Direct execution for all inputs, including multi-line pastes
|
|
1467
1662
|
await this.processRequest(trimmed);
|
|
1468
|
-
this.
|
|
1663
|
+
this.renderPromptArea();
|
|
1469
1664
|
}
|
|
1470
1665
|
/**
|
|
1471
1666
|
* Check if the command is a continuous/infinite loop command
|
|
@@ -1503,6 +1698,153 @@ export class InteractiveShell {
|
|
|
1503
1698
|
];
|
|
1504
1699
|
return patterns.some(pattern => pattern.test(lower));
|
|
1505
1700
|
}
|
|
1701
|
+
isDifficultProblem(input) {
|
|
1702
|
+
const normalized = input.toLowerCase();
|
|
1703
|
+
const wordCount = normalized.split(/\s+/).filter(Boolean).length;
|
|
1704
|
+
if (normalized.length > 600 || wordCount > 80) {
|
|
1705
|
+
return true;
|
|
1706
|
+
}
|
|
1707
|
+
const signals = [
|
|
1708
|
+
'root cause',
|
|
1709
|
+
'postmortem',
|
|
1710
|
+
'crash',
|
|
1711
|
+
'incident',
|
|
1712
|
+
'outage',
|
|
1713
|
+
'optimiz',
|
|
1714
|
+
'performance',
|
|
1715
|
+
'throughput',
|
|
1716
|
+
'latency',
|
|
1717
|
+
'scalab',
|
|
1718
|
+
'architecture',
|
|
1719
|
+
'rewrite',
|
|
1720
|
+
'migration',
|
|
1721
|
+
'refactor',
|
|
1722
|
+
'reverse engineer',
|
|
1723
|
+
'security',
|
|
1724
|
+
'exploit',
|
|
1725
|
+
'injection',
|
|
1726
|
+
'vulnerability',
|
|
1727
|
+
'compliance',
|
|
1728
|
+
'multi-step',
|
|
1729
|
+
'complex',
|
|
1730
|
+
'difficult',
|
|
1731
|
+
'hard problem',
|
|
1732
|
+
'debug',
|
|
1733
|
+
'trace',
|
|
1734
|
+
'profil',
|
|
1735
|
+
'bottleneck',
|
|
1736
|
+
];
|
|
1737
|
+
return signals.some((signal) => normalized.includes(signal));
|
|
1738
|
+
}
|
|
1739
|
+
buildAlphaZeroPrompt(request, flaggedDifficult) {
|
|
1740
|
+
const playbook = [
|
|
1741
|
+
'AlphaZero RL MODE is ACTIVE. Operate as a self-play reinforcement loop.',
|
|
1742
|
+
flaggedDifficult
|
|
1743
|
+
? 'Treat this as a difficult, high-risk task and over-verify the result.'
|
|
1744
|
+
: 'Apply the reinforcement loop even if the task looks small.',
|
|
1745
|
+
'Follow this closed-loop playbook:',
|
|
1746
|
+
'- Draft two competing solution strategies and merge the strongest ideas before executing.',
|
|
1747
|
+
'- Execute with tools while logging decisions and evidence.',
|
|
1748
|
+
'- Self-critique and repair until the quality is excellent (aim ≥90/100).',
|
|
1749
|
+
'- Run full-lifecycle verification like a human reviewer: build/tests, manual sanity checks, edge cases, performance/safety/security probes, docs/UX/readiness notes.',
|
|
1750
|
+
'- Keep a verification ledger: each check with PASS/FAIL, evidence, and remaining risks. If anything fails, fix and re-verify before claiming completion.',
|
|
1751
|
+
'Finish with a concise sign-off that lists what was achieved and the proof of completion.',
|
|
1752
|
+
];
|
|
1753
|
+
return `${playbook.join('\n')}\n\nPrimary user request:\n${request.trim()}`;
|
|
1754
|
+
}
|
|
1755
|
+
buildRunLogExcerpt(startIndex) {
|
|
1756
|
+
const buffer = this.terminalInput.getScrollbackBuffer();
|
|
1757
|
+
const sinceStart = buffer.slice(Math.max(0, startIndex));
|
|
1758
|
+
const excerpt = sinceStart.slice(-200); // Cap prompt size
|
|
1759
|
+
return excerpt.join('\n').trim();
|
|
1760
|
+
}
|
|
1761
|
+
buildRunLogEntry(request, response, scrollbackStartIndex, meta) {
|
|
1762
|
+
return {
|
|
1763
|
+
id: ++this.runIdCounter,
|
|
1764
|
+
request,
|
|
1765
|
+
response,
|
|
1766
|
+
timestamp: new Date().toISOString(),
|
|
1767
|
+
alphaZero: meta.alphaZeroEngaged,
|
|
1768
|
+
difficult: meta.alphaZeroDifficult,
|
|
1769
|
+
failureType: meta.failureType,
|
|
1770
|
+
outputExcerpt: this.buildRunLogExcerpt(scrollbackStartIndex),
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
buildAlphaZeroReflectionPrompt(runLog, options) {
|
|
1774
|
+
const lines = [];
|
|
1775
|
+
lines.push('AlphaZero Post-Run Self-Reflection (erosolar-cli)');
|
|
1776
|
+
lines.push(`Timestamp: ${runLog.timestamp}`);
|
|
1777
|
+
lines.push(`AlphaZero: ${runLog.alphaZero ? 'on' : 'off'}${runLog.difficult ? ' | difficult' : ''}${runLog.failureType ? ` | signal: ${runLog.failureType}` : ''}`);
|
|
1778
|
+
lines.push('');
|
|
1779
|
+
lines.push('User request:');
|
|
1780
|
+
lines.push(runLog.request);
|
|
1781
|
+
lines.push('');
|
|
1782
|
+
lines.push('Previous run log excerpt:');
|
|
1783
|
+
lines.push(runLog.outputExcerpt || '[empty]');
|
|
1784
|
+
lines.push('');
|
|
1785
|
+
lines.push('Instructions:');
|
|
1786
|
+
lines.push('- Reflect on the log to spot erosolar-cli bugs, UX issues, or reliability gaps.');
|
|
1787
|
+
lines.push('- Propose and apply targeted fixes in this repository only (no user workspace edits).');
|
|
1788
|
+
lines.push('- Prefer small, test-backed changes; run any relevant checks you invoke.');
|
|
1789
|
+
lines.push('- Keep notes concise and finish with applied changes plus follow-ups.');
|
|
1790
|
+
if (options.autoChain) {
|
|
1791
|
+
lines.push('- Continue iterating automatically while meaningful improvements remain.');
|
|
1792
|
+
lines.push('- When no further improvements are possible, reply with NO_MORE_IMPROVEMENTS on its own line.');
|
|
1793
|
+
}
|
|
1794
|
+
return lines.join('\n');
|
|
1795
|
+
}
|
|
1796
|
+
maybeQueueAlphaZeroSelfReflection(runLog, alphaZeroEngaged, allowAutoChain) {
|
|
1797
|
+
if (!alphaZeroEngaged) {
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
if (!isErosolarRepo(this.workingDir)) {
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
if (!runLog.outputExcerpt) {
|
|
1804
|
+
return;
|
|
1805
|
+
}
|
|
1806
|
+
if (this.lastReflectedRunId === runLog.id) {
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
if (allowAutoChain) {
|
|
1810
|
+
if (!this.autoContinueEnabled) {
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
if (this.alphaZeroAutoImproveIterations >= this.alphaZeroAutoImproveMaxIterations) {
|
|
1814
|
+
display.showInfo('AlphaZero auto-improvement limit reached; stopping.');
|
|
1815
|
+
this.alphaZeroAutoImproveActive = false;
|
|
1816
|
+
this.alphaZeroAutoImproveIterations = 0;
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
if (!this.alphaZeroAutoImproveActive) {
|
|
1820
|
+
this.alphaZeroAutoImproveIterations = 0;
|
|
1821
|
+
}
|
|
1822
|
+
this.alphaZeroAutoImproveActive = true;
|
|
1823
|
+
this.alphaZeroAutoImproveIterations++;
|
|
1824
|
+
}
|
|
1825
|
+
const prompt = this.buildAlphaZeroReflectionPrompt(runLog, { autoChain: allowAutoChain });
|
|
1826
|
+
this.lastReflectedRunId = runLog.id;
|
|
1827
|
+
this.skipNextAutoReflection = !allowAutoChain; // Prevent reflection-on-reflection unless auto-chaining
|
|
1828
|
+
this.enqueueFollowUpAction({ type: 'request', text: prompt });
|
|
1829
|
+
display.showInfo(allowAutoChain
|
|
1830
|
+
? 'Auto AlphaZero self-improvement queued (auto-continue enabled).'
|
|
1831
|
+
: 'Queued AlphaZero self-reflection to improve erosolar-cli from the latest run log.');
|
|
1832
|
+
}
|
|
1833
|
+
shouldStopAlphaZeroAutoImprove(responseText, allowAutoChain) {
|
|
1834
|
+
if (!this.alphaZeroAutoImproveActive) {
|
|
1835
|
+
return false;
|
|
1836
|
+
}
|
|
1837
|
+
if (!allowAutoChain) {
|
|
1838
|
+
return true;
|
|
1839
|
+
}
|
|
1840
|
+
if (!responseText) {
|
|
1841
|
+
return false;
|
|
1842
|
+
}
|
|
1843
|
+
const normalized = responseText.toLowerCase();
|
|
1844
|
+
return (normalized.includes('no_more_improvements') ||
|
|
1845
|
+
normalized.includes('no more improvements') ||
|
|
1846
|
+
normalized.includes('stop_auto_improve'));
|
|
1847
|
+
}
|
|
1506
1848
|
async handlePendingInteraction(input) {
|
|
1507
1849
|
if (!this.pendingInteraction) {
|
|
1508
1850
|
return false;
|
|
@@ -1510,7 +1852,7 @@ export class InteractiveShell {
|
|
|
1510
1852
|
switch (this.pendingInteraction.type) {
|
|
1511
1853
|
case 'model-loading':
|
|
1512
1854
|
display.showInfo('Still fetching model options. Please wait a moment.');
|
|
1513
|
-
this.
|
|
1855
|
+
this.renderPromptArea();
|
|
1514
1856
|
return true;
|
|
1515
1857
|
case 'model-provider':
|
|
1516
1858
|
await this.handleModelProviderSelection(input);
|
|
@@ -1541,7 +1883,7 @@ export class InteractiveShell {
|
|
|
1541
1883
|
const [command] = input.split(/\s+/);
|
|
1542
1884
|
if (!command) {
|
|
1543
1885
|
display.showWarning('Enter a slash command.');
|
|
1544
|
-
this.
|
|
1886
|
+
this.renderPromptArea();
|
|
1545
1887
|
return;
|
|
1546
1888
|
}
|
|
1547
1889
|
switch (command) {
|
|
@@ -1599,6 +1941,9 @@ export class InteractiveShell {
|
|
|
1599
1941
|
case '/autocontinue':
|
|
1600
1942
|
this.handleAutoContinueCommand(input);
|
|
1601
1943
|
break;
|
|
1944
|
+
case '/alphazero':
|
|
1945
|
+
this.handleAlphaZeroCommand(input);
|
|
1946
|
+
break;
|
|
1602
1947
|
case '/shortcuts':
|
|
1603
1948
|
case '/keys':
|
|
1604
1949
|
this.handleShortcutsCommand();
|
|
@@ -1703,7 +2048,7 @@ export class InteractiveShell {
|
|
|
1703
2048
|
}
|
|
1704
2049
|
break;
|
|
1705
2050
|
}
|
|
1706
|
-
this.
|
|
2051
|
+
this.renderPromptArea();
|
|
1707
2052
|
}
|
|
1708
2053
|
async tryCustomSlashCommand(command, fullInput) {
|
|
1709
2054
|
const custom = this.customCommandMap.get(command);
|
|
@@ -1740,6 +2085,7 @@ export class InteractiveShell {
|
|
|
1740
2085
|
` ${theme.info('Option+V')} ${theme.ui.muted('Toggle verification')}`,
|
|
1741
2086
|
` ${theme.info('Option+C')} ${theme.ui.muted('Toggle auto-continue')}`,
|
|
1742
2087
|
` ${theme.info('Option+T')} ${theme.ui.muted('Cycle thinking mode')}`,
|
|
2088
|
+
` ${theme.info('Option+A')} ${theme.ui.muted('Toggle AlphaZero RL mode')}`,
|
|
1743
2089
|
` ${theme.info('Option+E')} ${theme.ui.muted('Toggle edit permission mode')}`,
|
|
1744
2090
|
` ${theme.info('Option+X')} ${theme.ui.muted('Clear/compact context')}`,
|
|
1745
2091
|
'',
|
|
@@ -2025,6 +2371,24 @@ export class InteractiveShell {
|
|
|
2025
2371
|
};
|
|
2026
2372
|
display.showInfo(`Thinking mode set to ${theme.info(value)} – ${descriptions[this.thinkingMode]}`);
|
|
2027
2373
|
}
|
|
2374
|
+
handleAlphaZeroCommand(input) {
|
|
2375
|
+
const value = input.slice('/alphazero'.length).trim().toLowerCase();
|
|
2376
|
+
if (!value || value === 'status') {
|
|
2377
|
+
const status = this.alphaZeroModeEnabled ? theme.success('on') : theme.ui.muted('off');
|
|
2378
|
+
const verification = this.verificationEnabled ? 'verification locked on' : 'verification optional';
|
|
2379
|
+
display.showInfo(`AlphaZero RL mode is ${status}. When enabled, difficult prompts use duel/self-critique and human-style verification (${verification}).`);
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
if (['on', 'enable', 'enabled'].includes(value)) {
|
|
2383
|
+
this.setAlphaZeroMode(true, 'command');
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
if (['off', 'disable', 'disabled'].includes(value)) {
|
|
2387
|
+
this.setAlphaZeroMode(false, 'command');
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
display.showWarning('Usage: /alphazero [on|off|status]');
|
|
2391
|
+
}
|
|
2028
2392
|
handleShortcutsCommand() {
|
|
2029
2393
|
// Display keyboard shortcuts help (Claude Code style)
|
|
2030
2394
|
display.showSystemMessage(formatShortcutsHelp());
|
|
@@ -3494,7 +3858,7 @@ export class InteractiveShell {
|
|
|
3494
3858
|
display.clear();
|
|
3495
3859
|
clearAutosaveSnapshot(this.profile);
|
|
3496
3860
|
display.showInfo('Conversation cleared. Starting fresh.');
|
|
3497
|
-
this.
|
|
3861
|
+
this.renderPromptArea();
|
|
3498
3862
|
}
|
|
3499
3863
|
async handleResumeCommand(input) {
|
|
3500
3864
|
const tokens = input.split(/\s+/).slice(1);
|
|
@@ -3803,7 +4167,7 @@ export class InteractiveShell {
|
|
|
3803
4167
|
if (!providerOptions.length) {
|
|
3804
4168
|
display.showWarning('No providers are available.');
|
|
3805
4169
|
this.pendingInteraction = null;
|
|
3806
|
-
this.
|
|
4170
|
+
this.renderPromptArea();
|
|
3807
4171
|
return;
|
|
3808
4172
|
}
|
|
3809
4173
|
const lines = [
|
|
@@ -3824,7 +4188,7 @@ export class InteractiveShell {
|
|
|
3824
4188
|
catch (error) {
|
|
3825
4189
|
display.showError('Failed to load model list. Try again in a moment.', error);
|
|
3826
4190
|
this.pendingInteraction = null;
|
|
3827
|
-
this.
|
|
4191
|
+
this.renderPromptArea();
|
|
3828
4192
|
}
|
|
3829
4193
|
}
|
|
3830
4194
|
buildProviderOptions() {
|
|
@@ -4369,29 +4733,29 @@ export class InteractiveShell {
|
|
|
4369
4733
|
const trimmed = input.trim();
|
|
4370
4734
|
if (!trimmed) {
|
|
4371
4735
|
display.showWarning('Enter a number or type cancel.');
|
|
4372
|
-
this.
|
|
4736
|
+
this.renderPromptArea();
|
|
4373
4737
|
return;
|
|
4374
4738
|
}
|
|
4375
4739
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4376
4740
|
this.pendingInteraction = null;
|
|
4377
4741
|
display.showInfo('Model selection cancelled.');
|
|
4378
|
-
this.
|
|
4742
|
+
this.renderPromptArea();
|
|
4379
4743
|
return;
|
|
4380
4744
|
}
|
|
4381
4745
|
const choice = Number.parseInt(trimmed, 10);
|
|
4382
4746
|
if (!Number.isFinite(choice)) {
|
|
4383
4747
|
display.showWarning('Please enter a valid number.');
|
|
4384
|
-
this.
|
|
4748
|
+
this.renderPromptArea();
|
|
4385
4749
|
return;
|
|
4386
4750
|
}
|
|
4387
4751
|
const option = pending.options[choice - 1];
|
|
4388
4752
|
if (!option) {
|
|
4389
4753
|
display.showWarning('That option is not available.');
|
|
4390
|
-
this.
|
|
4754
|
+
this.renderPromptArea();
|
|
4391
4755
|
return;
|
|
4392
4756
|
}
|
|
4393
4757
|
this.showProviderModels(option);
|
|
4394
|
-
this.
|
|
4758
|
+
this.renderPromptArea();
|
|
4395
4759
|
}
|
|
4396
4760
|
async handleModelSelection(input) {
|
|
4397
4761
|
const pending = this.pendingInteraction;
|
|
@@ -4401,35 +4765,35 @@ export class InteractiveShell {
|
|
|
4401
4765
|
const trimmed = input.trim();
|
|
4402
4766
|
if (!trimmed) {
|
|
4403
4767
|
display.showWarning('Enter a number, type "back", or type "cancel".');
|
|
4404
|
-
this.
|
|
4768
|
+
this.renderPromptArea();
|
|
4405
4769
|
return;
|
|
4406
4770
|
}
|
|
4407
4771
|
if (trimmed.toLowerCase() === 'back') {
|
|
4408
4772
|
this.showModelMenu();
|
|
4409
|
-
this.
|
|
4773
|
+
this.renderPromptArea();
|
|
4410
4774
|
return;
|
|
4411
4775
|
}
|
|
4412
4776
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4413
4777
|
this.pendingInteraction = null;
|
|
4414
4778
|
display.showInfo('Model selection cancelled.');
|
|
4415
|
-
this.
|
|
4779
|
+
this.renderPromptArea();
|
|
4416
4780
|
return;
|
|
4417
4781
|
}
|
|
4418
4782
|
const choice = Number.parseInt(trimmed, 10);
|
|
4419
4783
|
if (!Number.isFinite(choice)) {
|
|
4420
4784
|
display.showWarning('Please enter a valid number.');
|
|
4421
|
-
this.
|
|
4785
|
+
this.renderPromptArea();
|
|
4422
4786
|
return;
|
|
4423
4787
|
}
|
|
4424
4788
|
const preset = pending.options[choice - 1];
|
|
4425
4789
|
if (!preset) {
|
|
4426
4790
|
display.showWarning('That option is not available.');
|
|
4427
|
-
this.
|
|
4791
|
+
this.renderPromptArea();
|
|
4428
4792
|
return;
|
|
4429
4793
|
}
|
|
4430
4794
|
this.pendingInteraction = null;
|
|
4431
4795
|
await this.applyModelPreset(preset);
|
|
4432
|
-
this.
|
|
4796
|
+
this.renderPromptArea();
|
|
4433
4797
|
}
|
|
4434
4798
|
async applyModelPreset(preset) {
|
|
4435
4799
|
try {
|
|
@@ -4462,30 +4826,30 @@ export class InteractiveShell {
|
|
|
4462
4826
|
const trimmed = input.trim();
|
|
4463
4827
|
if (!trimmed) {
|
|
4464
4828
|
display.showWarning('Enter a number or type cancel.');
|
|
4465
|
-
this.
|
|
4829
|
+
this.renderPromptArea();
|
|
4466
4830
|
return;
|
|
4467
4831
|
}
|
|
4468
4832
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4469
4833
|
this.pendingInteraction = null;
|
|
4470
4834
|
display.showInfo('Secret management cancelled.');
|
|
4471
|
-
this.
|
|
4835
|
+
this.renderPromptArea();
|
|
4472
4836
|
return;
|
|
4473
4837
|
}
|
|
4474
4838
|
const choice = Number.parseInt(trimmed, 10);
|
|
4475
4839
|
if (!Number.isFinite(choice)) {
|
|
4476
4840
|
display.showWarning('Please enter a valid number.');
|
|
4477
|
-
this.
|
|
4841
|
+
this.renderPromptArea();
|
|
4478
4842
|
return;
|
|
4479
4843
|
}
|
|
4480
4844
|
const secret = pending.options[choice - 1];
|
|
4481
4845
|
if (!secret) {
|
|
4482
4846
|
display.showWarning('That option is not available.');
|
|
4483
|
-
this.
|
|
4847
|
+
this.renderPromptArea();
|
|
4484
4848
|
return;
|
|
4485
4849
|
}
|
|
4486
4850
|
display.showSystemMessage(`Enter a new value for ${secret.label} or type "cancel".`);
|
|
4487
4851
|
this.pendingInteraction = { type: 'secret-input', secret };
|
|
4488
|
-
this.
|
|
4852
|
+
this.renderPromptArea();
|
|
4489
4853
|
}
|
|
4490
4854
|
async handleSecretInput(input) {
|
|
4491
4855
|
const pending = this.pendingInteraction;
|
|
@@ -4495,14 +4859,16 @@ export class InteractiveShell {
|
|
|
4495
4859
|
const trimmed = input.trim();
|
|
4496
4860
|
if (!trimmed) {
|
|
4497
4861
|
display.showWarning('Enter a value or type cancel.');
|
|
4498
|
-
this.
|
|
4862
|
+
this.renderPromptArea();
|
|
4499
4863
|
return;
|
|
4500
4864
|
}
|
|
4501
4865
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4502
4866
|
this.pendingInteraction = null;
|
|
4503
4867
|
this.pendingSecretRetry = null;
|
|
4868
|
+
this.apiKeyGateActive = false;
|
|
4504
4869
|
display.showInfo('Secret unchanged.');
|
|
4505
|
-
this.
|
|
4870
|
+
this.renderPromptArea();
|
|
4871
|
+
this.scheduleQueueProcessing();
|
|
4506
4872
|
return;
|
|
4507
4873
|
}
|
|
4508
4874
|
try {
|
|
@@ -4511,6 +4877,7 @@ export class InteractiveShell {
|
|
|
4511
4877
|
this.pendingInteraction = null;
|
|
4512
4878
|
const deferred = this.pendingSecretRetry;
|
|
4513
4879
|
this.pendingSecretRetry = null;
|
|
4880
|
+
this.apiKeyGateActive = false;
|
|
4514
4881
|
if (pending.secret.providers.includes(this.sessionState.provider)) {
|
|
4515
4882
|
if (this.rebuildAgent()) {
|
|
4516
4883
|
this.resetChatBoxAfterModelSwap();
|
|
@@ -4525,12 +4892,14 @@ export class InteractiveShell {
|
|
|
4525
4892
|
display.showError(message);
|
|
4526
4893
|
this.pendingInteraction = null;
|
|
4527
4894
|
this.pendingSecretRetry = null;
|
|
4895
|
+
this.apiKeyGateActive = false;
|
|
4528
4896
|
}
|
|
4529
|
-
this.
|
|
4897
|
+
this.renderPromptArea();
|
|
4898
|
+
this.scheduleQueueProcessing();
|
|
4530
4899
|
}
|
|
4531
|
-
async processRequest(
|
|
4900
|
+
async processRequest(userRequest) {
|
|
4532
4901
|
if (this.isProcessing) {
|
|
4533
|
-
this.enqueueFollowUpAction({ type: 'request', text:
|
|
4902
|
+
this.enqueueFollowUpAction({ type: 'request', text: userRequest });
|
|
4534
4903
|
return;
|
|
4535
4904
|
}
|
|
4536
4905
|
if (!this.agent && !this.rebuildAgent()) {
|
|
@@ -4541,28 +4910,54 @@ export class InteractiveShell {
|
|
|
4541
4910
|
if (!agent) {
|
|
4542
4911
|
return;
|
|
4543
4912
|
}
|
|
4544
|
-
this.
|
|
4913
|
+
this.hasShownThoughtProcess = false;
|
|
4914
|
+
const alphaZeroEngaged = this.alphaZeroModeEnabled;
|
|
4915
|
+
const alphaZeroDifficult = alphaZeroEngaged ? this.isDifficultProblem(userRequest) : false;
|
|
4916
|
+
const requestForAgent = alphaZeroEngaged
|
|
4917
|
+
? this.buildAlphaZeroPrompt(userRequest, alphaZeroDifficult)
|
|
4918
|
+
: userRequest;
|
|
4919
|
+
const skipReflectionForThisRun = this.skipNextAutoReflection;
|
|
4920
|
+
this.skipNextAutoReflection = false;
|
|
4921
|
+
const scrollbackStartIndex = this.terminalInput.getScrollbackBuffer().length;
|
|
4922
|
+
const alphaZeroStatusId = 'alpha-zero';
|
|
4923
|
+
let alphaZeroStatusApplied = false;
|
|
4924
|
+
let alphaZeroTaskStarted = false;
|
|
4925
|
+
let alphaZeroTaskCompleted = false;
|
|
4926
|
+
if (alphaZeroEngaged) {
|
|
4927
|
+
const detail = alphaZeroDifficult ? 'Difficult request detected' : 'Reinforcement loop enabled';
|
|
4928
|
+
this.statusTracker.pushOverride(alphaZeroStatusId, 'AlphaZero RL active', {
|
|
4929
|
+
detail: `${detail} · full verification`,
|
|
4930
|
+
tone: 'info',
|
|
4931
|
+
});
|
|
4932
|
+
alphaZeroStatusApplied = true;
|
|
4933
|
+
display.showInfo(`AlphaZero RL mode engaged${alphaZeroDifficult ? ' for a difficult request' : ''}. Duel + self-critique with verification enabled.`);
|
|
4934
|
+
this.alphaZeroMetrics.startAlphaZeroTask(userRequest);
|
|
4935
|
+
alphaZeroTaskStarted = true;
|
|
4936
|
+
}
|
|
4937
|
+
this.logUserPrompt(userRequest);
|
|
4545
4938
|
this.isProcessing = true;
|
|
4546
4939
|
this.uiUpdates.setMode('processing');
|
|
4547
4940
|
this.terminalInput.setStreaming(true);
|
|
4548
4941
|
// Keep the persistent input/control bar active as we transition into streaming.
|
|
4549
|
-
this.
|
|
4942
|
+
this.renderPromptArea(true);
|
|
4550
4943
|
const requestStartTime = Date.now(); // Alpha Zero 2 timing
|
|
4551
4944
|
// Clear previous parallel agents and start fresh for new request
|
|
4552
4945
|
const parallelManager = getParallelAgentManager();
|
|
4553
4946
|
parallelManager.clear();
|
|
4554
4947
|
parallelManager.startBatch();
|
|
4555
4948
|
// AlphaZero: Track task for learning
|
|
4556
|
-
this.lastUserQuery =
|
|
4557
|
-
this.currentTaskType = classifyTaskType(
|
|
4949
|
+
this.lastUserQuery = userRequest;
|
|
4950
|
+
this.currentTaskType = classifyTaskType(userRequest);
|
|
4558
4951
|
this.currentToolCalls = [];
|
|
4559
4952
|
this.uiAdapter.startProcessing('Working on your request');
|
|
4560
4953
|
this.setProcessingStatus();
|
|
4561
4954
|
let responseText = '';
|
|
4955
|
+
let detectedFailure = null;
|
|
4956
|
+
let hadUnhandledError = false;
|
|
4562
4957
|
try {
|
|
4563
4958
|
// Start streaming - no header needed, the input area already provides context
|
|
4564
|
-
this.startStreamingHeartbeat('Streaming response');
|
|
4565
|
-
responseText = await agent.send(
|
|
4959
|
+
this.startStreamingHeartbeat(alphaZeroEngaged ? 'AlphaZero RL' : 'Streaming response');
|
|
4960
|
+
responseText = await agent.send(requestForAgent, true);
|
|
4566
4961
|
await this.awaitPendingCleanup();
|
|
4567
4962
|
this.captureHistorySnapshot();
|
|
4568
4963
|
this.autosaveIfEnabled();
|
|
@@ -4581,14 +4976,18 @@ export class InteractiveShell {
|
|
|
4581
4976
|
duration: 0,
|
|
4582
4977
|
}));
|
|
4583
4978
|
// AlphaZero: Check for failure in response
|
|
4584
|
-
|
|
4979
|
+
detectedFailure = detectFailure(responseText, {
|
|
4585
4980
|
toolCalls: this.currentToolCalls,
|
|
4586
|
-
userMessage:
|
|
4981
|
+
userMessage: userRequest,
|
|
4587
4982
|
});
|
|
4588
|
-
if (
|
|
4589
|
-
this.
|
|
4983
|
+
if (alphaZeroEngaged && alphaZeroTaskStarted && !alphaZeroTaskCompleted) {
|
|
4984
|
+
this.alphaZeroMetrics.completeAlphaZeroTask(!detectedFailure);
|
|
4985
|
+
alphaZeroTaskCompleted = true;
|
|
4986
|
+
}
|
|
4987
|
+
if (detectedFailure) {
|
|
4988
|
+
this.lastFailure = detectedFailure;
|
|
4590
4989
|
// Check if we have a recovery strategy
|
|
4591
|
-
const strategy = findRecoveryStrategy(
|
|
4990
|
+
const strategy = findRecoveryStrategy(detectedFailure);
|
|
4592
4991
|
if (strategy) {
|
|
4593
4992
|
display.showSystemMessage(`🔄 Found recovery strategy for this type of issue (success rate: ${Math.round(strategy.successRate * 100)}%)`);
|
|
4594
4993
|
}
|
|
@@ -4611,13 +5010,42 @@ export class InteractiveShell {
|
|
|
4611
5010
|
}
|
|
4612
5011
|
}
|
|
4613
5012
|
catch (error) {
|
|
4614
|
-
const handled = this.handleProviderError(error, () => this.processRequest(
|
|
5013
|
+
const handled = this.handleProviderError(error, () => this.processRequest(userRequest));
|
|
5014
|
+
hadUnhandledError = !handled;
|
|
5015
|
+
if (alphaZeroEngaged && alphaZeroTaskStarted && !alphaZeroTaskCompleted) {
|
|
5016
|
+
this.alphaZeroMetrics.completeAlphaZeroTask(false);
|
|
5017
|
+
alphaZeroTaskCompleted = true;
|
|
5018
|
+
}
|
|
4615
5019
|
if (!handled) {
|
|
4616
5020
|
// Pass full error object for enhanced formatting with stack trace
|
|
4617
5021
|
display.showError(error instanceof Error ? error.message : String(error), error);
|
|
4618
5022
|
}
|
|
4619
5023
|
}
|
|
4620
5024
|
finally {
|
|
5025
|
+
const runLogEntry = this.buildRunLogEntry(userRequest, responseText, scrollbackStartIndex, {
|
|
5026
|
+
alphaZeroEngaged,
|
|
5027
|
+
alphaZeroDifficult,
|
|
5028
|
+
failureType: detectedFailure?.type ?? (hadUnhandledError ? 'unhandled-error' : null),
|
|
5029
|
+
});
|
|
5030
|
+
this.lastRunLog = runLogEntry;
|
|
5031
|
+
const allowAutoChain = alphaZeroEngaged && this.autoContinueEnabled && isErosolarRepo(this.workingDir);
|
|
5032
|
+
let shouldStopAuto = false;
|
|
5033
|
+
if (this.alphaZeroAutoImproveActive) {
|
|
5034
|
+
shouldStopAuto = this.shouldStopAlphaZeroAutoImprove(responseText, allowAutoChain);
|
|
5035
|
+
if (shouldStopAuto) {
|
|
5036
|
+
this.alphaZeroAutoImproveActive = false;
|
|
5037
|
+
this.alphaZeroAutoImproveIterations = 0;
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
if (!skipReflectionForThisRun && !shouldStopAuto) {
|
|
5041
|
+
this.maybeQueueAlphaZeroSelfReflection(runLogEntry, alphaZeroEngaged, allowAutoChain);
|
|
5042
|
+
}
|
|
5043
|
+
if (alphaZeroEngaged && alphaZeroStatusApplied) {
|
|
5044
|
+
this.statusTracker.clearOverride(alphaZeroStatusId);
|
|
5045
|
+
}
|
|
5046
|
+
if (alphaZeroEngaged && alphaZeroTaskStarted && !alphaZeroTaskCompleted) {
|
|
5047
|
+
this.alphaZeroMetrics.completeAlphaZeroTask(false);
|
|
5048
|
+
}
|
|
4621
5049
|
display.stopThinking(false);
|
|
4622
5050
|
this.uiUpdates.setMode('processing');
|
|
4623
5051
|
this.stopStreamingHeartbeat();
|
|
@@ -4631,7 +5059,7 @@ export class InteractiveShell {
|
|
|
4631
5059
|
// CRITICAL: Ensure readline prompt is active for user input
|
|
4632
5060
|
// Claude Code style: New prompt naturally appears at bottom
|
|
4633
5061
|
this.ensureReadlineReady();
|
|
4634
|
-
this.
|
|
5062
|
+
this.renderPromptArea();
|
|
4635
5063
|
this.scheduleQueueProcessing();
|
|
4636
5064
|
this.refreshQueueIndicators();
|
|
4637
5065
|
}
|
|
@@ -4662,6 +5090,7 @@ export class InteractiveShell {
|
|
|
4662
5090
|
if (!agent) {
|
|
4663
5091
|
return;
|
|
4664
5092
|
}
|
|
5093
|
+
this.hasShownThoughtProcess = false;
|
|
4665
5094
|
this.isProcessing = true;
|
|
4666
5095
|
this.uiUpdates.setMode('processing');
|
|
4667
5096
|
this.terminalInput.setStreaming(true);
|
|
@@ -4702,6 +5131,7 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
|
4702
5131
|
}
|
|
4703
5132
|
while (iteration < MAX_ITERATIONS) {
|
|
4704
5133
|
iteration++;
|
|
5134
|
+
this.hasShownThoughtProcess = false;
|
|
4705
5135
|
display.showSystemMessage(`\n📍 Iteration ${iteration}/${MAX_ITERATIONS}`);
|
|
4706
5136
|
this.updateStatusMessage(`Working on iteration ${iteration}...`);
|
|
4707
5137
|
try {
|
|
@@ -5102,6 +5532,8 @@ What's the next action?`;
|
|
|
5102
5532
|
finally {
|
|
5103
5533
|
this.updateStatusMessage(null);
|
|
5104
5534
|
this.autoTestInFlight = false;
|
|
5535
|
+
this.terminalInput.resetContentPosition();
|
|
5536
|
+
this.terminalInput.forceRender();
|
|
5105
5537
|
}
|
|
5106
5538
|
}
|
|
5107
5539
|
isBuildToolCall(entry) {
|
|
@@ -5208,7 +5640,8 @@ What's the next action?`;
|
|
|
5208
5640
|
// Send the error to the agent for fixing
|
|
5209
5641
|
display.showThinking('Analyzing build errors');
|
|
5210
5642
|
this.refreshStatusLine(true);
|
|
5211
|
-
|
|
5643
|
+
this.hasShownThoughtProcess = false;
|
|
5644
|
+
const response = await this.withStreamingUi('Fixing build errors', () => this.agent.send(prompt, true));
|
|
5212
5645
|
display.stopThinking();
|
|
5213
5646
|
this.refreshStatusLine(true);
|
|
5214
5647
|
if (response) {
|
|
@@ -5243,22 +5676,15 @@ What's the next action?`;
|
|
|
5243
5676
|
onStreamFallback: (info) => this.handleStreamingFallback(info),
|
|
5244
5677
|
onAssistantMessage: (content, metadata) => {
|
|
5245
5678
|
const enriched = this.buildDisplayMetadata(metadata);
|
|
5679
|
+
const parsed = this.splitThinkingResponse(content);
|
|
5680
|
+
const thinking = parsed?.thinking ?? null;
|
|
5681
|
+
const responseContent = parsed ? parsed.response?.trim() ?? '' : content.trim();
|
|
5246
5682
|
// Update spinner based on message type
|
|
5247
5683
|
if (metadata.isFinal) {
|
|
5684
|
+
this.presentThoughtProcess(thinking, enriched, { wasStreamed: metadata.wasStreamed });
|
|
5248
5685
|
// Skip display if content was already streamed to avoid double-display
|
|
5249
|
-
if (!metadata.wasStreamed) {
|
|
5250
|
-
|
|
5251
|
-
if (parsed?.thinking) {
|
|
5252
|
-
const summary = this.extractThoughtSummary(parsed.thinking);
|
|
5253
|
-
if (summary) {
|
|
5254
|
-
display.updateThinking(`💭 ${summary}`);
|
|
5255
|
-
}
|
|
5256
|
-
display.showAssistantMessage(parsed.thinking, { ...enriched, isFinal: false });
|
|
5257
|
-
}
|
|
5258
|
-
const finalContent = parsed?.response?.trim() || content;
|
|
5259
|
-
if (finalContent) {
|
|
5260
|
-
display.showAssistantMessage(finalContent, enriched);
|
|
5261
|
-
}
|
|
5686
|
+
if (!metadata.wasStreamed && responseContent) {
|
|
5687
|
+
display.showAssistantMessage(responseContent, enriched);
|
|
5262
5688
|
}
|
|
5263
5689
|
// Status shown in mode controls bar - no separate status line needed
|
|
5264
5690
|
display.stopThinking();
|
|
@@ -5275,12 +5701,16 @@ What's the next action?`;
|
|
|
5275
5701
|
void this.enforceAutoTests('final-response');
|
|
5276
5702
|
}
|
|
5277
5703
|
else {
|
|
5704
|
+
if (thinking) {
|
|
5705
|
+
this.presentThoughtProcess(thinking, enriched, { wasStreamed: metadata.wasStreamed });
|
|
5706
|
+
}
|
|
5278
5707
|
// Non-final message = narrative text before tool calls (Claude Code style)
|
|
5279
5708
|
// Stop spinner and show the narrative text directly
|
|
5280
5709
|
display.stopThinking();
|
|
5281
5710
|
// Skip display if content was already streamed to avoid double-display
|
|
5282
5711
|
if (!metadata.wasStreamed) {
|
|
5283
|
-
|
|
5712
|
+
const narrative = parsed?.response ?? content;
|
|
5713
|
+
display.showNarrative(narrative.trim());
|
|
5284
5714
|
}
|
|
5285
5715
|
// The isProcessing flag already shows "⏳ Processing..." - no need for duplicate status
|
|
5286
5716
|
this.requestPromptRefresh();
|
|
@@ -5318,19 +5748,19 @@ What's the next action?`;
|
|
|
5318
5748
|
this.updateContextUsage(percentage);
|
|
5319
5749
|
}
|
|
5320
5750
|
// Ensure prompt remains visible at bottom after context messages
|
|
5321
|
-
this.
|
|
5751
|
+
this.renderPromptArea();
|
|
5322
5752
|
},
|
|
5323
5753
|
onContinueAfterRecovery: () => {
|
|
5324
5754
|
// Update UI to show we're continuing after context recovery
|
|
5325
5755
|
display.showSystemMessage(`🔄 Continuing after context recovery...`);
|
|
5326
5756
|
this.updateStatusMessage('Retrying with reduced context...');
|
|
5327
|
-
this.
|
|
5757
|
+
this.renderPromptArea();
|
|
5328
5758
|
},
|
|
5329
5759
|
onAutoContinue: (attempt, maxAttempts, _message) => {
|
|
5330
5760
|
// Show auto-continue progress in UI
|
|
5331
5761
|
display.showSystemMessage(`🔄 Auto-continue (${attempt}/${maxAttempts}): Model expressed intent, prompting to act...`);
|
|
5332
5762
|
this.updateStatusMessage('Auto-continuing...');
|
|
5333
|
-
this.
|
|
5763
|
+
this.renderPromptArea();
|
|
5334
5764
|
},
|
|
5335
5765
|
onCancelled: () => {
|
|
5336
5766
|
// Update UI to show operation was cancelled
|
|
@@ -5339,7 +5769,7 @@ What's the next action?`;
|
|
|
5339
5769
|
this.stopStreamingHeartbeat();
|
|
5340
5770
|
this.updateStatusMessage(null);
|
|
5341
5771
|
this.terminalInput.setStreaming(false);
|
|
5342
|
-
this.
|
|
5772
|
+
this.renderPromptArea();
|
|
5343
5773
|
},
|
|
5344
5774
|
onVerificationNeeded: () => {
|
|
5345
5775
|
void this.enforceAutoBuild('verification');
|
|
@@ -5377,7 +5807,7 @@ What's the next action?`;
|
|
|
5377
5807
|
resetChatBoxAfterModelSwap() {
|
|
5378
5808
|
this.updateStatusMessage(null);
|
|
5379
5809
|
this.terminalInput.setStreaming(false);
|
|
5380
|
-
this.
|
|
5810
|
+
this.renderPromptArea();
|
|
5381
5811
|
this.ensureReadlineReady();
|
|
5382
5812
|
}
|
|
5383
5813
|
/**
|
|
@@ -5463,6 +5893,19 @@ What's the next action?`;
|
|
|
5463
5893
|
contextWindowTokens: this.activeContextWindowTokens,
|
|
5464
5894
|
};
|
|
5465
5895
|
}
|
|
5896
|
+
presentThoughtProcess(thinking, metadata, options) {
|
|
5897
|
+
if (!thinking || this.hasShownThoughtProcess) {
|
|
5898
|
+
return;
|
|
5899
|
+
}
|
|
5900
|
+
const summary = this.extractThoughtSummary(thinking);
|
|
5901
|
+
if (summary) {
|
|
5902
|
+
display.updateThinking(`💭 ${summary}`);
|
|
5903
|
+
}
|
|
5904
|
+
if (!options?.wasStreamed) {
|
|
5905
|
+
display.showAssistantMessage(thinking, { ...metadata, isFinal: false });
|
|
5906
|
+
}
|
|
5907
|
+
this.hasShownThoughtProcess = true;
|
|
5908
|
+
}
|
|
5466
5909
|
handleContextTelemetry(metadata, displayMetadata) {
|
|
5467
5910
|
if (!metadata.isFinal) {
|
|
5468
5911
|
return null;
|
|
@@ -5823,7 +6266,7 @@ What's the next action?`;
|
|
|
5823
6266
|
}
|
|
5824
6267
|
handleAgentSetupError(error, retryAction, providerOverride) {
|
|
5825
6268
|
this.pendingInteraction = null;
|
|
5826
|
-
const provider = providerOverride
|
|
6269
|
+
const provider = providerOverride === undefined ? this.sessionState.provider : providerOverride;
|
|
5827
6270
|
const apiKeyIssue = detectApiKeyError(error, provider);
|
|
5828
6271
|
if (apiKeyIssue) {
|
|
5829
6272
|
this.handleApiKeyIssue(apiKeyIssue, retryAction);
|
|
@@ -5843,7 +6286,8 @@ What's the next action?`;
|
|
|
5843
6286
|
this.requestPromptRefresh(true);
|
|
5844
6287
|
}
|
|
5845
6288
|
handleProviderError(error, retryAction) {
|
|
5846
|
-
const
|
|
6289
|
+
const providerHint = error instanceof MissingSecretError ? null : this.sessionState.provider;
|
|
6290
|
+
const apiKeyIssue = detectApiKeyError(error, providerHint);
|
|
5847
6291
|
if (!apiKeyIssue) {
|
|
5848
6292
|
return false;
|
|
5849
6293
|
}
|
|
@@ -5852,13 +6296,19 @@ What's the next action?`;
|
|
|
5852
6296
|
}
|
|
5853
6297
|
handleApiKeyIssue(info, retryAction) {
|
|
5854
6298
|
const secret = info.secret ?? null;
|
|
5855
|
-
const providerLabel = info.provider
|
|
6299
|
+
const providerLabel = info.provider
|
|
6300
|
+
? this.providerLabel(info.provider)
|
|
6301
|
+
: secret?.providers?.length
|
|
6302
|
+
? this.providerLabel(secret.providers[0])
|
|
6303
|
+
: null;
|
|
6304
|
+
const targetLabel = providerLabel ?? secret?.label ?? 'this tool';
|
|
6305
|
+
this.apiKeyGateActive = !!secret;
|
|
5856
6306
|
if (!secret) {
|
|
5857
6307
|
this.pendingSecretRetry = null;
|
|
5858
6308
|
const guidance = 'Run "/secrets" to configure the required API key or export it (e.g., EXPORT KEY=value) before launching the CLI.';
|
|
5859
6309
|
const baseMessage = info.type === 'missing'
|
|
5860
|
-
? `An API key is required before using ${
|
|
5861
|
-
: `API authentication failed for ${
|
|
6310
|
+
? `An API key is required before using ${targetLabel}.`
|
|
6311
|
+
: `API authentication failed for ${targetLabel}.`;
|
|
5862
6312
|
display.showWarning(`${baseMessage} ${guidance}`.trim());
|
|
5863
6313
|
return;
|
|
5864
6314
|
}
|
|
@@ -5867,8 +6317,8 @@ What's the next action?`;
|
|
|
5867
6317
|
display.showWarning(info.message.trim());
|
|
5868
6318
|
}
|
|
5869
6319
|
const prefix = isMissing
|
|
5870
|
-
? `${secret.label} is required before you can use ${
|
|
5871
|
-
: `${secret.label} appears to be invalid for ${
|
|
6320
|
+
? `${secret.label} is required before you can use ${targetLabel}.`
|
|
6321
|
+
: `${secret.label} appears to be invalid for ${targetLabel}.`;
|
|
5872
6322
|
display.showWarning(prefix);
|
|
5873
6323
|
this.pendingSecretRetry = retryAction ?? null;
|
|
5874
6324
|
this.pendingInteraction = { type: 'secret-input', secret };
|