deadbyte-mcp 0.15.2 → 0.15.4
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/MANIFEST.SHA256 +66 -41
- package/PROVENANCE.json +3 -3
- package/RELEASE.json +3 -3
- package/package.json +1 -1
- package/scripts/autonomous-build.ps1 +1 -0
- package/scripts/autonomous-tests.ps1 +1 -0
- package/scripts/check-agent-backend-r46.mjs +77 -0
- package/scripts/check-atomic-resource-r46.mjs +84 -0
- package/scripts/check-autonomous-race-r46.mjs +160 -0
- package/scripts/check-coding-task-deadline-r46.mjs +59 -0
- package/scripts/check-deadline-cancellation-r46.mjs +49 -0
- package/scripts/check-process-deadline-r46.mjs +52 -0
- package/scripts/check-r46-background.mjs +5 -0
- package/scripts/extract-r46-failures.mjs +5 -0
- package/scripts/full-regression-r46.mjs +20 -12
- package/scripts/gate-windows-r46.ps1 +2 -0
- package/scripts/inspect-r46-active.mjs +2 -0
- package/scripts/r47-core-failures.mjs +1 -0
- package/scripts/release-manifest.mjs +1 -1
- package/scripts/run-r46-full-regression-background.mjs +7 -0
- package/scripts/run-r46-windows-gate-background.mjs +6 -0
- package/scripts/run-r46-windows-gate-background.ps1 +10 -0
- package/scripts/windows-gate-evidence-r46.mjs +4 -3
- package/scripts/workload-contract-regression-r47.mjs +14 -0
- package/scripts/workload-stream-regression.mjs +16 -0
- package/scripts/workload-substrate-r47-regression.mjs +12 -0
- package/src/agent-backend-r44.mjs +75 -10
- package/src/atomic-mutation.mjs +55 -0
- package/src/autonomous-mcp-tools.mjs +4 -3
- package/src/autonomous-output-contracts.mjs +16 -3
- package/src/autonomous-runtime.mjs +83 -30
- package/src/coding-mcp-tools.mjs +6 -6
- package/src/coding-output-contracts.mjs +20 -5
- package/src/coding-plane.mjs +3 -24
- package/src/coding-search.mjs +52 -15
- package/src/coding-task-runtime.mjs +41 -6
- package/src/compact-gateway-mcp-tools.mjs +3 -3
- package/src/deadline-cancellation.mjs +83 -0
- package/src/fuzzy-search-core.mjs +117 -0
- package/src/fuzzy-search-worker.mjs +8 -0
- package/src/fuzzy-search.mjs +34 -0
- package/src/machine-fs-mcp-tools.mjs +1 -1
- package/src/machine-fs-output-contracts.mjs +1 -1
- package/src/machine-fs-smoke-client.mjs +1 -1
- package/src/machine-fs.mjs +10 -29
- package/src/mcp-server.mjs +6 -0
- package/src/observation-smoke-client.mjs +1 -1
- package/src/process-mcp-tools.mjs +11 -3
- package/src/process-output-contracts.mjs +23 -0
- package/src/process-runtime.mjs +54 -5
- package/src/process-smoke-client.mjs +1 -1
- package/src/resource-identity.mjs +59 -0
- package/src/runtime-update.mjs +526 -162
- package/src/workload-substrate.mjs +87 -0
- package/test/coding-runtime.test.mjs +12 -0
- package/test/coding-search-r36.test.mjs +7 -0
- package/test/full-max-catalog-r46.test.mjs +2 -2
- package/test/fuzzy-search-r46.test.mjs +54 -0
- package/test/helpers/autonomous-r34-fixture.mjs +10 -1
- package/test/machine-fs-mcp-tools.test.mjs +2 -0
- package/test/machine-fs-runtime.test.mjs +6 -0
- package/test/process-mcp-tools.test.mjs +5 -2
- package/test/process-runtime.test.mjs +18 -1
- package/test/r45-finalization.test.mjs +1 -1
- package/test/release-version.test.mjs +1 -1
- package/test/runtime-self-update.test.mjs +118 -1
- package/test/workload-substrate.test.mjs +22 -0
|
@@ -3,6 +3,7 @@ import { EventEmitter } from 'node:events';
|
|
|
3
3
|
import { lstat, mkdir, open, readFile, realpath, rename } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
|
+
import { classifyTermination, composeAbortSignal, createCancellationToken, createDeadline } from './deadline-cancellation.mjs';
|
|
6
7
|
|
|
7
8
|
const STATE_SCHEMA='deadbyte.agent-backend-state.v1';
|
|
8
9
|
const HEX64=/^[0-9a-f]{64}$/;
|
|
@@ -46,6 +47,16 @@ function validateState(state,backendId){
|
|
|
46
47
|
insist(typeof item.method==='string'&&METHOD.test(item.method),'agent backend request method invalid');
|
|
47
48
|
insist(HEX64.test(item.params_sha256??''),'agent backend params hash invalid');
|
|
48
49
|
insist(typeof item.created_at_utc==='string'&&typeof item.updated_at_utc==='string','agent backend request timestamp invalid');
|
|
50
|
+
if(item.deadline!==undefined){
|
|
51
|
+
insist(item.deadline&&item.deadline.schema==='deadbyte.deadline.v1','agent backend request deadline invalid');
|
|
52
|
+
insist(item.deadline.timeout_ms===null||Number.isInteger(item.deadline.timeout_ms),'agent backend request deadline timeout invalid');
|
|
53
|
+
insist(item.deadline.deadline_ms===null||Number.isFinite(item.deadline.deadline_ms),'agent backend request deadline timestamp invalid');
|
|
54
|
+
}
|
|
55
|
+
if(item.termination!==undefined){
|
|
56
|
+
insist(item.termination&&typeof item.termination==='object'&&!Array.isArray(item.termination),'agent backend request termination invalid');
|
|
57
|
+
for(const key of ['deadline_exceeded','cancellation_requested','physical_termination','verified'])insist(typeof item.termination[key]==='boolean',`agent backend request termination ${key} invalid`);
|
|
58
|
+
insist(typeof item.termination.terminal_semantics==='string','agent backend request termination semantics invalid');
|
|
59
|
+
}
|
|
49
60
|
}
|
|
50
61
|
insist(typeof state.updated_at_utc==='string','agent backend state timestamp invalid');
|
|
51
62
|
return state;
|
|
@@ -157,11 +168,12 @@ export async function createAgentBackendR44({
|
|
|
157
168
|
threads:structuredClone(state.threads),requests:structuredClone(state.requests)
|
|
158
169
|
});
|
|
159
170
|
|
|
160
|
-
async function terminal(id,{stateName,result=null,error=null}){
|
|
171
|
+
async function terminal(id,{stateName,result=null,error=null,termination=null}){
|
|
161
172
|
const record=state.requests[id];if(!record||record.state!=='pending')return;
|
|
162
173
|
record.state=stateName;record.updated_at_utc=now();
|
|
163
174
|
if(result!==null)record.result=result;
|
|
164
175
|
if(error!==null)record.error=String(error);
|
|
176
|
+
if(termination!==null)record.termination=termination;
|
|
165
177
|
await persist();
|
|
166
178
|
const waiter=pending.get(id);pending.delete(id);
|
|
167
179
|
if(!waiter)return;
|
|
@@ -198,11 +210,29 @@ export async function createAgentBackendR44({
|
|
|
198
210
|
for(const id of pending.keys())void terminal(id,{stateName:'failed',error:String(error?.message??error)});
|
|
199
211
|
});
|
|
200
212
|
transport.on('transport_error',error=>{
|
|
201
|
-
for(const id of pending.keys())
|
|
213
|
+
for(const id of pending.keys()){
|
|
214
|
+
const record=state.requests[id];
|
|
215
|
+
const termination=classifyTermination({
|
|
216
|
+
deadlineExceeded:record?.termination?.deadline_exceeded===true,
|
|
217
|
+
cancellationRequested:record?.termination?.cancellation_requested===true,
|
|
218
|
+
physicallyTerminated:false,
|
|
219
|
+
verified:false
|
|
220
|
+
});
|
|
221
|
+
void terminal(id,{stateName:'interrupted',error:String(error?.message??error),termination});
|
|
222
|
+
}
|
|
202
223
|
started=false;
|
|
203
224
|
});
|
|
204
225
|
transport.on('exit',()=>{
|
|
205
|
-
for(const id of pending.keys())
|
|
226
|
+
for(const id of pending.keys()){
|
|
227
|
+
const record=state.requests[id];
|
|
228
|
+
const termination=classifyTermination({
|
|
229
|
+
deadlineExceeded:record?.termination?.deadline_exceeded===true,
|
|
230
|
+
cancellationRequested:record?.termination?.cancellation_requested===true,
|
|
231
|
+
physicallyTerminated:true,
|
|
232
|
+
verified:true
|
|
233
|
+
});
|
|
234
|
+
void terminal(id,{stateName:'interrupted',error:'agent backend transport exited',termination});
|
|
235
|
+
}
|
|
206
236
|
started=false;
|
|
207
237
|
});
|
|
208
238
|
await transport.start();started=true;return publicState();
|
|
@@ -223,17 +253,52 @@ export async function createAgentBackendR44({
|
|
|
223
253
|
const sequence=++state.next_sequence;
|
|
224
254
|
const paramsSha=sha(Buffer.from(canonicalJson(params),'utf8'));
|
|
225
255
|
const id=sha(Buffer.from(canonicalJson({backend_id:backendId,state_epoch:state.state_epoch,sequence,method,params_sha256:paramsSha}),'utf8'));
|
|
226
|
-
|
|
256
|
+
const deadline=createDeadline({timeoutMs,id});
|
|
257
|
+
const cancellation=createCancellationToken({id});
|
|
258
|
+
const composed=composeAbortSignal({deadline,cancellation});
|
|
259
|
+
state.requests[id]={
|
|
260
|
+
state:'pending',method,params_sha256:paramsSha,created_at_utc:now(),updated_at_utc:now(),
|
|
261
|
+
deadline,
|
|
262
|
+
termination:classifyTermination()
|
|
263
|
+
};
|
|
227
264
|
await persist();
|
|
228
|
-
let timer;
|
|
229
265
|
const promise=new Promise((resolve,reject)=>{
|
|
230
|
-
pending.set(id,{resolve,reject});
|
|
231
|
-
|
|
232
|
-
|
|
266
|
+
pending.set(id,{resolve,reject,cancellation,composed});
|
|
267
|
+
composed.signal.addEventListener('abort',()=>{
|
|
268
|
+
const reason=String(composed.signal.reason??'cancelled');
|
|
269
|
+
const deadlineExceeded=reason==='deadline_exceeded';
|
|
270
|
+
const cancellationRequested=cancellation.snapshot().requested;
|
|
271
|
+
const termination=classifyTermination({deadlineExceeded,cancellationRequested,physicallyTerminated:false,verified:false});
|
|
272
|
+
void terminal(id,{stateName:'failed',error:deadlineExceeded?'agent backend request deadline exceeded':'agent backend request cancelled',termination});
|
|
273
|
+
},{once:true});
|
|
274
|
+
}).finally(()=>{
|
|
275
|
+
composed.close();
|
|
276
|
+
const waiter=pending.get(id);
|
|
277
|
+
if(waiter?.composed===composed)pending.delete(id);
|
|
278
|
+
});
|
|
233
279
|
try{await transport.send(wire({id,method,params}));}
|
|
234
|
-
catch(error){
|
|
280
|
+
catch(error){
|
|
281
|
+
const record=state.requests[id];
|
|
282
|
+
const termination=classifyTermination({
|
|
283
|
+
deadlineExceeded:record?.termination?.deadline_exceeded===true,
|
|
284
|
+
cancellationRequested:record?.termination?.cancellation_requested===true,
|
|
285
|
+
physicallyTerminated:false,
|
|
286
|
+
verified:false
|
|
287
|
+
});
|
|
288
|
+
await terminal(id,{stateName:'failed',error:String(error?.message??error),termination});
|
|
289
|
+
}
|
|
235
290
|
return promise;
|
|
236
291
|
}
|
|
292
|
+
async function cancelRequest(id,{reason='operator_request'}={}){
|
|
293
|
+
insist(HEX64.test(id),'agent backend request id invalid');
|
|
294
|
+
const record=state.requests[id];
|
|
295
|
+
if(!record)return {status:'missing',request_id:id};
|
|
296
|
+
if(record.state!=='pending')return {status:'terminal',request_id:id,state:record.state,termination:record.termination??null};
|
|
297
|
+
const waiter=pending.get(id);
|
|
298
|
+
if(!waiter?.cancellation)return {status:'pending',request_id:id,termination:record.termination??null};
|
|
299
|
+
waiter.cancellation.request(reason);
|
|
300
|
+
return {status:'requested',request_id:id};
|
|
301
|
+
}
|
|
237
302
|
async function notify({method,params={}}={}){
|
|
238
303
|
insist(started&&transport,'agent backend is not started');
|
|
239
304
|
insist(typeof method==='string'&&METHOD.test(method),'agent backend notification method invalid');
|
|
@@ -250,5 +315,5 @@ export async function createAgentBackendR44({
|
|
|
250
315
|
for(const [id,waiter] of pending){waiter.reject(new Error('simulated backend crash'));pending.delete(id);}
|
|
251
316
|
if(transport?.stop)await transport.stop();transport=null;started=false;
|
|
252
317
|
}
|
|
253
|
-
return Object.freeze({start,bindThread,request,notify,status,close,simulateCrashForTest,state_file:stateFile,wire_mode:wireMode});
|
|
318
|
+
return Object.freeze({start,bindThread,request,cancelRequest,notify,status,close,simulateCrashForTest,state_file:stateFile,wire_mode:wireMode});
|
|
254
319
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { open, rename, rm } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const sha256Bytes = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
6
|
+
|
|
7
|
+
export async function atomicMutation({
|
|
8
|
+
target,
|
|
9
|
+
bytes,
|
|
10
|
+
expected,
|
|
11
|
+
readState,
|
|
12
|
+
assertExpected,
|
|
13
|
+
authorityCheck = null,
|
|
14
|
+
tempTag = 'deadbyte-atomic',
|
|
15
|
+
verifyPostcondition = null
|
|
16
|
+
}) {
|
|
17
|
+
if (typeof target !== 'string' || target.length === 0) throw new Error('atomic mutation target is required');
|
|
18
|
+
if (!Buffer.isBuffer(bytes)) throw new Error('atomic mutation bytes must be a Buffer');
|
|
19
|
+
if (typeof readState !== 'function' || typeof assertExpected !== 'function') {
|
|
20
|
+
throw new Error('atomic mutation requires readState and assertExpected');
|
|
21
|
+
}
|
|
22
|
+
const before = await readState(target);
|
|
23
|
+
assertExpected(before, expected);
|
|
24
|
+
const temp = path.join(
|
|
25
|
+
path.dirname(target),
|
|
26
|
+
`.\${path.basename(target)}.\${tempTag}-\${process.pid}-\${randomBytes(8).toString('hex')}.tmp`
|
|
27
|
+
);
|
|
28
|
+
let handle;
|
|
29
|
+
try {
|
|
30
|
+
if (authorityCheck) await authorityCheck();
|
|
31
|
+
handle = await open(temp, 'wx', 0o600);
|
|
32
|
+
await handle.writeFile(bytes);
|
|
33
|
+
await handle.sync();
|
|
34
|
+
await handle.close();
|
|
35
|
+
handle = null;
|
|
36
|
+
|
|
37
|
+
const race = await readState(target);
|
|
38
|
+
assertExpected(race, expected);
|
|
39
|
+
if (authorityCheck) await authorityCheck();
|
|
40
|
+
|
|
41
|
+
await rename(temp, target);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (handle) await handle.close().catch(() => {});
|
|
44
|
+
await rm(temp, { force: true }).catch(() => {});
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const after = await readState(target);
|
|
49
|
+
const expectedAfter = sha256Bytes(bytes);
|
|
50
|
+
if (!after.exists || after.sha256 !== expectedAfter) {
|
|
51
|
+
throw new Error('atomic mutation post-commit hash mismatch');
|
|
52
|
+
}
|
|
53
|
+
if (verifyPostcondition) await verifyPostcondition({ before, after, expected_after_sha256: expectedAfter });
|
|
54
|
+
return { before, after, expected_after_sha256: expectedAfter };
|
|
55
|
+
}
|
|
@@ -72,11 +72,12 @@ export function registerAutonomousTools(server,{ autonomousRuntime, nativeDiffRu
|
|
|
72
72
|
inputSchema:z.strictObject({ submission_id:id, root_id:id, title:z.string().max(160).default(''),
|
|
73
73
|
goal:z.string().min(1).max(8192), acceptance:z.string().max(4096).default(''),
|
|
74
74
|
task_contract:taskContract.nullable().default(null),
|
|
75
|
-
max_iterations:z.number().int().min(1).max(64).nullable().default(null)
|
|
75
|
+
max_iterations:z.number().int().min(1).max(64).nullable().default(null),
|
|
76
|
+
timeout_ms:z.number().int().min(100).max(900000).nullable().default(null) }),
|
|
76
77
|
outputSchema:autonomousGoalSubmitOutputSchema
|
|
77
|
-
},async({submission_id,root_id,title,goal,acceptance,task_contract,max_iterations})=>{ try {
|
|
78
|
+
},async({submission_id,root_id,title,goal,acceptance,task_contract,max_iterations,timeout_ms})=>{ try {
|
|
78
79
|
return result(autonomousGoalSubmitOutputSchema,await autonomousRuntime.submit({ submissionId:submission_id,
|
|
79
|
-
rootId:root_id,title,goal,acceptance,taskContract:task_contract,maxIterations:max_iterations })); }
|
|
80
|
+
rootId:root_id,title,goal,acceptance,taskContract:task_contract,maxIterations:max_iterations,timeoutMs:timeout_ms })); }
|
|
80
81
|
catch(error){ return fail(autonomousGoalSubmitOutputSchema,error); } });
|
|
81
82
|
server.registerTool('autonomous_goal_run',{
|
|
82
83
|
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.',
|
|
@@ -3,7 +3,17 @@ import * as z from 'zod/v4';
|
|
|
3
3
|
const hex64 = z.string().regex(/^[0-9a-f]{64}$/);
|
|
4
4
|
const goalId = hex64;
|
|
5
5
|
const jsonObject = z.record(z.string(),z.json());
|
|
6
|
+
const streamCoverage = z.strictObject({
|
|
7
|
+
logical_first_seq:z.number().int().min(1), logical_last_seq:z.number().int().min(0),
|
|
8
|
+
retained_first_seq:z.number().int().min(1), retained_last_seq:z.number().int().min(0),
|
|
9
|
+
complete:z.boolean(), truncated:z.boolean(),
|
|
10
|
+
missing_ranges:z.array(z.strictObject({from:z.number().int().min(1),to:z.number().int().min(0)})).max(100000),
|
|
11
|
+
logical_item_count:z.number().int().min(0), retained_item_count:z.number().int().min(0),
|
|
12
|
+
logical_bytes:z.number().int().min(0), retained_bytes:z.number().int().min(0),
|
|
13
|
+
dropped_items:z.number().int().min(0), dropped_bytes:z.number().int().min(0), status:z.enum(['open','closed'])
|
|
14
|
+
});
|
|
6
15
|
const goalState = z.enum(['pending','running','paused','cancelled','succeeded']);
|
|
16
|
+
const deadline = z.strictObject({ schema:z.literal('deadbyte.deadline.v1'), id:z.string().nullable(), created_at_ms:z.number(), timeout_ms:z.number().int().min(1).nullable(), deadline_ms:z.number().nullable() });
|
|
7
17
|
const loopPhase = z.enum(['PLANNING','INSPECTING','ACTING','VERIFYING','REPLANNING','WAITING','COMPLETE']);
|
|
8
18
|
const loopStep = z.strictObject({
|
|
9
19
|
step_id:z.string().regex(/^[A-Za-z0-9._-]{1,64}$/), intent:z.string().min(1).max(512), status:z.literal('active')
|
|
@@ -106,7 +116,7 @@ export const autonomousGoalSubmitOutputSchema = statusContract({
|
|
|
106
116
|
const runShape = Object.fromEntries(Object.entries(derivedShape).map(([key,schema]) => [key,schema.optional()]));
|
|
107
117
|
export const autonomousGoalRunOutputSchema = z.strictObject({
|
|
108
118
|
status:z.enum(['terminal','paused','cancelled','completed','yielded','running','input_required','failed']), error:z.string().optional(),
|
|
109
|
-
goal_id:goalId.optional(), release:jsonObject.optional(), planner_request:jsonObject.optional(), loop:publicLoopSchema.optional(),
|
|
119
|
+
goal_id:goalId.optional(), release:jsonObject.optional(), planner_request:jsonObject.optional(), deadline:deadline.optional(), loop:publicLoopSchema.optional(),
|
|
110
120
|
cycles:z.number().int().min(1).max(32).optional(), ...runShape
|
|
111
121
|
}).superRefine((value,ctx) => {
|
|
112
122
|
if (value.error !== undefined) { if (value.status !== 'failed') ctx.addIssue({code:'custom',path:['error'],message:'error wrapper requires failed'}); return; }
|
|
@@ -119,12 +129,15 @@ export const autonomousGoalStatusOutputSchema = statusContract({
|
|
|
119
129
|
shape:{ goal_id:goalId.optional(), goal_sha256:hex64.optional(), title:z.string().optional(), root_id:z.string().optional(),
|
|
120
130
|
journal_verified:z.literal(true).optional(), run_busy:z.boolean().optional(),
|
|
121
131
|
run_owner_pid:z.number().int().min(1).nullable().optional(),
|
|
122
|
-
run_lock_created_at_utc:z.string().nullable().optional(), loop:publicLoopSchema.optional(),
|
|
132
|
+
run_lock_created_at_utc:z.string().nullable().optional(), timeout_ms:z.number().int().min(100).max(900000).nullable().optional(), deadline:deadline.optional(), loop:publicLoopSchema.optional(),
|
|
133
|
+
stream_id:goalId.nullable().optional(), stream_generation:z.number().int().min(1).nullable().optional(),
|
|
134
|
+
stream_next_seq:z.number().int().min(1).nullable().optional(), stream_coverage:streamCoverage.nullable().optional(), ...runShape }
|
|
123
135
|
});
|
|
124
136
|
export const autonomousGoalEventsOutputSchema = statusContract({
|
|
125
137
|
statuses:['ok','failed'], success:['ok'], required:['goal_id','journal_verified','journal_head_sha256','events'],
|
|
126
138
|
shape:{ goal_id:goalId.optional(), journal_verified:z.literal(true).optional(), journal_head_sha256:hex64.optional(),
|
|
127
|
-
events:z.array(jsonObject).max(200).optional()
|
|
139
|
+
events:z.array(jsonObject).max(200).optional(), stream_id:goalId.optional(), stream_generation:z.number().int().min(1).optional(),
|
|
140
|
+
stream_next_seq:z.number().int().min(1).optional(), stream_coverage:streamCoverage.optional() }
|
|
128
141
|
});
|
|
129
142
|
export const autonomousGoalCancelOutputSchema = statusContract({
|
|
130
143
|
statuses:['terminal','requested','existing','failed'], success:['terminal','requested','existing'], required:['goal_id','state'],
|
|
@@ -17,6 +17,8 @@ import { deriveAgentMemory } from './agent-memory-plane.mjs';
|
|
|
17
17
|
import { effectIdentity, loopGuardDisposition, bindEffectCompletion } from './effect-ledger.mjs';
|
|
18
18
|
import { createWorkerScheduler } from './worker-scheduler.mjs';
|
|
19
19
|
import { issueObservationLease, verifyObservationLease } from './observation-lease.mjs';
|
|
20
|
+
import { createJournalStream } from './workload-substrate.mjs';
|
|
21
|
+
import { createDeadline, deadlineState } from './deadline-cancellation.mjs';
|
|
20
22
|
|
|
21
23
|
export const AUTONOMOUS_GOAL_SCHEMA = 'deadbyte.autonomous-goal.v1';
|
|
22
24
|
export const AUTONOMOUS_EVENT_SCHEMA = 'deadbyte.autonomous-event.v1';
|
|
@@ -229,7 +231,7 @@ function profileOutcome(profile, checked) {
|
|
|
229
231
|
{ median_ms:receipt.median_ms, p95_ms:receipt.p95_ms, regression_pct:receipt.regression_pct, verdict:receipt.verdict }) } };
|
|
230
232
|
}
|
|
231
233
|
async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch, policy, codingRuntime, signingKeyPath,
|
|
232
|
-
r34ResumePhase = null }) {
|
|
234
|
+
r34ResumePhase = null, childDeadline = null }) {
|
|
233
235
|
const profile = policy.profiles[profileId];
|
|
234
236
|
if (!profile) throw new Error(`autonomous profile '${profileId}' not found`);
|
|
235
237
|
const prior = [...events].reverse().find(event => event.type === 'profile_completed' && event.payload?.action_key === actionKey && event.payload?.profile_id === profileId);
|
|
@@ -274,6 +276,9 @@ async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch
|
|
|
274
276
|
await appendEvent(ctx,events,signingKeyPath,'profile_completed',payload);
|
|
275
277
|
return { status:outcome.passed ? 'passed' : 'failed', observation:payload, existing:false };
|
|
276
278
|
}
|
|
279
|
+
const childRemainingRaw = childDeadline ? deadlineState(childDeadline).remaining_ms : null;
|
|
280
|
+
const childRemainingMs = childRemainingRaw === null ? null : Math.floor(childRemainingRaw);
|
|
281
|
+
if (childRemainingMs !== null && childRemainingMs < 100) throw new Error('deadline_exceeded');
|
|
277
282
|
const autonomousAuthority = await assertAutonomousArmed(policy,profile.root_id);
|
|
278
283
|
if (Number.isFinite(autonomousAuthority.remaining_ms) && autonomousAuthority.remaining_ms < 100) {
|
|
279
284
|
throw new Error('autonomous lease expires too soon to execute profile');
|
|
@@ -283,20 +288,22 @@ async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch
|
|
|
283
288
|
authority_instance_nonce:autonomousAuthority.instance_nonce,
|
|
284
289
|
authority_expires_at_utc:autonomousAuthority.expires_at_utc });
|
|
285
290
|
const preExecutionCheck = () => recheckAutonomousAuthority(policy,autonomousAuthority,profile.root_id);
|
|
291
|
+
const childTimeoutMs = childRemainingMs === null ? profile.timeout_ms : Math.max(100, Math.min(profile.timeout_ms, childRemainingMs));
|
|
286
292
|
let result;
|
|
287
293
|
try {
|
|
288
294
|
result = profile.kind === 'command'
|
|
289
295
|
? await codingRuntime.commandRun({ rootId:profile.root_id, commandId:profile.command_id, scriptPath:profile.script_path,
|
|
290
|
-
scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:
|
|
296
|
+
scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:childTimeoutMs,
|
|
291
297
|
executionDeadlineUtc:autonomousAuthority.expires_at_utc, preExecutionCheck, receiptId, requestSha256 })
|
|
292
298
|
: await codingRuntime.benchmarkRun({ rootId:profile.root_id, commandId:profile.command_id, scriptPath:profile.script_path,
|
|
293
|
-
scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:
|
|
299
|
+
scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:childTimeoutMs,
|
|
294
300
|
executionDeadlineUtc:autonomousAuthority.expires_at_utc, preExecutionCheck,
|
|
295
301
|
warmups:profile.warmups, iterations:profile.iterations, baselineMedianMs:profile.baseline_median_ms,
|
|
296
302
|
maxRegressionPct:profile.max_regression_pct, receiptId, requestSha256 });
|
|
297
303
|
} catch (error) {
|
|
298
304
|
const checked = await codingRuntime.verifyReceiptDetailed(receiptId);
|
|
299
305
|
if (!checked.ok) {
|
|
306
|
+
if (childDeadline && deadlineState(childDeadline).expired) throw new Error('deadline_exceeded');
|
|
300
307
|
const r34Paused=await pauseR34Ambiguous(checked.reason ?? error);
|
|
301
308
|
if (r34Paused) return r34Paused;
|
|
302
309
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{ reason:'profile_execution_without_receipt', profile_id:profileId,
|
|
@@ -311,6 +318,7 @@ async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch
|
|
|
311
318
|
if (r34Paused) return r34Paused;
|
|
312
319
|
throw new Error(`profile '${profileId}' post-execution receipt verification failed`);
|
|
313
320
|
}
|
|
321
|
+
if (childDeadline && deadlineState(childDeadline).expired) throw new Error('deadline_exceeded');
|
|
314
322
|
const outcome = profileOutcome(profile,checked);
|
|
315
323
|
if (!outcome.valid) {
|
|
316
324
|
const r34Paused=await pauseR34Ambiguous(outcome.reason);
|
|
@@ -363,7 +371,7 @@ function normalizeTaskContract(raw) {
|
|
|
363
371
|
constraints:list('constraints',32,512),evidence_requirements:list('evidence_requirements',32,512),
|
|
364
372
|
risk_level:value.risk_level,clarification_policy:value.clarification_policy,...rigor});
|
|
365
373
|
}
|
|
366
|
-
function normalizeGoal(policy, { submissionId, rootId, title = '', goal, acceptance = '', taskContract = null, maxIterations = null }) {
|
|
374
|
+
function normalizeGoal(policy, { submissionId, rootId, title = '', goal, acceptance = '', taskContract = null, maxIterations = null, timeoutMs = null }) {
|
|
367
375
|
if (!ID_RE.test(submissionId ?? '')) throw new Error('autonomous submission_id invalid');
|
|
368
376
|
if (!policy.root_ids.includes(rootId)) throw new Error(`autonomous root '${rootId}' is not allowed`);
|
|
369
377
|
if (typeof title !== 'string' || title.length > 160) throw new Error('autonomous title must be <=160 characters');
|
|
@@ -371,9 +379,10 @@ function normalizeGoal(policy, { submissionId, rootId, title = '', goal, accepta
|
|
|
371
379
|
if (typeof acceptance !== 'string' || acceptance.length > 4096) throw new Error('autonomous acceptance must be <=4096 characters');
|
|
372
380
|
const iterations = maxIterations ?? policy.limits.max_iterations;
|
|
373
381
|
if (!Number.isInteger(iterations) || iterations < 1 || iterations > policy.limits.max_iterations) throw new Error('autonomous max_iterations exceeds policy');
|
|
382
|
+
if (timeoutMs !== null && (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 900000)) throw new Error('autonomous timeout_ms must be null or in [100,900000]');
|
|
374
383
|
const body = { schema:AUTONOMOUS_GOAL_SCHEMA, policy_sha256:policy.policy_sha256,
|
|
375
384
|
coding_policy_sha256:policy.coding_policy_sha256, submission_id:submissionId, root_id:rootId,
|
|
376
|
-
title, goal, acceptance, task_contract:normalizeTaskContract(taskContract),max_iterations:iterations };
|
|
385
|
+
title, goal, acceptance, task_contract:normalizeTaskContract(taskContract),max_iterations:iterations, timeout_ms:timeoutMs };
|
|
377
386
|
return Object.freeze({ ...body, goal_sha256:sha256Object(body) });
|
|
378
387
|
}
|
|
379
388
|
|
|
@@ -731,7 +740,9 @@ function assertDelegatedIdentity(events, operation) {
|
|
|
731
740
|
}
|
|
732
741
|
}
|
|
733
742
|
}
|
|
734
|
-
async function invokeDelegatedOperation(goal, operation, runtimes, desktopContext=null) {
|
|
743
|
+
async function invokeDelegatedOperation(goal, operation, runtimes, desktopContext=null, childDeadline=null) {
|
|
744
|
+
const remainingMs = childDeadline ? Math.max(100, Math.floor(deadlineState(childDeadline).remaining_ms)) : null;
|
|
745
|
+
if (childDeadline && deadlineState(childDeadline).expired) throw new Error('deadline_exceeded');
|
|
735
746
|
const { codingRuntime, semanticRuntime, nativeDiffRuntime, machineFsRuntime, observationRuntime, processRuntime, desktopRuntime } = runtimes;
|
|
736
747
|
switch (operation.kind) {
|
|
737
748
|
case 'stat':
|
|
@@ -804,7 +815,7 @@ async function invokeDelegatedOperation(goal, operation, runtimes, desktopContex
|
|
|
804
815
|
return observationRuntime.systemStatus();
|
|
805
816
|
case 'process_start':
|
|
806
817
|
if (!processRuntime) throw new Error('process runtime unavailable');
|
|
807
|
-
return processRuntime.start({ profileId:operation.profile_id, rootId:goal.root_id, cwd:operation.cwd, args:operation.args??[] });
|
|
818
|
+
return processRuntime.start({ profileId:operation.profile_id, rootId:goal.root_id, cwd:operation.cwd, args:operation.args??[], timeoutMs:remainingMs });
|
|
808
819
|
case 'process_read':
|
|
809
820
|
if (!processRuntime) throw new Error('process runtime unavailable');
|
|
810
821
|
return processRuntime.read({ sessionId:operation.session_id, offset:operation.offset, maxBytes:operation.max_bytes });
|
|
@@ -893,7 +904,7 @@ async function verifyDelegatedEvidence(operation, result, runtimes, verifyKeyPat
|
|
|
893
904
|
return { kind:'runtime_result', result_sha256:sha256Object(result) };
|
|
894
905
|
}
|
|
895
906
|
async function executeDelegate({ ctx, events, goal, decisionEvent, decision, policy, runtimes, assertRunAuthority,
|
|
896
|
-
signingKeyPath, verifyKeyPath }) {
|
|
907
|
+
signingKeyPath, verifyKeyPath, childDeadline = null }) {
|
|
897
908
|
const capabilityId=capabilityIdForOperation(decision.operation);
|
|
898
909
|
if(!capabilityId) throw new Error(`unsupported typed capability action '${String(decision.operation?.kind)}'`);
|
|
899
910
|
const actionKey = `capability-${decisionEvent.event_sha256}`;
|
|
@@ -939,7 +950,7 @@ async function executeDelegate({ ctx, events, goal, decisionEvent, decision, pol
|
|
|
939
950
|
}
|
|
940
951
|
};
|
|
941
952
|
}
|
|
942
|
-
const result = await invokeDelegatedOperation(goal,decision.operation,runtimes,desktopContext);
|
|
953
|
+
const result = await invokeDelegatedOperation(goal,decision.operation,runtimes,desktopContext,childDeadline);
|
|
943
954
|
if (Buffer.byteLength(canonicalJson(result),'utf8') > policy.limits.max_context_bytes) {
|
|
944
955
|
throw new Error('delegated result exceeds autonomous context bound');
|
|
945
956
|
}
|
|
@@ -971,7 +982,7 @@ async function executeDelegate({ ctx, events, goal, decisionEvent, decision, pol
|
|
|
971
982
|
}
|
|
972
983
|
}
|
|
973
984
|
|
|
974
|
-
async function executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,actionKey,profileId,policy,codingRuntime,signingKeyPath,r34ResumePhase=null}) {
|
|
985
|
+
async function executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,actionKey,profileId,policy,codingRuntime,signingKeyPath,r34ResumePhase=null,childDeadline=null}) {
|
|
975
986
|
if(!workerScheduler) throw new Error('R37 worker scheduler unavailable');
|
|
976
987
|
const taskId=`${goal.goal_id}:${actionKey}:${profileId}`;
|
|
977
988
|
const lease=workerScheduler.acquire({taskId,workerClass:'profile',cpuUnits:1,memoryMb:256});
|
|
@@ -981,7 +992,7 @@ async function executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,ac
|
|
|
981
992
|
});
|
|
982
993
|
let outcomeStatus='failed';
|
|
983
994
|
try {
|
|
984
|
-
const result=await executeProfile({ctx,events,goalId:goal.goal_id,actionKey,profileId,epoch,policy,codingRuntime,signingKeyPath,r34ResumePhase});
|
|
995
|
+
const result=await executeProfile({ctx,events,goalId:goal.goal_id,actionKey,profileId,epoch,policy,codingRuntime,signingKeyPath,r34ResumePhase,childDeadline});
|
|
985
996
|
outcomeStatus=result.status;
|
|
986
997
|
return result;
|
|
987
998
|
} finally {
|
|
@@ -993,14 +1004,14 @@ async function executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,ac
|
|
|
993
1004
|
}
|
|
994
1005
|
}
|
|
995
1006
|
|
|
996
|
-
async function runMutationProfiles({ ctx, events, goal, epoch, actionKey, policy, codingRuntime, signingKeyPath, workerScheduler }) {
|
|
1007
|
+
async function runMutationProfiles({ ctx, events, goal, epoch, actionKey, policy, codingRuntime, signingKeyPath, workerScheduler, childDeadline=null }) {
|
|
997
1008
|
const profileIds = Object.entries(policy.profiles)
|
|
998
1009
|
.filter(([,profile]) => profile.run_after_mutation)
|
|
999
1010
|
.map(([id]) => id);
|
|
1000
1011
|
const results = [];
|
|
1001
1012
|
for (const profileId of profileIds) {
|
|
1002
1013
|
const result = await executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,
|
|
1003
|
-
actionKey:`${actionKey}:${profileId}`,profileId,policy,codingRuntime,signingKeyPath});
|
|
1014
|
+
actionKey:`${actionKey}:${profileId}`,profileId,policy,codingRuntime,signingKeyPath,childDeadline});
|
|
1004
1015
|
results.push({ profile_id:profileId, status:result.status, observation:result.observation });
|
|
1005
1016
|
if (result.status === 'paused') break;
|
|
1006
1017
|
}
|
|
@@ -1402,7 +1413,7 @@ function r34ReasonHash(goal,decisionEvent,reason) {
|
|
|
1402
1413
|
}
|
|
1403
1414
|
async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,policy,codingRuntime,
|
|
1404
1415
|
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,desktopRuntime,assertRunAuthority,
|
|
1405
|
-
signingKeyPath,verifyKeyPath,workerScheduler}) {
|
|
1416
|
+
signingKeyPath,verifyKeyPath,workerScheduler,childDeadline=null}) {
|
|
1406
1417
|
let loop=deriveLoopState(goal,events);
|
|
1407
1418
|
if (decision.kind === 'plan_create') {
|
|
1408
1419
|
if (loop.phase !== 'PLAN' || loop.plan) throw new Error('R34 plan_create requires empty PLANNING state');
|
|
@@ -1460,11 +1471,11 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1460
1471
|
await assertRunAuthority(goal.root_id);
|
|
1461
1472
|
outcome=await executeProfileWithLease({workerScheduler,ctx,events,goal,
|
|
1462
1473
|
actionKey:`r34-${decisionEvent.event_sha256}`,profileId:decision.action.profile_id,
|
|
1463
|
-
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath,r34ResumePhase:loop.phase});
|
|
1474
|
+
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath,r34ResumePhase:loop.phase,childDeadline});
|
|
1464
1475
|
} else if (decision.action.kind === 'delegate') {
|
|
1465
1476
|
outcome=await executeDelegate({ctx,events,goal,decisionEvent,
|
|
1466
1477
|
decision:{operation:decision.action.operation},policy,
|
|
1467
|
-
runtimes:{codingRuntime,semanticRuntime,nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,desktopRuntime},assertRunAuthority,signingKeyPath,verifyKeyPath});
|
|
1478
|
+
runtimes:{codingRuntime,semanticRuntime,nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,desktopRuntime},assertRunAuthority,signingKeyPath,verifyKeyPath,childDeadline});
|
|
1468
1479
|
} else if (decision.action.kind === 'native_diff_apply') {
|
|
1469
1480
|
await assertRunAuthority(goal.root_id);
|
|
1470
1481
|
outcome=await executePreparedDiff({ctx,events,goal,state,decisionEvent,diffId:decision.action.diff_id,
|
|
@@ -1493,7 +1504,7 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1493
1504
|
} else if (capabilityIdForOperation(decision.action)) {
|
|
1494
1505
|
outcome=await executeDelegate({ctx,events,goal,decisionEvent,
|
|
1495
1506
|
decision:{operation:decision.action},policy,
|
|
1496
|
-
runtimes:{codingRuntime,semanticRuntime,nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,desktopRuntime},assertRunAuthority,signingKeyPath,verifyKeyPath});
|
|
1507
|
+
runtimes:{codingRuntime,semanticRuntime,nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,desktopRuntime},assertRunAuthority,signingKeyPath,verifyKeyPath,childDeadline});
|
|
1497
1508
|
} else {
|
|
1498
1509
|
throw new Error(`unsupported R34 action '${String(decision.action.kind)}'`);
|
|
1499
1510
|
}
|
|
@@ -1612,12 +1623,12 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1612
1623
|
|
|
1613
1624
|
async function executeDecisionCore({ ctx, events, goal, state, decisionEvent, policy, codingRuntime,
|
|
1614
1625
|
nativeDiffRuntime, machineFsRuntime, observationRuntime, processRuntime, semanticRuntime, desktopRuntime, assertRunAuthority,
|
|
1615
|
-
signingKeyPath, verifyKeyPath, workerScheduler }) {
|
|
1626
|
+
signingKeyPath, verifyKeyPath, workerScheduler, childDeadline = null }) {
|
|
1616
1627
|
const decision = decisionEvent.decision;
|
|
1617
1628
|
if (decision?.schema === 'deadbyte.autonomous-decision.v2') {
|
|
1618
1629
|
const outcome=await executeR34Decision({ctx,events,goal,state,decisionEvent,decision,policy,codingRuntime,
|
|
1619
1630
|
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,desktopRuntime,assertRunAuthority,
|
|
1620
|
-
signingKeyPath,verifyKeyPath,workerScheduler});
|
|
1631
|
+
signingKeyPath,verifyKeyPath,workerScheduler,childDeadline});
|
|
1621
1632
|
await appendEvent(ctx,events,signingKeyPath,'decision_completed',{
|
|
1622
1633
|
decision_event_sha256:decisionEvent.event_sha256,action:decision.kind,
|
|
1623
1634
|
outcome_status:outcome.status ?? 'completed'
|
|
@@ -1650,12 +1661,12 @@ async function executeDecisionCore({ ctx, events, goal, state, decisionEvent, po
|
|
|
1650
1661
|
policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
1651
1662
|
} else if (decision.action === 'delegate') {
|
|
1652
1663
|
outcome = await executeDelegate({ ctx,events,goal,decisionEvent,decision,policy,
|
|
1653
|
-
runtimes:{ machineFsRuntime,observationRuntime,processRuntime },assertRunAuthority,signingKeyPath,verifyKeyPath });
|
|
1664
|
+
runtimes:{ machineFsRuntime,observationRuntime,processRuntime },assertRunAuthority,signingKeyPath,verifyKeyPath,childDeadline });
|
|
1654
1665
|
} else if (decision.action === 'run_profile') {
|
|
1655
1666
|
await assertRunAuthority(goal.root_id);
|
|
1656
1667
|
outcome = await executeProfileWithLease({workerScheduler,ctx,events,goal,
|
|
1657
1668
|
actionKey:`planner-${decisionEvent.event_sha256}`,profileId:decision.profile_id,
|
|
1658
|
-
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath});
|
|
1669
|
+
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath,childDeadline});
|
|
1659
1670
|
} else if (decision.action === 'pause') {
|
|
1660
1671
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{
|
|
1661
1672
|
reason:decision.reason, planner_summary:decision.summary
|
|
@@ -1817,9 +1828,9 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1817
1828
|
return { autonomous, coding };
|
|
1818
1829
|
}
|
|
1819
1830
|
|
|
1820
|
-
async function submit({ submissionId, rootId, title = '', goal, acceptance = '', taskContract = null, maxIterations = null }) {
|
|
1831
|
+
async function submit({ submissionId, rootId, title = '', goal, acceptance = '', taskContract = null, maxIterations = null, timeoutMs = null }) {
|
|
1821
1832
|
await assertRunAuthority(rootId);
|
|
1822
|
-
const normalized = normalizeGoal(policy,{ submissionId,rootId,title,goal,acceptance,taskContract,maxIterations });
|
|
1833
|
+
const normalized = normalizeGoal(policy,{ submissionId,rootId,title,goal,acceptance,taskContract,maxIterations,timeoutMs });
|
|
1823
1834
|
const goalId = goalIdFor(policy.policy_sha256,submissionId);
|
|
1824
1835
|
const ctx = goalContext(policy,goalId);
|
|
1825
1836
|
if (await exists(ctx.dir)) {
|
|
@@ -1838,7 +1849,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1838
1849
|
await appendEvent(ctx,journal,signingKeyPath,'goal_created',{
|
|
1839
1850
|
submission_id:submissionId, root_id:rootId, title, acceptance:normalized.acceptance,
|
|
1840
1851
|
task_contract:normalized.task_contract,goal_sha256:normalized.goal_sha256,
|
|
1841
|
-
max_iterations:normalized.max_iterations,
|
|
1852
|
+
max_iterations:normalized.max_iterations, timeout_ms:normalized.timeout_ms,
|
|
1842
1853
|
...(memoryProvider?{source_release_manifest:memoryProvider.source_release_manifest}:{})
|
|
1843
1854
|
});
|
|
1844
1855
|
return { status:'accepted', goal_id:goalId, goal_sha256:normalized.goal_sha256, state:'pending' };
|
|
@@ -1849,11 +1860,18 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1849
1860
|
const goal = await loadGoal(ctx,policy,verifyKeyPath);
|
|
1850
1861
|
const journal = await readEvents(ctx,verifyKeyPath);
|
|
1851
1862
|
const derived = deriveState(goal,journal);
|
|
1863
|
+
const goalCreated = journal.find(event => event.type === 'goal_created');
|
|
1864
|
+
const goalCreatedAtMs = goalCreated ? Date.parse(goalCreated.created_at_utc) : NaN;
|
|
1865
|
+
if (!Number.isFinite(goalCreatedAtMs)) throw new Error('autonomous goal creation timestamp invalid');
|
|
1866
|
+
const deadline = createDeadline({ timeoutMs:goal.timeout_ms, nowMs:goalCreatedAtMs, id:goalId });
|
|
1852
1867
|
const loop = publicLoopState(loopStateOrNull(goal,journal),goal,journal);
|
|
1853
1868
|
const lock=await runLockStatus(ctx);
|
|
1869
|
+
const stream=createJournalStream({streamId:goalId,events:journal,maxItems:10000,maxBytes:16*1024*1024,producer:'autonomous-goal',channel:'event'});
|
|
1870
|
+
const snapshot=stream.snapshot();
|
|
1854
1871
|
return { status:'ok', goal_id:goalId, goal_sha256:goal.goal_sha256,
|
|
1855
|
-
title:goal.title, root_id:goal.root_id, journal_verified:true, ...derived, ...lock,
|
|
1856
|
-
|
|
1872
|
+
title:goal.title, root_id:goal.root_id, timeout_ms:goal.timeout_ms, deadline, journal_verified:true, ...derived, ...lock,
|
|
1873
|
+
stream_id:snapshot.stream_id, stream_generation:snapshot.generation, stream_next_seq:snapshot.next_seq,
|
|
1874
|
+
stream_coverage:stream.coverage(), ...(loop ? {loop} : {}) };
|
|
1857
1875
|
}
|
|
1858
1876
|
|
|
1859
1877
|
async function events({ goalId, fromSeq = 1, limit = 100 }) {
|
|
@@ -1861,9 +1879,13 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1861
1879
|
if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new Error('autonomous event limit must be in [1,200]');
|
|
1862
1880
|
const ctx = goalContext(policy,goalId); await loadGoal(ctx,policy,verifyKeyPath);
|
|
1863
1881
|
const journal = await readEvents(ctx,verifyKeyPath);
|
|
1882
|
+
const stream=createJournalStream({streamId:goalId,events:journal,maxItems:10000,maxBytes:16*1024*1024,producer:'autonomous-goal',channel:'event'});
|
|
1883
|
+
const page=stream.read(fromSeq,limit);
|
|
1884
|
+
const snapshot=stream.snapshot();
|
|
1864
1885
|
return { status:'ok', goal_id:goalId, journal_verified:true,
|
|
1865
1886
|
journal_head_sha256:journal.at(-1)?.event_sha256 ?? ZERO_HASH,
|
|
1866
|
-
|
|
1887
|
+
stream_id:snapshot.stream_id, stream_generation:snapshot.generation, stream_next_seq:snapshot.next_seq,
|
|
1888
|
+
stream_coverage:stream.coverage(), events:page.items.map(item=>item.value) };
|
|
1867
1889
|
}
|
|
1868
1890
|
async function cancel({ goalId, reason = 'operator_request' }) {
|
|
1869
1891
|
if (typeof reason !== 'string' || reason.length < 1 || reason.length > 256) throw new Error('autonomous cancel reason invalid');
|
|
@@ -1896,6 +1918,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1896
1918
|
const current = deriveState(goal,journal);
|
|
1897
1919
|
if (terminalState(current)) return withLoopResult(goal,journal,{ status:'terminal', goal_id:goalId, state:current.state });
|
|
1898
1920
|
if (!pauseState(current)) throw new Error('autonomous goal is not paused');
|
|
1921
|
+
if (current.reason === 'deadline_exceeded') throw new Error('autonomous goal deadline expired');
|
|
1899
1922
|
if (decision === 'reject') {
|
|
1900
1923
|
await appendEvent(ctx,journal,signingKeyPath,'goal_cancelled',{ reason:'resume_rejected' });
|
|
1901
1924
|
return withLoopResult(goal,journal,{ status:'rejected', goal_id:goalId, state:'cancelled' });
|
|
@@ -2026,9 +2049,26 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
2026
2049
|
if (await consumeCancel(ctx,journal,signingKeyPath,verifyKeyPath)) {
|
|
2027
2050
|
state = deriveState(goal,journal); return withLoopResult(goal,journal,{ status:'cancelled', goal_id:goalId, ...state });
|
|
2028
2051
|
}
|
|
2029
|
-
|
|
2052
|
+
const goalCreated = journal.find(event => event.type === 'goal_created');
|
|
2053
|
+
const goalCreatedAtMs = goalCreated ? Date.parse(goalCreated.created_at_utc) : NaN;
|
|
2054
|
+
if (!Number.isFinite(goalCreatedAtMs)) throw new Error('autonomous goal creation timestamp invalid');
|
|
2055
|
+
const deadline = createDeadline({ timeoutMs:goal.timeout_ms, nowMs:goalCreatedAtMs, id:goalId });
|
|
2056
|
+
const deadlineExpired = () => goal.timeout_ms !== null && deadlineState(deadline).expired;
|
|
2057
|
+
const stopAtDeadline = async () => {
|
|
2058
|
+
if (!deadlineExpired()) return false;
|
|
2059
|
+
const existing = deriveState(goal,journal);
|
|
2060
|
+
if (!(existing.state === 'paused' && existing.reason === 'deadline_exceeded')) {
|
|
2061
|
+
await appendEvent(ctx,journal,signingKeyPath,'goal_paused',{ reason:'deadline_exceeded', deadline });
|
|
2062
|
+
}
|
|
2063
|
+
return true;
|
|
2064
|
+
};
|
|
2065
|
+
await appendEvent(ctx,journal,signingKeyPath,'goal_run_started',{ max_cycles:maxCycles, deadline });
|
|
2030
2066
|
let cycles = 0; let suppliedResponse = plannerResponse;
|
|
2031
2067
|
while (cycles < maxCycles) {
|
|
2068
|
+
if (await stopAtDeadline()) {
|
|
2069
|
+
state = deriveState(goal,journal);
|
|
2070
|
+
return withLoopResult(goal,journal,{ status:'paused', reason:'deadline_exceeded', goal_id:goalId, deadline, ...state });
|
|
2071
|
+
}
|
|
2032
2072
|
state = deriveState(goal,journal);
|
|
2033
2073
|
if (terminalState(state) || pauseState(state)) return withLoopResult(goal,journal,{ status:state.state, goal_id:goalId, ...state });
|
|
2034
2074
|
if (await consumeCancel(ctx,journal,signingKeyPath,verifyKeyPath)) {
|
|
@@ -2039,14 +2079,23 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
2039
2079
|
try {
|
|
2040
2080
|
outcome = await executeDecision({ ctx,events:journal,goal,state,
|
|
2041
2081
|
decisionEvent:state.pending_decision,policy,codingRuntime,nativeDiffRuntime,machineFsRuntime,
|
|
2042
|
-
observationRuntime,processRuntime,semanticRuntime,desktopRuntime,assertRunAuthority,signingKeyPath,verifyKeyPath,workerScheduler });
|
|
2082
|
+
observationRuntime,processRuntime,semanticRuntime,desktopRuntime,assertRunAuthority,signingKeyPath,verifyKeyPath,workerScheduler,childDeadline:deadline });
|
|
2043
2083
|
} catch (error) {
|
|
2084
|
+
if (deadlineExpired() || error?.message === 'deadline_exceeded') {
|
|
2085
|
+
await stopAtDeadline();
|
|
2086
|
+
state = deriveState(goal,journal);
|
|
2087
|
+
return withLoopResult(goal,journal,{ status:'paused', reason:'deadline_exceeded', goal_id:goalId, deadline, ...state });
|
|
2088
|
+
}
|
|
2044
2089
|
const loop=loopStateOrNull(goal,journal);
|
|
2045
2090
|
if (!loop || loop.pending_action || !isAuthorityUnavailable(error)) throw error;
|
|
2046
2091
|
outcome=await r34EnterWaiting({ctx,events:journal,goal,signingKeyPath,
|
|
2047
2092
|
reason:'authority_unavailable',resumePhase:loop.phase});
|
|
2048
2093
|
}
|
|
2049
2094
|
cycles += 1; state = deriveState(goal,journal);
|
|
2095
|
+
if (await stopAtDeadline()) {
|
|
2096
|
+
state = deriveState(goal,journal);
|
|
2097
|
+
return withLoopResult(goal,journal,{ status:'paused', reason:'deadline_exceeded', goal_id:goalId, deadline, ...state });
|
|
2098
|
+
}
|
|
2050
2099
|
if (outcome.status === 'paused' || pauseState(state)) return withLoopResult(goal,journal,{ status:'paused', goal_id:goalId, ...state });
|
|
2051
2100
|
if (outcome.status === 'finish_requested') {
|
|
2052
2101
|
const gate = await releaseGateLocked(ctx,goal,journal);
|
|
@@ -2063,6 +2112,10 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
2063
2112
|
}
|
|
2064
2113
|
continue;
|
|
2065
2114
|
}
|
|
2115
|
+
if (await stopAtDeadline()) {
|
|
2116
|
+
state = deriveState(goal,journal);
|
|
2117
|
+
return withLoopResult(goal,journal,{ status:'paused', reason:'deadline_exceeded', goal_id:goalId, deadline, ...state });
|
|
2118
|
+
}
|
|
2066
2119
|
const accepted = await acceptPlannerDecision({ ctx,events:journal,goal,state,policy,codingRuntime,capabilityManifest,
|
|
2067
2120
|
desktopMemoryProvider,memoryProvider,signingKeyPath,plannerResponse:suppliedResponse,plannerProviderRuntime });
|
|
2068
2121
|
suppliedResponse = null;
|
|
@@ -2079,7 +2132,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
2079
2132
|
if (pauseState(state)) return withLoopResult(goal,journal,{ status:'paused', goal_id:goalId, ...state });
|
|
2080
2133
|
}
|
|
2081
2134
|
state = deriveState(goal,journal);
|
|
2082
|
-
return withLoopResult(goal,journal,{ status:'yielded', goal_id:goalId, cycles, ...state });
|
|
2135
|
+
return withLoopResult(goal,journal,{ status:'yielded', goal_id:goalId, cycles, deadline, ...state });
|
|
2083
2136
|
} finally { await releaseLock(ctx); }
|
|
2084
2137
|
}
|
|
2085
2138
|
|