neoagent 3.0.1-beta.1 → 3.0.1-beta.3

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": "3.0.1-beta.1",
3
+ "version": "3.0.1-beta.3",
4
4
  "description": "Self-hosted AI agent for long-running tasks, automation, messaging, device control, and local memory",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "server/index.js",
@@ -1 +1 @@
1
- ac4b974e68fa4b1a3241e794eb2a4ff9
1
+ 498b1aaa642bdbb1ac88a1a679f3d456
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19c
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "4045856802" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "2616548470" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -134819,7 +134819,7 @@ r===$&&A.b()
134819
134819
  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
134820
134820
  if(!s.ay)if(!s.ch){r=s.e
134821
134821
  r===$&&A.b()
134822
- r=B.b.u("mqh8922l-d59d25a").length!==0&&r.b}if(r){r=s.d
134822
+ r=B.b.u("mqhrubbx-567212e").length!==0&&r.b}if(r){r=s.d
134823
134823
  r===$&&A.b()
134824
134824
  r=r.aP&&!r.ai?84:0
134825
134825
  s=s.e
@@ -140540,7 +140540,7 @@ $S:0}
140540
140540
  A.a_6.prototype={}
140541
140541
  A.SQ.prototype={
140542
140542
  nb(a){var s=this
140543
- if(B.b.u("mqh8922l-d59d25a").length===0||s.a!=null)return
140543
+ if(B.b.u("mqhrubbx-567212e").length===0||s.a!=null)return
140544
140544
  s.AU()
140545
140545
  s.a=A.on(B.RI,new A.bc9(s))},
140546
140546
  AU(){var s=0,r=A.l(t.H),q,p=2,o=[],n=this,m,l,k,j,i,h,g,f
@@ -140558,7 +140558,7 @@ if(!t.f.b(k)){s=1
140558
140558
  break}i=J.a3(k,"buildId")
140559
140559
  h=i==null?null:B.b.u(J.p(i))
140560
140560
  j=h==null?"":h
140561
- if(J.bi(j)===0||J.d(j,"mqh8922l-d59d25a")){s=1
140561
+ if(J.bi(j)===0||J.d(j,"mqhrubbx-567212e")){s=1
140562
140562
  break}n.b=!0
140563
140563
  n.E()
140564
140564
  p=2
@@ -140575,7 +140575,7 @@ case 2:return A.i(o.at(-1),r)}})
140575
140575
  return A.k($async$AU,r)},
140576
140576
  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
