@myagentroam/agent 0.11.38 → 0.11.40

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 (161) hide show
  1. package/dist/cli/catalog-file.d.ts +2 -0
  2. package/dist/cli/main.js +11 -4
  3. package/dist/cli/subagent/control.d.ts +56 -0
  4. package/dist/cli/subagent/control.js +219 -0
  5. package/dist/cli/subagent/history.d.ts +17 -0
  6. package/dist/cli/subagent/history.js +85 -0
  7. package/dist/cli/subagent/index.d.ts +10 -0
  8. package/dist/cli/subagent/index.js +94 -0
  9. package/dist/cli/subagent/native.d.ts +91 -0
  10. package/dist/cli/subagent/native.js +359 -0
  11. package/dist/cli/subagent/observations.d.ts +57 -0
  12. package/dist/cli/subagent/observations.js +351 -0
  13. package/dist/cli/subagent/query.d.ts +4 -0
  14. package/dist/cli/subagent/query.js +114 -0
  15. package/dist/cli/subagent/resources.d.ts +3 -0
  16. package/dist/cli/subagent/resources.js +112 -0
  17. package/dist/cli/subagent/snapshot.d.ts +77 -0
  18. package/dist/cli/subagent/snapshot.js +127 -0
  19. package/dist/cli/subagent/start.d.ts +24 -0
  20. package/dist/cli/subagent/start.js +201 -0
  21. package/dist/cli/subagent/wait-output.d.ts +19 -0
  22. package/dist/cli/subagent/wait-output.js +56 -0
  23. package/dist/cli/subagent/wait.d.ts +175 -0
  24. package/dist/cli/subagent/wait.js +453 -0
  25. package/dist/extensions/contracts.d.ts +2 -5
  26. package/dist/extensions/manager.d.ts +0 -2
  27. package/dist/extensions/manager.js +1 -2
  28. package/dist/extensions/models.d.ts +3 -0
  29. package/dist/extensions/operation.d.ts +8 -0
  30. package/dist/extensions/operation.js +3 -0
  31. package/dist/extensions/services.d.ts +9 -1
  32. package/dist/extensions/services.js +26 -3
  33. package/dist/extensions/session-context.d.ts +18 -0
  34. package/dist/extensions/session-context.js +4 -0
  35. package/dist/extensions/session-input.d.ts +2 -2
  36. package/dist/extensions/session-input.js +3 -4
  37. package/dist/extensions/session-messages.d.ts +1 -1
  38. package/dist/extensions/session-tools.js +20 -3
  39. package/dist/extensions/session.d.ts +1 -4
  40. package/dist/extensions/session.js +2 -16
  41. package/dist/extensions/tools.js +21 -3
  42. package/dist/extensions.d.ts +5 -2
  43. package/dist/extensions.js +2 -1
  44. package/dist/host/local-agent-host.d.ts +2 -2
  45. package/dist/host/local-exec-tool.d.ts +1 -1
  46. package/dist/host/local-exec-tool.js +28 -3
  47. package/dist/host/local-tool-registry.d.ts +2 -2
  48. package/dist/index.d.ts +2 -2
  49. package/dist/model/configuration.d.ts +3 -1
  50. package/dist/model/configuration.js +1 -0
  51. package/dist/model/openai-responses.js +5 -0
  52. package/dist/model/responses-request.js +9 -0
  53. package/dist/prompts/index.js +1 -3
  54. package/dist/prompts/resources.d.ts +1 -5
  55. package/dist/prompts/resources.js +3 -12
  56. package/dist/prompts/subagent.d.ts +1 -1
  57. package/dist/prompts/subagent.js +1 -1
  58. package/dist/runtime/context/gc-candidates-web.d.ts +6 -0
  59. package/dist/runtime/context/gc-candidates-web.js +53 -1
  60. package/dist/runtime/context/gc-candidates.js +1 -9
  61. package/dist/runtime/context/gc.js +19 -11
  62. package/dist/runtime/context/projection.js +1 -0
  63. package/dist/runtime/events.d.ts +4 -3
  64. package/dist/runtime/execution-handle.d.ts +2 -0
  65. package/dist/runtime/wait.js +12 -2
  66. package/dist/sdk/agent.js +94 -5
  67. package/dist/sdk/execution-context-coordinator.d.ts +2 -3
  68. package/dist/sdk/execution-context-coordinator.js +3 -3
  69. package/dist/sdk/execution-input.d.ts +3 -4
  70. package/dist/sdk/execution-input.js +31 -25
  71. package/dist/sdk/execution-round-preparation.d.ts +1 -1
  72. package/dist/sdk/execution-round-preparation.js +4 -4
  73. package/dist/sdk/execution-tool-catalog.js +2 -10
  74. package/dist/sdk/execution-tool-scope.d.ts +1 -3
  75. package/dist/sdk/execution-tool-scope.js +10 -12
  76. package/dist/sdk/extension-models.js +3 -0
  77. package/dist/sdk/extension-session-launch.d.ts +3 -2
  78. package/dist/sdk/extension-session-launch.js +2 -3
  79. package/dist/sdk/extension-tools.js +0 -2
  80. package/dist/sdk/native-steer.d.ts +2 -2
  81. package/dist/sdk/native-steer.js +2 -2
  82. package/dist/sdk/session-composition.d.ts +2 -17
  83. package/dist/sdk/session-execution-factory.d.ts +2 -3
  84. package/dist/sdk/session-execution-factory.js +20 -114
  85. package/dist/sdk/session-execution.d.ts +13 -7
  86. package/dist/sdk/session-execution.js +11 -3
  87. package/dist/sdk/session-extension-messages.d.ts +1 -3
  88. package/dist/sdk/session-extension-messages.js +14 -9
  89. package/dist/sdk/session-extension-prompt.js +1 -3
  90. package/dist/sdk/session-maintenance.d.ts +1 -0
  91. package/dist/sdk/session-maintenance.js +16 -7
  92. package/dist/sdk/session-open.d.ts +2 -3
  93. package/dist/sdk/session-open.js +5 -24
  94. package/dist/sdk/session-runtime.d.ts +19 -8
  95. package/dist/sdk/session-runtime.js +36 -30
  96. package/dist/sdk/session.d.ts +3 -2
  97. package/dist/sdk/session.js +22 -89
  98. package/dist/sdk/types.d.ts +36 -0
  99. package/dist/session/catalog.d.ts +22 -1
  100. package/dist/session/catalog.js +102 -0
  101. package/dist/session/context-gc-checkpoint.js +30 -1
  102. package/dist/session/context-gc-contract.d.ts +7 -0
  103. package/dist/session/context-gc-replacements.d.ts +3 -0
  104. package/dist/session/context-gc-replacements.js +26 -0
  105. package/dist/session/store/contracts.d.ts +2 -2
  106. package/dist/session/store/jsonl/directory-index.d.ts +1 -1
  107. package/dist/session/store/jsonl/directory-index.js +18 -17
  108. package/dist/session/store/jsonl/history.js +1 -1
  109. package/dist/session/store/jsonl/index-transaction.js +2 -8
  110. package/dist/session/store/jsonl/jsonl-store.d.ts +1 -1
  111. package/dist/session/store/jsonl/jsonl-store.js +24 -9
  112. package/dist/session/types.d.ts +1 -0
  113. package/dist/tools/agent/sleep.js +1 -1
  114. package/dist/tools/callers.js +1 -12
  115. package/dist/tools/code-mode/dispatch.js +5 -2
  116. package/dist/tools/code-mode/index.d.ts +1 -1
  117. package/dist/tools/code-mode/index.js +2 -0
  118. package/dist/tools/contracts.d.ts +20 -0
  119. package/dist/tools/execution-limits.d.ts +5 -20
  120. package/dist/tools/execution-limits.js +0 -2
  121. package/dist/tools/execution.js +16 -4
  122. package/dist/tools/local/exec.js +8 -2
  123. package/dist/tools/output-projection.d.ts +5 -2
  124. package/dist/tools/output-projection.js +133 -92
  125. package/dist/tools/registry.js +1 -13
  126. package/dist/tools/runtime-context.d.ts +1 -21
  127. package/package.json +2 -2
  128. package/dist/extensions/agents.d.ts +0 -100
  129. package/dist/extensions/agents.js +0 -121
  130. package/dist/runtime/context/gc-candidates-subagent.d.ts +0 -6
  131. package/dist/runtime/context/gc-candidates-subagent.js +0 -100
  132. package/dist/sdk/extension-agent-controller.d.ts +0 -3
  133. package/dist/sdk/extension-agent-controller.js +0 -69
  134. package/dist/sdk/extension-agents.d.ts +0 -9
  135. package/dist/sdk/extension-agents.js +0 -58
  136. package/dist/sdk/subagent-backend.d.ts +0 -3
  137. package/dist/sdk/subagent-backend.js +0 -49
  138. package/dist/subagent/contracts.d.ts +0 -107
  139. package/dist/subagent/contracts.js +0 -1
  140. package/dist/subagent/limits.d.ts +0 -17
  141. package/dist/subagent/limits.js +0 -17
  142. package/dist/subagent/model-update.d.ts +0 -2
  143. package/dist/subagent/model-update.js +0 -81
  144. package/dist/subagent/session-controller.d.ts +0 -87
  145. package/dist/subagent/session-controller.js +0 -1343
  146. package/dist/subagent/task.d.ts +0 -134
  147. package/dist/subagent/task.js +0 -436
  148. package/dist/subagent/turn-contracts.d.ts +0 -64
  149. package/dist/subagent/turn-contracts.js +0 -1
  150. package/dist/subagent/wait-targets.d.ts +0 -10
  151. package/dist/subagent/wait-targets.js +0 -26
  152. package/dist/subagent/wait.d.ts +0 -26
  153. package/dist/subagent/wait.js +0 -73
  154. package/dist/tools/agent/agent-cancel.d.ts +0 -7
  155. package/dist/tools/agent/agent-cancel.js +0 -29
  156. package/dist/tools/agent/agent-message.d.ts +0 -7
  157. package/dist/tools/agent/agent-message.js +0 -57
  158. package/dist/tools/agent/agent-start.d.ts +0 -12
  159. package/dist/tools/agent/agent-start.js +0 -106
  160. package/dist/tools/agent/agent-wait.d.ts +0 -7
  161. package/dist/tools/agent/agent-wait.js +0 -91
