neuralos 3.2.10 → 3.2.12

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.
Files changed (2) hide show
  1. package/bin/gybackend.cjs +78 -19
  2. package/package.json +2 -2
package/bin/gybackend.cjs CHANGED
@@ -349384,17 +349384,18 @@ function createTaskCompletionDecisionUserPrompt() {
349384
349384
  return new HumanMessage(
349385
349385
  [
349386
349386
  "# Task Completion Audit",
349387
- "You are a strict completion auditor for an autonomous agent.",
349387
+ "You are a completion auditor for an autonomous agent.",
349388
349388
  "",
349389
- "Check the full conversation and decide whether the agent has truly finished ALL user tasks.",
349390
- "Do not approve stopping if there are reasonable alternative attempts/tools left.",
349389
+ "Check the conversation and decide whether the agent has finished the user's task.",
349391
349390
  "",
349392
349391
  "Output MUST be JSON only:",
349393
349392
  '{"is_fully_completed": true|false, "reason":"..."}',
349394
349393
  "",
349395
349394
  "Decision rules:",
349396
- "- true only when the user request is fully completed and verified, or further progress is impossible and must be handed to user.",
349397
- "- false if requirements are unmet, verification is missing, or alternative attempts still exist.",
349395
+ "- true when the user's request has been answered or the requested work was performed and its result reported.",
349396
+ "- true when the agent already provided a complete, usable answer \u2014 do NOT demand extra verification the user never asked for.",
349397
+ "- false only when a clearly stated user requirement is still unmet or the agent's answer is factually wrong.",
349398
+ "- Do not invent optional follow-up work (extra checks, alternative approaches, further reading) as a reason to continue. If the user asked for X and X was delivered, the task is done.",
349398
349399
  "- reason must be concrete and reference what is done/missing."
349399
349400
  ].join("\n")
349400
349401
  );
@@ -367715,6 +367716,18 @@ var StateAnnotation = Ann.Root({
367715
367716
  reducer: (x, y) => y ?? x,
367716
367717
  default: () => "end"
367717
367718
  }),
367719
+ // v3.2.12: how many times the completion guard has forced a continue in the
367720
+ // current run. Bounded so an over-strict auditor can't loop forever.
367721
+ guardContinueCount: Ann({
367722
+ reducer: (x, y) => typeof y === "number" ? y : x,
367723
+ default: () => 0
367724
+ }),
367725
+ // v3.2.12: the gateway runId for the current graph invocation (used to
367726
+ // dedupe the DONE broadcast).
367727
+ runId: Ann({
367728
+ reducer: (x, y) => typeof y === "string" ? y : x,
367729
+ default: () => ""
367730
+ }),
367718
367731
  modelRequestPassCount: Ann({
367719
367732
  reducer: (x, y) => typeof y === "number" ? y : x,
367720
367733
  default: () => 0
@@ -367742,6 +367755,7 @@ var StateAnnotation = Ann.Root({
367742
367755
  });
367743
367756
  var MODEL_RETRY_MAX = 4;
367744
367757
  var MODEL_RETRY_DELAYS_MS = [1e3, 2e3, 4e3, 6e3];
367758
+ var TASK_COMPLETION_GUARD_MAX_CONTINUES = 1;
367745
367759
  var COMPACTION_PROTECTED_NORMAL_USER_ROUNDS = 2;
367746
367760
  var FALLBACK_COMPACTION_SUMMARY_MAX_CHARS = 6e4;
367747
367761
  var FALLBACK_COMPACTION_DIGEST_MIN_CHARS = 8e3;
@@ -367932,6 +367946,9 @@ var AgentService_v2 = class {
367932
367946
  checkpointer;
367933
367947
  builtInToolEnabled = {};
367934
367948
  lastAbortedMessage = null;
367949
+ /** v3.2.12: runIds whose final_output node already emitted `done` — lets
367950
+ * GatewayService skip its duplicate DONE broadcast for the same run. */
367951
+ doneEmittedForRunIds = /* @__PURE__ */ new Set();
367935
367952
  sessionModelBindings = /* @__PURE__ */ new Map();
367936
367953
  selfCorrectionRuntimeManager = new SelfCorrectionRuntimeManager();
367937
367954
  waitForFeedback = null;
@@ -368056,6 +368073,19 @@ var AgentService_v2 = class {
368056
368073
  isAbortError(error40) {
368057
368074
  return this.helpers.isAbortError(error40);
368058
368075
  }
368076
+ /**
368077
+ * v3.2.12: true when the given run's final_output node already emitted the
368078
+ * `done` event. GatewayService uses this to avoid broadcasting a duplicate
368079
+ * DONE for the same run (the UI saw every run finish twice).
368080
+ */
368081
+ emittedDoneForRun(runId) {
368082
+ if (!runId) return false;
368083
+ const emitted = this.doneEmittedForRunIds.has(runId);
368084
+ if (emitted) {
368085
+ this.doneEmittedForRunIds.delete(runId);
368086
+ }
368087
+ return emitted;
368088
+ }
368059
368089
  throwIfAborted(signal) {
368060
368090
  if (signal?.aborted) {
368061
368091
  throw new Error("AbortError");
@@ -369962,6 +369992,19 @@ ${reminder}`;
369962
369992
  return RunnableLambda.from(async (state, config2) => {
369963
369993
  const sessionId = state.sessionId;
369964
369994
  if (!sessionId) throw new Error("No session ID in state");
369995
+ const guardContinueCount = typeof state.guardContinueCount === "number" ? state.guardContinueCount : 0;
369996
+ if (guardContinueCount >= TASK_COMPLETION_GUARD_MAX_CONTINUES) {
369997
+ console.log(
369998
+ `[AgentService_v2][task_guard] Continue limit reached (${guardContinueCount}). Forcing completion (sessionId=${sessionId}).`
369999
+ );
370000
+ return {
370001
+ messages: state.messages,
370002
+ sessionId,
370003
+ pendingToolCalls: [],
370004
+ completionGuardDecision: "end",
370005
+ guardContinueCount
370006
+ };
370007
+ }
369965
370008
  const messages = [...state.messages];
369966
370009
  const lastMessage = messages.length > 0 ? messages[messages.length - 1] : void 0;
369967
370010
  const lastMessageIsAi = AIMessage.isInstance(lastMessage);
@@ -369976,7 +370019,8 @@ ${reminder}`;
369976
370019
  messages: guardMessages,
369977
370020
  sessionId,
369978
370021
  pendingToolCalls: [],
369979
- completionGuardDecision: "end"
370022
+ completionGuardDecision: "end",
370023
+ guardContinueCount
369980
370024
  };
369981
370025
  }
369982
370026
  const guardTail = guardMessages[guardMessages.length - 1];
@@ -369986,7 +370030,8 @@ ${reminder}`;
369986
370030
  messages: guardMessages,
369987
370031
  sessionId,
369988
370032
  pendingToolCalls: [],
369989
- completionGuardDecision: "continue"
370033
+ completionGuardDecision: "continue",
370034
+ guardContinueCount
369990
370035
  };
369991
370036
  }
369992
370037
  const unfinishedBackgroundCommands = this.consumeUnfinishedBackgroundExecCommandsForGuard(sessionId);
@@ -370003,7 +370048,8 @@ ${reminder}`;
370003
370048
  messages: [...guardMessages, continueMessage2],
370004
370049
  sessionId,
370005
370050
  pendingToolCalls: [],
370006
- completionGuardDecision: "continue"
370051
+ completionGuardDecision: "continue",
370052
+ guardContinueCount
370007
370053
  };
370008
370054
  }
370009
370055
  const unfinishedBackgroundTransfers = this.consumeUnfinishedBackgroundFileTransfersForGuard(sessionId);
@@ -370020,7 +370066,8 @@ ${reminder}`;
370020
370066
  messages: [...guardMessages, continueMessage2],
370021
370067
  sessionId,
370022
370068
  pendingToolCalls: [],
370023
- completionGuardDecision: "continue"
370069
+ completionGuardDecision: "continue",
370070
+ guardContinueCount
370024
370071
  };
370025
370072
  }
370026
370073
  const lateQueuedInsertionResult = this.appendQueuedInsertionMessagesForContinue(
@@ -370033,7 +370080,8 @@ ${reminder}`;
370033
370080
  messages: lateQueuedInsertionResult.messages,
370034
370081
  sessionId,
370035
370082
  pendingToolCalls: [],
370036
- completionGuardDecision: "continue"
370083
+ completionGuardDecision: "continue",
370084
+ guardContinueCount
370037
370085
  };
370038
370086
  }
370039
370087
  let completionDecision;
@@ -370071,7 +370119,8 @@ ${reminder}`;
370071
370119
  messages: lateQueuedInsertionAfterAuditResult.messages,
370072
370120
  sessionId,
370073
370121
  pendingToolCalls: [],
370074
- completionGuardDecision: "continue"
370122
+ completionGuardDecision: "continue",
370123
+ guardContinueCount
370075
370124
  };
370076
370125
  }
370077
370126
  console.log(
@@ -370081,7 +370130,8 @@ ${reminder}`;
370081
370130
  messages: guardMessages,
370082
370131
  sessionId,
370083
370132
  pendingToolCalls: [],
370084
- completionGuardDecision: "end"
370133
+ completionGuardDecision: "end",
370134
+ guardContinueCount
370085
370135
  };
