@myagentroam/node 0.11.42 → 0.11.43

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 (29) hide show
  1. package/dist/connector.js +9 -2
  2. package/dist/hosting/hosted-conversation-node-service.js +1 -2
  3. package/dist/marctl-guidance.js +3 -1
  4. package/dist/runner/abstract-runner.js +2 -2
  5. package/dist/runner/claude/managed-run-controller.js +1 -1
  6. package/dist/runner/claude/native-transcript.js +1 -1
  7. package/dist/runner/claude/tool-normalizer.js +21 -12
  8. package/dist/runner/codex/conversation-parser.js +17 -9
  9. package/dist/runner/codex/managed-run-controller.js +1 -1
  10. package/dist/runner/codex/tool-normalizer.js +17 -9
  11. package/dist/runner/execution-presentation.js +0 -3
  12. package/dist/runner/mar-agent/agent-network-extension.js +2 -2
  13. package/dist/runner/mar-agent/conversation-normalizer.js +259 -43
  14. package/dist/runner/mar-agent/managed-run-controller.js +2 -1
  15. package/dist/runner/mar-agent/runtime-model-factory.js +2 -4
  16. package/dist/runner/mar-agent-runner.js +32 -8
  17. package/dist/runner/normalization.js +8 -0
  18. package/dist/runner/opencode/tool-normalizer.js +8 -4
  19. package/dist/runtime-state.js +0 -1
  20. package/dist/service/agent-network-bindings.js +4 -2
  21. package/dist/service/agent-network-invoke.js +5 -2
  22. package/dist/service/agent-network-observations.js +15 -13
  23. package/dist/service/agent-network-service.js +39 -15
  24. package/dist/service/goal-continuation-coordinator.js +5 -0
  25. package/dist/service/runner-service.js +7 -3
  26. package/dist/session/runtime/conversation-projection.js +3 -1
  27. package/dist/session/session-lifecycle-service.js +7 -4
  28. package/dist/session/session-message-service.js +4 -2
  29. package/package.json +4 -4
@@ -141,7 +141,9 @@ export function createNodeAgentNetwork(options) {
141
141
  options.projection.resolve(record.id, true)));
142
142
  return resolved.filter((session) => session !== undefined);
143
143
  },
144
- observe: (actor, session) => options.ensureObservations(actor).observe(session.id),
144
+ observe: (actor) => {
145
+ options.ensureObservations(actor);
146
+ },
145
147
  isUpward: async (actor, session) => !terminalCalls.has(actor) && (await actorSession(actor)).parentSessionId === session.id,
