open-multi-agent-kit 0.98.4 → 0.98.5
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/CHANGELOG.md +12 -0
- package/README.md +3 -2
- package/dist/commands/run-command.d.ts +2 -1
- package/dist/commands/run-command.d.ts.map +1 -1
- package/dist/commands/run-command.js +9 -1
- package/dist/commands/run-command.js.map +1 -1
- package/dist/commands/verified-run-cli.d.ts +6 -0
- package/dist/commands/verified-run-cli.d.ts.map +1 -0
- package/dist/commands/verified-run-cli.js +190 -0
- package/dist/commands/verified-run-cli.js.map +1 -0
- package/dist/core/agent-session-services.d.ts +8 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +41 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -8
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +61 -41
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/prompt-settlement.d.ts +4 -3
- package/dist/core/prompt-settlement.d.ts.map +1 -1
- package/dist/core/prompt-settlement.js.map +1 -1
- package/dist/core/run-budget-policy.d.ts +18 -0
- package/dist/core/run-budget-policy.d.ts.map +1 -0
- package/dist/core/run-budget-policy.js +52 -0
- package/dist/core/run-budget-policy.js.map +1 -0
- package/dist/core/run-budget.d.ts +33 -0
- package/dist/core/run-budget.d.ts.map +1 -0
- package/dist/core/run-budget.js +89 -0
- package/dist/core/run-budget.js.map +1 -0
- package/dist/core/run-execution-api.d.ts +15 -0
- package/dist/core/run-execution-api.d.ts.map +1 -0
- package/dist/core/run-execution-api.js +7 -0
- package/dist/core/run-execution-api.js.map +1 -0
- package/dist/core/run-journal.d.ts.map +1 -1
- package/dist/core/run-journal.js +30 -208
- package/dist/core/run-journal.js.map +1 -1
- package/dist/core/session-bash-service.d.ts +2 -2
- package/dist/core/session-bash-service.d.ts.map +1 -1
- package/dist/core/session-bash-service.js +21 -9
- package/dist/core/session-bash-service.js.map +1 -1
- package/dist/core/session-failure-cause.d.ts.map +1 -1
- package/dist/core/session-failure-cause.js +5 -0
- package/dist/core/session-failure-cause.js.map +1 -1
- package/dist/core/session-prompt-lifecycle.d.ts +25 -0
- package/dist/core/session-prompt-lifecycle.d.ts.map +1 -0
- package/dist/core/session-prompt-lifecycle.js +87 -0
- package/dist/core/session-prompt-lifecycle.js.map +1 -0
- package/dist/core/session-run-budget.d.ts +28 -0
- package/dist/core/session-run-budget.d.ts.map +1 -0
- package/dist/core/session-run-budget.js +127 -0
- package/dist/core/session-run-budget.js.map +1 -0
- package/dist/core/session-run-termination.d.ts.map +1 -1
- package/dist/core/session-run-termination.js +14 -3
- package/dist/core/session-run-termination.js.map +1 -1
- package/dist/core/session-termination-types.d.ts +97 -0
- package/dist/core/session-termination-types.d.ts.map +1 -0
- package/dist/core/session-termination-types.js +26 -0
- package/dist/core/session-termination-types.js.map +1 -0
- package/dist/core/session-termination.d.ts +3 -97
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +24 -28
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/subagent-lane-launcher.d.ts +3 -2
- package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
- package/dist/core/subagent-lane-launcher.js +24 -13
- package/dist/core/subagent-lane-launcher.js.map +1 -1
- package/dist/core/verified-run/broker.d.ts +26 -0
- package/dist/core/verified-run/broker.d.ts.map +1 -0
- package/dist/core/verified-run/broker.js +210 -0
- package/dist/core/verified-run/broker.js.map +1 -0
- package/dist/core/verified-run/candidate.d.ts +24 -0
- package/dist/core/verified-run/candidate.d.ts.map +1 -0
- package/dist/core/verified-run/candidate.js +167 -0
- package/dist/core/verified-run/candidate.js.map +1 -0
- package/dist/core/verified-run/check-receipt.d.ts +18 -0
- package/dist/core/verified-run/check-receipt.d.ts.map +1 -0
- package/dist/core/verified-run/check-receipt.js +92 -0
- package/dist/core/verified-run/check-receipt.js.map +1 -0
- package/dist/core/verified-run/coordinator.d.ts +39 -0
- package/dist/core/verified-run/coordinator.d.ts.map +1 -0
- package/dist/core/verified-run/coordinator.js +190 -0
- package/dist/core/verified-run/coordinator.js.map +1 -0
- package/dist/core/verified-run/dag-candidates.d.ts +8 -0
- package/dist/core/verified-run/dag-candidates.d.ts.map +1 -0
- package/dist/core/verified-run/dag-candidates.js +65 -0
- package/dist/core/verified-run/dag-candidates.js.map +1 -0
- package/dist/core/verified-run/dag-phase.d.ts +7 -0
- package/dist/core/verified-run/dag-phase.d.ts.map +1 -0
- package/dist/core/verified-run/dag-phase.js +92 -0
- package/dist/core/verified-run/dag-phase.js.map +1 -0
- package/dist/core/verified-run/dag-projection.d.ts +7 -0
- package/dist/core/verified-run/dag-projection.d.ts.map +1 -0
- package/dist/core/verified-run/dag-projection.js +90 -0
- package/dist/core/verified-run/dag-projection.js.map +1 -0
- package/dist/core/verified-run/dag-recovery.d.ts +13 -0
- package/dist/core/verified-run/dag-recovery.d.ts.map +1 -0
- package/dist/core/verified-run/dag-recovery.js +98 -0
- package/dist/core/verified-run/dag-recovery.js.map +1 -0
- package/dist/core/verified-run/dag-retry-projection.d.ts +9 -0
- package/dist/core/verified-run/dag-retry-projection.d.ts.map +1 -0
- package/dist/core/verified-run/dag-retry-projection.js +43 -0
- package/dist/core/verified-run/dag-retry-projection.js.map +1 -0
- package/dist/core/verified-run/dag-types.d.ts +47 -0
- package/dist/core/verified-run/dag-types.d.ts.map +1 -0
- package/dist/core/verified-run/dag-types.js +2 -0
- package/dist/core/verified-run/dag-types.js.map +1 -0
- package/dist/core/verified-run/event-parser.d.ts +3 -0
- package/dist/core/verified-run/event-parser.d.ts.map +1 -0
- package/dist/core/verified-run/event-parser.js +153 -0
- package/dist/core/verified-run/event-parser.js.map +1 -0
- package/dist/core/verified-run/events.d.ts +4 -0
- package/dist/core/verified-run/events.d.ts.map +1 -0
- package/dist/core/verified-run/events.js +3 -0
- package/dist/core/verified-run/events.js.map +1 -0
- package/dist/core/verified-run/evidence-binding.d.ts +18 -0
- package/dist/core/verified-run/evidence-binding.d.ts.map +1 -0
- package/dist/core/verified-run/evidence-binding.js +81 -0
- package/dist/core/verified-run/evidence-binding.js.map +1 -0
- package/dist/core/verified-run/evidence.d.ts +27 -0
- package/dist/core/verified-run/evidence.d.ts.map +1 -0
- package/dist/core/verified-run/evidence.js +100 -0
- package/dist/core/verified-run/evidence.js.map +1 -0
- package/dist/core/verified-run/journal.d.ts +32 -0
- package/dist/core/verified-run/journal.d.ts.map +1 -0
- package/dist/core/verified-run/journal.js +103 -0
- package/dist/core/verified-run/journal.js.map +1 -0
- package/dist/core/verified-run/namespace-identity.d.ts +11 -0
- package/dist/core/verified-run/namespace-identity.d.ts.map +1 -0
- package/dist/core/verified-run/namespace-identity.js +77 -0
- package/dist/core/verified-run/namespace-identity.js.map +1 -0
- package/dist/core/verified-run/owned-execution.d.ts +21 -0
- package/dist/core/verified-run/owned-execution.d.ts.map +1 -0
- package/dist/core/verified-run/owned-execution.js +43 -0
- package/dist/core/verified-run/owned-execution.js.map +1 -0
- package/dist/core/verified-run/phase-context.d.ts +9 -0
- package/dist/core/verified-run/phase-context.d.ts.map +1 -0
- package/dist/core/verified-run/phase-context.js +2 -0
- package/dist/core/verified-run/phase-context.js.map +1 -0
- package/dist/core/verified-run/process-gate.d.ts +5 -0
- package/dist/core/verified-run/process-gate.d.ts.map +1 -0
- package/dist/core/verified-run/process-gate.js +31 -0
- package/dist/core/verified-run/process-gate.js.map +1 -0
- package/dist/core/verified-run/projection.d.ts +4 -0
- package/dist/core/verified-run/projection.d.ts.map +1 -0
- package/dist/core/verified-run/projection.js +219 -0
- package/dist/core/verified-run/projection.js.map +1 -0
- package/dist/core/verified-run/recovery-clock.d.ts +19 -0
- package/dist/core/verified-run/recovery-clock.d.ts.map +1 -0
- package/dist/core/verified-run/recovery-clock.js +69 -0
- package/dist/core/verified-run/recovery-clock.js.map +1 -0
- package/dist/core/verified-run/recovery-command.d.ts +11 -0
- package/dist/core/verified-run/recovery-command.d.ts.map +1 -0
- package/dist/core/verified-run/recovery-command.js +73 -0
- package/dist/core/verified-run/recovery-command.js.map +1 -0
- package/dist/core/verified-run/recovery-projection.d.ts +12 -0
- package/dist/core/verified-run/recovery-projection.d.ts.map +1 -0
- package/dist/core/verified-run/recovery-projection.js +88 -0
- package/dist/core/verified-run/recovery-projection.js.map +1 -0
- package/dist/core/verified-run/recovery.d.ts +12 -0
- package/dist/core/verified-run/recovery.d.ts.map +1 -0
- package/dist/core/verified-run/recovery.js +115 -0
- package/dist/core/verified-run/recovery.js.map +1 -0
- package/dist/core/verified-run/run-types.d.ts +103 -0
- package/dist/core/verified-run/run-types.d.ts.map +1 -0
- package/dist/core/verified-run/run-types.js +2 -0
- package/dist/core/verified-run/run-types.js.map +1 -0
- package/dist/core/verified-run/scripted-writer.d.ts +15 -0
- package/dist/core/verified-run/scripted-writer.d.ts.map +1 -0
- package/dist/core/verified-run/scripted-writer.js +94 -0
- package/dist/core/verified-run/scripted-writer.js.map +1 -0
- package/dist/core/verified-run/session-port.d.ts +27 -0
- package/dist/core/verified-run/session-port.d.ts.map +1 -0
- package/dist/core/verified-run/session-port.js +2 -0
- package/dist/core/verified-run/session-port.js.map +1 -0
- package/dist/core/verified-run/storage.d.ts +15 -0
- package/dist/core/verified-run/storage.d.ts.map +1 -0
- package/dist/core/verified-run/storage.js +96 -0
- package/dist/core/verified-run/storage.js.map +1 -0
- package/dist/core/verified-run/verification-phase.d.ts +5 -0
- package/dist/core/verified-run/verification-phase.d.ts.map +1 -0
- package/dist/core/verified-run/verification-phase.js +56 -0
- package/dist/core/verified-run/verification-phase.js.map +1 -0
- package/dist/core/verified-run/work-recovery.d.ts +8 -0
- package/dist/core/verified-run/work-recovery.d.ts.map +1 -0
- package/dist/core/verified-run/work-recovery.js +44 -0
- package/dist/core/verified-run/work-recovery.js.map +1 -0
- package/dist/core/verified-run/writer-completion.d.ts +4 -0
- package/dist/core/verified-run/writer-completion.d.ts.map +1 -0
- package/dist/core/verified-run/writer-completion.js +27 -0
- package/dist/core/verified-run/writer-completion.js.map +1 -0
- package/dist/core/verified-run/writer-phase.d.ts +8 -0
- package/dist/core/verified-run/writer-phase.d.ts.map +1 -0
- package/dist/core/verified-run/writer-phase.js +76 -0
- package/dist/core/verified-run/writer-phase.js.map +1 -0
- package/dist/core/verified-run/writer-projection.d.ts +11 -0
- package/dist/core/verified-run/writer-projection.d.ts.map +1 -0
- package/dist/core/verified-run/writer-projection.js +70 -0
- package/dist/core/verified-run/writer-projection.js.map +1 -0
- package/dist/core/verified-run/writer-recovery.d.ts +16 -0
- package/dist/core/verified-run/writer-recovery.d.ts.map +1 -0
- package/dist/core/verified-run/writer-recovery.js +107 -0
- package/dist/core/verified-run/writer-recovery.js.map +1 -0
- package/dist/core/workload-permit-pool.d.ts +1 -3
- package/dist/core/workload-permit-pool.d.ts.map +1 -1
- package/dist/core/workload-permit-pool.js +11 -11
- package/dist/core/workload-permit-pool.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -8
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/session-failure.d.ts +13 -0
- package/dist/modes/interactive/components/session-failure.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-failure.js +81 -0
- package/dist/modes/interactive/components/session-failure.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +45 -31
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tui-diagnostics.d.ts +36 -0
- package/dist/modes/interactive/tui-diagnostics.d.ts.map +1 -0
- package/dist/modes/interactive/tui-diagnostics.js +105 -0
- package/dist/modes/interactive/tui-diagnostics.js.map +1 -0
- package/dist/modes/interactive/tui-runtime-info.d.ts +20 -0
- package/dist/modes/interactive/tui-runtime-info.d.ts.map +1 -0
- package/dist/modes/interactive/tui-runtime-info.js +76 -0
- package/dist/modes/interactive/tui-runtime-info.js.map +1 -0
- package/docs/development.md +10 -0
- package/docs/keybindings.md +1 -1
- package/docs/release-audit-0.98.5.md +84 -0
- package/docs/run-protocol.md +33 -1
- package/docs/runtime-algorithms.md +26 -0
- package/docs/sdk.md +193 -0
- package/docs/usage.md +54 -0
- package/docs/verified-run-testing.md +417 -0
- package/docs/verified-run.md +388 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +6 -6
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { performance } from "node:perf_hooks";
|
|
3
|
+
import { Agent } from "omk-agent-core";
|
|
4
|
+
import { fauxAssistantMessage, fauxToolCall, registerFauxProvider, streamSimple } from "omk-ai";
|
|
5
|
+
import { Type } from "typebox";
|
|
6
|
+
import { convertToLlm } from "../messages.js";
|
|
7
|
+
import { RunBudgetExceededError } from "../run-budget-policy.js";
|
|
8
|
+
import { VerifiedRunError } from "./storage.js";
|
|
9
|
+
/** Offline reference adapter. The real AgentSession is trusted host code; every command stays in bwrap. */
|
|
10
|
+
export async function executeScriptedWriter(writer, goal, context) {
|
|
11
|
+
if (context.signal?.aborted)
|
|
12
|
+
throw new VerifiedRunError("cancelled");
|
|
13
|
+
const faux = registerFauxProvider({ provider: `verified-scripted-${randomUUID()}` });
|
|
14
|
+
let session;
|
|
15
|
+
let failure;
|
|
16
|
+
let completedSteps = 0;
|
|
17
|
+
const cancel = () => session?.agent.abort();
|
|
18
|
+
try {
|
|
19
|
+
const model = faux.getModel();
|
|
20
|
+
const schema = Type.Object({ index: Type.Integer({ minimum: 0, maximum: writer.steps.length - 1 }) }, { additionalProperties: false });
|
|
21
|
+
const tool = {
|
|
22
|
+
name: "verified_step",
|
|
23
|
+
label: "Execute approved step",
|
|
24
|
+
description: "Execute one contract-approved step in order.",
|
|
25
|
+
parameters: schema,
|
|
26
|
+
execute: async (_id, args, signal) => {
|
|
27
|
+
try {
|
|
28
|
+
if (failure || args.index !== completedSteps || !writer.steps[args.index])
|
|
29
|
+
throw new VerifiedRunError("writer_step");
|
|
30
|
+
const { result } = await context.executeStep(args.index, signal);
|
|
31
|
+
if (result.failure)
|
|
32
|
+
throw new VerifiedRunError(result.failure);
|
|
33
|
+
completedSteps += 1;
|
|
34
|
+
return { content: [{ type: "text", text: result.stdout.toString("utf8") }], details: {} };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
failure = error;
|
|
38
|
+
cancel();
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
faux.setResponses([
|
|
44
|
+
...writer.steps.map((_step, index) => fauxAssistantMessage(fauxToolCall(tool.name, { index }))),
|
|
45
|
+
fauxAssistantMessage("Contracted steps finished; only the supervisor may verify the candidate."),
|
|
46
|
+
]);
|
|
47
|
+
const agent = new Agent({
|
|
48
|
+
initialState: { model, tools: [] },
|
|
49
|
+
convertToLlm,
|
|
50
|
+
getApiKey: () => "synthetic-local-only",
|
|
51
|
+
streamFn: (selected, input, options) => {
|
|
52
|
+
context.beforeRequest();
|
|
53
|
+
return streamSimple(selected, input, options);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
session = context.runtime.createSession({ agent, tool, workspace: context.workspace });
|
|
57
|
+
context.signal?.addEventListener("abort", cancel, { once: true });
|
|
58
|
+
if (context.signal?.aborted)
|
|
59
|
+
throw new VerifiedRunError("cancelled");
|
|
60
|
+
const remaining = Math.floor(context.deadline - performance.now());
|
|
61
|
+
if (remaining <= 0)
|
|
62
|
+
throw new VerifiedRunError("deadline");
|
|
63
|
+
await session.prompt(goal, {
|
|
64
|
+
expandPromptTemplates: false,
|
|
65
|
+
runBudget: { timeoutMs: remaining, maxRequests: context.requestLimit, maxConcurrentRequests: 1 },
|
|
66
|
+
});
|
|
67
|
+
if (failure)
|
|
68
|
+
throw failure;
|
|
69
|
+
if (completedSteps !== writer.steps.length ||
|
|
70
|
+
session.lastTermination?.kind !== "completed" ||
|
|
71
|
+
session.getRunBudgetSnapshot()?.activeRequests !== 0)
|
|
72
|
+
throw new VerifiedRunError("writer_incomplete");
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (failure instanceof VerifiedRunError)
|
|
76
|
+
throw failure;
|
|
77
|
+
if (error instanceof RunBudgetExceededError)
|
|
78
|
+
throw new VerifiedRunError(error.code === "requests" ? "model_request_limit" : "deadline");
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
context.signal?.removeEventListener("abort", cancel);
|
|
83
|
+
try {
|
|
84
|
+
if (session) {
|
|
85
|
+
await session.abort();
|
|
86
|
+
session.dispose();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
faux.unregister();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=scripted-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scripted-writer.js","sourceRoot":"","sources":["../../../src/core/verified-run/scripted-writer.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { performance } from \"node:perf_hooks\";\nimport { Agent, type AgentTool } from \"omk-agent-core\";\nimport { fauxAssistantMessage, fauxToolCall, registerFauxProvider, streamSimple } from \"omk-ai\";\nimport type { RunScriptedWriter } from \"omk-protocol\";\nimport { Type } from \"typebox\";\nimport { convertToLlm } from \"../messages.ts\";\nimport { RunBudgetExceededError } from \"../run-budget-policy.ts\";\nimport type { OwnedRunResult } from \"./owned-execution.ts\";\nimport type { VerifiedRunRuntime, VerifiedRunSession } from \"./session-port.ts\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\nexport interface ScriptedWriterContext {\n\treadonly runtime: VerifiedRunRuntime;\n\treadonly workspace: string;\n\treadonly deadline: number;\n\treadonly requestLimit: number;\n\treadonly signal?: AbortSignal;\n\treadonly beforeRequest: () => void;\n\treadonly executeStep: (index: number, signal?: AbortSignal) => Promise<OwnedRunResult>;\n}\n\n/** Offline reference adapter. The real AgentSession is trusted host code; every command stays in bwrap. */\nexport async function executeScriptedWriter(\n\twriter: RunScriptedWriter,\n\tgoal: string,\n\tcontext: ScriptedWriterContext,\n): Promise<void> {\n\tif (context.signal?.aborted) throw new VerifiedRunError(\"cancelled\");\n\tconst faux = registerFauxProvider({ provider: `verified-scripted-${randomUUID()}` });\n\tlet session: VerifiedRunSession | undefined;\n\tlet failure: unknown;\n\tlet completedSteps = 0;\n\tconst cancel = (): void => session?.agent.abort();\n\ttry {\n\t\tconst model = faux.getModel();\n\t\tconst schema = Type.Object(\n\t\t\t{ index: Type.Integer({ minimum: 0, maximum: writer.steps.length - 1 }) },\n\t\t\t{ additionalProperties: false },\n\t\t);\n\t\tconst tool: AgentTool<typeof schema> = {\n\t\t\tname: \"verified_step\",\n\t\t\tlabel: \"Execute approved step\",\n\t\t\tdescription: \"Execute one contract-approved step in order.\",\n\t\t\tparameters: schema,\n\t\t\texecute: async (_id, args, signal) => {\n\t\t\t\ttry {\n\t\t\t\t\tif (failure || args.index !== completedSteps || !writer.steps[args.index])\n\t\t\t\t\t\tthrow new VerifiedRunError(\"writer_step\");\n\t\t\t\t\tconst { result } = await context.executeStep(args.index, signal);\n\t\t\t\t\tif (result.failure) throw new VerifiedRunError(result.failure);\n\t\t\t\t\tcompletedSteps += 1;\n\t\t\t\t\treturn { content: [{ type: \"text\", text: result.stdout.toString(\"utf8\") }], details: {} };\n\t\t\t\t} catch (error) {\n\t\t\t\t\tfailure = error;\n\t\t\t\t\tcancel();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t\tfaux.setResponses([\n\t\t\t...writer.steps.map((_step, index) => fauxAssistantMessage(fauxToolCall(tool.name, { index }))),\n\t\t\tfauxAssistantMessage(\"Contracted steps finished; only the supervisor may verify the candidate.\"),\n\t\t]);\n\t\tconst agent = new Agent({\n\t\t\tinitialState: { model, tools: [] },\n\t\t\tconvertToLlm,\n\t\t\tgetApiKey: () => \"synthetic-local-only\",\n\t\t\tstreamFn: (selected, input, options) => {\n\t\t\t\tcontext.beforeRequest();\n\t\t\t\treturn streamSimple(selected, input, options);\n\t\t\t},\n\t\t});\n\t\tsession = context.runtime.createSession({ agent, tool, workspace: context.workspace });\n\t\tcontext.signal?.addEventListener(\"abort\", cancel, { once: true });\n\t\tif (context.signal?.aborted) throw new VerifiedRunError(\"cancelled\");\n\t\tconst remaining = Math.floor(context.deadline - performance.now());\n\t\tif (remaining <= 0) throw new VerifiedRunError(\"deadline\");\n\t\tawait session.prompt(goal, {\n\t\t\texpandPromptTemplates: false,\n\t\t\trunBudget: { timeoutMs: remaining, maxRequests: context.requestLimit, maxConcurrentRequests: 1 },\n\t\t});\n\t\tif (failure) throw failure;\n\t\tif (\n\t\t\tcompletedSteps !== writer.steps.length ||\n\t\t\tsession.lastTermination?.kind !== \"completed\" ||\n\t\t\tsession.getRunBudgetSnapshot()?.activeRequests !== 0\n\t\t)\n\t\t\tthrow new VerifiedRunError(\"writer_incomplete\");\n\t} catch (error) {\n\t\tif (failure instanceof VerifiedRunError) throw failure;\n\t\tif (error instanceof RunBudgetExceededError)\n\t\t\tthrow new VerifiedRunError(error.code === \"requests\" ? \"model_request_limit\" : \"deadline\");\n\t\tthrow error;\n\t} finally {\n\t\tcontext.signal?.removeEventListener(\"abort\", cancel);\n\t\ttry {\n\t\t\tif (session) {\n\t\t\t\tawait session.abort();\n\t\t\t\tsession.dispose();\n\t\t\t}\n\t\t} finally {\n\t\t\tfaux.unregister();\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Agent, AgentTool } from "omk-agent-core";
|
|
2
|
+
import type { RunBudgetLimits } from "../run-budget-policy.ts";
|
|
3
|
+
/** Host composition port: not accepted from a contract, worker message or RPC payload. */
|
|
4
|
+
export interface VerifiedRunSession {
|
|
5
|
+
readonly agent: Pick<Agent, "abort">;
|
|
6
|
+
readonly lastTermination?: {
|
|
7
|
+
readonly kind: string;
|
|
8
|
+
};
|
|
9
|
+
prompt(goal: string, options: {
|
|
10
|
+
readonly expandPromptTemplates: false;
|
|
11
|
+
readonly runBudget: RunBudgetLimits;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
getRunBudgetSnapshot(): {
|
|
14
|
+
readonly activeRequests: number;
|
|
15
|
+
} | undefined;
|
|
16
|
+
abort(): Promise<void>;
|
|
17
|
+
dispose(): void;
|
|
18
|
+
}
|
|
19
|
+
export interface VerifiedRunSessionInput {
|
|
20
|
+
readonly agent: Agent;
|
|
21
|
+
readonly tool: AgentTool;
|
|
22
|
+
readonly workspace: string;
|
|
23
|
+
}
|
|
24
|
+
export interface VerifiedRunRuntime {
|
|
25
|
+
readonly createSession: (input: VerifiedRunSessionInput) => VerifiedRunSession;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=session-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-port.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/session-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,0FAA0F;AAC1F,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,eAAe,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,MAAM,CACL,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,QAAQ,CAAC,qBAAqB,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;KAAE,GACrF,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,oBAAoB,IAAI;QAAE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACxE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,IAAI,CAAC;CAChB;AACD,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AACD,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,kBAAkB,CAAC;CAC/E","sourcesContent":["import type { Agent, AgentTool } from \"omk-agent-core\";\nimport type { RunBudgetLimits } from \"../run-budget-policy.ts\";\n\n/** Host composition port: not accepted from a contract, worker message or RPC payload. */\nexport interface VerifiedRunSession {\n\treadonly agent: Pick<Agent, \"abort\">;\n\treadonly lastTermination?: { readonly kind: string };\n\tprompt(\n\t\tgoal: string,\n\t\toptions: { readonly expandPromptTemplates: false; readonly runBudget: RunBudgetLimits },\n\t): Promise<void>;\n\tgetRunBudgetSnapshot(): { readonly activeRequests: number } | undefined;\n\tabort(): Promise<void>;\n\tdispose(): void;\n}\nexport interface VerifiedRunSessionInput {\n\treadonly agent: Agent;\n\treadonly tool: AgentTool;\n\treadonly workspace: string;\n}\nexport interface VerifiedRunRuntime {\n\treadonly createSession: (input: VerifiedRunSessionInput) => VerifiedRunSession;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-port.js","sourceRoot":"","sources":["../../../src/core/verified-run/session-port.ts"],"names":[],"mappings":"","sourcesContent":["import type { Agent, AgentTool } from \"omk-agent-core\";\nimport type { RunBudgetLimits } from \"../run-budget-policy.ts\";\n\n/** Host composition port: not accepted from a contract, worker message or RPC payload. */\nexport interface VerifiedRunSession {\n\treadonly agent: Pick<Agent, \"abort\">;\n\treadonly lastTermination?: { readonly kind: string };\n\tprompt(\n\t\tgoal: string,\n\t\toptions: { readonly expandPromptTemplates: false; readonly runBudget: RunBudgetLimits },\n\t): Promise<void>;\n\tgetRunBudgetSnapshot(): { readonly activeRequests: number } | undefined;\n\tabort(): Promise<void>;\n\tdispose(): void;\n}\nexport interface VerifiedRunSessionInput {\n\treadonly agent: Agent;\n\treadonly tool: AgentTool;\n\treadonly workspace: string;\n}\nexport interface VerifiedRunRuntime {\n\treadonly createSession: (input: VerifiedRunSessionInput) => VerifiedRunSession;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class VerifiedRunError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(code: string);
|
|
4
|
+
}
|
|
5
|
+
export declare const digestBytes: (bytes: string | Uint8Array<ArrayBufferLike>) => string;
|
|
6
|
+
export declare const digestObject: (value: unknown) => string;
|
|
7
|
+
export declare function readRegularFile(path: string, maxBytes: number): Buffer;
|
|
8
|
+
export declare function readJson(path: string, maxBytes?: number): unknown;
|
|
9
|
+
export declare function publishBytes(path: string, bytes: Uint8Array): void;
|
|
10
|
+
export declare function publishObject(path: string, value: unknown): string;
|
|
11
|
+
/** Resolve existing parents without creating state. State must never be part of a mounted workspace. */
|
|
12
|
+
export declare function stateRunPath(root: string, id: string): string;
|
|
13
|
+
export declare function assertStateOutsideWorkspace(stateRoot: string, workspace: string): void;
|
|
14
|
+
export declare function assertDirectory(path: string): void;
|
|
15
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/storage.ts"],"names":[],"mappings":"AAMA,qBAAa,gBAAiB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,YAAY,IAAI,EAAE,MAAM,EAIvB;CACD;AAED,eAAO,MAAM,WAAW,yDAA2F,CAAC;AACpH,eAAO,MAAM,YAAY,4BAAgE,CAAC;AAE1F,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAetE;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAU,GAAG,OAAO,CAOlE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAOlE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAIlE;AAED,wGAAwG;AACxG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAwBtF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, realpathSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { writeExclusiveFileDurablySync } from \"../durable-file-io.ts\";\nimport { canonicalJson } from \"../run-journal.ts\";\n\nexport class VerifiedRunError extends Error {\n\treadonly code: string;\n\tconstructor(code: string) {\n\t\tsuper(`verified-run: ${code}`);\n\t\tthis.name = \"VerifiedRunError\";\n\t\tthis.code = code;\n\t}\n}\n\nexport const digestBytes = (bytes: Uint8Array | string): string => createHash(\"sha256\").update(bytes).digest(\"hex\");\nexport const digestObject = (value: unknown): string => digestBytes(canonicalJson(value));\n\nexport function readRegularFile(path: string, maxBytes: number): Buffer {\n\tconst fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (!before.isFile() || before.nlink !== 1n) throw new VerifiedRunError(\"file_type\");\n\t\tif (before.size > BigInt(maxBytes)) throw new VerifiedRunError(\"storage_limit\");\n\t\tconst bytes = readFileSync(fd);\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tif (before.size !== after.size || before.ctimeNs !== after.ctimeNs || BigInt(bytes.length) !== before.size) {\n\t\t\tthrow new VerifiedRunError(\"integrity\");\n\t\t}\n\t\treturn bytes;\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function readJson(path: string, maxBytes = 1048576): unknown {\n\ttry {\n\t\treturn JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(readRegularFile(path, maxBytes)));\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError || error instanceof TypeError) throw new VerifiedRunError(\"integrity\");\n\t\tthrow error;\n\t}\n}\n\nexport function publishBytes(path: string, bytes: Uint8Array): void {\n\ttry {\n\t\twriteExclusiveFileDurablySync(path, bytes);\n\t} catch (error) {\n\t\tif (!(error instanceof Error && \"code\" in error && error.code === \"EEXIST\")) throw error;\n\t\tif (!readRegularFile(path, bytes.length).equals(Buffer.from(bytes))) throw new VerifiedRunError(\"integrity\");\n\t}\n}\n\nexport function publishObject(path: string, value: unknown): string {\n\tconst bytes = Buffer.from(canonicalJson(value));\n\tpublishBytes(path, bytes);\n\treturn digestBytes(bytes);\n}\n\n/** Resolve existing parents without creating state. State must never be part of a mounted workspace. */\nexport function stateRunPath(root: string, id: string): string {\n\tif (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(id)) throw new VerifiedRunError(\"run_id\");\n\treturn join(resolve(root), id);\n}\n\nexport function assertStateOutsideWorkspace(stateRoot: string, workspace: string): void {\n\tlet cursor = resolve(stateRoot);\n\tconst tail: string[] = [];\n\twhile (true) {\n\t\ttry {\n\t\t\tcursor = join(realpathSync(cursor), ...tail);\n\t\t\tbreak;\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n\t\t\ttail.unshift(basename(cursor));\n\t\t\tcursor = dirname(cursor);\n\t\t}\n\t}\n\tconst base = realpathSync(workspace);\n\tconst under = relative(base, cursor);\n\tconst contains = relative(cursor, base);\n\tif (\n\t\tunder === \"\" ||\n\t\t(!under.startsWith(\"../\") && under !== \"..\") ||\n\t\tcontains === \"\" ||\n\t\t(!contains.startsWith(\"../\") && contains !== \"..\")\n\t) {\n\t\tthrow new VerifiedRunError(\"state_scope\");\n\t}\n}\n\nexport function assertDirectory(path: string): void {\n\tif (!lstatSync(path).isDirectory() || realpathSync(path) !== resolve(path)) throw new VerifiedRunError(\"file_type\");\n}\n"]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, realpathSync } from "node:fs";
|
|
3
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
4
|
+
import { writeExclusiveFileDurablySync } from "../durable-file-io.js";
|
|
5
|
+
import { canonicalJson } from "../run-journal.js";
|
|
6
|
+
export class VerifiedRunError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(code) {
|
|
9
|
+
super(`verified-run: ${code}`);
|
|
10
|
+
this.name = "VerifiedRunError";
|
|
11
|
+
this.code = code;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export const digestBytes = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
15
|
+
export const digestObject = (value) => digestBytes(canonicalJson(value));
|
|
16
|
+
export function readRegularFile(path, maxBytes) {
|
|
17
|
+
const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
18
|
+
try {
|
|
19
|
+
const before = fstatSync(fd, { bigint: true });
|
|
20
|
+
if (!before.isFile() || before.nlink !== 1n)
|
|
21
|
+
throw new VerifiedRunError("file_type");
|
|
22
|
+
if (before.size > BigInt(maxBytes))
|
|
23
|
+
throw new VerifiedRunError("storage_limit");
|
|
24
|
+
const bytes = readFileSync(fd);
|
|
25
|
+
const after = fstatSync(fd, { bigint: true });
|
|
26
|
+
if (before.size !== after.size || before.ctimeNs !== after.ctimeNs || BigInt(bytes.length) !== before.size) {
|
|
27
|
+
throw new VerifiedRunError("integrity");
|
|
28
|
+
}
|
|
29
|
+
return bytes;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
closeSync(fd);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function readJson(path, maxBytes = 1048576) {
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(readRegularFile(path, maxBytes)));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error instanceof SyntaxError || error instanceof TypeError)
|
|
41
|
+
throw new VerifiedRunError("integrity");
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function publishBytes(path, bytes) {
|
|
46
|
+
try {
|
|
47
|
+
writeExclusiveFileDurablySync(path, bytes);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (!(error instanceof Error && "code" in error && error.code === "EEXIST"))
|
|
51
|
+
throw error;
|
|
52
|
+
if (!readRegularFile(path, bytes.length).equals(Buffer.from(bytes)))
|
|
53
|
+
throw new VerifiedRunError("integrity");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function publishObject(path, value) {
|
|
57
|
+
const bytes = Buffer.from(canonicalJson(value));
|
|
58
|
+
publishBytes(path, bytes);
|
|
59
|
+
return digestBytes(bytes);
|
|
60
|
+
}
|
|
61
|
+
/** Resolve existing parents without creating state. State must never be part of a mounted workspace. */
|
|
62
|
+
export function stateRunPath(root, id) {
|
|
63
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(id))
|
|
64
|
+
throw new VerifiedRunError("run_id");
|
|
65
|
+
return join(resolve(root), id);
|
|
66
|
+
}
|
|
67
|
+
export function assertStateOutsideWorkspace(stateRoot, workspace) {
|
|
68
|
+
let cursor = resolve(stateRoot);
|
|
69
|
+
const tail = [];
|
|
70
|
+
while (true) {
|
|
71
|
+
try {
|
|
72
|
+
cursor = join(realpathSync(cursor), ...tail);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
|
|
77
|
+
throw error;
|
|
78
|
+
tail.unshift(basename(cursor));
|
|
79
|
+
cursor = dirname(cursor);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const base = realpathSync(workspace);
|
|
83
|
+
const under = relative(base, cursor);
|
|
84
|
+
const contains = relative(cursor, base);
|
|
85
|
+
if (under === "" ||
|
|
86
|
+
(!under.startsWith("../") && under !== "..") ||
|
|
87
|
+
contains === "" ||
|
|
88
|
+
(!contains.startsWith("../") && contains !== "..")) {
|
|
89
|
+
throw new VerifiedRunError("state_scope");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export function assertDirectory(path) {
|
|
93
|
+
if (!lstatSync(path).isDirectory() || realpathSync(path) !== resolve(path))
|
|
94
|
+
throw new VerifiedRunError("file_type");
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/core/verified-run/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, realpathSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { writeExclusiveFileDurablySync } from \"../durable-file-io.ts\";\nimport { canonicalJson } from \"../run-journal.ts\";\n\nexport class VerifiedRunError extends Error {\n\treadonly code: string;\n\tconstructor(code: string) {\n\t\tsuper(`verified-run: ${code}`);\n\t\tthis.name = \"VerifiedRunError\";\n\t\tthis.code = code;\n\t}\n}\n\nexport const digestBytes = (bytes: Uint8Array | string): string => createHash(\"sha256\").update(bytes).digest(\"hex\");\nexport const digestObject = (value: unknown): string => digestBytes(canonicalJson(value));\n\nexport function readRegularFile(path: string, maxBytes: number): Buffer {\n\tconst fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (!before.isFile() || before.nlink !== 1n) throw new VerifiedRunError(\"file_type\");\n\t\tif (before.size > BigInt(maxBytes)) throw new VerifiedRunError(\"storage_limit\");\n\t\tconst bytes = readFileSync(fd);\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tif (before.size !== after.size || before.ctimeNs !== after.ctimeNs || BigInt(bytes.length) !== before.size) {\n\t\t\tthrow new VerifiedRunError(\"integrity\");\n\t\t}\n\t\treturn bytes;\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function readJson(path: string, maxBytes = 1048576): unknown {\n\ttry {\n\t\treturn JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(readRegularFile(path, maxBytes)));\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError || error instanceof TypeError) throw new VerifiedRunError(\"integrity\");\n\t\tthrow error;\n\t}\n}\n\nexport function publishBytes(path: string, bytes: Uint8Array): void {\n\ttry {\n\t\twriteExclusiveFileDurablySync(path, bytes);\n\t} catch (error) {\n\t\tif (!(error instanceof Error && \"code\" in error && error.code === \"EEXIST\")) throw error;\n\t\tif (!readRegularFile(path, bytes.length).equals(Buffer.from(bytes))) throw new VerifiedRunError(\"integrity\");\n\t}\n}\n\nexport function publishObject(path: string, value: unknown): string {\n\tconst bytes = Buffer.from(canonicalJson(value));\n\tpublishBytes(path, bytes);\n\treturn digestBytes(bytes);\n}\n\n/** Resolve existing parents without creating state. State must never be part of a mounted workspace. */\nexport function stateRunPath(root: string, id: string): string {\n\tif (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(id)) throw new VerifiedRunError(\"run_id\");\n\treturn join(resolve(root), id);\n}\n\nexport function assertStateOutsideWorkspace(stateRoot: string, workspace: string): void {\n\tlet cursor = resolve(stateRoot);\n\tconst tail: string[] = [];\n\twhile (true) {\n\t\ttry {\n\t\t\tcursor = join(realpathSync(cursor), ...tail);\n\t\t\tbreak;\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n\t\t\ttail.unshift(basename(cursor));\n\t\t\tcursor = dirname(cursor);\n\t\t}\n\t}\n\tconst base = realpathSync(workspace);\n\tconst under = relative(base, cursor);\n\tconst contains = relative(cursor, base);\n\tif (\n\t\tunder === \"\" ||\n\t\t(!under.startsWith(\"../\") && under !== \"..\") ||\n\t\tcontains === \"\" ||\n\t\t(!contains.startsWith(\"../\") && contains !== \"..\")\n\t) {\n\t\tthrow new VerifiedRunError(\"state_scope\");\n\t}\n}\n\nexport function assertDirectory(path: string): void {\n\tif (!lstatSync(path).isDirectory() || realpathSync(path) !== resolve(path)) throw new VerifiedRunError(\"file_type\");\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RunPhaseContext } from "./phase-context.ts";
|
|
2
|
+
import type { RunProjection } from "./run-types.ts";
|
|
3
|
+
/** Both start and resume use this same verification path; no writer/model code is reachable here. */
|
|
4
|
+
export declare function verifyCandidate(context: RunPhaseContext): Promise<RunProjection>;
|
|
5
|
+
//# sourceMappingURL=verification-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification-phase.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/verification-phase.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD,qGAAqG;AACrG,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC,CAiDtF","sourcesContent":["import { join } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport { commandEnvironmentDigest } from \"./broker.ts\";\nimport { captureCandidate, loadCandidate, materializeCandidate } from \"./candidate.ts\";\nimport { storeCheckReceipt } from \"./check-receipt.ts\";\nimport { type CheckObservation, issueRunEvidence } from \"./evidence.ts\";\nimport { executeRunCommand } from \"./owned-execution.ts\";\nimport type { RunPhaseContext } from \"./phase-context.ts\";\nimport { localVerificationDeadline } from \"./recovery-clock.ts\";\nimport type { RunProjection } from \"./run-types.ts\";\nimport { digestBytes, VerifiedRunError } from \"./storage.ts\";\n\n/** Both start and resume use this same verification path; no writer/model code is reachable here. */\nexport async function verifyCandidate(context: RunPhaseContext): Promise<RunProjection> {\n\tconst { contract, journal, runPath } = context;\n\tconst state = journal.state;\n\tif (!state.candidateDigest || !state.budget || state.verificationDeadlineMs === null || !state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"resume_unavailable\");\n\tconst deadline = localVerificationDeadline(state.budget, state.verificationDeadlineMs);\n\tif (commandEnvironmentDigest(contract, \"gated-v1\") !== state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"environment_changed\");\n\tconst candidate = loadCandidate(runPath, state.candidateDigest, contract.budget);\n\tconst fixed = join(runPath, state.generation === 1 ? \"candidate\" : `candidate-${state.generation}`);\n\tmaterializeCandidate(candidate, fixed);\n\tconst checks: CheckObservation[] = [];\n\tfor (const check of contract.checks) {\n\t\tconst { executionId, result, timeoutMs } = await executeRunCommand(\n\t\t\tjournal,\n\t\t\t{ role: \"verifier\", argv: check.argv, workspace: fixed, deadline, claimId: check.claimId },\n\t\t\t{ ...contract.budget, ...(context.signal ? { signal: context.signal } : {}) },\n\t\t);\n\t\tchecks.push({\n\t\t\tclaimId: check.claimId,\n\t\t\texecutionId,\n\t\t\tstdoutDigest: digestBytes(result.stdout),\n\t\t\tstderrDigest: digestBytes(result.stderr),\n\t\t\texitCode: result.exitCode,\n\t\t\tfailure: result.failure,\n\t\t\treceiptCoreDigest: storeCheckReceipt(runPath, contract, {\n\t\t\t\tcheck,\n\t\t\t\texecutionId,\n\t\t\t\tresult,\n\t\t\t\ttimeoutMs,\n\t\t\t\tmanifest: candidate.manifest,\n\t\t\t}),\n\t\t});\n\t}\n\tif (\n\t\tcaptureCandidate(fixed, contract.budget).digest !== state.candidateDigest ||\n\t\tcommandEnvironmentDigest(contract, \"gated-v1\") !== state.environmentDigest\n\t)\n\t\tthrow new VerifiedRunError(\"integrity\");\n\tif (performance.now() >= deadline) throw new VerifiedRunError(\"deadline\");\n\tconst receipt = issueRunEvidence(runPath, contract, {\n\t\tgeneration: state.generation,\n\t\tcandidateDigest: state.candidateDigest,\n\t\tenvironmentDigest: state.environmentDigest,\n\t\tchecks,\n\t});\n\tif (performance.now() >= deadline || journal.state.generation !== state.generation)\n\t\tthrow new VerifiedRunError(\"deadline\");\n\treturn journal.append({ kind: \"evaluated\", receiptDigest: receipt.digest, verified: receipt.verified });\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { performance } from "node:perf_hooks";
|
|
3
|
+
import { commandEnvironmentDigest } from "./broker.js";
|
|
4
|
+
import { captureCandidate, loadCandidate, materializeCandidate } from "./candidate.js";
|
|
5
|
+
import { storeCheckReceipt } from "./check-receipt.js";
|
|
6
|
+
import { issueRunEvidence } from "./evidence.js";
|
|
7
|
+
import { executeRunCommand } from "./owned-execution.js";
|
|
8
|
+
import { localVerificationDeadline } from "./recovery-clock.js";
|
|
9
|
+
import { digestBytes, VerifiedRunError } from "./storage.js";
|
|
10
|
+
/** Both start and resume use this same verification path; no writer/model code is reachable here. */
|
|
11
|
+
export async function verifyCandidate(context) {
|
|
12
|
+
const { contract, journal, runPath } = context;
|
|
13
|
+
const state = journal.state;
|
|
14
|
+
if (!state.candidateDigest || !state.budget || state.verificationDeadlineMs === null || !state.environmentDigest)
|
|
15
|
+
throw new VerifiedRunError("resume_unavailable");
|
|
16
|
+
const deadline = localVerificationDeadline(state.budget, state.verificationDeadlineMs);
|
|
17
|
+
if (commandEnvironmentDigest(contract, "gated-v1") !== state.environmentDigest)
|
|
18
|
+
throw new VerifiedRunError("environment_changed");
|
|
19
|
+
const candidate = loadCandidate(runPath, state.candidateDigest, contract.budget);
|
|
20
|
+
const fixed = join(runPath, state.generation === 1 ? "candidate" : `candidate-${state.generation}`);
|
|
21
|
+
materializeCandidate(candidate, fixed);
|
|
22
|
+
const checks = [];
|
|
23
|
+
for (const check of contract.checks) {
|
|
24
|
+
const { executionId, result, timeoutMs } = await executeRunCommand(journal, { role: "verifier", argv: check.argv, workspace: fixed, deadline, claimId: check.claimId }, { ...contract.budget, ...(context.signal ? { signal: context.signal } : {}) });
|
|
25
|
+
checks.push({
|
|
26
|
+
claimId: check.claimId,
|
|
27
|
+
executionId,
|
|
28
|
+
stdoutDigest: digestBytes(result.stdout),
|
|
29
|
+
stderrDigest: digestBytes(result.stderr),
|
|
30
|
+
exitCode: result.exitCode,
|
|
31
|
+
failure: result.failure,
|
|
32
|
+
receiptCoreDigest: storeCheckReceipt(runPath, contract, {
|
|
33
|
+
check,
|
|
34
|
+
executionId,
|
|
35
|
+
result,
|
|
36
|
+
timeoutMs,
|
|
37
|
+
manifest: candidate.manifest,
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (captureCandidate(fixed, contract.budget).digest !== state.candidateDigest ||
|
|
42
|
+
commandEnvironmentDigest(contract, "gated-v1") !== state.environmentDigest)
|
|
43
|
+
throw new VerifiedRunError("integrity");
|
|
44
|
+
if (performance.now() >= deadline)
|
|
45
|
+
throw new VerifiedRunError("deadline");
|
|
46
|
+
const receipt = issueRunEvidence(runPath, contract, {
|
|
47
|
+
generation: state.generation,
|
|
48
|
+
candidateDigest: state.candidateDigest,
|
|
49
|
+
environmentDigest: state.environmentDigest,
|
|
50
|
+
checks,
|
|
51
|
+
});
|
|
52
|
+
if (performance.now() >= deadline || journal.state.generation !== state.generation)
|
|
53
|
+
throw new VerifiedRunError("deadline");
|
|
54
|
+
return journal.append({ kind: "evaluated", receiptDigest: receipt.digest, verified: receipt.verified });
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=verification-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification-phase.js","sourceRoot":"","sources":["../../../src/core/verified-run/verification-phase.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport { commandEnvironmentDigest } from \"./broker.ts\";\nimport { captureCandidate, loadCandidate, materializeCandidate } from \"./candidate.ts\";\nimport { storeCheckReceipt } from \"./check-receipt.ts\";\nimport { type CheckObservation, issueRunEvidence } from \"./evidence.ts\";\nimport { executeRunCommand } from \"./owned-execution.ts\";\nimport type { RunPhaseContext } from \"./phase-context.ts\";\nimport { localVerificationDeadline } from \"./recovery-clock.ts\";\nimport type { RunProjection } from \"./run-types.ts\";\nimport { digestBytes, VerifiedRunError } from \"./storage.ts\";\n\n/** Both start and resume use this same verification path; no writer/model code is reachable here. */\nexport async function verifyCandidate(context: RunPhaseContext): Promise<RunProjection> {\n\tconst { contract, journal, runPath } = context;\n\tconst state = journal.state;\n\tif (!state.candidateDigest || !state.budget || state.verificationDeadlineMs === null || !state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"resume_unavailable\");\n\tconst deadline = localVerificationDeadline(state.budget, state.verificationDeadlineMs);\n\tif (commandEnvironmentDigest(contract, \"gated-v1\") !== state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"environment_changed\");\n\tconst candidate = loadCandidate(runPath, state.candidateDigest, contract.budget);\n\tconst fixed = join(runPath, state.generation === 1 ? \"candidate\" : `candidate-${state.generation}`);\n\tmaterializeCandidate(candidate, fixed);\n\tconst checks: CheckObservation[] = [];\n\tfor (const check of contract.checks) {\n\t\tconst { executionId, result, timeoutMs } = await executeRunCommand(\n\t\t\tjournal,\n\t\t\t{ role: \"verifier\", argv: check.argv, workspace: fixed, deadline, claimId: check.claimId },\n\t\t\t{ ...contract.budget, ...(context.signal ? { signal: context.signal } : {}) },\n\t\t);\n\t\tchecks.push({\n\t\t\tclaimId: check.claimId,\n\t\t\texecutionId,\n\t\t\tstdoutDigest: digestBytes(result.stdout),\n\t\t\tstderrDigest: digestBytes(result.stderr),\n\t\t\texitCode: result.exitCode,\n\t\t\tfailure: result.failure,\n\t\t\treceiptCoreDigest: storeCheckReceipt(runPath, contract, {\n\t\t\t\tcheck,\n\t\t\t\texecutionId,\n\t\t\t\tresult,\n\t\t\t\ttimeoutMs,\n\t\t\t\tmanifest: candidate.manifest,\n\t\t\t}),\n\t\t});\n\t}\n\tif (\n\t\tcaptureCandidate(fixed, contract.budget).digest !== state.candidateDigest ||\n\t\tcommandEnvironmentDigest(contract, \"gated-v1\") !== state.environmentDigest\n\t)\n\t\tthrow new VerifiedRunError(\"integrity\");\n\tif (performance.now() >= deadline) throw new VerifiedRunError(\"deadline\");\n\tconst receipt = issueRunEvidence(runPath, contract, {\n\t\tgeneration: state.generation,\n\t\tcandidateDigest: state.candidateDigest,\n\t\tenvironmentDigest: state.environmentDigest,\n\t\tchecks,\n\t});\n\tif (performance.now() >= deadline || journal.state.generation !== state.generation)\n\t\tthrow new VerifiedRunError(\"deadline\");\n\treturn journal.append({ kind: \"evaluated\", receiptDigest: receipt.digest, verified: receipt.verified });\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RunContract } from "omk-protocol";
|
|
2
|
+
import type { JournalSnapshot } from "./journal.ts";
|
|
3
|
+
/** Common immutable-input, original-budget and observed-process boundary for local work recovery. */
|
|
4
|
+
export declare function assertWorkRecoverable(runPath: string, snapshot: JournalSnapshot): {
|
|
5
|
+
readonly contract: RunContract;
|
|
6
|
+
readonly remainingMs: number;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=work-recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-recovery.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/work-recovery.ts"],"names":[],"mappings":"AACA,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAG9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAKpD,qGAAqG;AACrG,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,GACvB;IAAE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAiClE","sourcesContent":["import { join } from \"node:path\";\nimport { MAX_VERIFIED_RUN_GENERATIONS, type RunContract } from \"omk-protocol\";\nimport { commandEnvironmentDigest } from \"./broker.ts\";\nimport { loadCandidate } from \"./candidate.ts\";\nimport type { JournalSnapshot } from \"./journal.ts\";\nimport { probeNamespace } from \"./namespace-identity.ts\";\nimport { readRunClock, remainingRunTime } from \"./recovery-clock.ts\";\nimport { readRegularFile, VerifiedRunError } from \"./storage.ts\";\n\n/** Common immutable-input, original-budget and observed-process boundary for local work recovery. */\nexport function assertWorkRecoverable(\n\trunPath: string,\n\tsnapshot: JournalSnapshot,\n): { readonly contract: RunContract; readonly remainingMs: number } {\n\tconst state = snapshot.state;\n\tconst first = snapshot.records[0]?.event;\n\tif (state.execution === \"failed\" || state.receiptDigest) throw new VerifiedRunError(\"resume_terminal\");\n\tif (first?.kind !== \"created\" || !state.inputDigest || !state.budget || !state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"input_checkpoint_missing\");\n\tif (state.candidateDigest || state.verificationDeadlineMs !== null) throw new VerifiedRunError(\"candidate_present\");\n\tif (state.generation >= MAX_VERIFIED_RUN_GENERATIONS) throw new VerifiedRunError(\"recovery_limit\");\n\tconst clock = readRunClock();\n\tconst remainingMs = remainingRunTime(state.budget, state.budget.workDeadlineMs, clock);\n\tif (clock.nowMs < (state.lastClockMs ?? state.budget.startedMs)) throw new VerifiedRunError(\"clock_rollback\");\n\tif (remainingMs <= 0) throw new VerifiedRunError(\"deadline\");\n\tfor (const id of state.activeExecutionIds) {\n\t\tconst dispatch = snapshot.records.find(\n\t\t\t(record) =>\n\t\t\t\trecord.generation === state.generation &&\n\t\t\t\trecord.event.kind === \"dispatch\" &&\n\t\t\t\trecord.event.executionId === id,\n\t\t)?.event;\n\t\tconst identity = state.processes.find((item) => item.executionId === id)?.identity;\n\t\tif (\n\t\t\tdispatch?.kind !== \"dispatch\" ||\n\t\t\tdispatch.role !== \"writer\" ||\n\t\t\t!identity ||\n\t\t\tprobeNamespace(identity) !== \"gone\"\n\t\t)\n\t\t\tthrow new VerifiedRunError(\"unsettled\");\n\t}\n\tif (readRegularFile(join(runPath, \"issuer.key\"), 32).length !== 32) throw new VerifiedRunError(\"integrity\");\n\tloadCandidate(runPath, state.inputDigest, first.contract.budget);\n\tif (commandEnvironmentDigest(first.contract, \"gated-v1\") !== state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"integrity\");\n\treturn { contract: first.contract, remainingMs };\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { MAX_VERIFIED_RUN_GENERATIONS } from "omk-protocol";
|
|
3
|
+
import { commandEnvironmentDigest } from "./broker.js";
|
|
4
|
+
import { loadCandidate } from "./candidate.js";
|
|
5
|
+
import { probeNamespace } from "./namespace-identity.js";
|
|
6
|
+
import { readRunClock, remainingRunTime } from "./recovery-clock.js";
|
|
7
|
+
import { readRegularFile, VerifiedRunError } from "./storage.js";
|
|
8
|
+
/** Common immutable-input, original-budget and observed-process boundary for local work recovery. */
|
|
9
|
+
export function assertWorkRecoverable(runPath, snapshot) {
|
|
10
|
+
const state = snapshot.state;
|
|
11
|
+
const first = snapshot.records[0]?.event;
|
|
12
|
+
if (state.execution === "failed" || state.receiptDigest)
|
|
13
|
+
throw new VerifiedRunError("resume_terminal");
|
|
14
|
+
if (first?.kind !== "created" || !state.inputDigest || !state.budget || !state.environmentDigest)
|
|
15
|
+
throw new VerifiedRunError("input_checkpoint_missing");
|
|
16
|
+
if (state.candidateDigest || state.verificationDeadlineMs !== null)
|
|
17
|
+
throw new VerifiedRunError("candidate_present");
|
|
18
|
+
if (state.generation >= MAX_VERIFIED_RUN_GENERATIONS)
|
|
19
|
+
throw new VerifiedRunError("recovery_limit");
|
|
20
|
+
const clock = readRunClock();
|
|
21
|
+
const remainingMs = remainingRunTime(state.budget, state.budget.workDeadlineMs, clock);
|
|
22
|
+
if (clock.nowMs < (state.lastClockMs ?? state.budget.startedMs))
|
|
23
|
+
throw new VerifiedRunError("clock_rollback");
|
|
24
|
+
if (remainingMs <= 0)
|
|
25
|
+
throw new VerifiedRunError("deadline");
|
|
26
|
+
for (const id of state.activeExecutionIds) {
|
|
27
|
+
const dispatch = snapshot.records.find((record) => record.generation === state.generation &&
|
|
28
|
+
record.event.kind === "dispatch" &&
|
|
29
|
+
record.event.executionId === id)?.event;
|
|
30
|
+
const identity = state.processes.find((item) => item.executionId === id)?.identity;
|
|
31
|
+
if (dispatch?.kind !== "dispatch" ||
|
|
32
|
+
dispatch.role !== "writer" ||
|
|
33
|
+
!identity ||
|
|
34
|
+
probeNamespace(identity) !== "gone")
|
|
35
|
+
throw new VerifiedRunError("unsettled");
|
|
36
|
+
}
|
|
37
|
+
if (readRegularFile(join(runPath, "issuer.key"), 32).length !== 32)
|
|
38
|
+
throw new VerifiedRunError("integrity");
|
|
39
|
+
loadCandidate(runPath, state.inputDigest, first.contract.budget);
|
|
40
|
+
if (commandEnvironmentDigest(first.contract, "gated-v1") !== state.environmentDigest)
|
|
41
|
+
throw new VerifiedRunError("integrity");
|
|
42
|
+
return { contract: first.contract, remainingMs };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=work-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-recovery.js","sourceRoot":"","sources":["../../../src/core/verified-run/work-recovery.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { MAX_VERIFIED_RUN_GENERATIONS, type RunContract } from \"omk-protocol\";\nimport { commandEnvironmentDigest } from \"./broker.ts\";\nimport { loadCandidate } from \"./candidate.ts\";\nimport type { JournalSnapshot } from \"./journal.ts\";\nimport { probeNamespace } from \"./namespace-identity.ts\";\nimport { readRunClock, remainingRunTime } from \"./recovery-clock.ts\";\nimport { readRegularFile, VerifiedRunError } from \"./storage.ts\";\n\n/** Common immutable-input, original-budget and observed-process boundary for local work recovery. */\nexport function assertWorkRecoverable(\n\trunPath: string,\n\tsnapshot: JournalSnapshot,\n): { readonly contract: RunContract; readonly remainingMs: number } {\n\tconst state = snapshot.state;\n\tconst first = snapshot.records[0]?.event;\n\tif (state.execution === \"failed\" || state.receiptDigest) throw new VerifiedRunError(\"resume_terminal\");\n\tif (first?.kind !== \"created\" || !state.inputDigest || !state.budget || !state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"input_checkpoint_missing\");\n\tif (state.candidateDigest || state.verificationDeadlineMs !== null) throw new VerifiedRunError(\"candidate_present\");\n\tif (state.generation >= MAX_VERIFIED_RUN_GENERATIONS) throw new VerifiedRunError(\"recovery_limit\");\n\tconst clock = readRunClock();\n\tconst remainingMs = remainingRunTime(state.budget, state.budget.workDeadlineMs, clock);\n\tif (clock.nowMs < (state.lastClockMs ?? state.budget.startedMs)) throw new VerifiedRunError(\"clock_rollback\");\n\tif (remainingMs <= 0) throw new VerifiedRunError(\"deadline\");\n\tfor (const id of state.activeExecutionIds) {\n\t\tconst dispatch = snapshot.records.find(\n\t\t\t(record) =>\n\t\t\t\trecord.generation === state.generation &&\n\t\t\t\trecord.event.kind === \"dispatch\" &&\n\t\t\t\trecord.event.executionId === id,\n\t\t)?.event;\n\t\tconst identity = state.processes.find((item) => item.executionId === id)?.identity;\n\t\tif (\n\t\t\tdispatch?.kind !== \"dispatch\" ||\n\t\t\tdispatch.role !== \"writer\" ||\n\t\t\t!identity ||\n\t\t\tprobeNamespace(identity) !== \"gone\"\n\t\t)\n\t\t\tthrow new VerifiedRunError(\"unsettled\");\n\t}\n\tif (readRegularFile(join(runPath, \"issuer.key\"), 32).length !== 32) throw new VerifiedRunError(\"integrity\");\n\tloadCandidate(runPath, state.inputDigest, first.contract.budget);\n\tif (commandEnvironmentDigest(first.contract, \"gated-v1\") !== state.environmentDigest)\n\t\tthrow new VerifiedRunError(\"integrity\");\n\treturn { contract: first.contract, remainingMs };\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RunPhaseContext } from "./phase-context.ts";
|
|
2
|
+
/** Seal output only against the input that was durably pinned before this run's first writer. */
|
|
3
|
+
export declare function publishWriterCandidate(context: RunPhaseContext, workspace: string, workDeadline: number): void;
|
|
4
|
+
//# sourceMappingURL=writer-completion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer-completion.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/writer-completion.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAI1D,iGAAiG;AACjG,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAqB9G","sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport { assertCandidateScope, captureCandidate, loadCandidate, storeCandidate } from \"./candidate.ts\";\nimport type { RunPhaseContext } from \"./phase-context.ts\";\nimport { readRunClock } from \"./recovery-clock.ts\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\n/** Seal output only against the input that was durably pinned before this run's first writer. */\nexport function publishWriterCandidate(context: RunPhaseContext, workspace: string, workDeadline: number): void {\n\tconst { contract, journal, runPath } = context;\n\tconst state = journal.state;\n\tif (!state.inputDigest || !state.budget) throw new VerifiedRunError(\"input_checkpoint_missing\");\n\tconst base = loadCandidate(runPath, state.inputDigest, contract.budget);\n\tconst candidate = captureCandidate(workspace, contract.budget);\n\tassertCandidateScope(base.manifest, candidate.manifest, contract.writablePaths);\n\tstoreCandidate(candidate, runPath);\n\tconst observed = readRunClock();\n\tif (\n\t\tobserved.bootId !== state.budget.bootId ||\n\t\tobserved.nowMs > state.budget.workDeadlineMs ||\n\t\tperformance.now() >= workDeadline\n\t)\n\t\tthrow new VerifiedRunError(\"deadline\");\n\tjournal.append({\n\t\tkind: \"candidate\",\n\t\tdigest: candidate.digest,\n\t\tobservedMs: observed.nowMs,\n\t\tverificationDeadlineMs: Math.min(observed.nowMs + contract.budget.verifyMs, state.budget.verifyCapMs),\n\t});\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { performance } from "node:perf_hooks";
|
|
2
|
+
import { assertCandidateScope, captureCandidate, loadCandidate, storeCandidate } from "./candidate.js";
|
|
3
|
+
import { readRunClock } from "./recovery-clock.js";
|
|
4
|
+
import { VerifiedRunError } from "./storage.js";
|
|
5
|
+
/** Seal output only against the input that was durably pinned before this run's first writer. */
|
|
6
|
+
export function publishWriterCandidate(context, workspace, workDeadline) {
|
|
7
|
+
const { contract, journal, runPath } = context;
|
|
8
|
+
const state = journal.state;
|
|
9
|
+
if (!state.inputDigest || !state.budget)
|
|
10
|
+
throw new VerifiedRunError("input_checkpoint_missing");
|
|
11
|
+
const base = loadCandidate(runPath, state.inputDigest, contract.budget);
|
|
12
|
+
const candidate = captureCandidate(workspace, contract.budget);
|
|
13
|
+
assertCandidateScope(base.manifest, candidate.manifest, contract.writablePaths);
|
|
14
|
+
storeCandidate(candidate, runPath);
|
|
15
|
+
const observed = readRunClock();
|
|
16
|
+
if (observed.bootId !== state.budget.bootId ||
|
|
17
|
+
observed.nowMs > state.budget.workDeadlineMs ||
|
|
18
|
+
performance.now() >= workDeadline)
|
|
19
|
+
throw new VerifiedRunError("deadline");
|
|
20
|
+
journal.append({
|
|
21
|
+
kind: "candidate",
|
|
22
|
+
digest: candidate.digest,
|
|
23
|
+
observedMs: observed.nowMs,
|
|
24
|
+
verificationDeadlineMs: Math.min(observed.nowMs + contract.budget.verifyMs, state.budget.verifyCapMs),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=writer-completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer-completion.js","sourceRoot":"","sources":["../../../src/core/verified-run/writer-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEvG,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,iGAAiG;AACjG,MAAM,UAAU,sBAAsB,CAAC,OAAwB,EAAE,SAAiB,EAAE,YAAoB,EAAQ;IAC/G,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,gBAAgB,CAAC,0BAA0B,CAAC,CAAC;IAChG,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/D,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;IAChF,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,IACC,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC,MAAM;QACvC,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,cAAc;QAC5C,WAAW,CAAC,GAAG,EAAE,IAAI,YAAY;QAEjC,MAAM,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACxC,OAAO,CAAC,MAAM,CAAC;QACd,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,UAAU,EAAE,QAAQ,CAAC,KAAK;QAC1B,sBAAsB,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC;KACrG,CAAC,CAAC;AAAA,CACH","sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport { assertCandidateScope, captureCandidate, loadCandidate, storeCandidate } from \"./candidate.ts\";\nimport type { RunPhaseContext } from \"./phase-context.ts\";\nimport { readRunClock } from \"./recovery-clock.ts\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\n/** Seal output only against the input that was durably pinned before this run's first writer. */\nexport function publishWriterCandidate(context: RunPhaseContext, workspace: string, workDeadline: number): void {\n\tconst { contract, journal, runPath } = context;\n\tconst state = journal.state;\n\tif (!state.inputDigest || !state.budget) throw new VerifiedRunError(\"input_checkpoint_missing\");\n\tconst base = loadCandidate(runPath, state.inputDigest, contract.budget);\n\tconst candidate = captureCandidate(workspace, contract.budget);\n\tassertCandidateScope(base.manifest, candidate.manifest, contract.writablePaths);\n\tstoreCandidate(candidate, runPath);\n\tconst observed = readRunClock();\n\tif (\n\t\tobserved.bootId !== state.budget.bootId ||\n\t\tobserved.nowMs > state.budget.workDeadlineMs ||\n\t\tperformance.now() >= workDeadline\n\t)\n\t\tthrow new VerifiedRunError(\"deadline\");\n\tjournal.append({\n\t\tkind: \"candidate\",\n\t\tdigest: candidate.digest,\n\t\tobservedMs: observed.nowMs,\n\t\tverificationDeadlineMs: Math.min(observed.nowMs + contract.budget.verifyMs, state.budget.verifyCapMs),\n\t});\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RunPhaseContext } from "./phase-context.ts";
|
|
2
|
+
import type { VerifiedRunRuntime } from "./session-port.ts";
|
|
3
|
+
export declare function executeWriter(context: RunPhaseContext, options: {
|
|
4
|
+
readonly workspace: string;
|
|
5
|
+
readonly deadline: number;
|
|
6
|
+
readonly runtime?: VerifiedRunRuntime;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=writer-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer-phase.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/writer-phase.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,wBAAsB,aAAa,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE;IACR,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC;CACtC,GACC,OAAO,CAAC,IAAI,CAAC,CA+Df","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { performance } from \"node:perf_hooks\";\nimport { executeDag } from \"./dag-phase.ts\";\nimport { executeRunCommand, type OwnedRunCommand } from \"./owned-execution.ts\";\nimport type { RunPhaseContext } from \"./phase-context.ts\";\nimport { executeScriptedWriter } from \"./scripted-writer.ts\";\nimport type { VerifiedRunRuntime } from \"./session-port.ts\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\nexport async function executeWriter(\n\tcontext: RunPhaseContext,\n\toptions: {\n\t\treadonly workspace: string;\n\t\treadonly deadline: number;\n\t\treadonly runtime?: VerifiedRunRuntime;\n\t},\n): Promise<void> {\n\tconst { contract, journal } = context;\n\tconst execute = (request: OwnedRunCommand, toolSignal?: AbortSignal) => {\n\t\tconst signals = [context.signal, toolSignal].filter((signal): signal is AbortSignal => signal !== undefined);\n\t\treturn executeRunCommand(journal, request, {\n\t\t\t...contract.budget,\n\t\t\t...(signals.length ? { signal: AbortSignal.any(signals) } : {}),\n\t\t});\n\t};\n\tswitch (contract.profile) {\n\t\tcase \"linux-command-dag-v1\":\n\t\t\treturn executeDag(context, options);\n\t\tcase \"linux-command-v1\": {\n\t\t\tconst writer = await execute({\n\t\t\t\trole: \"writer\",\n\t\t\t\targv: contract.writer,\n\t\t\t\tworkspace: options.workspace,\n\t\t\t\tdeadline: options.deadline,\n\t\t\t\tclaimId: null,\n\t\t\t});\n\t\t\tif (writer.result.failure) throw new VerifiedRunError(writer.result.failure);\n\t\t\treturn;\n\t\t}\n\t\tcase \"linux-scripted-agent-v1\": {\n\t\t\tconst runtime = options.runtime;\n\t\t\tif (!runtime) throw new VerifiedRunError(\"writer_backend_missing\");\n\t\t\tconst writer = contract.writer;\n\t\t\tconst requestLimit = writer.maxRequests - journal.state.modelRequests;\n\t\t\tif (requestLimit <= 0) throw new VerifiedRunError(\"model_request_limit\");\n\t\t\tjournal.append({ kind: \"writer_opened\" });\n\t\t\tlet completed = false;\n\t\t\ttry {\n\t\t\t\tawait executeScriptedWriter(writer, contract.goal, {\n\t\t\t\t\truntime,\n\t\t\t\t\tworkspace: options.workspace,\n\t\t\t\t\tdeadline: options.deadline,\n\t\t\t\t\trequestLimit,\n\t\t\t\t\t...(context.signal ? { signal: context.signal } : {}),\n\t\t\t\t\tbeforeRequest: () => {\n\t\t\t\t\t\tif (performance.now() >= options.deadline) throw new VerifiedRunError(\"deadline\");\n\t\t\t\t\t\tjournal.append({ kind: \"model_request\", requestId: randomUUID() });\n\t\t\t\t\t\tif (performance.now() >= options.deadline) throw new VerifiedRunError(\"deadline\");\n\t\t\t\t\t},\n\t\t\t\t\texecuteStep: (index, signal) => {\n\t\t\t\t\t\tconst argv = writer.steps[index];\n\t\t\t\t\t\tif (!argv) throw new VerifiedRunError(\"writer_step\");\n\t\t\t\t\t\treturn execute(\n\t\t\t\t\t\t\t{ role: \"writer\", argv, workspace: options.workspace, deadline: options.deadline, claimId: null },\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tcompleted = true;\n\t\t\t} finally {\n\t\t\t\tif (journal.state.activeExecutionIds.length === 0) journal.append({ kind: \"writer_closed\", completed });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tdefault: {\n\t\t\tconst exhaustive: never = contract;\n\t\t\tthrow new VerifiedRunError(String(exhaustive));\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { performance } from "node:perf_hooks";
|
|
3
|
+
import { executeDag } from "./dag-phase.js";
|
|
4
|
+
import { executeRunCommand } from "./owned-execution.js";
|
|
5
|
+
import { executeScriptedWriter } from "./scripted-writer.js";
|
|
6
|
+
import { VerifiedRunError } from "./storage.js";
|
|
7
|
+
export async function executeWriter(context, options) {
|
|
8
|
+
const { contract, journal } = context;
|
|
9
|
+
const execute = (request, toolSignal) => {
|
|
10
|
+
const signals = [context.signal, toolSignal].filter((signal) => signal !== undefined);
|
|
11
|
+
return executeRunCommand(journal, request, {
|
|
12
|
+
...contract.budget,
|
|
13
|
+
...(signals.length ? { signal: AbortSignal.any(signals) } : {}),
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
switch (contract.profile) {
|
|
17
|
+
case "linux-command-dag-v1":
|
|
18
|
+
return executeDag(context, options);
|
|
19
|
+
case "linux-command-v1": {
|
|
20
|
+
const writer = await execute({
|
|
21
|
+
role: "writer",
|
|
22
|
+
argv: contract.writer,
|
|
23
|
+
workspace: options.workspace,
|
|
24
|
+
deadline: options.deadline,
|
|
25
|
+
claimId: null,
|
|
26
|
+
});
|
|
27
|
+
if (writer.result.failure)
|
|
28
|
+
throw new VerifiedRunError(writer.result.failure);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
case "linux-scripted-agent-v1": {
|
|
32
|
+
const runtime = options.runtime;
|
|
33
|
+
if (!runtime)
|
|
34
|
+
throw new VerifiedRunError("writer_backend_missing");
|
|
35
|
+
const writer = contract.writer;
|
|
36
|
+
const requestLimit = writer.maxRequests - journal.state.modelRequests;
|
|
37
|
+
if (requestLimit <= 0)
|
|
38
|
+
throw new VerifiedRunError("model_request_limit");
|
|
39
|
+
journal.append({ kind: "writer_opened" });
|
|
40
|
+
let completed = false;
|
|
41
|
+
try {
|
|
42
|
+
await executeScriptedWriter(writer, contract.goal, {
|
|
43
|
+
runtime,
|
|
44
|
+
workspace: options.workspace,
|
|
45
|
+
deadline: options.deadline,
|
|
46
|
+
requestLimit,
|
|
47
|
+
...(context.signal ? { signal: context.signal } : {}),
|
|
48
|
+
beforeRequest: () => {
|
|
49
|
+
if (performance.now() >= options.deadline)
|
|
50
|
+
throw new VerifiedRunError("deadline");
|
|
51
|
+
journal.append({ kind: "model_request", requestId: randomUUID() });
|
|
52
|
+
if (performance.now() >= options.deadline)
|
|
53
|
+
throw new VerifiedRunError("deadline");
|
|
54
|
+
},
|
|
55
|
+
executeStep: (index, signal) => {
|
|
56
|
+
const argv = writer.steps[index];
|
|
57
|
+
if (!argv)
|
|
58
|
+
throw new VerifiedRunError("writer_step");
|
|
59
|
+
return execute({ role: "writer", argv, workspace: options.workspace, deadline: options.deadline, claimId: null }, signal);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
completed = true;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
if (journal.state.activeExecutionIds.length === 0)
|
|
66
|
+
journal.append({ kind: "writer_closed", completed });
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
default: {
|
|
71
|
+
const exhaustive = contract;
|
|
72
|
+
throw new VerifiedRunError(String(exhaustive));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=writer-phase.js.map
|