erosolar-cli 2.1.183 → 2.1.184
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/runtime/flowOrchestrator.d.ts.map +1 -1
- package/dist/runtime/flowOrchestrator.js +7 -0
- package/dist/runtime/flowOrchestrator.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +2 -13
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +121 -282
- package/dist/shell/interactiveShell.js.map +1 -1
- package/package.json +1 -1
|
@@ -2333,87 +2333,6 @@ export class InteractiveShell {
|
|
|
2333
2333
|
}
|
|
2334
2334
|
return false;
|
|
2335
2335
|
}
|
|
2336
|
-
/**
|
|
2337
|
-
* Decide whether to automatically continue execution when the model stops after a plan/summary
|
|
2338
|
-
* without taking actions. This keeps flows moving toward completion instead of stalling on planning.
|
|
2339
|
-
*/
|
|
2340
|
-
shouldAutoEscalateToExecution(request, response, toolsUsed) {
|
|
2341
|
-
// Only auto-escalate when the original request itself was action-oriented
|
|
2342
|
-
if (!this.shouldAutoRunToCompletion(request)) {
|
|
2343
|
-
return false;
|
|
2344
|
-
}
|
|
2345
|
-
if (!response || response.includes('TASK_FULLY_COMPLETE')) {
|
|
2346
|
-
return false;
|
|
2347
|
-
}
|
|
2348
|
-
const lower = response.toLowerCase();
|
|
2349
|
-
// Skip if the model explicitly says it is blocked
|
|
2350
|
-
const blockerPatterns = [
|
|
2351
|
-
/\bneed(s)?\s+(more\s+)?(info|information|details|clarification)\b/,
|
|
2352
|
-
/\bmissing\s+(api\s*key|credentials?|access|permission|token)\b/,
|
|
2353
|
-
/\b(no|not)\s+authorized\b/,
|
|
2354
|
-
/\bcannot\s+(proceed|continue|start|run)\b/,
|
|
2355
|
-
/\bblocked\b/,
|
|
2356
|
-
];
|
|
2357
|
-
if (blockerPatterns.some((pattern) => pattern.test(lower))) {
|
|
2358
|
-
return false;
|
|
2359
|
-
}
|
|
2360
|
-
const mutatingToolUsed = toolsUsed.some((tool) => WRITE_TOOL_NAMES.has(tool.toLowerCase()));
|
|
2361
|
-
const planOnly = this.flowOrchestrator.isPlanOnlyResponse(response);
|
|
2362
|
-
const lowActionDensity = response.split(/\s+/).length < 80;
|
|
2363
|
-
// If it's clearly a plan-only response, continue regardless of prior tool usage
|
|
2364
|
-
if (planOnly) {
|
|
2365
|
-
return true;
|
|
2366
|
-
}
|
|
2367
|
-
// Thin responses without any mutating work should keep pushing toward completion
|
|
2368
|
-
if (!mutatingToolUsed && lowActionDensity) {
|
|
2369
|
-
return true;
|
|
2370
|
-
}
|
|
2371
|
-
return false;
|
|
2372
|
-
}
|
|
2373
|
-
/**
|
|
2374
|
-
* Build a follow-through request when the model stops after planning instead of executing.
|
|
2375
|
-
*/
|
|
2376
|
-
maybeAutoFollowThrough(request, response, toolsUsed) {
|
|
2377
|
-
if (!this.shouldAutoEscalateToExecution(request, response, toolsUsed)) {
|
|
2378
|
-
return null;
|
|
2379
|
-
}
|
|
2380
|
-
const prompt = `${request.trim()}
|
|
2381
|
-
|
|
2382
|
-
Execute the plan you outlined. Use the available tools (bash, edits, git) to take the next actions and keep going until the request is fully accomplished. Do not restate the plan—perform the steps and report progress. Reply with TASK_FULLY_COMPLETE only when the work is truly done.`;
|
|
2383
|
-
return {
|
|
2384
|
-
prompt,
|
|
2385
|
-
reason: 'Plan-only or low-action response detected; auto-continuing to complete the task.',
|
|
2386
|
-
};
|
|
2387
|
-
}
|
|
2388
|
-
/**
|
|
2389
|
-
* Ensure informational requests produce a user-facing answer rather than stopping after planning.
|
|
2390
|
-
*/
|
|
2391
|
-
maybeAutoAnswerInformational(request, response) {
|
|
2392
|
-
const trimmedRequest = request.trim();
|
|
2393
|
-
const trimmedResponse = response.trim();
|
|
2394
|
-
if (!trimmedResponse) {
|
|
2395
|
-
return null;
|
|
2396
|
-
}
|
|
2397
|
-
if (!this.flowOrchestrator.isInformationalRequest(trimmedRequest)) {
|
|
2398
|
-
return null;
|
|
2399
|
-
}
|
|
2400
|
-
if (trimmedResponse.includes('TASK_FULLY_COMPLETE')) {
|
|
2401
|
-
return null;
|
|
2402
|
-
}
|
|
2403
|
-
const providesAnswer = this.flowOrchestrator.responseAnswersUserRequest(trimmedResponse);
|
|
2404
|
-
const planOnly = this.flowOrchestrator.isPlanOnlyResponse(trimmedResponse);
|
|
2405
|
-
const indicatesIncomplete = this.flowOrchestrator.responseIndicatesIncompleteWork(trimmedResponse);
|
|
2406
|
-
if (providesAnswer && !planOnly && !indicatesIncomplete) {
|
|
2407
|
-
return null;
|
|
2408
|
-
}
|
|
2409
|
-
const prompt = `${trimmedRequest}
|
|
2410
|
-
|
|
2411
|
-
You have gathered context but did not provide a clear answer. Respond now with a concise, helpful summary that addresses the request directly. Include the key findings (not the plan), and end with "TASK_FULLY_COMPLETE" if nothing else is needed.`;
|
|
2412
|
-
return {
|
|
2413
|
-
prompt,
|
|
2414
|
-
reason: 'Informational request lacked a user-facing answer; prompting to finish helpfully.',
|
|
2415
|
-
};
|
|
2416
|
-
}
|
|
2417
2336
|
isExitCommand(input) {
|
|
2418
2337
|
const lower = input.trim().toLowerCase();
|
|
2419
2338
|
return (lower === 'exit' ||
|
|
@@ -5861,20 +5780,22 @@ You have gathered context but did not provide a clear answer. Respond now with a
|
|
|
5861
5780
|
this.clearInlinePanel();
|
|
5862
5781
|
this.syncRendererInput();
|
|
5863
5782
|
}
|
|
5864
|
-
async
|
|
5783
|
+
async runFlowControlledTask(initialRequest, options) {
|
|
5784
|
+
const { maxIterations, mode } = options;
|
|
5785
|
+
const followUpType = mode === 'continuous' ? 'continuous' : 'request';
|
|
5865
5786
|
if (this.isProcessing) {
|
|
5866
|
-
this.enqueueFollowUpAction({ type:
|
|
5867
|
-
return;
|
|
5787
|
+
this.enqueueFollowUpAction({ type: followUpType, text: initialRequest });
|
|
5788
|
+
return null;
|
|
5868
5789
|
}
|
|
5869
5790
|
if (!this.agent && !this.rebuildAgent()) {
|
|
5870
5791
|
display.showWarning('Configure an API key via /secrets before sending requests.');
|
|
5871
|
-
return;
|
|
5792
|
+
return null;
|
|
5872
5793
|
}
|
|
5873
5794
|
this.inlinePanelScopeActive = false;
|
|
5874
5795
|
this.clearInlinePanel();
|
|
5875
5796
|
const agent = this.agent;
|
|
5876
5797
|
if (!agent) {
|
|
5877
|
-
return;
|
|
5798
|
+
return null;
|
|
5878
5799
|
}
|
|
5879
5800
|
this.toolsUsedThisRun = [];
|
|
5880
5801
|
this.currentToolCalls = [];
|
|
@@ -5885,200 +5806,41 @@ You have gathered context but did not provide a clear answer. Respond now with a
|
|
|
5885
5806
|
else {
|
|
5886
5807
|
this.resetNetworkRetryState();
|
|
5887
5808
|
}
|
|
5888
|
-
// Reset per-request render tracking
|
|
5889
5809
|
this.responseRendered = false;
|
|
5890
|
-
if (this.shouldLogPrompt(
|
|
5891
|
-
this.logUserPrompt(
|
|
5810
|
+
if (this.shouldLogPrompt(initialRequest)) {
|
|
5811
|
+
this.logUserPrompt(initialRequest);
|
|
5892
5812
|
}
|
|
5893
5813
|
this.isProcessing = true;
|
|
5894
5814
|
this.uiUpdates.setMode('processing');
|
|
5895
|
-
this.streamingTokenCount = 0;
|
|
5815
|
+
this.streamingTokenCount = 0;
|
|
5896
5816
|
this.terminalInput.setStreaming(true);
|
|
5897
|
-
// Keep the persistent input/control bar active as we transition into streaming.
|
|
5898
5817
|
this.syncRendererInput();
|
|
5899
5818
|
this.renderer?.render();
|
|
5900
|
-
const
|
|
5901
|
-
// Clear previous parallel agents and start fresh for new request
|
|
5819
|
+
const overallStartTime = Date.now();
|
|
5902
5820
|
const parallelManager = getParallelAgentManager();
|
|
5903
5821
|
parallelManager.clear();
|
|
5904
5822
|
parallelManager.startBatch();
|
|
5905
|
-
|
|
5906
|
-
this.
|
|
5907
|
-
this.currentTaskType = classifyTaskType(request);
|
|
5823
|
+
this.lastUserQuery = initialRequest;
|
|
5824
|
+
this.currentTaskType = classifyTaskType(initialRequest);
|
|
5908
5825
|
this.currentToolCalls = [];
|
|
5909
5826
|
this.clearToolUsageMeta();
|
|
5910
5827
|
this.renderer?.setActivity('Starting...');
|
|
5911
|
-
this.uiAdapter.startProcessing('Working on your request');
|
|
5828
|
+
this.uiAdapter.startProcessing(mode === 'continuous' ? 'Continuous execution mode' : 'Working on your request');
|
|
5912
5829
|
this.setProcessingStatus();
|
|
5913
5830
|
this.beginAiRuntime();
|
|
5914
|
-
|
|
5915
|
-
let autoFollowThrough = null;
|
|
5916
|
-
let informationalFollowUp = null;
|
|
5917
|
-
try {
|
|
5918
|
-
// Start streaming - no header needed, the input area already provides context
|
|
5919
|
-
this.startStreamingHeartbeat('Streaming response');
|
|
5920
|
-
responseText = await agent.send(request, true);
|
|
5921
|
-
this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
|
|
5922
|
-
await this.awaitPendingCleanup();
|
|
5923
|
-
this.captureHistorySnapshot();
|
|
5924
|
-
this.autosaveIfEnabled();
|
|
5925
|
-
// Track metrics with Alpha Zero 2
|
|
5926
|
-
const elapsedMs = Date.now() - requestStartTime;
|
|
5927
|
-
this.alphaZeroMetrics.recordMessage(elapsedMs);
|
|
5928
|
-
if (!responseText?.trim()) {
|
|
5929
|
-
display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
|
|
5930
|
-
}
|
|
5931
|
-
// AlphaZero: Extract and track tool calls from response
|
|
5932
|
-
const toolsUsed = this.getExecutedTools(responseText);
|
|
5933
|
-
this.currentToolCalls = toolsUsed.map(name => ({
|
|
5934
|
-
name,
|
|
5935
|
-
arguments: {},
|
|
5936
|
-
success: true, // Assume success if we got here
|
|
5937
|
-
duration: 0,
|
|
5938
|
-
}));
|
|
5939
|
-
autoFollowThrough = this.maybeAutoFollowThrough(request, responseText, toolsUsed);
|
|
5940
|
-
informationalFollowUp = this.maybeAutoAnswerInformational(request, responseText);
|
|
5941
|
-
// AlphaZero: Check for failure in response
|
|
5942
|
-
const failure = detectFailure(responseText, {
|
|
5943
|
-
toolCalls: this.currentToolCalls,
|
|
5944
|
-
userMessage: request,
|
|
5945
|
-
});
|
|
5946
|
-
if (failure) {
|
|
5947
|
-
this.lastFailure = failure;
|
|
5948
|
-
// Check if we have a recovery strategy
|
|
5949
|
-
const strategy = findRecoveryStrategy(failure);
|
|
5950
|
-
if (strategy) {
|
|
5951
|
-
display.showSystemMessage(`🔄 Found recovery strategy for this type of issue (success rate: ${Math.round(strategy.successRate * 100)}%)`);
|
|
5952
|
-
}
|
|
5953
|
-
}
|
|
5954
|
-
else {
|
|
5955
|
-
// Success - record the tool pattern for this task type
|
|
5956
|
-
if (this.currentToolCalls.length > 0) {
|
|
5957
|
-
const toolPattern = {
|
|
5958
|
-
taskType: this.currentTaskType,
|
|
5959
|
-
toolSequence: this.currentToolCalls.map(t => t.name),
|
|
5960
|
-
successRate: 1.0,
|
|
5961
|
-
avgDuration: elapsedMs,
|
|
5962
|
-
occurrences: 1,
|
|
5963
|
-
};
|
|
5964
|
-
addToolPattern(this.currentTaskType, toolPattern);
|
|
5965
|
-
}
|
|
5966
|
-
// Clear action history on success
|
|
5967
|
-
clearActionHistory();
|
|
5968
|
-
this.lastFailure = null;
|
|
5969
|
-
}
|
|
5970
|
-
}
|
|
5971
|
-
catch (error) {
|
|
5972
|
-
const handled = this.handleProviderError(error, () => this.processRequest(request));
|
|
5973
|
-
if (!handled) {
|
|
5974
|
-
// Pass full error object for enhanced formatting with stack trace
|
|
5975
|
-
display.showError(error instanceof Error ? error.message : String(error), error);
|
|
5976
|
-
}
|
|
5977
|
-
}
|
|
5978
|
-
finally {
|
|
5979
|
-
// Fallback: if no assistant message was rendered (e.g., streaming hiccup), show the full response
|
|
5980
|
-
if (!this.responseRendered && responseText.trim()) {
|
|
5981
|
-
const finalText = responseText.trim();
|
|
5982
|
-
display.showAssistantMessage(finalText, { isFinal: true });
|
|
5983
|
-
this.ui.controller.recordAssistantResponse(finalText, {
|
|
5984
|
-
source: 'final',
|
|
5985
|
-
});
|
|
5986
|
-
this.responseRendered = true;
|
|
5987
|
-
}
|
|
5988
|
-
this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
|
|
5989
|
-
display.stopThinking(false);
|
|
5990
|
-
this.uiUpdates.setMode('processing');
|
|
5991
|
-
this.stopStreamingHeartbeat('complete', { quiet: true });
|
|
5992
|
-
this.endAiRuntime();
|
|
5993
|
-
this.isProcessing = false;
|
|
5994
|
-
this.terminalInput.setStreaming(false);
|
|
5995
|
-
this.uiAdapter.endProcessing('Ready for prompts');
|
|
5996
|
-
this.updateToolUsageMeta(this.uiAdapter.getToolUsageSummary({ plain: true }));
|
|
5997
|
-
this.setIdleStatus();
|
|
5998
|
-
this.updateStatusMessage(null);
|
|
5999
|
-
if (autoFollowThrough) {
|
|
6000
|
-
display.showSystemMessage(`🔁 Auto-follow-through: ${autoFollowThrough.reason}`);
|
|
6001
|
-
this.enqueueFollowUpAction({ type: 'continuous', text: autoFollowThrough.prompt });
|
|
6002
|
-
}
|
|
6003
|
-
if (informationalFollowUp) {
|
|
6004
|
-
display.showSystemMessage(`🔁 Auto-follow-up: ${informationalFollowUp.reason}`);
|
|
6005
|
-
this.enqueueFollowUpAction({ type: 'request', text: informationalFollowUp.prompt });
|
|
6006
|
-
}
|
|
6007
|
-
this.toolsUsedThisRun = [];
|
|
6008
|
-
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
6009
|
-
// CRITICAL: Ensure readline prompt is active for user input
|
|
6010
|
-
// Erosolar-CLI style: New prompt naturally appears at bottom
|
|
6011
|
-
this.ensureReadlineReady();
|
|
6012
|
-
this.scheduleQueueProcessing();
|
|
6013
|
-
this.maybeProcessPromptInbox();
|
|
6014
|
-
this.refreshQueueIndicators();
|
|
6015
|
-
}
|
|
6016
|
-
}
|
|
6017
|
-
/**
|
|
6018
|
-
* Process a continuous/infinite loop request.
|
|
6019
|
-
* Runs the agent in a loop until:
|
|
6020
|
-
* 1. The agent indicates completion (verified by AI confirmation)
|
|
6021
|
-
* 2. User interrupts (Ctrl+C)
|
|
6022
|
-
* 3. Maximum iterations reached (safety limit)
|
|
6023
|
-
*
|
|
6024
|
-
* Uses intelligent task completion detection with AI verification
|
|
6025
|
-
* to ensure tasks are truly complete before stopping.
|
|
6026
|
-
*
|
|
6027
|
-
* Context is automatically managed - overflow errors trigger auto-recovery.
|
|
6028
|
-
*/
|
|
6029
|
-
async processContinuousRequest(initialRequest) {
|
|
6030
|
-
const MAX_ITERATIONS = 100; // Safety limit to prevent truly infinite loops
|
|
6031
|
-
if (this.isProcessing) {
|
|
6032
|
-
this.enqueueFollowUpAction({ type: 'continuous', text: initialRequest });
|
|
6033
|
-
return;
|
|
6034
|
-
}
|
|
6035
|
-
if (!this.agent && !this.rebuildAgent()) {
|
|
6036
|
-
display.showWarning('Configure an API key via /secrets before sending requests.');
|
|
6037
|
-
return;
|
|
6038
|
-
}
|
|
6039
|
-
this.inlinePanelScopeActive = false;
|
|
6040
|
-
this.clearInlinePanel();
|
|
6041
|
-
const agent = this.agent;
|
|
6042
|
-
if (!agent) {
|
|
6043
|
-
return;
|
|
6044
|
-
}
|
|
6045
|
-
this.toolsUsedThisRun = [];
|
|
6046
|
-
this.currentToolCalls = [];
|
|
6047
|
-
this.lastUserQuery = initialRequest;
|
|
6048
|
-
this.clearToolUsageMeta();
|
|
6049
|
-
this.isProcessing = true;
|
|
6050
|
-
this.uiUpdates.setMode('processing');
|
|
6051
|
-
this.streamingTokenCount = 0; // Reset token counter for new request
|
|
6052
|
-
this.terminalInput.setStreaming(true);
|
|
6053
|
-
if (this.suppressNextNetworkReset) {
|
|
6054
|
-
this.suppressNextNetworkReset = false;
|
|
6055
|
-
}
|
|
6056
|
-
else {
|
|
6057
|
-
this.resetNetworkRetryState();
|
|
6058
|
-
}
|
|
6059
|
-
const overallStartTime = Date.now();
|
|
6060
|
-
// Clear previous parallel agents and start fresh for continuous mode
|
|
6061
|
-
const parallelManager = getParallelAgentManager();
|
|
6062
|
-
parallelManager.clear();
|
|
6063
|
-
parallelManager.startBatch();
|
|
6064
|
-
// Initialize the task completion detector
|
|
5831
|
+
this.startStreamingHeartbeat(mode === 'continuous' ? 'Streaming' : 'Streaming response');
|
|
6065
5832
|
const completionDetector = getTaskCompletionDetector();
|
|
6066
5833
|
completionDetector.reset();
|
|
6067
|
-
// Display user prompt in scrollback (Claude Code style)
|
|
6068
|
-
this.logUserPrompt(initialRequest);
|
|
6069
|
-
display.showSystemMessage(`Continuous mode active. Ctrl+C to stop.`);
|
|
6070
|
-
this.uiAdapter.startProcessing('Continuous execution mode');
|
|
6071
|
-
this.setProcessingStatus();
|
|
6072
|
-
this.beginAiRuntime();
|
|
6073
|
-
// No streaming header - just start streaming directly
|
|
6074
|
-
this.startStreamingHeartbeat('Streaming');
|
|
6075
5834
|
this.flowOrchestrator.start(initialRequest);
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
5835
|
+
if (mode === 'continuous') {
|
|
5836
|
+
display.showSystemMessage('Continuous mode active. Ctrl+C to stop.');
|
|
5837
|
+
}
|
|
5838
|
+
else {
|
|
5839
|
+
display.showSystemMessage('Flow orchestrator engaged; running until the request is satisfied.');
|
|
5840
|
+
}
|
|
5841
|
+
let currentPrompt = initialRequest;
|
|
5842
|
+
if (this.isSelfImprovementRequest(initialRequest)) {
|
|
5843
|
+
currentPrompt = `${initialRequest}
|
|
6082
5844
|
|
|
6083
5845
|
IMPORTANT: You have full git access. After making improvements:
|
|
6084
5846
|
1. Use bash to run: git status (see changes)
|
|
@@ -6088,22 +5850,26 @@ IMPORTANT: You have full git access. After making improvements:
|
|
|
6088
5850
|
|
|
6089
5851
|
Commit frequently with descriptive messages. Push when ready.
|
|
6090
5852
|
When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
6091
|
-
|
|
6092
|
-
|
|
5853
|
+
}
|
|
5854
|
+
let iteration = 0;
|
|
5855
|
+
let lastResponseText = '';
|
|
5856
|
+
let lastToolsUsed = [];
|
|
5857
|
+
let result = null;
|
|
5858
|
+
try {
|
|
5859
|
+
while (iteration < maxIterations) {
|
|
6093
5860
|
iteration++;
|
|
6094
5861
|
this.toolsUsedThisRun = [];
|
|
6095
|
-
display.showSystemMessage(`\n📍 Iteration ${iteration}/${
|
|
5862
|
+
display.showSystemMessage(`\n📍 Iteration ${iteration}/${maxIterations}`);
|
|
6096
5863
|
this.updateStatusMessage(`Working on iteration ${iteration}...`);
|
|
6097
5864
|
try {
|
|
6098
|
-
// Send the request and capture the response (streaming disabled)
|
|
6099
5865
|
display.showThinking('Responding...');
|
|
6100
5866
|
this.refreshStatusLine(true);
|
|
6101
5867
|
const response = await agent.send(currentPrompt, true);
|
|
5868
|
+
lastResponseText = response ?? '';
|
|
6102
5869
|
this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
|
|
6103
5870
|
await this.awaitPendingCleanup();
|
|
6104
5871
|
this.captureHistorySnapshot();
|
|
6105
5872
|
this.autosaveIfEnabled();
|
|
6106
|
-
// Track metrics
|
|
6107
5873
|
const elapsedMs = Date.now() - overallStartTime;
|
|
6108
5874
|
this.alphaZeroMetrics.recordMessage(elapsedMs);
|
|
6109
5875
|
if (!response?.trim()) {
|
|
@@ -6113,10 +5879,9 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
|
6113
5879
|
The previous reply was empty. Resume the task now: take the next action, call the necessary tools, and report progress.`;
|
|
6114
5880
|
continue;
|
|
6115
5881
|
}
|
|
6116
|
-
// Extract tools used from the response (look for tool call patterns)
|
|
6117
5882
|
const toolsUsed = this.getExecutedTools(response);
|
|
5883
|
+
lastToolsUsed = toolsUsed;
|
|
6118
5884
|
toolsUsed.forEach(tool => completionDetector.recordToolCall(tool, true, true));
|
|
6119
|
-
// Use intelligent completion detection
|
|
6120
5885
|
const completionAnalysis = completionDetector.analyzeCompletion(response, toolsUsed);
|
|
6121
5886
|
display.showSystemMessage(`📈 Completion confidence: ${(completionAnalysis.confidence * 100).toFixed(0)}%`);
|
|
6122
5887
|
const decision = this.flowOrchestrator.decide({
|
|
@@ -6154,39 +5919,50 @@ The previous reply was empty. Resume the task now: take the next action, call th
|
|
|
6154
5919
|
}
|
|
6155
5920
|
currentPrompt = decision.prompt;
|
|
6156
5921
|
}
|
|
6157
|
-
// Small delay between iterations to prevent rate limiting
|
|
6158
5922
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
6159
5923
|
}
|
|
6160
5924
|
catch (error) {
|
|
6161
5925
|
display.stopThinking(false);
|
|
6162
|
-
// Handle context overflow specially - the agent should auto-recover
|
|
6163
|
-
// but if it propagates here, we continue the loop
|
|
6164
5926
|
if (this.isContextOverflowError(error)) {
|
|
6165
5927
|
display.showSystemMessage(`⚡ Context overflow handled. Continuing with reduced context...`);
|
|
6166
|
-
// The agent.ts should have already handled recovery
|
|
6167
|
-
// Continue to next iteration
|
|
6168
5928
|
continue;
|
|
6169
5929
|
}
|
|
6170
|
-
|
|
6171
|
-
const handled = this.handleProviderError(error, () => this.processContinuousRequest(initialRequest));
|
|
5930
|
+
const handled = this.handleProviderError(error, () => this.runFlowControlledTask(initialRequest, options));
|
|
6172
5931
|
if (!handled) {
|
|
6173
5932
|
display.showError(error instanceof Error ? error.message : String(error), error);
|
|
6174
5933
|
break;
|
|
6175
5934
|
}
|
|
6176
5935
|
}
|
|
6177
5936
|
}
|
|
6178
|
-
if (iteration >=
|
|
6179
|
-
display.showWarning(`\n⚠️ Reached maximum iterations (${
|
|
5937
|
+
if (iteration >= maxIterations) {
|
|
5938
|
+
display.showWarning(`\n⚠️ Reached maximum iterations (${maxIterations}). Stopping to prevent infinite loop.`);
|
|
5939
|
+
}
|
|
5940
|
+
if (!this.responseRendered && lastResponseText.trim()) {
|
|
5941
|
+
const finalText = lastResponseText.trim();
|
|
5942
|
+
display.showAssistantMessage(finalText, { isFinal: true });
|
|
5943
|
+
this.ui.controller.recordAssistantResponse(finalText, {
|
|
5944
|
+
source: 'final',
|
|
5945
|
+
});
|
|
5946
|
+
this.responseRendered = true;
|
|
6180
5947
|
}
|
|
5948
|
+
result = {
|
|
5949
|
+
finalResponse: lastResponseText,
|
|
5950
|
+
toolsUsed: lastToolsUsed,
|
|
5951
|
+
iterations: iteration,
|
|
5952
|
+
elapsedMs: Date.now() - overallStartTime,
|
|
5953
|
+
};
|
|
6181
5954
|
}
|
|
6182
5955
|
finally {
|
|
6183
5956
|
this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
|
|
6184
5957
|
const totalElapsed = Date.now() - overallStartTime;
|
|
6185
5958
|
const minutes = Math.floor(totalElapsed / 60000);
|
|
6186
5959
|
const seconds = Math.floor((totalElapsed % 60000) / 1000);
|
|
6187
|
-
|
|
6188
|
-
|
|
5960
|
+
const completionLabel = mode === 'continuous'
|
|
5961
|
+
? `\n🏁 Continuous execution completed: ${iteration} iterations, ${minutes}m ${seconds}s total`
|
|
5962
|
+
: `\n🏁 Task run completed: ${iteration} iterations, ${minutes}m ${seconds}s total`;
|
|
5963
|
+
display.showSystemMessage(completionLabel);
|
|
6189
5964
|
resetTaskCompletionDetector();
|
|
5965
|
+
display.stopThinking(false);
|
|
6190
5966
|
this.uiUpdates.setMode('processing');
|
|
6191
5967
|
this.stopStreamingHeartbeat('complete', { quiet: true });
|
|
6192
5968
|
this.endAiRuntime();
|
|
@@ -6198,13 +5974,76 @@ The previous reply was empty. Resume the task now: take the next action, call th
|
|
|
6198
5974
|
this.updateStatusMessage(null);
|
|
6199
5975
|
this.toolsUsedThisRun = [];
|
|
6200
5976
|
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
6201
|
-
// CRITICAL: Ensure readline prompt is active for user input
|
|
6202
|
-
// Erosolar-CLI style: New prompt naturally appears at bottom
|
|
6203
5977
|
this.ensureReadlineReady();
|
|
6204
5978
|
this.scheduleQueueProcessing();
|
|
6205
5979
|
this.maybeProcessPromptInbox();
|
|
6206
5980
|
this.refreshQueueIndicators();
|
|
6207
5981
|
}
|
|
5982
|
+
return result;
|
|
5983
|
+
}
|
|
5984
|
+
handleFlowRunOutcome(request, result) {
|
|
5985
|
+
this.currentToolCalls = result.toolsUsed.map((name) => ({
|
|
5986
|
+
name,
|
|
5987
|
+
arguments: {},
|
|
5988
|
+
success: true,
|
|
5989
|
+
duration: 0,
|
|
5990
|
+
}));
|
|
5991
|
+
const failure = detectFailure(result.finalResponse, {
|
|
5992
|
+
toolCalls: this.currentToolCalls,
|
|
5993
|
+
userMessage: request,
|
|
5994
|
+
});
|
|
5995
|
+
if (failure) {
|
|
5996
|
+
this.lastFailure = failure;
|
|
5997
|
+
const strategy = findRecoveryStrategy(failure);
|
|
5998
|
+
if (strategy) {
|
|
5999
|
+
display.showSystemMessage(`🔄 Found recovery strategy for this type of issue (success rate: ${Math.round(strategy.successRate * 100)}%)`);
|
|
6000
|
+
}
|
|
6001
|
+
return;
|
|
6002
|
+
}
|
|
6003
|
+
if (this.currentToolCalls.length > 0) {
|
|
6004
|
+
const toolPattern = {
|
|
6005
|
+
taskType: this.currentTaskType,
|
|
6006
|
+
toolSequence: this.currentToolCalls.map((t) => t.name),
|
|
6007
|
+
successRate: 1.0,
|
|
6008
|
+
avgDuration: result.elapsedMs,
|
|
6009
|
+
occurrences: 1,
|
|
6010
|
+
};
|
|
6011
|
+
addToolPattern(this.currentTaskType, toolPattern);
|
|
6012
|
+
}
|
|
6013
|
+
clearActionHistory();
|
|
6014
|
+
this.lastFailure = null;
|
|
6015
|
+
}
|
|
6016
|
+
async processRequest(request) {
|
|
6017
|
+
const result = await this.runFlowControlledTask(request, {
|
|
6018
|
+
maxIterations: 12,
|
|
6019
|
+
mode: 'standard',
|
|
6020
|
+
});
|
|
6021
|
+
if (!result) {
|
|
6022
|
+
return;
|
|
6023
|
+
}
|
|
6024
|
+
this.handleFlowRunOutcome(request, result);
|
|
6025
|
+
}
|
|
6026
|
+
/**
|
|
6027
|
+
* Process a continuous/infinite loop request.
|
|
6028
|
+
* Runs the agent in a loop until:
|
|
6029
|
+
* 1. The agent indicates completion (verified by AI confirmation)
|
|
6030
|
+
* 2. User interrupts (Ctrl+C)
|
|
6031
|
+
* 3. Maximum iterations reached (safety limit)
|
|
6032
|
+
*
|
|
6033
|
+
* Uses intelligent task completion detection with AI verification
|
|
6034
|
+
* to ensure tasks are truly complete before stopping.
|
|
6035
|
+
*
|
|
6036
|
+
* Context is automatically managed - overflow errors trigger auto-recovery.
|
|
6037
|
+
*/
|
|
6038
|
+
async processContinuousRequest(initialRequest) {
|
|
6039
|
+
const result = await this.runFlowControlledTask(initialRequest, {
|
|
6040
|
+
maxIterations: 100,
|
|
6041
|
+
mode: 'continuous',
|
|
6042
|
+
});
|
|
6043
|
+
if (!result) {
|
|
6044
|
+
return;
|
|
6045
|
+
}
|
|
6046
|
+
this.handleFlowRunOutcome(initialRequest, result);
|
|
6208
6047
|
}
|
|
6209
6048
|
/**
|
|
6210
6049
|
* Resolve executed tools for the current turn. Prefer the actual tool
|