neoagent 2.5.2-beta.21 → 2.5.2-beta.23

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.23",
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
+ d276dee2ae356c64a3cfa6047a3a1bd1
@@ -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: "82494360" /* 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("mqgu5j85-f9cebb0").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("mqgu5j85-f9cebb0").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,"mqgu5j85-f9cebb0")){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("mqgu5j85-f9cebb0").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
  }
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const FIRST_UPDATE_MS = 35 * 1000;
3
+ const FIRST_UPDATE_MS = 30 * 1000;
4
4
  const REPEAT_UPDATE_MS = 75 * 1000;
5
5
  const STALL_MS = 150 * 1000;
6
6
  const TICK_MS = 15 * 1000;
@@ -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.',
@@ -45,6 +45,7 @@ const PLAN_SCHEMA_EXAMPLE = {
45
45
  const ANALYSIS_PROMPT_INSTRUCTIONS = [
46
46
  'Choose the lightest routing mode that still handles the task well.',
47
47
  'Use mode="direct_answer" only when a final user-facing reply can be given immediately without tool work.',
48
+ 'For short immediate questions, greetings, small explanations, or quick conversational replies, prefer mode="direct_answer" with progress_update_policy="none"; speed matters more than creating plans or tasks.',
48
49
  'Use mode="execute" for normal tool-driven work without a separate planning step.',
49
50
  'Use mode="plan_execute" only when the task is genuinely multi-step, broad, or coordination-heavy.',
50
51
  'Set needs_verification=true when the final answer should be checked against tool evidence before it is sent.',
@@ -54,6 +55,7 @@ const ANALYSIS_PROMPT_INSTRUCTIONS = [
54
55
  'Set complexity from the actual work shape, not from keywords: simple, standard, or complex.',
55
56
  'Set autonomy_level="high" when the agent should decide sequencing, retries, evidence gathering, and verification without asking the user unless blocked.',
56
57
  'Set progress_update_policy="required" for long, slow, voice, messaging, or externally visible work where silence would be confusing.',
58
+ 'Do not suggest create_task, update_task, delete_task, or list_tasks for ordinary immediate work. Use task tools only when the user asks for future, recurring, scheduled, monitored, background, or existing-task management behavior.',
57
59
  'Set parallel_work=true when independent tool calls or subagents can materially reduce latency.',
58
60
  'Set completion_confidence_required="high" when wrong completion would be costly, state-changing, user-visible, or hard to recover.',
59
61
  ];
@@ -85,6 +87,7 @@ const EXECUTION_GUIDANCE_ACTION_LINES = [
85
87
  'Your shell (execute_command) starts in your workspace, and the file tools (read_file, write_file, list_directory, search_files) operate on that same workspace. Clone or create files into the current directory and then inspect or edit them with either the shell or the file tools interchangeably. Clone a repo once and reuse it; do not re-clone or re-list the same tree.',
86
88
  'Tool results are already present in the conversation as tool output. Do not assume a tool result was persisted to a readable /tmp path unless that exact path was explicitly returned by the tool result.',
87
89
  'Use send_interim_update sparingly when a short real update or question would help.',
90
+ 'Do not create background tasks for immediate short work. Answer directly unless the user asked to schedule, repeat, monitor, defer, or manage a saved task.',
88
91
  'When you must ask for missing required user input, ask once, then wait for the reply instead of re-asking in the same run.',
89
92
  'For outbound messages, calls, emails, shared edits, installs, restarts, or task mutations, verify the action result before claiming it happened. If user confirmation is required and missing, draft or ask instead of sending.',
90
93
  'Retry with alternative tools or approaches when one path fails. If evidence is still insufficient, say so explicitly instead of guessing.',
@@ -1144,7 +1144,7 @@ function getAvailableTools(app, options = {}) {
1144
1144
  },
1145
1145
  {
1146
1146
  name: 'create_task',
1147
- description: 'Create a background task with a named trigger and self-contained prompt.',
1147
+ description: 'Create a future, recurring, monitored, or background automation with a named trigger and self-contained prompt. Do not use for immediate short answers.',
1148
1148
  parameters: {
1149
1149
  type: 'object',
1150
1150
  properties: {
@@ -1163,12 +1163,12 @@ function getAvailableTools(app, options = {}) {
1163
1163
  },
1164
1164
  {
1165
1165
  name: 'list_tasks',
1166
- description: 'List all tasks for this user and agent.',
1166
+ description: 'List saved background/scheduled tasks for this user and agent. Do not use for ordinary immediate replies.',
1167
1167
  parameters: { type: 'object', properties: {} }
1168
1168
  },
1169
1169
  {
1170
1170
  name: 'delete_task',
1171
- description: 'Delete a task by its ID.',
1171
+ description: 'Delete a saved background/scheduled task by its ID.',
1172
1172
  parameters: {
1173
1173
  type: 'object',
1174
1174
  properties: {
@@ -1179,7 +1179,7 @@ function getAvailableTools(app, options = {}) {
1179
1179
  },
1180
1180
  {
1181
1181
  name: 'update_task',
1182
- description: 'Update an existing task, including its trigger, prompt, or enabled state.',
1182
+ description: 'Update an existing saved background/scheduled task, including its trigger, prompt, or enabled state.',
1183
1183
  parameters: {
1184
1184
  type: 'object',
1185
1185
  properties: {