neoagent 2.1.18-beta.37 → 2.1.18-beta.38

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.37",
3
+ "version": "2.1.18-beta.38",
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: "1235668503" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "2247189506" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -173,10 +173,10 @@ function joinSentMessages(messages = []) {
173
173
 
174
174
  function buildBlankMessagingReplyPrompt(attempt) {
175
175
  if (attempt <= 1) {
176
- return 'You must send one non-empty plain-text reply for the external messaging user right now. Do not call tools. Do not use markdown. Give either: (a) the concrete outcome, or (b) a clear blocker and the next action. If tool work already happened, summarize what you actually tried and where it got blocked. Do not ask the user to repeat the original request.';
176
+ return 'You must send one non-empty plain-text reply for the external messaging user right now. Do not call tools. Do not use markdown. Give either: (a) the concrete outcome, or (b) a clear blocker. If tool work already happened, summarize what you actually tried and where it got blocked. Do not ask the user to repeat the original request. Do not promise future work unless that work already happened in this run or will happen automatically before this reply is sent.';
177
177
  }
178
178
 
179
- return 'Your previous reply was empty. Return one non-empty plain-text message now. Do not call tools. Do not use markdown. If needed, apologize briefly, explain the blocker in one sentence, and tell the user what to do next. Use the run evidence already in the conversation instead of asking the user to restate the task.';
179
+ return 'Your previous reply was empty. Return one non-empty plain-text message now. Do not call tools. Do not use markdown. If needed, apologize briefly and explain the blocker in one sentence. Use the run evidence already in the conversation instead of asking the user to restate the task. Do not promise future work unless that work already happened in this run or will happen automatically before this reply is sent.';
180
180
  }
181
181
 
182
182
  function parseToolExecutionSummary(item) {
@@ -280,21 +280,35 @@ function buildDeterministicMessagingFallback({ failedStepCount, stepIndex, toolE
280
280
  return 'I could not produce a reliable final reply just now.';
281
281
  }
282
282
 
283
- function buildModelFailureLoopPrompt({ failedModel, nextModel, errorMessage }) {
284
- return [
285
- `The previous model call on "${failedModel}" failed with: ${summarizeForLog(errorMessage, 220)}.`,
286
- `Continue on "${nextModel}" and recover autonomously.`,
287
- 'If a previous plan depended on that failed call, adjust your approach and proceed end-to-end.',
288
- 'Only ask the user for help if no safe path remains.'
289
- ].join(' ');
290
- }
283
+ function buildMessagingFailureScenario({ err, failedStepCount, stepIndex, toolExecutions = [] }) {
284
+ const parts = [];
285
+ const runtimeError = normalizeOutgoingMessage(err?.message || '');
286
+ const workSummary = summarizeRecentWork(toolExecutions);
287
+ const blocker = [...toolExecutions].reverse()
288
+ .map((item) => extractToolFailureMessage(item))
289
+ .find(Boolean);
291
290
 
292
- function buildMessagingErrorReply(err) {
293
- const message = String(err?.message || '').trim();
294
- if (!message) {
295
- return 'I ran into an internal error while processing your request and could not finish it reliably.';
291
+ if (runtimeError) {
292
+ parts.push(`Runtime error: ${summarizeForLog(runtimeError, 260)}.`);
293
+ }
294
+ if (workSummary) {
295
+ parts.push(`Observed work before failure: ${workSummary}.`);
296
+ }
297
+ if (blocker) {
298
+ parts.push(`Most specific blocker from run evidence: ${summarizeForLog(blocker, 260)}.`);
299
+ }
300
+ if (stepIndex > 0) {
301
+ parts.push(`Completed steps before failure: ${stepIndex}.`);
302
+ }
303
+ if (failedStepCount > 0) {
304
+ parts.push(`Failed tool steps: ${failedStepCount}.`);
296
305
  }
297
306
 
307
+ return parts.join(' ');
308
+ }
309
+
310
+ function buildDeterministicMessagingErrorReply({ err, failedStepCount, stepIndex, toolExecutions = [] }) {
311
+ const message = normalizeOutgoingMessage(err?.message || '');
298
312
  if (/no ai providers? are currently available/i.test(message)) {
299
313
  return 'I cannot continue right now because no AI provider is available for this account. Please check the provider settings.';
300
314
  }
@@ -303,7 +317,27 @@ function buildMessagingErrorReply(err) {
303
317
  return 'I hit a timeout while processing your request and could not finish it reliably.';
304
318
  }
305
319
 
306
- return 'I ran into an internal error while processing your request and could not finish it reliably.';
320
+ const blocker = [...toolExecutions].reverse()
321
+ .map((item) => extractToolFailureMessage(item))
322
+ .find(Boolean);
323
+ if (blocker) {
324
+ return `I got blocked while checking this: ${blocker}.`;
325
+ }
326
+
327
+ if (message) {
328
+ return `I got blocked while working on this: ${message}.`;
329
+ }
330
+
331
+ return buildDeterministicMessagingFallback({ failedStepCount, stepIndex, toolExecutions });
332
+ }
333
+
334
+ function buildModelFailureLoopPrompt({ failedModel, nextModel, errorMessage }) {
335
+ return [
336
+ `The previous model call on "${failedModel}" failed with: ${summarizeForLog(errorMessage, 220)}.`,
337
+ `Continue on "${nextModel}" and recover autonomously.`,
338
+ 'If a previous plan depended on that failed call, adjust your approach and proceed end-to-end.',
339
+ 'Only ask the user for help if no safe path remains.'
340
+ ].join(' ');
307
341
  }
308
342
 
309
343
  const MAX_AUTONOMOUS_MESSAGING_RETRIES = 2;
@@ -1984,12 +2018,18 @@ class AgentEngine {
1984
2018
  if (!runMeta?.messagingSent) {
1985
2019
  const manager = this.messagingManager;
1986
2020
  if (manager) {
2021
+ const failureScenario = buildMessagingFailureScenario({
2022
+ err,
2023
+ failedStepCount,
2024
+ stepIndex,
2025
+ toolExecutions,
2026
+ });
1987
2027
  try {
1988
2028
  const failedMessage = sanitizeConversationMessages([
1989
2029
  ...messages,
1990
2030
  {
1991
2031
  role: 'system',
1992
- content: `The run encountered a runtime error and cannot continue reliably: ${summarizeForLog(err.message, 260)}. Do not call tools. Write exactly one short plain-text user message that explains the blocker naturally. Do not ask the user to resend or restate the same task. Only ask the user for something if a specific external input, permission, or configuration change is actually required.`
2032
+ content: `The run encountered a runtime error and cannot continue reliably. Use the actual run scenario below to explain the blocker naturally.\n\nScenario:\n${failureScenario || 'No additional scenario details were captured.'}\n\nDo not call tools. Write exactly one short plain-text user message. Do not ask the user to resend or restate the same task. Only ask the user for something if a specific external input, permission, or configuration change is actually required. Do not promise future work unless it will happen automatically before this reply is sent.`
1993
2033
  }
1994
2034
  ]);
1995
2035
  const modelReply = await provider.chat(failedMessage, [], {
@@ -2005,7 +2045,12 @@ class AgentEngine {
2005
2045
  }
2006
2046
 
2007
2047
  if (!messagingFailureContent) {
2008
- messagingFailureContent = buildMessagingErrorReply(err);
2048
+ messagingFailureContent = buildDeterministicMessagingErrorReply({
2049
+ err,
2050
+ failedStepCount,
2051
+ stepIndex,
2052
+ toolExecutions,
2053
+ });
2009
2054
  }
2010
2055
 
2011
2056
  try {
@@ -78,6 +78,7 @@ For long tasks, give brief progress only when the user is waiting or the operati
78
78
  REPORT ACTUAL RESULTS
79
79
  When a tool returns data, share the relevant parts — summarized if large, direct if short. Never paste raw JSON as the answer. Never narrate what you're about to do at length before doing it.
80
80
  Never promise an action in the final answer unless you already took that action in this run. Do not say "I'll check", "I'll fix it", or "I'll send it" and then stop. Either do it first or say you have not done it yet.
81
+ Do not promise future follow-up work unless that work will actually happen automatically before the current run ends.
81
82
  For scheduler or task-config changes, never claim that a cron job was created, updated, deleted, enabled, disabled, or “fixed” unless the corresponding scheduler tool call succeeded in this run. If you did not verify the actual task config, say that clearly instead of guessing.
82
83
  If the user asks you to debug scheduler timing or frequency, inspect the current scheduled-task list first and separate three things clearly: what you observed, what you infer, and what you actually changed.
83
84