@fitlab-ai/agent-infra 0.11.11 → 0.11.13
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/dist/bin/internal-cli.js +2 -2
- package/dist/lib/agent-clients/adapter.js +7 -1
- package/dist/lib/agent-clients/adapters/claude-code.js +5 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +78 -63
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +114 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +447 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-client.js +130 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-operation.js +131 -0
- package/dist/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.js +2 -2
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +48 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +124 -62
- package/dist/lib/{internal/codex-sandbox-controller.js → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js} +3 -3
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -5
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +211 -213
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +468 -0
- package/dist/lib/agent-clients/adapters/codex.js +40 -1
- package/dist/lib/agent-clients/adapters/index.js +2 -10
- package/dist/lib/agent-clients/tokens.js +3 -2
- package/dist/lib/internal/agent-client.js +132 -72
- package/dist/lib/internal/cli-route-inventory.js +2 -2
- package/dist/lib/internal/sandbox-control.js +1 -81
- package/dist/lib/internal/task-finalization.js +26 -19
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +1 -1
- package/dist/lib/internal/task-validate.js +1 -1
- package/dist/lib/platform/github-client.js +33 -3
- package/dist/lib/platform/issues.js +18 -6
- package/dist/lib/runtime/agent-runtime.js +6 -29
- package/dist/lib/sandbox/commands/control-status.js +1 -0
- package/dist/lib/sandbox/commands/create.js +7 -2
- package/dist/lib/sandbox/commands/ls.js +4 -5
- package/dist/lib/sandbox/commands/rm.js +1 -1
- package/dist/lib/sandbox/control/agent-operation.js +34 -0
- package/dist/lib/sandbox/control/client.js +14 -201
- package/dist/lib/sandbox/control/executor.js +12 -125
- package/dist/lib/sandbox/control/lifecycle.js +66 -4
- package/dist/lib/sandbox/control/protocol.js +15 -54
- package/dist/lib/sandbox/control/server.js +216 -281
- package/dist/lib/sandbox/control/task-view.js +0 -13
- package/dist/lib/sandbox/mounts.js +9 -1
- package/dist/lib/sandbox/recovery.js +31 -10
- package/dist/lib/sandbox/removal.js +28 -5
- package/dist/lib/sandbox/workspace-identity.js +18 -6
- package/dist/lib/sandbox/workspace-view.js +56 -19
- package/dist/lib/task/commands/ls.js +3 -3
- package/dist/lib/task/control-authority.js +56 -264
- package/dist/lib/task/control-recovery.js +2 -3
- package/dist/lib/task/create.js +2 -2
- package/dist/lib/task/delegation-receipts.js +74 -161
- package/dist/lib/task/events.js +88 -44
- package/dist/lib/task/finalization.js +35 -6
- package/dist/lib/task/lifecycle.js +274 -115
- package/dist/lib/task/orchestration.js +201 -194
- package/dist/lib/task/runtime-paths.js +10 -0
- package/dist/lib/task/short-id.js +37 -27
- package/dist/lib/task/verification-engine.js +32 -26
- package/dist/lib/task/workspace-snapshot.js +1 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapter.ts +39 -0
- package/lib/agent-clients/adapters/claude-code.ts +5 -1
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +105 -80
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +147 -0
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +510 -0
- package/lib/agent-clients/adapters/codex-lifecycle/controller-client.ts +158 -0
- package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +1 -1
- package/lib/agent-clients/adapters/codex-lifecycle/controller-operation.ts +151 -0
- package/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.ts +4 -4
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +43 -0
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +8 -5
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +190 -65
- package/lib/{internal/codex-sandbox-controller.ts → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.ts} +2 -2
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -5
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +270 -224
- package/lib/agent-clients/adapters/codex-orchestration.ts +632 -0
- package/lib/agent-clients/adapters/codex.ts +44 -1
- package/lib/agent-clients/adapters/index.ts +7 -20
- package/lib/agent-clients/tokens.ts +4 -3
- package/lib/internal/agent-client.ts +142 -73
- package/lib/internal/cli-route-inventory.ts +2 -2
- package/lib/internal/sandbox-control.ts +0 -97
- package/lib/internal/task-finalization.ts +30 -18
- package/lib/internal/task-lifecycle.ts +1 -1
- package/lib/internal/task-operation-registry.ts +1 -1
- package/lib/internal/task-validate.ts +1 -1
- package/lib/platform/github-client.ts +34 -3
- package/lib/platform/issues.ts +18 -6
- package/lib/runtime/agent-runtime.ts +6 -41
- package/lib/sandbox/commands/control-status.ts +1 -0
- package/lib/sandbox/commands/create.ts +7 -1
- package/lib/sandbox/commands/ls.ts +4 -5
- package/lib/sandbox/commands/rm.ts +1 -1
- package/lib/sandbox/control/agent-operation.ts +49 -0
- package/lib/sandbox/control/client.ts +20 -254
- package/lib/sandbox/control/executor.ts +13 -136
- package/lib/sandbox/control/lifecycle.ts +67 -4
- package/lib/sandbox/control/protocol.ts +22 -66
- package/lib/sandbox/control/server.ts +21 -95
- package/lib/sandbox/control/task-view.ts +0 -19
- package/lib/sandbox/mounts.ts +10 -1
- package/lib/sandbox/recovery.ts +38 -17
- package/lib/sandbox/removal.ts +33 -7
- package/lib/sandbox/workspace-identity.ts +16 -6
- package/lib/sandbox/workspace-view.ts +50 -18
- package/lib/task/commands/ls.ts +3 -3
- package/lib/task/control-authority.ts +66 -378
- package/lib/task/control-recovery.ts +3 -4
- package/lib/task/create.ts +3 -3
- package/lib/task/delegation-receipts.ts +87 -231
- package/lib/task/events.ts +100 -42
- package/lib/task/finalization.ts +37 -7
- package/lib/task/lifecycle.ts +257 -109
- package/lib/task/orchestration.ts +260 -237
- package/lib/task/runtime-paths.ts +12 -0
- package/lib/task/short-id.ts +33 -40
- package/lib/task/verification-engine.ts +30 -25
- package/lib/task/workspace-snapshot.ts +1 -1
- package/package.json +1 -1
- package/templates/.agents/hooks/lifecycle-delegation.js +1 -25
- package/templates/.agents/rules/README.en.md +2 -1
- package/templates/.agents/rules/README.zh-CN.md +2 -1
- package/templates/.agents/rules/next-step-output.en.md +6 -19
- package/templates/.agents/rules/next-step-output.zh-CN.md +6 -19
- package/templates/.agents/rules/strategy-pattern.en.md +25 -0
- package/templates/.agents/rules/strategy-pattern.zh-CN.md +25 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/check-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +4 -0
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +0 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +0 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +5 -29
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +5 -26
- package/templates/.agents/skills/plan-task/SKILL.en.md +7 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +0 -546
- package/dist/lib/internal/codex-lifecycle.js +0 -385
- package/dist/lib/task/codex-orchestration.js +0 -206
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +0 -776
- package/lib/internal/codex-lifecycle.ts +0 -390
- package/lib/task/codex-orchestration.ts +0 -276
|
@@ -18,47 +18,18 @@ import { inspectSandboxControlContainer } from './container-identity.js';
|
|
|
18
18
|
import { acquireSandboxControlBrokerStartup, garbageCollectSandboxControlRoot, isSandboxControlRootQuiescing, readSandboxControlManifest } from './lifecycle.js';
|
|
19
19
|
import { nextSandboxControlBackoff } from './timing.js';
|
|
20
20
|
import { readTaskFinalizationReceipt } from '../../task/finalization.js';
|
|
21
|
-
import {
|
|
21
|
+
import { recoverAgentClientOperation, validateAgentClientOperation } from './agent-operation.js';
|
|
22
22
|
import { validateSandboxControlIdentity } from './identity-sentinel.js';
|
|
23
|
-
import { mergeSandboxTaskView,
|
|
23
|
+
import { mergeSandboxTaskView, taskViewForManifest } from './task-view.js';
|
|
24
24
|
import { taskCreateOutputUnavailableResult } from '../../task/create-service.js';
|
|
25
|
-
async function taskViewForFinalizationResult(manifest, request, result) {
|
|
26
|
-
if (request.family !== 'task-finalization' || result?.exitCode !== 0 || !manifest.taskId)
|
|
27
|
-
return null;
|
|
28
|
-
let receipt = null;
|
|
29
|
-
for (let attempt = 0; attempt < 100 && !receipt; attempt += 1) {
|
|
30
|
-
try {
|
|
31
|
-
receipt = readTaskFinalizationReceipt(manifest.repoRoot, manifest.taskId);
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// A missing or temporarily moving task directory is retried before publishing completion.
|
|
35
|
-
}
|
|
36
|
-
if (!receipt)
|
|
37
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
38
|
-
}
|
|
39
|
-
const finalized = taskViewAfterFinalization({
|
|
40
|
-
taskId: manifest.taskId,
|
|
41
|
-
generation: manifest.generation,
|
|
42
|
-
requestId: request.id,
|
|
43
|
-
receipt
|
|
44
|
-
});
|
|
45
|
-
if (finalized.state === 'unknown')
|
|
46
|
-
return finalized;
|
|
47
|
-
const canonical = taskViewForManifest({ ...manifest, receipt });
|
|
48
|
-
return canonical.state === 'current' && canonical.observedSource === 'completed'
|
|
49
|
-
? canonical
|
|
50
|
-
: finalized;
|
|
51
|
-
}
|
|
52
25
|
function appendBrokerAudit(manifest, event, fields = {}) {
|
|
53
26
|
appendDiagnosticAudit(manifest, event, { source: 'broker', ...fields });
|
|
54
27
|
}
|
|
55
28
|
function operationKey(request) {
|
|
56
|
-
if (request.family === 'task-finalization')
|
|
57
|
-
return request.operation;
|
|
58
29
|
if (request.family === 'task-create')
|
|
59
30
|
return 'create';
|
|
60
|
-
if (request.family === '
|
|
61
|
-
return request.
|
|
31
|
+
if (request.family === 'agent-client')
|
|
32
|
+
return request.operation;
|
|
62
33
|
if (request.family !== 'task-lifecycle')
|
|
63
34
|
return null;
|
|
64
35
|
try {
|
|
@@ -217,51 +188,12 @@ function taskCreateDomainEvidence(manifest, output) {
|
|
|
217
188
|
return { consistent: false };
|
|
218
189
|
}
|
|
219
190
|
}
|
|
220
|
-
function controllerDomainEvidence(manifest, manifestPath, request, output) {
|
|
221
|
-
if (!output || output.error !== null || typeof output.status !== 'string')
|
|
222
|
-
return { consistent: false };
|
|
223
|
-
try {
|
|
224
|
-
const registration = readCodexControllerRegistration(manifestPath);
|
|
225
|
-
if (request.family !== 'codex-controller')
|
|
226
|
-
return { consistent: false };
|
|
227
|
-
if (request.command === 'open') {
|
|
228
|
-
const lease = output.lease && typeof output.lease === 'object' && !Array.isArray(output.lease)
|
|
229
|
-
? output.lease : null;
|
|
230
|
-
return {
|
|
231
|
-
consistent: output.status === 'opened' && output.changed === true
|
|
232
|
-
&& lease?.taskId === registration.taskId
|
|
233
|
-
&& lease.controlGeneration === registration.controlGeneration
|
|
234
|
-
&& lease.controllerInstanceDigest === registration.controllerInstanceDigest
|
|
235
|
-
&& registration.taskId === manifest.taskId
|
|
236
|
-
&& registration.controlGeneration === manifest.generation
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
if (request.command === 'verify') {
|
|
240
|
-
const binding = output.binding && typeof output.binding === 'object' && !Array.isArray(output.binding)
|
|
241
|
-
? output.binding : null;
|
|
242
|
-
return {
|
|
243
|
-
consistent: output.status === 'verified' && output.changed === false
|
|
244
|
-
&& binding?.taskId === registration.taskId
|
|
245
|
-
&& binding.controlGeneration === registration.controlGeneration
|
|
246
|
-
&& binding.controllerInstanceDigest === registration.controllerInstanceDigest
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
return { consistent: false };
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
return { consistent: request.family === 'codex-controller' && request.command === 'close'
|
|
253
|
-
&& error.code === 'CODEX_SANDBOX_CONTROLLER_REGISTRATION_MISSING'
|
|
254
|
-
&& output?.status === 'closed' && typeof output.changed === 'boolean' };
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
191
|
async function readRecoveryDomain(manifest, manifestPath, request, operation, terminalResult, payloadOutput) {
|
|
258
192
|
if (!operation)
|
|
259
193
|
return { domain: null };
|
|
260
|
-
const taskRef = request.
|
|
261
|
-
? manifest.taskId
|
|
262
|
-
: 'args' in request ? request.args[0] ?? null : manifest.taskId;
|
|
194
|
+
const taskRef = 'args' in request ? request.args[0] ?? null : manifest.taskId;
|
|
263
195
|
const output = parseControlOutput(payloadOutput);
|
|
264
|
-
if (!taskRef && operation.family !== 'task-create' && operation.family !== '
|
|
196
|
+
if (!taskRef && operation.family !== 'task-create' && operation.family !== 'agent-client') {
|
|
265
197
|
return { domain: null };
|
|
266
198
|
}
|
|
267
199
|
if (operation.family === 'task-lifecycle') {
|
|
@@ -289,8 +221,13 @@ async function readRecoveryDomain(manifest, manifestPath, request, operation, te
|
|
|
289
221
|
if (operation.family === 'task-create') {
|
|
290
222
|
return { domain: taskCreateDomainEvidence(manifest, output) };
|
|
291
223
|
}
|
|
292
|
-
if (operation.family === '
|
|
293
|
-
return { domain:
|
|
224
|
+
if (operation.family === 'agent-client' && request.family === 'agent-client') {
|
|
225
|
+
return { domain: recoverAgentClientOperation({
|
|
226
|
+
request,
|
|
227
|
+
manifest,
|
|
228
|
+
manifestPath,
|
|
229
|
+
stdout: payloadOutput
|
|
230
|
+
}) };
|
|
294
231
|
}
|
|
295
232
|
return { domain: null };
|
|
296
233
|
}
|
|
@@ -509,6 +446,8 @@ async function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
|
|
|
509
446
|
request = validateSandboxControlRequest(rawRequest, manifest, {
|
|
510
447
|
now: typeof rawRequest.issuedAt === 'number' ? rawRequest.issuedAt : undefined
|
|
511
448
|
});
|
|
449
|
+
if (request.family === 'agent-client')
|
|
450
|
+
validateAgentClientOperation(request, manifest);
|
|
512
451
|
}
|
|
513
452
|
catch {
|
|
514
453
|
// Missing or malformed request evidence remains fail-closed below.
|
|
@@ -760,6 +699,8 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
760
699
|
try {
|
|
761
700
|
if (!brokerOwns())
|
|
762
701
|
return;
|
|
702
|
+
if (isSandboxControlRootQuiescing(root))
|
|
703
|
+
return;
|
|
763
704
|
if (taskView.state === 'current' && taskView.observedSource === 'completed') {
|
|
764
705
|
// Recheck durable re-entry evidence before publishing a trusted startup view.
|
|
765
706
|
const unverified = { ...taskView, state: 'unknown',
|
|
@@ -866,11 +807,6 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
866
807
|
settledExecution = active;
|
|
867
808
|
active = null;
|
|
868
809
|
}
|
|
869
|
-
const finalizationView = settledExecution
|
|
870
|
-
? await taskViewForFinalizationResult(manifest, settledExecution.request, settledExecution.result)
|
|
871
|
-
: null;
|
|
872
|
-
if (finalizationView)
|
|
873
|
-
taskView = finalizationView;
|
|
874
810
|
let reasonCode = null;
|
|
875
811
|
try {
|
|
876
812
|
if (!brokerOwns())
|
|
@@ -948,228 +884,232 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
948
884
|
fs.rmSync(path.join(manifest.processingDir, settledExecution.request.id), { recursive: true, force: true });
|
|
949
885
|
}
|
|
950
886
|
let retiring = false;
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
if (!preparedExecution)
|
|
1021
|
-
throw new Error('SANDBOX_CONTROL_EXECUTION_PREPARE_INVALID');
|
|
1022
|
-
criticalRequestPhase(manifest, request, 'prepared', 'in-progress', `${preparedExecution.execution.child.pid}`);
|
|
1023
|
-
appendBrokerAudit(manifest, 'executor-prepared', {
|
|
1024
|
-
...requestAuditFields(manifest, request),
|
|
1025
|
-
requestPath: claimed,
|
|
1026
|
-
executorCwd: manifest.repoRoot,
|
|
1027
|
-
childPid: preparedExecution.execution.child.pid,
|
|
1028
|
-
childStartTime: preparedExecution.execution.child.startTime,
|
|
1029
|
-
childProcessGroupId: preparedExecution.execution.child.processGroupId,
|
|
1030
|
-
executionPath: executionPath(manifest, request.id)
|
|
1031
|
-
});
|
|
1032
|
-
const execution = {
|
|
1033
|
-
request, prepared: preparedExecution, result: null,
|
|
1034
|
-
resultEvidenceWritten: false, failure: null, settled: false
|
|
1035
|
-
};
|
|
1036
|
-
active = execution;
|
|
1037
|
-
preparedExecution.completion.then((result) => {
|
|
1038
|
-
execution.result = sanitizeSandboxControlResult(manifest, result);
|
|
1039
|
-
appendBrokerAudit(manifest, 'executor-completed', {
|
|
887
|
+
const quiescing = isSandboxControlRootQuiescing(root);
|
|
888
|
+
if (quiescing && !active)
|
|
889
|
+
break;
|
|
890
|
+
if (!quiescing)
|
|
891
|
+
for (const name of fs.readdirSync(requestsDir).sort()) {
|
|
892
|
+
if (!/^[a-f0-9-]{16,64}\.json$/.test(name))
|
|
893
|
+
continue;
|
|
894
|
+
const id = name.slice(0, -5);
|
|
895
|
+
const source = path.join(requestsDir, name);
|
|
896
|
+
let claimed = null;
|
|
897
|
+
let validatedRequest = null;
|
|
898
|
+
let prepared = null;
|
|
899
|
+
try {
|
|
900
|
+
if (isSandboxControlRootQuiescing(root)) {
|
|
901
|
+
retiring = true;
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
904
|
+
if (!brokerOwns()) {
|
|
905
|
+
retiring = true;
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
claimed = claimRequest(manifest, source, id);
|
|
909
|
+
appendBrokerAudit(manifest, 'request-claimed', {
|
|
910
|
+
requestId: id,
|
|
911
|
+
requestSourcePath: source,
|
|
912
|
+
requestClaimedPath: claimed,
|
|
913
|
+
requestProcessingDir: path.dirname(claimed)
|
|
914
|
+
});
|
|
915
|
+
if (!brokerOwns()) {
|
|
916
|
+
retiring = true;
|
|
917
|
+
break;
|
|
918
|
+
}
|
|
919
|
+
consumeRequest(consumedDir, id);
|
|
920
|
+
if (!brokerOwns()) {
|
|
921
|
+
retiring = true;
|
|
922
|
+
break;
|
|
923
|
+
}
|
|
924
|
+
if (reasonCode)
|
|
925
|
+
throw new Error(reasonCode);
|
|
926
|
+
if (active)
|
|
927
|
+
throw new Error('SANDBOX_CONTROL_BUSY');
|
|
928
|
+
const request = validateSandboxControlRequest(JSON.parse(fs.readFileSync(claimed, 'utf8')), manifest);
|
|
929
|
+
if (request.family === 'agent-client')
|
|
930
|
+
validateAgentClientOperation(request, manifest);
|
|
931
|
+
validatedRequest = request;
|
|
932
|
+
criticalRequestPhase(manifest, request, 'validated', 'in-progress');
|
|
933
|
+
appendBrokerAudit(manifest, 'request-validated', {
|
|
934
|
+
...requestAuditFields(manifest, request),
|
|
935
|
+
requestPath: claimed
|
|
936
|
+
});
|
|
937
|
+
if (bindingCheck(manifest))
|
|
938
|
+
throw new Error('SANDBOX_WORKTREE_BINDING_LOST');
|
|
939
|
+
if (readActiveLease(manifest))
|
|
940
|
+
throw new Error('SANDBOX_CONTROL_HANDOFF_ACTIVE');
|
|
941
|
+
criticalRequestPhase(manifest, request, 'gated', 'in-progress');
|
|
942
|
+
appendBrokerAudit(manifest, 'request-gates-passed', {
|
|
943
|
+
...requestAuditFields(manifest, request),
|
|
944
|
+
requestPath: claimed,
|
|
945
|
+
bindingChecked: true,
|
|
946
|
+
handoffLeaseChecked: true
|
|
947
|
+
});
|
|
948
|
+
criticalRequestPhase(manifest, request, 'reserved', 'in-progress');
|
|
949
|
+
writeSandboxControlReservation(manifest, request.id, sandboxControlGenerationUsage(manifest));
|
|
950
|
+
appendBrokerAudit(manifest, 'executor-reservation-written', {
|
|
951
|
+
...requestAuditFields(manifest, request),
|
|
952
|
+
requestPath: claimed,
|
|
953
|
+
executionPath: executionPath(manifest, request.id)
|
|
954
|
+
});
|
|
955
|
+
appendBrokerAudit(manifest, 'executor-prepare-start', {
|
|
1040
956
|
...requestAuditFields(manifest, request),
|
|
1041
|
-
|
|
957
|
+
requestPath: claimed,
|
|
958
|
+
executorCwd: manifest.repoRoot,
|
|
959
|
+
executorEntry: options.internalCliPath ?? process.argv[1] ?? null
|
|
960
|
+
});
|
|
961
|
+
prepared = await prepareExecution({
|
|
962
|
+
manifest, manifestPath, request, requestPath: claimed,
|
|
963
|
+
internalCliPath: options.internalCliPath ?? process.argv[1]
|
|
964
|
+
});
|
|
965
|
+
const preparedExecution = prepared;
|
|
966
|
+
if (!preparedExecution)
|
|
967
|
+
throw new Error('SANDBOX_CONTROL_EXECUTION_PREPARE_INVALID');
|
|
968
|
+
criticalRequestPhase(manifest, request, 'prepared', 'in-progress', `${preparedExecution.execution.child.pid}`);
|
|
969
|
+
appendBrokerAudit(manifest, 'executor-prepared', {
|
|
970
|
+
...requestAuditFields(manifest, request),
|
|
971
|
+
requestPath: claimed,
|
|
972
|
+
executorCwd: manifest.repoRoot,
|
|
1042
973
|
childPid: preparedExecution.execution.child.pid,
|
|
1043
|
-
childStartTime: preparedExecution.execution.child.startTime
|
|
974
|
+
childStartTime: preparedExecution.execution.child.startTime,
|
|
975
|
+
childProcessGroupId: preparedExecution.execution.child.processGroupId,
|
|
976
|
+
executionPath: executionPath(manifest, request.id)
|
|
1044
977
|
});
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
978
|
+
const execution = {
|
|
979
|
+
request, prepared: preparedExecution, result: null,
|
|
980
|
+
resultEvidenceWritten: false, failure: null, settled: false
|
|
981
|
+
};
|
|
982
|
+
active = execution;
|
|
983
|
+
preparedExecution.completion.then((result) => {
|
|
984
|
+
execution.result = sanitizeSandboxControlResult(manifest, result);
|
|
985
|
+
appendBrokerAudit(manifest, 'executor-completed', {
|
|
1050
986
|
...requestAuditFields(manifest, request),
|
|
1051
|
-
|
|
1052
|
-
|
|
987
|
+
...resultAuditFields(execution.result),
|
|
988
|
+
childPid: preparedExecution.execution.child.pid,
|
|
989
|
+
childStartTime: preparedExecution.execution.child.startTime
|
|
1053
990
|
});
|
|
1054
|
-
|
|
1055
|
-
|
|
991
|
+
try {
|
|
992
|
+
writeSandboxControlResultEvidence(manifest, request.id, execution.result);
|
|
993
|
+
execution.resultEvidenceWritten = true;
|
|
994
|
+
execution.settled = true;
|
|
995
|
+
appendBrokerAudit(manifest, 'executor-result-evidence-written', {
|
|
996
|
+
...requestAuditFields(manifest, request),
|
|
997
|
+
resultPath: path.join(manifest.processingDir, request.id, 'result.json'),
|
|
998
|
+
...resultAuditFields(execution.result)
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
catch (error) {
|
|
1002
|
+
execution.failure = error;
|
|
1003
|
+
appendBrokerAudit(manifest, 'executor-result-evidence-failed', {
|
|
1004
|
+
...requestAuditFields(manifest, request),
|
|
1005
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
}, (error) => {
|
|
1056
1009
|
execution.failure = error;
|
|
1057
|
-
|
|
1010
|
+
execution.settled = true;
|
|
1011
|
+
appendBrokerAudit(manifest, 'executor-failed', {
|
|
1058
1012
|
...requestAuditFields(manifest, request),
|
|
1013
|
+
childPid: preparedExecution.execution.child.pid,
|
|
1014
|
+
childStartTime: preparedExecution.execution.child.startTime,
|
|
1059
1015
|
errorType: error instanceof Error ? error.name : typeof error,
|
|
1060
1016
|
});
|
|
1061
|
-
}
|
|
1062
|
-
}, (error) => {
|
|
1063
|
-
execution.failure = error;
|
|
1064
|
-
execution.settled = true;
|
|
1065
|
-
appendBrokerAudit(manifest, 'executor-failed', {
|
|
1066
|
-
...requestAuditFields(manifest, request),
|
|
1067
|
-
childPid: preparedExecution.execution.child.pid,
|
|
1068
|
-
childStartTime: preparedExecution.execution.child.startTime,
|
|
1069
|
-
errorType: error instanceof Error ? error.name : typeof error,
|
|
1070
1017
|
});
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
active = null;
|
|
1081
|
-
retiring = true;
|
|
1082
|
-
continue;
|
|
1083
|
-
}
|
|
1084
|
-
criticalRequestPhase(manifest, request, 'accepted-authorized', 'in-progress');
|
|
1085
|
-
writeAcceptedResponse(manifest, {
|
|
1086
|
-
version: 2, id, phase: 'accepted', exitCode: null, stdout: '', stderr: '', error: null
|
|
1087
|
-
});
|
|
1088
|
-
writeSandboxControlTransition(manifest, { requestId: request.id, phase: 'accepted-committed' });
|
|
1089
|
-
appendBrokerAudit(manifest, 'request-accepted', {
|
|
1090
|
-
...requestAuditFields(manifest, request),
|
|
1091
|
-
acceptedPath: acceptedResponsePath(manifest, id),
|
|
1092
|
-
executionPhase: 'prepared'
|
|
1093
|
-
});
|
|
1094
|
-
if (!brokerOwns()) {
|
|
1095
|
-
prepared.terminate(false);
|
|
1096
|
-
active = null;
|
|
1097
|
-
retiring = true;
|
|
1098
|
-
break;
|
|
1099
|
-
}
|
|
1100
|
-
try {
|
|
1101
|
-
criticalRequestPhase(manifest, request, 'start-authorized', 'in-progress', `${prepared.execution.child.pid}`);
|
|
1102
|
-
appendBrokerAudit(manifest, 'executor-start', {
|
|
1103
|
-
...requestAuditFields(manifest, request),
|
|
1104
|
-
childPid: prepared.execution.child.pid,
|
|
1105
|
-
childStartTime: prepared.execution.child.startTime,
|
|
1106
|
-
executionPath: executionPath(manifest, request.id)
|
|
1018
|
+
if (!brokerOwns()) {
|
|
1019
|
+
prepared.terminate(false);
|
|
1020
|
+
active = null;
|
|
1021
|
+
retiring = true;
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
criticalRequestPhase(manifest, request, 'accepted-authorized', 'in-progress');
|
|
1025
|
+
writeAcceptedResponse(manifest, {
|
|
1026
|
+
version: 2, id, phase: 'accepted', exitCode: null, stdout: '', stderr: '', error: null
|
|
1107
1027
|
});
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
catch (error) {
|
|
1111
|
-
appendBrokerAudit(manifest, 'executor-start-failed', {
|
|
1028
|
+
writeSandboxControlTransition(manifest, { requestId: request.id, phase: 'accepted-committed' });
|
|
1029
|
+
appendBrokerAudit(manifest, 'request-accepted', {
|
|
1112
1030
|
...requestAuditFields(manifest, request),
|
|
1113
|
-
|
|
1031
|
+
acceptedPath: acceptedResponsePath(manifest, id),
|
|
1032
|
+
executionPhase: 'prepared'
|
|
1114
1033
|
});
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
if (!owned || !brokerOwns()) {
|
|
1034
|
+
if (!brokerOwns()) {
|
|
1035
|
+
prepared.terminate(false);
|
|
1118
1036
|
active = null;
|
|
1119
1037
|
retiring = true;
|
|
1120
1038
|
break;
|
|
1121
1039
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1040
|
+
try {
|
|
1041
|
+
criticalRequestPhase(manifest, request, 'start-authorized', 'in-progress', `${prepared.execution.child.pid}`);
|
|
1042
|
+
appendBrokerAudit(manifest, 'executor-start', {
|
|
1043
|
+
...requestAuditFields(manifest, request),
|
|
1044
|
+
childPid: prepared.execution.child.pid,
|
|
1045
|
+
childStartTime: prepared.execution.child.startTime,
|
|
1046
|
+
executionPath: executionPath(manifest, request.id)
|
|
1047
|
+
});
|
|
1048
|
+
prepared.start(brokerOwns);
|
|
1049
|
+
}
|
|
1050
|
+
catch (error) {
|
|
1051
|
+
appendBrokerAudit(manifest, 'executor-start-failed', {
|
|
1052
|
+
...requestAuditFields(manifest, request),
|
|
1053
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
1054
|
+
});
|
|
1055
|
+
const owned = brokerOwns();
|
|
1056
|
+
prepared.terminate(owned);
|
|
1057
|
+
if (!owned || !brokerOwns()) {
|
|
1058
|
+
active = null;
|
|
1059
|
+
retiring = true;
|
|
1060
|
+
break;
|
|
1061
|
+
}
|
|
1062
|
+
writeSandboxControlResponse(manifest, unknown(id));
|
|
1063
|
+
if (!brokerOwns()) {
|
|
1064
|
+
active = null;
|
|
1065
|
+
retiring = true;
|
|
1066
|
+
break;
|
|
1067
|
+
}
|
|
1068
|
+
removeAcceptedResponse(manifest, id);
|
|
1069
|
+
fs.rmSync(path.join(manifest.processingDir, id), { recursive: true, force: true });
|
|
1124
1070
|
active = null;
|
|
1071
|
+
claimed = null;
|
|
1072
|
+
if (!brokerOwns()) {
|
|
1073
|
+
retiring = true;
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
1076
|
+
appendBrokerAudit(manifest, 'executor-gate-failed', { requestId: id });
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
catch (error) {
|
|
1081
|
+
if (prepared) {
|
|
1082
|
+
try {
|
|
1083
|
+
prepared.terminate(brokerOwns());
|
|
1084
|
+
}
|
|
1085
|
+
catch { /* cleanup is best effort after a failed admission */ }
|
|
1086
|
+
prepared = null;
|
|
1087
|
+
active = null;
|
|
1088
|
+
}
|
|
1089
|
+
if (!brokerOwns()) {
|
|
1125
1090
|
retiring = true;
|
|
1126
1091
|
break;
|
|
1127
1092
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1093
|
+
const detail = controlError(error);
|
|
1094
|
+
appendBrokerAudit(manifest, 'request-rejected', {
|
|
1095
|
+
requestId: id,
|
|
1096
|
+
requestFamily: validatedRequest?.family ?? null,
|
|
1097
|
+
sandboxTaskId: manifest.taskId,
|
|
1098
|
+
requestPath: claimed,
|
|
1099
|
+
errorCode: detail.code,
|
|
1100
|
+
errorRetryable: detail.retryable,
|
|
1101
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
1102
|
+
});
|
|
1103
|
+
writeSandboxControlResponse(manifest, rejected(id, error));
|
|
1132
1104
|
if (!brokerOwns()) {
|
|
1133
1105
|
retiring = true;
|
|
1134
1106
|
break;
|
|
1135
1107
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
catch (error) {
|
|
1141
|
-
if (prepared) {
|
|
1142
|
-
try {
|
|
1143
|
-
prepared.terminate(brokerOwns());
|
|
1144
|
-
}
|
|
1145
|
-
catch { /* cleanup is best effort after a failed admission */ }
|
|
1146
|
-
prepared = null;
|
|
1147
|
-
active = null;
|
|
1148
|
-
}
|
|
1149
|
-
if (!brokerOwns()) {
|
|
1150
|
-
retiring = true;
|
|
1151
|
-
break;
|
|
1152
|
-
}
|
|
1153
|
-
const detail = controlError(error);
|
|
1154
|
-
appendBrokerAudit(manifest, 'request-rejected', {
|
|
1155
|
-
requestId: id,
|
|
1156
|
-
requestFamily: validatedRequest?.family ?? null,
|
|
1157
|
-
sandboxTaskId: manifest.taskId,
|
|
1158
|
-
requestPath: claimed,
|
|
1159
|
-
errorCode: detail.code,
|
|
1160
|
-
errorRetryable: detail.retryable,
|
|
1161
|
-
errorType: error instanceof Error ? error.name : typeof error,
|
|
1162
|
-
});
|
|
1163
|
-
writeSandboxControlResponse(manifest, rejected(id, error));
|
|
1164
|
-
if (!brokerOwns()) {
|
|
1165
|
-
retiring = true;
|
|
1166
|
-
break;
|
|
1108
|
+
removeAcceptedResponse(manifest, id);
|
|
1109
|
+
if (claimed)
|
|
1110
|
+
fs.rmSync(path.dirname(claimed), { recursive: true, force: true });
|
|
1167
1111
|
}
|
|
1168
|
-
removeAcceptedResponse(manifest, id);
|
|
1169
|
-
if (claimed)
|
|
1170
|
-
fs.rmSync(path.dirname(claimed), { recursive: true, force: true });
|
|
1171
1112
|
}
|
|
1172
|
-
}
|
|
1173
1113
|
if (retiring || !brokerOwns())
|
|
1174
1114
|
break;
|
|
1175
1115
|
await delay(timing.controlTickMs);
|
|
@@ -1191,11 +1131,6 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1191
1131
|
}
|
|
1192
1132
|
}
|
|
1193
1133
|
if (owned && active.result && active.resultEvidenceWritten) {
|
|
1194
|
-
const finalizationView = await taskViewForFinalizationResult(manifest, active.request, active.result);
|
|
1195
|
-
if (finalizationView) {
|
|
1196
|
-
taskView = finalizationView;
|
|
1197
|
-
writeSandboxControlStatus(manifest, broker, 'healthy', null, null, Date.now(), taskView);
|
|
1198
|
-
}
|
|
1199
1134
|
if (publishExecutionResult(manifest, active.request, active.result, brokerOwns)) {
|
|
1200
1135
|
if (brokerOwns()) {
|
|
1201
1136
|
removeAcceptedResponse(manifest, active.request.id);
|
|
@@ -130,19 +130,6 @@ export function projectSandboxTaskView(input) {
|
|
|
130
130
|
reasonCode: receipt ? 'SANDBOX_TASK_VIEW_SOURCE_UNCONFIRMED' : 'SANDBOX_TASK_VIEW_EVIDENCE_UNAVAILABLE'
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
|
-
export function taskViewAfterFinalization(params) {
|
|
134
|
-
const receipt = receiptIdentity(params.receipt, params.generation, params.requestId);
|
|
135
|
-
if (!receipt) {
|
|
136
|
-
return {
|
|
137
|
-
state: 'unknown', taskId: params.taskId, observedSource: 'unknown', receipt: null,
|
|
138
|
-
reasonCode: 'SANDBOX_TASK_VIEW_RECEIPT_INVALID'
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return {
|
|
142
|
-
state: 'finalized-stale', taskId: params.taskId, observedSource: 'active', receipt,
|
|
143
|
-
reasonCode: 'SANDBOX_TASK_VIEW_FINALIZED'
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
133
|
export function mergeSandboxTaskView(canonical, previous) {
|
|
147
134
|
if (previous.state !== 'finalized-stale' && previous.state !== 'unknown')
|
|
148
135
|
return canonical;
|
|
@@ -38,11 +38,19 @@ export function sandboxCoreBindMounts(config, branch, overrides) {
|
|
|
38
38
|
...workspaceMounts,
|
|
39
39
|
];
|
|
40
40
|
if (taskBound) {
|
|
41
|
+
const taskMountPath = path.posix.join('/workspace/.agents/workspace/active', overrides.taskId);
|
|
41
42
|
mounts.push({
|
|
42
43
|
hostPaths: taskSources,
|
|
43
|
-
containerPath:
|
|
44
|
+
containerPath: taskMountPath,
|
|
44
45
|
readOnly: false
|
|
45
46
|
});
|
|
47
|
+
if (overrides.completedTaskSource) {
|
|
48
|
+
mounts.push({
|
|
49
|
+
hostPaths: [overrides.completedTaskSource],
|
|
50
|
+
containerPath: path.posix.join('/workspace/.agents/workspace/completed', overrides.taskId),
|
|
51
|
+
readOnly: false
|
|
52
|
+
});
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
mounts.push({
|
|
48
56
|
hostPaths: [shareCommonDir(config)],
|