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.
Files changed (128) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/MATURITY.md +2 -2
  3. package/README.md +86 -39
  4. package/ROADMAP.md +20 -17
  5. package/dist/brand/night-city.theme.json +122 -24
  6. package/dist/brand/rust-forge.theme.json +1 -1
  7. package/dist/commands/chat/native-root-loop.d.ts +27 -3
  8. package/dist/commands/chat/native-root-loop.js +370 -49
  9. package/dist/commands/dag.js +45 -0
  10. package/dist/commands/init/content.d.ts +1 -1
  11. package/dist/commands/init/content.js +3 -3
  12. package/dist/commands/init.js +3 -3
  13. package/dist/commands/verify.js +59 -1
  14. package/dist/contracts/dag.d.ts +9 -1
  15. package/dist/evidence/graph-ontology-relation-gate.d.ts +10 -0
  16. package/dist/evidence/graph-ontology-relation-gate.js +46 -0
  17. package/dist/evidence/headroom-replay-verifier.d.ts +19 -0
  18. package/dist/evidence/headroom-replay-verifier.js +86 -0
  19. package/dist/memory/local-graph-memory-store.d.ts +75 -0
  20. package/dist/memory/local-graph-memory-store.js +570 -0
  21. package/dist/orchestration/dag.d.ts +22 -1
  22. package/dist/orchestration/evidence-gate.js +12 -0
  23. package/dist/orchestration/executor.js +111 -15
  24. package/dist/orchestration/loop-controller-headroom.d.ts +6 -0
  25. package/dist/orchestration/loop-controller-headroom.js +33 -0
  26. package/dist/orchestration/scheduler.d.ts +2 -0
  27. package/dist/orchestration/scheduler.js +3 -0
  28. package/dist/orchestration/task-graph.d.ts +17 -0
  29. package/dist/orchestration/task-graph.js +38 -0
  30. package/dist/providers/codex-cli-runner.js +17 -2
  31. package/dist/runtime/agent-runtime.d.ts +32 -3
  32. package/dist/runtime/agent-runtime.js +20 -7
  33. package/dist/runtime/authority-matrix.d.ts +23 -0
  34. package/dist/runtime/authority-matrix.js +171 -0
  35. package/dist/runtime/chat-advisory-runtime.js +3 -0
  36. package/dist/runtime/codex-cli-runtime.js +2 -0
  37. package/dist/runtime/codex-runtime.d.ts +4 -1
  38. package/dist/runtime/codex-runtime.js +34 -12
  39. package/dist/runtime/context-broker-converter.js +32 -2
  40. package/dist/runtime/context-broker.js +18 -0
  41. package/dist/runtime/contracts/evidence.d.ts +52 -0
  42. package/dist/runtime/contracts/evidence.js +138 -1
  43. package/dist/runtime/contracts/shared.d.ts +27 -0
  44. package/dist/runtime/data-retention-gate.d.ts +42 -0
  45. package/dist/runtime/data-retention-gate.js +123 -0
  46. package/dist/runtime/deepseek-runtime.d.ts +5 -1
  47. package/dist/runtime/deepseek-runtime.js +13 -7
  48. package/dist/runtime/external-cli-adapter.js +20 -7
  49. package/dist/runtime/freedomd-evidence-envelope.d.ts +57 -0
  50. package/dist/runtime/freedomd-evidence-envelope.js +110 -0
  51. package/dist/runtime/freedomd-exception.d.ts +32 -0
  52. package/dist/runtime/freedomd-exception.js +95 -0
  53. package/dist/runtime/freedomd-incidents.d.ts +23 -0
  54. package/dist/runtime/freedomd-incidents.js +103 -0
  55. package/dist/runtime/freedomd-policy.d.ts +35 -0
  56. package/dist/runtime/freedomd-policy.js +114 -0
  57. package/dist/runtime/freedomd-router.d.ts +66 -0
  58. package/dist/runtime/freedomd-router.js +433 -0
  59. package/dist/runtime/headroom-aware-loop-decision.d.ts +21 -0
  60. package/dist/runtime/headroom-aware-loop-decision.js +67 -0
  61. package/dist/runtime/headroom-loop-risk.d.ts +19 -0
  62. package/dist/runtime/headroom-loop-risk.js +43 -0
  63. package/dist/runtime/headroom-policy.d.ts +14 -1
  64. package/dist/runtime/headroom-policy.js +74 -12
  65. package/dist/runtime/kimi-api-runtime.d.ts +4 -1
  66. package/dist/runtime/kimi-api-runtime.js +35 -11
  67. package/dist/runtime/kimi-print-runtime.js +21 -0
  68. package/dist/runtime/kimi-wire-protocol-runtime.js +17 -1
  69. package/dist/runtime/local-llm-runtime.d.ts +5 -1
  70. package/dist/runtime/local-llm-runtime.js +14 -23
  71. package/dist/runtime/private-stderr.d.ts +13 -0
  72. package/dist/runtime/private-stderr.js +69 -0
  73. package/dist/runtime/prompt-envelope.d.ts +1 -1
  74. package/dist/runtime/provider-sovereignty.d.ts +81 -0
  75. package/dist/runtime/provider-sovereignty.js +285 -0
  76. package/dist/runtime/runtime-backed-task-runner.d.ts +1 -0
  77. package/dist/runtime/runtime-backed-task-runner.js +282 -10
  78. package/dist/runtime/runtime-bootstrap.d.ts +12 -0
  79. package/dist/runtime/runtime-bootstrap.js +54 -11
  80. package/dist/runtime/runtime-failure-classifier.d.ts +15 -0
  81. package/dist/runtime/runtime-failure-classifier.js +107 -0
  82. package/dist/runtime/runtime-health-probes.d.ts +30 -0
  83. package/dist/runtime/runtime-health-probes.js +102 -0
  84. package/dist/runtime/runtime-router.d.ts +6 -2
  85. package/dist/runtime/runtime-router.js +575 -53
  86. package/dist/runtime/structured-compaction.d.ts +107 -0
  87. package/dist/runtime/structured-compaction.js +414 -0
  88. package/dist/runtime/tool-dispatch-contracts.d.ts +7 -5
  89. package/dist/runtime/tool-dispatch-contracts.js +15 -4
  90. package/dist/runtime/tool-plane.d.ts +1 -1
  91. package/dist/runtime/tool-plane.js +49 -1
  92. package/dist/runtime/worker-manifest.js +1 -1
  93. package/dist/schema/evidence-bundle.schema.d.ts +8 -8
  94. package/dist/schema/proof-bundle.schema.d.ts +2 -2
  95. package/dist/util/hash.d.ts +2 -0
  96. package/dist/util/hash.js +13 -0
  97. package/dist/util/session.js +5 -4
  98. package/docs/2026-06-16/critical-issues.md +19 -0
  99. package/docs/2026-06-16/improvements.md +15 -0
  100. package/docs/2026-06-16/init-checklist.md +25 -0
  101. package/docs/2026-06-16/plan.md +20 -0
  102. package/docs/2026-06-17/critical-issues.md +19 -0
  103. package/docs/2026-06-17/improvements.md +15 -0
  104. package/docs/2026-06-17/init-checklist.md +25 -0
  105. package/docs/2026-06-17/plan.md +20 -0
  106. package/docs/ARCHITECTURE_ANALYSIS_CODEGRAPH.md +2 -1
  107. package/docs/GSTACK_MIGRATION.md +1 -1
  108. package/docs/algorithm-hardening-playbook.md +219 -0
  109. package/docs/claims.md +1 -1
  110. package/docs/getting-started.md +1 -1
  111. package/docs/native-root-runtime-hardening.md +42 -32
  112. package/docs/post-0793-hardening-roadmap.md +123 -0
  113. package/docs/provider-maturity.md +18 -16
  114. package/docs/versioning.md +3 -3
  115. package/docs/what-is-omk.md +1 -1
  116. package/package.json +8 -4
  117. package/readmeasset/.npmignore +2 -0
  118. package/readmeasset/ASSET_INDEX.md +2 -0
  119. package/readmeasset/ASSET_PROVENANCE.md +40 -20
  120. package/readmeasset/omk-adaptorch-ouroboros-supermemory.svg +1 -1
  121. package/readmeasset/omk-control-surfaces.svg +1 -1
  122. package/readmeasset/omk-core-loop.svg +1 -1
  123. package/readmeasset/omk-freedomd-control-plane.svg +59 -0
  124. package/readmeasset/omk-freedomd-control-plane.webp +0 -0
  125. package/readmeasset/omk-init-control-loop.svg +1 -1
  126. package/readmeasset/omk-logo-mark.svg +1 -1
  127. package/readmeasset/omk-parallel-subagents.svg +1 -1
  128. package/readmeasset/omk-release-assertions.svg +1 -1
