neoagent 2.1.18-beta.40 → 2.1.18-beta.41

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.1.18-beta.40",
3
+ "version": "2.1.18-beta.41",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "MIT",
6
6
  "main": "server/index.js",
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"425cfb54d01a9472b3e81d9e76fd63a4a44cfb
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "893563102" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "3254712906" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -347,8 +347,6 @@ function buildModelFailureLoopPrompt({ failedModel, nextModel, errorMessage }) {
347
347
  ].join(' ');
348
348
  }
349
349
 
350
- const MAX_AUTONOMOUS_MESSAGING_RETRIES = 2;
351
-
352
350
  function clampRunContext(text, maxChars) {
353
351
  const value = normalizeOutgoingMessage(text);
354
352
  if (!value) return '';
@@ -511,6 +509,55 @@ function summarizeAvailableTools(tools = [], { exclude = [] } = {}) {
511
509
  .join(', ');
512
510
  }
513
511
 
512
+ function inferToolFailureMessage(toolName, result) {
513
+ const explicitError = normalizeOutgoingMessage(result?.error || '');
514
+ if (explicitError) return explicitError;
515
+
516
+ if (!result || typeof result !== 'object') return '';
517
+
518
+ if (toolName === 'execute_command') {
519
+ if (result.timedOut) {
520
+ return `Command timed out after ${result.durationMs || 'unknown'} ms`;
521
+ }
522
+ if (result.killed) {
523
+ return 'Command was killed before it finished';
524
+ }
525
+ if (typeof result.exitCode === 'number' && result.exitCode !== 0) {
526
+ return summarizeForLog(result.stderr || result.stdout || `Command exited with code ${result.exitCode}`, 220);
527
+ }
528
+ }
529
+
530
+ if (toolName === 'http_request' && typeof result.status === 'number' && result.status >= 400) {
531
+ const bodySnippet = normalizeOutgoingMessage(result.body || '');
532
+ return summarizeForLog(
533
+ bodySnippet
534
+ ? `HTTP request returned status ${result.status}: ${bodySnippet}`
535
+ : `HTTP request returned status ${result.status}`,
536
+ 240
537
+ );
538
+ }
539
+
540
+ return '';
541
+ }
542
+
543
+ function buildAutonomousRecoveryContext({ err, toolExecutions = [], tools = [], userMessage, messagingSent = false }) {
544
+ const lastFailure = [...toolExecutions].reverse().find((item) => !item.ok);
545
+ const alternativeTools = summarizeAvailableTools(tools, { exclude: lastFailure?.toolName || null });
546
+ const parts = [
547
+ 'This is an internal recovery retry for the same user task. Continue the task instead of stopping.',
548
+ userMessage ? `Original task: ${clampRunContext(userMessage, 260)}` : '',
549
+ lastFailure?.toolName ? `Previous attempt failed on tool: ${lastFailure.toolName}.` : '',
550
+ lastFailure?.error ? `Concrete failure: ${summarizeForLog(lastFailure.error, 260)}.` : '',
551
+ err?.message ? `Run-level error after that failure: ${summarizeForLog(err.message, 220)}.` : '',
552
+ 'Do not send a blocker message just because one tool path failed.',
553
+ 'Use a different safe approach if available: alternate tool, different query, browser path, HTTP fetch, file/code inspection, or command verification.',
554
+ messagingSent ? 'A user-facing message was already sent in a previous internal attempt. Continue silently unless you have a materially new finished result or a real external blocker.' : '',
555
+ alternativeTools ? `Other available tools in this run: ${alternativeTools}.` : '',
556
+ 'Only stop if the remaining problem truly requires an external dependency or user action outside this run.'
557
+ ];
558
+ return parts.filter(Boolean).join(' ');
559
+ }
560
+
514
561
  class AgentEngine {
515
562
  constructor(io, services = {}) {
516
563
  this.io = io;
@@ -1092,7 +1139,7 @@ class AgentEngine {
1092
1139
  }
1093
1140
 
1094
1141
  getMessagingRetryLimit(maxIterations) {
1095
- return Math.max(1, Math.min(MAX_AUTONOMOUS_MESSAGING_RETRIES, maxIterations));
1142
+ return Math.max(1, maxIterations);
1096
1143
  }
1097
1144
 
1098
1145
  buildContextMessages(systemPrompt, summaryMessage, historyMessages, recallMsg) {
@@ -1705,14 +1752,25 @@ class AgentEngine {
1705
1752
  allowExternalSideEffects: options.allowExternalSideEffects === true,
1706
1753
  });
1707
1754
  this.detachProcessFromRun(runId, toolResult?.pid);
1755
+ toolErrorMessage = inferToolFailureMessage(toolName, toolResult);
1756
+ if (toolErrorMessage) {
1757
+ failedStepCount++;
1758
+ }
1708
1759
  const screenshotPath = toolResult?.screenshotPath || null;
1709
- const stepStatus = this.isRunStopped(runId) ? 'stopped' : 'completed';
1710
- db.prepare('UPDATE agent_steps SET status = ?, result = ?, screenshot_path = ?, completed_at = datetime(\'now\') WHERE id = ?')
1711
- .run(stepStatus, JSON.stringify(toolResult).slice(0, 20000), screenshotPath, stepId);
1712
- this.emit(userId, 'run:tool_end', { runId, stepId, toolName, result: toolResult, screenshotPath, status: stepStatus });
1713
- console.info(
1714
- `[Run ${shortenRunId(runId)}] step=${stepIndex} done tool=${toolName} status=${stepStatus} durationMs=${Date.now() - stepStartedAt} result=${summarizeForLog(toolResult)}`
1715
- );
1760
+ const stepStatus = this.isRunStopped(runId) ? 'stopped' : (toolErrorMessage ? 'failed' : 'completed');
1761
+ db.prepare('UPDATE agent_steps SET status = ?, result = ?, error = ?, screenshot_path = ?, completed_at = datetime(\'now\') WHERE id = ?')
1762
+ .run(stepStatus, JSON.stringify(toolResult).slice(0, 20000), toolErrorMessage || null, screenshotPath, stepId);
1763
+ if (toolErrorMessage) {
1764
+ this.emit(userId, 'run:tool_end', { runId, stepId, toolName, error: toolErrorMessage, result: toolResult, screenshotPath, status: stepStatus });
1765
+ console.warn(
1766
+ `[Run ${shortenRunId(runId)}] step=${stepIndex} failed tool=${toolName} durationMs=${Date.now() - stepStartedAt} error=${summarizeForLog(toolErrorMessage, 160)}`
1767
+ );
1768
+ } else {
1769
+ this.emit(userId, 'run:tool_end', { runId, stepId, toolName, result: toolResult, screenshotPath, status: stepStatus });
1770
+ console.info(
1771
+ `[Run ${shortenRunId(runId)}] step=${stepIndex} done tool=${toolName} status=${stepStatus} durationMs=${Date.now() - stepStartedAt} result=${summarizeForLog(toolResult)}`
1772
+ );
1773
+ }
1716
1774
  } catch (err) {
1717
1775
  toolResult = { error: err.message };
1718
1776
  toolErrorMessage = String(err.message || 'Tool execution failed');
@@ -1766,9 +1824,6 @@ class AgentEngine {
1766
1824
 
1767
1825
  if (
1768
1826
  toolName === 'execute_command'
1769
- && !toolErrorMessage
1770
- && !toolResult?.timedOut
1771
- && !toolResult?.killed
1772
1827
  && toolResult?.exitCode !== undefined
1773
1828
  && toolResult.exitCode !== 0
1774
1829
  ) {
@@ -2015,11 +2070,17 @@ class AgentEngine {
2015
2070
  triggerSource === 'messaging'
2016
2071
  && options.source
2017
2072
  && options.chatId
2018
- && !runMeta?.messagingSent
2019
2073
  && retryCount < this.getMessagingRetryLimit(maxIterations)
2020
2074
  );
2021
2075
 
2022
2076
  if (canRetryMessagingRun) {
2077
+ const recoveryContext = buildAutonomousRecoveryContext({
2078
+ err,
2079
+ toolExecutions,
2080
+ tools,
2081
+ userMessage,
2082
+ messagingSent: runMeta?.messagingSent === true,
2083
+ });
2023
2084
  db.prepare('UPDATE agent_runs SET status = ?, error = ?, updated_at = datetime(\'now\') WHERE id = ?')
2024
2085
  .run('retrying', err.message, runId);
2025
2086
  console.warn(
@@ -2035,7 +2096,14 @@ class AgentEngine {
2035
2096
 
2036
2097
  const retryOptions = {
2037
2098
  ...options,
2038
- messagingAutonomousRetryCount: retryCount + 1
2099
+ messagingAutonomousRetryCount: retryCount + 1,
2100
+ context: {
2101
+ ...(options.context || {}),
2102
+ additionalContext: [
2103
+ options.context?.additionalContext || '',
2104
+ recoveryContext,
2105
+ ].filter(Boolean).join('\n\n')
2106
+ }
2039
2107
  };
2040
2108
  delete retryOptions.runId;
2041
2109