140577
140577
  var $async$vE=A.h(function(a2,a3){if(a2===1){o.push(a3)
140578
- s=p}for(;;)switch(s){case 0:if(B.b.u("mqh8922l-d59d25a").length===0||n.c){s=1
140578
+ s=p}for(;;)switch(s){case 0:if(B.b.u("mqhrubbx-567212e").length===0||n.c){s=1
140579
140579
  break}n.c=!0
140580
140580
  n.E()
140581
140581
  p=4
@@ -202,12 +202,13 @@ function buildCompletionDecisionPrompt({
202
202
  'Schema: {"status":"continue|complete|blocked","reason":"short concrete reason"}',
203
203
  'Rules:',
204
204
  '- Use "continue" whenever any safe next step remains in this same run.',
205
- '- Use "complete" only when the requested outcome is actually achieved and the latest draft is the finished user-facing answer.',
206
- '- Use "blocked" only when a specific external dependency, missing user input, or permission outside this run is required and the latest draft is the blocker reply.',
205
+ '- Use "complete" when the requested outcome is achieved, already done, or a no-op because there is nothing matching the request to change, and the latest draft is the finished user-facing answer.',
206
+ '- Use "blocked" when a specific external dependency, missing user input, permission outside this run, or unavailable required capability makes the task impossible in this run and the latest draft is the blocker reply.',
207
207
  '- If the latest draft asks the user for a missing required value, confirmation, or choice needed to proceed, use "blocked" so the run waits instead of repeating the same ask.',
208
208
  '- A progress note, next-step note, apology, plan, or promise to investigate is "continue", not "complete".',
209
209
  '- A single failed tool attempt is not blocked if another safe retry, verification step, or alternative path remains.',
210
210
  '- A tool-specific API error, timeout, rate limit, or missing result inside this run is usually "continue", not "blocked", if any other available tool could still make progress.',
211
+ '- Repeated read-only inspection that has already established the relevant object is absent or unchanged is not progress. Accept a concise complete/blocker reply instead of requiring more searching.',
211
212
  `- If completion_confidence_required is ${goalContext.effectiveCompletionConfidence} and the latest draft depends on unverified assumptions, use "continue" so the run can gather evidence, inspect state, or narrow the reply.`,
212
213
  triggerSource === 'messaging' && messagingSent
213
214
  ? '- A final reply was already delivered via send_message. Use "complete" unless concrete task work remains.'
@@ -125,6 +125,7 @@ const {
125
125
  isReadOnlyToolCall: isReadOnlyToolCallImpl,
126
126
  } = require('./tool_dispatch');
127
127
  const {
128
+ buildReadOnlyChurnGuidance,
128
129
  isProgressToolCall,
129
130
  } = require('./progress_classification');
130
131
  const {
@@ -1174,19 +1175,10 @@ async function runConversation(engine, userId, userMessage, options = {}, _model
1174
1175
  if (analysis.mode === 'execute' || analysis.mode === 'plan_execute') {
1175
1176
  const readOnlyCount = engine.getRunMeta(runId)?.consecutiveReadOnlyIterations || 0;
1176
1177
  if (readOnlyCount >= 3) {
1177
- const urgency = readOnlyCount >= 6 ? 'CRITICAL' : 'ACTION REQUIRED';
1178
1178
  const alreadyRead = summarizeReadTargets(toolExecutions);
1179
1179
  messages.push({
1180
1180
  role: 'system',
1181
- content: [
1182
- `${urgency} — ${readOnlyCount} consecutive read-only turns with no concrete action.`,
1183
- alreadyRead
1184
- ? `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.`
1185
- : 'Do not re-read or re-search anything already in this conversation.',
1186
- 'If you are repeatedly extracting evidence through low-level commands, switch to the available file/search/edit tools over the shared workspace.',
1187
- 'Act on what you already know now: edit files, run a state-changing command, create the branch/PR, or send the result.',
1188
- '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.',
1189
- ].join(' '),
1181
+ content: buildReadOnlyChurnGuidance({ readOnlyCount, alreadyRead }),
1190
1182
  });
1191
1183
  }
1192
1184
  }
@@ -172,7 +172,22 @@ function isProgressToolCall(toolName, toolArgs = {}) {
172
172
  return true;
173
173
  }
174
174
 
175
+ function buildReadOnlyChurnGuidance({ readOnlyCount = 0, alreadyRead = '' } = {}) {
176
+ const count = Math.max(0, Number(readOnlyCount) || 0);
177
+ const urgency = count >= 6 ? 'CRITICAL' : 'ACTION REQUIRED';
178
+ return [
179
+ `${urgency}: ${count} consecutive read-only turns with no concrete action.`,
180
+ alreadyRead
181
+ ? `You have already read/searched: ${alreadyRead}. Their output is in this conversation above, so do not read or search them again.`
182
+ : 'Do not re-read or re-search anything already in this conversation.',
183
+ 'Decide from the evidence you have now.',
184
+ 'If the requested work is already done, no matching target exists, or the available tools cannot make the change, call task_complete with that truthful final answer or blocker.',
185
+ 'If exactly one concrete safe action remains, take that action now. Otherwise finish; more poking around is not progress.',
186
+ ].join(' ');
187
+ }
188
+
175
189
  module.exports = {
190
+ buildReadOnlyChurnGuidance,
176
191
  isClearlyReadOnlyShellCommand,
177
192
  isProgressToolCall,
178
193
  };
@@ -125,6 +125,7 @@ Use specific identifiers. If a tool distinguishes message IDs, draft IDs, attach
125
125
  If the user asks a broad personal-information question such as "what are my todos?", "what did I miss?", or "find everything about X", search across the relevant available private sources in parallel when possible: memory/session context, official integrations, files, email/calendar tools, and MCP tools.
126
126
  For coding or system debugging, inspect the code/configuration first, then form a hypothesis. Do not overfit to a single log line if code or environment evidence suggests another path.
127
127
  For long tasks, give brief progress only when the user is waiting or the operation is slow. Avoid announcing every internal step.
128
+ When evidence shows the requested work is already done, there is no matching target to change, the available tools cannot perform the required action, or the task now needs outside input, stop cleanly with that result. A truthful no-op, not-found result, or concrete blocker is a valid finish; do not keep searching just to look busy.
128
129
 
129
130
  COMPLEX TASKS
130
131
  For anything multi-step or open-ended, plan before you sprint. Break the goal into concrete steps and, for a real job, keep a running checklist (a task or a working file) that tracks done versus pending so nothing quietly falls off the list.
@@ -185,13 +186,13 @@ Prefer direct file reads and targeted commands over broad log-grep rituals. For
185
186
 
186
187
  ERROR RECOVERY
187
188
  When a tool call or command fails, first check whether the failure came from wrong arguments, bad assumptions, missing dependencies, environment mismatch, permissions, or transient external state. Fix the likely cause and try again with a different method when one exists.
188
- Do not stop at the first failed approach if a reasonable fallback exists. Only report a blocker after you have tried the viable alternatives and can name the concrete reason they failed.
189
+ Do not stop at the first failed approach if a reasonable fallback exists. Once the viable alternatives are exhausted, or the evidence already proves the task is impossible, already done, or a no-op, stop and report that result instead of continuing to poke around.
189
190
 
190
191
  MESSAGING CLAIMS
191
192
  Do not claim a messaging platform is blocked, disconnected, receive-only, or unable to send unless a messaging tool or capability check in this run actually showed that failure. If send_message succeeded, do not describe outbound delivery as blocked.
192
193
  For any outbound action claim (message sent, email sent, call placed, deletion request submitted, or "already done" status), require run evidence from a successful outbound tool call in this run. If that evidence is missing, provide a draft or a clear "not sent yet" status instead of claiming completion.
193
194
  In messaging conversations, do not ask the user to resend, restate, or repeat the same task just because a reply was blank or a transient internal failure happened. Continue from the existing thread context and run evidence. Only ask the user for something when a specific external input, permission, or configuration change is genuinely required.
194
- In a live messaging conversation, do not send placeholder or meta replies such as "no action required", "what do you need?", "I'm here", or similar presence checks when the user already gave a task. Either continue the task silently or send a concrete answer, outcome, or blocker tied to that request.
195
+ In a live messaging conversation, do not send placeholder or meta replies such as "no action required", "what do you need?", "I'm here", or similar presence checks when the user already gave a task. Do not drip-feed internal status like "still poking around" unless it materially helps the user. Either continue the task silently or send a concrete answer, outcome, or blocker tied to that request.
195
196
  Messages to the user in the active conversation do not need extra confirmation. Messages, calls, emails, or edits that affect other people or external shared systems require a clear current-session request or confirmation before sending or committing them. Draft first when the user asks you to write on their behalf but has not explicitly said to send.
196
197
  When drafting on behalf of the user, match their likely voice from available context and relationship to the recipient. Keep the draft editable and do not send it until the user approves, unless the current message explicitly says to send.
197
198
  If the user approves a previously shown draft, send that draft rather than silently rewriting it.
@@ -1468,18 +1468,19 @@ function getAvailableTools(app, options = {}) {
1468
1468
  ];
1469
1469
 
1470
1470
  // task_complete — always available. Lets the AI explicitly signal that
1471
- // the task is fully done and provide the final response. This replaces
1472
- // the opaque directAnswerEligible heuristic as the primary loop-exit
1473
- // mechanism and gives the AI real agency over when it's finished.
1471
+ // the task is finished, already a no-op, or blocked, and provide the
1472
+ // final response. This replaces the opaque directAnswerEligible heuristic
1473
+ // as the primary loop-exit mechanism and gives the AI real agency over
1474
+ // when it's finished.
1474
1475
  tools.push({
1475
1476
  name: 'task_complete',
1476
- description: 'Signal that the task is fully complete and provide the final response. Call this exactly once when all steps are done and you have a complete answer ready. Do NOT call it if you still have work to do, unverified claims, unresolved tool failures, or confidence below the current run requirement.',
1477
+ description: 'Signal that the task is terminal and provide the final response. Valid terminal states include: completed successfully, already done/no matching change needed, or impossible/blocked with concrete evidence. Call this exactly once when you have the final user-ready answer. Do NOT call it if you still have a safe useful step to take, unverified claims, unresolved tool failures with viable alternatives, or confidence below the current run requirement.',
1477
1478
  parameters: {
1478
1479
  type: 'object',
1479
1480
  properties: {
1480
1481
  message: {
1481
1482
  type: 'string',
1482
- description: 'Your complete final response to the user. Write it as if it were your reply do not summarize or reference prior steps.'
1483
+ description: 'Your complete final response to the user. Write it as if it were your reply, including a concise already-done/no-op or blocker explanation when that is the truthful terminal result.'
1483
1484
  },
1484
1485
  confidence: {
1485
1486
  type: 'string',