@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
@@ -0,0 +1,127 @@
1
+ export function boundedUtf8(value, maxBytes) {
2
+ const bytes = Buffer.from(value, 'utf8');
3
+ if (bytes.length <= maxBytes)
4
+ return { value, truncated: false };
5
+ let end = maxBytes;
6
+ while (end > 0 && (bytes[end] & 0xc0) === 0x80)
7
+ end--;
8
+ return { value: bytes.subarray(0, end).toString('utf8'), truncated: true };
9
+ }
10
+ export function projectChildEvent(snapshot, event, full = false) {
11
+ if (event.type === 'execution.failed' || event.type === 'execution.cancelled') {
12
+ delete snapshot.summary;
13
+ delete snapshot.summaryTruncated;
14
+ }
15
+ if (full && event.type === 'message.completed') {
16
+ snapshot.latestMessage = {
17
+ itemId: event.itemId,
18
+ turnId: event.turnId ?? '',
19
+ phase: event.phase,
20
+ text: event.text,
21
+ timestamp: event.timestamp,
22
+ truncated: false
23
+ };
24
+ snapshot.latestActivity = { kind: 'message', timestamp: event.timestamp, phase: event.phase };
25
+ }
26
+ else if (full &&
27
+ (event.type === 'tool.started' ||
28
+ event.type === 'tool.completed' ||
29
+ event.type === 'tool.failed')) {
30
+ snapshot.latestActivity = {
31
+ kind: 'tool',
32
+ timestamp: event.timestamp,
33
+ toolName: event.toolName,
34
+ status: event.type === 'tool.started'
35
+ ? 'started'
36
+ : event.type === 'tool.completed'
37
+ ? 'completed'
38
+ : 'failed'
39
+ };
40
+ if (event.type === 'tool.completed' && event.toolName === 'exec') {
41
+ (snapshot.verification ??= []).push(event.summary);
42
+ }
43
+ else if (event.type === 'tool.completed' &&
44
+ event.toolName === 'read' &&
45
+ event.data &&
46
+ 'results' in event.data &&
47
+ Array.isArray(event.data.results)) {
48
+ for (const result of event.data.results) {
49
+ if (!result ||
50
+ typeof result !== 'object' ||
51
+ typeof result.path !== 'string' ||
52
+ result.error !== undefined)
53
+ continue;
54
+ const positive = (value) => typeof value === 'number' && Number.isInteger(value) && value >= 1;
55
+ const evidence = {
56
+ path: result.path,
57
+ ...(positive(result.startLine) ? { startLine: result.startLine } : {}),
58
+ ...(positive(result.endLine) ? { endLine: result.endLine } : {})
59
+ };
60
+ const entries = (snapshot.evidence ??= []);
61
+ if (!entries.some((item) => item.path === evidence.path &&
62
+ item.startLine === evidence.startLine &&
63
+ item.endLine === evidence.endLine))
64
+ entries.push(evidence);
65
+ }
66
+ }
67
+ }
68
+ if (event.type === 'message.completed' && event.phase === 'final_answer') {
69
+ const summary = full
70
+ ? { value: event.text, truncated: false }
71
+ : boundedUtf8(event.text, 16_384);
72
+ snapshot.summary = summary.value;
73
+ if (summary.truncated)
74
+ snapshot.summaryTruncated = true;
75
+ else
76
+ delete snapshot.summaryTruncated;
77
+ if (event.turnId)
78
+ snapshot.turnId = event.turnId;
79
+ else
80
+ delete snapshot.turnId;
81
+ }
82
+ if (event.type !== 'tool.completed' ||
83
+ event.toolName !== 'apply_patch' ||
84
+ !event.data ||
85
+ !('files' in event.data) ||
86
+ !Array.isArray(event.data.files))
87
+ return;
88
+ for (const file of event.data.files) {
89
+ if (typeof file !== 'object' || file === null)
90
+ continue;
91
+ for (const candidate of [
92
+ file.path,
93
+ file.targetPath
94
+ ]) {
95
+ if (typeof candidate !== 'string' || !candidate || snapshot.changedFiles.includes(candidate))
96
+ continue;
97
+ if (!full && snapshot.changedFiles.length >= 200) {
98
+ snapshot.changedFilesTruncated = true;
99
+ continue;
100
+ }
101
+ snapshot.changedFiles.push(candidate);
102
+ }
103
+ }
104
+ }
105
+ export function publicChildSnapshot(snapshot) {
106
+ if (!snapshot)
107
+ return {};
108
+ return {
109
+ ...(snapshot.summary === undefined ? {} : { summary: snapshot.summary }),
110
+ ...(snapshot.summaryTruncated ? { summaryTruncated: true } : {}),
111
+ ...(snapshot.turnId ? { turnId: snapshot.turnId } : {}),
112
+ ...(snapshot.changedFiles.length ? { changedFiles: [...snapshot.changedFiles] } : {}),
113
+ ...(snapshot.changedFilesTruncated ? { changedFilesTruncated: true } : {})
114
+ };
115
+ }
116
+ /** Full native details are never included in model-facing projections. */
117
+ export function nativeChildSnapshot(snapshot) {
118
+ return {
119
+ ...publicChildSnapshot(snapshot),
120
+ ...(snapshot?.latestMessage ? { latestMessage: { ...snapshot.latestMessage } } : {}),
121
+ ...(snapshot?.latestActivity ? { latestActivity: { ...snapshot.latestActivity } } : {}),
122
+ ...(snapshot?.verification?.length ? { verification: [...snapshot.verification] } : {}),
123
+ ...(snapshot?.evidence?.length
124
+ ? { evidence: snapshot.evidence.map((item) => ({ ...item })) }
125
+ : {})
126
+ };
127
+ }
@@ -0,0 +1,24 @@
1
+ import { type Agent, type AgentReasoningEffort, type ExecutionHandle } from '@myagentroam/agent';
2
+ import type { ExtensionOperationContext, SessionExtensionContext } from '@myagentroam/agent/extensions';
3
+ export interface StartInput {
4
+ readonly description: string;
5
+ readonly title?: string;
6
+ readonly prompt: string;
7
+ readonly role: 'general-purpose' | 'explore';
8
+ readonly modelId?: string;
9
+ readonly reasoningEffort?: AgentReasoningEffort;
10
+ readonly turnSignal?: AbortSignal;
11
+ }
12
+ /** Admission reservations are bounded quota accounting, not Execution state. */
13
+ export declare class StartAdmission {
14
+ #private;
15
+ finish(executionId: string): void;
16
+ reserve(agent: Agent, parentSessionId: string, executionId: string): (created: boolean) => void;
17
+ reserveResume(agent: Agent, parentSessionId: string): () => void;
18
+ }
19
+ export declare function registerStart(context: SessionExtensionContext, agent: Agent, admission: StartAdmission): void;
20
+ /** Both adapters enter this Session-owned creation path with their actual Core operation. */
21
+ export declare function startChild(context: SessionExtensionContext, agent: Agent, admission: StartAdmission, input: StartInput, call: ExtensionOperationContext, mode: 'model' | 'native'): Promise<{
22
+ data: Record<string, unknown>;
23
+ execution?: ExecutionHandle;
24
+ }>;
@@ -0,0 +1,201 @@
1
+ import { AgentError } from '@myagentroam/agent';
2
+ /** Admission reservations are bounded quota accounting, not Execution state. */
3
+ export class StartAdmission {
4
+ #pending = new Map();
5
+ #perExecution = new Map();
6
+ finish(executionId) {
7
+ this.#perExecution.delete(executionId);
8
+ }
9
+ reserve(agent, parentSessionId, executionId) {
10
+ return this.#reserve(agent, parentSessionId, executionId);
11
+ }
12
+ reserveResume(agent, parentSessionId) {
13
+ const release = this.#reserve(agent, parentSessionId);
14
+ return () => release(false);
15
+ }
16
+ #reserve(agent, parentSessionId, executionId) {
17
+ const registration = agent.observeSessionExecutions(() => { });
18
+ const active = registration.sessions.filter((session) => session.source.parentSessionId === parentSessionId).length;
19
+ registration.unsubscribe();
20
+ const used = executionId === undefined ? 0 : (this.#perExecution.get(executionId) ?? 0);
21
+ const pending = this.#pending.get(parentSessionId) ?? 0;
22
+ if (used >= 16 || active + pending >= 16)
23
+ throw new AgentError('MAR_AGENT_SUBAGENT_LIMIT', 'Subagent admission limit was reached.');
24
+ this.#pending.set(parentSessionId, pending + 1);
25
+ if (executionId !== undefined)
26
+ this.#perExecution.set(executionId, used + 1);
27
+ let released = false;
28
+ return (created) => {
29
+ if (released)
30
+ return;
31
+ released = true;
32
+ const remaining = (this.#pending.get(parentSessionId) ?? 1) - 1;
33
+ if (remaining === 0)
34
+ this.#pending.delete(parentSessionId);
35
+ else
36
+ this.#pending.set(parentSessionId, remaining);
37
+ if (!created && executionId !== undefined)
38
+ this.#perExecution.set(executionId, (this.#perExecution.get(executionId) ?? 1) - 1);
39
+ };
40
+ }
41
+ }
42
+ export function registerStart(context, agent, admission) {
43
+ context.tools.register({
44
+ name: 'agent_start',
45
+ description: 'Start a child Session and return its identity without waiting for completion.',
46
+ allowedCallers: ['direct', 'programmatic'],
47
+ parallelSafety: 'serial',
48
+ inputSchema: {
49
+ type: 'object',
50
+ properties: {
51
+ title: { type: 'string', minLength: 1, maxLength: 80 },
52
+ description: { type: 'string', minLength: 1, maxLength: 80 },
53
+ prompt: { type: 'string', minLength: 1 },
54
+ role: { type: 'string', enum: ['general-purpose', 'explore'] },
55
+ modelId: { type: 'string', minLength: 1 },
56
+ reasoningEffort: {
57
+ type: 'string',
58
+ enum: ['low', 'medium', 'high', 'xhigh', 'max', 'ultra']
59
+ }
60
+ },
61
+ required: ['title', 'prompt', 'role'],
62
+ additionalProperties: false
63
+ },
64
+ async execute(raw, call) {
65
+ const input = raw;
66
+ const { data } = await startChild(context, agent, admission, { ...input, description: input.description ?? input.title ?? '' }, call, 'model');
67
+ return { content: JSON.stringify(data), data, eventData: { agentId: data.agentId } };
68
+ }
69
+ });
70
+ }
71
+ /** Both adapters enter this Session-owned creation path with their actual Core operation. */
72
+ export async function startChild(context, agent, admission, input, call, mode) {
73
+ if ((mode === 'model' && !call.executionId) || !context.session || !context.models)
74
+ throw new AgentError('MAR_AGENT_SUBAGENT_LIMIT', 'An active parent Execution is required.');
75
+ if (mode === 'model' && (typeof input.title !== 'string' || !input.title.trim()))
76
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Child title is required.');
77
+ if (!input.description.trim() ||
78
+ !input.prompt.trim() ||
79
+ (mode === 'model' && Buffer.byteLength(input.prompt) > 131_072))
80
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Child description or prompt is invalid.');
81
+ const parent = await agent.getSession(context.sessionId);
82
+ let root = parent;
83
+ let depth = 1;
84
+ const visited = new Set([root.id]);
85
+ while (root.source.parentSessionId !== undefined) {
86
+ if (depth >= 3 || visited.has(root.source.parentSessionId))
87
+ throw new AgentError('MAR_AGENT_SUBAGENT_LIMIT', 'Child Session depth limit was reached.');
88
+ root = await agent.getSession(root.source.parentSessionId);
89
+ if (root.workspace !== parent.workspace)
90
+ throw new AgentError('MAR_AGENT_SUBAGENT_LIMIT', 'Child ancestry is invalid.');
91
+ visited.add(root.id);
92
+ depth++;
93
+ }
94
+ if (depth >= 3)
95
+ throw new AgentError('MAR_AGENT_SUBAGENT_LIMIT', 'Child Session depth limit was reached.');
96
+ const request = mode === 'model' ? await context.session.captureRequest() : undefined;
97
+ const selected = input.modelId ??
98
+ request?.request.modelId ??
99
+ (mode === 'native'
100
+ ? (parent.modelId ?? context.models.list().find((candidate) => candidate.isDefault)?.id)
101
+ : undefined);
102
+ if (!selected)
103
+ throw new AgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Child model is unavailable.');
104
+ const effort = input.reasoningEffort ??
105
+ request?.request.reasoningEffort ??
106
+ (mode === 'native' ? parent.reasoningEffort : undefined);
107
+ const validate = () => {
108
+ const model = context.models.list().find((candidate) => candidate.id === selected);
109
+ if (!model?.conversationModel || !model.subagentModel)
110
+ throw new AgentError('MAR_AGENT_MODEL_DISABLED', 'The selected child model is not eligible.');
111
+ if (input.reasoningEffort && !model.reasoningEfforts.includes(input.reasoningEffort))
112
+ throw new AgentError('MAR_AGENT_SUBAGENT_REASONING_EFFORT_UNAVAILABLE', 'The selected child effort is unavailable.');
113
+ const effectiveEffort = input.reasoningEffort ??
114
+ model.reasoningEfforts.find((candidate) => candidate === effort) ??
115
+ model.defaultReasoningEffort;
116
+ return { model, effectiveEffort };
117
+ };
118
+ validate();
119
+ call.signal.throwIfAborted();
120
+ input.turnSignal?.throwIfAborted();
121
+ const nativeRelease = mode === 'native' ? admission.reserveResume(agent, parent.id) : undefined;
122
+ const release = nativeRelease
123
+ ? (_created) => nativeRelease()
124
+ : admission.reserve(agent, parent.id, call.executionId);
125
+ let childId;
126
+ try {
127
+ const child = await agent.createSession({
128
+ workspace: parent.workspace,
129
+ ...(mode === 'model' ? { title: input.title.trim() } : {}),
130
+ source: {
131
+ type: 'subagent',
132
+ parentSessionId: parent.id,
133
+ rootSessionId: root.id,
134
+ ...(call.executionId ? { parentExecutionId: call.executionId } : {}),
135
+ parentOperationId: call.operationId,
136
+ ...(call.ownerInstanceId ? { ownerInstanceId: call.ownerInstanceId } : {}),
137
+ ...(call.extensionId ? { extensionId: call.extensionId } : {}),
138
+ role: input.role,
139
+ description: input.description.trim()
140
+ }
141
+ });
142
+ childId = child.id;
143
+ call.signal.throwIfAborted();
144
+ input.turnSignal?.throwIfAborted();
145
+ const { model, effectiveEffort } = validate();
146
+ const originId = parent.id.replace(/[&<>"']/g, (character) => ({
147
+ '&': '&amp;',
148
+ '<': '&lt;',
149
+ '>': '&gt;',
150
+ '"': '&quot;',
151
+ "'": '&apos;'
152
+ })[character]);
153
+ const prompt = `<mar_session_origin sessionId="${originId}" relation="parent">\n <instruction>Message from the parent session.</instruction>\n</mar_session_origin>\n${input.prompt}`;
154
+ const executionInput = {
155
+ prompt,
156
+ modelId: model.id,
157
+ reasoningEffort: effectiveEffort,
158
+ permissionMode: call.permissionMode ?? 'auto'
159
+ };
160
+ const execution = input.role === 'explore' ? child.plan(executionInput) : child.run(executionInput);
161
+ if (input.turnSignal) {
162
+ const turnSignal = input.turnSignal;
163
+ const cancel = () => execution.cancel();
164
+ turnSignal.addEventListener('abort', cancel, { once: true });
165
+ if (turnSignal.aborted)
166
+ cancel();
167
+ void execution
168
+ .result()
169
+ .finally(() => turnSignal.removeEventListener('abort', cancel))
170
+ .catch(() => { });
171
+ }
172
+ else
173
+ void execution.result().catch(() => { });
174
+ const result = {
175
+ agentId: child.id,
176
+ executionId: execution.executionId,
177
+ status: 'running',
178
+ modelId: model.id,
179
+ modelName: model.name,
180
+ reasoningEffort: effectiveEffort,
181
+ description: input.description.trim(),
182
+ role: input.role
183
+ };
184
+ return { data: result, execution };
185
+ }
186
+ catch (error) {
187
+ if (childId === undefined)
188
+ throw error;
189
+ const result = {
190
+ agentId: childId,
191
+ status: 'not-started',
192
+ description: input.description.trim(),
193
+ role: input.role,
194
+ errorCode: error instanceof AgentError ? error.code : 'MAR_AGENT_SUBAGENT_START_FAILED'
195
+ };
196
+ return { data: result };
197
+ }
198
+ finally {
199
+ release(childId !== undefined);
200
+ }
201
+ }
@@ -0,0 +1,19 @@
1
+ type WaitAgent = {
2
+ agentId: string;
3
+ executionId?: string;
4
+ status: string;
5
+ waitOutcome: string;
6
+ summary?: string;
7
+ summaryTruncated?: boolean;
8
+ changedFiles?: string[];
9
+ changedFilesTruncated?: boolean;
10
+ updates?: Array<{
11
+ value: string;
12
+ truncated?: boolean;
13
+ }>;
14
+ };
15
+ /** Keep the model's JSON parseable without modifying the native result. */
16
+ export declare function modelWaitAgent<T extends WaitAgent>(agent: T, maximumBytes: number): T & {
17
+ detailsTruncated?: boolean;
18
+ };
19
+ export {};
@@ -0,0 +1,56 @@
1
+ import { boundedUtf8 } from './snapshot.js';
2
+ /** Keep the model's JSON parseable without modifying the native result. */
3
+ export function modelWaitAgent(agent, maximumBytes) {
4
+ const result = {
5
+ ...agent,
6
+ ...(agent.changedFiles ? { changedFiles: [...agent.changedFiles] } : {}),
7
+ ...(agent.updates ? { updates: agent.updates.map((update) => ({ ...update })) } : {})
8
+ };
9
+ const size = () => Buffer.byteLength(JSON.stringify(result), 'utf8');
10
+ while (size() > maximumBytes && result.changedFiles?.length) {
11
+ result.changedFiles.pop();
12
+ result.changedFilesTruncated = true;
13
+ }
14
+ if (size() > maximumBytes && result.summary !== undefined) {
15
+ const summary = result.summary;
16
+ let low = 0;
17
+ let high = Buffer.byteLength(summary, 'utf8');
18
+ result.summaryTruncated = true;
19
+ while (low < high) {
20
+ const middle = Math.ceil((low + high) / 2);
21
+ result.summary = boundedUtf8(summary, middle).value;
22
+ if (size() <= maximumBytes)
23
+ low = middle;
24
+ else
25
+ high = middle - 1;
26
+ }
27
+ result.summary = boundedUtf8(summary, low).value;
28
+ }
29
+ for (const update of result.updates ?? []) {
30
+ if (size() <= maximumBytes)
31
+ break;
32
+ const value = update.value;
33
+ let low = 0;
34
+ let high = Buffer.byteLength(value, 'utf8');
35
+ update.truncated = true;
36
+ while (low < high) {
37
+ const middle = Math.ceil((low + high) / 2);
38
+ update.value = boundedUtf8(value, middle).value;
39
+ if (size() <= maximumBytes)
40
+ low = middle;
41
+ else
42
+ high = middle - 1;
43
+ }
44
+ update.value = boundedUtf8(value, low).value;
45
+ }
46
+ if (size() <= maximumBytes)
47
+ return result;
48
+ // Preserve the identity and outcome even if unusual metadata itself exceeds the budget.
49
+ return {
50
+ agentId: agent.agentId,
51
+ ...(agent.executionId ? { executionId: agent.executionId } : {}),
52
+ status: agent.status,
53
+ waitOutcome: agent.waitOutcome,
54
+ detailsTruncated: true
55
+ };
56
+ }
@@ -0,0 +1,175 @@
1
+ import { type Agent } from '@myagentroam/agent';
2
+ import { type ExtensionOperationContext, type SessionExtensionContext } from '@myagentroam/agent/extensions';
3
+ import type { SessionObservations } from './observations.js';
4
+ export type WaitInput = {
5
+ agentId?: string | undefined;
6
+ agentIds?: string[] | undefined;
7
+ mode?: 'any' | 'all' | undefined;
8
+ waitFor?: 'message' | 'completion' | undefined;
9
+ waitMs?: number | undefined;
10
+ untilSettled?: true | undefined;
11
+ };
12
+ /** A foreground wait observes fixed Execution identities, never owning or cancelling them. */
13
+ export declare function registerWait(context: SessionExtensionContext, agent: Agent, observations: SessionObservations, history?: Pick<Agent, 'sessionHistory'>): void;
14
+ /** Model and native callers share target capture and acknowledgement, not their limits or cursors. */
15
+ export declare function waitForChild(context: SessionExtensionContext, agent: Agent, observations: SessionObservations, input: WaitInput, call: ExtensionOperationContext, mode: 'model' | 'native', receipts?: SessionObservations, history?: Pick<Agent, 'sessionHistory'>): Promise<{
16
+ data: {
17
+ waitOutcome?: string;
18
+ reason?: string;
19
+ waitFor: "message" | "completion";
20
+ } | {
21
+ waitOutcome: string;
22
+ reason?: string;
23
+ waitFor: "message" | "completion";
24
+ updates?: {
25
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
26
+ errorMessage?: string;
27
+ errorCode?: string;
28
+ truncated?: boolean;
29
+ final?: boolean;
30
+ kind: "message" | "terminal";
31
+ value: string;
32
+ }[];
33
+ receipt?: import("@myagentroam/agent").AgentSessionInputReceipt;
34
+ changedFilesTruncated?: boolean;
35
+ changedFiles?: string[];
36
+ turnId?: string;
37
+ summaryTruncated?: boolean;
38
+ summary?: string;
39
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
40
+ errorMessage?: string;
41
+ errorCode?: string;
42
+ status: string;
43
+ description?: string;
44
+ role?: "general-purpose" | "explore";
45
+ modelId?: string;
46
+ modelName?: string;
47
+ reasoningEffort?: string;
48
+ extensionId?: string;
49
+ executionId?: string;
50
+ agentId: string;
51
+ } | {
52
+ waitOutcome: string;
53
+ reason?: string;
54
+ waitFor: "message" | "completion";
55
+ updates?: {
56
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
57
+ errorMessage?: string;
58
+ errorCode?: string;
59
+ truncated?: boolean;
60
+ final?: boolean;
61
+ kind: "message" | "terminal";
62
+ value: string;
63
+ }[];
64
+ receipt?: import("@myagentroam/agent").AgentSessionInputReceipt;
65
+ latestActivity?: {
66
+ kind: "message";
67
+ timestamp: string;
68
+ phase: "commentary" | "final_answer";
69
+ } | {
70
+ kind: "tool";
71
+ timestamp: string;
72
+ toolName: string;
73
+ status: "started" | "completed" | "failed";
74
+ };
75
+ latestMessage?: {
76
+ itemId: string;
77
+ turnId: string;
78
+ phase: "commentary" | "final_answer";
79
+ text: string;
80
+ timestamp: string;
81
+ truncated: boolean;
82
+ };
83
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
84
+ errorMessage?: string;
85
+ errorCode?: string;
86
+ status: string;
87
+ description?: string;
88
+ role?: "general-purpose" | "explore";
89
+ modelId?: string;
90
+ modelName?: string;
91
+ reasoningEffort?: string;
92
+ extensionId?: string;
93
+ executionId?: string;
94
+ agentId: string;
95
+ } | {
96
+ agents: ({
97
+ updates?: {
98
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
99
+ errorMessage?: string;
100
+ errorCode?: string;
101
+ truncated?: boolean;
102
+ final?: boolean;
103
+ kind: "message" | "terminal";
104
+ value: string;
105
+ }[];
106
+ receipt?: import("@myagentroam/agent").AgentSessionInputReceipt;
107
+ changedFilesTruncated?: boolean;
108
+ changedFiles?: string[];
109
+ turnId?: string;
110
+ summaryTruncated?: boolean;
111
+ summary?: string;
112
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
113
+ errorMessage?: string;
114
+ errorCode?: string;
115
+ status: string;
116
+ waitOutcome: string;
117
+ description?: string;
118
+ role?: "general-purpose" | "explore";
119
+ modelId?: string;
120
+ modelName?: string;
121
+ reasoningEffort?: string;
122
+ extensionId?: string;
123
+ executionId?: string;
124
+ agentId: string;
125
+ } | {
126
+ updates?: {
127
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
128
+ errorMessage?: string;
129
+ errorCode?: string;
130
+ truncated?: boolean;
131
+ final?: boolean;
132
+ kind: "message" | "terminal";
133
+ value: string;
134
+ }[];
135
+ receipt?: import("@myagentroam/agent").AgentSessionInputReceipt;
136
+ latestActivity?: {
137
+ kind: "message";
138
+ timestamp: string;
139
+ phase: "commentary" | "final_answer";
140
+ } | {
141
+ kind: "tool";
142
+ timestamp: string;
143
+ toolName: string;
144
+ status: "started" | "completed" | "failed";
145
+ };
146
+ latestMessage?: {
147
+ itemId: string;
148
+ turnId: string;
149
+ phase: "commentary" | "final_answer";
150
+ text: string;
151
+ timestamp: string;
152
+ truncated: boolean;
153
+ };
154
+ permissionStop?: import("@myagentroam/agent").PermissionStop;
155
+ errorMessage?: string;
156
+ errorCode?: string;
157
+ status: string;
158
+ waitOutcome: string;
159
+ description?: string;
160
+ role?: "general-purpose" | "explore";
161
+ modelId?: string;
162
+ modelName?: string;
163
+ reasoningEffort?: string;
164
+ extensionId?: string;
165
+ executionId?: string;
166
+ agentId: string;
167
+ })[];
168
+ pendingAgentIds: string[];
169
+ reason?: string;
170
+ mode: "any" | "all";
171
+ waitFor: "message" | "completion";
172
+ waitOutcome: string;
173
+ };
174
+ content: string;
175
+ }>;