neoagent 2.5.2-beta.21 → 2.5.2-beta.22

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.21",
3
+ "version": "2.5.2-beta.22",
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
- 5990cad8eaec79b0d23482e43d4c38de
1
+ 7b68be842f70ebca5228682c4fe3dc90
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19c
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "2751675703" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "1027370389" /* 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("mqgr61zr-76de6f0").length!==0&&r.b}if(r){r=s.d
134797
+ r=B.b.u("mqgt278r-971ca3d").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("mqgr61zr-76de6f0").length===0||s.a!=null)return
140509
+ if(B.b.u("mqgt278r-971ca3d").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,"mqgr61zr-76de6f0")){s=1
140527
+ if(J.bi(j)===0||J.d(j,"mqgt278r-971ca3d")){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("mqgr61zr-76de6f0").length===0||n.c){s=1
140544
+ s=p}for(;;)switch(s){case 0:if(B.b.u("mqgt278r-971ca3d").length===0||n.c){s=1
140545
140545
  break}n.c=!0
140546
140546
  n.F()
140547
140547
  p=4
@@ -248,6 +248,33 @@ function fingerprintOutput(toolName, result, toolArgs = {}) {
248
248
  return h >>> 0;
249
249
  }
250
250
 
251
+ // Concise list of files/targets the run has already read or searched, so the
252
+ // analysis-paralysis nudge can name them and tell the model not to re-read them.
253
+ function summarizeReadTargets(toolExecutions = []) {
254
+ const targets = [];
255
+ const seen = new Set();
256
+ for (const item of toolExecutions) {
257
+ if (!item || item.stateChanged) continue; // only read-only steps
258
+ const input = item.input || {};
259
+ let target = '';
260
+ if (typeof input.path === 'string' && input.path.trim()) {
261
+ target = input.path.trim();
262
+ } else if (typeof input.command === 'string') {
263
+ const files = input.command.match(/[\w./-]+\.(?:js|ts|tsx|jsx|py|dart|json|md|kt|c|h|ya?ml|sql|txt|sh)\b/g);
264
+ if (files && files.length) target = [...new Set(files)].slice(0, 2).join(', ');
265
+ } else if (typeof input.query === 'string' && input.query.trim()) {
266
+ target = `search:${input.query.trim().slice(0, 30)}`;
267
+ }
268
+ if (!target) continue;
269
+ const key = target.toLowerCase();
270
+ if (seen.has(key)) continue;
271
+ seen.add(key);
272
+ targets.push(target);
273
+ if (targets.length >= 8) break;
274
+ }
275
+ return targets.join('; ');
276
+ }
277
+
251
278
  function cloneInterimHistory(history = []) {
252
279
  if (!Array.isArray(history)) return [];
253
280
  return history.map((item) => ({
@@ -789,10 +816,10 @@ async function runConversation(engine, userId, userMessage, options = {}, _model
789
816
  try {
790
817
  const rm = engine.getRunMeta(runId);
791
818
  const ledger = rm?.progressLedger || {};
792
- const recent = toolExecutions.slice(-5).map((item) => {
793
- const name = item.toolName || item.tool || 'step';
794
- return `- ${name}${item.ok === false ? ' (failed)' : ''}`;
795
- }).join('\n') || '(no tool activity yet)';
819
+ // Real, specific evidence (actual commands + their output) so the update is
820
+ // grounded in what happened, not invented. Bare tool names make a weak model
821
+ // confabulate generic activity ("running the build", "training").
822
+ const recent = summarizeToolExecutions(toolExecutions, 5) || '(no tool activity yet)';
796
823
  const priorUpdate = String(rm?.lastInterimMessage || '').trim();
797
824
  const contextBlock = [
798
825
  buildProgressUpdatePrompt(),
@@ -800,7 +827,7 @@ async function runConversation(engine, userId, userMessage, options = {}, _model
800
827
  '',
801
828
  `Original request: ${summarizeForLog(userMessage, 320)}`,
802
829
  `Doing now: ${ledger.currentTool ? `using ${ledger.currentTool}` : (ledger.currentPhase || 'thinking')}`,
803
- `Recent steps:\n${recent}`,
830
+ `Actual recent tool activity (newest last) — describe ONLY this, do not extrapolate:\n${recent}`,
804
831
  priorUpdate ? `Your previous update (say something different): ${summarizeForLog(priorUpdate, 160)}` : '',
805
832
  ].filter(Boolean).join('\n');
806
833
  // Reuse the run's real system prompt so the update follows the same voice and
@@ -1125,9 +1152,17 @@ async function runConversation(engine, userId, userMessage, options = {}, _model
1125
1152
  const readOnlyCount = engine.getRunMeta(runId)?.consecutiveReadOnlyIterations || 0;
1126
1153
  if (readOnlyCount >= 3) {
1127
1154
  const urgency = readOnlyCount >= 6 ? 'CRITICAL' : 'ACTION REQUIRED';
1155
+ const alreadyRead = summarizeReadTargets(toolExecutions);
1128
1156
  messages.push({
1129
1157
  role: 'system',
1130
- content: `${urgency} — ${readOnlyCount} consecutive read-only turns: You have been gathering information for ${readOnlyCount} turns without implementation progress such as writing, editing, creating a branch, running verification, or delivering a final/blocker. Switch method now: establish or reuse a writable checkout, create a task branch, edit files, run verification, open/update a PR, or call task_complete with the real blocker. If the user has been waiting, send one concise interim update, but that does not satisfy the method switch. Do not do more remote tree/list/content scraping first. Do not assume tool results exist at /tmp paths unless a tool explicitly returned that readable path.`,
1158
+ content: [
1159
+ `${urgency} — ${readOnlyCount} consecutive read-only turns with no concrete action.`,
1160
+ alreadyRead
1161
+ ? `You have ALREADY read/searched: ${alreadyRead}. Their output is in this conversation above — do not read or search them again; re-reading what you already have is the main way runs stall.`
1162
+ : 'Do not re-read or re-search anything already in this conversation.',
1163
+ 'Act on what you already know now: edit files, run a state-changing command, create the branch/PR, or send the result.',
1164
+ 'If you genuinely cannot proceed, call task_complete with your best answer or a concrete blocker. Deciding to finish is a valid action; continuing to gather is not.',
1165
+ ].join(' '),
1131
1166
  });
1132
1167
  }
1133
1168
  }
@@ -24,7 +24,9 @@ const UNLIMITED_ITERATIONS = 1_000_000;
24
24
  const DEFAULT_MAX_ITERATIONS = UNLIMITED_ITERATIONS;
25
25
  const DEFAULT_WIDGET_MAX_ITERATIONS = UNLIMITED_ITERATIONS;
26
26
  const DEFAULT_PLAN_EXECUTE_MAX_ITERATIONS = UNLIMITED_ITERATIONS;
27
- const DEFAULT_COMPACTION_THRESHOLD = 0.60;
27
+ // Less aggressive than 0.60 so the model retains file contents it already read for
28
+ // longer, instead of losing them to compaction and re-reading the same files.
29
+ const DEFAULT_COMPACTION_THRESHOLD = 0.80;
28
30
  const DEFAULT_MAX_CONSECUTIVE_TOOL_FAILURES = 5;
29
31
  const DEFAULT_MAX_MODEL_FAILURE_RECOVERIES = 3;
30
32
 
@@ -55,7 +55,8 @@ function buildProgressUpdatePrompt() {
55
55
  // formatting guidelines as every other message and stays maintainable in one place.
56
56
  return [
57
57
  'You are mid-task and working autonomously while the user waits.',
58
- 'Send ONE brief progress ping saying what you are doing right now, based on the recent activity below.',
58
+ 'Send ONE brief progress ping saying what you are doing right now, grounded ONLY in the actual recent tool activity below.',
59
+ 'Describe what the evidence literally shows (e.g. reading files, searching the repo, cloning, editing). Do NOT invent or guess steps, and never mention builds, compiling, gradle, tests, training, models, evaluation, pipelines, batch jobs, or deployments unless they actually appear in the activity.',
59
60
  'This is not the final answer: do not claim the task is done and do not summarize results.',
60
61
  'No greeting, no question, no sign-off; vary the wording from your previous update.',
61
62
  'Follow your normal voice and formatting rules. Output only the message text.',