146
148
  reportUpward: async (actor, session, input, signal) => {
147
149
  const child = await actorSession(actor);
@@ -210,7 +212,7 @@ export function createNodeAgentNetwork(options) {
210
212
  throw new Error('SESSION_INVALID');
211
213
  const model = input.model ??
212
214
  database.getRunnerDefaults().find((entry) => entry.runner === runner)?.model ??
213
- runnerAdapter.defaultConfiguration(workspace, actor.secretEnvironment ?? {}).model;
215
+ runnerAdapter.defaultConfiguration(workspace, actor.secretEnvironment ?? {}, runnerAdapter.prepareExecutionContext(actor.runnerConfiguration ?? {})).model;
214
216
  const request = {
215
217
  ...executionInput(actor, runner, model, parent !== undefined),
216
218
  workspaceId: workspace.id,
@@ -11,11 +11,14 @@ export function agentNetworkInvoke(input) {
11
11
  }
12
12
  /** Read actor resources from the current Node-owned Execution, not caller arguments. */
13
13
  export function executionAgentActor(input) {
14
- const { sessionId, executionId } = input;
14
+ const { executionId } = input;
15
+ // Warm runtimes and execution credentials may retain the bootstrap Session ID.
16
+ const sessionId = input.runtime.getAgentSessionById(input.sessionId)?.id;
15
17
  const execution = input.runtime.executionSnapshot(executionId);
16
18
  const prepared = input.coordinator.pending(executionId);
17
19
  const run = execution && input.runtime.getRun(execution.runId);
18
- if (!execution ||
20
+ if (!sessionId ||
21
+ !execution ||
19
22
  !prepared ||
20
23
  !run ||
21
24
  execution.sessionId !== sessionId ||
@@ -32,6 +32,7 @@ export function agentObservationFromRunEvent(input) {
32
32
  /** Volatile, session-owned delivery of live direct-child observations. */
33
33
  export class AgentNetworkObservations {
34
34
  #parents = new Map();
35
+ #waiters = new Map();
35
36
  attach(parentId) {
36
37
  if (this.#parents.has(parentId))
37
38
  throw new Error('AGENT_NETWORK_PARENT_ALREADY_ATTACHED');
@@ -49,11 +50,21 @@ export class AgentNetworkObservations {
49
50
  publish(input) {
50
51
  this.#parents.get(input.parentId)?.publish(input);
51
52
  }
52
- /** Direct children are automatic; other Sessions are watched only when explicitly targeted. */
53
+ /** Call-local observations never enter a Session's automatic context or wake channel. */
54
+ watchExecutions(targets) {
55
+ const observations = new ParentObservations(() => this.#waiters.delete(observations));
56
+ this.#waiters.set(observations, targets);
57
+ return observations;
58
+ }
59
+ /** Only direct children are automatic; other targets reach active, execution-scoped waits. */
53
60
  publishChild(input) {
54
- for (const [parentId, parent] of this.#parents) {
55
- if (parentId === input.parentId || parent.observes(input.childId))
56
- parent.publish(input);
61
+ if (input.parentId != null)
62
+ this.#parents.get(input.parentId)?.publish(input);
63
+ for (const [waiter, targets] of this.#waiters) {
64
+ if (targets.some((target) => target.agentId === input.childId &&
65
+ target.runId === input.runId &&
66
+ target.executionId === input.executionId))
67
+ waiter.publish(input);
57
68
  }
58
69
  }
59
70
  promote(previousId, nextId) {
@@ -74,19 +85,11 @@ export class ParentObservations {
74
85
  #results = new Map();
75
86
  #listeners = new Set();
76
87
  #wakeListeners = new Set();
77
- #targets = new Set();
78
88
  #revision = 0;
79
89
  #closed = false;
80
90
  constructor(detach) {
81
91
  this.detach = detach;
82
92
  }
83
- observe(childId) {
84
- if (!this.#closed)
85
- this.#targets.add(childId);
86
- }
87
- observes(childId) {
88
- return this.#targets.has(childId);
89
- }
90
93
  wake = {
91
94
  pending: () => [...this.#items.values()].some((item) => item.kind === 'message' && item.wakes !== false),
92
95
  subscribe: (listener) => {
@@ -302,7 +305,6 @@ export class ParentObservations {
302
305
  this.#results.clear();
303
306
  this.#listeners.clear();
304
307
  this.#wakeListeners.clear();
305
- this.#targets.clear();
306
308
  this.detach();
307
309
  }
308
310
  }
@@ -41,7 +41,8 @@ export class AgentNetworkService {
41
41
  goal
42
42
  }, signal);
43
43
  try {
44
- this.options.observe(actor, created.session);
44
+ if (created.session.parentSessionId === actor.sessionId)
45
+ this.options.observe(actor, created.session);
45
46
  return { agentId: created.session.id, start: created.result };
46
47
  }
47
48
  catch (error) {
@@ -106,7 +107,8 @@ export class AgentNetworkService {
106
107
  return { agentId: session.id, message: { status: 'accepted', result } };
107
108
  }
108
109
  signal?.throwIfAborted();
109
- this.options.observe(actor, session);
110
+ if (session.parentSessionId === actor.sessionId)
111
+ this.options.observe(actor, session);
110
112
  const approvalResult = input.approval === undefined
111
113
  ? undefined
112
114
  : await this.options.approval(actor, session, input.approval, signal);
@@ -281,22 +283,44 @@ export class AgentNetworkService {
281
283
  if (!targets.length)
282
284
  throw new Error('AGENT_EXECUTION_NOT_FOUND');
283
285
  const selected = new Set(targets.map((target) => target.agentId));
286
+ const directChildren = new Set();
284
287
  for (const session of sessions)
285
- if (selected.has(session.id))
288
+ if (selected.has(session.id) && session.parentSessionId === actor.sessionId) {
286
289
  this.options.observe(actor, session);
287
- const observations = this.options.observations.get(actor.observationId ?? actor.sessionId);
288
- if (!observations)
290
+ directChildren.add(session.id);
291
+ }
292
+ const parent = this.options.observations.get(actor.observationId ?? actor.sessionId);
293
+ if (directChildren.size && !parent)
289
294
  throw new Error('AGENT_OBSERVATION_UNAVAILABLE');
290
- return waitForAgentTargets({
291
- targets,
292
- observations,
293
- single: input.agentIds === undefined,
294
- waitMs: input.waitMs ?? 30_000,
295
- ...(input.mode === undefined ? {} : { mode: input.mode }),
296
- ...(input.waitFor === undefined ? {} : { waitFor: input.waitFor }),
297
- ...(input.signal === undefined ? {} : { signal: input.signal }),
298
- ...(input.interrupt === undefined ? {} : { interrupt: input.interrupt })
299
- });
295
+ const otherTargets = targets.filter((target) => !directChildren.has(target.agentId));
296
+ const temporary = otherTargets.length && input.waitMs !== 0
297
+ ? this.options.observations.watchExecutions(otherTargets)
298
+ : undefined;
299
+ try {
300
+ return await waitForAgentTargets({
301
+ targets,
302
+ observations: {
303
+ capture: (id, executionId) => (directChildren.has(id) ? parent : temporary)?.capture(id, executionId),
304
+ subscribe: (listener) => {
305
+ const unsubscribeParent = directChildren.size ? parent?.subscribe(listener) : undefined;
306
+ const unsubscribeTemporary = temporary?.subscribe(listener);
307
+ return () => {
308
+ unsubscribeParent?.();
309
+ unsubscribeTemporary?.();
310
+ };
311
+ }
312
+ },
313
+ single: input.agentIds === undefined,
314
+ waitMs: input.waitMs ?? 30_000,
315
+ ...(input.mode === undefined ? {} : { mode: input.mode }),
316
+ ...(input.waitFor === undefined ? {} : { waitFor: input.waitFor }),
317
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
318
+ ...(input.interrupt === undefined ? {} : { interrupt: input.interrupt })
319
+ });
320
+ }
321
+ finally {
322
+ temporary?.close();
323
+ }
300
324
  }
301
325
  }
302
326
  function sameGoal(left, right) {
@@ -180,6 +180,11 @@ export class GoalContinuationCoordinator {
180
180
  };
181
181
  }
182
182
  async start({ session, objective, initiatedByUserId, suppressNotifications, secretEnvironment, personalInstructions, executionContext, usageGrant, preserveActiveRun, messageIntent, messageContent, clientMessageId, messageOrigin, attachments, attachmentIds }) {
183
+ if (session.parentSessionId != null)
184
+ this.options
185
+ .runners()
186
+ .require(session.runner)
187
+ .assertChildModel(session.model, executionContext);
183
188
  this.invalidateGoalContinuation(session.id);
184
189
  const prepared = this.prepareGoalSession(session);
185
190
  const goalSession = prepared.session;
@@ -44,10 +44,14 @@ export class RunnerService {
44
44
  async listProfiles(data) {
45
45
  const input = data;
46
46
  const marAgent = this.runners.optional('mar-agent');
47
+ let marAgentProfile;
47
48
  if (marAgent !== undefined &&
48
49
  'configureModels' in marAgent &&
49
50
  typeof marAgent.configureModels === 'function')
50
- marAgent.configureModels(input.marAgentModels);
51
+ marAgentProfile = marAgent.configureModels(input.marAgentModels);
52
+ // Capture the request's display catalog before any asynchronous Runner refresh.
53
+ // This cache is not used for model admission.
54
+ const requestProfiles = (profiles) => profiles.map((profile) => profile.runner === 'mar-agent' && marAgentProfile !== undefined ? marAgentProfile : profile);
51
55
  const environment = parseSecretEnvironment(input.secretEnvironment);
52
56
  const defaults = this.database()
53
57
  .getRunnerDefaults()
@@ -71,12 +75,12 @@ export class RunnerService {
71
75
  if (cacheOnly) {
72
76
  void refresh.catch(() => undefined);
73
77
  return {
74
- profiles: this.profiles(environment),
78
+ profiles: requestProfiles(this.profiles(environment)),
75
79
  defaults
76
80
  };
77
81
  }
78
82
  return {
79
- profiles: await refresh,
83
+ profiles: requestProfiles(await refresh),
80
84
  defaults
81
85
  };
82
86
  }
@@ -1,4 +1,4 @@
1
- import { permissionStopSchema } from '@myagentroam/protocol';
1
+ import { appendExecutionPresentation, permissionStopSchema } from '@myagentroam/protocol';
2
2
  import { projectConversationWorkProcesses } from './work-process.js';
3
3
  function isRecord(value) {
4
4
  return typeof value === 'object' && value !== null;
@@ -293,6 +293,8 @@ export function mergeConversationItemPayload(existing, next) {
293
293
  if (next.append === 'output' &&
294
294
  isRecord(next.payload.output) &&
295
295
  typeof next.payload.output.text === 'string') {
296
+ if (next.payload.toolPresentation !== undefined)
297
+ value.toolPresentation = appendExecutionPresentation(base.toolPresentation, next.payload.toolPresentation);
296
298
  const prior = isRecord(base.output) && typeof base.output.text === 'string' ? base.output : undefined;
297
299
  const text = `${prior?.text ?? ''}${next.payload.output.text}`;
298
300
  value.output = {
@@ -168,7 +168,8 @@ export class SessionLifecycleService {
168
168
  }
169
169
  const environment = parseSecretEnvironment(input.secretEnvironment);
170
170
  const saved = database.getRunnerDefaults().find((value) => value.runner === runner.name);
171
- const fallback = runner.defaultConfiguration(workspace, environment);
171
+ const executionContext = runner.prepareExecutionContext(input);
172
+ const fallback = runner.defaultConfiguration(workspace, environment, executionContext);
172
173
  const configuration = {
173
174
  runner: runner.name,
174
175
  model: typeof input.model === 'string' ? input.model : (saved?.model ?? fallback.model),
@@ -182,7 +183,7 @@ export class SessionLifecycleService {
182
183
  if (runner.name === 'mar-agent' && !['auto', 'full-access'].includes(configuration.access))
183
184
  throw new Error('SESSION_INVALID');
184
185
  if (parentSessionId !== undefined)
185
- runner.assertChildModel(configuration.model);
186
+ runner.assertChildModel(configuration.model, executionContext);
186
187
  const session = this.options.runtime.createAgentSession({
187
188
  ...(parentSessionId === undefined ? {} : { parentSessionId }),
188
189
  workspaceId: input.workspaceId,
@@ -221,8 +222,10 @@ export class SessionLifecycleService {
221
222
  input.access !== undefined &&
222
223
  !['auto', 'full-access'].includes(input.access))
223
224
  throw new Error('SESSION_INVALID');
224
- if (current.parentSessionId != null && typeof input.model === 'string')
225
- this.options.runners.require(current.runner).assertChildModel(input.model);
225
+ if (current.parentSessionId != null && typeof input.model === 'string') {
226
+ const runner = this.options.runners.require(current.runner);
227
+ runner.assertChildModel(input.model, runner.prepareExecutionContext(input));
228
+ }
226
229
  const session = this.options.runtime.updateAgentSessionConfiguration({
227
230
  sessionId: current.id,
228
231
  ...(typeof input.model === 'string' ? { model: input.model } : {}),
@@ -143,10 +143,12 @@ export class SessionMessageService {
143
143
  idempotent: true,
144
144
  auditReceipt: auditReceipt(session, existing.kind === 'queue' ? 'QUEUE' : 'SEND', existing.kind === 'queue' ? existing.item.id : existing.run.id, existing.kind === 'queue' ? existing.item.id : undefined)
145
145
  };
146
- if (session.parentSessionId != null)
147
- this.options.runners.require(session.runner).assertChildModel(session.model);
148
146
  const executionContext = input[RUNNER_EXECUTION_CONTEXT] ??
149
147
  this.options.runners.require(session.runner).prepareExecutionContext(input);
148
+ if (session.parentSessionId != null)
149
+ this.options.runners
150
+ .require(session.runner)
151
+ .assertChildModel(session.model, executionContext);
150
152
  const sourceContent = withSessionMessageOrigin(content, input.__marctlOrigin, session.parentSessionId);
151
153
  const goalMessage = internalGoal || internalSchedule || internalRestore
152
154
  ? undefined
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.11.42",
3
+ "version": "0.11.43",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -38,10 +38,10 @@
38
38
  "sharp": "0.35.5",
39
39
  "ws": "^8.21.3",
40
40
  "zod": "4.4.3",
41
- "@myagentroam/agent": "0.11.42",
41
+ "@myagentroam/agent": "0.11.43",
42
+ "@myagentroam/marctl": "0.11.6",
42
43
  "@myagentroam/code-navigation": "0.11.1",
43
- "@myagentroam/marctl": "0.11.5",
44
- "@myagentroam/protocol": "0.11.42"
44
+ "@myagentroam/protocol": "0.11.43"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/ws": "^8.18.1"