maka-agent 0.2.0-dev.76.20261009 → 0.2.0-dev.78.20261010
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +3 -3
- package/dist/pi-tui-pickers.js +5 -2
- package/dist/pi-tui-runner.js +211 -33
- package/dist/runtime-host-session-driver.js +91 -13
- package/dist/session-catalog-limits.js +22 -0
- package/dist/session-driver.js +10 -0
- package/dist/tui-copy-catalog.js +15 -0
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/bot-chat-settings.js +3 -0
- package/node_modules/@maka/core/dist/bot-events.js +1 -8
- package/node_modules/@maka/core/dist/local-memory.js +38 -1
- package/node_modules/@maka/core/dist/scheduled-task.js +14 -15
- package/node_modules/@maka/core/dist/session.js +3 -0
- package/node_modules/@maka/core/dist/text-sanitize.js +8 -3
- package/node_modules/@maka/runtime/dist/agent-graph-supervisor-wake.js +115 -17
- package/node_modules/@maka/runtime/dist/agent-run.js +11 -0
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +11 -0
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +13 -5
- package/node_modules/@maka/runtime/dist/bots/proxied-fetch.js +29 -1
- package/node_modules/@maka/runtime/dist/computer-use-observation-text.js +22 -0
- package/node_modules/@maka/runtime/dist/conversation-copy-agent-output.js +227 -0
- package/node_modules/@maka/runtime/dist/conversation-copy.js +176 -46
- package/node_modules/@maka/runtime/dist/file-stable-write.js +15 -3
- package/node_modules/@maka/runtime/dist/filesystem-worker/resource-resolver.js +3 -1
- package/node_modules/@maka/runtime/dist/model-adapter.js +20 -1
- package/node_modules/@maka/runtime/dist/network/proxy-test.js +28 -1
- package/node_modules/@maka/runtime/dist/network/scoped-fetch-transport.js +13 -2
- package/node_modules/@maka/runtime/dist/owned-child-process.js +209 -0
- package/node_modules/@maka/runtime/dist/owned-process-main.js +183 -0
- package/node_modules/@maka/runtime/dist/pipe-process-driver.js +19 -25
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +216 -8
- package/node_modules/@maka/runtime/dist/sandbox-boundary-tool.js +12 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +156 -17
- package/node_modules/@maka/runtime/dist/shell-exec.js +18 -20
- package/node_modules/@maka/runtime/dist/shell-run-manager.js +2 -1
- package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +279 -8
- package/node_modules/@maka/runtime/dist/stream-graph-schedule-reconcile.js +209 -37
- package/node_modules/@maka/runtime/dist/tool-availability.js +55 -18
- package/node_modules/@maka/runtime/dist/tool-call-snapshot.js +142 -0
- package/node_modules/@maka/runtime/dist/tool-runtime.js +27 -84
- package/node_modules/@maka/runtime/dist/workers/{filesystem-worker.js → filesystem-worker.mjs} +12 -1
- package/node_modules/@maka/runtime-host/dist/client/connect-or-spawn.js +30 -6
- package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
- package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +44 -13
- package/node_modules/@maka/runtime-host/dist/client/session-catalog-summary.js +6 -0
- package/node_modules/@maka/runtime-host/dist/client/wsl-environment.js +4 -0
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
- package/node_modules/@maka/runtime-host/dist/protocol/message.js +1 -13
- package/node_modules/@maka/runtime-host/dist/protocol/session-catalog.js +46 -9
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -13
- package/node_modules/@maka/runtime-host/dist/protocol/turn.js +1 -13
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +4 -7
- package/node_modules/@maka/runtime-host/dist/server/archive-retention-coordinator.js +81 -105
- package/node_modules/@maka/runtime-host/dist/server/candidate.js +47 -40
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +87 -67
- package/node_modules/@maka/runtime-host/dist/server/execution-service.js +5 -1
- package/node_modules/@maka/runtime-host/dist/server/host-maintenance-guards.js +95 -0
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +18 -8
- package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +32 -3
- package/node_modules/@maka/runtime-host/dist/server/project-catalog-coordinator.js +2 -0
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +109 -8
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +20 -3
- package/node_modules/@maka/runtime-host/dist/server/session-background-activity.js +71 -0
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +8 -4
- package/node_modules/@maka/runtime-host/dist/server/session-interaction-activity.js +78 -0
- package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +56 -0
- package/node_modules/@maka/runtime-host/dist/server/session-revision-graph-references.js +16 -2
- package/node_modules/@maka/runtime-host/dist/server/skill-catalog-coordinator.js +2 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +19 -24
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +74 -19
- package/node_modules/@maka/runtime-host/dist/server/workhub-result-coordinator.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/workhub-result-runtime.js +6 -99
- package/node_modules/@maka/runtime-host/dist/server/workhub-target-execution-authority.js +14 -126
- package/node_modules/@maka/storage/dist/context-offload-store.js +8 -3
- package/node_modules/@maka/storage/dist/git-entry.js +142 -5
- package/node_modules/@maka/storage/dist/session-bundle-policy.js +54 -19
- package/package.json +2 -2
|
@@ -21,6 +21,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
21
21
|
import { decodeRuntimeBoundaryCursor, } from '@maka/core/runtime-boundary';
|
|
22
22
|
import { isTerminalRuntimeEvent, } from '@maka/core/runtime-event';
|
|
23
23
|
import { isDeepStrictEqual } from 'node:util';
|
|
24
|
+
import { createGenesisExecutionBoundary } from '@maka/core/sandbox-boundary';
|
|
24
25
|
import { resolveEffectiveOrchestration, } from '@maka/core/orchestration';
|
|
25
26
|
import { AgentRun, ContinuationStartCommitError, } from './agent-run.js';
|
|
26
27
|
import { createSessionEventMapMemory, isLiveBackendSessionEvent, mapSessionEventToRuntimeEvent, } from './session-event-runtime-mapper.js';
|
|
@@ -320,7 +321,17 @@ export class RuntimeKernel {
|
|
|
320
321
|
const execution = this.takeExecutionClaim(sessionId, options.execution);
|
|
321
322
|
try {
|
|
322
323
|
await this.enterExecutionClaim(execution);
|
|
323
|
-
|
|
324
|
+
execution.executionPolicy = options.executionPolicy;
|
|
325
|
+
const existing = this.active.get(sessionId);
|
|
326
|
+
if (existing && !isDeepStrictEqual(existing.executionPolicy, options.executionPolicy)) {
|
|
327
|
+
if (existing.activeRuns.size > 0)
|
|
328
|
+
throw new Error('Cannot change execution policy while a Turn is running');
|
|
329
|
+
await this.disposeBackend(sessionId);
|
|
330
|
+
}
|
|
331
|
+
const storedHeader = await this.readBackendHeader(execution);
|
|
332
|
+
const header = options.executionPolicy
|
|
333
|
+
? { ...storedHeader, permissionMode: options.executionPolicy.permissionMode }
|
|
334
|
+
: storedHeader;
|
|
324
335
|
let workspaceIdentity;
|
|
325
336
|
if (this.deps.inspectContinuationSafety) {
|
|
326
337
|
try {
|
|
@@ -355,7 +366,12 @@ export class RuntimeKernel {
|
|
|
355
366
|
return active;
|
|
356
367
|
},
|
|
357
368
|
unregisterRun: (active, activeRun) => this.unregisterParentRun(active, activeRun),
|
|
358
|
-
updateHeader: (targetSessionId, patch) =>
|
|
369
|
+
updateHeader: async (targetSessionId, patch) => {
|
|
370
|
+
const updated = await this.updateHeader(targetSessionId, patch);
|
|
371
|
+
return options.executionPolicy
|
|
372
|
+
? { ...updated, permissionMode: options.executionPolicy.permissionMode }
|
|
373
|
+
: updated;
|
|
374
|
+
},
|
|
359
375
|
updateStatus: (targetSessionId, status, blockedReason, ts) => this.updateStatus(targetSessionId, status, blockedReason, ts),
|
|
360
376
|
...this.messageProjectionHook(),
|
|
361
377
|
},
|
|
@@ -410,7 +426,14 @@ export class RuntimeKernel {
|
|
|
410
426
|
(this.executionClaims.get(continuation.sessionId)?.size ?? 0) > 1) {
|
|
411
427
|
throw new Error('Cannot continue while another run is active');
|
|
412
428
|
}
|
|
413
|
-
|
|
429
|
+
execution.executionPolicy = options.executionPolicy;
|
|
430
|
+
const existing = this.active.get(continuation.sessionId);
|
|
431
|
+
if (existing && !isDeepStrictEqual(existing.executionPolicy, options.executionPolicy))
|
|
432
|
+
await this.disposeBackend(continuation.sessionId);
|
|
433
|
+
const storedHeader = await this.readBackendHeader(execution);
|
|
434
|
+
const header = options.executionPolicy
|
|
435
|
+
? { ...storedHeader, permissionMode: options.executionPolicy.permissionMode }
|
|
436
|
+
: storedHeader;
|
|
414
437
|
const sessionRuns = await this.deps.runtimeEventStore.listSessionInvocations(continuation.sessionId);
|
|
415
438
|
const sourceRun = sessionRuns.find((run) => run.runId === continuation.sourceRunId);
|
|
416
439
|
if (!sourceRun) {
|
|
@@ -564,7 +587,12 @@ export class RuntimeKernel {
|
|
|
564
587
|
return active;
|
|
565
588
|
},
|
|
566
589
|
unregisterRun: (active, activeRun) => this.unregisterParentRun(active, activeRun),
|
|
567
|
-
updateHeader: (targetSessionId, patch) =>
|
|
590
|
+
updateHeader: async (targetSessionId, patch) => {
|
|
591
|
+
const updated = await this.updateHeader(targetSessionId, patch);
|
|
592
|
+
return options.executionPolicy
|
|
593
|
+
? { ...updated, permissionMode: options.executionPolicy.permissionMode }
|
|
594
|
+
: updated;
|
|
595
|
+
},
|
|
568
596
|
updateStatus: (targetSessionId, status, blockedReason, ts) => this.updateStatus(targetSessionId, status, blockedReason, ts),
|
|
569
597
|
...this.messageProjectionHook(),
|
|
570
598
|
},
|
|
@@ -1308,6 +1336,106 @@ export class RuntimeKernel {
|
|
|
1308
1336
|
},
|
|
1309
1337
|
];
|
|
1310
1338
|
}
|
|
1339
|
+
/** Stop one captured owner without cancelling other queued executions in its Session. */
|
|
1340
|
+
stopExecution(claim, input = {}) {
|
|
1341
|
+
normalizeStopSessionSource(input.source, input.workHubActionId);
|
|
1342
|
+
const execution = this.executionClaimStates.get(claim);
|
|
1343
|
+
if (!execution)
|
|
1344
|
+
throw new Error('Runtime execution claim belongs to another owner');
|
|
1345
|
+
if (execution.scopedStopAttempt)
|
|
1346
|
+
return execution.scopedStopAttempt;
|
|
1347
|
+
const run = execution.run;
|
|
1348
|
+
const active = run &&
|
|
1349
|
+
this.backendGenerationsFor(execution.sessionId).find((candidate) => candidate.activeRuns.get(run.runId) === run);
|
|
1350
|
+
if (!active && (execution.phase === 'released' || execution.phase === 'failed')) {
|
|
1351
|
+
return run
|
|
1352
|
+
? this.retryStoppedRun({
|
|
1353
|
+
sessionId: execution.sessionId,
|
|
1354
|
+
runId: run.runId,
|
|
1355
|
+
turnId: run.turnId,
|
|
1356
|
+
}, input)
|
|
1357
|
+
: Promise.resolve();
|
|
1358
|
+
}
|
|
1359
|
+
if (active && run)
|
|
1360
|
+
this.assertScopedStopGeneration(active, run);
|
|
1361
|
+
// Validate first, then capture the capability synchronously. A pending
|
|
1362
|
+
// owner carries the stop through attach/reserve without a Session fence.
|
|
1363
|
+
execution.stopIntent ??= { input, claims: new Set([execution]) };
|
|
1364
|
+
if (active && run)
|
|
1365
|
+
this.captureScopedRunStop(active, run, input);
|
|
1366
|
+
else
|
|
1367
|
+
run?.stop(input.source, input.workHubActionId);
|
|
1368
|
+
execution.abortController.abort(execution.cancellation);
|
|
1369
|
+
const attempt = this.stopCapturedExecution(execution, input).finally(() => {
|
|
1370
|
+
if (execution.scopedStopAttempt === attempt)
|
|
1371
|
+
execution.scopedStopAttempt = undefined;
|
|
1372
|
+
});
|
|
1373
|
+
execution.scopedStopAttempt = attempt;
|
|
1374
|
+
return attempt;
|
|
1375
|
+
}
|
|
1376
|
+
/** A failed cleanup attempt keeps its captured owner parked until a successful retry. */
|
|
1377
|
+
waitForExecutionStop(claim) {
|
|
1378
|
+
const run = this.executionClaimStates.get(claim)?.run;
|
|
1379
|
+
const operation = run &&
|
|
1380
|
+
this.retainedRunStopOperation({
|
|
1381
|
+
sessionId: claim.sessionId,
|
|
1382
|
+
runId: run.runId,
|
|
1383
|
+
turnId: run.turnId,
|
|
1384
|
+
});
|
|
1385
|
+
return operation ? operation.completion : Promise.resolve();
|
|
1386
|
+
}
|
|
1387
|
+
/** Whether a retained stop operation still owns cleanup for this exact Run. */
|
|
1388
|
+
hasPendingRunStop(identity) {
|
|
1389
|
+
return this.retainedRunStopOperation(identity) !== undefined;
|
|
1390
|
+
}
|
|
1391
|
+
retainedRunStopOperation(identity) {
|
|
1392
|
+
const operation = this.stopOperations.get(identity.sessionId);
|
|
1393
|
+
return operation &&
|
|
1394
|
+
[...operation.targets.values()].some((target) => target.runs.get(identity.runId)?.turnId === identity.turnId)
|
|
1395
|
+
? operation
|
|
1396
|
+
: undefined;
|
|
1397
|
+
}
|
|
1398
|
+
/** Exact identity lookup never redirects a completed Run's stop to its successor. */
|
|
1399
|
+
stopRun(identity, input = {}) {
|
|
1400
|
+
normalizeStopSessionSource(input.source, input.workHubActionId);
|
|
1401
|
+
const execution = [...(this.executionClaims.get(identity.sessionId) ?? [])].find((candidate) => candidate.run?.runId === identity.runId && candidate.run.turnId === identity.turnId);
|
|
1402
|
+
if (execution)
|
|
1403
|
+
return this.stopExecution(execution.handle, input);
|
|
1404
|
+
for (const active of this.backendGenerationsFor(identity.sessionId)) {
|
|
1405
|
+
const run = active.activeRuns.get(identity.runId);
|
|
1406
|
+
if (!run || run.turnId !== identity.turnId)
|
|
1407
|
+
continue;
|
|
1408
|
+
this.assertScopedStopGeneration(active, run);
|
|
1409
|
+
this.captureScopedRunStop(active, run, input);
|
|
1410
|
+
return this.retryStoppedRun(identity, input);
|
|
1411
|
+
}
|
|
1412
|
+
return this.retryStoppedRun(identity, input);
|
|
1413
|
+
}
|
|
1414
|
+
assertScopedStopGeneration(active, run) {
|
|
1415
|
+
if ([...active.activeRuns.values()].some((other) => other !== run && !other.isStopped())) {
|
|
1416
|
+
throw new Error('Cannot stop one Run while its backend generation owns another active Run');
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
captureScopedRunStop(active, run, input) {
|
|
1420
|
+
const operation = this.claimRunForStop(active.sessionId, input, active, run);
|
|
1421
|
+
if (operation && active.phase === 'active')
|
|
1422
|
+
active.phase = 'stopping';
|
|
1423
|
+
}
|
|
1424
|
+
async stopCapturedExecution(execution, input) {
|
|
1425
|
+
await execution.settled;
|
|
1426
|
+
if (execution.run) {
|
|
1427
|
+
await this.retryStoppedRun({
|
|
1428
|
+
sessionId: execution.sessionId,
|
|
1429
|
+
runId: execution.run.runId,
|
|
1430
|
+
turnId: execution.run.turnId,
|
|
1431
|
+
}, input);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
async retryStoppedRun(identity, input) {
|
|
1435
|
+
const operation = this.retainedRunStopOperation(identity);
|
|
1436
|
+
if (operation)
|
|
1437
|
+
await this.enqueueStopOperation(identity.sessionId, operation, input, true);
|
|
1438
|
+
}
|
|
1311
1439
|
stopSession(sessionId, input = {}) {
|
|
1312
1440
|
normalizeStopSessionSource(input.source, input.workHubActionId);
|
|
1313
1441
|
const existing = this.stopAttempts.get(sessionId);
|
|
@@ -1403,12 +1531,22 @@ export class RuntimeKernel {
|
|
|
1403
1531
|
buildStopOperation(input) {
|
|
1404
1532
|
const abortSource = normalizeStopSessionSource(input.source, input.workHubActionId);
|
|
1405
1533
|
const ts = this.deps.now();
|
|
1534
|
+
let resolveCompletion;
|
|
1535
|
+
let rejectCompletion;
|
|
1536
|
+
const completion = new Promise((resolve, reject) => {
|
|
1537
|
+
resolveCompletion = resolve;
|
|
1538
|
+
rejectCompletion = reject;
|
|
1539
|
+
});
|
|
1540
|
+
void completion.catch(() => undefined);
|
|
1406
1541
|
return {
|
|
1407
1542
|
abortSource,
|
|
1408
1543
|
ts,
|
|
1409
1544
|
statusProjected: false,
|
|
1410
1545
|
targets: new Map(),
|
|
1411
1546
|
queue: Promise.resolve(),
|
|
1547
|
+
completion,
|
|
1548
|
+
resolveCompletion,
|
|
1549
|
+
rejectCompletion,
|
|
1412
1550
|
};
|
|
1413
1551
|
}
|
|
1414
1552
|
enqueueStopOperation(sessionId, operation, input, deliverPending) {
|
|
@@ -1507,7 +1645,16 @@ export class RuntimeKernel {
|
|
|
1507
1645
|
if (target.delivery.kind === 'failed')
|
|
1508
1646
|
failures.add(target.delivery.error);
|
|
1509
1647
|
}
|
|
1510
|
-
|
|
1648
|
+
try {
|
|
1649
|
+
failures.throwIfAny(`Stop cleanup failed for session ${sessionId}`);
|
|
1650
|
+
if (completed)
|
|
1651
|
+
operation.resolveCompletion();
|
|
1652
|
+
}
|
|
1653
|
+
catch (error) {
|
|
1654
|
+
if (completed)
|
|
1655
|
+
operation.rejectCompletion(error);
|
|
1656
|
+
throw error;
|
|
1657
|
+
}
|
|
1511
1658
|
}
|
|
1512
1659
|
async respondToSandboxBoundary(sessionId, response) {
|
|
1513
1660
|
const key = interactionOwnerKey(sessionId, response.requestId);
|
|
@@ -1570,6 +1717,32 @@ export class RuntimeKernel {
|
|
|
1570
1717
|
hasActiveRun(sessionId, runId, turnId) {
|
|
1571
1718
|
return this.activeRunsFor(sessionId).some((run) => run.runId === runId && (turnId === undefined || run.turnId === turnId));
|
|
1572
1719
|
}
|
|
1720
|
+
readExecutionPolicy(sessionId, runId) {
|
|
1721
|
+
for (const generation of this.backendGenerationsFor(sessionId)) {
|
|
1722
|
+
if (generation.activeRuns.has(runId))
|
|
1723
|
+
return generation.executionPolicy;
|
|
1724
|
+
}
|
|
1725
|
+
return [...(this.executionClaims.get(sessionId) ?? [])].find((execution) => execution.run?.runId === runId)?.executionPolicy;
|
|
1726
|
+
}
|
|
1727
|
+
returnExecutionQuestions(sessionId, runId) {
|
|
1728
|
+
for (const generation of this.backendGenerationsFor(sessionId)) {
|
|
1729
|
+
const run = generation.activeRuns.get(runId);
|
|
1730
|
+
if (!run)
|
|
1731
|
+
continue;
|
|
1732
|
+
const policy = {
|
|
1733
|
+
permissionMode: run.headerSnapshot().permissionMode,
|
|
1734
|
+
questions: 'return',
|
|
1735
|
+
};
|
|
1736
|
+
generation.executionPolicy = policy;
|
|
1737
|
+
for (const execution of this.executionClaims.get(sessionId) ?? []) {
|
|
1738
|
+
if (execution.run?.runId === runId)
|
|
1739
|
+
execution.executionPolicy = policy;
|
|
1740
|
+
}
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
// A terminal backend can precede the Host's terminal admission. Its queued
|
|
1744
|
+
// steering is recovered into a successor with the durable delegated policy.
|
|
1745
|
+
}
|
|
1573
1746
|
requestRunHandoff(sessionId, runId, pause, signal) {
|
|
1574
1747
|
if (!this.deps.inspectContinuationSafety)
|
|
1575
1748
|
return undefined;
|
|
@@ -1868,11 +2041,17 @@ export class RuntimeKernel {
|
|
|
1868
2041
|
}));
|
|
1869
2042
|
execution.run?.bindProviderStateIdentity(prepared.providerStateIdentity);
|
|
1870
2043
|
const subagent = await this.resolveSubagentActivation(header);
|
|
2044
|
+
const kernel = this;
|
|
1871
2045
|
const backend = await prepared.build({
|
|
1872
2046
|
sessionId,
|
|
1873
2047
|
workspaceRoot: header.workspaceRoot,
|
|
1874
2048
|
header,
|
|
1875
|
-
store:
|
|
2049
|
+
store: execution.executionPolicy
|
|
2050
|
+
? this.executionPolicyStore(sessionId, execution.executionPolicy)
|
|
2051
|
+
: this.deps.store,
|
|
2052
|
+
get executionPolicy() {
|
|
2053
|
+
return kernel.active.get(sessionId)?.executionPolicy ?? execution.executionPolicy;
|
|
2054
|
+
},
|
|
1876
2055
|
abortSignal: execution.abortController.signal,
|
|
1877
2056
|
...(subagent
|
|
1878
2057
|
? {
|
|
@@ -1888,12 +2067,39 @@ export class RuntimeKernel {
|
|
|
1888
2067
|
});
|
|
1889
2068
|
await this.rejectCancelledBackendActivation(backend, header, execution);
|
|
1890
2069
|
const generation = this.createBackendGeneration(sessionId, backend, header, prepared.providerStateIdentity);
|
|
2070
|
+
generation.executionPolicy = execution.executionPolicy;
|
|
1891
2071
|
this.active.set(sessionId, generation);
|
|
1892
2072
|
return generation;
|
|
1893
2073
|
});
|
|
1894
2074
|
entry.cachedHeader = header;
|
|
1895
2075
|
return entry;
|
|
1896
2076
|
}
|
|
2077
|
+
executionPolicyStore(targetSessionId, policy) {
|
|
2078
|
+
const store = this.deps.store;
|
|
2079
|
+
// Host stores are frozen. Proxy invariants forbid replacing their own
|
|
2080
|
+
// non-configurable methods, so intercept on an independent facade instead.
|
|
2081
|
+
return new Proxy(Object.create(store), {
|
|
2082
|
+
get(_facade, property) {
|
|
2083
|
+
if (property === 'readHeader')
|
|
2084
|
+
return async (sessionId) => {
|
|
2085
|
+
const header = await store.readHeader(sessionId);
|
|
2086
|
+
return sessionId === targetSessionId
|
|
2087
|
+
? { ...header, permissionMode: policy.permissionMode }
|
|
2088
|
+
: header;
|
|
2089
|
+
};
|
|
2090
|
+
if (property === 'readExecutionBoundary')
|
|
2091
|
+
return async (sessionId) => {
|
|
2092
|
+
const boundary = await store.readExecutionBoundary(sessionId);
|
|
2093
|
+
if (sessionId === targetSessionId &&
|
|
2094
|
+
(policy.permissionMode === 'bypass' || boundary.kind === 'bypass'))
|
|
2095
|
+
return createGenesisExecutionBoundary(policy.permissionMode);
|
|
2096
|
+
return boundary;
|
|
2097
|
+
};
|
|
2098
|
+
const value = Reflect.get(store, property);
|
|
2099
|
+
return typeof value === 'function' ? value.bind(store) : value;
|
|
2100
|
+
},
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
1897
2103
|
async shareBackendActivation(activationKey, activate) {
|
|
1898
2104
|
let activation = this.backendActivationBuilds.get(activationKey);
|
|
1899
2105
|
if (!activation) {
|
|
@@ -2038,7 +2244,9 @@ export class RuntimeKernel {
|
|
|
2038
2244
|
releaseStoppedRunReferences(operation, run) {
|
|
2039
2245
|
for (const target of operation.targets.values()) {
|
|
2040
2246
|
const stoppedRun = target.runs.get(run.runId);
|
|
2041
|
-
|
|
2247
|
+
// A failed terminal append still needs this captured Run on retry, even
|
|
2248
|
+
// after its stream exits. Drop it only once stop settlement succeeded.
|
|
2249
|
+
if (stoppedRun?.run === run && stoppedRun.stopCompleted)
|
|
2042
2250
|
stoppedRun.run = undefined;
|
|
2043
2251
|
if (target.active &&
|
|
2044
2252
|
target.delivery.kind !== 'pending' &&
|
|
@@ -2077,7 +2285,7 @@ export class RuntimeKernel {
|
|
|
2077
2285
|
async clearBackendQuarantineForActivation(sessionId, execution) {
|
|
2078
2286
|
const ownsCurrentStop = execution.phase === 'attached' &&
|
|
2079
2287
|
execution.stopIntent !== undefined &&
|
|
2080
|
-
|
|
2288
|
+
execution.stopIntent.claims.has(execution);
|
|
2081
2289
|
if (this.stopOperations.has(sessionId) && !ownsCurrentStop) {
|
|
2082
2290
|
throw new Error(`Session ${sessionId} is quarantined by a retained stop operation`);
|
|
2083
2291
|
}
|
|
@@ -31,6 +31,18 @@ export const SANDBOX_BOUNDARY_UNAVAILABLE = 'request_sandbox_boundary is not ava
|
|
|
31
31
|
'Retrying will fail the same way — redo the work inside the paths already allowed, or tell the ' +
|
|
32
32
|
'user which path needs access.';
|
|
33
33
|
export const REQUEST_SANDBOX_BOUNDARY_TOOL_NAME = 'request_sandbox_boundary';
|
|
34
|
+
/**
|
|
35
|
+
* Session-stable required names for the widening tool. Host only binds it when
|
|
36
|
+
* the Session is not Full access. Passing the name through `requiredToolNames`
|
|
37
|
+
* keeps the schema visible without a `tool_search` hop, and without depending
|
|
38
|
+
* on a live boundary prompt that would change the provider prefix per Turn
|
|
39
|
+
* (#5879). Returns empty when the tool is not bound.
|
|
40
|
+
*/
|
|
41
|
+
export function requiredSandboxBoundaryToolNames(hostTools) {
|
|
42
|
+
return hostTools.some((tool) => tool.name === REQUEST_SANDBOX_BOUNDARY_TOOL_NAME)
|
|
43
|
+
? new Set([REQUEST_SANDBOX_BOUNDARY_TOOL_NAME])
|
|
44
|
+
: new Set();
|
|
45
|
+
}
|
|
34
46
|
export const SANDBOX_BOUNDARY_DENIED_FOR_TURN = 'The user denied a sandbox boundary expansion for this Turn. Do not request another expansion. ' +
|
|
35
47
|
'Continue only with the authority already available, or explain the remaining blocker.';
|
|
36
48
|
export const SANDBOX_BOUNDARY_FINALIZATION_PROMPT = [
|
|
@@ -27,7 +27,7 @@ import { PLAN_USER_ABANDON_REASON, PLAN_USER_CANCEL_REASON, PlanConflictError, a
|
|
|
27
27
|
import { DEFAULT_SESSION_NAME } from '@maka/core/session-name';
|
|
28
28
|
import { SUBAGENT_SESSION_RUNTIME_SCHEMA_VERSION, SUBAGENT_SESSION_SPAWN_SCHEMA_VERSION, childSessionsForParent, subagentSessionRuntimeSummary, } from '@maka/core/session';
|
|
29
29
|
import { decodeAgentGraphIntentClaim } from '@maka/core/agent-graph-control';
|
|
30
|
-
import { executionBoundaryContains } from '@maka/core/sandbox-boundary';
|
|
30
|
+
import { createGenesisExecutionBoundary, executionBoundaryContains, } from '@maka/core/sandbox-boundary';
|
|
31
31
|
import { failureClassFromCompleteStopReason } from '@maka/core/events';
|
|
32
32
|
import { isActiveShellRunStatus } from '@maka/core/shell-run';
|
|
33
33
|
import { isTerminalRuntimeEvent } from '@maka/core/runtime-event';
|
|
@@ -1436,6 +1436,22 @@ export class SessionManager {
|
|
|
1436
1436
|
async preflightContextCompaction(sessionId) {
|
|
1437
1437
|
await this.runtimeKernel.preflightContextCompaction(sessionId);
|
|
1438
1438
|
}
|
|
1439
|
+
returnExecutionQuestions(sessionId, runId) {
|
|
1440
|
+
if (!this.runtimeKernel.returnExecutionQuestions)
|
|
1441
|
+
throw new Error('Runtime does not support execution question policy');
|
|
1442
|
+
this.runtimeKernel.returnExecutionQuestions(sessionId, runId);
|
|
1443
|
+
}
|
|
1444
|
+
async readExecutionPolicy(sessionId, runId) {
|
|
1445
|
+
return (this.runtimeKernel.readExecutionPolicy?.(sessionId, runId) ??
|
|
1446
|
+
(await this.deps.resolveExecutionPolicy?.(sessionId, runId)));
|
|
1447
|
+
}
|
|
1448
|
+
async readExecutionBoundaryForRun(sessionId, runId) {
|
|
1449
|
+
const policy = await this.readExecutionPolicy(sessionId, runId);
|
|
1450
|
+
const boundary = await this.deps.store.readExecutionBoundary(sessionId);
|
|
1451
|
+
return policy && (policy.permissionMode === 'bypass' || boundary.kind === 'bypass')
|
|
1452
|
+
? createGenesisExecutionBoundary(policy.permissionMode)
|
|
1453
|
+
: boundary;
|
|
1454
|
+
}
|
|
1439
1455
|
/**
|
|
1440
1456
|
* Create and run a durable linked child Session.
|
|
1441
1457
|
*
|
|
@@ -1504,7 +1520,7 @@ export class SessionManager {
|
|
|
1504
1520
|
const [parentHeader, sourceRun, parentBoundary] = await Promise.all([
|
|
1505
1521
|
this.deps.store.readHeader(input.source.sessionId),
|
|
1506
1522
|
this.readInvocation(input.source.sessionId, input.source.runId),
|
|
1507
|
-
this.
|
|
1523
|
+
this.readExecutionBoundaryForRun(input.source.sessionId, input.source.runId),
|
|
1508
1524
|
]);
|
|
1509
1525
|
if (sourceRun.sessionId !== input.source.sessionId ||
|
|
1510
1526
|
sourceRun.runId !== input.source.runId ||
|
|
@@ -1530,7 +1546,10 @@ export class SessionManager {
|
|
|
1530
1546
|
const resolvedToolNames = executorId
|
|
1531
1547
|
? []
|
|
1532
1548
|
: await this.resolveChildToolNames(input.source.sessionId, parentHeader, definition);
|
|
1533
|
-
const childPermissionMode =
|
|
1549
|
+
const childPermissionMode = ((await this.readExecutionPolicy(input.source.sessionId, input.source.runId))
|
|
1550
|
+
?.permissionMode ?? parentHeader.permissionMode) === 'bypass'
|
|
1551
|
+
? 'bypass'
|
|
1552
|
+
: definition.permissionMode;
|
|
1534
1553
|
const initialTurnId = this.deps.newId();
|
|
1535
1554
|
const initialRunId = this.deps.newId();
|
|
1536
1555
|
const identityHash = stableHash({
|
|
@@ -1698,9 +1717,28 @@ export class SessionManager {
|
|
|
1698
1717
|
return await inFlight.promise;
|
|
1699
1718
|
}
|
|
1700
1719
|
const runtimeExecution = this.runtimeKernel.claimExecution(claim.targetSessionId);
|
|
1701
|
-
const
|
|
1720
|
+
const owner = {
|
|
1721
|
+
identity: {
|
|
1722
|
+
sessionId: claim.targetSessionId,
|
|
1723
|
+
runId: claim.targetRunId,
|
|
1724
|
+
turnId: claim.targetTurnId,
|
|
1725
|
+
},
|
|
1726
|
+
execution: runtimeExecution,
|
|
1727
|
+
hostAdmitted: false,
|
|
1728
|
+
};
|
|
1729
|
+
resolved.onHostAdmission = () => {
|
|
1730
|
+
owner.hostAdmitted = true;
|
|
1731
|
+
};
|
|
1732
|
+
const promise = this.enqueueClaimedAgentGraphIntent(resolved, runtimeExecution, async () => {
|
|
1733
|
+
runtimeExecution.release();
|
|
1734
|
+
// Keep the existing Session slot until scoped backend cleanup completes.
|
|
1735
|
+
// Other queued claims retain their own uncancelled runtime capabilities.
|
|
1736
|
+
await owner.stopTask?.catch(() => undefined);
|
|
1737
|
+
await this.runtimeKernel.waitForExecutionStop?.(runtimeExecution);
|
|
1738
|
+
});
|
|
1702
1739
|
this.claimedAgentGraphIntentRuns.set(claim.claimId, {
|
|
1703
1740
|
requestFingerprint,
|
|
1741
|
+
owner,
|
|
1704
1742
|
promise,
|
|
1705
1743
|
});
|
|
1706
1744
|
try {
|
|
@@ -1712,7 +1750,7 @@ export class SessionManager {
|
|
|
1712
1750
|
}
|
|
1713
1751
|
}
|
|
1714
1752
|
}
|
|
1715
|
-
enqueueClaimedAgentGraphIntent(input, runtimeExecution) {
|
|
1753
|
+
enqueueClaimedAgentGraphIntent(input, runtimeExecution, release) {
|
|
1716
1754
|
const sessionId = input.claim.targetSessionId;
|
|
1717
1755
|
const previous = this.claimedAgentGraphSessionTails.get(sessionId) ?? Promise.resolve();
|
|
1718
1756
|
let enteredQueue = false;
|
|
@@ -1729,7 +1767,8 @@ export class SessionManager {
|
|
|
1729
1767
|
}
|
|
1730
1768
|
enteredQueue = true;
|
|
1731
1769
|
return this.runClaimedAgentGraphIntentOnce(input, runtimeExecution);
|
|
1732
|
-
})
|
|
1770
|
+
})
|
|
1771
|
+
.finally(release);
|
|
1733
1772
|
const tail = queuedExecution.then(() => { }, () => { });
|
|
1734
1773
|
this.claimedAgentGraphSessionTails.set(sessionId, tail);
|
|
1735
1774
|
void tail.then(() => {
|
|
@@ -1742,8 +1781,10 @@ export class SessionManager {
|
|
|
1742
1781
|
rejectStopped = reject;
|
|
1743
1782
|
});
|
|
1744
1783
|
const onRuntimeStop = () => {
|
|
1745
|
-
if (!enteredQueue)
|
|
1784
|
+
if (!enteredQueue) {
|
|
1785
|
+
runtimeExecution.release();
|
|
1746
1786
|
rejectStopped(runtimeExecution.stopSignal.reason);
|
|
1787
|
+
}
|
|
1747
1788
|
};
|
|
1748
1789
|
runtimeExecution.stopSignal.addEventListener('abort', onRuntimeStop, { once: true });
|
|
1749
1790
|
if (runtimeExecution.stopSignal.aborted)
|
|
@@ -1769,6 +1810,7 @@ export class SessionManager {
|
|
|
1769
1810
|
throw new Error('Claimed graph execution target must be a linked child session');
|
|
1770
1811
|
}
|
|
1771
1812
|
await this.assertLinkedChildBoundaryMatchesParent(child.subagentParent.parentSessionId, child.id);
|
|
1813
|
+
const executionPolicy = await this.readExecutionPolicy(child.subagentParent.parentSessionId, child.subagentParent.spawnedBy.parentRunId);
|
|
1772
1814
|
const rootExecution = {
|
|
1773
1815
|
kind: 'claimed_agent_graph_intent',
|
|
1774
1816
|
claim,
|
|
@@ -1804,6 +1846,9 @@ export class SessionManager {
|
|
|
1804
1846
|
this.assertClaimedAgentGraphRun(child, snapshot, claim, run);
|
|
1805
1847
|
if (input.hostedGraphExecution) {
|
|
1806
1848
|
const admission = await this.requireClaimedGraphAdmissionIdentity(claim, input.hostedGraphExecution);
|
|
1849
|
+
if (input.hostedGraphExecution && runtimeExecution.stopSignal.aborted)
|
|
1850
|
+
throw runtimeExecution.stopSignal.reason;
|
|
1851
|
+
input.onHostAdmission?.();
|
|
1807
1852
|
await this.consumeLinkedRootExecution({
|
|
1808
1853
|
sessionId: child.id,
|
|
1809
1854
|
turnId: claim.targetTurnId,
|
|
@@ -1839,13 +1884,22 @@ export class SessionManager {
|
|
|
1839
1884
|
await this.finalizeChildWorkspacePatches(child.id);
|
|
1840
1885
|
// An invocation is what makes a Turn exist on the ledger, so the run listing
|
|
1841
1886
|
// is the whole occupancy check: a Turn with durable content has one.
|
|
1842
|
-
const
|
|
1887
|
+
const invocations = await this.listInvocations(child.id);
|
|
1888
|
+
const turnOwner = invocations.find((candidate) => candidate.turnId === claim.targetTurnId);
|
|
1843
1889
|
if (turnOwner) {
|
|
1844
1890
|
throw new Error(`Claimed graph turn ${claim.targetTurnId} is already owned by run ${turnOwner.runId}`);
|
|
1845
1891
|
}
|
|
1846
|
-
if (child.isArchived
|
|
1892
|
+
if (child.isArchived) {
|
|
1847
1893
|
throw new Error('Claimed graph execution target child session is terminated');
|
|
1848
1894
|
}
|
|
1895
|
+
if (child.status === 'aborted') {
|
|
1896
|
+
const latest = [...invocations].sort((left, right) => right.openedAt - left.openedAt)[0];
|
|
1897
|
+
// A graph stop ends one activation, not the reusable operator. Only a
|
|
1898
|
+
// durable graph-supervisor stop permits a new claim on an aborted child.
|
|
1899
|
+
if (latest?.terminalEvent?.actions?.stateDelta?.abortSource !== 'graph.supervisor') {
|
|
1900
|
+
throw new Error('Claimed graph execution target child session is terminated');
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1849
1903
|
if (input.abortSignal?.aborted) {
|
|
1850
1904
|
throw new Error('Claimed graph execution was cancelled before runtime admission');
|
|
1851
1905
|
}
|
|
@@ -1860,11 +1914,28 @@ export class SessionManager {
|
|
|
1860
1914
|
let aborted = false;
|
|
1861
1915
|
let stopPromise;
|
|
1862
1916
|
const userMessageId = await this.claimedGraphUserMessageId(claim, input.hostedGraphExecution);
|
|
1917
|
+
if (input.hostedGraphExecution && runtimeExecution.stopSignal.aborted)
|
|
1918
|
+
throw runtimeExecution.stopSignal.reason;
|
|
1919
|
+
// Host runs this gate in its Session admission lease immediately before
|
|
1920
|
+
// the durable admission. Until it passes, a graph stop only cancels the
|
|
1921
|
+
// local capability and the gate refuses the Turn; after it passes, the
|
|
1922
|
+
// stop must go through the Host fence.
|
|
1923
|
+
const hostedAdmitExecution = input.hostedGraphExecution
|
|
1924
|
+
? async () => {
|
|
1925
|
+
if (runtimeExecution.stopSignal.aborted)
|
|
1926
|
+
return 'cancelled';
|
|
1927
|
+
const admission = admitExecution ? await admitExecution() : 'executing';
|
|
1928
|
+
if (admission === 'cancelled' || runtimeExecution.stopSignal.aborted)
|
|
1929
|
+
return 'cancelled';
|
|
1930
|
+
input.onHostAdmission?.();
|
|
1931
|
+
return 'executing';
|
|
1932
|
+
}
|
|
1933
|
+
: admitExecution;
|
|
1863
1934
|
const execution = this.consumeLinkedRootExecution({
|
|
1864
1935
|
...identity,
|
|
1865
1936
|
userMessageId,
|
|
1866
1937
|
execution: rootExecution,
|
|
1867
|
-
...(
|
|
1938
|
+
...(hostedAdmitExecution ? { admitExecution: hostedAdmitExecution } : {}),
|
|
1868
1939
|
content: { text: input.prompt },
|
|
1869
1940
|
start: ({ runId, userMessageId, onRunStarted }) => this.sendMessage(child.id, {
|
|
1870
1941
|
turnId: claim.targetTurnId,
|
|
@@ -1882,6 +1953,7 @@ export class SessionManager {
|
|
|
1882
1953
|
: {}),
|
|
1883
1954
|
onRunStarted,
|
|
1884
1955
|
execution: runtimeExecution,
|
|
1956
|
+
...(executionPolicy ? { executionPolicy } : {}),
|
|
1885
1957
|
}),
|
|
1886
1958
|
onReady: notifyReady,
|
|
1887
1959
|
onEvent: (event) => {
|
|
@@ -2002,8 +2074,9 @@ export class SessionManager {
|
|
|
2002
2074
|
const [parentHeader, parentRun, parentBoundary] = await Promise.all([
|
|
2003
2075
|
this.deps.store.readHeader(parentSessionId),
|
|
2004
2076
|
this.readInvocation(parentSessionId, input.spawnedBy.parentRunId),
|
|
2005
|
-
this.
|
|
2077
|
+
this.readExecutionBoundaryForRun(parentSessionId, input.spawnedBy.parentRunId),
|
|
2006
2078
|
]);
|
|
2079
|
+
const executionPolicy = await this.readExecutionPolicy(parentSessionId, input.spawnedBy.parentRunId);
|
|
2007
2080
|
this.assertActiveParentRun(parentSessionId, parentRun, input.spawnedBy.parentTurnId);
|
|
2008
2081
|
const definition = requireBuiltinAgentDefinitionByProfile(input.agentProfile);
|
|
2009
2082
|
const executorId = input.executorId ?? (input.resolvedPreset ? undefined : parentHeader.executorId);
|
|
@@ -2163,6 +2236,7 @@ export class SessionManager {
|
|
|
2163
2236
|
durability: 'required',
|
|
2164
2237
|
onRunStarted,
|
|
2165
2238
|
execution: runtimeOwner.execution,
|
|
2239
|
+
...(executionPolicy ? { executionPolicy } : {}),
|
|
2166
2240
|
}),
|
|
2167
2241
|
onReady: notifyReady,
|
|
2168
2242
|
onEvent: (event) => {
|
|
@@ -2312,8 +2386,11 @@ export class SessionManager {
|
|
|
2312
2386
|
return target;
|
|
2313
2387
|
}
|
|
2314
2388
|
async assertLinkedChildBoundaryMatchesParent(parentSessionId, childSessionId) {
|
|
2389
|
+
const child = await this.deps.store.readHeader(childSessionId);
|
|
2390
|
+
if (!child.subagentParent)
|
|
2391
|
+
throw new Error('Linked child is missing parent provenance');
|
|
2315
2392
|
const [parentBoundary, childBoundary] = await Promise.all([
|
|
2316
|
-
this.
|
|
2393
|
+
this.readExecutionBoundaryForRun(parentSessionId, child.subagentParent.spawnedBy.parentRunId),
|
|
2317
2394
|
this.deps.store.readExecutionBoundary(childSessionId),
|
|
2318
2395
|
]);
|
|
2319
2396
|
if (!executionBoundaryContains(parentBoundary, childBoundary)) {
|
|
@@ -2478,6 +2555,61 @@ export class SessionManager {
|
|
|
2478
2555
|
},
|
|
2479
2556
|
};
|
|
2480
2557
|
}
|
|
2558
|
+
/** Stop the captured graph activation, never a newer Run or a queued sibling. */
|
|
2559
|
+
async stopAgentGraphActivation(identity, input = { source: 'graph_supervisor' }) {
|
|
2560
|
+
const authority = isRuntimeHostedRootAuthority(this.deps.messageAuthority)
|
|
2561
|
+
? this.deps.messageAuthority
|
|
2562
|
+
: undefined;
|
|
2563
|
+
// Until the Host admission gate passes, the capability is only local
|
|
2564
|
+
// ownership: cancel it synchronously, and both the pre-submission check
|
|
2565
|
+
// and that gate refuse the Turn. Once admitted, Host must commit its
|
|
2566
|
+
// durable fence before Runtime stop.
|
|
2567
|
+
if (authority) {
|
|
2568
|
+
const admission = await this.deps.hostedAgentGraphExecution?.readRootTurnAdmissionIdentity(identity.sessionId, identity.turnId);
|
|
2569
|
+
if (admission && admission.runId !== identity.runId) {
|
|
2570
|
+
throw new Error('Graph stop identity does not match its durable admission');
|
|
2571
|
+
}
|
|
2572
|
+
// A recovered local claim can be new while the Host already owns its Run.
|
|
2573
|
+
// Recheck the gate after the durable read closes that lookup race.
|
|
2574
|
+
if (admission || this.findGraphRuntimeActivation(identity)?.hostAdmitted) {
|
|
2575
|
+
await authority.stopRootRun(identity, input);
|
|
2576
|
+
return;
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
await this.stopGraphRuntimeActivation(identity, input);
|
|
2580
|
+
}
|
|
2581
|
+
/** Whether a failed stop left cleanup retained for this exact graph activation. */
|
|
2582
|
+
hasPendingAgentGraphActivationStop(identity) {
|
|
2583
|
+
return this.runtimeKernel.hasPendingRunStop?.(identity) ?? false;
|
|
2584
|
+
}
|
|
2585
|
+
findGraphRuntimeActivation(identity) {
|
|
2586
|
+
return [...this.claimedAgentGraphIntentRuns.values()]
|
|
2587
|
+
.map((entry) => entry.owner)
|
|
2588
|
+
.find((candidate) => candidate.identity.sessionId === identity.sessionId &&
|
|
2589
|
+
candidate.identity.runId === identity.runId &&
|
|
2590
|
+
candidate.identity.turnId === identity.turnId);
|
|
2591
|
+
}
|
|
2592
|
+
stopGraphRuntimeActivation(identity, input) {
|
|
2593
|
+
const owner = this.findGraphRuntimeActivation(identity);
|
|
2594
|
+
if (owner) {
|
|
2595
|
+
if (owner.stopTask)
|
|
2596
|
+
return owner.stopTask;
|
|
2597
|
+
if (!this.runtimeKernel.stopExecution) {
|
|
2598
|
+
throw new Error('Runtime kernel does not support scoped graph activation stops');
|
|
2599
|
+
}
|
|
2600
|
+
const task = this.runtimeKernel.stopExecution(owner.execution, input);
|
|
2601
|
+
owner.stopTask = task;
|
|
2602
|
+
void task.catch(() => {
|
|
2603
|
+
if (owner.stopTask === task)
|
|
2604
|
+
owner.stopTask = undefined;
|
|
2605
|
+
});
|
|
2606
|
+
return task;
|
|
2607
|
+
}
|
|
2608
|
+
if (!this.runtimeKernel.stopRun) {
|
|
2609
|
+
throw new Error('Runtime kernel does not support exact Run stops');
|
|
2610
|
+
}
|
|
2611
|
+
return this.runtimeKernel.stopRun(identity, input);
|
|
2612
|
+
}
|
|
2481
2613
|
async stopSession(sessionId, input = {}) {
|
|
2482
2614
|
const hostedAuthority = isRuntimeHostedRootAuthority(this.deps.messageAuthority)
|
|
2483
2615
|
? this.deps.messageAuthority
|
|
@@ -2488,15 +2620,20 @@ export class SessionManager {
|
|
|
2488
2620
|
? hostedAuthority.stopSession(childSessionId, input)
|
|
2489
2621
|
: this.runtimeKernel.stopSession(childSessionId, input));
|
|
2490
2622
|
}
|
|
2491
|
-
async deliverHostedRootStop(sessionId, input = {}) {
|
|
2623
|
+
async deliverHostedRootStop(sessionId, input = {}, identity) {
|
|
2624
|
+
if (identity && identity.sessionId !== sessionId) {
|
|
2625
|
+
throw new Error('Hosted stop identity belongs to another Session');
|
|
2626
|
+
}
|
|
2492
2627
|
const authority = isRuntimeHostedRootAuthority(this.deps.messageAuthority)
|
|
2493
2628
|
? this.deps.messageAuthority
|
|
2494
2629
|
: undefined;
|
|
2495
|
-
await this.#stopSessionTree(sessionId,
|
|
2630
|
+
await this.#stopSessionTree(sessionId, identity
|
|
2631
|
+
? this.stopGraphRuntimeActivation(identity, input)
|
|
2632
|
+
: this.runtimeKernel.stopSession(sessionId, input), (childSessionId) => authority
|
|
2496
2633
|
? authority.stopSession(childSessionId, input)
|
|
2497
|
-
: this.runtimeKernel.stopSession(childSessionId, input));
|
|
2634
|
+
: this.runtimeKernel.stopSession(childSessionId, input), identity);
|
|
2498
2635
|
}
|
|
2499
|
-
async #stopSessionTree(sessionId, ownStop, stopChild) {
|
|
2636
|
+
async #stopSessionTree(sessionId, ownStop, stopChild, parentIdentity) {
|
|
2500
2637
|
// Observe immediately while child lookup runs; await below still propagates the original error.
|
|
2501
2638
|
void ownStop.catch(() => undefined);
|
|
2502
2639
|
let childStops = [];
|
|
@@ -2504,7 +2641,9 @@ export class SessionManager {
|
|
|
2504
2641
|
try {
|
|
2505
2642
|
const children = await this.listChildSessions(sessionId);
|
|
2506
2643
|
childStops = await Promise.allSettled(children
|
|
2507
|
-
.filter((child) => child.subagentParent?.lifecycle === 'foreground'
|
|
2644
|
+
.filter((child) => child.subagentParent?.lifecycle === 'foreground' &&
|
|
2645
|
+
(!parentIdentity ||
|
|
2646
|
+
child.subagentParent.spawnedBy.parentTurnId === parentIdentity.turnId))
|
|
2508
2647
|
.map((child) => stopChild(child.id)));
|
|
2509
2648
|
}
|
|
2510
2649
|
catch (error) {
|