neoagent 2.5.2-beta.7 → 2.5.2-beta.8

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.5.2-beta.7",
3
+ "version": "2.5.2-beta.8",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "server/index.js",
@@ -1 +1 @@
1
- c71ef84ad1471500295da6f6c6f13299
1
+ bb621393d8fc51c33384ab5b836db272
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19c
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "2830694115" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "2920927188" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -134794,7 +134794,7 @@ r===$&&A.b()
134794
134794
  p.push(A.jP(q,A.j9(!1,new A.a_(B.uG,A.d8(new A.cA(B.jt,new A.a7N(r,q),q),q,q),q),!1,B.H,!0),q,q,0,0,0,q))}r=!1
134795
134795
  if(!s.ay)if(!s.ch){r=s.e
134796
134796
  r===$&&A.b()
134797
- r=B.b.u("mqfoxi8l-ab0f828").length!==0&&r.b}if(r){r=s.d
134797
+ r=B.b.u("mqfpjvdl-88fa84f").length!==0&&r.b}if(r){r=s.d
134798
134798
  r===$&&A.b()
134799
134799
  r=r.aP&&!r.ai?84:0
134800
134800
  s=s.e
@@ -140506,7 +140506,7 @@ $S:0}
140506
140506
  A.a_6.prototype={}
140507
140507
  A.SQ.prototype={
140508
140508
  nb(a){var s=this
140509
- if(B.b.u("mqfoxi8l-ab0f828").length===0||s.a!=null)return
140509
+ if(B.b.u("mqfpjvdl-88fa84f").length===0||s.a!=null)return
140510
140510
  s.AU()
140511
140511
  s.a=A.on(B.RH,new A.bc8(s))},
140512
140512
  AU(){var s=0,r=A.l(t.H),q,p=2,o=[],n=this,m,l,k,j,i,h,g,f
@@ -140524,7 +140524,7 @@ if(!t.f.b(k)){s=1
140524
140524
  break}i=J.a3(k,"buildId")
140525
140525
  h=i==null?null:B.b.u(J.p(i))
140526
140526
  j=h==null?"":h
140527
- if(J.bi(j)===0||J.d(j,"mqfoxi8l-ab0f828")){s=1
140527
+ if(J.bi(j)===0||J.d(j,"mqfpjvdl-88fa84f")){s=1
140528
140528
  break}n.b=!0
140529
140529
  n.F()
140530
140530
  p=2
@@ -140541,7 +140541,7 @@ case 2:return A.i(o.at(-1),r)}})
140541
140541
  return A.k($async$AU,r)},
