deadbyte-mcp 0.13.0 → 0.15.0
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/.gitattributes +7 -0
- package/AGENTS.md +18 -0
- package/CONTEXT.md +3 -3
- package/MANIFEST.SHA256 +152 -75
- package/R42-PARENT.json +19 -0
- package/R43-PARENT.json +20 -0
- package/R44-DONORS.json +99 -0
- package/R44-PARENT.json +18 -0
- package/README.txt +7 -2
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/controller/README.TXT +4 -5
- package/controller/deadbyte-controller.ps1 +1 -1
- package/controller/deadbyte-desktop-policy.json +5 -5
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/ARCHITECTURE.md +8 -1
- package/docs/R44-ARCHITECTURE.md +37 -0
- package/harness/r42-agent-evals.json +48 -0
- package/harness/task-contract.schema.json +33 -0
- package/package.json +15 -8
- package/proof/CONTAINMENT-BUILD.txt +6 -6
- package/scripts/agent-eval-r42.mjs +46 -0
- package/scripts/deferred-slot-operation-r42.mjs +126 -0
- package/scripts/deferred-slot-operation-r43.mjs +126 -0
- package/scripts/deferred-slot-operation-r44.mjs +126 -0
- package/scripts/final-closure-r42.mjs +116 -0
- package/scripts/final-closure-r43.mjs +115 -0
- package/scripts/final-closure-r44.mjs +121 -0
- package/scripts/final-closure-verify-r42.mjs +223 -0
- package/scripts/final-closure-verify-r43.mjs +213 -0
- package/scripts/final-closure-verify-r44.mjs +220 -0
- package/scripts/finalize-r43.mjs +217 -0
- package/scripts/finalize-r44.mjs +217 -0
- package/scripts/full-regression-r43.mjs +20 -0
- package/scripts/full-regression-r44.mjs +20 -0
- package/scripts/gate-windows-r42.ps1 +54 -0
- package/scripts/gate-windows-r43.ps1 +36 -0
- package/scripts/gate-windows-r44.ps1 +36 -0
- package/scripts/release-parity-r42.mjs +235 -0
- package/scripts/release-parity-r43.mjs +218 -0
- package/scripts/release-parity-r44.mjs +242 -0
- package/scripts/release-parity-tests-r42.ps1 +6 -0
- package/scripts/release-parity-tests-r43.ps1 +8 -0
- package/scripts/release-parity-tests-r44.ps1 +8 -0
- package/scripts/verify-r42-parent.mjs +101 -0
- package/scripts/verify-r43-parent.mjs +126 -0
- package/scripts/verify-r44-parent.mjs +142 -0
- package/scripts/windows-gate-evidence-r42.mjs +64 -0
- package/scripts/windows-gate-evidence-r43.mjs +55 -0
- package/scripts/windows-gate-evidence-r44.mjs +55 -0
- package/src/agent-backend-r44.mjs +254 -0
- package/src/agent-eval-r42.mjs +73 -0
- package/src/agent-eval-runner-r42.mjs +138 -0
- package/src/agent-governance-r42.mjs +142 -0
- package/src/autonomous-context-engine.mjs +2 -0
- package/src/autonomous-loop-state.mjs +10 -0
- package/src/autonomous-mcp-tools.mjs +21 -6
- package/src/autonomous-output-contracts.mjs +18 -2
- package/src/autonomous-planner-contracts.mjs +3 -0
- package/src/autonomous-planner.mjs +46 -6
- package/src/autonomous-policy.mjs +50 -5
- package/src/autonomous-runtime.mjs +138 -25
- package/src/autonomous-supervisor-host.mjs +12 -2
- package/src/autonomous-supervisor.mjs +1 -1
- package/src/capability-ledger.mjs +2 -1
- package/src/codex-app-server-r44.mjs +154 -0
- package/src/coding-plane.mjs +66 -19
- package/src/durable-job-r44.mjs +145 -0
- package/src/evidence-publisher-r42.mjs +76 -0
- package/src/external-job-provider-r44.mjs +126 -0
- package/src/host-plane.mjs +27 -6
- package/src/job-supervisor-host-r44.mjs +112 -0
- package/src/machine-fs-smoke-client.mjs +1 -1
- package/src/machine-fs.mjs +21 -10
- package/src/mcp-host-smoke-client.mjs +1 -1
- package/src/mcp-server.mjs +20 -3
- package/src/mcp-smoke-client.mjs +1 -1
- package/src/native-diff-v2.mjs +3 -3
- package/src/native-diff.mjs +3 -2
- package/src/observation-smoke-client.mjs +1 -1
- package/src/operator-surface.mjs +2 -2
- package/src/process-policy.mjs +19 -0
- package/src/process-runtime.mjs +5 -2
- package/src/process-smoke-client.mjs +2 -2
- package/src/provider-circuit.mjs +10 -4
- package/src/r44-compact-disarmed-probe.mjs +74 -0
- package/src/r44-full-surface-probe.mjs +34 -0
- package/src/remote-device-r44.mjs +205 -0
- package/src/remote-mcp-autonomous-smoke-client.mjs +4 -4
- package/src/remote-mcp-r44-parity-client.mjs +203 -0
- package/src/remote-mcp-smoke-client.mjs +7 -4
- package/src/runtime-update.mjs +64 -31
- package/src/skill-mcp-tools-r44.mjs +37 -0
- package/src/skill-plane-r44.mjs +203 -0
- package/src/tunnel-stdio-compat-smoke.mjs +1 -1
- package/src/version.mjs +1 -1
- package/test/agent-backend-r44.test.mjs +115 -0
- package/test/agent-eval-r42.test.mjs +39 -0
- package/test/agent-eval-runner-r42.test.mjs +61 -0
- package/test/agent-governance-r42.test.mjs +77 -0
- package/test/agent-runtime.test.mjs +3 -3
- package/test/autonomous-loop.test.mjs +97 -11
- package/test/autonomous-r34-e2e.test.mjs +2 -1
- package/test/autonomous-runtime.test.mjs +2 -2
- package/test/capability-ledger-r36.test.mjs +3 -3
- package/test/cli-entrypoint.test.mjs +1 -1
- package/test/codex-app-server-r44.test.mjs +115 -0
- package/test/codex-autonomous-r44.test.mjs +87 -0
- package/test/coding-plane.test.mjs +2 -2
- package/test/coding-runtime.test.mjs +36 -1
- package/test/compact-catalog-r36.test.mjs +3 -3
- package/test/compact-max-catalog-r40.test.mjs +4 -2
- package/test/compact-max-catalog-r44.test.mjs +97 -0
- package/test/core.test.mjs +1 -1
- package/test/durable-job-r44.test.mjs +75 -0
- package/test/evidence-publisher-r42.test.mjs +53 -0
- package/test/external-job-provider-r44.test.mjs +46 -0
- package/test/full-max-catalog-r40.test.mjs +5 -3
- package/test/full-max-catalog-r44.test.mjs +91 -0
- package/test/host-plane.test.mjs +15 -1
- package/test/human-clarification-r42.test.mjs +53 -0
- package/test/native-diff.test.mjs +28 -0
- package/test/output-schema.test.mjs +2 -2
- package/test/process-policy.test.mjs +22 -1
- package/test/prompts-resources.test.mjs +1 -1
- package/test/provider-responses-r42.test.mjs +90 -0
- package/test/r33-closeout-regression.test.mjs +14 -16
- package/test/r33-finalization.test.mjs +7 -7
- package/test/r42-finalization.test.mjs +38 -0
- package/test/r43-finalization.test.mjs +31 -0
- package/test/r43-finalizer.test.mjs +34 -0
- package/test/r43-parent.test.mjs +29 -0
- package/test/r44-finalization.test.mjs +58 -0
- package/test/r44-finalizer.test.mjs +48 -0
- package/test/r44-parent.test.mjs +25 -0
- package/test/release-version.test.mjs +53 -19
- package/test/remote-device-r44.test.mjs +104 -0
- package/test/runtime-self-update.test.mjs +42 -0
- package/test/skill-mcp-r44.test.mjs +38 -0
- package/test/skill-plane-r44.test.mjs +93 -0
- package/test/standing-grants.test.mjs +5 -1
- package/test/task-contract-r42.test.mjs +41 -0
|
@@ -146,6 +146,7 @@ export function deriveLoopState(goal,events) {
|
|
|
146
146
|
replan_count:0,
|
|
147
147
|
pending_action:null,
|
|
148
148
|
pending_approval:false,
|
|
149
|
+
clarification:null,
|
|
149
150
|
progress:null,
|
|
150
151
|
critic:null,
|
|
151
152
|
repair:null,
|
|
@@ -223,6 +224,10 @@ export function deriveLoopState(goal,events) {
|
|
|
223
224
|
state.phase='WAITING';
|
|
224
225
|
state.wait_reason=requireText(payload.reason,'loop wait reason');
|
|
225
226
|
state.pending_approval=payload.requires_approval===true;
|
|
227
|
+
state.clarification=payload.reason==='human_input_required' ? {
|
|
228
|
+
question:requireText(payload.question,'loop clarification question',1000),
|
|
229
|
+
choices:Array.isArray(payload.choices) ? payload.choices.map((choice,index)=>requireText(choice,`loop clarification choice ${index+1}`,256)) : []
|
|
230
|
+
} : null;
|
|
226
231
|
break;
|
|
227
232
|
case 'waiting_resumed': {
|
|
228
233
|
if (state.phase !== 'WAITING') throw new Error('loop waiting_resumed outside WAITING phase');
|
|
@@ -231,6 +236,7 @@ export function deriveLoopState(goal,events) {
|
|
|
231
236
|
state.phase=resumed;
|
|
232
237
|
state.wait_reason=null;
|
|
233
238
|
state.pending_approval=false;
|
|
239
|
+
state.clarification=null;
|
|
234
240
|
break;
|
|
235
241
|
}
|
|
236
242
|
case 'planner_requested':
|
|
@@ -255,24 +261,28 @@ export function deriveLoopState(goal,events) {
|
|
|
255
261
|
state.phase='PLAN';
|
|
256
262
|
state.wait_reason=null;
|
|
257
263
|
state.pending_approval=false;
|
|
264
|
+
state.clarification=null;
|
|
258
265
|
}
|
|
259
266
|
break;
|
|
260
267
|
case 'goal_cancelled':
|
|
261
268
|
state.phase='FAILED';
|
|
262
269
|
state.wait_reason=typeof payload.reason==='string'&&payload.reason.length>0?payload.reason:'cancelled';
|
|
263
270
|
state.pending_approval=false;
|
|
271
|
+
state.clarification=null;
|
|
264
272
|
state.pending_action=null;
|
|
265
273
|
break;
|
|
266
274
|
case 'goal_failed':
|
|
267
275
|
state.phase='FAILED';
|
|
268
276
|
state.wait_reason=typeof payload.reason==='string'&&payload.reason.length>0?payload.reason:'failed';
|
|
269
277
|
state.pending_approval=false;
|
|
278
|
+
state.clarification=null;
|
|
270
279
|
state.pending_action=null;
|
|
271
280
|
break;
|
|
272
281
|
case 'release_completed':
|
|
273
282
|
state.phase='SUCCEEDED';
|
|
274
283
|
state.wait_reason=null;
|
|
275
284
|
state.pending_approval=false;
|
|
285
|
+
state.clarification=null;
|
|
276
286
|
state.pending_action=null;
|
|
277
287
|
break;
|
|
278
288
|
default:
|
|
@@ -25,6 +25,17 @@ const rmdirOperation = z.strictObject({ kind:z.literal('rmdir'), path:relPath, e
|
|
|
25
25
|
const nativeOperation = z.union([writeOperation,replaceOperation,deleteOperation,mkdirOperation,moveOperation,rmdirOperation]);
|
|
26
26
|
const plannerResponse = z.strictObject({ request_id:hex64, raw_text:z.string().min(2).max(8*1024*1024),
|
|
27
27
|
model:z.string().min(1).max(128).default('client-model') });
|
|
28
|
+
const taskContract = z.strictObject({
|
|
29
|
+
schema:z.literal('deadbyte.task-contract.v1'),
|
|
30
|
+
scope:z.array(z.string().min(1).max(512)).max(32).default([]),
|
|
31
|
+
non_goals:z.array(z.string().min(1).max(512)).max(24).default([]),
|
|
32
|
+
constraints:z.array(z.string().min(1).max(512)).max(32).default([]),
|
|
33
|
+
evidence_requirements:z.array(z.string().min(1).max(512)).max(32).default([]),
|
|
34
|
+
risk_level:z.enum(['low','medium','high']).default('medium'),
|
|
35
|
+
clarification_policy:z.enum(['ask_when_blocked','fail_closed']).default('ask_when_blocked'),
|
|
36
|
+
project_default:z.enum(['lightweight','structured','agentic']).default('structured'),
|
|
37
|
+
explicit_override:z.enum(['lightweight','structured','agentic']).nullable().default(null)
|
|
38
|
+
});
|
|
28
39
|
function result(schema,value,isError=false) { return autonomousStructuredResult(schema,value,isError); }
|
|
29
40
|
function fail(schema,error,status='failed') { return result(schema,{ status, error:String(error) },true); }
|
|
30
41
|
|
|
@@ -60,11 +71,12 @@ export function registerAutonomousTools(server,{ autonomousRuntime, nativeDiffRu
|
|
|
60
71
|
description:'Submit one bounded R24 production goal. Execution requires separate live coding and autonomous leases.',
|
|
61
72
|
inputSchema:z.strictObject({ submission_id:id, root_id:id, title:z.string().max(160).default(''),
|
|
62
73
|
goal:z.string().min(1).max(8192), acceptance:z.string().max(4096).default(''),
|
|
74
|
+
task_contract:taskContract.nullable().default(null),
|
|
63
75
|
max_iterations:z.number().int().min(1).max(64).nullable().default(null) }),
|
|
64
76
|
outputSchema:autonomousGoalSubmitOutputSchema
|
|
65
|
-
},async({submission_id,root_id,title,goal,acceptance,max_iterations})=>{ try {
|
|
77
|
+
},async({submission_id,root_id,title,goal,acceptance,task_contract,max_iterations})=>{ try {
|
|
66
78
|
return result(autonomousGoalSubmitOutputSchema,await autonomousRuntime.submit({ submissionId:submission_id,
|
|
67
|
-
rootId:root_id,title,goal,acceptance,maxIterations:max_iterations })); }
|
|
79
|
+
rootId:root_id,title,goal,acceptance,taskContract:task_contract,maxIterations:max_iterations })); }
|
|
68
80
|
catch(error){ return fail(autonomousGoalSubmitOutputSchema,error); } });
|
|
69
81
|
server.registerTool('autonomous_goal_run',{
|
|
70
82
|
description:'Advance one autonomous production goal through inspect/native-diff/build/test/benchmark/replan cycles. Client-planner mode returns a typed input_required sentinel for the Bridge MRTR adapter.',
|
|
@@ -100,11 +112,14 @@ export function registerAutonomousTools(server,{ autonomousRuntime, nativeDiffRu
|
|
|
100
112
|
catch(error){ return fail(autonomousGoalCancelOutputSchema,error); } });
|
|
101
113
|
|
|
102
114
|
server.registerTool('autonomous_goal_approve',{
|
|
103
|
-
description:'Approve or reject resuming a paused autonomous goal. This never arms or renews any lease and cannot bypass release evidence.',
|
|
104
|
-
inputSchema:z.strictObject({ goal_id:hex64, decision:z.enum(['approve','reject']).default('approve')
|
|
115
|
+
description:'Approve or reject resuming a paused autonomous goal, optionally supplying the bounded answer required by a typed human clarification. This never arms or renews any lease and cannot bypass release evidence.',
|
|
116
|
+
inputSchema:z.strictObject({ goal_id:hex64, decision:z.enum(['approve','reject']).default('approve'),
|
|
117
|
+
answer:z.string().min(1).max(4096).nullable().default(null),
|
|
118
|
+
approval_subject_sha256:hex64.nullable().default(null),
|
|
119
|
+
expires_in_ms:z.number().int().min(1000).max(3600000).default(300000) }),
|
|
105
120
|
outputSchema:autonomousGoalApproveOutputSchema
|
|
106
|
-
},async({goal_id,decision})=>{ try { return result(autonomousGoalApproveOutputSchema,
|
|
107
|
-
await autonomousRuntime.approve({goalId:goal_id,decision})); }
|
|
121
|
+
},async({goal_id,decision,answer,approval_subject_sha256,expires_in_ms})=>{ try { return result(autonomousGoalApproveOutputSchema,
|
|
122
|
+
await autonomousRuntime.approve({goalId:goal_id,decision,answer,approvalSubjectSha256:approval_subject_sha256,expiresInMs:expires_in_ms})); }
|
|
108
123
|
catch(error){ return fail(autonomousGoalApproveOutputSchema,error); } });
|
|
109
124
|
|
|
110
125
|
server.registerTool('autonomous_goal_verify',{
|
|
@@ -15,12 +15,28 @@ const loopProgress = z.strictObject({
|
|
|
15
15
|
const loopPendingAction = z.strictObject({
|
|
16
16
|
action_id:hex64, request_sha256:hex64, kind:z.string().regex(/^[A-Za-z0-9._-]{1,64}$/)
|
|
17
17
|
});
|
|
18
|
+
const loopClarification = z.strictObject({
|
|
19
|
+
question:z.string().min(1).max(1000), choices:z.array(z.string().min(1).max(256)).max(5)
|
|
20
|
+
});
|
|
21
|
+
const loopApprovalSubject = z.strictObject({
|
|
22
|
+
goal_id:hex64,reviewed_event_seq:z.number().int().min(1),reviewed_event_sha256:hex64,
|
|
23
|
+
journal_head_sha256:hex64,scope:z.enum(['resume_goal','human_clarification','desktop_resume','interrupted_effect_resume']),
|
|
24
|
+
subject:z.strictObject({reason:z.string().min(1).max(1024),waiting_payload_sha256:hex64}),approval_subject_sha256:hex64
|
|
25
|
+
});
|
|
26
|
+
const taskDagTask=z.strictObject({task_id:z.string().regex(/^[A-Za-z0-9._-]{1,64}$/),depends_on:z.array(z.string()).max(256),
|
|
27
|
+
input_artifacts:z.array(z.string()).max(128),output_artifacts:z.array(z.string()).max(128),
|
|
28
|
+
state:z.enum(['PENDING','RUNNING','COMPLETE','FAILED','STALE'])});
|
|
29
|
+
const taskDag=z.strictObject({schema:z.literal('deadbyte.task-dag.v1'),run_id:z.string().regex(/^[A-Za-z0-9._-]{1,96}$/),
|
|
30
|
+
goal_id:hex64,tasks:z.array(taskDagTask).min(1).max(256),dag_sha256:hex64});
|
|
18
31
|
const publicLoopSchema = z.strictObject({
|
|
19
32
|
schema:z.literal('deadbyte.autonomous-loop-state.v1'), phase:loopPhase,
|
|
20
33
|
plan_id:hex64.nullable(), plan_version:z.number().int().min(1).nullable(),
|
|
21
34
|
current_step:loopStep.nullable(), replan_count:z.number().int().min(0),
|
|
22
35
|
progress:loopProgress.nullable(), pending_action:loopPendingAction.nullable(),
|
|
23
|
-
pending_approval:z.boolean(), wait_reason:z.string().min(1).max(1024).nullable()
|
|
36
|
+
pending_approval:z.boolean(), wait_reason:z.string().min(1).max(1024).nullable(),
|
|
37
|
+
clarification:loopClarification.nullable().default(null),
|
|
38
|
+
approval_subject:loopApprovalSubject.nullable().default(null),
|
|
39
|
+
task_dag:taskDag.nullable().default(null)
|
|
24
40
|
});
|
|
25
41
|
function requireFields(value,ctx,fields) {
|
|
26
42
|
for (const field of fields) if (value[field] === undefined) ctx.addIssue({ code:'custom', path:[field], message:`${field} is required` });
|
|
@@ -52,7 +68,7 @@ export const autonomousSessionStatusOutputSchema = statusContract({
|
|
|
52
68
|
shape:{ configured:z.literal(true).optional(), armed:z.boolean().optional(), autonomous_armed:z.boolean().optional(),
|
|
53
69
|
autonomous_reason:z.string().optional(), autonomous_expires_at_utc:z.string().nullable().optional(),
|
|
54
70
|
coding_armed:z.boolean().optional(), coding_reason:z.string().optional(), root_ids:z.array(z.string()).max(64).optional(),
|
|
55
|
-
planner_backend:z.enum(['client_sampling','openai_compatible']).optional(), profile_ids:z.array(z.string()).max(128).optional(),
|
|
71
|
+
planner_backend:z.enum(['client_sampling','openai_compatible','openai_responses','codex_app_server']).optional(), profile_ids:z.array(z.string()).max(128).optional(),
|
|
56
72
|
policy_sha256:hex64.optional(), coding_policy_sha256:hex64.optional() }
|
|
57
73
|
});
|
|
58
74
|
|
|
@@ -163,6 +163,9 @@ export const r34PlannerDecisionSchema = z.discriminatedUnion('kind',[
|
|
|
163
163
|
step_id:z.string().regex(ID),evidence:z.array(r34EvidenceSchema).min(1).max(32)}),
|
|
164
164
|
z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('replan'),
|
|
165
165
|
reason:z.string().min(1).max(512),steps:z.array(r34PlanStepSchema).min(1).max(24)}),
|
|
166
|
+
z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('clarify'),
|
|
167
|
+
question:z.string().min(1).max(1000),
|
|
168
|
+
choices:z.array(z.string().min(1).max(256)).min(2).max(5).default([])}),
|
|
166
169
|
z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('pause'),
|
|
167
170
|
reason:z.string().min(1).max(1000)}),
|
|
168
171
|
z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('finish'),
|
|
@@ -276,7 +276,7 @@ export function parseR34PlannerDecision(rawText, policy) {
|
|
|
276
276
|
assertR34UniqueSteps(decision.steps,'R34 replan');
|
|
277
277
|
return decision;
|
|
278
278
|
}
|
|
279
|
-
if (decision.kind === 'pause' || decision.kind === 'finish') return decision;
|
|
279
|
+
if (decision.kind === 'clarify' || decision.kind === 'pause' || decision.kind === 'finish') return decision;
|
|
280
280
|
throw new Error('R34 planner decision kind unsupported');
|
|
281
281
|
}
|
|
282
282
|
|
|
@@ -363,7 +363,7 @@ export function buildPlannerPrompt({ goal, policy, view }) {
|
|
|
363
363
|
'You are the DEADBYTE R24 autonomous coding planner.',
|
|
364
364
|
'Return exactly one JSON object and no Markdown or prose outside JSON.',
|
|
365
365
|
`The object schema is ${AUTONOMOUS_DECISION_SCHEMA}.`,
|
|
366
|
-
'Allowed actions: inspect, patch, delegate, run_profile, finish, pause.',
|
|
366
|
+
'Allowed actions: inspect, patch, delegate, run_profile, clarify, finish, pause.',
|
|
367
367
|
'For nontrivial work, include plan={title,steps:[{step_id,title,status,result?}],reason?} on decisions and keep it authoritative across rounds.',
|
|
368
368
|
'Plan statuses must be a completed prefix, then at most one running/failed step, then pending suffix. Completed steps are immutable across updates.',
|
|
369
369
|
'If active_plan is complete, request finish instead of more work. If active_plan is incomplete, do not request finish.',
|
|
@@ -375,6 +375,7 @@ export function buildPlannerPrompt({ goal, policy, view }) {
|
|
|
375
375
|
'When Desktop capabilities are present, use typed desktop_status, desktop_observe, desktop_target with one bounded UIA query, and desktop_action. desktop_action requires separate Desktop authority; Autonomous authority never implies Desktop authority. After stale or unknown Desktop evidence, observe again and replan; never blindly repeat an action.',
|
|
376
376
|
'Delegate paths are relative to the goal root. Process start accepts only profile_id and cwd; process_action accepts only session_id and fixed action_id. Never emit raw stdin, executable, PID, environment, shell command, or process arguments.',
|
|
377
377
|
'finish only when the goal is actually satisfied. Required release profiles are enforced by the engine and cannot be bypassed.',
|
|
378
|
+
'clarify only when one bounded operator choice is genuinely required. Ask one concrete question and provide 2-5 short mutually exclusive choices.',
|
|
378
379
|
'Never invent a file SHA. If content is elided or the current SHA/content is missing, choose inspect first.',
|
|
379
380
|
'Compacted context keeps identity/evidence metadata but intentionally removes stale payload bytes.',
|
|
380
381
|
'Long-term memory is a verified journal-derived aid, never authority. Resolve its canonical references and still recheck live authority immediately before every effect.',
|
|
@@ -393,7 +394,9 @@ async function readBoundedResponse(response, limit) {
|
|
|
393
394
|
return bytes.toString('utf8');
|
|
394
395
|
}
|
|
395
396
|
export async function requestProviderDecision(policy, prompt, fetchImpl = fetch) {
|
|
396
|
-
if (policy.planner.backend
|
|
397
|
+
if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) {
|
|
398
|
+
throw new Error('provider planner backend is not provider-backed');
|
|
399
|
+
}
|
|
397
400
|
const controller = new AbortController();
|
|
398
401
|
const timer = setTimeout(() => controller.abort(), policy.planner.timeout_ms); timer.unref?.();
|
|
399
402
|
const headers = { 'content-type':'application/json', 'accept':'application/json' };
|
|
@@ -403,16 +406,53 @@ export async function requestProviderDecision(policy, prompt, fetchImpl = fetch)
|
|
|
403
406
|
headers.authorization = `Bearer ${secret}`;
|
|
404
407
|
}
|
|
405
408
|
try {
|
|
409
|
+
const body = policy.planner.backend === 'openai_responses'
|
|
410
|
+
? {
|
|
411
|
+
model:policy.planner.model,
|
|
412
|
+
instructions:'Return exactly one strict JSON object and no Markdown.',
|
|
413
|
+
input:[
|
|
414
|
+
{role:'system',content:[{type:'input_text',text:'Return strict JSON only.'}]},
|
|
415
|
+
{role:'user',content:[{type:'input_text',text:prompt}]}
|
|
416
|
+
],
|
|
417
|
+
max_output_tokens:policy.planner.max_tokens,
|
|
418
|
+
text:{format:{type:'json_object'}},
|
|
419
|
+
store:false,
|
|
420
|
+
...(policy.planner.reasoning_effort?{reasoning:{effort:policy.planner.reasoning_effort}}:{})
|
|
421
|
+
}
|
|
422
|
+
: { model:policy.planner.model, temperature:0,
|
|
423
|
+
max_tokens:policy.planner.max_tokens,
|
|
424
|
+
messages:[{ role:'system', content:'Return strict JSON only.' },{ role:'user', content:prompt }] };
|
|
406
425
|
const response = await fetchImpl(policy.planner.endpoint, {
|
|
407
426
|
method:'POST', redirect:'error', signal:controller.signal, headers,
|
|
408
|
-
body:JSON.stringify(
|
|
409
|
-
max_tokens:policy.planner.max_tokens,
|
|
410
|
-
messages:[{ role:'system', content:'Return strict JSON only.' },{ role:'user', content:prompt }] })
|
|
427
|
+
body:JSON.stringify(body)
|
|
411
428
|
});
|
|
412
429
|
const rawBody = await readBoundedResponse(response, policy.planner.max_response_bytes);
|
|
413
430
|
if (!response.ok) throw new Error(`planner HTTP ${response.status}: ${rawBody.slice(0,512)}`);
|
|
414
431
|
let parsed;
|
|
415
432
|
try { parsed = JSON.parse(rawBody); } catch { throw new Error('planner HTTP response is not JSON'); }
|
|
433
|
+
if (policy.planner.backend === 'openai_responses') {
|
|
434
|
+
if (parsed?.status !== 'completed') throw new Error(`planner Responses API response not completed: ${String(parsed?.status ?? 'missing')}`);
|
|
435
|
+
const content=[];
|
|
436
|
+
let refused=false;
|
|
437
|
+
for (const item of Array.isArray(parsed?.output) ? parsed.output : []) {
|
|
438
|
+
if (item?.type !== 'message') continue;
|
|
439
|
+
for (const part of Array.isArray(item.content) ? item.content : []) {
|
|
440
|
+
if (part?.type === 'refusal') refused=true;
|
|
441
|
+
if (part?.type === 'output_text' && typeof part.text === 'string') content.push(part.text);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (refused) throw new Error('planner Responses API refusal');
|
|
445
|
+
if (content.length < 1) throw new Error('planner Responses API response missing output_text');
|
|
446
|
+
const usage=parsed?.usage && Number.isInteger(parsed.usage.input_tokens) && Number.isInteger(parsed.usage.output_tokens) && Number.isInteger(parsed.usage.total_tokens)
|
|
447
|
+
? {input_tokens:parsed.usage.input_tokens,output_tokens:parsed.usage.output_tokens,total_tokens:parsed.usage.total_tokens}
|
|
448
|
+
: null;
|
|
449
|
+
return {
|
|
450
|
+
backend:'openai_responses', model:typeof parsed.model === 'string' ? parsed.model.slice(0,128) : policy.planner.model,
|
|
451
|
+
raw_text:content.join(''),
|
|
452
|
+
response_id:typeof parsed.id === 'string' ? parsed.id.slice(0,160) : null,
|
|
453
|
+
usage
|
|
454
|
+
};
|
|
455
|
+
}
|
|
416
456
|
const content = parsed?.choices?.[0]?.message?.content;
|
|
417
457
|
if (typeof content !== 'string') throw new Error('planner HTTP response missing choices[0].message.content');
|
|
418
458
|
return { backend:'openai_compatible', model:typeof parsed.model === 'string' ? parsed.model : policy.planner.model,
|
|
@@ -30,12 +30,31 @@ function normalizeProviderCircuit(raw) {
|
|
|
30
30
|
half_open_probe_limit:integer(value.half_open_probe_limit,'planner.circuit.half_open_probe_limit',1,8,1)
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
-
function normalizePlanner(raw) {
|
|
33
|
+
function normalizePlanner(raw,codingPolicy,rootIds) {
|
|
34
34
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('autonomous planner missing');
|
|
35
35
|
const backend = raw.backend;
|
|
36
|
-
if (!['client_sampling', 'openai_compatible'].includes(backend)) throw new Error('autonomous planner backend invalid');
|
|
36
|
+
if (!['client_sampling', 'openai_compatible', 'openai_responses', 'codex_app_server'].includes(backend)) throw new Error('autonomous planner backend invalid');
|
|
37
37
|
const common = { backend, max_tokens: integer(raw.max_tokens, 'planner.max_tokens', 256, 16384, 4096) };
|
|
38
38
|
if (backend === 'client_sampling') return common;
|
|
39
|
+
if (typeof raw.model !== 'string' || raw.model.length < 1 || raw.model.length > 128) throw new Error('planner.model invalid');
|
|
40
|
+
if (backend === 'codex_app_server') {
|
|
41
|
+
if (!ID_RE.test(raw.root_id ?? '') || !rootIds.includes(raw.root_id) || !codingPolicy.roots[raw.root_id]) {
|
|
42
|
+
throw new Error('planner.root_id invalid');
|
|
43
|
+
}
|
|
44
|
+
if (typeof raw.executable !== 'string' || !path.isAbsolute(raw.executable)) throw new Error('planner.executable must be absolute');
|
|
45
|
+
if (!SHA256_RE.test(raw.executable_sha256 ?? '')) throw new Error('planner.executable_sha256 invalid');
|
|
46
|
+
const args=raw.args ?? ['app-server'];
|
|
47
|
+
if (!Array.isArray(args) || args.length < 1 || args.length > 16 ||
|
|
48
|
+
args.some(value=>typeof value!=='string'||value.length<1||value.length>2048||value.includes('\0'))) {
|
|
49
|
+
throw new Error('planner.args invalid');
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
...common, model:raw.model, root_id:raw.root_id, executable:path.resolve(raw.executable),
|
|
53
|
+
executable_sha256:raw.executable_sha256, args:[...args],
|
|
54
|
+
timeout_ms:integer(raw.timeout_ms,'planner.timeout_ms',1000,300000,60000),
|
|
55
|
+
circuit:normalizeProviderCircuit(raw.circuit)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
39
58
|
if (typeof raw.endpoint !== 'string') throw new Error('planner.endpoint required');
|
|
40
59
|
const endpoint = new URL(raw.endpoint);
|
|
41
60
|
const loopback = ['127.0.0.1', 'localhost', '::1'].includes(endpoint.hostname);
|
|
@@ -43,15 +62,22 @@ function normalizePlanner(raw) {
|
|
|
43
62
|
throw new Error('planner endpoint must be HTTPS or loopback HTTP');
|
|
44
63
|
}
|
|
45
64
|
if (endpoint.username || endpoint.password || endpoint.hash) throw new Error('planner endpoint credentials/fragments forbidden');
|
|
46
|
-
if (typeof raw.model !== 'string' || raw.model.length < 1 || raw.model.length > 128) throw new Error('planner.model invalid');
|
|
47
65
|
const apiKeyEnv = raw.api_key_env ?? null;
|
|
48
66
|
if (apiKeyEnv !== null && !ENV_RE.test(apiKeyEnv)) throw new Error('planner.api_key_env invalid');
|
|
49
|
-
|
|
67
|
+
const provider = {
|
|
50
68
|
...common, endpoint: endpoint.toString(), model: raw.model, api_key_env: apiKeyEnv,
|
|
51
69
|
timeout_ms: integer(raw.timeout_ms, 'planner.timeout_ms', 1000, 300000, 60000),
|
|
52
70
|
max_response_bytes: integer(raw.max_response_bytes, 'planner.max_response_bytes', 4096, 2 * 1024 * 1024, 512 * 1024),
|
|
53
71
|
circuit:normalizeProviderCircuit(raw.circuit)
|
|
54
72
|
};
|
|
73
|
+
if (backend === 'openai_responses') {
|
|
74
|
+
const effort = raw.reasoning_effort ?? null;
|
|
75
|
+
if (effort !== null && !['minimal','low','medium','high','xhigh'].includes(effort)) {
|
|
76
|
+
throw new Error('planner.reasoning_effort invalid');
|
|
77
|
+
}
|
|
78
|
+
return { ...provider, reasoning_effort:effort, store:false };
|
|
79
|
+
}
|
|
80
|
+
return provider;
|
|
55
81
|
}
|
|
56
82
|
function normalizeProfile(id, raw, codingPolicy) {
|
|
57
83
|
if (!ID_RE.test(id)) throw new Error(`invalid autonomous profile '${id}'`);
|
|
@@ -109,7 +135,7 @@ export async function loadAutonomousPolicy(policyPath, codingPolicy) {
|
|
|
109
135
|
schema: AUTONOMOUS_POLICY_SCHEMA, enabled: true, policy_path: absolute,
|
|
110
136
|
lease_file: path.resolve(raw.lease_file), evidence_dir: path.resolve(raw.evidence_dir),
|
|
111
137
|
coding_policy_sha256: codingPolicy.policy_sha256, root_ids: rootIds,
|
|
112
|
-
planner: normalizePlanner(raw.planner), profiles,
|
|
138
|
+
planner: normalizePlanner(raw.planner,codingPolicy,rootIds), profiles,
|
|
113
139
|
limits: {
|
|
114
140
|
max_iterations: integer(limits.max_iterations, 'limits.max_iterations', 1, 64, 12),
|
|
115
141
|
max_mutations: integer(limits.max_mutations, 'limits.max_mutations', 1, 128, 24),
|
|
@@ -157,3 +183,22 @@ export async function assertAutonomousArmed(policy, rootId = null, now = new Dat
|
|
|
157
183
|
if (rootId !== null && !status.root_ids.includes(rootId)) throw new Error(`autonomous root '${rootId}' is outside active lease`);
|
|
158
184
|
return status;
|
|
159
185
|
}
|
|
186
|
+
|
|
187
|
+
export async function recheckAutonomousAuthority(policy, initial, rootId = null, now = new Date()) {
|
|
188
|
+
if (!initial?.armed || typeof initial.instance_nonce !== 'string' || !Array.isArray(initial.root_ids)) {
|
|
189
|
+
throw new Error('autonomous authority recheck requires an armed initial snapshot');
|
|
190
|
+
}
|
|
191
|
+
let current;
|
|
192
|
+
try { current = await assertAutonomousArmed(policy, rootId, now); }
|
|
193
|
+
catch (error) { throw new Error(`autonomous authority changed during operation: ${String(error?.message ?? error)}`); }
|
|
194
|
+
const initialRoots = [...initial.root_ids].sort();
|
|
195
|
+
const currentRoots = [...current.root_ids].sort();
|
|
196
|
+
const changed =
|
|
197
|
+
current.instance_nonce !== initial.instance_nonce ||
|
|
198
|
+
current.standing !== initial.standing ||
|
|
199
|
+
current.expires_at_utc !== initial.expires_at_utc ||
|
|
200
|
+
initialRoots.length !== currentRoots.length ||
|
|
201
|
+
initialRoots.some((id, index) => id !== currentRoots[index]);
|
|
202
|
+
if (changed) throw new Error('autonomous authority changed during operation');
|
|
203
|
+
return current;
|
|
204
|
+
}
|