@myagentroam/node 0.9.130 → 0.9.131

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/dist/connector.js CHANGED
@@ -263,6 +263,7 @@ export class NodeConnector {
263
263
  goalSubmissionAttempts = new Map();
264
264
  goalContinuationEpochs = new Map();
265
265
  goalExecutionProgress = new Set();
266
+ nativeGoalBindings = new Map();
266
267
  sessionScheduleService;
267
268
  goalMcpServer = new GoalMcpServer(this.goalRuntime, (sessionId) => {
268
269
  const goal = this.goalRuntime.get(sessionId);
@@ -270,6 +271,7 @@ export class NodeConnector {
270
271
  if (goal === undefined || session === undefined)
271
272
  return;
272
273
  if (goal.status !== 'active') {
274
+ this.nativeGoalBindings.delete(goal.id);
273
275
  this.retireGoalContinuation(sessionId);
274
276
  this.continuousRunCoordinator.removeGoalQueue(sessionId);
275
277
  }
@@ -384,11 +386,9 @@ export class NodeConnector {
384
386
  failed: status === 'FAILED',
385
387
  progressed: status !== 'SUCCEEDED' || progressed
386
388
  });
387
- if (disposition === 'blocked' || disposition === 'paused') {
388
- if (disposition === 'blocked')
389
- this.retireGoalContinuation(pending.sessionId);
390
- else
391
- this.invalidateGoalContinuation(pending.sessionId);
389
+ if (disposition === 'blocked' || disposition === 'completed') {
390
+ this.nativeGoalBindings.delete(pending.goal.id);
391
+ this.retireGoalContinuation(pending.sessionId);
392
392
  this.continuousRunCoordinator.removeGoalQueue(pending.sessionId);
393
393
  const terminalGoal = this.goalRuntime.get(pending.sessionId);
394
394
  const session = this.runtime.getAgentSession(pending.sessionId);
@@ -528,6 +528,7 @@ export class NodeConnector {
528
528
  promoteSession: (sessionId, nativeSessionId) => this.sessionIdentityService.promote(sessionId, nativeSessionId),
529
529
  send: (type, payload) => this.send(type, payload),
530
530
  emit: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
531
+ nativeGoalUpdated: (runId, goal) => this.handleNativeGoalUpdate(runId, goal),
531
532
  cancel: (runId, threadId, turnId, cwd, status) => this.runnerInteractionService.cancelCodexTurn(runId, threadId, turnId, cwd, status),
532
533
  createApproval: (input) => this.runtime.createApproval(input),
533
534
  publishApproval: (input) => this.publishApprovalForRun(input),
@@ -985,6 +986,9 @@ export class NodeConnector {
985
986
  goalAlreadyActive: true
986
987
  };
987
988
  if (existing !== undefined) {
989
+ const previousGoal = this.goalRuntime.get(session.id);
990
+ if (previousGoal !== undefined)
991
+ this.nativeGoalBindings.delete(previousGoal.id);
988
992
  this.goalRuntime.clear(session.id);
989
993
  this.commandStates.clear(session.id, 'goal');
990
994
  }
@@ -1720,10 +1724,46 @@ export class NodeConnector {
1720
1724
  const current = this.goalRuntime.get(sessionId);
1721
1725
  return ((this.goalContinuationEpochs.get(sessionId) ?? 0) === goal.epoch &&
1722
1726
  current?.status === 'active' &&
1723
- !current.continuationPaused &&
1724
1727
  current.id === goal.id &&
1725
1728
  current.revision === goal.revision);
1726
1729
  }
1730
+ handleNativeGoalUpdate(runId, nativeGoal) {
1731
+ const pending = this.continuousRunCoordinator.pending(runId);
1732
+ if (pending?.goal === undefined || !this.goalGenerationCurrent(pending.sessionId, pending.goal))
1733
+ return;
1734
+ const goal = this.goalRuntime.get(pending.sessionId);
1735
+ if (nativeGoal.status === 'active') {
1736
+ if ((nativeGoal.createdAt + 1) * 1_000 < goal.revisionStartedAt)
1737
+ return;
1738
+ const previous = this.nativeGoalBindings.get(goal.id);
1739
+ if (previous !== undefined &&
1740
+ previous.revision !== goal.revision &&
1741
+ previous.threadId === nativeGoal.threadId &&
1742
+ previous.createdAt === nativeGoal.createdAt &&
1743
+ previous.objective === nativeGoal.objective)
1744
+ return;
1745
+ this.nativeGoalBindings.set(goal.id, {
1746
+ revision: goal.revision,
1747
+ threadId: nativeGoal.threadId,
1748
+ createdAt: nativeGoal.createdAt,
1749
+ objective: nativeGoal.objective
1750
+ });
1751
+ return;
1752
+ }
1753
+ const bound = this.nativeGoalBindings.get(goal.id);
1754
+ if (bound?.revision !== goal.revision ||
1755
+ bound.threadId !== nativeGoal.threadId ||
1756
+ bound.createdAt !== nativeGoal.createdAt ||
1757
+ bound.objective !== nativeGoal.objective)
1758
+ return;
1759
+ this.nativeGoalBindings.delete(goal.id);
1760
+ const completed = this.goalRuntime.update(pending.sessionId, goal.id, goal.revision, 'completed');
1761
+ this.retireGoalContinuation(pending.sessionId);
1762
+ this.continuousRunCoordinator.removeGoalQueue(pending.sessionId);
1763
+ const session = this.runtime.getAgentSession(pending.sessionId);
1764
+ if (session !== undefined)
1765
+ this.publishGoalState(session, completed);
1766
+ }
1727
1767
  beginGoalSubmission(sessionId, continuationEpoch = this.goalContinuationEpochs.get(sessionId) ?? 0) {
1728
1768
  const attempt = { sessionId, epoch: continuationEpoch };
1729
1769
  const attempts = this.goalSubmissionAttempts.get(sessionId) ?? new Set();
@@ -1814,6 +1854,7 @@ export class NodeConnector {
1814
1854
  this.clearGoalRetry(attempt.sessionId);
1815
1855
  if (failedAttempts > 3) {
1816
1856
  const blocked = this.goalRuntime.blockAfterRuntimeFailure(attempt.sessionId, input.goal.id, input.goal.revision);
1857
+ this.nativeGoalBindings.delete(input.goal.id);
1817
1858
  this.continuousRunCoordinator.removeGoalQueue(attempt.sessionId);
1818
1859
  this.goalContinuationEpochs.delete(attempt.sessionId);
1819
1860
  this.finishIdleGoalRun(attempt.sessionId, 'FAILED');
@@ -1861,6 +1902,9 @@ export class NodeConnector {
1861
1902
  }
1862
1903
  clearGoalState(sessionId, status) {
1863
1904
  const goalExit = this.goalRuntime.exitSummary(sessionId, status);
1905
+ const goal = this.goalRuntime.get(sessionId);
1906
+ if (goal !== undefined)
1907
+ this.nativeGoalBindings.delete(goal.id);
1864
1908
  this.retireGoalContinuation(sessionId);
1865
1909
  const removed = this.goalRuntime.clear(sessionId);
1866
1910
  this.continuousRunCoordinator.removeGoalQueue(sessionId);
@@ -142,6 +142,27 @@ export class CodexManagedRunController {
142
142
  this.host.emit(runId, 'run.running', { threadId, turnId }, 'RUNNING');
143
143
  return;
144
144
  }
145
+ if (notification.method === 'thread/goal/updated' &&
146
+ activeRun.goalMcp === true &&
147
+ turnId !== undefined &&
148
+ threadId !== undefined &&
149
+ isPlainRecord(params.goal) &&
150
+ params.goal.threadId === threadId &&
151
+ Number.isSafeInteger(params.goal.createdAt) &&
152
+ params.goal.createdAt > 0 &&
153
+ typeof params.goal.objective === 'string' &&
154
+ params.goal.objective.length <= 20_000 &&
155
+ (params.goal.status !== 'active' ||
156
+ (params.goal.tokensUsed === 0 && params.goal.timeUsedSeconds === 0)) &&
157
+ (params.goal.status === 'active' || params.goal.status === 'complete')) {
158
+ this.host.nativeGoalUpdated(runId, {
159
+ threadId,
160
+ createdAt: params.goal.createdAt,
161
+ objective: params.goal.objective,
162
+ status: params.goal.status === 'complete' ? 'completed' : 'active'
163
+ });
164
+ return;
165
+ }
145
166
  if (notification.requestId !== undefined &&
146
167
  (notification.method === 'item/commandExecution/requestApproval' ||
147
168
  notification.method === 'item/fileChange/requestApproval')) {
@@ -102,18 +102,19 @@ export class GoalRuntime {
102
102
  throw new Error('GOAL_OBJECTIVE_INVALID');
103
103
  const current = this.goals.get(sessionId);
104
104
  const continuing = current?.status === 'active';
105
+ const now = this.now();
105
106
  const goal = {
106
107
  id: continuing ? current.id : randomUUID(),
107
108
  sessionId,
108
109
  objective: normalized,
109
- startedAt: continuing ? current.startedAt : this.now(),
110
+ startedAt: continuing ? current.startedAt : now,
111
+ revisionStartedAt: now,
110
112
  revision: continuing ? current.revision + 1 : 1,
111
113
  status: 'active',
112
114
  turns: 0,
113
115
  retryRequired: false,
114
116
  retryStartedAtTurn: null,
115
- consecutiveNoProgressTurns: 0,
116
- continuationPaused: false
117
+ consecutiveNoProgressTurns: 0
117
118
  };
118
119
  this.goals.set(sessionId, goal);
119
120
  this.executionFailures.delete(sessionId);
@@ -144,34 +145,32 @@ export class GoalRuntime {
144
145
  if (!input.failed && !input.progressed) {
145
146
  this.executionFailures.delete(sessionId);
146
147
  const consecutiveNoProgressTurns = current.consecutiveNoProgressTurns + 1;
147
- const paused = consecutiveNoProgressTurns >= 3;
148
+ const completed = consecutiveNoProgressTurns >= 3;
148
149
  const goal = {
149
150
  ...current,
150
151
  consecutiveNoProgressTurns,
151
- continuationPaused: paused
152
+ ...(completed ? { status: 'completed' } : {})
152
153
  };
153
154
  this.goals.set(sessionId, goal);
154
155
  this.changed(goal);
155
- return paused ? 'paused' : 'continue';
156
+ return completed ? 'completed' : 'continue';
156
157
  }
157
158
  if (!input.failed) {
158
159
  this.executionFailures.delete(sessionId);
159
- if (current.consecutiveNoProgressTurns > 0 || current.continuationPaused) {
160
+ if (current.consecutiveNoProgressTurns > 0) {
160
161
  const goal = {
161
162
  ...current,
162
- consecutiveNoProgressTurns: 0,
163
- continuationPaused: false
163
+ consecutiveNoProgressTurns: 0
164
164
  };
165
165
  this.goals.set(sessionId, goal);
166
166
  this.changed(goal);
167
167
  }
168
168
  return 'continue';
169
169
  }
170
- if (current.consecutiveNoProgressTurns > 0 || current.continuationPaused) {
170
+ if (current.consecutiveNoProgressTurns > 0) {
171
171
  const goal = {
172
172
  ...current,
173
- consecutiveNoProgressTurns: 0,
174
- continuationPaused: false
173
+ consecutiveNoProgressTurns: 0
175
174
  };
176
175
  this.goals.set(sessionId, goal);
177
176
  }
@@ -191,12 +190,11 @@ export class GoalRuntime {
191
190
  const current = this.goals.get(sessionId);
192
191
  if (current?.status !== 'active')
193
192
  return current;
194
- if (!current.continuationPaused && current.consecutiveNoProgressTurns === 0)
193
+ if (current.consecutiveNoProgressTurns === 0)
195
194
  return current;
196
195
  const goal = {
197
196
  ...current,
198
- consecutiveNoProgressTurns: 0,
199
- continuationPaused: false
197
+ consecutiveNoProgressTurns: 0
200
198
  };
201
199
  this.goals.set(sessionId, goal);
202
200
  this.changed(goal);
@@ -247,7 +245,7 @@ export class GoalRuntime {
247
245
  const heading = kind === 'start' ? 'A Goal has started or changed.' : 'Continue the active Goal.';
248
246
  const open = kind === 'start' ? START_OPEN : CONTINUE_OPEN;
249
247
  const close = kind === 'start' ? START_CLOSE : CONTINUE_CLOSE;
250
- return `${open}\n${heading}\n\nOriginal objective:\n${goal.objective}\n\nContinue executing this Goal across turns:\n- Work on the objective now. If it is incomplete, use tools to finish a coherent unit or obtain decisive evidence; do not stop at an acknowledgement, status, plan, or promise.\n- Preserve the original scope. Before completion, review the full objective and verify it with real evidence, then call mar_update_goal with status=completed.\n- Adapt and retry after individual failures. Request blocked only after the same blocker persists for three turns and the required additional retry.\n- Use mar_get_goal only when you need to reread the authoritative objective or status.\n- After mar_update_goal confirms completed or finally blocked, summarize the completed work, verification evidence, remaining issues, and the tool-reported elapsedWallMs converted from milliseconds into a concise readable duration in your final user-facing response. Name whether the Goal completed or is finally blocked. That elapsed time is wall-clock time through the status update, including waiting and retries, not tool execution time or time through this final response. If blocked returns active for the required retry, continue work instead of claiming a final summary.\n${close}`;
248
+ return `${open}\n${heading}\n\nOriginal objective:\n${goal.objective}\n\nContinue executing this Goal across turns:\n- This Goal is owned by the Node's myagentroam_goal MCP server. Prefer myagentroam_goal.mar_update_goal to complete it. In Codex, a runner-native Goal created during this Goal may also complete it when Codex reports that native Goal complete; native Goal state from another task or turn does not count. Do not claim completion based only on a final message or an unrelated Goal.\n- Work on the objective now. If it is incomplete, use tools to finish a coherent unit or obtain decisive evidence; do not stop at an acknowledgement, status, plan, or promise.\n- Preserve the original scope. Before completion, review the full objective and verify it with real evidence, then call mar_update_goal with status=completed when available.\n- Adapt and retry after individual failures. Request blocked only after the same blocker persists for three turns and the required additional retry.\n- Use mar_get_goal only when you need to reread the authoritative objective or status.\n- After mar_update_goal confirms completed or finally blocked, summarize the completed work, verification evidence, remaining issues, and the tool-reported elapsedWallMs converted from milliseconds into a concise readable duration in your final user-facing response. If Codex instead confirms completion with its native Goal, summarize the work without claiming a MAR elapsedWallMs value. Name whether the Goal completed or is finally blocked. MAR elapsedWallMs includes waiting and retries through the status update, not tool execution time or the final response. If blocked returns active for the required retry, continue work instead of claiming a final summary.\n${close}`;
251
249
  }
252
250
  requireCurrent(sessionId, goalId, revision) {
253
251
  const current = this.goals.get(sessionId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.9.130",
3
+ "version": "0.9.131",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -30,9 +30,9 @@
30
30
  "npm": "11.12.1",
31
31
  "ws": "^8.21.3",
32
32
  "zod": "4.4.3",
33
- "@myagentroam/protocol": "0.9.130",
34
- "@myagentroam/code-navigation": "0.9.129",
35
- "@myagentroam/agent": "0.9.130"
33
+ "@myagentroam/agent": "0.9.131",
34
+ "@myagentroam/protocol": "0.9.131",
35
+ "@myagentroam/code-navigation": "0.9.129"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/ws": "^8.18.1"