@kingsoftcloud/agentkit-harness-node 0.0.0-stage → 0.0.2

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 (151) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +1 -0
  3. package/README.md +124 -2
  4. package/THIRD_PARTY_NOTICES.md +66 -0
  5. package/ZCode-LICENSE +202 -0
  6. package/dist/index.mjs +4871 -0
  7. package/dist/native-command-plan.LICENSE.txt +221 -0
  8. package/dist/native-command-plan.json +16 -0
  9. package/dist/native-command-plan.mjs +8 -0
  10. package/dist/rpc-entry.mjs +5682 -0
  11. package/package.json +169 -4
  12. package/src/native/a2a-receipt-source.mjs +19 -0
  13. package/src/native/a2a-tools.mjs +517 -0
  14. package/src/native/activity-status.mjs +30 -0
  15. package/src/native/artifact-codec.mjs +481 -0
  16. package/src/native/artifact-store.mjs +1162 -0
  17. package/src/native/assistant-stream.mjs +76 -0
  18. package/src/native/background-command-port.mjs +95 -0
  19. package/src/native/browser-action-observation.mjs +43 -0
  20. package/src/native/browser-availability.mjs +22 -0
  21. package/src/native/browser-canvas-metrics.mjs +71 -0
  22. package/src/native/browser-dom.mjs +193 -0
  23. package/src/native/browser-playwright.mjs +1249 -0
  24. package/src/native/browser-vision.mjs +369 -0
  25. package/src/native/browser-workspace-policy.mjs +22 -0
  26. package/src/native/browser-workspace-protocol.mjs +95 -0
  27. package/src/native/browser-workspace-server.mjs +164 -0
  28. package/src/native/browser-workspace.mjs +355 -0
  29. package/src/native/captured-source.mjs +3 -0
  30. package/src/native/child-budget-allocation.mjs +87 -0
  31. package/src/native/child-capabilities.mjs +35 -0
  32. package/src/native/child-command-resource.mjs +20 -0
  33. package/src/native/child-history.mjs +188 -0
  34. package/src/native/child-merge.mjs +98 -0
  35. package/src/native/child-model-surface.mjs +19 -0
  36. package/src/native/child-observation.mjs +100 -0
  37. package/src/native/child-owner.mjs +620 -0
  38. package/src/native/child-publication.mjs +76 -0
  39. package/src/native/child-readers.mjs +366 -0
  40. package/src/native/child-tools.mjs +46 -0
  41. package/src/native/child-workspace-binding.mjs +29 -0
  42. package/src/native/child-workspace-tools.mjs +1 -0
  43. package/src/native/child-workspaces.mjs +655 -0
  44. package/src/native/children.mjs +365 -0
  45. package/src/native/command-plan-worker.mjs +14 -0
  46. package/src/native/command-plan.mjs +31 -0
  47. package/src/native/command-progress.mjs +64 -0
  48. package/src/native/command-shell.mjs +9 -0
  49. package/src/native/command-workspace-observation.mjs +36 -0
  50. package/src/native/component-tools.mjs +280 -0
  51. package/src/native/context-counter.mjs +133 -0
  52. package/src/native/context-markers.mjs +51 -0
  53. package/src/native/context-profile.mjs +72 -0
  54. package/src/native/context-status.mjs +27 -0
  55. package/src/native/conversation-command-control.mjs +133 -0
  56. package/src/native/delivery-timeline.mjs +39 -0
  57. package/src/native/dsh-background-ownership.mjs +102 -0
  58. package/src/native/dsh-managed-ownership.mjs +23 -0
  59. package/src/native/dsh-turn-contract.mjs +3 -0
  60. package/src/native/dsh-turn-ownership.mjs +54 -0
  61. package/src/native/dsh-turn-runtime.mjs +498 -0
  62. package/src/native/e2b-background-supervisor.mjs +347 -0
  63. package/src/native/e2b-background.mjs +368 -0
  64. package/src/native/e2b-command-state.mjs +40 -0
  65. package/src/native/e2b-command-tools.mjs +486 -0
  66. package/src/native/e2b-sandbox-owner.mjs +227 -0
  67. package/src/native/hook-executor.mjs +249 -0
  68. package/src/native/instruction-assembly.mjs +60 -0
  69. package/src/native/instruction-context.mjs +54 -0
  70. package/src/native/local-background-supervisor.mjs +108 -0
  71. package/src/native/local-background.mjs +207 -0
  72. package/src/native/local-command-evidence.mjs +57 -0
  73. package/src/native/local-command-policy-worker.mjs +197 -0
  74. package/src/native/local-command-policy.mjs +46 -0
  75. package/src/native/local-command-state.mjs +177 -0
  76. package/src/native/local-command-tools.mjs +302 -0
  77. package/src/native/local-execution-profile.mjs +36 -0
  78. package/src/native/local-output-policy.mjs +92 -0
  79. package/src/native/local-process-bin/darwin-arm64/launcher +0 -0
  80. package/src/native/local-process-bin/darwin-x64/launcher +0 -0
  81. package/src/native/local-process-bin/linux-arm64/launcher +0 -0
  82. package/src/native/local-process-bin/linux-x64/launcher +0 -0
  83. package/src/native/local-process-launcher.c +183 -0
  84. package/src/native/local-process-licenses/GCC-COPYING.RUNTIME +72 -0
  85. package/src/native/local-process-licenses/GCC-COPYING3 +674 -0
  86. package/src/native/local-process-licenses/NOTICE +21 -0
  87. package/src/native/local-process-licenses/musl-COPYRIGHT +193 -0
  88. package/src/native/local-process-manifest.json +32 -0
  89. package/src/native/local-process.mjs +246 -0
  90. package/src/native/local-resource-profile.mjs +32 -0
  91. package/src/native/memory-candidate.mjs +121 -0
  92. package/src/native/memory-extraction-run.mjs +60 -0
  93. package/src/native/memory-extraction-tools.mjs +116 -0
  94. package/src/native/memory-recall.mjs +65 -0
  95. package/src/native/memory-store.mjs +334 -0
  96. package/src/native/memory-tools.mjs +329 -0
  97. package/src/native/model-anthropic-cache.mjs +49 -0
  98. package/src/native/model-anthropic-tool-search.mjs +85 -0
  99. package/src/native/model-anthropic.mjs +753 -0
  100. package/src/native/model-chat-usage.mjs +24 -0
  101. package/src/native/model-inline-reasoning.mjs +111 -0
  102. package/src/native/model-media.mjs +174 -0
  103. package/src/native/model-normalize.mjs +228 -0
  104. package/src/native/model-openai-chat.mjs +561 -0
  105. package/src/native/model-port.mjs +361 -0
  106. package/src/native/model-provider-compat.mjs +129 -0
  107. package/src/native/model-replay.mjs +153 -0
  108. package/src/native/model-request.mjs +15 -0
  109. package/src/native/model-responses.mjs +1205 -0
  110. package/src/native/model-sse.mjs +171 -0
  111. package/src/native/model-surface-host.mjs +27 -0
  112. package/src/native/model-tool-search-policy.mjs +16 -0
  113. package/src/native/model-transport-observation.mjs +27 -0
  114. package/src/native/owned-child.mjs +114 -0
  115. package/src/native/owned-command.mjs +106 -0
  116. package/src/native/python-syntax-worker.mjs +60 -0
  117. package/src/native/python-syntax.mjs +50 -0
  118. package/src/native/read-interruption.mjs +16 -0
  119. package/src/native/result-stream.mjs +63 -0
  120. package/src/native/ruff-ast.mjs +95 -0
  121. package/src/native/run-observation.mjs +128 -0
  122. package/src/native/session-delivery-journal.mjs +96 -0
  123. package/src/native/session-delivery.mjs +434 -0
  124. package/src/native/shell-analysis.mjs +50 -0
  125. package/src/native/skill-disclosure.mjs +404 -0
  126. package/src/native/skill-events.mjs +164 -0
  127. package/src/native/skill-tools.mjs +813 -0
  128. package/src/native/source-page.mjs +73 -0
  129. package/src/native/sqlite-session-inbox.mjs +42 -0
  130. package/src/native/sqlite-store.mjs +617 -0
  131. package/src/native/tool-authority.mjs +99 -0
  132. package/src/native/tool-guidance.mjs +12 -0
  133. package/src/native/tool-observation.mjs +75 -0
  134. package/src/native/tool-states.mjs +14 -0
  135. package/src/native/verification-authority.mjs +37 -0
  136. package/src/native/web-tools.mjs +643 -0
  137. package/src/native/workspace-checkpoints.mjs +312 -0
  138. package/src/native/workspace-context.mjs +61 -0
  139. package/src/native/workspace-display.mjs +39 -0
  140. package/src/native/workspace-edit-match.mjs +19 -0
  141. package/src/native/workspace-edit-worker.mjs +15 -0
  142. package/src/native/workspace-editing.mjs +447 -0
  143. package/src/native/workspace-image.mjs +72 -0
  144. package/src/native/workspace-instructions.mjs +107 -0
  145. package/src/native/workspace-mutation-lock.mjs +74 -0
  146. package/src/native/workspace-patch-worker.mjs +17 -0
  147. package/src/native/workspace-patch.mjs +17 -0
  148. package/src/native/workspace-paths.mjs +225 -0
  149. package/src/native/workspace-state.mjs +272 -0
  150. package/src/native/workspace-subject-observer.mjs +84 -0
  151. package/src/native/workspace-tools.mjs +1740 -0