140542
140542
  vE(){var s=0,r=A.l(t.H),q,p=2,o=[],n=this,m,l,k,j,i,h,g,f,e,d,c,b,a,a0,a1
140543
140543
  var $async$vE=A.h(function(a2,a3){if(a2===1){o.push(a3)
140544
- s=p}for(;;)switch(s){case 0:if(B.b.u("mqfoxi8l-ab0f828").length===0||n.c){s=1
140544
+ s=p}for(;;)switch(s){case 0:if(B.b.u("mqfpjvdl-88fa84f").length===0||n.c){s=1
140545
140545
  break}n.c=!0
140546
140546
  n.F()
140547
140547
  p=4
@@ -192,6 +192,18 @@ function fingerprintOutput(toolName, result) {
192
192
  return h >>> 0;
193
193
  }
194
194
 
195
+ // Tools that represent concrete forward progress (write, create, send, update, run).
196
+ // Anything NOT in this set is considered read-only for the analysis-paralysis gate.
197
+ // execute_command counts as progress — it can do anything, including modify state.
198
+ function isProgressTool(toolName) {
199
+ if (!toolName) return false;
200
+ // Neutral / bookkeeping — don't count either way
201
+ if (toolName === 'activate_tools' || toolName === 'save_widget_snapshot') return false;
202
+ // Explicitly read-only patterns
203
+ if (/^(list_|search_|read_file|get_file|find_files?|github_list|github_get|github_search|browser_get|browser_read)/.test(toolName)) return false;
204
+ return true;
205
+ }
206
+
195
207
  function resolveModelCallTimeoutMs(options = {}) {
196
208
  const requested = Number(options?.modelCallTimeoutMs);
197
209
  if (Number.isFinite(requested) && requested > 0) {
@@ -2648,6 +2660,7 @@ class AgentEngine {
2648
2660
  toolPids: new Set(),
2649
2661
  repetitionGuard: new ToolRepetitionGuard(),
2650
2662
  seenOutputHashes: new Map(),
2663
+ consecutiveReadOnlyIterations: 0,
2651
2664
  messagingContext: triggerSource === 'messaging'
2652
2665
  ? {
2653
2666
  platform: options.source || null,
@@ -3036,13 +3049,6 @@ class AgentEngine {
3036
3049
  }
3037
3050
  messages = sanitizeConversationMessages(messages);
3038
3051
 
3039
- if (analysis.mode === 'execute' || analysis.mode === 'plan_execute') {
3040
- messages.push({
3041
- role: 'system',
3042
- content: 'Research budget: after 3 read/list/search tool calls, you must take a concrete action (write, create, send, update) or explain clearly why you cannot. Work on one item at a time — do not queue up more reads.',
3043
- });
3044
- }
3045
-
3046
3052
  directAnswerEligible = isDirectAnswerEligibleAnalysis(analysis)
3047
3053
  && Boolean(normalizeOutgoingMessage(analysis.draft_reply));
3048
3054
 
@@ -3074,6 +3080,21 @@ class AgentEngine {
3074
3080
  });
3075
3081
  messages = steeringAtLoopStart.messages;
3076
3082
  messages = sanitizeConversationMessages(messages);
3083
+
3084
+ // Analysis-paralysis gate: fire at the start of every iteration where
3085
+ // the agent has spent N turns only reading/listing/searching without
3086
+ // taking any concrete action. Escalates in urgency each turn.
3087
+ if (analysis.mode === 'execute' || analysis.mode === 'plan_execute') {
3088
+ const readOnlyCount = this.getRunMeta(runId)?.consecutiveReadOnlyIterations || 0;
3089
+ if (readOnlyCount >= 3) {
3090
+ const urgency = readOnlyCount >= 6 ? 'CRITICAL' : 'ACTION REQUIRED';
3091
+ messages.push({
3092
+ role: 'system',
3093
+ content: `${urgency} — ${readOnlyCount} consecutive read-only turns: You have been gathering information for ${readOnlyCount} turns without writing, creating, sending, or running anything. You must take ONE concrete action this turn (create a file, open a PR, run a command that modifies state, send a message) or call task_complete to report what you found and why you cannot proceed. Do not read or list anything further.`,
3094
+ });
3095
+ }
3096
+ }
3097
+
3077
3098
  this.updateRunProgress(runId, {
3078
3099
  currentPhase: 'model',
3079
3100
  currentStep: `model:${iteration}`,
@@ -3640,6 +3661,24 @@ class AgentEngine {
3640
3661
  });
3641
3662
  } else {
3642
3663
  currentRunMeta.seenOutputHashes.set(fp, { toolName, iteration });
3664
+ // External state: persist large read results to disk so the
3665
+ // model can reference them after context compaction without
3666
+ // re-fetching. Only for significant payloads.
3667
+ const persistRaw = typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult ?? '');
3668
+ if (persistRaw.length >= 1000 && runId) {
3669
+ const persistPath = `/tmp/run-${runId.slice(0, 8)}-${toolName}.json`;
3670
+ try {
3671
+ require('fs').writeFileSync(persistPath, persistRaw.slice(0, 40000));
3672
+ if (!currentRunMeta.persistedDataPaths) currentRunMeta.persistedDataPaths = [];
3673
+ if (!currentRunMeta.persistedDataPaths.includes(persistPath)) {
3674
+ currentRunMeta.persistedDataPaths.push(persistPath);
3675
+ messages.push({
3676
+ role: 'system',
3677
+ content: `Data from "${toolName}" (iteration ${iteration}) persisted to ${persistPath}. If context compacts and you need this data again, use execute_command with \`cat ${persistPath}\` instead of re-fetching.`,
3678
+ });
3679
+ }
3680
+ } catch { /* non-fatal — disk full or permissions */ }
3681
+ }
3643
3682
  }
3644
3683
  }
3645
3684
  }
@@ -3704,6 +3743,19 @@ class AgentEngine {
3704
3743
  }
3705
3744
  }
3706
3745
 
3746
+ // Update analysis-paralysis counter after each iteration's tool calls.
3747
+ // Resets to 0 when any progress tool was called; otherwise increments.
3748
+ if (!directAnswerEligible && response?.toolCalls?.length > 0
3749
+ && (analysis.mode === 'execute' || analysis.mode === 'plan_execute')) {
3750
+ const iterMeta = this.getRunMeta(runId);
3751
+ if (iterMeta) {
3752
+ const calledProgress = response.toolCalls.some((tc) => isProgressTool(tc.function?.name || ''));
3753
+ iterMeta.consecutiveReadOnlyIterations = calledProgress
3754
+ ? 0
3755
+ : (iterMeta.consecutiveReadOnlyIterations || 0) + 1;
3756
+ }
3757
+ }
3758
+
3707
3759
  if (this.isRunStopped(runId)) break;
3708
3760
  if (this.getRunMeta(runId)?.terminalInterim) break;
3709
3761
  if (this.getRunMeta(runId)?.widgetSnapshotSaved) break;