deadbyte-mcp 0.14.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/AGENTS.md +11 -18
- package/CONTEXT.md +3 -3
- package/MANIFEST.SHA256 +104 -53
- package/R43-PARENT.json +20 -0
- package/R44-DONORS.json +99 -0
- package/R44-PARENT.json +18 -0
- package/README.txt +7 -2
- package/controller/README.TXT +4 -5
- package/controller/deadbyte-controller.ps1 +1 -1
- package/docs/ARCHITECTURE.md +8 -1
- package/docs/R44-ARCHITECTURE.md +37 -0
- package/package.json +13 -8
- package/scripts/deferred-slot-operation-r43.mjs +126 -0
- package/scripts/deferred-slot-operation-r44.mjs +126 -0
- package/scripts/final-closure-r43.mjs +115 -0
- package/scripts/final-closure-r44.mjs +121 -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-r43.ps1 +36 -0
- package/scripts/gate-windows-r44.ps1 +36 -0
- package/scripts/release-parity-r43.mjs +218 -0
- package/scripts/release-parity-r44.mjs +242 -0
- package/scripts/release-parity-tests-r43.ps1 +8 -0
- package/scripts/release-parity-tests-r44.ps1 +8 -0
- package/scripts/verify-r43-parent.mjs +126 -0
- package/scripts/verify-r44-parent.mjs +142 -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/autonomous-output-contracts.mjs +1 -1
- package/src/autonomous-policy.mjs +41 -4
- package/src/autonomous-runtime.mjs +25 -12
- package/src/autonomous-supervisor-host.mjs +12 -2
- 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/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 +8 -2
- 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-runtime.test.mjs +3 -3
- package/test/autonomous-loop.test.mjs +97 -11
- 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/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/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/r33-closeout-regression.test.mjs +13 -30
- package/test/r33-finalization.test.mjs +7 -7
- 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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, open, readFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { verifyR44Parent } from './verify-r44-parent.mjs';
|
|
7
|
+
|
|
8
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const root=path.resolve(here,'..');
|
|
10
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const marker='DEADBYTE V0.15.0 / R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS';
|
|
12
|
+
function insist(ok,message){if(!ok)throw new Error(message);}
|
|
13
|
+
|
|
14
|
+
export async function writeWindowsGateEvidence({
|
|
15
|
+
candidateRoot=root,
|
|
16
|
+
stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp')),
|
|
17
|
+
clock=()=>new Date()
|
|
18
|
+
}={}){
|
|
19
|
+
const candidate=path.resolve(candidateRoot);
|
|
20
|
+
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
21
|
+
const manifestSha256=sha256(manifestBytes);
|
|
22
|
+
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
23
|
+
insist(pkg.version==='0.15.0',`Windows gate evidence requires V0.15.0, found ${pkg.version}`);
|
|
24
|
+
const parent=await verifyR44Parent(path.join(candidate,'R44-PARENT.json'));
|
|
25
|
+
const completed=clock();
|
|
26
|
+
insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
|
|
27
|
+
const evidence={
|
|
28
|
+
schema:'deadbyte.r44-windows-gate.v1',status:'passed',exit_code:0,version:'0.15.0',
|
|
29
|
+
marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256,
|
|
30
|
+
parent:{release_id:parent.release_id,manifest_sha256:parent.manifest_sha256,
|
|
31
|
+
generation_manifest_sha256:parent.generation_manifest_sha256,
|
|
32
|
+
final_closure_sha256:parent.closure_sha256,final_closure_file_sha256:parent.closure_file_sha256,
|
|
33
|
+
signer_key_id:parent.signer_key_id},
|
|
34
|
+
features:{skill_integrity:true,agent_backend_persistence:true,codex_protocol_contract:true,
|
|
35
|
+
remote_device_identity:true,durable_job_supervisor:true,real_external_supervisor_smoke:true,
|
|
36
|
+
full_regression_required:true,codex_live_binary_required:false}
|
|
37
|
+
};
|
|
38
|
+
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
|
|
39
|
+
const dir=path.join(path.resolve(stateRoot),'evidence','release');await mkdir(dir,{recursive:true});
|
|
40
|
+
const file=path.join(dir,`r44-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
41
|
+
try{
|
|
42
|
+
const handle=await open(file,'wx',0o600);try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
43
|
+
return {status:'written',path:file,sha256:sha256(bytes),manifest_sha256:manifestSha256,parent:evidence.parent};
|
|
44
|
+
}catch(error){
|
|
45
|
+
if(error?.code!=='EEXIST')throw error;
|
|
46
|
+
const existingBytes=await readFile(file);
|
|
47
|
+
const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
48
|
+
insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing R44 Windows gate evidence invalid');
|
|
49
|
+
insist(existing.version==='0.15.0'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing R44 Windows gate identity mismatch');
|
|
50
|
+
insist(existing.parent?.release_id===parent.release_id&&existing.parent?.final_closure_sha256===parent.closure_sha256,'existing R44 parent evidence mismatch');
|
|
51
|
+
return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256,parent:existing.parent};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
55
|
+
if(invoked)writeWindowsGateEvidence().then(value=>console.log(JSON.stringify(value))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import { lstat, mkdir, open, readFile, realpath, rename } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
const STATE_SCHEMA='deadbyte.agent-backend-state.v1';
|
|
8
|
+
const HEX64=/^[0-9a-f]{64}$/;
|
|
9
|
+
const ID=/^[A-Za-z0-9._-]{1,64}$/;
|
|
10
|
+
const METHOD=/^[A-Za-z0-9._\/-]{1,128}$/;
|
|
11
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
12
|
+
const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
|
|
13
|
+
?Object.fromEntries(Object.keys(value).sort((a,b)=>a.localeCompare(b,'en')).map(key=>[key,canonical(value[key])])):value;
|
|
14
|
+
const canonicalJson=value=>JSON.stringify(canonical(value));
|
|
15
|
+
function insist(ok,message){if(!ok) throw new Error(message);}
|
|
16
|
+
function now(){return new Date().toISOString();}
|
|
17
|
+
function isJson(value){try{JSON.stringify(value);return true;}catch{return false;}}
|
|
18
|
+
|
|
19
|
+
async function atomicJson(file,value){
|
|
20
|
+
await mkdir(path.dirname(file),{recursive:true});
|
|
21
|
+
const bytes=Buffer.from(`${JSON.stringify(value,null,2)}\n`,'utf8');
|
|
22
|
+
const temp=`${file}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`;
|
|
23
|
+
const handle=await open(temp,'wx');
|
|
24
|
+
try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
25
|
+
await rename(temp,file);
|
|
26
|
+
return sha(bytes);
|
|
27
|
+
}
|
|
28
|
+
function validateState(state,backendId){
|
|
29
|
+
insist(state&&typeof state==='object'&&!Array.isArray(state),'agent backend state must be object');
|
|
30
|
+
const allowed=['schema','backend_id','state_epoch','next_sequence','threads','requests','updated_at_utc'];
|
|
31
|
+
insist(Object.keys(state).every(k=>allowed.includes(k))&&allowed.every(k=>Object.hasOwn(state,k)),'agent backend state fields mismatch');
|
|
32
|
+
insist(state.schema===STATE_SCHEMA,'agent backend state schema mismatch');
|
|
33
|
+
insist(state.backend_id===backendId,'agent backend state backend mismatch');
|
|
34
|
+
insist(HEX64.test(state.state_epoch??''),'agent backend state epoch invalid');
|
|
35
|
+
insist(Number.isInteger(state.next_sequence)&&state.next_sequence>=0,'agent backend sequence invalid');
|
|
36
|
+
insist(state.threads&&typeof state.threads==='object'&&!Array.isArray(state.threads),'agent backend threads invalid');
|
|
37
|
+
for(const [logicalId,threadId] of Object.entries(state.threads)){
|
|
38
|
+
insist(ID.test(logicalId),'agent backend logical thread id invalid');
|
|
39
|
+
insist(typeof threadId==='string'&&threadId.length>=1&&threadId.length<=512,'agent backend thread id invalid');
|
|
40
|
+
}
|
|
41
|
+
insist(state.requests&&typeof state.requests==='object'&&!Array.isArray(state.requests),'agent backend requests invalid');
|
|
42
|
+
for(const [id,item] of Object.entries(state.requests)){
|
|
43
|
+
insist(HEX64.test(id),'agent backend request id invalid');
|
|
44
|
+
insist(item&&typeof item==='object'&&!Array.isArray(item),'agent backend request record invalid');
|
|
45
|
+
insist(['pending','completed','failed','interrupted'].includes(item.state),'agent backend request state invalid');
|
|
46
|
+
insist(typeof item.method==='string'&&METHOD.test(item.method),'agent backend request method invalid');
|
|
47
|
+
insist(HEX64.test(item.params_sha256??''),'agent backend params hash invalid');
|
|
48
|
+
insist(typeof item.created_at_utc==='string'&&typeof item.updated_at_utc==='string','agent backend request timestamp invalid');
|
|
49
|
+
}
|
|
50
|
+
insist(typeof state.updated_at_utc==='string','agent backend state timestamp invalid');
|
|
51
|
+
return state;
|
|
52
|
+
}
|
|
53
|
+
async function loadState(file,backendId){
|
|
54
|
+
try{
|
|
55
|
+
const st=await lstat(file);
|
|
56
|
+
insist(st.isFile()&&!st.isSymbolicLink(),'agent backend state must be real file');
|
|
57
|
+
let parsed;
|
|
58
|
+
try{parsed=JSON.parse(await readFile(file,'utf8'));}catch(error){throw new Error(`agent backend state JSON invalid: ${error.message}`);}
|
|
59
|
+
return validateState(parsed,backendId);
|
|
60
|
+
}catch(error){
|
|
61
|
+
if(error?.code!=='ENOENT') throw error;
|
|
62
|
+
return {schema:STATE_SCHEMA,backend_id:backendId,state_epoch:randomBytes(32).toString('hex'),next_sequence:0,threads:{},requests:{},updated_at_utc:now()};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function fileSha256(file){
|
|
66
|
+
const st=await lstat(file);
|
|
67
|
+
insist(st.isFile()&&!st.isSymbolicLink(),'agent backend executable must be real file');
|
|
68
|
+
return sha(await readFile(file));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
class JsonRpcLineTransport extends EventEmitter {
|
|
72
|
+
constructor({executable,args=[],cwd=null,env=null,maxLineBytes=1024*1024}){
|
|
73
|
+
super();this.executable=executable;this.args=args;this.cwd=cwd;this.env=env;this.maxLineBytes=maxLineBytes;this.child=null;this.buffer='';
|
|
74
|
+
}
|
|
75
|
+
async start(){
|
|
76
|
+
if(this.child) throw new Error('agent backend transport already started');
|
|
77
|
+
this.child=spawn(this.executable,this.args,{cwd:this.cwd??undefined,env:this.env??process.env,windowsHide:true,shell:false,stdio:['pipe','pipe','pipe']});
|
|
78
|
+
this.child.stdout.setEncoding('utf8');
|
|
79
|
+
this.child.stdout.on('data',chunk=>{
|
|
80
|
+
this.buffer+=chunk;
|
|
81
|
+
if(Buffer.byteLength(this.buffer,'utf8')>this.maxLineBytes*2){this.emit('protocol_error',new Error('agent backend JSON-RPC buffer limit exceeded'));return;}
|
|
82
|
+
for(;;){
|
|
83
|
+
const nl=this.buffer.indexOf('\n');if(nl<0)break;
|
|
84
|
+
const line=this.buffer.slice(0,nl).trim();this.buffer=this.buffer.slice(nl+1);
|
|
85
|
+
if(!line)continue;
|
|
86
|
+
if(Buffer.byteLength(line,'utf8')>this.maxLineBytes){this.emit('protocol_error',new Error('agent backend JSON-RPC line limit exceeded'));continue;}
|
|
87
|
+
try{this.emit('message',JSON.parse(line));}catch(error){this.emit('protocol_error',new Error(`agent backend JSON-RPC invalid: ${error.message}`));}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
let stderr='';
|
|
91
|
+
this.child.stderr.setEncoding('utf8');
|
|
92
|
+
this.child.stderr.on('data',chunk=>{stderr=(stderr+chunk).slice(-16384);});
|
|
93
|
+
this.child.once('error',error=>this.emit('transport_error',error));
|
|
94
|
+
this.child.once('exit',(code,signal)=>{this.emit('exit',{code,signal,stderr});this.child=null;});
|
|
95
|
+
await new Promise((resolve,reject)=>{
|
|
96
|
+
if(this.child.pid){resolve();return;}
|
|
97
|
+
this.child.once('spawn',resolve);this.child.once('error',reject);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async send(value){
|
|
101
|
+
insist(this.child?.stdin?.writable,'agent backend transport is not writable');
|
|
102
|
+
const line=`${JSON.stringify(value)}\n`;
|
|
103
|
+
insist(Buffer.byteLength(line,'utf8')<=this.maxLineBytes,'agent backend outbound JSON-RPC line limit exceeded');
|
|
104
|
+
await new Promise((resolve,reject)=>this.child.stdin.write(line,error=>error?reject(error):resolve()));
|
|
105
|
+
}
|
|
106
|
+
async stop(){
|
|
107
|
+
if(!this.child)return;
|
|
108
|
+
const child=this.child;
|
|
109
|
+
const done=new Promise(resolve=>child.once('exit',resolve));
|
|
110
|
+
child.kill();
|
|
111
|
+
await Promise.race([done,new Promise(resolve=>setTimeout(resolve,3000))]);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function createAgentBackendR44({
|
|
116
|
+
backendId,stateDir,transportFactory=null,serverRequestHandler=null,notificationHandler=null,wireMode='jsonrpc2',
|
|
117
|
+
executable=null,executableSha256=null,args=[],cwd=null,env=null
|
|
118
|
+
}={}){
|
|
119
|
+
insist(typeof backendId==='string'&&ID.test(backendId),'agent backend id invalid');
|
|
120
|
+
insist(typeof stateDir==='string'&&path.isAbsolute(stateDir),'agent backend stateDir must be absolute');
|
|
121
|
+
await mkdir(stateDir,{recursive:true});
|
|
122
|
+
const root=await realpath(stateDir);
|
|
123
|
+
const stateFile=path.join(root,`${backendId}.json`);
|
|
124
|
+
if(transportFactory===null){
|
|
125
|
+
insist(typeof executable==='string'&&path.isAbsolute(executable),'agent backend executable must be absolute');
|
|
126
|
+
insist(HEX64.test(executableSha256??''),'agent backend executable SHA-256 invalid');
|
|
127
|
+
insist(await fileSha256(executable)===executableSha256,'agent backend executable hash mismatch');
|
|
128
|
+
insist(Array.isArray(args)&&args.length<=64&&args.every(x=>typeof x==='string'&&x.length<=4096),'agent backend args invalid');
|
|
129
|
+
transportFactory=async()=>new JsonRpcLineTransport({executable,args,cwd,env});
|
|
130
|
+
}else insist(typeof transportFactory==='function','agent backend transportFactory invalid');
|
|
131
|
+
insist(serverRequestHandler===null||typeof serverRequestHandler==='function','agent backend serverRequestHandler invalid');
|
|
132
|
+
insist(notificationHandler===null||typeof notificationHandler==='function','agent backend notificationHandler invalid');
|
|
133
|
+
insist(['jsonrpc2','codex-app-server'].includes(wireMode),'agent backend wireMode invalid');
|
|
134
|
+
const wire=value=>wireMode==='jsonrpc2'?{jsonrpc:'2.0',...value}:value;
|
|
135
|
+
|
|
136
|
+
let state=await loadState(stateFile,backendId);
|
|
137
|
+
let changed=false;
|
|
138
|
+
for(const item of Object.values(state.requests)){
|
|
139
|
+
if(item.state==='pending'){item.state='interrupted';item.updated_at_utc=now();item.error='backend restarted before terminal response';changed=true;}
|
|
140
|
+
}
|
|
141
|
+
if(changed){state.updated_at_utc=now();await atomicJson(stateFile,state);}
|
|
142
|
+
else{
|
|
143
|
+
try{await lstat(stateFile);}catch(error){if(error?.code==='ENOENT')await atomicJson(stateFile,state);else throw error;}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let transport=null;
|
|
147
|
+
let started=false;
|
|
148
|
+
const pending=new Map();
|
|
149
|
+
let writeChain=Promise.resolve();
|
|
150
|
+
const persist=async()=>{
|
|
151
|
+
state.updated_at_utc=now();
|
|
152
|
+
writeChain=writeChain.then(()=>atomicJson(stateFile,state));
|
|
153
|
+
return writeChain;
|
|
154
|
+
};
|
|
155
|
+
const publicState=()=>({
|
|
156
|
+
status:'ok',backend_id:backendId,running:started,state_epoch:state.state_epoch,
|
|
157
|
+
threads:structuredClone(state.threads),requests:structuredClone(state.requests)
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
async function terminal(id,{stateName,result=null,error=null}){
|
|
161
|
+
const record=state.requests[id];if(!record||record.state!=='pending')return;
|
|
162
|
+
record.state=stateName;record.updated_at_utc=now();
|
|
163
|
+
if(result!==null)record.result=result;
|
|
164
|
+
if(error!==null)record.error=String(error);
|
|
165
|
+
await persist();
|
|
166
|
+
const waiter=pending.get(id);pending.delete(id);
|
|
167
|
+
if(!waiter)return;
|
|
168
|
+
if(stateName==='completed')waiter.resolve(result);
|
|
169
|
+
else waiter.reject(new Error(record.error??stateName));
|
|
170
|
+
}
|
|
171
|
+
async function handleMessage(message){
|
|
172
|
+
if(!message||typeof message!=='object'||Array.isArray(message))return;
|
|
173
|
+
if(typeof message.id==='string'&&Object.hasOwn(message,'method')){
|
|
174
|
+
const method=String(message.method);
|
|
175
|
+
try{
|
|
176
|
+
if(!serverRequestHandler) throw Object.assign(new Error('server request denied by DEADBYTE policy'),{code:-32001});
|
|
177
|
+
const result=await serverRequestHandler({method,params:message.params??{},backendId});
|
|
178
|
+
await transport?.send(wire({id:message.id,result}));
|
|
179
|
+
}catch(error){
|
|
180
|
+
await transport?.send(wire({id:message.id,error:{code:Number.isInteger(error?.code)?error.code:-32001,message:String(error?.message??error)}}));
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if(!Object.hasOwn(message,'id')&&typeof message.method==='string'){
|
|
185
|
+
if(notificationHandler) await notificationHandler({method:String(message.method),params:message.params??{},backendId});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if(typeof message.id!=='string'||!state.requests[message.id])return;
|
|
189
|
+
if(Object.hasOwn(message,'result'))await terminal(message.id,{stateName:'completed',result:message.result});
|
|
190
|
+
else if(Object.hasOwn(message,'error'))await terminal(message.id,{stateName:'failed',error:message.error?.message??'JSON-RPC error'});
|
|
191
|
+
}
|
|
192
|
+
async function start(){
|
|
193
|
+
if(started)return publicState();
|
|
194
|
+
transport=await transportFactory();
|
|
195
|
+
insist(transport&&typeof transport.start==='function'&&typeof transport.send==='function'&&typeof transport.on==='function','agent backend transport contract invalid');
|
|
196
|
+
transport.on('message',message=>{void handleMessage(message);});
|
|
197
|
+
transport.on('protocol_error',error=>{
|
|
198
|
+
for(const id of pending.keys())void terminal(id,{stateName:'failed',error:String(error?.message??error)});
|
|
199
|
+
});
|
|
200
|
+
transport.on('transport_error',error=>{
|
|
201
|
+
for(const id of pending.keys())void terminal(id,{stateName:'interrupted',error:String(error?.message??error)});
|
|
202
|
+
started=false;
|
|
203
|
+
});
|
|
204
|
+
transport.on('exit',()=>{
|
|
205
|
+
for(const id of pending.keys())void terminal(id,{stateName:'interrupted',error:'agent backend transport exited'});
|
|
206
|
+
started=false;
|
|
207
|
+
});
|
|
208
|
+
await transport.start();started=true;return publicState();
|
|
209
|
+
}
|
|
210
|
+
async function bindThread({logicalId,threadId}={}){
|
|
211
|
+
insist(typeof logicalId==='string'&&ID.test(logicalId),'logical thread id invalid');
|
|
212
|
+
insist(typeof threadId==='string'&&threadId.length>=1&&threadId.length<=512,'provider thread id invalid');
|
|
213
|
+
const existing=state.threads[logicalId];
|
|
214
|
+
if(existing!==undefined&&existing!==threadId) throw new Error('logical thread already bound to different provider thread');
|
|
215
|
+
state.threads[logicalId]=threadId;await persist();
|
|
216
|
+
return {status:'ok',logical_id:logicalId,thread_id:threadId};
|
|
217
|
+
}
|
|
218
|
+
async function request({method,params={},timeoutMs=60000}={}){
|
|
219
|
+
insist(started&&transport,'agent backend is not started');
|
|
220
|
+
insist(typeof method==='string'&&METHOD.test(method),'agent backend method invalid');
|
|
221
|
+
insist(isJson(params)&¶ms&&typeof params==='object','agent backend params must be JSON');
|
|
222
|
+
insist(Number.isInteger(timeoutMs)&&timeoutMs>=100&&timeoutMs<=900000,'agent backend timeout invalid');
|
|
223
|
+
const sequence=++state.next_sequence;
|
|
224
|
+
const paramsSha=sha(Buffer.from(canonicalJson(params),'utf8'));
|
|
225
|
+
const id=sha(Buffer.from(canonicalJson({backend_id:backendId,state_epoch:state.state_epoch,sequence,method,params_sha256:paramsSha}),'utf8'));
|
|
226
|
+
state.requests[id]={state:'pending',method,params_sha256:paramsSha,created_at_utc:now(),updated_at_utc:now()};
|
|
227
|
+
await persist();
|
|
228
|
+
let timer;
|
|
229
|
+
const promise=new Promise((resolve,reject)=>{
|
|
230
|
+
pending.set(id,{resolve,reject});
|
|
231
|
+
timer=setTimeout(()=>{void terminal(id,{stateName:'failed',error:'agent backend request timeout'});},timeoutMs);
|
|
232
|
+
}).finally(()=>clearTimeout(timer));
|
|
233
|
+
try{await transport.send(wire({id,method,params}));}
|
|
234
|
+
catch(error){await terminal(id,{stateName:'failed',error:String(error?.message??error)});}
|
|
235
|
+
return promise;
|
|
236
|
+
}
|
|
237
|
+
async function notify({method,params={}}={}){
|
|
238
|
+
insist(started&&transport,'agent backend is not started');
|
|
239
|
+
insist(typeof method==='string'&&METHOD.test(method),'agent backend notification method invalid');
|
|
240
|
+
insist(isJson(params)&¶ms&&typeof params==='object','agent backend notification params must be JSON');
|
|
241
|
+
await transport.send(wire({method,params}));
|
|
242
|
+
return {status:'sent',method};
|
|
243
|
+
}
|
|
244
|
+
async function status(){return publicState();}
|
|
245
|
+
async function close(){
|
|
246
|
+
for(const id of [...pending.keys()])await terminal(id,{stateName:'interrupted',error:'agent backend closed before response'});
|
|
247
|
+
if(transport?.stop)await transport.stop();transport=null;started=false;return publicState();
|
|
248
|
+
}
|
|
249
|
+
async function simulateCrashForTest(){
|
|
250
|
+
for(const [id,waiter] of pending){waiter.reject(new Error('simulated backend crash'));pending.delete(id);}
|
|
251
|
+
if(transport?.stop)await transport.stop();transport=null;started=false;
|
|
252
|
+
}
|
|
253
|
+
return Object.freeze({start,bindThread,request,notify,status,close,simulateCrashForTest,state_file:stateFile,wire_mode:wireMode});
|
|
254
|
+
}
|
|
@@ -68,7 +68,7 @@ export const autonomousSessionStatusOutputSchema = statusContract({
|
|
|
68
68
|
shape:{ configured:z.literal(true).optional(), armed:z.boolean().optional(), autonomous_armed:z.boolean().optional(),
|
|
69
69
|
autonomous_reason:z.string().optional(), autonomous_expires_at_utc:z.string().nullable().optional(),
|
|
70
70
|
coding_armed:z.boolean().optional(), coding_reason:z.string().optional(), root_ids:z.array(z.string()).max(64).optional(),
|
|
71
|
-
planner_backend:z.enum(['client_sampling','openai_compatible','openai_responses']).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(),
|
|
72
72
|
policy_sha256:hex64.optional(), coding_policy_sha256:hex64.optional() }
|
|
73
73
|
});
|
|
74
74
|
|
|
@@ -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', 'openai_responses'].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,7 +62,6 @@ 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 = {
|
|
@@ -117,7 +135,7 @@ export async function loadAutonomousPolicy(policyPath, codingPolicy) {
|
|
|
117
135
|
schema: AUTONOMOUS_POLICY_SCHEMA, enabled: true, policy_path: absolute,
|
|
118
136
|
lease_file: path.resolve(raw.lease_file), evidence_dir: path.resolve(raw.evidence_dir),
|
|
119
137
|
coding_policy_sha256: codingPolicy.policy_sha256, root_ids: rootIds,
|
|
120
|
-
planner: normalizePlanner(raw.planner), profiles,
|
|
138
|
+
planner: normalizePlanner(raw.planner,codingPolicy,rootIds), profiles,
|
|
121
139
|
limits: {
|
|
122
140
|
max_iterations: integer(limits.max_iterations, 'limits.max_iterations', 1, 64, 12),
|
|
123
141
|
max_mutations: integer(limits.max_mutations, 'limits.max_mutations', 1, 128, 24),
|
|
@@ -165,3 +183,22 @@ export async function assertAutonomousArmed(policy, rootId = null, now = new Dat
|
|
|
165
183
|
if (rootId !== null && !status.root_ids.includes(rootId)) throw new Error(`autonomous root '${rootId}' is outside active lease`);
|
|
166
184
|
return status;
|
|
167
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
|
+
}
|
|
@@ -3,7 +3,7 @@ import { access, mkdir, open, readFile, readdir, rm, writeFile } from 'node:fs/p
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { canonicalJson } from './canonical-json.mjs';
|
|
5
5
|
import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
|
|
6
|
-
import { assertAutonomousArmed, autonomousSessionStatus } from './autonomous-policy.mjs';
|
|
6
|
+
import { assertAutonomousArmed, autonomousSessionStatus, recheckAutonomousAuthority } from './autonomous-policy.mjs';
|
|
7
7
|
import { buildPlannerPrompt, parsePlannerDecision, parseR34PlannerDecision, requestProviderDecision } from './autonomous-planner.mjs';
|
|
8
8
|
import { actionIdentity, reconcileStartedAction } from './autonomous-action-reconcile.mjs';
|
|
9
9
|
import { createPlan, replanPlan, completePlanStep, planIsComplete as r34PlanIsComplete } from './autonomous-plan.mjs';
|
|
@@ -274,16 +274,24 @@ async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch
|
|
|
274
274
|
await appendEvent(ctx,events,signingKeyPath,'profile_completed',payload);
|
|
275
275
|
return { status:outcome.passed ? 'passed' : 'failed', observation:payload, existing:false };
|
|
276
276
|
}
|
|
277
|
+
const autonomousAuthority = await assertAutonomousArmed(policy,profile.root_id);
|
|
278
|
+
if (Number.isFinite(autonomousAuthority.remaining_ms) && autonomousAuthority.remaining_ms < 100) {
|
|
279
|
+
throw new Error('autonomous lease expires too soon to execute profile');
|
|
280
|
+
}
|
|
277
281
|
await appendEvent(ctx,events,signingKeyPath,'profile_started',{ action_key:actionKey, profile_id:profileId,
|
|
278
|
-
mutation_epoch:epoch, receipt_id:receiptId, request_sha256:requestSha256
|
|
282
|
+
mutation_epoch:epoch, receipt_id:receiptId, request_sha256:requestSha256,
|
|
283
|
+
authority_instance_nonce:autonomousAuthority.instance_nonce,
|
|
284
|
+
authority_expires_at_utc:autonomousAuthority.expires_at_utc });
|
|
285
|
+
const preExecutionCheck = () => recheckAutonomousAuthority(policy,autonomousAuthority,profile.root_id);
|
|
279
286
|
let result;
|
|
280
287
|
try {
|
|
281
288
|
result = profile.kind === 'command'
|
|
282
289
|
? await codingRuntime.commandRun({ rootId:profile.root_id, commandId:profile.command_id, scriptPath:profile.script_path,
|
|
283
290
|
scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:profile.timeout_ms,
|
|
284
|
-
receiptId, requestSha256 })
|
|
291
|
+
executionDeadlineUtc:autonomousAuthority.expires_at_utc, preExecutionCheck, receiptId, requestSha256 })
|
|
285
292
|
: await codingRuntime.benchmarkRun({ rootId:profile.root_id, commandId:profile.command_id, scriptPath:profile.script_path,
|
|
286
293
|
scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:profile.timeout_ms,
|
|
294
|
+
executionDeadlineUtc:autonomousAuthority.expires_at_utc, preExecutionCheck,
|
|
287
295
|
warmups:profile.warmups, iterations:profile.iterations, baselineMedianMs:profile.baseline_median_ms,
|
|
288
296
|
maxRegressionPct:profile.max_regression_pct, receiptId, requestSha256 });
|
|
289
297
|
} catch (error) {
|
|
@@ -527,7 +535,7 @@ function withLoopResult(goal,events,result) {
|
|
|
527
535
|
return loop ? {...result,loop} : result;
|
|
528
536
|
}
|
|
529
537
|
function providerCircuitSnapshot(policy,events,observedAtUtc=new Date().toISOString()) {
|
|
530
|
-
if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) return null;
|
|
538
|
+
if (!['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend)) return null;
|
|
531
539
|
return deriveCircuit(events,providerCircuitId(policy.planner),policy.planner.circuit,observedAtUtc);
|
|
532
540
|
}
|
|
533
541
|
async function enterProviderCircuitWait({ctx,events,goal,policy,signingKeyPath,reason,circuit}) {
|
|
@@ -545,7 +553,7 @@ async function enterProviderCircuitWait({ctx,events,goal,policy,signingKeyPath,r
|
|
|
545
553
|
});
|
|
546
554
|
return {status:'paused',reason,circuit};
|
|
547
555
|
}
|
|
548
|
-
async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath}) {
|
|
556
|
+
async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath,plannerProviderRuntime}) {
|
|
549
557
|
const providerId=providerCircuitId(policy.planner);
|
|
550
558
|
let circuit=providerCircuitSnapshot(policy,events);
|
|
551
559
|
let disposition=providerCallDisposition(circuit);
|
|
@@ -566,7 +574,9 @@ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signin
|
|
|
566
574
|
});
|
|
567
575
|
}
|
|
568
576
|
try {
|
|
569
|
-
const response=
|
|
577
|
+
const response=policy.planner.backend==='codex_app_server'
|
|
578
|
+
? await plannerProviderRuntime.runPlanner({logicalId:`goal-${goal.goal_id}`,prompt:pending.prompt,timeoutMs:policy.planner.timeout_ms})
|
|
579
|
+
: await requestProviderDecision(policy,pending.prompt);
|
|
570
580
|
await appendEvent(ctx,events,signingKeyPath,'provider_call_succeeded',{
|
|
571
581
|
provider_id:providerId,request_id:pending.request_id,probe:disposition.probe===true,
|
|
572
582
|
...(response.response_id?{response_id:response.response_id}:{}),
|
|
@@ -589,15 +599,15 @@ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signin
|
|
|
589
599
|
throw error;
|
|
590
600
|
}
|
|
591
601
|
}
|
|
592
|
-
async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider,memoryProvider, signingKeyPath, plannerResponse }) {
|
|
602
|
+
async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider,memoryProvider, signingKeyPath, plannerResponse, plannerProviderRuntime }) {
|
|
593
603
|
let currentState = state;
|
|
594
604
|
let pending = currentState.pending_request ?? await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,desktopMemoryProvider,memoryProvider,signingKeyPath);
|
|
595
605
|
if (!pending) return null;
|
|
596
606
|
let suppliedResponse = plannerResponse;
|
|
597
607
|
while (pending) {
|
|
598
608
|
let response;
|
|
599
|
-
if (['openai_compatible','openai_responses'].includes(policy.planner.backend)) {
|
|
600
|
-
const provider=await requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath});
|
|
609
|
+
if (['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend)) {
|
|
610
|
+
const provider=await requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath,plannerProviderRuntime});
|
|
601
611
|
if (provider.waiting) return {needs_planner:false,rejected:false,paused:true,provider_waiting:true};
|
|
602
612
|
response=provider.response;
|
|
603
613
|
} else {
|
|
@@ -1765,9 +1775,12 @@ function isAuthorityUnavailable(error) {
|
|
|
1765
1775
|
|
|
1766
1776
|
export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRuntime, machineFsRuntime = null,
|
|
1767
1777
|
observationRuntime = null, processRuntime = null, semanticRuntime = null, desktopRuntime = null,
|
|
1768
|
-
desktopMemoryProvider = null,memoryProvider=null, signingKeyPath, verifyKeyPath }) {
|
|
1778
|
+
desktopMemoryProvider = null,memoryProvider=null, plannerProviderRuntime=null, signingKeyPath, verifyKeyPath }) {
|
|
1769
1779
|
if (!policy || !codingRuntime || !nativeDiffRuntime) throw new Error('autonomous runtime requires policy/coding/native-diff runtimes');
|
|
1770
1780
|
if (!signingKeyPath || !verifyKeyPath) throw new Error('autonomous runtime requires trust keys');
|
|
1781
|
+
if (policy.planner?.backend==='codex_app_server' && (!plannerProviderRuntime || typeof plannerProviderRuntime.runPlanner!=='function')) {
|
|
1782
|
+
throw new Error('Codex planner provider runtime is required by autonomous policy');
|
|
1783
|
+
}
|
|
1771
1784
|
const capabilityManifest=configuredCapabilityManifest({machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,desktopRuntime});
|
|
1772
1785
|
const profileTimeoutCeiling=Math.max(120000,...Object.values(policy.profiles??{}).map(profile=>
|
|
1773
1786
|
Number.isInteger(profile?.timeout_ms)&&profile.timeout_ms>0?profile.timeout_ms+120000:120000));
|
|
@@ -1784,7 +1797,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1784
1797
|
coding_policy_sha256:policy.coding_policy_sha256 };
|
|
1785
1798
|
}
|
|
1786
1799
|
async function providerCircuitStatus({goalId}) {
|
|
1787
|
-
if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) return null;
|
|
1800
|
+
if (!['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend)) return null;
|
|
1788
1801
|
const ctx=goalContext(policy,goalId);
|
|
1789
1802
|
await loadGoal(ctx,policy,verifyKeyPath);
|
|
1790
1803
|
const journal=await readEvents(ctx,verifyKeyPath);
|
|
@@ -2046,7 +2059,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
2046
2059
|
continue;
|
|
2047
2060
|
}
|
|
2048
2061
|
const accepted = await acceptPlannerDecision({ ctx,events:journal,goal,state,policy,codingRuntime,capabilityManifest,
|
|
2049
|
-
desktopMemoryProvider,memoryProvider,signingKeyPath,plannerResponse:suppliedResponse });
|
|
2062
|
+
desktopMemoryProvider,memoryProvider,signingKeyPath,plannerResponse:suppliedResponse,plannerProviderRuntime });
|
|
2050
2063
|
suppliedResponse = null;
|
|
2051
2064
|
if (accepted?.needs_planner) {
|
|
2052
2065
|
state = deriveState(goal,journal);
|
|
@@ -7,6 +7,8 @@ import { createCodingRuntime, loadCodingPolicy } from './coding-plane.mjs';
|
|
|
7
7
|
import { loadAutonomousPolicy } from './autonomous-policy.mjs';
|
|
8
8
|
import { createNativeDiffRuntime } from './native-diff.mjs';
|
|
9
9
|
import { createAutonomousRuntime } from './autonomous-runtime.mjs';
|
|
10
|
+
import { createCodexAppServerR44 } from './codex-app-server-r44.mjs';
|
|
11
|
+
import { DEADBYTE_VERSION } from './version.mjs';
|
|
10
12
|
import { startLocalSupervisorHost } from './autonomous-local-supervisor.mjs';
|
|
11
13
|
|
|
12
14
|
const packageRoot=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
@@ -30,7 +32,15 @@ const codingPolicy=await loadCodingPolicy(codingPolicyPath);
|
|
|
30
32
|
const codingRuntime=createCodingRuntime({policy:codingPolicy,signingKeyPath,verifyKeyPath});
|
|
31
33
|
const autonomousPolicy=await loadAutonomousPolicy(autonomousPolicyPath,codingPolicy);
|
|
32
34
|
const nativeDiffRuntime=createNativeDiffRuntime({policy:autonomousPolicy,codingRuntime,signingKeyPath,verifyKeyPath});
|
|
33
|
-
const
|
|
35
|
+
const plannerProviderRuntime=autonomousPolicy.planner.backend==='codex_app_server'
|
|
36
|
+
? await createCodexAppServerR44({
|
|
37
|
+
stateDir:path.join(autonomousPolicy.evidence_dir,'provider-r44','codex-app-server'),
|
|
38
|
+
model:autonomousPolicy.planner.model,cwd:codingPolicy.roots[autonomousPolicy.planner.root_id].real_path,
|
|
39
|
+
clientVersion:DEADBYTE_VERSION,executable:autonomousPolicy.planner.executable,
|
|
40
|
+
executableSha256:autonomousPolicy.planner.executable_sha256,args:autonomousPolicy.planner.args
|
|
41
|
+
})
|
|
42
|
+
: null;
|
|
43
|
+
const autonomousRuntime=createAutonomousRuntime({policy:autonomousPolicy,codingRuntime,nativeDiffRuntime,plannerProviderRuntime,signingKeyPath,verifyKeyPath});
|
|
34
44
|
const markerPath=path.resolve(process.env.DEADBYTE_SUPERVISOR_MARKER||path.join(autonomousPolicy.evidence_dir,'supervisor-owner.json'));
|
|
35
45
|
const host=await startLocalSupervisorHost({runtime:autonomousRuntime,policy:autonomousPolicy,markerPath,
|
|
36
46
|
idleDelayMs:750,maxCycles:32,continuous:onceMode!=='1'});
|
|
@@ -43,7 +53,7 @@ let stopping=false;
|
|
|
43
53
|
async function stopAndExit(code=0){
|
|
44
54
|
if(stopping) return;
|
|
45
55
|
stopping=true;
|
|
46
|
-
try { await host.stop(); }
|
|
56
|
+
try { await host.stop(); await plannerProviderRuntime?.close(); }
|
|
47
57
|
catch(error){ process.stderr.write(`DEADBYTE supervisor host stop failed: ${String(error)}\n`); code=1; }
|
|
48
58
|
process.exitCode=code;
|
|
49
59
|
}
|
|
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
|
|
|
3
3
|
export const CAPABILITY_LEDGER_SCHEMA='deadbyte.capability-ledger.v1';
|
|
4
4
|
const AUTHORITIES=new Set(['none','process','coding','autonomous','desktop','host']);
|
|
5
5
|
const PROFILE_ENV='DEADBYTE_CAPABILITY_PROFILE';
|
|
6
|
-
const COMPACT_TOOL_LIMIT=
|
|
6
|
+
const COMPACT_TOOL_LIMIT=43;
|
|
7
7
|
|
|
8
8
|
function sha256(text){return createHash('sha256').update(text,'utf8').digest('hex');}
|
|
9
9
|
function canonicalJson(value){
|
|
@@ -81,6 +81,7 @@ const gateway=(id,full_tool,compact_tool,compact_op,runtime_flag,authority,{muta
|
|
|
81
81
|
|
|
82
82
|
export const R36_CAPABILITY_ENTRIES=Object.freeze([
|
|
83
83
|
direct('evidence.verify','evidence_verify',null,'none',{receipt_class:'verification'}),
|
|
84
|
+
direct('skill.catalog','skill_catalog',null,'none',{receipt_class:'skill'}),
|
|
84
85
|
gateway('machine.list','machine_list','machine_observe','machine_list','DEADBYTE_MACHINE_RUNTIME','none',{receipt_class:'machine'}),
|
|
85
86
|
gateway('machine.status','machine_status','machine_observe','machine_status','DEADBYTE_MACHINE_RUNTIME','none',{receipt_class:'machine'}),
|
|
86
87
|
gateway('machine.ping','machine_ping','machine_observe','machine_ping','DEADBYTE_MACHINE_RUNTIME','none',{receipt_class:'machine'}),
|