@@ -262,6 +262,15 @@ export function compressDiagnostic(command, exitCode, stdout, stderr) {
262
262
  /** Allowlist pattern reused from quality-gate.ts */
263
263
  const SCRIPT_NAME_PATTERN = /^[A-Za-z0-9:_-]+$/;
264
264
  const PACKAGE_MANAGERS = new Set(["npm", "pnpm", "yarn", "bun"]);
265
+ /**
266
+ * Agent-freedom mode (e.g. SWE-bench / DeepSWE) relaxes command-pass gate
267
+ * allowlisting so agents can run arbitrary test/build/lint commands.
268
+ */
269
+ function isStrictGuardrailMode() {
270
+ const raw = process.env.OMK_STRICT_GUARDRAIL ?? "";
271
+ const normalized = raw.trim().toLowerCase();
272
+ return normalized === "1" || normalized === "true" || normalized === "on";
273
+ }
265
274
  export const SUMMARY_ALIASES = [
266
275
  "## Summary",
267
276
  "## Evidence",
@@ -279,6 +288,9 @@ export const SUMMARY_ALIASES = [
279
288
  function resolveSafeCommand(command) {
280
289
  const trimmed = command.trim();
281
290
  const parts = trimmed.split(/\s+/);
291
+ if (!isStrictGuardrailMode()) {
292
+ return { cmd: parts[0], args: parts.slice(1) };
293
+ }
282
294
  if (parts.length === 1 && SCRIPT_NAME_PATTERN.test(parts[0])) {
283
295
  return { cmd: "npm", args: ["run", parts[0]] };
284
296
  }
@@ -5,6 +5,7 @@ import { estimateRunProgress } from "./eta.js";
5
5
  import { dagNodeRoutingEnv } from "./routing.js";
6
6
  import { getOmkResourceSettings } from "../util/resource-profile.js";
7
7
  import { checkEvidenceGates } from "./evidence-gate.js";
8
+ import { checkEvidenceGate } from "../runtime/contracts/evidence.js";
8
9
  import { invalidateTaskDagGraph } from "./task-graph.js";
9
10
  import { resolveTimeoutMs } from "../util/timeout-config.js";
10
11
  import { createNodeMonitorEngine } from "./node-monitor.js";
@@ -318,46 +319,141 @@ export function createExecutor(executorOptions = {}) {
318
319
  }
319
320
  }
320
321
  async function checkNodeEvidence(node, result, options) {
321
- const gates = [];
322
+ const cwd = options.worktreeRoot ?? process.cwd();
323
+ const latestAttempt = node.attempts?.[node.attempts.length - 1];
324
+ const attemptId = latestAttempt ? `${node.id}__${latestAttempt.attempt}` : `${node.id}__1`;
325
+ const required = nodeRequiresEvidence(node);
326
+ const bridge = await legacyEvidenceBridge(node, result, { cwd, runId: options.runId, attemptId, required });
327
+ const metadata = {
328
+ ...(result.metadata ?? {}),
329
+ ...(bridge.evidenceGates.length > 0 && { evidenceGates: bridge.evidenceGates }),
330
+ ...(bridge.diffObserved && { diff: true }),
331
+ };
332
+ const check = checkEvidenceGate(required, node.outputs, metadata, result.stdout, bridge.artifactPaths);
333
+ return {
334
+ passed: check.satisfied,
335
+ evidence: evidenceGateCheckToDagEvidence(check, bridge.evidence),
336
+ };
337
+ }
338
+ async function legacyEvidenceBridge(node, result, options) {
339
+ const legacyGates = [];
322
340
  for (const output of node.outputs ?? []) {
323
341
  switch (output.gate) {
324
342
  case "file-exists":
343
+ case "artifact":
325
344
  if (output.ref)
326
- gates.push({ type: "file-exists", path: output.ref });
345
+ legacyGates.push({ type: "file-exists", path: output.ref });
327
346
  break;
328
347
  case "test-pass":
329
- gates.push({ type: "command-pass", command: output.ref ?? "npm test" });
348
+ legacyGates.push({ type: "command-pass", command: output.ref ?? "npm test" });
330
349
  break;
331
350
  case "command-pass":
332
- gates.push({ type: "command-pass", command: output.ref ?? "" });
351
+ legacyGates.push({ type: "command-pass", command: output.ref ?? "" });
352
+ break;
353
+ case "diff":
354
+ legacyGates.push({ type: "diff-nonempty" });
333
355
  break;
334
356
  case "review-pass":
335
357
  case "summary":
336
- gates.push({ type: "summary-present", summaryMarker: output.ref ?? "## Summary" });
358
+ legacyGates.push({ type: "summary-present", summaryMarker: output.ref ?? "## Summary" });
337
359
  break;
338
360
  case "none":
339
361
  default:
340
362
  break;
341
363
  }
342
364
  }
343
- const hasCommandGate = (node.outputs ?? []).some((o) => o.gate === "command-pass" || o.gate === "test-pass");
344
- if (node.routing?.evidenceRequired && !hasCommandGate) {
345
- gates.push({ type: "summary-present", summaryMarker: "## Evidence" });
365
+ if (options.required && node.routing?.evidenceRequired && !legacyGates.some((gate) => gate.type === "command-pass")) {
366
+ legacyGates.push({ type: "summary-present", summaryMarker: "## Evidence" });
346
367
  }
347
- if (gates.length === 0) {
348
- return { passed: true, evidence: [] };
368
+ if (legacyGates.length === 0) {
369
+ return { evidenceGates: [], artifactPaths: [], diffObserved: false, evidence: [] };
349
370
  }
350
- const latestAttempt = node.attempts?.[node.attempts.length - 1];
351
- const attemptId = latestAttempt ? `${node.id}__${latestAttempt.attempt}` : `${node.id}__1`;
352
- return checkEvidenceGates(gates, {
353
- cwd: options.worktreeRoot ?? process.cwd(),
371
+ const legacy = await checkEvidenceGates(legacyGates, {
372
+ cwd: options.cwd,
354
373
  stdout: result.stdout,
355
374
  nodeId: node.id,
356
375
  runId: options.runId,
357
- attemptId,
376
+ attemptId: options.attemptId,
358
377
  });
378
+ const evidenceGates = [];
379
+ const artifactPaths = [];
380
+ let diffObserved = false;
381
+ for (const item of legacy.evidence) {
382
+ if (!item.passed)
383
+ continue;
384
+ if (item.gate === "command-pass")
385
+ evidenceGates.push("command-pass");
386
+ else if (item.gate === "summary-present")
387
+ evidenceGates.push("summary");
388
+ else if (item.gate === "file-exists") {
389
+ evidenceGates.push("artifact");
390
+ if (item.ref)
391
+ artifactPaths.push(item.ref);
392
+ }
393
+ else if (item.gate === "diff-nonempty") {
394
+ evidenceGates.push("diff");
395
+ diffObserved = true;
396
+ }
397
+ }
398
+ return { evidenceGates, artifactPaths, diffObserved, evidence: legacy.evidence };
399
+ }
400
+ function evidenceGateCheckToDagEvidence(check, bridgeEvidence) {
401
+ const evidence = [...bridgeEvidence];
402
+ for (const observation of check.observations ?? []) {
403
+ evidence.push({
404
+ gate: observation.kind,
405
+ passed: check.satisfied,
406
+ ref: observation.ref ?? observation.artifactPath,
407
+ message: `Evidence observation ${observation.kind} from ${observation.source} confidence=${observation.confidence}`,
408
+ });
409
+ }
410
+ for (const missing of check.missing) {
411
+ evidence.push({
412
+ gate: missing,
413
+ passed: false,
414
+ failureKind: "missing-evidence-observation",
415
+ message: check.reason,
416
+ });
417
+ }
418
+ return evidence;
419
+ }
420
+ function hasRequiredEvidenceOutput(node) {
421
+ return (node.outputs ?? []).some((output) => output.required !== false && output.gate !== undefined && output.gate !== "none");
422
+ }
423
+ function nodeRequiresEvidence(node) {
424
+ const highRisk = nodeHasHighRiskCapabilities(node);
425
+ const outputs = node.outputs ?? [];
426
+ const explicitlyNoEvidence = outputs.length > 0 && outputs.every((output) => output.required === false || output.gate === undefined || output.gate === "none");
427
+ if (explicitlyNoEvidence && !highRisk)
428
+ return false;
429
+ return hasRequiredEvidenceOutput(node) || highRisk;
430
+ }
431
+ function nodeHasHighRiskCapabilities(node) {
432
+ return node.routing?.assignedProviderCapabilities?.some((cap) => ["write", "patch", "shell", "merge"].includes(cap)) ?? false;
359
433
  }
360
434
  async function runNode(node, dag, runner, options, state, signal, outAbort) {
435
+ if (nodeRequiresEvidence(node)) {
436
+ const hasGate = (node.outputs ?? []).some((output) => ["file-exists", "test-pass", "review-pass", "command-pass", "summary", "artifact", "diff"].includes(output.gate ?? ""));
437
+ if (!hasGate) {
438
+ scheduler.updateNodeStatus(dag, node.id, "failed", options.runId);
439
+ markNodeStarted(node);
440
+ const completedAt = new Date().toISOString();
441
+ const startedAtMs = Date.parse(node.startedAt ?? completedAt);
442
+ const durationMs = Math.max(0, Date.parse(completedAt) - startedAtMs);
443
+ const latestAttempt = { attempt: node.retries + 1, startedAt: node.startedAt ?? completedAt, completedAt, durationMs, status: "failed", error: "[omk] Evidence gate required but missing: high-risk node has no command-pass, test-pass, review-pass, file-exists, or summary output gate" };
444
+ node.attempts = [...(node.attempts ?? []), latestAttempt];
445
+ node.evidence = [
446
+ ...(node.evidence ?? []),
447
+ { gate: "evidence-required", passed: false, message: latestAttempt.error, failureKind: "missing-evidence-gate" },
448
+ ];
449
+ markNodeFinished(node, "failed");
450
+ refreshState(state, dag, options);
451
+ await commitState(state);
452
+ emit(cloneState(state));
453
+ emitTelemetry({ type: "lane.failed", runId: options.runId, nodeId: node.id, laneId: node.id, status: "failed", data: { success: false, exitCode: 78 } });
454
+ return;
455
+ }
456
+ }
361
457
  scheduler.updateNodeStatus(dag, node.id, "running", options.runId);
362
458
  markNodeStarted(node);
363
459
  bumpActivity(state);
@@ -0,0 +1,6 @@
1
+ import type { EvaluateLoopDecisionInput, LoopDecision } from "./loop-state.js";
2
+ import type { HeadroomDecisionHistoryEntry } from "../runtime/headroom-loop-risk.js";
3
+ export interface HeadroomAwareLoopControllerInput extends EvaluateLoopDecisionInput {
4
+ readonly headroomHistory: readonly HeadroomDecisionHistoryEntry[];
5
+ }
6
+ export declare function evaluateHeadroomAwareLoopController(input: HeadroomAwareLoopControllerInput): LoopDecision;
@@ -0,0 +1,33 @@
1
+ import { evaluateLoopDecision } from "./loop-controller.js";
2
+ import { evaluateHeadroomAwareLoopDecision } from "../runtime/headroom-aware-loop-decision.js";
3
+ function toHeadroomAction(action) {
4
+ switch (action) {
5
+ case "close":
6
+ return "continue";
7
+ case "verify-only":
8
+ return "continue";
9
+ case "handoff":
10
+ return "block";
11
+ default:
12
+ return action;
13
+ }
14
+ }
15
+ export function evaluateHeadroomAwareLoopController(input) {
16
+ const baseDecision = evaluateLoopDecision(input);
17
+ const headroomAware = evaluateHeadroomAwareLoopDecision({
18
+ baseAction: toHeadroomAction(baseDecision.action),
19
+ baseReason: baseDecision.reason,
20
+ baseConfidence: baseDecision.confidence,
21
+ headroomHistory: input.headroomHistory,
22
+ });
23
+ return {
24
+ ...baseDecision,
25
+ action: headroomAware.action === "context-adjustment" ? "continue" : headroomAware.action,
26
+ reason: headroomAware.reason,
27
+ confidence: headroomAware.confidence,
28
+ risk: {
29
+ ...baseDecision.risk,
30
+ headroom: headroomAware.risk?.headroom,
31
+ },
32
+ };
33
+ }
@@ -1,6 +1,8 @@
1
1
  import type { Dag, DagNode, TaskStatus } from "./dag.js";
2
+ import type { RunnableNodePlan } from "./task-graph.js";
2
3
  export interface Scheduler {
3
4
  getRunnableNodes(dag: Dag): DagNode[];
5
+ getRunnablePlan(dag: Dag): RunnableNodePlan[];
4
6
  updateNodeStatus(dag: Dag, id: string, status: TaskStatus, runId?: string): void;
5
7
  isComplete(dag: Dag): boolean;
6
8
  isFailed(dag: Dag): boolean;
@@ -6,6 +6,9 @@ export function createScheduler() {
6
6
  getRunnableNodes(dag) {
7
7
  return getTaskDagGraph(dag).runnableNodes().slice();
8
8
  },
9
+ getRunnablePlan(dag) {
10
+ return getTaskDagGraph(dag).runnablePlan();
11
+ },
9
12
  updateNodeStatus(dag, id, status, runId) {
10
13
  const node = getTaskDagGraph(dag).getNode(id);
11
14
  if (!node)
@@ -1,4 +1,17 @@
1
1
  import { type Dag, type DagNode } from "./dag.js";
2
+ export interface RunnableNodePlan {
3
+ readonly node: DagNode;
4
+ readonly nodeId: string;
5
+ readonly rank: number;
6
+ readonly score: number;
7
+ readonly criticalPathDepth: number;
8
+ readonly downstreamCount: number;
9
+ readonly priority: number;
10
+ readonly cost: number;
11
+ readonly evidenceProducer: boolean;
12
+ readonly evidenceRequired: boolean;
13
+ readonly reason: string;
14
+ }
2
15
  export declare class TaskDagGraph {
3
16
  private readonly nodeById;
4
17
  private readonly predecessorIds;
@@ -19,8 +32,12 @@ export declare class TaskDagGraph {
19
32
  findCycle(): string[];
20
33
  findAllCycles(limit?: number): string[][];
21
34
  getCriticalPathDepth(id: string): number;
35
+ getDownstreamCount(id: string): number;
36
+ getRunnableScore(id: string): number;
37
+ runnablePlan(): RunnableNodePlan[];
22
38
  private compareOrder;
23
39
  private compareRunnable;
40
+ private describeRunnableNode;
24
41
  private runnableScore;
25
42
  private criticalPathDepth;
26
43
  private downstreamCount;
@@ -190,12 +190,50 @@ export class TaskDagGraph {
190
190
  getCriticalPathDepth(id) {
191
191
  return this.criticalPathDepth(id);
192
192
  }
193
+ getDownstreamCount(id) {
194
+ return this.downstreamCount(id);
195
+ }
196
+ getRunnableScore(id) {
197
+ return this.runnableScore(id);
198
+ }
199
+ runnablePlan() {
200
+ return this.runnableNodes().map((node, index) => this.describeRunnableNode(node, index));
201
+ }
193
202
  compareOrder(a, b) {
194
203
  return (this.order.get(a) ?? 0) - (this.order.get(b) ?? 0);
195
204
  }
196
205
  compareRunnable(a, b) {
197
206
  return this.runnableScore(b) - this.runnableScore(a) || this.compareOrder(a, b);
198
207
  }
208
+ describeRunnableNode(node, index) {
209
+ const criticalPathDepth = this.criticalPathDepth(node.id);
210
+ const downstreamCount = this.downstreamCount(node.id);
211
+ const evidenceProducer = (node.outputs ?? []).some((output) => output.gate && output.gate !== "none");
212
+ const evidenceRequired = node.routing?.evidenceRequired === true;
213
+ const priority = Number.isFinite(node.priority) ? node.priority ?? 0 : 0;
214
+ const cost = node.cost ?? 1;
215
+ const score = this.runnableScore(node.id);
216
+ return {
217
+ node,
218
+ nodeId: node.id,
219
+ rank: index + 1,
220
+ score,
221
+ criticalPathDepth,
222
+ downstreamCount,
223
+ priority,
224
+ cost,
225
+ evidenceProducer,
226
+ evidenceRequired,
227
+ reason: [
228
+ `criticalDepth=${criticalPathDepth}`,
229
+ `downstream=${downstreamCount}`,
230
+ `priority=${priority}`,
231
+ `cost=${cost}`,
232
+ evidenceProducer ? "evidenceProducer" : "noEvidenceGate",
233
+ evidenceRequired ? "evidenceRequired" : "evidenceOptional",
234
+ ].join("; "),
235
+ };
236
+ }
199
237
  runnableScore(id) {
200
238
  const node = this.nodeById.get(id);
201
239
  if (!node)
@@ -56,8 +56,8 @@ export function createCodexCliAdvisoryTaskRunner(options) {
56
56
  };
57
57
  }
58
58
  const prompt = preflight.input;
59
- const sandboxMode = risk === "read" || advisoryMode ? "read-only" : "workspace-write";
60
- const approvalPolicy = sandboxMode === "workspace-write" ? "on-request" : "never";
59
+ const sandboxMode = resolveCodexCliSandboxMode(risk, advisoryMode, env);
60
+ const approvalPolicy = codexCliApprovalPolicy(env.OMK_APPROVAL_POLICY ?? env.OMK_EXECUTION, sandboxMode);
61
61
  const childEnv = buildChildEnv({
62
62
  overrideEnv: {
63
63
  ...env,
@@ -101,6 +101,21 @@ export function createCodexCliAdvisoryTaskRunner(options) {
101
101
  };
102
102
  return runner;
103
103
  }
104
+ function resolveCodexCliSandboxMode(risk, advisoryMode, env) {
105
+ if (risk === "read" || advisoryMode)
106
+ return "read-only";
107
+ if (env.OMK_PROVIDER_AUTHORITY === "advisory")
108
+ return "read-only";
109
+ return "workspace-write";
110
+ }
111
+ function codexCliApprovalPolicy(value, sandboxMode) {
112
+ if (sandboxMode !== "read-only")
113
+ return "on-request";
114
+ const normalized = value?.trim().toLowerCase();
115
+ if (normalized === "never" || normalized === "yolo")
116
+ return "never";
117
+ return "on-request";
118
+ }
104
119
  function buildCodexPrompt(node, env) {
105
120
  return [
106
121
  "You are a Codex CLI advisory/read-only lane inside OMK.",
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import type { TaskResult } from "../contracts/orchestration.js";
7
7
  import type { ContextCapsule } from "./context-capsule.js";
8
- import type { RuntimeCapabilities as SharedRuntimeCapabilities, RuntimeHealth as SharedRuntimeHealth, RuntimeId, RuntimeKind } from "./contracts/shared.js";
8
+ import type { RuntimeCapabilities as SharedRuntimeCapabilities, RuntimeHealth as SharedRuntimeHealth, RuntimeHealthProbeRequest, RuntimeId, RuntimeKind } from "./contracts/shared.js";
9
9
  export type { RuntimeAuthority, RuntimeId, RuntimeKind } from "./contracts/shared.js";
10
10
  export interface TokenUsage {
11
11
  readonly inputTokens: number;
@@ -58,6 +58,29 @@ export interface ToolManifest {
58
58
  readonly skills?: readonly string[];
59
59
  readonly hooks?: readonly string[];
60
60
  }
61
+ export interface AgentTaskSafety {
62
+ readonly risk: string;
63
+ readonly riskTrace?: unknown;
64
+ readonly approvalPolicy: string;
65
+ readonly sandboxMode: string;
66
+ readonly evidenceRequired: boolean;
67
+ readonly authorityMode: string;
68
+ }
69
+ export interface AgentTaskSovereignty {
70
+ readonly mode: "freedomd" | "standard";
71
+ readonly dataBoundary: "public" | "internal" | "customer" | "secret";
72
+ readonly retentionDecision: "allow" | "redact" | "downgrade" | "block";
73
+ readonly jurisdictionDecision: "allow" | "downgrade" | "block";
74
+ readonly providerCutoffRisk: number;
75
+ readonly localFallbackAvailable: boolean;
76
+ readonly reason: string;
77
+ }
78
+ export interface AgentContextCompaction {
79
+ readonly schemaVersion: "omk.task-compaction.v1";
80
+ readonly contract: unknown;
81
+ readonly diagnostics: Readonly<Record<string, unknown>>;
82
+ readonly artifactRef?: string;
83
+ }
61
84
  export interface AgentContext {
62
85
  readonly runId: string;
63
86
  readonly nodeId: string;
@@ -72,6 +95,9 @@ export interface AgentContext {
72
95
  }>;
73
96
  readonly goalContext?: unknown;
74
97
  readonly workerManifest?: unknown;
98
+ readonly compaction?: AgentContextCompaction;
99
+ /** Freedomd sovereignty decision surfaced to runtime adapters. */
100
+ readonly sovereignty?: AgentTaskSovereignty;
75
101
  readonly abortSignal?: AbortSignal;
76
102
  readonly cwd?: string;
77
103
  readonly env?: Record<string, string>;
@@ -105,8 +131,11 @@ export interface AgentTask {
105
131
  readonly tools: ToolManifest;
106
132
  readonly providerPolicy: ProviderPolicy;
107
133
  readonly capabilities: CapabilityManifest;
134
+ readonly safety: AgentTaskSafety;
108
135
  /** Images/files attached to this task (clipboard paste, --image, drag). */
109
136
  readonly attachments?: readonly AgentTaskAttachment[];
137
+ /** Freedomd sovereignty decision attached by retention/jurisdiction gates. */
138
+ readonly sovereignty?: AgentTaskSovereignty;
110
139
  }
111
140
  export interface AgentResult {
112
141
  readonly output: string;
@@ -122,11 +151,11 @@ export interface AgentRuntime {
122
151
  readonly displayName?: string;
123
152
  readonly kind?: RuntimeKind;
124
153
  readonly legacy?: boolean;
125
- readonly runtimeMode?: string;
154
+ readonly runtimeMode: string;
126
155
  readonly priority: number;
127
156
  readonly capabilities?: RuntimeCapabilities;
128
157
  supports(capsule: ContextCapsule): boolean;
129
- health?(): Promise<RuntimeHealth>;
158
+ health?(input?: RuntimeHealthProbeRequest): Promise<RuntimeHealth>;
130
159
  runNode(capsule: ContextCapsule, signal: AbortSignal): Promise<AgentRunResult>;
131
160
  execute?(task: AgentTask): Promise<AgentResult>;
132
161
  }
@@ -3,16 +3,29 @@
3
3
  *
4
4
  * Each runtime wraps a specific Kimi/provider invocation mode.
5
5
  */
6
+ import { sanitizeRuntimeStderrResult } from "./private-stderr.js";
6
7
  export function toTaskResult(result) {
8
+ const runtimeId = typeof result.metadata?.selectedRuntime === "string"
9
+ ? result.metadata.selectedRuntime
10
+ : typeof result.metadata?.runtime === "string"
11
+ ? result.metadata.runtime
12
+ : undefined;
13
+ const sanitized = sanitizeRuntimeStderrResult(result, {
14
+ runId: typeof result.metadata?.runId === "string" ? result.metadata.runId : process.env.OMK_RUN_ID,
15
+ nodeId: typeof result.metadata?.nodeId === "string" ? result.metadata.nodeId : process.env.OMK_NODE_ID,
16
+ runtimeId,
17
+ root: process.env.OMK_PROJECT_ROOT ?? process.cwd(),
18
+ env: process.env,
19
+ });
7
20
  return {
8
- success: result.success,
9
- exitCode: result.exitCode,
10
- stdout: result.stdout,
11
- stderr: result.stderr,
21
+ success: sanitized.success,
22
+ exitCode: sanitized.exitCode,
23
+ stdout: sanitized.stdout,
24
+ stderr: sanitized.stderr,
12
25
  metadata: {
13
- ...result.metadata,
14
- ...(result.tokenUsage != null && { tokenUsage: result.tokenUsage }),
15
- ...(result.toolCalls != null && result.toolCalls.length > 0 && { toolCalls: result.toolCalls }),
26
+ ...sanitized.metadata,
27
+ ...(sanitized.tokenUsage != null && { tokenUsage: sanitized.tokenUsage }),
28
+ ...(sanitized.toolCalls != null && sanitized.toolCalls.length > 0 && { toolCalls: sanitized.toolCalls }),
16
29
  },
17
30
  };
18
31
  }
@@ -0,0 +1,23 @@
1
+ import type { AgentRuntime, AgentTask } from "./agent-runtime.js";
2
+ export type RuntimeMode = "api" | "cli" | "wire" | "mcp" | "local" | "composite" | string;
3
+ export type AuthorityOperation = "read" | "review" | "write" | "patch" | "shell" | "mcp" | "merge" | "vision" | "toolCalling";
4
+ export interface RuntimeAuthorityMatrixEntry {
5
+ readonly providerId: string;
6
+ readonly runtimeMode: RuntimeMode;
7
+ readonly authorities: readonly AuthorityOperation[];
8
+ readonly advisory: boolean;
9
+ readonly notes?: string;
10
+ }
11
+ export declare const RUNTIME_AUTHORITY_MATRIX: readonly RuntimeAuthorityMatrixEntry[];
12
+ export declare function runtimeProviderId(runtime: Pick<AgentRuntime, "providerId" | "id">): string;
13
+ export declare function runtimeModeOf(runtime: Pick<AgentRuntime, "runtimeMode" | "kind" | "id">): RuntimeMode;
14
+ export declare function getRuntimeAuthorityEntry(runtime: Pick<AgentRuntime, "providerId" | "runtimeMode" | "kind" | "id">): RuntimeAuthorityMatrixEntry | undefined;
15
+ export declare function authoritiesForRuntime(runtime: Pick<AgentRuntime, "providerId" | "runtimeMode" | "kind" | "id" | "capabilities">): readonly AuthorityOperation[];
16
+ export declare function runtimeIsAdvisory(runtime: Pick<AgentRuntime, "providerId" | "runtimeMode" | "kind" | "id" | "capabilities">): boolean;
17
+ export declare function requiredAuthorityForTask(task: Pick<AgentTask, "capabilities">): readonly AuthorityOperation[];
18
+ export declare function runtimeSatisfiesAuthority(runtime: AgentRuntime, task: AgentTask): {
19
+ ok: boolean;
20
+ missing: readonly AuthorityOperation[];
21
+ reason?: string;
22
+ };
23
+ export declare function authorityCapableProviderIds(required: readonly AuthorityOperation[]): string[];