@@ -15,6 +15,10 @@ export class SessionExecution {
15
15
  kind;
16
16
  source;
17
17
  snapshot;
18
+ #observedTerminal;
19
+ get observedTerminal() {
20
+ return this.#observedTerminal;
21
+ }
18
22
  #contextInvalid = false;
19
23
  #contextFailure;
20
24
  #bindings;
@@ -227,10 +231,15 @@ export class SessionExecution {
227
231
  full.type === 'execution.cancelled')
228
232
  committedTerminal = this.persistedTerminal = true;
229
233
  }
234
+ if (full.type === 'execution.completed' ||
235
+ full.type === 'execution.failed' ||
236
+ full.type === 'execution.cancelled')
237
+ this.#observedTerminal = structuredClone(full);
230
238
  if (full.type === 'tool.output')
231
239
  this.events.pushIfWaiting(full);
232
240
  else
233
241
  this.events.push(full);
242
+ ports.observe?.(full);
234
243
  this.compactRequests.publish(full);
235
244
  try {
236
245
  await ports.publish?.(full);
@@ -363,7 +372,7 @@ export class SessionExecution {
363
372
  join() {
364
373
  return this.resultPromise;
365
374
  }
366
- handle(enqueueMessage) {
375
+ handle() {
367
376
  const owner = this;
368
377
  return {
369
378
  get persistedEvents() {
@@ -376,8 +385,7 @@ export class SessionExecution {
376
385
  this.events.discardIfUnobserved();
377
386
  return this.resultPromise;
378
387
  },
379
- cancel: () => owner.cancel(new AgentError('MAR_AGENT_CANCELLED', 'Execution was cancelled.')),
380
- enqueueMessage
388
+ cancel: () => owner.cancel(new AgentError('MAR_AGENT_CANCELLED', 'Execution was cancelled.'))
381
389
  };
382
390
  }
383
391
  cancel(reason) {
@@ -1,13 +1,11 @@
1
1
  import type { ExtensionSessionBackend } from '../extensions/session-input.js';
2
- import type { ExtensionAgentsBackend } from '../extensions/agents.js';
3
2
  import type { SessionStore } from '../session/store/contracts.js';
4
3
  import type { SessionRuntime } from './session-runtime.js';
5
4
  import type { ResolvedModelConfiguration } from './model-runtime.js';
6
5
  /** Reads either a live request snapshot or the authoritative Session history. */
7
6
  export declare function createSessionExtensionMessages(ports: {
8
7
  sessionId: string;
9
- store: Pick<SessionStore, 'readResource' | 'readInputImages' | 'readExecutionState' | 'readContextualWorldState'>;
10
- agents(): Pick<ExtensionAgentsBackend, 'inspect'> | undefined;
8
+ store: Pick<SessionStore, 'getSession' | 'executionConfiguration' | 'readResource' | 'readInputImages' | 'readExecutionState' | 'readContextualWorldState'>;
11
9
  runtime(id: string): Pick<SessionRuntime, 'execution' | 'contextualWorldState'> | undefined;
12
10
  models(): {
13
11
  models: ReadonlyMap<string, ResolvedModelConfiguration>;
@@ -5,19 +5,20 @@ import { latestContextualWorldStateGeneration, parsePersistedContextualWorldStat
5
5
  import { projectSessionRequestMessages } from './request-preparation.js';
6
6
  /** Reads either a live request snapshot or the authoritative Session history. */
7
7
  export function createSessionExtensionMessages(ports) {
8
- const { sessionId, store, agents, runtime, models } = ports;
8
+ const { sessionId, store, runtime, models } = ports;
9
9
  return async (input, call) => {
10
10
  const selection = normalizeSessionMessagesInput(input);
11
11
  call.signal.throwIfAborted();
12
12
  let target = sessionId;
13
- let targetModelId;
14
13
  if (selection.agentId !== undefined) {
15
- const backend = agents();
16
- if (!backend)
17
- throw new AgentError('MAR_AGENT_SESSION_INPUT_UNAVAILABLE', 'Session child message access is unavailable.');
18
- const child = await backend.inspect({ agentId: selection.agentId }, call);
19
- target = child.agentId;
20
- targetModelId = child.modelId;
14
+ const child = await store.getSession(selection.agentId).catch((error) => {
15
+ if (error instanceof AgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND')
16
+ throw new AgentError('MAR_AGENT_SUBAGENT_NOT_FOUND', 'Direct child Session not found.');
17
+ throw error;
18
+ });
19
+ if (child.source.parentSessionId !== sessionId)
20
+ throw new AgentError('MAR_AGENT_SUBAGENT_NOT_FOUND', 'Direct child Session not found.');
21
+ target = child.id;
21
22
  }
22
23
  call.signal.throwIfAborted();
23
24
  const targetRuntime = runtime(target);
@@ -36,8 +37,12 @@ export function createSessionExtensionMessages(ports) {
36
37
  return sessionMessagesPage(restored, selection);
37
38
  }
38
39
  const modelState = models();
40
+ const targetConfiguration = selection.view === 'request' && target !== sessionId
41
+ ? await store.executionConfiguration(target)
42
+ : undefined;
43
+ call.signal.throwIfAborted();
39
44
  const requestModel = selection.view === 'request'
40
- ? modelState.models.get(targetModelId ?? modelState.defaultModelId)
45
+ ? modelState.models.get(targetConfiguration?.modelId ?? modelState.defaultModelId)
41
46
  : undefined;
42
47
  if (selection.view === 'request' && !requestModel)
43
48
  throw new AgentError('MAR_AGENT_MODEL_DISABLED', 'Selected model is unavailable.');
@@ -19,9 +19,7 @@ export function createSessionExtensionPrompt(ports) {
19
19
  .filter((binding) => binding.available?.(call) !== false)
20
20
  .map((binding) => binding.definition)
21
21
  .filter((tool) => !(ports.source === 'subagent' &&
22
- (tool.agentScope === 'ROOT_ONLY' ||
23
- tool.name.startsWith('agent_') ||
24
- tool.name === 'question')) &&
22
+ (tool.agentScope === 'ROOT_ONLY' || tool.name === 'question')) &&
25
23
  !(tool.name === 'question' && mode !== 'plan') &&
26
24
  !(tool.name === 'view_image' && !model.inputCapabilities.includes('IMAGE')) &&
27
25
  !(['code_exec', 'code_exec_wait'].includes(tool.name) &&
@@ -20,6 +20,7 @@ export declare class SessionMaintenanceCoordinator {
20
20
  join(): Promise<void>;
21
21
  clear(id: string): Promise<void>;
22
22
  delete(id: string): Promise<void>;
23
+ deleteMembers(members: readonly string[]): Promise<void>;
23
24
  }
24
25
  /** Complete all independent stages, reporting the first authoritative failure. */
25
26
  export declare function completeAgentCleanup(steps: readonly (() => unknown | Promise<unknown>)[]): Promise<void>;
@@ -57,7 +57,6 @@ export class SessionMaintenanceCoordinator {
57
57
  () => this.extensions.retireSession(id),
58
58
  () => this.extensions.clearSession(id),
59
59
  () => runtime?.retireInputs(),
60
- () => runtime?.disposeSubagents(),
61
60
  () => closeModelAdapters(runtime === undefined
62
61
  ? []
63
62
  : runtime
@@ -84,8 +83,19 @@ export class SessionMaintenanceCoordinator {
84
83
  });
85
84
  }
86
85
  delete(id) {
86
+ return this.deleteMembers([id]);
87
+ }
88
+ deleteMembers(members) {
89
+ const requestedIds = [...members];
90
+ if (requestedIds.length === 0 ||
91
+ requestedIds.some((id) => typeof id !== 'string' || id.length === 0) ||
92
+ new Set(requestedIds).size !== requestedIds.length)
93
+ return Promise.reject(new AgentError('MAR_AGENT_SESSION_INVALID', 'Invalid Session maintenance members.'));
94
+ requestedIds.sort();
95
+ const id = requestedIds[0];
96
+ const signature = JSON.stringify(requestedIds);
87
97
  return this.#track(id, 'delete', async () => {
88
- const maintenance = await this.store.acquireSessionMaintenance(id, 'delete', this.writerOwner);
98
+ const maintenance = await this.store.acquireSessionMaintenance(id, 'delete', this.writerOwner, requestedIds);
89
99
  let failed = false;
90
100
  const ids = maintenance.sessionIds;
91
101
  for (const sessionId of ids)
@@ -119,7 +129,6 @@ export class SessionMaintenanceCoordinator {
119
129
  ...ids.map((sessionId) => () => this.extensions.retireSession(sessionId)),
120
130
  ...ids.map((sessionId) => () => this.extensions.clearSession(sessionId)),
121
131
  () => completeAgentCleanup(runtimes.map((runtime) => () => runtime.retireInputs())),
122
- () => completeAgentCleanup(runtimes.map((runtime) => () => runtime.disposeSubagents())),
123
132
  () => Promise.all(runtimes.map((runtime) => runtime.joinExecutions())),
124
133
  () => {
125
134
  for (const sessionId of ids) {
@@ -157,25 +166,25 @@ export class SessionMaintenanceCoordinator {
157
166
  }
158
167
  }
159
168
  }
160
- });
169
+ }, signature);
161
170
  }
162
171
  #invalidate(ids) {
163
172
  for (const id of ids)
164
173
  this.#epochs.set(id, this.epoch(id) + 1);
165
174
  }
166
- #track(id, kind, operation) {
175
+ #track(id, kind, operation, signature = '') {
167
176
  if (this.disposed())
168
177
  return Promise.reject(new AgentError('MAR_AGENT_DISPOSED', 'Agent is disposed.'));
169
178
  const current = this.#operations.get(id);
170
179
  if (current)
171
- return current.kind === kind
180
+ return current.kind === kind && current.signature === signature
172
181
  ? current.pending
173
182
  : Promise.reject(new AgentError('MAR_AGENT_SESSION_CLOSING', 'Session is closing.'));
174
183
  if (this.#treeAdmissions.has(id))
175
184
  return Promise.reject(new AgentError('MAR_AGENT_SESSION_CLOSING', 'Session is closing.'));
176
185
  const completion = Promise.withResolvers();
177
186
  const pending = completion.promise.finally(() => this.#operations.delete(id));
178
- this.#operations.set(id, { kind, pending });
187
+ this.#operations.set(id, { kind, signature, pending });
179
188
  void pending.catch(() => undefined);
180
189
  try {
181
190
  completion.resolve(operation());
@@ -1,8 +1,7 @@
1
1
  import type { ModelAdapter } from '../model/contracts.js';
2
2
  import type { SessionStore } from '../session/store/contracts.js';
3
- import type { SubagentSessionController } from '../subagent/session-controller.js';
4
3
  import type { ResolvedModelConfiguration } from './model-runtime.js';
5
- import { type SessionRegistry } from './session-registry.js';
4
+ import type { SessionRegistry } from './session-registry.js';
6
5
  import { SessionRuntime } from './session-runtime.js';
7
6
  type StoredSession = Awaited<ReturnType<SessionStore['getSession']>>;
8
7
  interface SessionOpenPorts<Handle> {
@@ -11,7 +10,7 @@ interface SessionOpenPorts<Handle> {
11
10
  readonly generation: () => number;
12
11
  readonly createAdapter: (id: string, models: ReadonlyMap<string, ResolvedModelConfiguration>) => ModelAdapter;
13
12
  readonly hasCustomAdapters: boolean;
14
- readonly openSubagents: (id: string, workspace: string) => Promise<SubagentSessionController>;
13
+ readonly onExecutionRegistered: (runtime: SessionRuntime) => void;
15
14
  readonly assertAdmission: (id: string) => void;
16
15
  readonly epoch: (id: string) => number;
17
16
  readonly canPublish: (id: string, epoch: number) => boolean;
@@ -1,5 +1,4 @@
1
1
  import { AgentError } from '../error.js';
2
- import { SessionOpenCleanupError } from './session-registry.js';
3
2
  import { SessionRuntime } from './session-runtime.js';
4
3
  /** The open flow owns unpublished candidates; the registry owns only identity and barriers. */
5
4
  export function createSessionOpen(ports) {
@@ -9,35 +8,17 @@ export function createSessionOpen(ports) {
9
8
  return ports.registry.trackOpen(id, async () => {
10
9
  const runtime = await ports.registry.getOrCreate(id, epoch, () => ports.canPublish(id, epoch), async (publish) => {
11
10
  const stored = await ports.getSession(id);
12
- const candidate = new SessionRuntime(stored, ports.generation(), ports.createAdapter, ports.hasCustomAdapters);
13
- try {
14
- if (stored.source.type === 'user')
15
- await candidate.ensureSubagents(() => ports.openSubagents(id, stored.workspace));
16
- ports.createHandle(id, candidate, stored, workspace);
17
- if (!publish(candidate))
18
- throw new AgentError('MAR_AGENT_SESSION_CLOSING', 'Session is closing.');
19
- return candidate;
20
- }
21
- catch (error) {
22
- try {
23
- await candidate.disposeSubagents();
24
- }
25
- catch (cleanupError) {
26
- throw new SessionOpenCleanupError(cleanupError);
27
- }
28
- throw error;
29
- }
11
+ const candidate = new SessionRuntime(stored, ports.generation(), ports.createAdapter, ports.hasCustomAdapters, ports.onExecutionRegistered);
12
+ ports.createHandle(id, candidate, stored, workspace);
13
+ if (!publish(candidate))
14
+ throw new AgentError('MAR_AGENT_SESSION_CLOSING', 'Session is closing.');
15
+ return candidate;
30
16
  });
31
17
  ports.assertAdmission(id);
32
18
  const stored = await ports.getSession(id);
33
19
  ports.assertAdmission(id);
34
20
  if (!ports.canPublish(id, epoch))
35
21
  throw new AgentError('MAR_AGENT_SESSION_CLOSING', 'Session is closing.');
36
- if (stored.source.type === 'user' && runtime.subagents === undefined) {
37
- await runtime.ensureSubagents(() => ports.openSubagents(id, stored.workspace));
38
- if (!ports.canPublish(id, epoch))
39
- throw new AgentError('MAR_AGENT_SESSION_CLOSING', 'Session is closing.');
40
- }
41
22
  return ports.createHandle(id, runtime, stored, workspace);
42
23
  });
43
24
  };
@@ -1,21 +1,21 @@
1
1
  import { ExtensionRequestSnapshots, type ExtensionRequestSnapshot } from '../extensions/model-request.js';
2
2
  import type { ExtensionSessionBackend, SessionInputCoordinator } from '../extensions/session-input.js';
3
- import type { ExtensionAgentsBackend } from '../extensions/agents.js';
4
3
  import type { ModelAdapter } from '../model/contracts.js';
5
4
  import type { ModelCredentialProvider } from '../model/configuration.js';
6
5
  import type { SessionModelRequest as ModelRequest } from '../session/model-request.js';
7
6
  import type { SessionStore } from '../session/store/contracts.js';
8
7
  import { type ContextualWorldState } from '../runtime/context/world-state.js';
9
- import type { SubagentSessionController } from '../subagent/session-controller.js';
10
8
  import { TodoStore } from '../tools/agent/todo.js';
11
9
  import type { ExecutionResult } from './types.js';
10
+ import type { AgentEvent } from '../runtime/events.js';
12
11
  import type { ResolvedModelConfiguration } from './model-runtime.js';
13
12
  import type { SessionExecution, SessionExecutionContext } from './session-execution.js';
14
13
  export declare class SessionRuntime {
15
14
  #private;
16
15
  readonly storedSession: Awaited<ReturnType<SessionStore['getSession']>>;
16
+ readonly onExecutionRegistered: (runtime: SessionRuntime) => void;
17
17
  readonly scheduleTool: <T>(definition: import("../host.js").ClientToolDefinition | undefined, run: () => Promise<T>) => Promise<T>;
18
- constructor(storedSession: Awaited<ReturnType<SessionStore['getSession']>>, generation: number, createAdapter: (modelId: string, models: ReadonlyMap<string, ResolvedModelConfiguration>) => ModelAdapter, hasCustomAdapters: boolean);
18
+ constructor(storedSession: Awaited<ReturnType<SessionStore['getSession']>>, generation: number, createAdapter: (modelId: string, models: ReadonlyMap<string, ResolvedModelConfiguration>) => ModelAdapter, hasCustomAdapters: boolean, onExecutionRegistered?: (runtime: SessionRuntime) => void);
19
19
  adapter(modelId: string, models: ReadonlyMap<string, ResolvedModelConfiguration>): ModelAdapter;
20
20
  refreshAdapters(generation: number, retained: ReadonlySet<ModelAdapter>): Promise<void>;
21
21
  static stageModelReconfiguration(sessions: readonly SessionRuntime[], models: ReadonlyMap<string, ResolvedModelConfiguration>, active: ReadonlySet<ModelAdapter>, assertOpen: () => void): Promise<(generation: number) => void>;
@@ -26,9 +26,6 @@ export declare class SessionRuntime {
26
26
  static closeModelAdapters(sessions: readonly SessionRuntime[]): Promise<void>;
27
27
  retireInputs(): Promise<unknown> | undefined;
28
28
  getOrCreateInputs(create: () => SessionInputCoordinator): SessionInputCoordinator;
29
- disposeSubagents(): Promise<unknown> | undefined;
30
- get subagents(): SubagentSessionController | undefined;
31
- ensureSubagents(open: () => Promise<SubagentSessionController>): Promise<SubagentSessionController>;
32
29
  resetAfterClear(generation: number): void;
33
30
  recordRequest(modelId: string, request: ModelRequest): ExtensionRequestSnapshot;
34
31
  completeRequest(snapshot: ExtensionRequestSnapshot): void;
@@ -54,19 +51,33 @@ export declare class SessionRuntime {
54
51
  ensureSessionBackend(create: () => ExtensionSessionBackend & {
55
52
  kick(): void;
56
53
  }): void;
57
- get agentsBackend(): ExtensionAgentsBackend | undefined;
58
- ensureAgentsBackend(create: () => ExtensionAgentsBackend): void;
59
54
  get execution(): SessionExecutionContext | undefined;
60
55
  bindExecutionContext(context: SessionExecutionContext): void;
61
56
  unbindExecutionContext(context: SessionExecutionContext): void;
62
57
  get contextualWorldState(): ContextualWorldState | undefined;
63
58
  updateContextualWorldState(state: ContextualWorldState): void;
64
59
  get activeExecutionId(): string | undefined;
60
+ subscribe(listener: (event: AgentEvent) => void): {
61
+ unsubscribe: () => void;
62
+ terminalEvent?: (import("./types.js").AgentEventBase & {
63
+ type: "execution.completed";
64
+ permissionStop?: import("../host.js").PermissionStop;
65
+ }) | (import("./types.js").AgentEventBase & {
66
+ type: "execution.failed";
67
+ code: string;
68
+ message?: string;
69
+ }) | (import("./types.js").AgentEventBase & {
70
+ type: "execution.cancelled";
71
+ });
72
+ activeExecutionId?: string;
73
+ };
74
+ publishEvent(event: AgentEvent): void;
65
75
  assertCanExecute(): void;
66
76
  registerExecution(execution: SessionExecution): void;
67
77
  deactivateExecution(execution: SessionExecution): void;
68
78
  unregisterExecution(execution: SessionExecution): void;
69
79
  cancelExecution(executionId: string): void;
80
+ joinExecution(executionId: string): Promise<ExecutionResult> | undefined;
70
81
  cancelExecutions(): void;
71
82
  joinExecutions(): Promise<PromiseSettledResult<ExecutionResult>[]>;
72
83
  }
@@ -6,22 +6,22 @@ import { createSessionToolScheduler } from '../tools/scheduler.js';
6
6
  import { SessionModelAdapters } from './session-model-adapters.js';
7
7
  export class SessionRuntime {
8
8
  storedSession;
9
+ onExecutionRegistered;
9
10
  #executionContext;
10
11
  #todo;
11
12
  scheduleTool = createSessionToolScheduler();
12
13
  #modelAdapters;
13
14
  #contextualWorldState;
14
- #subagents;
15
- #subagentsOpening;
16
15
  #inputs;
17
16
  #requestSnapshots;
18
17
  #recordProjection;
19
18
  #sessionBackend;
20
- #agentsBackend;
21
19
  #executions = new Map();
22
20
  #activeExecutionId;
23
- constructor(storedSession, generation, createAdapter, hasCustomAdapters) {
21
+ #eventObservers = new Set();
22
+ constructor(storedSession, generation, createAdapter, hasCustomAdapters, onExecutionRegistered = () => { }) {
24
23
  this.storedSession = storedSession;
24
+ this.onExecutionRegistered = onExecutionRegistered;
25
25
  this.#modelAdapters = new SessionModelAdapters(generation, createAdapter, hasCustomAdapters);
26
26
  }
27
27
  adapter(modelId, models) {
@@ -54,29 +54,9 @@ export class SessionRuntime {
54
54
  getOrCreateInputs(create) {
55
55
  return (this.#inputs ??= create());
56
56
  }
57
- disposeSubagents() {
58
- return this.#subagents?.dispose();
59
- }
60
- get subagents() {
61
- return this.#subagents;
62
- }
63
- async ensureSubagents(open) {
64
- if (this.#subagents)
65
- return this.#subagents;
66
- const pending = (this.#subagentsOpening ??= open());
67
- try {
68
- return (this.#subagents = await pending);
69
- }
70
- finally {
71
- if (this.#subagentsOpening === pending)
72
- this.#subagentsOpening = undefined;
73
- }
74
- }
75
57
  resetAfterClear(generation) {
76
58
  this.#modelAdapters.setGeneration(generation);
77
59
  this.#todo = undefined;
78
- this.#subagents = undefined;
79
- this.#subagentsOpening = undefined;
80
60
  this.#contextualWorldState = undefined;
81
61
  this.#inputs = undefined;
82
62
  this.#requestSnapshots = undefined;
@@ -146,12 +126,6 @@ export class SessionRuntime {
146
126
  ensureSessionBackend(create) {
147
127
  this.#sessionBackend ??= create();
148
128
  }
149
- get agentsBackend() {
150
- return this.#agentsBackend;
151
- }
152
- ensureAgentsBackend(create) {
153
- this.#agentsBackend ??= create();
154
- }
155
129
  get execution() {
156
130
  return this.#executionContext;
157
131
  }
@@ -171,6 +145,34 @@ export class SessionRuntime {
171
145
  get activeExecutionId() {
172
146
  return this.#activeExecutionId;
173
147
  }
148
+ subscribe(listener) {
149
+ const observer = (event) => listener(structuredClone(event));
150
+ this.#eventObservers.add(observer);
151
+ const terminal = this.#activeExecutionId === undefined
152
+ ? undefined
153
+ : this.#executions.get(this.#activeExecutionId)?.observedTerminal;
154
+ return {
155
+ ...(this.#activeExecutionId === undefined
156
+ ? {}
157
+ : { activeExecutionId: this.#activeExecutionId }),
158
+ ...(terminal === undefined ? {} : { terminalEvent: structuredClone(terminal) }),
159
+ unsubscribe: () => {
160
+ this.#eventObservers.delete(observer);
161
+ }
162
+ };
163
+ }
164
+ publishEvent(event) {
165
+ for (const listener of [...this.#eventObservers]) {
166
+ if (!this.#eventObservers.has(listener))
167
+ continue;
168
+ try {
169
+ listener(event);
170
+ }
171
+ catch {
172
+ /* Observers cannot change the owning Execution. */
173
+ }
174
+ }
175
+ }
174
176
  assertCanExecute() {
175
177
  if (this.#activeExecutionId !== undefined)
176
178
  throw new AgentError('MAR_AGENT_EXECUTION_ACTIVE', 'Session already has an active execution.');
@@ -179,6 +181,7 @@ export class SessionRuntime {
179
181
  this.assertCanExecute();
180
182
  this.#executions.set(execution.executionId, execution);
181
183
  this.#activeExecutionId = execution.executionId;
184
+ this.onExecutionRegistered(this);
182
185
  }
183
186
  deactivateExecution(execution) {
184
187
  if (this.#executions.get(execution.executionId) === execution &&
@@ -192,6 +195,9 @@ export class SessionRuntime {
192
195
  cancelExecution(executionId) {
193
196
  this.#executions.get(executionId)?.cancel();
194
197
  }
198
+ joinExecution(executionId) {
199
+ return this.#executions.get(executionId)?.join();
200
+ }
195
201
  cancelExecutions() {
196
202
  for (const execution of this.#executions.values())
197
203
  execution.cancel();
@@ -1,3 +1,4 @@
1
- import type { InternalAgentSession, SessionServices } from './session-composition.js';
1
+ import type { SessionServices } from './session-composition.js';
2
+ import type { AgentSession } from './types.js';
2
3
  /** SDK Session orchestration owns warm resources; Runtime owns only the model/tool loop. */
3
- export declare function createSessionOpener(services: SessionServices): (id: string, workspace?: string) => Promise<InternalAgentSession>;
4
+ export declare function createSessionOpener(services: SessionServices): (id: string, workspace?: string) => Promise<AgentSession>;
@@ -2,21 +2,15 @@ import { createExtensionSessionLaunch, extensionInputSource } from './extension-
2
2
  import { createSessionExecutionFactory } from './session-execution-factory.js';
3
3
  import { createSessionExtensionMessages } from './session-extension-messages.js';
4
4
  import { createSessionExtensionPrompt } from './session-extension-prompt.js';
5
- import { createSubagentBackend } from './subagent-backend.js';
6
5
  import { AgentError } from '../error.js';
7
6
  import { SessionInputCoordinator, recordSessionInputCommit } from '../extensions/session-input.js';
8
7
  import { buildSystemPromptSections } from '../prompts/index.js';
9
8
  import { childSubagentInstruction } from '../prompts/subagent.js';
10
9
  import { DEFAULT_COMPACTION_FOCUS } from '../runtime/compaction/history.js';
11
10
  import { restoreEnvironmentState } from '../runtime/context/environment.js';
12
- import { SubagentSessionController } from '../subagent/session-controller.js';
13
11
  import { allowsDirectTool } from '../tools/callers.js';
14
- import { createExtensionAgentsBackend } from './extension-agents.js';
15
12
  import { createExtensionSessionBackend } from './extension-session.js';
16
13
  import { createSessionOpen } from './session-open.js';
17
- function restoreSubagentOrigin(origin) {
18
- return { ...origin.correlation, signal: origin.signal };
19
- }
20
14
  /** SDK Session orchestration owns warm resources; Runtime owns only the model/tool loop. */
21
15
  export function createSessionOpener(services) {
22
16
  const { host, description, settings, store, createAdapter, activeAdaptersExcept } = services;
@@ -27,11 +21,7 @@ export function createSessionOpener(services) {
27
21
  generation: () => services.modelState().generation,
28
22
  createAdapter,
29
23
  hasCustomAdapters: services.hasCustomAdapters,
30
- openSubagents: (id, workspace) => SubagentSessionController.open({
31
- parentSessionId: id,
32
- rootSessionId: id,
33
- backend: createSubagentBackend(store, workspace)
34
- }),
24
+ onExecutionRegistered: services.agentResources.onExecutionRegistered,
35
25
  assertAdmission: services.assertSessionAdmission,
36
26
  epoch: services.openEpoch,
37
27
  canPublish: services.canPublishSession,
@@ -149,8 +139,7 @@ export function createSessionOpener(services) {
149
139
  refreshSessionAdapters,
150
140
  sessionInputs,
151
141
  withRecordProjection,
152
- appendExtensionMessage,
153
- startSubagentTurn: async (id, input) => (await openSession(id)).startSubagentTurn(input)
142
+ appendExtensionMessage
154
143
  });
155
144
  sessionRuntime.ensureSessionBackend(() => createExtensionSessionBackend({
156
145
  describe: async (call) => {
@@ -200,70 +189,32 @@ export function createSessionOpener(services) {
200
189
  messages: createSessionExtensionMessages({
201
190
  sessionId,
202
191
  store,
203
- agents: () => sessionRuntime.agentsBackend,
204
192
  runtime: (id) => sessionRuntimes.get(id),
205
193
  models: () => services.modelState()
206
194
  }),
207
- launch: createExtensionSessionLaunch(sessionSource.type, execution),
195
+ launch: createExtensionSessionLaunch(execution),
208
196
  diagnose: (code, operationId) => services.extensions.session(sessionId)?.diagnose({ code, operationId, sessionId })
209
197
  }));
210
- if (sessionSource.type === 'user')
211
- sessionRuntime.ensureAgentsBackend(() => createExtensionAgentsBackend({
212
- existingController: () => sessionRuntime.subagents,
213
- controller: async () => {
214
- // Access to managed children is not a new Execution admission for their parent.
215
- services.assertCanStart();
216
- if (sessionRuntime.subagents === undefined)
217
- await openSession(sessionId);
218
- if (!sessionRuntime.subagents)
219
- throw new AgentError('MAR_AGENT_SUBAGENT_FAILED', 'Session task controller is unavailable.');
220
- return sessionRuntime.subagents;
221
- },
222
- parent: (controller, call) => {
223
- const current = call.executionId === undefined
224
- ? undefined
225
- : controller.parentExecution(call.executionId);
226
- if (call.executionId !== undefined && !current)
227
- throw new AgentError('MAR_AGENT_SUBAGENT_FAILED', 'Parent Execution source is unavailable.');
228
- const state = services.modelState();
229
- const selected = state.models.get(state.defaultModelId);
230
- return {
231
- ...(current ?? {
232
- modelId: selected.id,
233
- reasoningEffort: selected.defaultReasoningEffort,
234
- models: state.models,
235
- emitTerminal: async () => { },
236
- startTurn: async (turn) => {
237
- const child = await openSession(turn.sessionId);
238
- return child.startSubagentTurn({
239
- prompt: turn.prompt,
240
- modelId: turn.modelId,
241
- reasoningEffort: turn.reasoningEffort,
242
- role: turn.role,
243
- initialMailbox: turn.initialMailbox,
244
- turnId: turn.turnId,
245
- ...(turn.origin === undefined
246
- ? {}
247
- : { origin: restoreSubagentOrigin(turn.origin) }),
248
- ...(turn.delivery === undefined ? {} : { delivery: turn.delivery })
249
- });
250
- }
251
- }),
252
- operationId: call.operationId,
253
- origin: { signal: call.signal, correlation: call },
254
- signal: call.signal,
255
- ...(call.ownerInstanceId === undefined
256
- ? {}
257
- : { ownerInstanceId: call.ownerInstanceId }),
258
- ...(call.extensionId === undefined ? {} : { extensionId: call.extensionId })
259
- };
260
- }
261
- }));
198
+ const inputSource = () => {
199
+ const current = services.extensions.operations.current();
200
+ return current && current.sessionId !== sessionId && current.extensionId
201
+ ? extensionInputSource(current)
202
+ : undefined;
203
+ };
204
+ const inputOptions = () => {
205
+ const source = inputSource();
206
+ return source ? { extensionSource: source } : {};
207
+ };
262
208
  return {
263
209
  id: sessionId,
264
- run: (input) => execution('run', input),
265
- plan: (input) => execution('plan', input),
266
- steer: (input) => sessionRuntime.execution?.steer?.(input) ?? Promise.resolve({ status: 'notAccepted' }),
210
+ subscribe: (listener) => {
211
+ services.assertSessionAdmission(sessionId);
212
+ return sessionRuntime.subscribe(listener);
213
+ },
214
+ run: (input) => execution('run', input, input.clientMessageId ? inputOptions() : undefined),
215
+ plan: (input) => execution('plan', input, input.clientMessageId ? inputOptions() : undefined),
216
+ steer: (input) => sessionRuntime.execution?.steer?.(input, inputSource()) ??
217
+ Promise.resolve({ status: 'notAccepted' }),
267
218
  compact: (input = {}) => {
268
219
  const requests = sessionRuntime.execution?.compactRequests;
269
220
  if (requests) {
@@ -276,25 +227,7 @@ export function createSessionOpener(services) {
276
227
  });
277
228
  },
278
229
  cancel: async (executionId) => sessionRuntime.cancelExecution(executionId),
279
- startSubagentTurn: (turn) => execution(turn.role === 'explore' ? 'plan' : 'run', {
280
- prompt: turn.prompt,
281
- modelId: turn.modelId,
282
- reasoningEffort: turn.reasoningEffort,
283
- ...(turn.permissionMode === undefined ? {} : { permissionMode: turn.permissionMode })
284
- }, {
285
- publishHostEvents: false,
286
- ...(turn.origin === undefined ? {} : { signal: turn.origin.signal }),
287
- inputSource: turn.origin === undefined ? 'parent_agent' : 'extension',
288
- ...(turn.origin === undefined
289
- ? {}
290
- : { extensionSource: extensionInputSource(turn.origin) }),
291
- initialMailbox: turn.initialMailbox,
292
- turnId: turn.turnId,
293
- ...(turn.mcpExecutionScopeId === undefined
294
- ? {}
295
- : { mcpExecutionScopeId: turn.mcpExecutionScopeId }),
296
- ...(turn.delivery ? { delivery: turn.delivery } : {})
297
- })
230
+ joinExecution: (executionId) => sessionRuntime.joinExecution(executionId)
298
231
  };
299
232
  };
300
233
  return openSession;