370086
370136
  }
370087
370137
  console.log(
@@ -370119,7 +370169,6 @@ ${reminder}`;
370119
370169
  continue_instruction: "Continue the task. Re-check unmet requirements, choose the next best tool/approach, execute it, and verify result."
370120
370170
  };
370121
370171
  }
370122
- this.emitRemoveMessageIfPresent(sessionId, lastMessage);
370123
370172
  const continueMessage = new HumanMessage(
370124
370173
  `${CONTINUE_INSTRUCTION_TAG}${this.appendTaskGuardSummaryReminder(continueInstruction.continue_instruction)}`
370125
370174
  );
@@ -370131,7 +370180,8 @@ ${reminder}`;
370131
370180
  messages: [...guardMessages, continueMessage],
370132
370181
  sessionId,
370133
370182
  pendingToolCalls: [],
370134
- completionGuardDecision: "continue"
370183
+ completionGuardDecision: "continue",
370184
+ guardContinueCount: guardContinueCount + 1
370135
370185
  };
370136
370186
  });
370137
370187
  }
@@ -370168,6 +370218,8 @@ ${reminder}`;
370168
370218
  history: JSON.parse(JSON.stringify(finalBoundaryMessages))
370169
370219
  });
370170
370220
  this.helpers.sendEvent(sessionId, { type: "done" });
370221
+ const doneRunId = typeof state?.runId === "string" ? state.runId : "";
370222
+ if (doneRunId) this.doneEmittedForRunIds.add(doneRunId);
370171
370223
  return {
370172
370224
  ...state,
370173
370225
  messages: finalBoundaryMessages,
@@ -371092,6 +371144,9 @@ ${reminder}`;
371092
371144
  sessionId,
