open-multi-agent-kit 0.79.3 → 0.80.2
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 +38 -0
- package/MATURITY.md +2 -2
- package/README.md +86 -39
- package/ROADMAP.md +20 -17
- package/dist/brand/night-city.theme.json +122 -24
- package/dist/brand/rust-forge.theme.json +1 -1
- package/dist/commands/chat/native-root-loop.d.ts +27 -3
- package/dist/commands/chat/native-root-loop.js +370 -49
- package/dist/commands/dag.js +45 -0
- package/dist/commands/init/content.d.ts +1 -1
- package/dist/commands/init/content.js +3 -3
- package/dist/commands/init.js +3 -3
- package/dist/commands/verify.js +59 -1
- package/dist/contracts/dag.d.ts +9 -1
- package/dist/evidence/graph-ontology-relation-gate.d.ts +10 -0
- package/dist/evidence/graph-ontology-relation-gate.js +46 -0
- package/dist/evidence/headroom-replay-verifier.d.ts +19 -0
- package/dist/evidence/headroom-replay-verifier.js +86 -0
- package/dist/memory/local-graph-memory-store.d.ts +75 -0
- package/dist/memory/local-graph-memory-store.js +570 -0
- package/dist/orchestration/dag.d.ts +22 -1
- package/dist/orchestration/evidence-gate.js +12 -0
- package/dist/orchestration/executor.js +111 -15
- package/dist/orchestration/loop-controller-headroom.d.ts +6 -0
- package/dist/orchestration/loop-controller-headroom.js +33 -0
- package/dist/orchestration/scheduler.d.ts +2 -0
- package/dist/orchestration/scheduler.js +3 -0
- package/dist/orchestration/task-graph.d.ts +17 -0
- package/dist/orchestration/task-graph.js +38 -0
- package/dist/providers/codex-cli-runner.js +17 -2
- package/dist/runtime/agent-runtime.d.ts +32 -3
- package/dist/runtime/agent-runtime.js +20 -7
- package/dist/runtime/authority-matrix.d.ts +23 -0
- package/dist/runtime/authority-matrix.js +171 -0
- package/dist/runtime/chat-advisory-runtime.js +3 -0
- package/dist/runtime/codex-cli-runtime.js +2 -0
- package/dist/runtime/codex-runtime.d.ts +4 -1
- package/dist/runtime/codex-runtime.js +34 -12
- package/dist/runtime/context-broker-converter.js +32 -2
- package/dist/runtime/context-broker.js +18 -0
- package/dist/runtime/contracts/evidence.d.ts +52 -0
- package/dist/runtime/contracts/evidence.js +138 -1
- package/dist/runtime/contracts/shared.d.ts +27 -0
- package/dist/runtime/data-retention-gate.d.ts +42 -0
- package/dist/runtime/data-retention-gate.js +123 -0
- package/dist/runtime/deepseek-runtime.d.ts +5 -1
- package/dist/runtime/deepseek-runtime.js +13 -7
- package/dist/runtime/external-cli-adapter.js +20 -7
- package/dist/runtime/freedomd-evidence-envelope.d.ts +57 -0
- package/dist/runtime/freedomd-evidence-envelope.js +110 -0
- package/dist/runtime/freedomd-exception.d.ts +32 -0
- package/dist/runtime/freedomd-exception.js +95 -0
- package/dist/runtime/freedomd-incidents.d.ts +23 -0
- package/dist/runtime/freedomd-incidents.js +103 -0
- package/dist/runtime/freedomd-policy.d.ts +35 -0
- package/dist/runtime/freedomd-policy.js +114 -0
- package/dist/runtime/freedomd-router.d.ts +66 -0
- package/dist/runtime/freedomd-router.js +433 -0
- package/dist/runtime/headroom-aware-loop-decision.d.ts +21 -0
- package/dist/runtime/headroom-aware-loop-decision.js +67 -0
- package/dist/runtime/headroom-loop-risk.d.ts +19 -0
- package/dist/runtime/headroom-loop-risk.js +43 -0
- package/dist/runtime/headroom-policy.d.ts +14 -1
- package/dist/runtime/headroom-policy.js +74 -12
- package/dist/runtime/kimi-api-runtime.d.ts +4 -1
- package/dist/runtime/kimi-api-runtime.js +35 -11
- package/dist/runtime/kimi-print-runtime.js +21 -0
- package/dist/runtime/kimi-wire-protocol-runtime.js +17 -1
- package/dist/runtime/local-llm-runtime.d.ts +5 -1
- package/dist/runtime/local-llm-runtime.js +14 -23
- package/dist/runtime/private-stderr.d.ts +13 -0
- package/dist/runtime/private-stderr.js +69 -0
- package/dist/runtime/prompt-envelope.d.ts +1 -1
- package/dist/runtime/provider-sovereignty.d.ts +81 -0
- package/dist/runtime/provider-sovereignty.js +285 -0
- package/dist/runtime/runtime-backed-task-runner.d.ts +1 -0
- package/dist/runtime/runtime-backed-task-runner.js +282 -10
- package/dist/runtime/runtime-bootstrap.d.ts +12 -0
- package/dist/runtime/runtime-bootstrap.js +54 -11
- package/dist/runtime/runtime-failure-classifier.d.ts +15 -0
- package/dist/runtime/runtime-failure-classifier.js +107 -0
- package/dist/runtime/runtime-health-probes.d.ts +30 -0
- package/dist/runtime/runtime-health-probes.js +102 -0
- package/dist/runtime/runtime-router.d.ts +6 -2
- package/dist/runtime/runtime-router.js +575 -53
- package/dist/runtime/structured-compaction.d.ts +107 -0
- package/dist/runtime/structured-compaction.js +414 -0
- package/dist/runtime/tool-dispatch-contracts.d.ts +7 -5
- package/dist/runtime/tool-dispatch-contracts.js +15 -4
- package/dist/runtime/tool-plane.d.ts +1 -1
- package/dist/runtime/tool-plane.js +49 -1
- package/dist/runtime/worker-manifest.js +1 -1
- package/dist/schema/evidence-bundle.schema.d.ts +8 -8
- package/dist/schema/proof-bundle.schema.d.ts +2 -2
- package/dist/util/hash.d.ts +2 -0
- package/dist/util/hash.js +13 -0
- package/dist/util/session.js +5 -4
- package/docs/2026-06-16/critical-issues.md +19 -0
- package/docs/2026-06-16/improvements.md +15 -0
- package/docs/2026-06-16/init-checklist.md +25 -0
- package/docs/2026-06-16/plan.md +20 -0
- package/docs/2026-06-17/critical-issues.md +19 -0
- package/docs/2026-06-17/improvements.md +15 -0
- package/docs/2026-06-17/init-checklist.md +25 -0
- package/docs/2026-06-17/plan.md +20 -0
- package/docs/ARCHITECTURE_ANALYSIS_CODEGRAPH.md +2 -1
- package/docs/GSTACK_MIGRATION.md +1 -1
- package/docs/algorithm-hardening-playbook.md +219 -0
- package/docs/claims.md +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/native-root-runtime-hardening.md +42 -32
- package/docs/post-0793-hardening-roadmap.md +123 -0
- package/docs/provider-maturity.md +18 -16
- package/docs/versioning.md +3 -3
- package/docs/what-is-omk.md +1 -1
- package/package.json +8 -4
- package/readmeasset/.npmignore +2 -0
- package/readmeasset/ASSET_INDEX.md +2 -0
- package/readmeasset/ASSET_PROVENANCE.md +40 -20
- package/readmeasset/omk-adaptorch-ouroboros-supermemory.svg +1 -1
- package/readmeasset/omk-control-surfaces.svg +1 -1
- package/readmeasset/omk-core-loop.svg +1 -1
- package/readmeasset/omk-freedomd-control-plane.svg +59 -0
- package/readmeasset/omk-freedomd-control-plane.webp +0 -0
- package/readmeasset/omk-init-control-loop.svg +1 -1
- package/readmeasset/omk-logo-mark.svg +1 -1
- package/readmeasset/omk-parallel-subagents.svg +1 -1
- package/readmeasset/omk-release-assertions.svg +1 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
export const RUNTIME_AUTHORITY_MATRIX = [
|
|
2
|
+
{
|
|
3
|
+
providerId: "kimi",
|
|
4
|
+
runtimeMode: "api",
|
|
5
|
+
authorities: ["read", "review", "vision", "toolCalling"],
|
|
6
|
+
advisory: true,
|
|
7
|
+
notes: "Moonshot/Kimi API is advisory; no direct workspace write/shell/merge authority.",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
providerId: "kimi",
|
|
11
|
+
runtimeMode: "wire",
|
|
12
|
+
authorities: ["read", "review", "write", "patch", "vision", "toolCalling"],
|
|
13
|
+
advisory: false,
|
|
14
|
+
notes: "Kimi wire/CLI compatibility path can edit through the OMK-controlled adapter, but shell/merge still require explicit authority.",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
providerId: "kimi",
|
|
18
|
+
runtimeMode: "cli",
|
|
19
|
+
authorities: ["read", "review", "write", "patch", "vision", "toolCalling"],
|
|
20
|
+
advisory: false,
|
|
21
|
+
notes: "Legacy Kimi CLI compatibility path is available only when explicitly requested; shell/merge remain separately gated.",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
providerId: "mimo",
|
|
25
|
+
runtimeMode: "api",
|
|
26
|
+
authorities: ["read", "review"],
|
|
27
|
+
advisory: true,
|
|
28
|
+
notes: "MiMo API is read/review/thinking only until a write-capable runtime-mode contract exists.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
providerId: "deepseek",
|
|
32
|
+
runtimeMode: "api",
|
|
33
|
+
authorities: ["read", "review"],
|
|
34
|
+
advisory: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
providerId: "glm",
|
|
38
|
+
runtimeMode: "api",
|
|
39
|
+
authorities: ["read", "review"],
|
|
40
|
+
advisory: true,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
providerId: "codex",
|
|
44
|
+
runtimeMode: "cli",
|
|
45
|
+
authorities: ["read", "review", "write", "patch", "shell"],
|
|
46
|
+
advisory: false,
|
|
47
|
+
notes: "Codex CLI authority is bounded by OMK approval/sandbox policy; merge remains withheld.",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
providerId: "opencode",
|
|
51
|
+
runtimeMode: "cli",
|
|
52
|
+
authorities: ["read", "review", "write", "patch", "shell"],
|
|
53
|
+
advisory: false,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
providerId: "commandcode",
|
|
57
|
+
runtimeMode: "cli",
|
|
58
|
+
authorities: ["read", "review", "write", "patch", "shell"],
|
|
59
|
+
advisory: false,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
providerId: "local-llm",
|
|
63
|
+
runtimeMode: "api",
|
|
64
|
+
authorities: ["read", "review"],
|
|
65
|
+
advisory: true,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
providerId: "openrouter",
|
|
69
|
+
runtimeMode: "api",
|
|
70
|
+
authorities: ["read", "review", "vision", "toolCalling"],
|
|
71
|
+
advisory: true,
|
|
72
|
+
notes: "OpenRouter API is advisory unless paired with an OMK-owned write/shell adapter.",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
providerId: "qwen",
|
|
76
|
+
runtimeMode: "api",
|
|
77
|
+
authorities: ["read", "review", "vision", "toolCalling"],
|
|
78
|
+
advisory: true,
|
|
79
|
+
notes: "Qwen API is advisory unless paired with an OMK-owned write/shell adapter.",
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
export function runtimeProviderId(runtime) {
|
|
83
|
+
return runtime.providerId ?? runtime.id.split("-")[0] ?? runtime.id;
|
|
84
|
+
}
|
|
85
|
+
export function runtimeModeOf(runtime) {
|
|
86
|
+
if (runtime.runtimeMode)
|
|
87
|
+
return runtime.runtimeMode;
|
|
88
|
+
if (runtime.kind)
|
|
89
|
+
return runtime.kind;
|
|
90
|
+
const suffix = runtime.id.split("-").slice(1).join("-");
|
|
91
|
+
if (suffix === "api" || suffix === "cli" || suffix === "wire")
|
|
92
|
+
return suffix;
|
|
93
|
+
return "api";
|
|
94
|
+
}
|
|
95
|
+
export function getRuntimeAuthorityEntry(runtime) {
|
|
96
|
+
const providerId = runtimeProviderId(runtime);
|
|
97
|
+
const runtimeMode = runtimeModeOf(runtime);
|
|
98
|
+
return RUNTIME_AUTHORITY_MATRIX.find((entry) => entry.providerId === providerId && entry.runtimeMode === runtimeMode);
|
|
99
|
+
}
|
|
100
|
+
export function authoritiesForRuntime(runtime) {
|
|
101
|
+
const entry = getRuntimeAuthorityEntry(runtime);
|
|
102
|
+
const caps = runtime.capabilities;
|
|
103
|
+
if (entry) {
|
|
104
|
+
const granted = new Set(entry.authorities);
|
|
105
|
+
// Provider/mode entries remain the source of truth for write/shell/merge.
|
|
106
|
+
// Add only explicitly declared auxiliary capabilities so test/fake runtimes
|
|
107
|
+
// and future adapters can expose MCP/tool contracts without broadening
|
|
108
|
+
// destructive authority by provider name alone.
|
|
109
|
+
if (caps?.mcp === true)
|
|
110
|
+
granted.add("mcp");
|
|
111
|
+
if (caps?.vision === true)
|
|
112
|
+
granted.add("vision");
|
|
113
|
+
if (caps?.toolCalling === true || caps?.supportsToolCalling === true)
|
|
114
|
+
granted.add("toolCalling");
|
|
115
|
+
return [...granted];
|
|
116
|
+
}
|
|
117
|
+
if (!caps)
|
|
118
|
+
return ["read"];
|
|
119
|
+
const derived = [];
|
|
120
|
+
for (const op of ["read", "review", "write", "patch", "shell", "mcp", "merge", "vision"]) {
|
|
121
|
+
if (caps[op] === true)
|
|
122
|
+
derived.push(op);
|
|
123
|
+
}
|
|
124
|
+
if (caps.toolCalling === true || caps.supportsToolCalling === true)
|
|
125
|
+
derived.push("toolCalling");
|
|
126
|
+
return derived.length > 0 ? derived : ["read"];
|
|
127
|
+
}
|
|
128
|
+
export function runtimeIsAdvisory(runtime) {
|
|
129
|
+
const entry = getRuntimeAuthorityEntry(runtime);
|
|
130
|
+
if (entry)
|
|
131
|
+
return entry.advisory;
|
|
132
|
+
return runtime.capabilities?.advisory === true;
|
|
133
|
+
}
|
|
134
|
+
export function requiredAuthorityForTask(task) {
|
|
135
|
+
const required = ["read"];
|
|
136
|
+
const caps = task.capabilities;
|
|
137
|
+
if (caps.review)
|
|
138
|
+
required.push("review");
|
|
139
|
+
if (caps.write)
|
|
140
|
+
required.push("write");
|
|
141
|
+
if (caps.patch)
|
|
142
|
+
required.push("patch");
|
|
143
|
+
if (caps.shell)
|
|
144
|
+
required.push("shell");
|
|
145
|
+
if (caps.mcp)
|
|
146
|
+
required.push("mcp");
|
|
147
|
+
if (caps.merge)
|
|
148
|
+
required.push("merge");
|
|
149
|
+
if (caps.vision)
|
|
150
|
+
required.push("vision");
|
|
151
|
+
if (caps.toolCalling)
|
|
152
|
+
required.push("toolCalling");
|
|
153
|
+
return [...new Set(required)];
|
|
154
|
+
}
|
|
155
|
+
export function runtimeSatisfiesAuthority(runtime, task) {
|
|
156
|
+
const granted = new Set(authoritiesForRuntime(runtime));
|
|
157
|
+
const required = requiredAuthorityForTask(task);
|
|
158
|
+
const missing = required.filter((op) => !granted.has(op));
|
|
159
|
+
if (missing.length === 0)
|
|
160
|
+
return { ok: true, missing: [] };
|
|
161
|
+
return {
|
|
162
|
+
ok: false,
|
|
163
|
+
missing,
|
|
164
|
+
reason: `runtime ${runtime.id} (${runtimeProviderId(runtime)}:${runtimeModeOf(runtime)}) lacks required authority: ${missing.join(", ")}`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export function authorityCapableProviderIds(required) {
|
|
168
|
+
return [...new Set(RUNTIME_AUTHORITY_MATRIX
|
|
169
|
+
.filter((entry) => required.every((op) => entry.authorities.includes(op)))
|
|
170
|
+
.map((entry) => entry.providerId))];
|
|
171
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Spawns the `codex` CLI subprocess and bridges AgentTask / AgentResult.
|
|
5
5
|
*/
|
|
6
6
|
import type { AgentRuntime, AgentRunResult, AgentResult, AgentTask, RuntimeCapabilities, RuntimeHealth } from "./agent-runtime.js";
|
|
7
|
+
import type { RuntimeHealthProbeRequest } from "./contracts/shared.js";
|
|
7
8
|
import type { ContextCapsule } from "./context-capsule.js";
|
|
8
9
|
export interface CodexRuntimeOptions {
|
|
9
10
|
bin?: string;
|
|
@@ -16,6 +17,8 @@ export interface CodexRuntimeOptions {
|
|
|
16
17
|
}
|
|
17
18
|
export declare class CodexRuntime implements AgentRuntime {
|
|
18
19
|
readonly id = "codex-cli";
|
|
20
|
+
readonly providerId = "codex";
|
|
21
|
+
readonly runtimeMode = "cli";
|
|
19
22
|
readonly kind = "cli";
|
|
20
23
|
readonly priority = 60;
|
|
21
24
|
readonly capabilities: RuntimeCapabilities;
|
|
@@ -28,7 +31,7 @@ export declare class CodexRuntime implements AgentRuntime {
|
|
|
28
31
|
private readonly safetyMarginTokens;
|
|
29
32
|
constructor(options?: CodexRuntimeOptions);
|
|
30
33
|
supports(capsule: ContextCapsule): boolean;
|
|
31
|
-
health(): Promise<RuntimeHealth>;
|
|
34
|
+
health(input?: RuntimeHealthProbeRequest): Promise<RuntimeHealth>;
|
|
32
35
|
runNode(capsule: ContextCapsule, signal: AbortSignal): Promise<AgentRunResult>;
|
|
33
36
|
execute(task: AgentTask): Promise<AgentResult>;
|
|
34
37
|
private buildPrompt;
|
|
@@ -9,8 +9,11 @@ import { sanitizeUserVisibleOutput } from "../util/user-visible-output.js";
|
|
|
9
9
|
import { buildChildEnv } from "./child-env.js";
|
|
10
10
|
import { contextPreflightErrorMessage, preflightProviderInput, } from "../providers/context-preflight.js";
|
|
11
11
|
import { createRuntimeSandboxProfile } from "./sandbox-profile.js";
|
|
12
|
+
import { staticRuntimeHealth } from "./runtime-health-probes.js";
|
|
12
13
|
export class CodexRuntime {
|
|
13
14
|
id = "codex-cli";
|
|
15
|
+
providerId = "codex";
|
|
16
|
+
runtimeMode = "cli";
|
|
14
17
|
kind = "cli";
|
|
15
18
|
priority = 60;
|
|
16
19
|
capabilities = {
|
|
@@ -68,14 +71,25 @@ export class CodexRuntime {
|
|
|
68
71
|
}
|
|
69
72
|
return true;
|
|
70
73
|
}
|
|
71
|
-
async health() {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
+
async health(input = { probeKind: "static", highRisk: false }) {
|
|
75
|
+
const started = Date.now();
|
|
76
|
+
const runtimeOk = input.probeKind === "static"
|
|
77
|
+
? await checkCommand(this.bin).catch(() => false)
|
|
78
|
+
: (await runShell(this.bin, ["--version"], { cwd: this.cwd, timeout: 5000 }).catch(() => ({ exitCode: 1 }))).exitCode === 0;
|
|
79
|
+
const available = runtimeOk;
|
|
80
|
+
return staticRuntimeHealth({
|
|
74
81
|
runtimeId: this.id,
|
|
75
82
|
available,
|
|
76
|
-
reason: available ? undefined : "codex CLI is not available
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
reason: available ? undefined : "codex CLI is not available or failed --version probe",
|
|
84
|
+
runtimeOk,
|
|
85
|
+
authOk: runtimeOk,
|
|
86
|
+
modelOk: true,
|
|
87
|
+
quotaOk: true,
|
|
88
|
+
rateLimitOk: true,
|
|
89
|
+
latencyMs: input.probeKind === "static" ? undefined : Date.now() - started,
|
|
90
|
+
probeKind: input.probeKind,
|
|
91
|
+
ttlMs: input.probeKind === "static" ? 60_000 : 30_000,
|
|
92
|
+
});
|
|
79
93
|
}
|
|
80
94
|
async runNode(capsule, signal) {
|
|
81
95
|
try {
|
|
@@ -146,12 +160,7 @@ export class CodexRuntime {
|
|
|
146
160
|
...(model ? { OMK_PROVIDER_MODEL: model } : {}),
|
|
147
161
|
},
|
|
148
162
|
});
|
|
149
|
-
const sandboxMode = task
|
|
150
|
-
? task.context.sandboxMode
|
|
151
|
-
:
|
|
152
|
-
task.capabilities.write || task.capabilities.patch || task.capabilities.shell
|
|
153
|
-
? "workspace-write"
|
|
154
|
-
: "read-only";
|
|
163
|
+
const sandboxMode = resolveCodexSandboxMode(task);
|
|
155
164
|
const approvalPolicy = codexApprovalPolicy(task.context.approvalPolicy ?? task.context.env?.OMK_APPROVAL_POLICY, sandboxMode);
|
|
156
165
|
const sandboxProfile = createRuntimeSandboxProfile({
|
|
157
166
|
cwd: this.cwd,
|
|
@@ -254,10 +263,23 @@ export class CodexRuntime {
|
|
|
254
263
|
return parts.join("\n");
|
|
255
264
|
}
|
|
256
265
|
}
|
|
266
|
+
function resolveCodexSandboxMode(task) {
|
|
267
|
+
if (task.context.sandboxMode === "read-only" || task.context.sandboxMode === "workspace-write") {
|
|
268
|
+
return task.context.sandboxMode;
|
|
269
|
+
}
|
|
270
|
+
// Advisory API runtimes must stay read-only even if capabilities request write.
|
|
271
|
+
if (task.context.env?.OMK_PROVIDER_AUTHORITY === "advisory")
|
|
272
|
+
return "read-only";
|
|
273
|
+
if (task.capabilities.write || task.capabilities.patch || task.capabilities.shell) {
|
|
274
|
+
return "workspace-write";
|
|
275
|
+
}
|
|
276
|
+
return "read-only";
|
|
277
|
+
}
|
|
257
278
|
function codexApprovalPolicy(value, sandboxMode) {
|
|
258
279
|
if (sandboxMode !== "read-only")
|
|
259
280
|
return "on-request";
|
|
260
281
|
const normalized = value?.trim().toLowerCase();
|
|
282
|
+
// OMK "ask" must never map to provider "never"; only explicit "never"/"yolo" does.
|
|
261
283
|
if (normalized === "never" || normalized === "yolo")
|
|
262
284
|
return "never";
|
|
263
285
|
return "on-request";
|
|
@@ -57,18 +57,46 @@ export async function capsuleToTask(capsule, options = {}) {
|
|
|
57
57
|
maxLatencyMs: undefined,
|
|
58
58
|
};
|
|
59
59
|
const capabilities = capabilitiesFromNode(capsule);
|
|
60
|
+
const safety = safetyFromCapsule(capsule, capabilities);
|
|
61
|
+
const sovereignty = routing?.freedomd
|
|
62
|
+
? {
|
|
63
|
+
mode: (routing.freedomd.degradedMode ?? routing.freedomd.dataBoundary) ? "freedomd" : "standard",
|
|
64
|
+
dataBoundary: routing.freedomd.dataBoundary ?? "internal",
|
|
65
|
+
retentionDecision: "allow",
|
|
66
|
+
jurisdictionDecision: "allow",
|
|
67
|
+
providerCutoffRisk: 0,
|
|
68
|
+
localFallbackAvailable: false,
|
|
69
|
+
reason: routing.freedomd.sovereigntyReason ?? "from dag routing",
|
|
70
|
+
}
|
|
71
|
+
: undefined;
|
|
60
72
|
const task = {
|
|
61
73
|
prompt: capsule.task,
|
|
62
74
|
context,
|
|
63
75
|
tools,
|
|
64
76
|
providerPolicy,
|
|
65
77
|
capabilities,
|
|
78
|
+
safety,
|
|
79
|
+
sovereignty,
|
|
66
80
|
};
|
|
67
81
|
return task;
|
|
68
82
|
}
|
|
69
83
|
function isAbortSignal(value) {
|
|
70
84
|
return "aborted" in value && typeof value.addEventListener === "function";
|
|
71
85
|
}
|
|
86
|
+
function safetyFromCapsule(capsule, capabilities) {
|
|
87
|
+
const routing = capsule.node.routing;
|
|
88
|
+
const risk = routing?.risk ?? (capabilities.shell || capabilities.merge ? "shell" : capabilities.write || capabilities.patch ? "write" : "read");
|
|
89
|
+
const authorityMode = routing?.assignedProviderAuthority
|
|
90
|
+
?? (routing?.readOnly === true ? "advisory" : "authority");
|
|
91
|
+
return {
|
|
92
|
+
risk,
|
|
93
|
+
riskTrace: routing?.riskTrace,
|
|
94
|
+
approvalPolicy: routing?.approvalPolicy ?? routing?.executionPrompt ?? "interactive",
|
|
95
|
+
sandboxMode: routing?.sandboxMode ?? (routing?.readOnly === true ? "read-only" : "workspace-write"),
|
|
96
|
+
evidenceRequired: routing?.evidenceRequired === true || capabilities.write || capabilities.patch || capabilities.shell || capabilities.merge,
|
|
97
|
+
authorityMode,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
72
100
|
function capabilitiesFromNode(capsule) {
|
|
73
101
|
const node = capsule.node;
|
|
74
102
|
const routing = node.routing;
|
|
@@ -77,7 +105,9 @@ function capabilitiesFromNode(capsule) {
|
|
|
77
105
|
const assigned = new Set(routing?.assignedProviderCapabilities ?? []);
|
|
78
106
|
const merge = assigned.has("merge") || role === "merger" || role === "integrator" || role === "orchestrator";
|
|
79
107
|
const write = assigned.has("write") || merge || role === "coder" || role === "executor" || role === "refactorer";
|
|
80
|
-
const shell =
|
|
108
|
+
const shell = routing?.readOnly === true
|
|
109
|
+
? false
|
|
110
|
+
: assigned.has("shell") || routing?.requiresToolCalling === true || gates.includes("command-pass") || gates.includes("test-pass");
|
|
81
111
|
const review = assigned.has("review") || role === "reviewer" || role === "qa" || role === "tester" || gates.includes("review-pass");
|
|
82
112
|
const mcp = assigned.has("mcp") || routing?.requiresMcp === true;
|
|
83
113
|
const vision = assigned.has("vision");
|
|
@@ -88,7 +118,7 @@ function capabilitiesFromNode(capsule) {
|
|
|
88
118
|
mcp,
|
|
89
119
|
patch: routing?.readOnly === true ? false : write,
|
|
90
120
|
review,
|
|
91
|
-
merge,
|
|
121
|
+
merge: routing?.readOnly === true ? false : merge,
|
|
92
122
|
vision,
|
|
93
123
|
toolCalling: routing?.requiresToolCalling === true || assigned.has("toolCalling"),
|
|
94
124
|
maxTokens: capsule.budget.maxInputTokens,
|
|
@@ -5,11 +5,27 @@ import { mkdir, readFile, stat, writeFile } from "fs/promises";
|
|
|
5
5
|
import { createContextBudgetOptimizer } from "./context-budget-optimizer.js";
|
|
6
6
|
import { createDecisionTraceStore } from "../evidence/decision-trace.js";
|
|
7
7
|
import { evaluateHeadroom } from "./headroom-policy.js";
|
|
8
|
+
import { getRunArtifactPath } from "../util/run-store.js";
|
|
8
9
|
const DEFAULT_CONTEXT_WINDOW = 200_000;
|
|
9
10
|
function resolveBudget(node) {
|
|
10
11
|
const preset = node.routing?.contextBudget ?? "small";
|
|
11
12
|
return CONTEXT_BUDGET_PRESETS[preset] ?? DEFAULT_CONTEXT_BUDGET;
|
|
12
13
|
}
|
|
14
|
+
async function loadPrivatePromptPayload(node, runId, projectRoot) {
|
|
15
|
+
const ref = node.routing?.promptPayloadRef;
|
|
16
|
+
if (!ref || !runId)
|
|
17
|
+
return undefined;
|
|
18
|
+
try {
|
|
19
|
+
const raw = await readFile(getRunArtifactPath(runId, ref, projectRoot), "utf-8");
|
|
20
|
+
const parsed = JSON.parse(raw);
|
|
21
|
+
if (typeof parsed.compiledPrompt !== "string" || parsed.compiledPrompt.trim().length === 0)
|
|
22
|
+
return undefined;
|
|
23
|
+
return parsed.compiledPrompt;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
13
29
|
function collectDependencySummaries(node, state) {
|
|
14
30
|
if (!state || !node.dependsOn.length)
|
|
15
31
|
return [];
|
|
@@ -238,9 +254,11 @@ export function createContextBroker(options = {}) {
|
|
|
238
254
|
nodeId: node.id,
|
|
239
255
|
graphMemory,
|
|
240
256
|
}).catch(() => { });
|
|
257
|
+
const privatePrompt = await loadPrivatePromptPayload(node, state?.runId, projectRoot);
|
|
241
258
|
const task = [
|
|
242
259
|
`Execute DAG node: ${node.id}`,
|
|
243
260
|
`Name: ${node.name}`,
|
|
261
|
+
privatePrompt ? `PrivatePrompt: ${privatePrompt}` : undefined,
|
|
244
262
|
`Role: ${node.role}`,
|
|
245
263
|
node.routing?.actionAtom ? `ActionAtom: ${node.routing.actionAtom.id} | ${node.routing.actionAtom.label} | ${node.routing.actionAtom.verb} ${node.routing.actionAtom.object ?? "assigned scope"} | evidence=${node.routing.actionAtom.evidenceTarget} | done=${node.routing.actionAtom.doneCondition}` : undefined,
|
|
246
264
|
node.routing?.skills?.length ? `Skills: ${node.routing.skills.join(", ")}` : undefined,
|
|
@@ -68,6 +68,58 @@ export interface AdapterTestResult {
|
|
|
68
68
|
readonly score: number;
|
|
69
69
|
readonly details?: string;
|
|
70
70
|
}
|
|
71
|
+
/** Kinds of output gates that can satisfy evidence-required turns. */
|
|
72
|
+
export type EvidenceGateKind = "file-exists" | "test-pass" | "review-pass" | "command-pass" | "summary" | "artifact" | "diff";
|
|
73
|
+
/** A declared gate requirement. Declarations are not evidence. */
|
|
74
|
+
export interface EvidenceRequirement {
|
|
75
|
+
readonly gate: EvidenceGateKind;
|
|
76
|
+
readonly ref?: string;
|
|
77
|
+
readonly required: boolean;
|
|
78
|
+
}
|
|
79
|
+
/** A produced, replayable evidence observation. */
|
|
80
|
+
export interface EvidenceObservation {
|
|
81
|
+
readonly kind: EvidenceGateKind;
|
|
82
|
+
readonly source: "stdout" | "metadata" | "artifact" | "file";
|
|
83
|
+
readonly ref?: string;
|
|
84
|
+
readonly artifactPath?: string;
|
|
85
|
+
readonly timestamp: string;
|
|
86
|
+
readonly replayable: boolean;
|
|
87
|
+
readonly redacted: boolean;
|
|
88
|
+
/** Confidence that this observation is replayable, command-backed evidence. */
|
|
89
|
+
readonly confidence: number;
|
|
90
|
+
}
|
|
91
|
+
/** Result of checking whether a node/task produced required evidence. */
|
|
92
|
+
export interface EvidenceGateCheck {
|
|
93
|
+
readonly required: boolean;
|
|
94
|
+
readonly satisfied: boolean;
|
|
95
|
+
readonly gates: readonly EvidenceGateKind[];
|
|
96
|
+
readonly missing: readonly EvidenceGateKind[];
|
|
97
|
+
readonly reason: string;
|
|
98
|
+
readonly requirements?: readonly EvidenceRequirement[];
|
|
99
|
+
readonly observations?: readonly EvidenceObservation[];
|
|
100
|
+
}
|
|
101
|
+
export declare function isEvidenceGateKind(value: string | undefined): value is EvidenceGateKind;
|
|
102
|
+
export declare function evidenceRequirementsFromOutputs(outputs: readonly {
|
|
103
|
+
gate?: string;
|
|
104
|
+
ref?: string;
|
|
105
|
+
required?: boolean;
|
|
106
|
+
}[] | undefined): EvidenceRequirement[];
|
|
107
|
+
export declare function hasDeclaredEvidenceRequirement(outputs: readonly {
|
|
108
|
+
gate?: string;
|
|
109
|
+
ref?: string;
|
|
110
|
+
required?: boolean;
|
|
111
|
+
}[] | undefined): boolean;
|
|
112
|
+
export declare function evidenceObservationsFromResult(input: {
|
|
113
|
+
readonly metadata?: Record<string, unknown> | null;
|
|
114
|
+
readonly stdout?: string;
|
|
115
|
+
readonly artifactPaths?: readonly string[];
|
|
116
|
+
readonly timestamp?: string;
|
|
117
|
+
}): EvidenceObservation[];
|
|
118
|
+
export declare function checkEvidenceGate(required: boolean | undefined, outputs: readonly {
|
|
119
|
+
gate?: string;
|
|
120
|
+
ref?: string;
|
|
121
|
+
required?: boolean;
|
|
122
|
+
}[] | undefined, metadata?: Record<string, unknown> | null, stdout?: string, artifactPaths?: readonly string[]): EvidenceGateCheck;
|
|
71
123
|
/** Per-gate check result. */
|
|
72
124
|
export interface GateCheck {
|
|
73
125
|
readonly gate: string;
|
|
@@ -4,4 +4,141 @@
|
|
|
4
4
|
* Core interfaces that bridge reasoning traces, runtime decisions,
|
|
5
5
|
* provider maturity, and release gates into a verifiable evidence model.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
const EVIDENCE_GATE_KINDS = [
|
|
8
|
+
"file-exists",
|
|
9
|
+
"test-pass",
|
|
10
|
+
"review-pass",
|
|
11
|
+
"command-pass",
|
|
12
|
+
"summary",
|
|
13
|
+
"artifact",
|
|
14
|
+
"diff",
|
|
15
|
+
];
|
|
16
|
+
export function isEvidenceGateKind(value) {
|
|
17
|
+
return Boolean(value && EVIDENCE_GATE_KINDS.includes(value.toLowerCase()));
|
|
18
|
+
}
|
|
19
|
+
export function evidenceRequirementsFromOutputs(outputs) {
|
|
20
|
+
const requirements = [];
|
|
21
|
+
for (const output of outputs ?? []) {
|
|
22
|
+
const kind = output.gate?.toLowerCase();
|
|
23
|
+
if (!isEvidenceGateKind(kind))
|
|
24
|
+
continue;
|
|
25
|
+
if (output.required === false)
|
|
26
|
+
continue;
|
|
27
|
+
requirements.push({ gate: kind, ref: output.ref, required: true });
|
|
28
|
+
}
|
|
29
|
+
return requirements;
|
|
30
|
+
}
|
|
31
|
+
export function hasDeclaredEvidenceRequirement(outputs) {
|
|
32
|
+
return evidenceRequirementsFromOutputs(outputs).length > 0;
|
|
33
|
+
}
|
|
34
|
+
export function evidenceObservationsFromResult(input) {
|
|
35
|
+
const timestamp = input.timestamp ?? new Date().toISOString();
|
|
36
|
+
const observations = [];
|
|
37
|
+
const metadata = input.metadata ?? undefined;
|
|
38
|
+
const metaGates = metadata?.evidenceGates;
|
|
39
|
+
if (Array.isArray(metaGates)) {
|
|
40
|
+
for (const raw of metaGates) {
|
|
41
|
+
const gate = typeof raw === "string" ? raw.toLowerCase() : undefined;
|
|
42
|
+
if (isEvidenceGateKind(gate)) {
|
|
43
|
+
observations.push({ kind: gate, source: "metadata", timestamp, replayable: true, redacted: true, confidence: 0.9 });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (metadata?.commandPass === true || metadata?.testPass === true || metadata?.buildPass === true) {
|
|
48
|
+
observations.push({ kind: "command-pass", source: "metadata", timestamp, replayable: true, redacted: true, confidence: 0.9 });
|
|
49
|
+
}
|
|
50
|
+
if (metadata?.diff || metadata?.patch || metadata?.changedFiles) {
|
|
51
|
+
observations.push({ kind: "diff", source: "metadata", timestamp, replayable: true, redacted: true, confidence: 0.9 });
|
|
52
|
+
}
|
|
53
|
+
const artifactRef = metadata?.artifact ?? metadata?.artifactPath ?? metadata?.evidenceRef;
|
|
54
|
+
if (typeof artifactRef === "string" && artifactRef.trim().length > 0) {
|
|
55
|
+
observations.push({ kind: "artifact", source: "metadata", ref: artifactRef, artifactPath: artifactRef, timestamp, replayable: true, redacted: true, confidence: 0.95 });
|
|
56
|
+
}
|
|
57
|
+
for (const artifactPath of input.artifactPaths ?? []) {
|
|
58
|
+
observations.push({ kind: "artifact", source: "artifact", artifactPath, ref: artifactPath, timestamp, replayable: true, redacted: true, confidence: 0.95 });
|
|
59
|
+
}
|
|
60
|
+
const stdout = input.stdout ?? "";
|
|
61
|
+
if (stdout.trim().length > 0) {
|
|
62
|
+
const hasStructuredSummaryMarker = /^##\s+(Summary|Evidence|Verification)\b/im.test(stdout);
|
|
63
|
+
observations.push({
|
|
64
|
+
kind: "summary",
|
|
65
|
+
source: "stdout",
|
|
66
|
+
timestamp,
|
|
67
|
+
replayable: true,
|
|
68
|
+
redacted: true,
|
|
69
|
+
confidence: hasStructuredSummaryMarker ? 0.9 : 0.4,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (/\b(pass(ed)?|success|ok)\b/i.test(stdout) && /\b(test|check|build|lint|command)\b/i.test(stdout)) {
|
|
73
|
+
observations.push({ kind: "command-pass", source: "stdout", timestamp, replayable: true, redacted: true, confidence: 0.4 });
|
|
74
|
+
}
|
|
75
|
+
return observations;
|
|
76
|
+
}
|
|
77
|
+
function minimumConfidenceFor(requirement) {
|
|
78
|
+
if (["command-pass", "test-pass", "summary", "review-pass"].includes(requirement.gate))
|
|
79
|
+
return 0.8;
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
function observationSatisfies(requirement, observation) {
|
|
83
|
+
if (!observation.replayable || !observation.redacted)
|
|
84
|
+
return false;
|
|
85
|
+
if (observation.confidence < minimumConfidenceFor(requirement))
|
|
86
|
+
return false;
|
|
87
|
+
if (observation.kind === requirement.gate)
|
|
88
|
+
return true;
|
|
89
|
+
if (requirement.gate === "test-pass" && observation.kind === "command-pass")
|
|
90
|
+
return true;
|
|
91
|
+
if (requirement.gate === "review-pass" && observation.kind === "summary")
|
|
92
|
+
return true;
|
|
93
|
+
if (requirement.gate === "file-exists" && observation.kind === "artifact")
|
|
94
|
+
return true;
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
export function checkEvidenceGate(required, outputs, metadata, stdout, artifactPaths) {
|
|
98
|
+
const requirements = evidenceRequirementsFromOutputs(outputs);
|
|
99
|
+
const observations = evidenceObservationsFromResult({ metadata, stdout, artifactPaths });
|
|
100
|
+
const observedKinds = new Set(observations.map((o) => o.kind));
|
|
101
|
+
if (!required) {
|
|
102
|
+
return { required: false, satisfied: true, gates: [...observedKinds], missing: [], reason: "evidence not required", requirements, observations };
|
|
103
|
+
}
|
|
104
|
+
if (requirements.length === 0 && observations.length > 0) {
|
|
105
|
+
const strongObservations = observations.filter((observation) => observation.confidence >= 0.8 && observation.replayable && observation.redacted);
|
|
106
|
+
if (strongObservations.length > 0) {
|
|
107
|
+
return {
|
|
108
|
+
required: true,
|
|
109
|
+
satisfied: true,
|
|
110
|
+
gates: [...new Set(strongObservations.map((observation) => observation.kind))],
|
|
111
|
+
missing: [],
|
|
112
|
+
reason: `evidence satisfied by high-confidence observations without explicit gate: ${[...new Set(strongObservations.map((observation) => observation.kind))].join(", ")}`,
|
|
113
|
+
requirements,
|
|
114
|
+
observations,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const effectiveRequirements = requirements.length > 0
|
|
119
|
+
? requirements
|
|
120
|
+
: EVIDENCE_GATE_KINDS.map((gate) => ({ gate, required: true }));
|
|
121
|
+
const missing = effectiveRequirements
|
|
122
|
+
.filter((requirement) => !observations.some((observation) => observationSatisfies(requirement, observation)))
|
|
123
|
+
.map((requirement) => requirement.gate);
|
|
124
|
+
if (missing.length === 0) {
|
|
125
|
+
return {
|
|
126
|
+
required: true,
|
|
127
|
+
satisfied: true,
|
|
128
|
+
gates: [...observedKinds],
|
|
129
|
+
missing: [],
|
|
130
|
+
reason: `evidence satisfied by observations: ${[...observedKinds].join(", ") || "none"}`,
|
|
131
|
+
requirements: effectiveRequirements,
|
|
132
|
+
observations,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
required: true,
|
|
137
|
+
satisfied: false,
|
|
138
|
+
gates: [...observedKinds],
|
|
139
|
+
missing,
|
|
140
|
+
reason: `required evidence observations missing: ${[...new Set(missing)].join(", ")}`,
|
|
141
|
+
requirements: effectiveRequirements,
|
|
142
|
+
observations,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -26,9 +26,36 @@ export interface RuntimeCapabilities {
|
|
|
26
26
|
supportsStructuredOutput?: boolean;
|
|
27
27
|
supportsToolCalling?: boolean;
|
|
28
28
|
}
|
|
29
|
+
export type HealthState = "pass" | "fail" | "unknown";
|
|
30
|
+
export type RuntimeHealthProbeKind = "none" | "static" | "cheap-call" | "live-call";
|
|
31
|
+
export interface RuntimeHealthVector {
|
|
32
|
+
/** Legacy boolean dimensions retained for backward compatibility. */
|
|
33
|
+
runtimeOk?: boolean;
|
|
34
|
+
authOk?: boolean;
|
|
35
|
+
modelOk?: boolean;
|
|
36
|
+
quotaOk?: boolean;
|
|
37
|
+
rateLimitOk?: boolean;
|
|
38
|
+
/** Tri-state dimensions used by health-aware routing v2. */
|
|
39
|
+
runtime?: HealthState;
|
|
40
|
+
auth?: HealthState;
|
|
41
|
+
model?: HealthState;
|
|
42
|
+
quota?: HealthState;
|
|
43
|
+
rateLimit?: HealthState;
|
|
44
|
+
latencyMs?: number;
|
|
45
|
+
lastProbeKind?: RuntimeHealthProbeKind;
|
|
46
|
+
checkedAt?: string;
|
|
47
|
+
expiresAt?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface RuntimeHealthProbeRequest {
|
|
50
|
+
readonly probeKind: RuntimeHealthProbeKind;
|
|
51
|
+
readonly taskRisk?: string;
|
|
52
|
+
readonly highRisk: boolean;
|
|
53
|
+
}
|
|
29
54
|
export interface RuntimeHealth {
|
|
30
55
|
runtimeId: RuntimeId;
|
|
31
56
|
available: boolean;
|
|
32
57
|
reason?: string;
|
|
33
58
|
checkedAt: string;
|
|
59
|
+
/** Structured health signals beyond a binary available flag. */
|
|
60
|
+
vector?: RuntimeHealthVector;
|
|
34
61
|
}
|