@@ -0,0 +1,620 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { NativeKernel, NativeError, isNativeError, CHILD_OWNER_CONTRACT, canonical, copy, configure,
3
+ addUsage, admittedToolBudget, childLifecycleRequest, childReadyProbe, scopeKey, terminal,
4
+ CHILD_TASK_POLICY, COORDINATOR_RESPONSE_POLICY, activePlanMode, isPlanChildCall, planModeWriteDenial,
5
+ CHILD_PLAN_POLICY, CHILD_PLAN_MODE_POLICY, defaultPolicyBindings } from '@kingsoftcloud/agentkit-harness-core';
6
+ import { loadSessionChild, accountedChildDelivery, hasUnsafeChildReceipt, childNeedsApproval } from './owned-child.mjs';
7
+ import { CHILD_ALLOCATION_POLICY, CHILD_ALLOCATION_DEFAULTS, LEGACY_CALL_DEFAULTS,
8
+ roleAllocationDefaults, resolveChildCallLimits } from './child-budget-allocation.mjs';
9
+
10
+ export { CHILD_ALLOCATION_POLICY, CHILD_ALLOCATION_DEFAULTS, LEGACY_CALL_DEFAULTS,
11
+ roleAllocationDefaults, resolveChildCallLimits };
12
+
13
+ const hash = value => createHash('sha256').update(canonical(value)).digest('hex');
14
+ const check = (value, code) => { if (!value) throw new NativeError(code); };
15
+ const same = (left, right) => canonical(left) === canonical(right);
16
+ const identity = value => Object.fromEntries(['scope', 'runId', 'sessionId', 'turnId', 'buildId', 'parentRunId', 'taskChainId'].map(key => [key, copy(value[key])]));
17
+ const locator = request => `native-child-${hash({ scope: request.scope, parentRunId: request.runId, operationKey: request.operationKey })}`;
18
+
19
+ /** Detach only this observer. Execution is owned by the child Kernel and ledger. */
20
+ async function observeWhileLive(operation, signal) {
21
+ signal.throwIfAborted();
22
+ let onAbort;
23
+ const canceled = new Promise((_, reject) => {
24
+ onAbort = () => reject(isNativeError(signal.reason) ? signal.reason : new NativeError('child_observation_paused'));
25
+ signal.addEventListener('abort', onAbort, { once: true });
26
+ });
27
+ try { const result = await Promise.race([operation, canceled]); signal.throwIfAborted(); return result; }
28
+ finally { signal.removeEventListener('abort', onAbort); }
29
+ }
30
+
31
+ /**
32
+ * Durable owner for background children. resolveChild/restoreChild are trusted
33
+ * Host bindings; they provide already admitted models/tools/workspaces, never
34
+ * an environment/profile fallback. This service does not advertise model tools.
35
+ */
36
+ export function createNativeChildOwner({ scope, childScopes = [scope], store, resolveChild, restoreChild, waitForIdle, canWaitForReceipt, onStream, now = Date.now,
37
+ childAllocationPolicy, admitRequirements, owner = `native-children-${randomUUID()}` }) {
38
+ const parentScope = copy(scope), entries = new Map();
39
+ scopeKey(parentScope);
40
+ check(childAllocationPolicy === undefined || childAllocationPolicy === CHILD_ALLOCATION_POLICY, 'invalid_child_owner_allocation_policy');
41
+ const allocationPolicy = childAllocationPolicy;
42
+ const scopes = copy(childScopes);
43
+ check(Array.isArray(scopes) && scopes.length > 0 && scopes.every(item => {
44
+ scopeKey(item); return ['tenantId', 'workspaceId', 'userId'].every(key => item[key] === parentScope[key]);
45
+ }), 'invalid_child_owner_scopes');
46
+ check(store && typeof resolveChild === 'function' && typeof owner === 'string' && owner.trim(), 'invalid_child_owner');
47
+ check(waitForIdle === undefined && canWaitForReceipt === undefined
48
+ || typeof waitForIdle === 'function' && typeof canWaitForReceipt === 'function', 'invalid_child_idle_owner');
49
+ const effective = record => record.snapshot.taskContract ? { ...record.configuration, contract: record.snapshot.taskContract } : record.configuration;
50
+ const parentRecord = request => {
51
+ check(same(request.scope, parentScope), 'child_parent_scope_mismatch');
52
+ const record = store.load(parentScope, request.runId);
53
+ check(same(identity(request), identity(record.snapshot)), 'child_parent_identity_mismatch');
54
+ return record;
55
+ };
56
+ const toolInvocation = request => {
57
+ const record = parentRecord(request), intent = record.intents.find(item => item.operationKey === request.operationKey);
58
+ const calls = intent?.payload.calls, config = effective(record);
59
+ check(intent?.kind === 'tool' && intent.status === 'running' && record.snapshot.pendingIntent === request.operationKey
60
+ && intent.claimedFence === request.executionFence && record.lease?.fence === request.executionFence && record.lease.expiresAt > now()
61
+ && Array.isArray(calls) && calls.length === 1 && same(calls[0], request.call)
62
+ && same(config.tools.find(tool => tool.name === request.call.name), request.definition)
63
+ && same(intent.payload.interaction, request.interaction)
64
+ && same(admittedToolBudget(record.snapshot, config, 1), request.budget), 'child_start_not_owned');
65
+ return record;
66
+ };
67
+ const startupReceipt = (reservation, role) => ({ status: 'ok', content: { status: 'started', child_run_id: reservation.childRunId, role,
68
+ instruction: 'The task is owned and its budget is reserved. Findings are not available in this startup receipt.' },
69
+ childBudgetReservation: copy(reservation) });
70
+ const makeReservation = (record, childScope) => {
71
+ const binding = record.configuration.childOwnerBinding;
72
+ return { childRunId: record.snapshot.runId, childScope: copy(childScope), parentOperationKey: binding.parentOperationKey,
73
+ parentToolCallId: binding.parentToolCallId, childRequestDigest: binding.childRequestDigest,
74
+ configurationDigest: record.snapshot.configDigest, maxModelCalls: binding.maxModelCalls,
75
+ maxToolCalls: binding.maxToolCalls, settledUsageDigest: null,
76
+ ...(binding.deliveryMode ? { deliveryMode: binding.deliveryMode } : {}) };
77
+ };
78
+ const attachKernel = (record, ports) => {
79
+ check(ports && typeof ports.model?.generate === 'function' && typeof ports.tools?.execute === 'function', 'child_ports_unavailable');
80
+ const binding = record.configuration.childOwnerBinding;
81
+ const admitted = () => {
82
+ const parent = store.load(binding.parent.scope, binding.parent.runId);
83
+ if (terminal(parent.snapshot.phase) || parent.snapshot.phase === 'finalizing' || parent.snapshot.childTerminalPhase
84
+ || parent.commands.some(row => !row.consumed && ['cancel', 'policy_revoked'].includes(row.command.kind))) return false;
85
+ const reservation = (parent.snapshot.childBudgetReservations ?? []).find(item => item.childRunId === record.snapshot.runId);
86
+ if (reservation) return reservation.configurationDigest === record.snapshot.configDigest
87
+ && reservation.childRequestDigest === binding.childRequestDigest && reservation.settledUsageDigest === null;
88
+ const start = parent.intents.find(item => item.operationKey === binding.parentOperationKey);
89
+ return start?.status === 'running' && parent.snapshot.pendingIntent === binding.parentOperationKey
90
+ && start.claimedFence === binding.parentExecutionFence && parent.lease?.fence === binding.parentExecutionFence && parent.lease.expiresAt > now();
91
+ };
92
+ const guarded = { ...ports, model: { ...ports.model, generate: (request, emit) => admitted()
93
+ ? ports.model.generate(request, emit) : Promise.resolve({ kind: 'policy_abort', text: '', toolCalls: [],
94
+ usage: { inputTokens: 0, outputTokens: 0, modelCalls: 0, toolCalls: 0, cost: 0 }, usageReported: true }) },
95
+ tools: { ...ports.tools, execute: (request, lifecycle) => admitted() ? ports.tools.execute(request, lifecycle)
96
+ : Promise.resolve({ status: 'error', content: { code: 'child_parent_authority_lost', executed: false } }) } };
97
+ for (const [port, method] of [['hooks', 'invoke'], ['verification', 'verify'], ['artifacts', 'write'], ['input', 'prepare'], ['context', 'readSource']]) {
98
+ if (typeof ports[port]?.[method] !== 'function') continue;
99
+ guarded[port] = { ...ports[port], [method]: (...args) => {
100
+ check(admitted(), 'child_parent_authority_lost'); return ports[port][method](...args);
101
+ } };
102
+ if (port === 'artifacts') for (const reader of ['read', 'search']) {
103
+ if (typeof ports.artifacts[reader] === 'function') guarded.artifacts[reader] = (...args) => ports.artifacts[reader](...args);
104
+ }
105
+ }
106
+ const entry = { scope: copy(record.snapshot.scope), runId: record.snapshot.runId, configuration: copy(record.configuration),
107
+ kernel: new NativeKernel({ store, ports: guarded, owner: `${owner}:${record.snapshot.runId}`, digest: hash, onStream }),
108
+ ports, admitted, idle: null, promise: null, error: null };
109
+ entries.set(record.snapshot.runId, entry); return entry;
110
+ };
111
+ const submit = (entry, command) => {
112
+ const receipt = entry.kernel.submit(entry.scope, entry.runId, command);
113
+ // A queued child control interrupts only this local observer. The Kernel
114
+ // consumes the durable command, including cancellation, on the next pass.
115
+ entry.idle?.abort(new NativeError('child_idle_woken'));
116
+ return receipt;
117
+ };
118
+ const drive = entry => {
119
+ if (entry.promise) return entry.promise;
120
+ entry.error = null;
121
+ entry.promise = (async () => {
122
+ for (;;) {
123
+ const snapshot = await entry.kernel.runUntilIdle(entry.scope, entry.runId);
124
+ if (terminal(snapshot.phase)) { entry.ports.tools.settleQuestions?.(snapshot); return; }
125
+ const record = store.load(entry.scope, entry.runId);
126
+ if (!canWaitForReceipt?.(record) || !entry.admitted()) return;
127
+ const idle = new AbortController(); entry.idle = idle;
128
+ try {
129
+ const command = await observeWhileLive(Promise.resolve().then(() => waitForIdle({
130
+ snapshot: copy(snapshot), tools: entry.ports.tools, signal: idle.signal,
131
+ })), idle.signal);
132
+ idle.signal.throwIfAborted();
133
+ check(entry.admitted() && same(store.load(entry.scope, entry.runId).snapshot, snapshot), 'child_idle_authority_lost');
134
+ if (!command) return;
135
+ check(submit(entry, command).status !== 'rejected', 'child_idle_command_rejected');
136
+ } catch (error) {
137
+ if (!idle.signal.aborted || idle.signal.reason?.code !== 'child_idle_woken') throw error;
138
+ } finally { if (entry.idle === idle) entry.idle = null; idle.abort(); }
139
+ }
140
+ })().catch(error => { entry.error = error; })
141
+ .finally(() => { entry.promise = null; });
142
+ return entry.promise;
143
+ };
144
+ const ownedChild = (request, reservation) => {
145
+ check(scopes.some(item => same(item, reservation.childScope)), 'child_scope_not_admitted');
146
+ const record = store.load(reservation.childScope, reservation.childRunId), binding = record.configuration.childOwnerBinding;
147
+ check(binding?.contract === CHILD_OWNER_CONTRACT && same(binding.parent, identity(request))
148
+ && (binding.childAllocationPolicy ?? null) === (allocationPolicy ?? null)
149
+ && binding.parentOperationKey === reservation.parentOperationKey && binding.parentToolCallId === reservation.parentToolCallId
150
+ && binding.childRequestDigest === reservation.childRequestDigest && binding.maxModelCalls === reservation.maxModelCalls
151
+ && binding.deliveryMode === reservation.deliveryMode
152
+ && binding.maxToolCalls === reservation.maxToolCalls && record.snapshot.configDigest === reservation.configurationDigest
153
+ && hash(record.configuration) === reservation.configurationDigest, 'child_owner_binding_mismatch');
154
+ return record;
155
+ };
156
+ const liveEntry = async (request, reservation, record) => {
157
+ let entry = entries.get(reservation.childRunId);
158
+ if (!entry && !terminal(record.snapshot.phase)) {
159
+ check(typeof restoreChild === 'function', 'child_owner_unavailable');
160
+ request.signal.throwIfAborted();
161
+ const ports = await observeWhileLive(Promise.resolve().then(() => restoreChild({ identity: identity(record.snapshot),
162
+ configuration: copy(record.configuration), binding: copy(record.configuration.childOwnerBinding) })), request.signal);
163
+ request.signal.throwIfAborted();
164
+ entry = attachKernel(record, ports);
165
+ }
166
+ return entry;
167
+ };
168
+ const unsafeReceipt = hasUnsafeChildReceipt;
169
+ const continuationSource = request => {
170
+ const args = request.call.arguments;
171
+ if (args.continuation_of === undefined) return null;
172
+ const resolved = loadSessionChild({ store, childScopes: scopes, parent: toolInvocation(request).snapshot,
173
+ childRunId: args.continuation_of });
174
+ check(resolved, 'child_followup_not_available');
175
+ check(resolved.child.configuration.childOwnerBinding.role === args.role, 'child_followup_role_mismatch');
176
+ check(accountedChildDelivery(resolved.parent, resolved.child), 'child_followup_requires_result_collection');
177
+ return resolved;
178
+ };
179
+ const responses = (record, cursors) => record.configuration.coordinatorResponsePolicy === COORDINATOR_RESPONSE_POLICY
180
+ ? record.events.filter(event => event.kind === 'coordinator.response_queued'
181
+ && event.seq > (cursors?.[record.snapshot.runId] ?? 0)).map(event => ({ childRunId: record.snapshot.runId,
182
+ sequence: event.seq, ...copy(event.payload) })) : [];
183
+ const terminalReceipt = (record, reservation, includeResponses = true) => {
184
+ check(terminal(record.snapshot.phase) && record.snapshot.phase !== 'interrupted' && !unsafeReceipt(record), 'child_receipt_unavailable');
185
+ const parent = store.load(record.configuration.childOwnerBinding.parent.scope, record.configuration.childOwnerBinding.parent.runId);
186
+ return { status: record.snapshot.phase === 'completed' ? 'ok' : 'error', content: {
187
+ child_run_id: record.snapshot.runId, status: record.snapshot.phase, outcome: record.snapshot.outcome,
188
+ reason: record.snapshot.reason, result: record.snapshot.finalText, parent_acceptance: 'not_evaluated' },
189
+ resourceUsage: addUsage(record.snapshot.usage, record.snapshot.descendantUsage),
190
+ ...(includeResponses && parent.configuration.childTaskPolicy === CHILD_TASK_POLICY
191
+ ? { coordinatorResponses: responses(record, parent.snapshot.childResponseCursors) } : {}),
192
+ childRunIds: [record.snapshot.runId, ...(record.snapshot.childRunIds ?? [])],
193
+ childBudgetSettlement: { childRunId: record.snapshot.runId, parentOperationKey: reservation.parentOperationKey,
194
+ childRequestDigest: reservation.childRequestDigest, terminalSnapshotDigest: hash(record.snapshot) },
195
+ metadata: { usageReported: record.snapshot.diagnostics.providerUsageIncomplete !== true
196
+ && record.snapshot.diagnostics.descendantUsageIncomplete !== true
197
+ && !record.receipts.some(receipt => receipt.status === 'uncertain') } };
198
+ };
199
+ const childApproval = (record, reservation) => {
200
+ const pending = record.snapshot.pendingInteraction;
201
+ const call = record.snapshot.pendingTools.find(item => item.callId === pending?.callId);
202
+ const definition = record.configuration.tools.find(item => item.name === call?.name);
203
+ check(pending && call && definition, 'child_approval_unavailable');
204
+ return { childRunId: record.snapshot.runId, childScope: copy(record.snapshot.scope), parentOperationKey: reservation.parentOperationKey,
205
+ parentToolCallId: reservation.parentToolCallId, interactionId: pending.interactionId, hostInteractionId: pending.hostInteractionId,
206
+ toolCall: copy(call), definitionDigest: hash(definition) };
207
+ };
208
+ const foregroundResult = async (request, reservation) => {
209
+ let record = ownedChild(request, reservation);
210
+ const entry = await liveEntry(request, reservation, record);
211
+ const startup = () => startupReceipt(reservation, record.configuration.childOwnerBinding.role);
212
+ const cancel = () => {
213
+ if (entry && !terminal(store.load(entry.scope, entry.runId).snapshot.phase)) {
214
+ submit(entry, { commandId: `foreground-cancel-${hash({ parent: request.runId,
215
+ operationKey: request.operationKey })}`, kind: 'cancel', payload: {} });
216
+ drive(entry);
217
+ }
218
+ };
219
+ request.signal.addEventListener('abort', cancel, { once: true });
220
+ try {
221
+ if (request.signal.aborted) cancel();
222
+ request.signal.throwIfAborted();
223
+ toolInvocation(request);
224
+ if (entry && !terminal(record.snapshot.phase)) drive(entry);
225
+ while (!terminal(record.snapshot.phase) && !childNeedsApproval(record)) {
226
+ request.signal.throwIfAborted(); const parent = toolInvocation(request);
227
+ if (parent.commands.some(row => !row.consumed && ['pause', 'promote_child', 'message_child', 'cancel_child'].includes(row.command.kind))
228
+ || entry?.error && entry.error.code !== 'lease_busy') return startup();
229
+ await observeWhileLive(new Promise(resolve => setTimeout(resolve, 25)), request.signal);
230
+ record = ownedChild(request, reservation);
231
+ if (entry?.error?.code === 'lease_busy') drive(entry);
232
+ }
233
+ request.signal.throwIfAborted(); toolInvocation(request);
234
+ if (childNeedsApproval(record) || record.snapshot.phase === 'interrupted' || unsafeReceipt(record)) return startup();
235
+ return { ...terminalReceipt(record, reservation), childBudgetReservation: copy(reservation) };
236
+ } finally { request.signal.removeEventListener('abort', cancel); }
237
+ };
238
+ const projection = (record, reservation) => ({ runId: record.snapshot.runId, sessionId: record.snapshot.sessionId,
239
+ operationKey: reservation.parentOperationKey, callId: reservation.parentToolCallId,
240
+ state: unsafeReceipt(record) && !canWaitForReceipt?.(record) ? 'interrupted' : record.snapshot.phase === 'created' ? 'prepared' : childNeedsApproval(record) ? 'awaiting_interaction'
241
+ : terminal(record.snapshot.phase) ? record.snapshot.phase : 'running',
242
+ reservedModelCalls: reservation.maxModelCalls, reservedToolCalls: reservation.maxToolCalls,
243
+ usage: addUsage(record.snapshot.usage, record.snapshot.descendantUsage), notified: false, metadata: {} });
244
+
245
+ return Object.freeze({
246
+ contract: CHILD_OWNER_CONTRACT,
247
+ async admitPlan(request) {
248
+ try {
249
+ request.signal.throwIfAborted();
250
+ const parent = toolInvocation(request);
251
+ if (!activePlanMode(parent.snapshot, effective(parent)) || !isPlanChildCall(effective(parent), request.call, request.definition)) return false;
252
+ if (request.definition.childBudgetPolicy === 'settle/v1') {
253
+ const reservation = parent.snapshot.childBudgetReservations.find(item => item.childRunId === request.call.arguments.child_run_id);
254
+ if (!reservation) return false;
255
+ ownedChild(request, reservation);
256
+ }
257
+ return true;
258
+ } catch { return false; }
259
+ },
260
+ tasks(request) {
261
+ const parent = parentRecord(request), snapshot = parent.snapshot;
262
+ const rows = [];
263
+ for (const childScope of scopes) for (const child of store.list(childScope)) {
264
+ const record = store.load(childScope, child.runId), binding = record.configuration.childOwnerBinding;
265
+ if (!binding || !same(binding.parent, identity(request))) continue;
266
+ let reservation = snapshot.childBudgetReservations.find(item => item.childRunId === child.runId);
267
+ if (!reservation) {
268
+ const intent = parent.intents.find(item => item.operationKey === binding.parentOperationKey);
269
+ const call = intent?.payload.calls?.[0];
270
+ if (intent?.kind !== 'tool' || intent.status !== 'running' || intent.payload.calls.length !== 1
271
+ || snapshot.pendingIntent !== intent.operationKey || intent.claimedFence !== binding.parentExecutionFence
272
+ || parent.lease?.fence !== binding.parentExecutionFence || parent.lease.expiresAt <= now()
273
+ || call.callId !== binding.parentToolCallId
274
+ || !['start/v1', 'delegate/v1'].includes(effective(parent).tools.find(tool => tool.name === call.name)?.childBudgetPolicy)
275
+ || hash({ parent: identity(snapshot), operationKey: intent.operationKey, call, budget: admittedToolBudget(snapshot, effective(parent), 1) }) !== binding.childRequestDigest) continue;
276
+ reservation = makeReservation(record, childScope);
277
+ }
278
+ ownedChild(request, reservation);
279
+ const delivery = reservation.deliveryMode === 'foreground' && !(snapshot.promotedChildRunIds ?? []).includes(child.runId)
280
+ ? 'foreground' : 'background';
281
+ const live = !terminal(snapshot.phase) && snapshot.phase !== 'finalizing' && !snapshot.childTerminalPhase
282
+ && !parent.commands.some(row => !row.consumed && ['cancel', 'policy_revoked'].includes(row.command.kind))
283
+ && !terminal(child.phase) && (!unsafeReceipt(record) || canWaitForReceipt?.(record)) && reservation.settledUsageDigest === null;
284
+ rows.push({ childRunId: child.runId, sessionId: child.sessionId, role: binding.role, phase: child.phase, goalRevision: child.goalRevision, delivery,
285
+ canPromote: live && delivery === 'foreground' && effective(parent).childPromotionPolicy === 'owned-child-promotion/v1',
286
+ canCancel: live, canSendInput: live });
287
+ }
288
+ return rows;
289
+ },
290
+ controlTarget(request, childRunId) {
291
+ const row = this.tasks(request).find(task => task.childRunId === childRunId);
292
+ if (!row) return null;
293
+ for (const childScope of scopes) {
294
+ let record;
295
+ try { record = store.load(childScope, childRunId); }
296
+ catch (error) { if (error.code === 'run_not_found') continue; throw error; }
297
+ if (!same(record.configuration.childOwnerBinding?.parent, identity(request))) continue;
298
+ const reservation = makeReservation(record, childScope);
299
+ ownedChild(request, reservation);
300
+ return { scope: copy(childScope), runId: childRunId, configurationDigest: record.snapshot.configDigest,
301
+ parentOperationKey: reservation.parentOperationKey, parentToolCallId: reservation.parentToolCallId };
302
+ }
303
+ return null;
304
+ },
305
+ async wakeControl(request, delivery) {
306
+ const parent = parentRecord(request), target = delivery.target;
307
+ const reservation = parent.snapshot.childBudgetReservations.find(item => item.childRunId === target.runId);
308
+ check(reservation && reservation.settledUsageDigest === null, 'child_control_not_owned');
309
+ const record = ownedChild(request, reservation);
310
+ check(same(record.snapshot.scope, target.scope) && record.snapshot.configDigest === target.configurationDigest
311
+ && record.commands.some(row => same(row.command, delivery.command)), 'child_control_delivery_missing');
312
+ if (terminal(record.snapshot.phase)) return;
313
+ const entry = await liveEntry({ ...request, signal: new AbortController().signal }, reservation, record);
314
+ check(entry, 'child_owner_unavailable');
315
+ // Only an exact duplicate of the transactionally admitted command may
316
+ // notify an active Kernel. Cancellation interrupts its existing effect.
317
+ check(submit(entry, delivery.command).status === 'duplicate', 'child_control_delivery_missing');
318
+ if (!childNeedsApproval(record) || delivery.command.kind === 'cancel') drive(entry);
319
+ },
320
+ async start(request) {
321
+ try {
322
+ request.signal.throwIfAborted();
323
+ const parent = toolInvocation(request), inheritedPlan = effective(parent).childPlanPolicy === CHILD_PLAN_POLICY;
324
+ if (activePlanMode(parent.snapshot, effective(parent)) && !isPlanChildCall(effective(parent), request.call, request.definition)) return planModeWriteDenial();
325
+ check(['start/v1', 'delegate/v1'].includes(request.definition.childBudgetPolicy), 'child_start_not_admitted');
326
+ const args = request.call.arguments;
327
+ if (effective(parent).childCapabilityPolicy === 'required-tools/v1') {
328
+ check(typeof admitRequirements === 'function', 'child_capability_owner_unavailable');
329
+ const refusal = admitRequirements(args);
330
+ if (refusal) return { status: 'error', content: refusal };
331
+ }
332
+ check(typeof args.role === 'string' && args.role.trim() && typeof args.task === 'string' && args.task.trim()
333
+ && (args.background === undefined || typeof args.background === 'boolean')
334
+ && (args.continuation_of === undefined || typeof args.continuation_of === 'string'
335
+ && args.continuation_of.trim() && args.continuation_of.length <= 256), 'child_background_request_invalid');
336
+ const foreground = args.background === false || request.call.name === 'native_delegate' && args.background !== true;
337
+ check(request.budget.depth < request.budget.maxDepth, 'child_depth_exhausted');
338
+ // Omitted call limits defer to the role cap + remaining parent budget under the
339
+ // allocation policy (no stacked 4/8 default); legacy keeps the historical 4/8.
340
+ // availableTools stays signed so an exhausted parent (maxToolCallsRemaining 0
341
+ // for start/v1) is refused here, before any child starts, rather than having core
342
+ // reject its receipt after execution.
343
+ const { maxModelCalls: requestedModelCalls, maxToolCalls: requestedToolCalls } = resolveChildCallLimits(
344
+ { policy: allocationPolicy, modelCallLimit: args.model_call_limit, toolCallLimit: args.tool_call_limit,
345
+ budget: request.budget, childBudgetPolicy: request.definition.childBudgetPolicy });
346
+ check(Number.isSafeInteger(requestedModelCalls) && requestedModelCalls > 0
347
+ && Number.isSafeInteger(requestedToolCalls) && requestedToolCalls >= 0, 'child_budget_exhausted');
348
+ let maxModelCalls = requestedModelCalls, maxToolCalls = requestedToolCalls;
349
+ const requestDigest = hash({ parent: identity(request), operationKey: request.operationKey, call: request.call, budget: request.budget });
350
+ const binding = { contract: CHILD_OWNER_CONTRACT, parent: identity(request), parentOperationKey: request.operationKey,
351
+ parentToolCallId: request.call.callId, parentExecutionFence: request.executionFence, childRequestDigest: requestDigest,
352
+ ...(inheritedPlan ? { planMode: activePlanMode(parent.snapshot, effective(parent)) } : {}),
353
+ ...(allocationPolicy ? { childAllocationPolicy } : {}),
354
+ role: args.role, maxModelCalls, maxToolCalls, ...(foreground ? { deliveryMode: 'foreground' } : {}) };
355
+ const runId = locator(request);
356
+ const existing = scopes.flatMap(childScope => store.list(childScope)).find(snapshot => snapshot.runId === runId);
357
+ if (existing) {
358
+ const record = store.load(existing.scope, runId), saved = record.configuration.childOwnerBinding;
359
+ // A stored child is never re-admitted under a foreign allocation policy: a
360
+ // legacy child must not silently gain the larger allowance, and vice versa.
361
+ check(saved?.childRequestDigest === requestDigest && saved.parentToolCallId === request.call.callId
362
+ && (saved.childAllocationPolicy ?? null) === (allocationPolicy ?? null)
363
+ && saved.maxModelCalls <= maxModelCalls && saved.maxToolCalls <= maxToolCalls, 'child_start_identity_conflict');
364
+ const reservation = makeReservation(record, existing.scope);
365
+ ownedChild(request, reservation);
366
+ return foreground ? foregroundResult(request, reservation) : startupReceipt(reservation, saved.role);
367
+ }
368
+ const source = continuationSource(request);
369
+ const childSessionId = source?.child.snapshot.sessionId ?? runId;
370
+ if (source) {
371
+ binding.continuationOf = source.child.snapshot.runId;
372
+ binding.continuationParentRunId = source.parent.snapshot.runId;
373
+ }
374
+ const bound = await observeWhileLive(Promise.resolve().then(() => resolveChild({ parent: identity(request), call: copy(request.call), childRunId: runId,
375
+ childSessionId,
376
+ role: args.role, task: args.task, parentContract: copy(effective(toolInvocation(request)).contract),
377
+ maxModelCalls, maxToolCalls, depth: request.budget.depth + 1, signal: request.signal })), request.signal);
378
+ request.signal.throwIfAborted(); toolInvocation(request);
379
+ check(bound?.scope && scopes.some(item => same(item, bound.scope))
380
+ && bound.configuration?.contract.objective === args.task, 'child_admission_binding_invalid');
381
+ if (source) {
382
+ const current = continuationSource(request);
383
+ check(same(bound.scope, source.child.snapshot.scope) && same(identity(current.child.snapshot), identity(source.child.snapshot))
384
+ && current.parent.snapshot.runId === source.parent.snapshot.runId, 'child_followup_not_available');
385
+ }
386
+ binding.maxModelCalls = Math.min(maxModelCalls, bound.configuration.limits.maxModelCalls ?? maxModelCalls);
387
+ binding.maxToolCalls = Math.min(maxToolCalls, bound.configuration.limits.maxToolCalls ?? maxToolCalls);
388
+ check(binding.maxModelCalls >= 1 && binding.maxToolCalls >= 0, 'child_budget_exhausted');
389
+ const childConfiguration = { ...copy(bound.configuration), delegationDepth: request.budget.depth + 1,
390
+ ...(inheritedPlan ? { planModePolicy: CHILD_PLAN_MODE_POLICY, planModeInitialActive: binding.planMode } : {}),
391
+ limits: { ...bound.configuration.limits, maxModelCalls: binding.maxModelCalls, maxToolCalls: binding.maxToolCalls }, childOwnerBinding: binding };
392
+ // This is a newly admitted child, not an upgrade of a stored run.
393
+ // Inherited Plan mode adds a required strategy to its own frozen set.
394
+ const modules = childConfiguration.policyModules ?? defaultPolicyBindings(childConfiguration);
395
+ childConfiguration.policyModules = [...modules, ...defaultPolicyBindings(childConfiguration)
396
+ .filter(required => !modules.some(module => module.id === required.id))];
397
+ const configuration = configure(childConfiguration);
398
+ const childIdentity = { scope: copy(bound.scope), runId, sessionId: childSessionId,
399
+ turnId: '1', buildId: request.buildId, parentRunId: null, taskChainId: source ? runId : request.taskChainId };
400
+ const kernel = new NativeKernel({ store, ports: bound.ports, owner: `${owner}:${runId}`, digest: hash, onStream });
401
+ try { kernel.start(childIdentity, configuration, { expectedParentRunId: source?.child.snapshot.runId ?? null }); }
402
+ catch (error) {
403
+ if (source && ['session_head_conflict', 'session_already_active'].includes(error.code))
404
+ throw new NativeError('child_followup_source_not_current');
405
+ throw error;
406
+ }
407
+ const record = store.load(childIdentity.scope, runId), reservation = makeReservation(record, childIdentity.scope);
408
+ const entry = attachKernel(record, bound.ports);
409
+ drive(entry);
410
+ return foreground ? foregroundResult(request, reservation) : startupReceipt(reservation, binding.role);
411
+ } catch (error) {
412
+ // Admission refusals happen before a child is created. They are known
413
+ // tool outcomes, not unknown external effects requiring reconciliation.
414
+ if (['child_followup_not_available', 'child_followup_role_mismatch', 'child_followup_requires_result_collection',
415
+ 'child_followup_source_not_current', 'child_followup_model_image_unavailable'].includes(error.code))
416
+ return { status: 'error', content: { error_code: error.code, executed: false } };
417
+ throw error;
418
+ }
419
+ },
420
+ async control(request) {
421
+ request.signal.throwIfAborted();
422
+ let parent = toolInvocation(request);
423
+ if (activePlanMode(parent.snapshot, effective(parent)) && !isPlanChildCall(effective(parent), request.call, request.definition)) return planModeWriteDenial();
424
+ check(request.definition.childBudgetPolicy === 'settle/v1', 'child_control_not_admitted');
425
+ const args = request.call.arguments, waitSeconds = args.wait_seconds ?? 15;
426
+ check(typeof args.child_run_id === 'string' && ['wait', 'send', 'stop'].includes(args.action)
427
+ && typeof waitSeconds === 'number' && Number.isFinite(waitSeconds) && waitSeconds >= 0 && waitSeconds <= 30
428
+ && (args.action === 'send' ? typeof args.message === 'string' && args.message.trim() && args.message.length <= 32000
429
+ : args.message === undefined), 'child_control_arguments_invalid');
430
+ const reservation = parent.snapshot.childBudgetReservations.find(item => item.childRunId === args.child_run_id);
431
+ check(reservation && parent.snapshot.childRunIds.includes(args.child_run_id), 'child_control_not_owned');
432
+ let record = ownedChild(request, reservation);
433
+ if (terminal(record.snapshot.phase)) return terminalReceipt(record, reservation);
434
+ check(reservation.settledUsageDigest === null, 'child_control_terminal_conflict');
435
+ const entry = await liveEntry(request, reservation, record);
436
+ parent = toolInvocation(request); request.signal.throwIfAborted();
437
+ check(entry, 'child_owner_unavailable');
438
+ if (args.action !== 'wait') {
439
+ submit(entry, { commandId: `parent-control-${hash({ parent: request.runId,
440
+ operationKey: request.operationKey, callId: request.call.callId })}`, kind: args.action === 'send' ? 'guide' : 'cancel',
441
+ payload: args.action === 'send' ? { text: args.message } : {} });
442
+ }
443
+ if (!childNeedsApproval(record) || args.action === 'stop') drive(entry);
444
+ const deadline = performance.now() + waitSeconds * 1000;
445
+ while (waitSeconds > 0 && args.action !== 'send') {
446
+ record = ownedChild(request, reservation);
447
+ if (terminal(record.snapshot.phase) || childNeedsApproval(record) && args.action !== 'stop' || performance.now() >= deadline) break;
448
+ await observeWhileLive(new Promise(resolve => setTimeout(resolve, 25)), request.signal);
449
+ if (entry.error?.code === 'lease_busy' || !entry.promise && record.commands.some(row => !row.consumed)) drive(entry);
450
+ }
451
+ request.signal.throwIfAborted(); toolInvocation(request);
452
+ record = ownedChild(request, reservation);
453
+ if (terminal(record.snapshot.phase)) return terminalReceipt(record, reservation);
454
+ return { status: 'ok', content: { child_run_id: record.snapshot.runId, status: record.snapshot.phase,
455
+ action: args.action, parent_acceptance: 'not_evaluated', result_available: false } };
456
+ },
457
+ async collect(request) {
458
+ request.signal.throwIfAborted();
459
+ const parent = parentRecord(request), intent = parent.intents.find(item => item.operationKey === request.operationKey);
460
+ check(intent?.status === 'running', 'child_collection_not_owned');
461
+ check(intent.claimedFence === request.executionFence && parent.lease?.fence === request.executionFence
462
+ && parent.lease.expiresAt > now(), 'child_collection_fence_lost');
463
+ const { signal, ...plain } = childLifecycleRequest(parent.snapshot, intent, request.signal);
464
+ const { signal: ignored, ...supplied } = request;
465
+ check(same(plain, supplied), 'child_collection_not_owned');
466
+ const records = request.reservations.map(reservation => ownedChild(request, reservation));
467
+ const awaited = [];
468
+ for (let index = 0; index < records.length; index++) {
469
+ const reservation = request.reservations[index], record = records[index];
470
+ const entry = await liveEntry(request, reservation, record);
471
+ request.signal.throwIfAborted();
472
+ if (!entry || terminal(record.snapshot.phase)) continue;
473
+ if (request.action === 'cancel') submit(entry, {
474
+ commandId: `parent-cancel-${hash({ parent: request.runId, operationKey: request.operationKey, child: entry.runId })}`, kind: 'cancel', payload: {} });
475
+ else if (request.childApproval?.childRunId === entry.runId && request.interaction) {
476
+ const expected = request.childApproval;
477
+ check(request.interaction.interactionId === `native-child-${hash(expected)}`
478
+ && request.interaction.callId === expected.toolCall.callId && ['allow', 'deny'].includes(request.interaction.decision), 'child_approval_identity_conflict');
479
+ const commandId = `parent-approval-${hash({ parent: identity(request), approval: expected, decision: request.interaction.decision })}`;
480
+ // A promotion may detach this observer after the decision was
481
+ // durably delivered. Accept only that same saved decision; never
482
+ // infer approval from a child's phase or ask for it a second time.
483
+ const previousIds = parent.intents.filter(item => item.kind === 'child' && same(item.payload.childApproval, expected)
484
+ && same(item.payload.interaction, request.interaction)).map(item =>
485
+ `parent-approval-${hash({ parent: item.operationKey, approval: expected, decision: request.interaction.decision })}`);
486
+ const delivered = record.commands.some(row => row.command.kind === 'submit_interaction'
487
+ && [commandId, ...previousIds].includes(row.command.commandId)
488
+ && same(row.command.payload, { interactionId: expected.interactionId, decision: request.interaction.decision }));
489
+ if (!delivered) {
490
+ check(same(childApproval(record, reservation), expected), 'child_approval_identity_conflict');
491
+ submit(entry, { commandId, kind: 'submit_interaction',
492
+ payload: { interactionId: expected.interactionId, decision: request.interaction.decision } });
493
+ }
494
+ }
495
+ if (!childNeedsApproval(record) || request.action === 'cancel' || request.childApproval?.childRunId === entry.runId) {
496
+ const promise = drive(entry);
497
+ if (!request.waitForChildRunIds || request.waitForChildRunIds.includes(entry.runId)) awaited.push(promise);
498
+ }
499
+ }
500
+ if (request.action !== 'poll') {
501
+ await observeWhileLive(Promise.all(awaited), request.signal);
502
+ while (request.reservations.some(reservation => {
503
+ const record = ownedChild(request, reservation);
504
+ return (!request.waitForChildRunIds || request.waitForChildRunIds.includes(reservation.childRunId))
505
+ && !terminal(record.snapshot.phase) && record.commands.some(row => !row.consumed);
506
+ })) {
507
+ const continuations = request.reservations.flatMap(reservation => {
508
+ if (request.waitForChildRunIds && !request.waitForChildRunIds.includes(reservation.childRunId)) return [];
509
+ const record = ownedChild(request, reservation), entry = entries.get(record.snapshot.runId);
510
+ return entry && !terminal(record.snapshot.phase) && record.commands.some(row => !row.consumed) ? [drive(entry)] : [];
511
+ });
512
+ if (!continuations.length) break;
513
+ await observeWhileLive(Promise.all(continuations), request.signal);
514
+ }
515
+ // Another live owner may still hold the child's lease. Observe it;
516
+ // after expiry the same Kernel classifies its existing claims.
517
+ while (request.reservations.some(reservation => {
518
+ if (request.waitForChildRunIds && !request.waitForChildRunIds.includes(reservation.childRunId)) return false;
519
+ const record = ownedChild(request, reservation);
520
+ return !terminal(record.snapshot.phase) && !childNeedsApproval(record)
521
+ && entries.get(record.snapshot.runId)?.error?.code === 'lease_busy';
522
+ })) {
523
+ await observeWhileLive(new Promise(resolve => setTimeout(resolve, 25)), request.signal);
524
+ const retries = request.reservations.flatMap(reservation => {
525
+ if (request.waitForChildRunIds && !request.waitForChildRunIds.includes(reservation.childRunId)) return [];
526
+ const record = ownedChild(request, reservation), entry = entries.get(record.snapshot.runId);
527
+ return entry && !terminal(record.snapshot.phase) && entry.error?.code === 'lease_busy' ? [drive(entry)] : [];
528
+ });
529
+ await observeWhileLive(Promise.all(retries), request.signal);
530
+ }
531
+ }
532
+ request.signal.throwIfAborted();
533
+ const result = { operationKey: request.operationKey, results: [], pendingChildRunIds: [], approvals: [], errorCode: null, children: [] };
534
+ if (request.responseCursors !== undefined) result.responses = [];
535
+ for (const reservation of request.reservations) {
536
+ const record = ownedChild(request, reservation);
537
+ if (result.responses) result.responses.push(...responses(record, request.responseCursors));
538
+ result.children.push(projection(record, reservation));
539
+ if (terminal(record.snapshot.phase) && record.snapshot.phase !== 'interrupted' && !unsafeReceipt(record)) result.results.push(terminalReceipt(record, reservation, false));
540
+ else {
541
+ result.pendingChildRunIds.push(record.snapshot.runId);
542
+ if (childNeedsApproval(record) && request.action !== 'cancel') result.approvals.push(childApproval(record, reservation));
543
+ if (record.snapshot.phase === 'interrupted' || unsafeReceipt(record) && !canWaitForReceipt?.(record)
544
+ || entries.get(record.snapshot.runId)?.error && entries.get(record.snapshot.runId).error.code !== 'lease_busy') result.errorCode = 'child_receipt_unavailable';
545
+ }
546
+ }
547
+ return result;
548
+ },
549
+ async readyChildren(request) {
550
+ request.signal.throwIfAborted();
551
+ const parent = parentRecord(request), intent = parent.intents.find(item => item.operationKey === parent.snapshot.pendingIntent) ?? null;
552
+ const { signal, ...plain } = request;
553
+ check(same(childReadyProbe(parent.snapshot, effective(parent), intent), plain), 'child_readiness_not_owned');
554
+ const ids = [];
555
+ for (const reservation of request.reservations) {
556
+ const record = ownedChild(request, reservation);
557
+ if (terminal(record.snapshot.phase) || request.includeApprovals && childNeedsApproval(record)
558
+ || request.responseCursors !== undefined && responses(record, request.responseCursors).length) ids.push(record.snapshot.runId);
559
+ }
560
+ return { childRunIds: ids };
561
+ },
562
+ async reconcile(request) {
563
+ request.signal.throwIfAborted();
564
+ const parent = parentRecord(request), intent = parent.intents.find(item => item.operationKey === request.operationKey);
565
+ check(intent?.status === 'running', 'child_recovery_not_owned');
566
+ const { signal, ...expected } = childLifecycleRequest(parent.snapshot, intent, request.signal);
567
+ const { signal: ignored, ...plain } = request;
568
+ check(same(expected, plain), 'child_recovery_not_owned');
569
+ const records = request.reservations.map(reservation => ownedChild(request, reservation));
570
+ // Reconcile observes ledgers only. A proven original receipt wait may
571
+ // remain pending after the parent collector died; it is not a failed
572
+ // collection and grants no authority to query/send/drive that child.
573
+ // Rebinding and execution happen later in a fresh fenced collect.
574
+ if (records.some(record => terminal(record.snapshot.phase)
575
+ ? record.snapshot.phase === 'interrupted' || unsafeReceipt(record)
576
+ : request.action === 'cancel' || !canWaitForReceipt?.(record))) return null;
577
+ return { operationKey: request.operationKey,
578
+ results: records.flatMap((record, index) => terminal(record.snapshot.phase) ? [terminalReceipt(record, request.reservations[index], false)] : []),
579
+ ...(request.responseCursors === undefined ? {} : { responses: records.flatMap(record => responses(record, request.responseCursors)) }),
580
+ pendingChildRunIds: records.filter(record => !terminal(record.snapshot.phase)).map(record => record.snapshot.runId),
581
+ approvals: [], errorCode: null, children: records.map((record, index) => projection(record, request.reservations[index])) };
582
+ },
583
+ async interruptedReceipts(request) {
584
+ check(same(request.scope, parentScope), 'child_parent_scope_mismatch');
585
+ const parent = store.load(parentScope, request.runId), intent = parent.intents.find(item => item.operationKey === request.parentOperationKey);
586
+ check(intent?.kind === 'tool' && intent.status === 'running' && parent.snapshot.pendingIntent === intent.operationKey, 'child_recovery_not_owned');
587
+ const calls = intent.payload.calls;
588
+ check(Array.isArray(calls) && calls.length === 1 && ['start/v1', 'delegate/v1'].includes(effective(parent).tools.find(tool => tool.name === calls[0].name)?.childBudgetPolicy), 'child_recovery_not_owned');
589
+ const childId = locator({ scope: parentScope, runId: request.runId, operationKey: intent.operationKey });
590
+ const records = scopes.flatMap(childScope => store.list(childScope)).filter(snapshot => snapshot.runId === childId);
591
+ const entry = entries.get(childId);
592
+ if (!records.length && !entry) return [];
593
+ const childScope = entry?.scope ?? records[0].scope, record = store.load(childScope, childId);
594
+ const reservation = makeReservation(record, childScope);
595
+ ownedChild(identity(parent.snapshot), reservation);
596
+ check(record.configuration.childOwnerBinding.parentToolCallId === calls[0].callId
597
+ && record.configuration.childOwnerBinding.childRequestDigest === hash({ parent: identity(parent.snapshot),
598
+ operationKey: intent.operationKey, call: calls[0], budget: admittedToolBudget(parent.snapshot, effective(parent), 1) }), 'child_recovery_identity_conflict');
599
+ return [{ parentOperationKey: intent.operationKey, parentToolCallId: calls[0].callId,
600
+ result: reservation.deliveryMode === 'foreground' && terminal(record.snapshot.phase)
601
+ && record.snapshot.phase !== 'interrupted' && !unsafeReceipt(record)
602
+ ? { ...terminalReceipt(record, reservation), childBudgetReservation: copy(reservation) }
603
+ : startupReceipt(reservation, record.configuration.childOwnerBinding.role) }];
604
+ },
605
+ async releaseRun(request) {
606
+ check(same(request.scope, parentScope), 'child_parent_scope_mismatch');
607
+ const jobs = [];
608
+ for (const entry of entries.values()) {
609
+ if (entry.configuration.childOwnerBinding.parent.runId !== request.runId) continue;
610
+ const record = store.load(entry.scope, entry.runId);
611
+ if (!terminal(record.snapshot.phase)) {
612
+ submit(entry, { commandId: `owner-release-${hash({ owner, runId: request.runId })}`, kind: 'cancel', payload: {} });
613
+ jobs.push(drive(entry));
614
+ }
615
+ }
616
+ await Promise.all(jobs);
617
+ for (const [id, entry] of entries) if (entry.configuration.childOwnerBinding.parent.runId === request.runId) entries.delete(id);
618
+ },
619
+ });
620
+ }