371093
371145
  startup_input: input,
371094
371146
  startup_mode: startMode,
371147
+ // v3.2.12: carried so final_output can mark this run as done-emitting
371148
+ // (dedupes the GatewayService finally-block DONE broadcast).
371149
+ runId: runId || "",
371095
371150
  runtimeThinkingCorrectionEnabled: runExperimentalFlags.runtimeThinkingCorrectionEnabled,
371096
371151
  taskFinishGuardEnabled: runExperimentalFlags.taskFinishGuardEnabled,
371097
371152
  firstTurnThinkingModelEnabled: runExperimentalFlags.firstTurnThinkingModelEnabled,
@@ -371143,6 +371198,7 @@ ${reminder}`;
371143
371198
  message: errorMessage,
371144
371199
  details: errorDetails
371145
371200
  });
371201
+ if (runId) this.doneEmittedForRunIds.add(runId);
371146
371202
  throw err;
371147
371203
  } finally {
371148
371204
  this.selfCorrectionRuntimeManager.clearSession(sessionId);
@@ -372780,11 +372836,14 @@ var GatewayService = class extends import_events2.EventEmitter {
372780
372836
  if (context2.metadata.agentRunRestartInProgress === agentRunId) {
372781
372837
  delete context2.metadata.agentRunRestartInProgress;
372782
372838
  }
372783
- this.broadcast({
372784
- type: "agent:event",
372785
- sessionId,
372786
- payload: { type: "done" }
372787
- });
372839
+ const agentEmittedDone = typeof this.agentService.emittedDoneForRun === "function" ? this.agentService.emittedDoneForRun(runId) : false;
372840
+ if (!agentEmittedDone) {
372841
+ this.broadcast({
372842
+ type: "agent:event",
372843
+ sessionId,
372844
+ payload: { type: "done" }
372845
+ });
372846
+ }
372788
372847
  this.transportHub.sendUIUpdate({ type: "SESSION_READY", sessionId });
372789
372848
  this.uiHistoryService.flush(sessionId);
372790
372849
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "neuralos",
3
- "version": "3.2.10",
4
- "description": "Headless AI-native backend for RTerm / neuralOS — v3.2.10: fixes rename (terminal tabs + chat sessions; window.prompt throws in Electron 42 → in-app modal) and the chat scroll trap after Prev/Next/Latest user-nav. 11 plugins, 55 plugin tools wired, parallel tool execution, captureStatus, rterm CLI. Transports (SSH/serial/local), SQLite, and NATS libs install automatically.",
3
+ "version": "3.2.12",
4
+ "description": "Headless AI-native backend for RTerm / neuralOS — v3.2.12: chat console fixed (task-completion guard bounded, answers no longer cleared + re-answered, DONE deduped, auditor prompt rebalanced). 11 plugins, 55 plugin tools, parallel tool execution, captureStatus. Transports (SSH/serial/local), SQLite, and NATS libs install automatically.",
5
5
  "main": "bin/gybackend.cjs",
6
6
  "bin": { "gybackend": "bin/gybackend.cjs" },
7
7
  "license": "MIT",