open-multi-agent-kit 0.96.0 → 0.96.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 +81 -0
- package/README.md +34 -6
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/commands/doctor-provider.d.ts.map +1 -1
- package/dist/commands/doctor-provider.js +15 -20
- package/dist/commands/doctor-provider.js.map +1 -1
- package/dist/commands/resource-doctor-cli.d.ts +22 -0
- package/dist/commands/resource-doctor-cli.d.ts.map +1 -0
- package/dist/commands/resource-doctor-cli.js +98 -0
- package/dist/commands/resource-doctor-cli.js.map +1 -0
- package/dist/commands/sdk-session-cli.d.ts +24 -0
- package/dist/commands/sdk-session-cli.d.ts.map +1 -0
- package/dist/commands/sdk-session-cli.js +225 -0
- package/dist/commands/sdk-session-cli.js.map +1 -0
- package/dist/core/advisory-judge-model.d.ts +18 -0
- package/dist/core/advisory-judge-model.d.ts.map +1 -0
- package/dist/core/advisory-judge-model.js +168 -0
- package/dist/core/advisory-judge-model.js.map +1 -0
- package/dist/core/advisory-judge-response.d.ts +8 -0
- package/dist/core/advisory-judge-response.d.ts.map +1 -0
- package/dist/core/advisory-judge-response.js +61 -0
- package/dist/core/advisory-judge-response.js.map +1 -0
- package/dist/core/advisory-judge-types.d.ts +53 -0
- package/dist/core/advisory-judge-types.d.ts.map +1 -0
- package/dist/core/advisory-judge-types.js +2 -0
- package/dist/core/advisory-judge-types.js.map +1 -0
- package/dist/core/advisory-judge.d.ts +8 -0
- package/dist/core/advisory-judge.d.ts.map +1 -0
- package/dist/core/advisory-judge.js +178 -0
- package/dist/core/advisory-judge.js.map +1 -0
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +41 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +396 -179
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +28 -4
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction-gate.d.ts +28 -0
- package/dist/core/compaction-gate.d.ts.map +1 -0
- package/dist/core/compaction-gate.js +34 -0
- package/dist/core/compaction-gate.js.map +1 -0
- package/dist/core/completion-sound.d.ts +109 -0
- package/dist/core/completion-sound.d.ts.map +1 -0
- package/dist/core/completion-sound.js +165 -0
- package/dist/core/completion-sound.js.map +1 -0
- package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt-items.js +5 -3
- package/dist/core/context-budget-system-prompt-items.js.map +1 -1
- package/dist/core/domain-loadouts.d.ts.map +1 -1
- package/dist/core/domain-loadouts.js +2 -2
- package/dist/core/domain-loadouts.js.map +1 -1
- package/dist/core/durable-goal-checkpoint.d.ts +6 -0
- package/dist/core/durable-goal-checkpoint.d.ts.map +1 -0
- package/dist/core/durable-goal-checkpoint.js +195 -0
- package/dist/core/durable-goal-checkpoint.js.map +1 -0
- package/dist/core/durable-goal-parse.d.ts +3 -0
- package/dist/core/durable-goal-parse.d.ts.map +1 -0
- package/dist/core/durable-goal-parse.js +86 -0
- package/dist/core/durable-goal-parse.js.map +1 -0
- package/dist/core/durable-goal-reducer.d.ts +3 -0
- package/dist/core/durable-goal-reducer.d.ts.map +1 -0
- package/dist/core/durable-goal-reducer.js +175 -0
- package/dist/core/durable-goal-reducer.js.map +1 -0
- package/dist/core/durable-goal-store.d.ts +19 -0
- package/dist/core/durable-goal-store.d.ts.map +1 -0
- package/dist/core/durable-goal-store.js +126 -0
- package/dist/core/durable-goal-store.js.map +1 -0
- package/dist/core/durable-goal.d.ts +92 -0
- package/dist/core/durable-goal.d.ts.map +1 -0
- package/dist/core/durable-goal.js +62 -0
- package/dist/core/durable-goal.js.map +1 -0
- package/dist/core/extensions/builtin/goal-controller.d.ts +3 -0
- package/dist/core/extensions/builtin/goal-controller.d.ts.map +1 -0
- package/dist/core/extensions/builtin/goal-controller.js +125 -0
- package/dist/core/extensions/builtin/goal-controller.js.map +1 -0
- package/dist/core/extensions/builtin/identical-loop.d.ts +3 -0
- package/dist/core/extensions/builtin/identical-loop.d.ts.map +1 -0
- package/dist/core/extensions/builtin/identical-loop.js +31 -0
- package/dist/core/extensions/builtin/identical-loop.js.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset.d.ts +3 -0
- package/dist/core/extensions/builtin/prompt-preset.d.ts.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset.js +13 -0
- package/dist/core/extensions/builtin/prompt-preset.js.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-repair.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-repair.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-repair.js +12 -0
- package/dist/core/extensions/builtin/tool-pair-repair.js.map +1 -0
- package/dist/core/extensions/types.d.ts +6 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/goal-continuation.d.ts +13 -0
- package/dist/core/goal-continuation.d.ts.map +1 -0
- package/dist/core/goal-continuation.js +10 -0
- package/dist/core/goal-continuation.js.map +1 -0
- package/dist/core/grok-harness.d.ts +1 -1
- package/dist/core/grok-harness.d.ts.map +1 -1
- package/dist/core/grok-harness.js +1 -1
- package/dist/core/grok-harness.js.map +1 -1
- package/dist/core/grok-playbook.d.ts +1 -1
- package/dist/core/grok-playbook.d.ts.map +1 -1
- package/dist/core/grok-playbook.js +1 -1
- package/dist/core/grok-playbook.js.map +1 -1
- package/dist/core/host-resource-probe.d.ts +63 -0
- package/dist/core/host-resource-probe.d.ts.map +1 -0
- package/dist/core/host-resource-probe.js +126 -0
- package/dist/core/host-resource-probe.js.map +1 -0
- package/dist/core/host-resource-snapshot.d.ts +54 -0
- package/dist/core/host-resource-snapshot.d.ts.map +1 -0
- package/dist/core/host-resource-snapshot.js +139 -0
- package/dist/core/host-resource-snapshot.js.map +1 -0
- package/dist/core/identical-loop.d.ts +15 -0
- package/dist/core/identical-loop.d.ts.map +1 -0
- package/dist/core/identical-loop.js +34 -0
- package/dist/core/identical-loop.js.map +1 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-prompt-policy.d.ts +11 -0
- package/dist/core/model-prompt-policy.d.ts.map +1 -0
- package/dist/core/model-prompt-policy.js +17 -0
- package/dist/core/model-prompt-policy.js.map +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +16 -4
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-budget.d.ts +21 -0
- package/dist/core/prompt-budget.d.ts.map +1 -0
- package/dist/core/prompt-budget.js +51 -0
- package/dist/core/prompt-budget.js.map +1 -0
- package/dist/core/prompt-cache.d.ts +14 -0
- package/dist/core/prompt-cache.d.ts.map +1 -0
- package/dist/core/prompt-cache.js +16 -0
- package/dist/core/prompt-cache.js.map +1 -0
- package/dist/core/prompt-preset.d.ts +8 -0
- package/dist/core/prompt-preset.d.ts.map +1 -0
- package/dist/core/prompt-preset.js +56 -0
- package/dist/core/prompt-preset.js.map +1 -0
- package/dist/core/prompt-settlement.d.ts +81 -0
- package/dist/core/prompt-settlement.d.ts.map +1 -0
- package/dist/core/prompt-settlement.js +84 -0
- package/dist/core/prompt-settlement.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +16 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +24 -2
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-retry.d.ts +36 -0
- package/dist/core/provider-retry.d.ts.map +1 -0
- package/dist/core/provider-retry.js +73 -0
- package/dist/core/provider-retry.js.map +1 -0
- package/dist/core/provider-usage.d.ts +16 -2
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +150 -8
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
- package/dist/core/reasoning-router-resolver.js +1 -1
- package/dist/core/reasoning-router-resolver.js.map +1 -1
- package/dist/core/resource-admission-config.d.ts +55 -0
- package/dist/core/resource-admission-config.d.ts.map +1 -0
- package/dist/core/resource-admission-config.js +97 -0
- package/dist/core/resource-admission-config.js.map +1 -0
- package/dist/core/resource-admission.d.ts +81 -0
- package/dist/core/resource-admission.d.ts.map +1 -0
- package/dist/core/resource-admission.js +128 -0
- package/dist/core/resource-admission.js.map +1 -0
- package/dist/core/resource-governor-format.d.ts +50 -0
- package/dist/core/resource-governor-format.d.ts.map +1 -0
- package/dist/core/resource-governor-format.js +113 -0
- package/dist/core/resource-governor-format.js.map +1 -0
- package/dist/core/resource-governor-settings.d.ts +56 -0
- package/dist/core/resource-governor-settings.d.ts.map +1 -0
- package/dist/core/resource-governor-settings.js +89 -0
- package/dist/core/resource-governor-settings.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +32 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/resource-observation-journal.d.ts +74 -0
- package/dist/core/resource-observation-journal.d.ts.map +1 -0
- package/dist/core/resource-observation-journal.js +198 -0
- package/dist/core/resource-observation-journal.js.map +1 -0
- package/dist/core/resource-safety-gate.d.ts +54 -0
- package/dist/core/resource-safety-gate.d.ts.map +1 -0
- package/dist/core/resource-safety-gate.js +51 -0
- package/dist/core/resource-safety-gate.js.map +1 -0
- package/dist/core/run-journal.d.ts.map +1 -1
- package/dist/core/run-journal.js +13 -1
- package/dist/core/run-journal.js.map +1 -1
- package/dist/core/run-resource-lease.d.ts +73 -0
- package/dist/core/run-resource-lease.d.ts.map +1 -0
- package/dist/core/run-resource-lease.js +78 -0
- package/dist/core/run-resource-lease.js.map +1 -0
- package/dist/core/sandbox/backend.d.ts +12 -0
- package/dist/core/sandbox/backend.d.ts.map +1 -1
- package/dist/core/sandbox/backend.js +52 -42
- package/dist/core/sandbox/backend.js.map +1 -1
- package/dist/core/sandbox/policy.d.ts +2 -0
- package/dist/core/sandbox/policy.d.ts.map +1 -1
- package/dist/core/sandbox/policy.js +2 -1
- package/dist/core/sandbox/policy.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-bash-service.d.ts +12 -0
- package/dist/core/session-bash-service.d.ts.map +1 -1
- package/dist/core/session-bash-service.js +14 -0
- package/dist/core/session-bash-service.js.map +1 -1
- package/dist/core/session-system-prompt.d.ts +30 -0
- package/dist/core/session-system-prompt.d.ts.map +1 -0
- package/dist/core/session-system-prompt.js +39 -0
- package/dist/core/session-system-prompt.js.map +1 -0
- package/dist/core/session-termination.d.ts +7 -2
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +29 -1
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +36 -0
- package/dist/core/settings-manager.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/strict-record.d.ts +2 -0
- package/dist/core/strict-record.d.ts.map +1 -0
- package/dist/core/strict-record.js +9 -0
- package/dist/core/strict-record.js.map +1 -0
- package/dist/core/subagent-lane-launcher.d.ts +64 -0
- package/dist/core/subagent-lane-launcher.d.ts.map +1 -0
- package/dist/core/subagent-lane-launcher.js +107 -0
- package/dist/core/subagent-lane-launcher.js.map +1 -0
- package/dist/core/system-cpu-sampler.d.ts +45 -0
- package/dist/core/system-cpu-sampler.d.ts.map +1 -0
- package/dist/core/system-cpu-sampler.js +95 -0
- package/dist/core/system-cpu-sampler.js.map +1 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -8
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tool-pair-repair.d.ts +11 -0
- package/dist/core/tool-pair-repair.d.ts.map +1 -0
- package/dist/core/tool-pair-repair.js +38 -0
- package/dist/core/tool-pair-repair.js.map +1 -0
- package/dist/core/tools/artifact-spill.d.ts +13 -0
- package/dist/core/tools/artifact-spill.d.ts.map +1 -0
- package/dist/core/tools/artifact-spill.js +26 -0
- package/dist/core/tools/artifact-spill.js.map +1 -0
- package/dist/core/tools/bash.d.ts +7 -4
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +8 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/read.d.ts +1 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +10 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +2 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/workload-classifier.d.ts +32 -0
- package/dist/core/workload-classifier.d.ts.map +1 -0
- package/dist/core/workload-classifier.js +66 -0
- package/dist/core/workload-classifier.js.map +1 -0
- package/dist/core/workload-family-matcher.d.ts +3 -0
- package/dist/core/workload-family-matcher.d.ts.map +1 -0
- package/dist/core/workload-family-matcher.js +126 -0
- package/dist/core/workload-family-matcher.js.map +1 -0
- package/dist/core/workload-permit-pool.d.ts +78 -0
- package/dist/core/workload-permit-pool.d.ts.map +1 -0
- package/dist/core/workload-permit-pool.js +138 -0
- package/dist/core/workload-permit-pool.js.map +1 -0
- package/dist/core/workload-shard-executor.d.ts +68 -0
- package/dist/core/workload-shard-executor.d.ts.map +1 -0
- package/dist/core/workload-shard-executor.js +156 -0
- package/dist/core/workload-shard-executor.js.map +1 -0
- package/dist/core/workload-shard-plan.d.ts +81 -0
- package/dist/core/workload-shard-plan.d.ts.map +1 -0
- package/dist/core/workload-shard-plan.js +183 -0
- package/dist/core/workload-shard-plan.js.map +1 -0
- package/dist/core/workload-shard-runner.d.ts +11 -0
- package/dist/core/workload-shard-runner.d.ts.map +1 -0
- package/dist/core/workload-shard-runner.js +98 -0
- package/dist/core/workload-shard-runner.js.map +1 -0
- package/dist/core/workload-shard-store.d.ts +44 -0
- package/dist/core/workload-shard-store.d.ts.map +1 -0
- package/dist/core/workload-shard-store.js +189 -0
- package/dist/core/workload-shard-store.js.map +1 -0
- package/dist/core/workload-sharders.d.ts +47 -0
- package/dist/core/workload-sharders.d.ts.map +1 -0
- package/dist/core/workload-sharders.js +162 -0
- package/dist/core/workload-sharders.js.map +1 -0
- package/dist/core/workload-shell-scan.d.ts +12 -0
- package/dist/core/workload-shell-scan.d.ts.map +1 -0
- package/dist/core/workload-shell-scan.js +79 -0
- package/dist/core/workload-shell-scan.js.map +1 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +14 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +81 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +14 -3
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/docs/adaptorch-preview-spec.md +1 -1
- package/docs/adaptorch-preview.md +2 -2
- package/docs/book-to-skill.md +1 -1
- package/docs/containerization.md +9 -0
- package/docs/docs.json +11 -3
- package/docs/environment-variables.md +11 -4
- package/docs/extensions.md +14 -1
- package/docs/grok-harness.md +35 -12
- package/docs/index.md +7 -6
- package/docs/loadout-domains/grok-harness.md +2 -2
- package/docs/models.md +10 -9
- package/docs/provider-resilience.md +9 -3
- package/docs/providers.md +9 -4
- package/docs/run-protocol.md +32 -0
- package/docs/sdk.md +100 -3
- package/docs/security.md +22 -32
- package/docs/sessions.md +14 -0
- package/docs/settings.md +64 -2
- package/docs/skills.md +16 -0
- package/docs/usage.md +37 -15
- 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/index.ts +6 -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/subagent/agent-capability-router.test.ts +7 -0
- package/examples/extensions/subagent/domain-profiles.ts +0 -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 +7 -9
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Local-only resource observation journal (roadmap §15.1/§15.2/§20.2).
|
|
5
|
+
*
|
|
6
|
+
* A dedicated JSONL artifact under `.omk/runs/<promptRunId>/` — deliberately
|
|
7
|
+
* NOT the hash-chained run journal: §15.2 restricts raw host facts to a
|
|
8
|
+
* separate local-only artifact, and extending the run journal's closed audit
|
|
9
|
+
* union would invalidate old readers. Shard plan/transition entries stay in
|
|
10
|
+
* `workload-shards.jsonl` (they already journal there); this file carries
|
|
11
|
+
* the remaining §20.2 entries.
|
|
12
|
+
*
|
|
13
|
+
* Privacy (§15.2, §20.3, §30): facts are flat primitives only — pressure
|
|
14
|
+
* levels, caps, digests, durations, reason codes. Never raw memory/cpu
|
|
15
|
+
* numbers, hostnames, usernames, or command text. Observability is
|
|
16
|
+
* fail-open: a write/read failure degrades to diagnostics, never breaks the
|
|
17
|
+
* run (probe failure is non-fatal by contract).
|
|
18
|
+
*/
|
|
19
|
+
export const RESOURCE_OBSERVATION_JOURNAL_FILE = "resource-observations.jsonl";
|
|
20
|
+
/** §20.2 journal entry kinds handled by this artifact. */
|
|
21
|
+
export const RESOURCE_OBSERVATION_KINDS = [
|
|
22
|
+
"resource_snapshot_v1",
|
|
23
|
+
"resource_admission_v1",
|
|
24
|
+
"resource_lease_acquired_v1",
|
|
25
|
+
"resource_lease_released_v1",
|
|
26
|
+
"workload_classification_v1",
|
|
27
|
+
"workload_permit_wait_v1",
|
|
28
|
+
"workload_permit_acquired_v1",
|
|
29
|
+
"workload_permit_released_v1",
|
|
30
|
+
"prompt_settled_v1",
|
|
31
|
+
"completion_sound_result_v1",
|
|
32
|
+
];
|
|
33
|
+
const PROTOCOL_KIND_BY_JOURNAL_KIND = {
|
|
34
|
+
resource_snapshot_v1: "resource_snapshot.v1",
|
|
35
|
+
resource_admission_v1: "resource_admission.v1",
|
|
36
|
+
workload_classification_v1: "workload_classification.v1",
|
|
37
|
+
workload_permit_wait_v1: "workload_permit.v1",
|
|
38
|
+
workload_permit_acquired_v1: "workload_permit.v1",
|
|
39
|
+
workload_permit_released_v1: "workload_permit.v1",
|
|
40
|
+
prompt_settled_v1: "prompt_settled.v1",
|
|
41
|
+
completion_sound_result_v1: "notification_result.v1",
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Project a journal record onto the §15.1 protocol observation surface.
|
|
45
|
+
* Lease entries are local-only operational detail and project to null.
|
|
46
|
+
*/
|
|
47
|
+
export function toProtocolObservation(record) {
|
|
48
|
+
const kind = PROTOCOL_KIND_BY_JOURNAL_KIND[record.kind];
|
|
49
|
+
return kind === undefined ? null : { kind, facts: record.facts };
|
|
50
|
+
}
|
|
51
|
+
/** §15.2: probe health and digest only — raw host values never leave the process. */
|
|
52
|
+
export function snapshotObservationFacts(snapshot) {
|
|
53
|
+
return {
|
|
54
|
+
cpuProbe: snapshot.systemCpuPercent !== null,
|
|
55
|
+
memoryProbe: snapshot.processAvailableMemoryBytes !== null || snapshot.hostFreeMemoryBytes !== null,
|
|
56
|
+
heapLimitKnown: snapshot.heapLimitBytes > 0,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** §15.2 example shape: pressure, action, and the three caps. */
|
|
60
|
+
export function admissionObservationFacts(decision) {
|
|
61
|
+
return {
|
|
62
|
+
decisionId: decision.decisionId,
|
|
63
|
+
snapshotDigest: decision.snapshotDigest,
|
|
64
|
+
pressure: decision.pressure,
|
|
65
|
+
action: decision.action,
|
|
66
|
+
maxToolConcurrency: decision.maxToolConcurrency,
|
|
67
|
+
maxParallelLanes: decision.maxParallelLanes,
|
|
68
|
+
maxHeavyProcesses: decision.maxHeavyProcesses,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function classificationObservationFacts(classification) {
|
|
72
|
+
return {
|
|
73
|
+
workloadClass: classification.workloadClass,
|
|
74
|
+
commandFamily: classification.commandFamily,
|
|
75
|
+
complexity: classification.complexity,
|
|
76
|
+
safeToAutoShard: classification.safeToAutoShard,
|
|
77
|
+
reasonCodes: classification.reasonCodes.slice(0, 8).join(","),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function settledObservationFacts(event) {
|
|
81
|
+
return {
|
|
82
|
+
outcome: event.outcome,
|
|
83
|
+
durationMs: event.durationMs,
|
|
84
|
+
...(event.terminationKind !== undefined ? { terminationKind: event.terminationKind } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export function soundObservationFacts(result) {
|
|
88
|
+
return {
|
|
89
|
+
backend: result.backend,
|
|
90
|
+
attempted: result.attempted,
|
|
91
|
+
success: result.success,
|
|
92
|
+
...(result.diagnostic !== undefined ? { diagnostic: result.diagnostic.slice(0, 120) } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const MAX_LINE_BYTES = 8 * 1024;
|
|
96
|
+
const MAX_RECORDS = 10_000;
|
|
97
|
+
export class ResourceObservationJournal {
|
|
98
|
+
journalPath;
|
|
99
|
+
promptRunId;
|
|
100
|
+
now;
|
|
101
|
+
seq = 0;
|
|
102
|
+
disabled = false;
|
|
103
|
+
constructor(journalPath, promptRunId, now = () => new Date()) {
|
|
104
|
+
this.journalPath = journalPath;
|
|
105
|
+
this.promptRunId = promptRunId;
|
|
106
|
+
this.now = now;
|
|
107
|
+
}
|
|
108
|
+
static open(cwd, promptRunId, now) {
|
|
109
|
+
return new ResourceObservationJournal(path.join(cwd, ".omk", "runs", promptRunId, RESOURCE_OBSERVATION_JOURNAL_FILE), promptRunId, now);
|
|
110
|
+
}
|
|
111
|
+
get filePath() {
|
|
112
|
+
return this.journalPath;
|
|
113
|
+
}
|
|
114
|
+
/** Fail-open append: returns false (and stops trying) instead of throwing. */
|
|
115
|
+
record(kind, facts) {
|
|
116
|
+
if (this.disabled || this.seq >= MAX_RECORDS)
|
|
117
|
+
return false;
|
|
118
|
+
const entry = {
|
|
119
|
+
schemaVersion: 1,
|
|
120
|
+
seq: this.seq + 1,
|
|
121
|
+
kind,
|
|
122
|
+
at: this.now().toISOString(),
|
|
123
|
+
promptRunId: this.promptRunId,
|
|
124
|
+
facts,
|
|
125
|
+
};
|
|
126
|
+
const line = `${JSON.stringify(entry)}\n`;
|
|
127
|
+
if (line.length > MAX_LINE_BYTES)
|
|
128
|
+
return false;
|
|
129
|
+
try {
|
|
130
|
+
fs.mkdirSync(path.dirname(this.journalPath), { recursive: true });
|
|
131
|
+
fs.appendFileSync(this.journalPath, line, "utf8");
|
|
132
|
+
this.seq = entry.seq;
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Observability must never break the run; stop retrying this run.
|
|
137
|
+
this.disabled = true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** Fail-open load: malformed lines become diagnostics, never throws. */
|
|
142
|
+
load() {
|
|
143
|
+
let raw;
|
|
144
|
+
try {
|
|
145
|
+
raw = fs.readFileSync(this.journalPath, "utf8");
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return { records: [], diagnostics: [] };
|
|
149
|
+
}
|
|
150
|
+
const records = [];
|
|
151
|
+
const diagnostics = [];
|
|
152
|
+
const lines = raw.split("\n");
|
|
153
|
+
for (let index = 0; index < lines.length && records.length < MAX_RECORDS; index++) {
|
|
154
|
+
const line = lines[index].trim();
|
|
155
|
+
if (line === "")
|
|
156
|
+
continue;
|
|
157
|
+
const parsed = parseObservationLine(line);
|
|
158
|
+
if (parsed === null) {
|
|
159
|
+
diagnostics.push(`line ${index + 1}: invalid observation record`);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
records.push(parsed);
|
|
163
|
+
}
|
|
164
|
+
return { records, diagnostics };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const KIND_SET = new Set(RESOURCE_OBSERVATION_KINDS);
|
|
168
|
+
function parseObservationLine(line) {
|
|
169
|
+
if (line.length > MAX_LINE_BYTES)
|
|
170
|
+
return null;
|
|
171
|
+
let value;
|
|
172
|
+
try {
|
|
173
|
+
value = JSON.parse(line);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
179
|
+
return null;
|
|
180
|
+
const record = value;
|
|
181
|
+
if (record.schemaVersion !== 1)
|
|
182
|
+
return null;
|
|
183
|
+
if (typeof record.seq !== "number" || !Number.isSafeInteger(record.seq) || record.seq < 1)
|
|
184
|
+
return null;
|
|
185
|
+
if (typeof record.kind !== "string" || !KIND_SET.has(record.kind))
|
|
186
|
+
return null;
|
|
187
|
+
if (typeof record.at !== "string" || typeof record.promptRunId !== "string")
|
|
188
|
+
return null;
|
|
189
|
+
if (typeof record.facts !== "object" || record.facts === null || Array.isArray(record.facts))
|
|
190
|
+
return null;
|
|
191
|
+
for (const factValue of Object.values(record.facts)) {
|
|
192
|
+
const kind = typeof factValue;
|
|
193
|
+
if (factValue !== null && kind !== "string" && kind !== "number" && kind !== "boolean")
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
return record;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=resource-observation-journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-observation-journal.js","sourceRoot":"","sources":["../../src/core/resource-observation-journal.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { CompletionSoundResult } from \"./completion-sound.ts\";\nimport type { PromptSettledEvent } from \"./prompt-settlement.ts\";\nimport type { ResourceAdmissionDecision } from \"./resource-admission.ts\";\nimport type { WorkloadClassification } from \"./workload-classifier.ts\";\n\n/**\n * Local-only resource observation journal (roadmap §15.1/§15.2/§20.2).\n *\n * A dedicated JSONL artifact under `.omk/runs/<promptRunId>/` — deliberately\n * NOT the hash-chained run journal: §15.2 restricts raw host facts to a\n * separate local-only artifact, and extending the run journal's closed audit\n * union would invalidate old readers. Shard plan/transition entries stay in\n * `workload-shards.jsonl` (they already journal there); this file carries\n * the remaining §20.2 entries.\n *\n * Privacy (§15.2, §20.3, §30): facts are flat primitives only — pressure\n * levels, caps, digests, durations, reason codes. Never raw memory/cpu\n * numbers, hostnames, usernames, or command text. Observability is\n * fail-open: a write/read failure degrades to diagnostics, never breaks the\n * run (probe failure is non-fatal by contract).\n */\n\nexport const RESOURCE_OBSERVATION_JOURNAL_FILE = \"resource-observations.jsonl\";\n\n/** §20.2 journal entry kinds handled by this artifact. */\nexport const RESOURCE_OBSERVATION_KINDS = [\n\t\"resource_snapshot_v1\",\n\t\"resource_admission_v1\",\n\t\"resource_lease_acquired_v1\",\n\t\"resource_lease_released_v1\",\n\t\"workload_classification_v1\",\n\t\"workload_permit_wait_v1\",\n\t\"workload_permit_acquired_v1\",\n\t\"workload_permit_released_v1\",\n\t\"prompt_settled_v1\",\n\t\"completion_sound_result_v1\",\n] as const;\n\nexport type ResourceObservationKind = (typeof RESOURCE_OBSERVATION_KINDS)[number];\n\nexport type ResourceObservationFacts = Readonly<Record<string, string | number | boolean | null>>;\n\nexport interface ResourceObservationRecord {\n\treadonly schemaVersion: 1;\n\treadonly seq: number;\n\treadonly kind: ResourceObservationKind;\n\treadonly at: string;\n\treadonly promptRunId: string;\n\treadonly facts: ResourceObservationFacts;\n}\n\n/** §15.1 protocol observation projection of one journal record. */\nexport interface ResourceProtocolObservation {\n\treadonly kind:\n\t\t| \"resource_snapshot.v1\"\n\t\t| \"resource_admission.v1\"\n\t\t| \"workload_classification.v1\"\n\t\t| \"workload_permit.v1\"\n\t\t| \"prompt_settled.v1\"\n\t\t| \"notification_result.v1\";\n\treadonly facts: ResourceObservationFacts;\n}\n\nconst PROTOCOL_KIND_BY_JOURNAL_KIND: Readonly<\n\tPartial<Record<ResourceObservationKind, ResourceProtocolObservation[\"kind\"]>>\n> = {\n\tresource_snapshot_v1: \"resource_snapshot.v1\",\n\tresource_admission_v1: \"resource_admission.v1\",\n\tworkload_classification_v1: \"workload_classification.v1\",\n\tworkload_permit_wait_v1: \"workload_permit.v1\",\n\tworkload_permit_acquired_v1: \"workload_permit.v1\",\n\tworkload_permit_released_v1: \"workload_permit.v1\",\n\tprompt_settled_v1: \"prompt_settled.v1\",\n\tcompletion_sound_result_v1: \"notification_result.v1\",\n};\n\n/**\n * Project a journal record onto the §15.1 protocol observation surface.\n * Lease entries are local-only operational detail and project to null.\n */\nexport function toProtocolObservation(record: ResourceObservationRecord): ResourceProtocolObservation | null {\n\tconst kind = PROTOCOL_KIND_BY_JOURNAL_KIND[record.kind];\n\treturn kind === undefined ? null : { kind, facts: record.facts };\n}\n\n/** §15.2: probe health and digest only — raw host values never leave the process. */\nexport function snapshotObservationFacts(snapshot: {\n\treadonly systemCpuPercent: number | null;\n\treadonly processAvailableMemoryBytes: number | null;\n\treadonly hostFreeMemoryBytes: number | null;\n\treadonly heapLimitBytes: number;\n}): ResourceObservationFacts {\n\treturn {\n\t\tcpuProbe: snapshot.systemCpuPercent !== null,\n\t\tmemoryProbe: snapshot.processAvailableMemoryBytes !== null || snapshot.hostFreeMemoryBytes !== null,\n\t\theapLimitKnown: snapshot.heapLimitBytes > 0,\n\t};\n}\n\n/** §15.2 example shape: pressure, action, and the three caps. */\nexport function admissionObservationFacts(decision: ResourceAdmissionDecision): ResourceObservationFacts {\n\treturn {\n\t\tdecisionId: decision.decisionId,\n\t\tsnapshotDigest: decision.snapshotDigest,\n\t\tpressure: decision.pressure,\n\t\taction: decision.action,\n\t\tmaxToolConcurrency: decision.maxToolConcurrency,\n\t\tmaxParallelLanes: decision.maxParallelLanes,\n\t\tmaxHeavyProcesses: decision.maxHeavyProcesses,\n\t};\n}\n\nexport function classificationObservationFacts(classification: WorkloadClassification): ResourceObservationFacts {\n\treturn {\n\t\tworkloadClass: classification.workloadClass,\n\t\tcommandFamily: classification.commandFamily,\n\t\tcomplexity: classification.complexity,\n\t\tsafeToAutoShard: classification.safeToAutoShard,\n\t\treasonCodes: classification.reasonCodes.slice(0, 8).join(\",\"),\n\t};\n}\n\nexport function settledObservationFacts(event: PromptSettledEvent): ResourceObservationFacts {\n\treturn {\n\t\toutcome: event.outcome,\n\t\tdurationMs: event.durationMs,\n\t\t...(event.terminationKind !== undefined ? { terminationKind: event.terminationKind } : {}),\n\t};\n}\n\nexport function soundObservationFacts(result: CompletionSoundResult): ResourceObservationFacts {\n\treturn {\n\t\tbackend: result.backend,\n\t\tattempted: result.attempted,\n\t\tsuccess: result.success,\n\t\t...(result.diagnostic !== undefined ? { diagnostic: result.diagnostic.slice(0, 120) } : {}),\n\t};\n}\n\nconst MAX_LINE_BYTES = 8 * 1024;\nconst MAX_RECORDS = 10_000;\n\nexport interface ResourceObservationLoadResult {\n\treadonly records: readonly ResourceObservationRecord[];\n\treadonly diagnostics: readonly string[];\n}\n\nexport class ResourceObservationJournal {\n\tprivate readonly journalPath: string;\n\tprivate readonly promptRunId: string;\n\tprivate readonly now: () => Date;\n\tprivate seq = 0;\n\tprivate disabled = false;\n\n\tconstructor(journalPath: string, promptRunId: string, now: () => Date = () => new Date()) {\n\t\tthis.journalPath = journalPath;\n\t\tthis.promptRunId = promptRunId;\n\t\tthis.now = now;\n\t}\n\n\tstatic open(cwd: string, promptRunId: string, now?: () => Date): ResourceObservationJournal {\n\t\treturn new ResourceObservationJournal(\n\t\t\tpath.join(cwd, \".omk\", \"runs\", promptRunId, RESOURCE_OBSERVATION_JOURNAL_FILE),\n\t\t\tpromptRunId,\n\t\t\tnow,\n\t\t);\n\t}\n\n\tget filePath(): string {\n\t\treturn this.journalPath;\n\t}\n\n\t/** Fail-open append: returns false (and stops trying) instead of throwing. */\n\trecord(kind: ResourceObservationKind, facts: ResourceObservationFacts): boolean {\n\t\tif (this.disabled || this.seq >= MAX_RECORDS) return false;\n\t\tconst entry: ResourceObservationRecord = {\n\t\t\tschemaVersion: 1,\n\t\t\tseq: this.seq + 1,\n\t\t\tkind,\n\t\t\tat: this.now().toISOString(),\n\t\t\tpromptRunId: this.promptRunId,\n\t\t\tfacts,\n\t\t};\n\t\tconst line = `${JSON.stringify(entry)}\\n`;\n\t\tif (line.length > MAX_LINE_BYTES) return false;\n\t\ttry {\n\t\t\tfs.mkdirSync(path.dirname(this.journalPath), { recursive: true });\n\t\t\tfs.appendFileSync(this.journalPath, line, \"utf8\");\n\t\t\tthis.seq = entry.seq;\n\t\t\treturn true;\n\t\t} catch {\n\t\t\t// Observability must never break the run; stop retrying this run.\n\t\t\tthis.disabled = true;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Fail-open load: malformed lines become diagnostics, never throws. */\n\tload(): ResourceObservationLoadResult {\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = fs.readFileSync(this.journalPath, \"utf8\");\n\t\t} catch {\n\t\t\treturn { records: [], diagnostics: [] };\n\t\t}\n\t\tconst records: ResourceObservationRecord[] = [];\n\t\tconst diagnostics: string[] = [];\n\t\tconst lines = raw.split(\"\\n\");\n\t\tfor (let index = 0; index < lines.length && records.length < MAX_RECORDS; index++) {\n\t\t\tconst line = lines[index].trim();\n\t\t\tif (line === \"\") continue;\n\t\t\tconst parsed = parseObservationLine(line);\n\t\t\tif (parsed === null) {\n\t\t\t\tdiagnostics.push(`line ${index + 1}: invalid observation record`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trecords.push(parsed);\n\t\t}\n\t\treturn { records, diagnostics };\n\t}\n}\n\nconst KIND_SET: ReadonlySet<string> = new Set(RESOURCE_OBSERVATION_KINDS);\n\nfunction parseObservationLine(line: string): ResourceObservationRecord | null {\n\tif (line.length > MAX_LINE_BYTES) return null;\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(line);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n\tconst record = value as Record<string, unknown>;\n\tif (record.schemaVersion !== 1) return null;\n\tif (typeof record.seq !== \"number\" || !Number.isSafeInteger(record.seq) || record.seq < 1) return null;\n\tif (typeof record.kind !== \"string\" || !KIND_SET.has(record.kind)) return null;\n\tif (typeof record.at !== \"string\" || typeof record.promptRunId !== \"string\") return null;\n\tif (typeof record.facts !== \"object\" || record.facts === null || Array.isArray(record.facts)) return null;\n\tfor (const factValue of Object.values(record.facts)) {\n\t\tconst kind = typeof factValue;\n\t\tif (factValue !== null && kind !== \"string\" && kind !== \"number\" && kind !== \"boolean\") return null;\n\t}\n\treturn record as unknown as ResourceObservationRecord;\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ResourceAdmissionDecision, ResourcePressure, ResourceReasonCode } from "./resource-admission.ts";
|
|
2
|
+
import type { WorkloadClassification } from "./workload-classifier.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Pure resource safety gate decision (OMK v0.97.x roadmap §11, M3/PR4).
|
|
5
|
+
*
|
|
6
|
+
* Maps (workload classification × admission decision) to a gate verdict.
|
|
7
|
+
* This module holds no permits and spawns nothing — the shared permit pool
|
|
8
|
+
* and the bash/launch integration consume these verdicts in the next slice.
|
|
9
|
+
*
|
|
10
|
+
* Order contract (§9.4, §22.2): command safety runs FIRST and stays
|
|
11
|
+
* authoritative. The input requires the literal `commandSafety: "allowed"`
|
|
12
|
+
* so a call site cannot even type-check unless the command already passed
|
|
13
|
+
* the safety gate; resource pressure can only throttle or defer an
|
|
14
|
+
* already-allowed command, never re-admit a blocked one.
|
|
15
|
+
*
|
|
16
|
+
* Fail-closed only where side effects matter (§4.6): heavy work and opaque
|
|
17
|
+
* complex shell are deferred at critical pressure, while light reads and
|
|
18
|
+
* bounded IO stay allowed so the agent remains usable (§21).
|
|
19
|
+
*/
|
|
20
|
+
export interface ResourceSafetyGateInput {
|
|
21
|
+
/** §9.4: structurally requires the command-safety gate to have allowed the command. */
|
|
22
|
+
readonly commandSafety: "allowed";
|
|
23
|
+
readonly classification: WorkloadClassification;
|
|
24
|
+
readonly decision: ResourceAdmissionDecision;
|
|
25
|
+
}
|
|
26
|
+
/** §11.3 structured block result. Bounded: no raw host values, paths, or identities. */
|
|
27
|
+
export interface ResourcePressureBlock {
|
|
28
|
+
readonly kind: "resource_pressure";
|
|
29
|
+
readonly pressure: ResourcePressure;
|
|
30
|
+
readonly action: "defer-heavy";
|
|
31
|
+
readonly reasonCodes: readonly ResourceReasonCode[];
|
|
32
|
+
readonly requiredAction: string;
|
|
33
|
+
}
|
|
34
|
+
export type ResourceSafetyGateVerdict = {
|
|
35
|
+
readonly kind: "allow";
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: "require-permit";
|
|
38
|
+
readonly weight: 1 | 2;
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: "block";
|
|
41
|
+
readonly block: ResourcePressureBlock;
|
|
42
|
+
};
|
|
43
|
+
export declare const RESOURCE_PRESSURE_REQUIRED_ACTION = "Create a bounded shard plan or free resources before retrying.";
|
|
44
|
+
/**
|
|
45
|
+
* Decide the §11.2 gate behavior for one already-safety-allowed command.
|
|
46
|
+
*
|
|
47
|
+
* | pressure | light | io | cpu | heavy / memory | unknown complex shell |
|
|
48
|
+
* | ----------- | ----- | ----- | -------- | -------------- | --------------------- |
|
|
49
|
+
* | normal | allow | allow | permit | permit | permit, no rewrite |
|
|
50
|
+
* | constrained | allow | allow | permit 1 | permit 1 | permit 1, no rewrite |
|
|
51
|
+
* | critical | allow | allow | permit 1 | block/defer | block/defer |
|
|
52
|
+
*/
|
|
53
|
+
export declare function decideResourceSafetyGate(input: ResourceSafetyGateInput): ResourceSafetyGateVerdict;
|
|
54
|
+
//# sourceMappingURL=resource-safety-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-safety-gate.d.ts","sourceRoot":"","sources":["../../src/core/resource-safety-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC/G,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEvE;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,uBAAuB;IACvC,wFAAuF;IACvF,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,sBAAsB,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,yBAAyB,CAAC;CAC7C;AAED,yFAAwF;AACxF,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,yBAAyB,GAClC;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAErE,eAAO,MAAM,iCAAiC,mEAAmE,CAAC;AAElH;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,uBAAuB,GAAG,yBAAyB,CA2ClG","sourcesContent":["import type { ResourceAdmissionDecision, ResourcePressure, ResourceReasonCode } from \"./resource-admission.ts\";\nimport type { WorkloadClassification } from \"./workload-classifier.ts\";\n\n/**\n * Pure resource safety gate decision (OMK v0.97.x roadmap §11, M3/PR4).\n *\n * Maps (workload classification × admission decision) to a gate verdict.\n * This module holds no permits and spawns nothing — the shared permit pool\n * and the bash/launch integration consume these verdicts in the next slice.\n *\n * Order contract (§9.4, §22.2): command safety runs FIRST and stays\n * authoritative. The input requires the literal `commandSafety: \"allowed\"`\n * so a call site cannot even type-check unless the command already passed\n * the safety gate; resource pressure can only throttle or defer an\n * already-allowed command, never re-admit a blocked one.\n *\n * Fail-closed only where side effects matter (§4.6): heavy work and opaque\n * complex shell are deferred at critical pressure, while light reads and\n * bounded IO stay allowed so the agent remains usable (§21).\n */\n\nexport interface ResourceSafetyGateInput {\n\t/** §9.4: structurally requires the command-safety gate to have allowed the command. */\n\treadonly commandSafety: \"allowed\";\n\treadonly classification: WorkloadClassification;\n\treadonly decision: ResourceAdmissionDecision;\n}\n\n/** §11.3 structured block result. Bounded: no raw host values, paths, or identities. */\nexport interface ResourcePressureBlock {\n\treadonly kind: \"resource_pressure\";\n\treadonly pressure: ResourcePressure;\n\treadonly action: \"defer-heavy\";\n\treadonly reasonCodes: readonly ResourceReasonCode[];\n\treadonly requiredAction: string;\n}\n\nexport type ResourceSafetyGateVerdict =\n\t| { readonly kind: \"allow\" }\n\t| { readonly kind: \"require-permit\"; readonly weight: 1 | 2 }\n\t| { readonly kind: \"block\"; readonly block: ResourcePressureBlock };\n\nexport const RESOURCE_PRESSURE_REQUIRED_ACTION = \"Create a bounded shard plan or free resources before retrying.\";\n\n/**\n * Decide the §11.2 gate behavior for one already-safety-allowed command.\n *\n * | pressure | light | io | cpu | heavy / memory | unknown complex shell |\n * | ----------- | ----- | ----- | -------- | -------------- | --------------------- |\n * | normal | allow | allow | permit | permit | permit, no rewrite |\n * | constrained | allow | allow | permit 1 | permit 1 | permit 1, no rewrite |\n * | critical | allow | allow | permit 1 | block/defer | block/defer |\n */\nexport function decideResourceSafetyGate(input: ResourceSafetyGateInput): ResourceSafetyGateVerdict {\n\tconst { classification, decision } = input;\n\tconst critical = decision.pressure === \"critical\";\n\n\tif (classification.workloadClass === \"light\") {\n\t\treturn { kind: \"allow\" };\n\t}\n\tif (classification.workloadClass === \"io\") {\n\t\t// Critical still allows bounded IO; the run lease already caps overall\n\t\t// tool concurrency (§11.2 \"allow with cap\").\n\t\treturn { kind: \"allow\" };\n\t}\n\tif (classification.workloadClass === \"cpu\") {\n\t\treturn { kind: \"require-permit\", weight: 1 };\n\t}\n\n\t// heavy, memory (heavy-equivalent — the §11.2 table has no softer column\n\t// for memory-bound work), and unknown workloads.\n\tconst heavyEquivalent = classification.workloadClass === \"heavy\" || classification.workloadClass === \"memory\";\n\tconst opaqueComplexShell =\n\t\tclassification.workloadClass === \"unknown\" && classification.complexity === \"complex-shell\";\n\n\tif (critical && (heavyEquivalent || opaqueComplexShell)) {\n\t\treturn {\n\t\t\tkind: \"block\",\n\t\t\tblock: {\n\t\t\t\tkind: \"resource_pressure\",\n\t\t\t\tpressure: decision.pressure,\n\t\t\t\taction: \"defer-heavy\",\n\t\t\t\treasonCodes: decision.reasons,\n\t\t\t\trequiredAction: RESOURCE_PRESSURE_REQUIRED_ACTION,\n\t\t\t},\n\t\t};\n\t}\n\tif (heavyEquivalent) {\n\t\t// §10.3: container builds may consume double weight in the permit pool.\n\t\treturn { kind: \"require-permit\", weight: classification.commandFamily === \"container-build\" ? 2 : 1 };\n\t}\n\t// unknown (simple argv or, below critical, complex shell): permit-gated so\n\t// fanout stays bounded, but never blocked outright below critical, and a\n\t// simple unknown binary stays runnable even at critical (§21: the agent\n\t// must remain usable).\n\treturn { kind: \"require-permit\", weight: 1 };\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const RESOURCE_PRESSURE_REQUIRED_ACTION = "Create a bounded shard plan or free resources before retrying.";
|
|
2
|
+
/**
|
|
3
|
+
* Decide the §11.2 gate behavior for one already-safety-allowed command.
|
|
4
|
+
*
|
|
5
|
+
* | pressure | light | io | cpu | heavy / memory | unknown complex shell |
|
|
6
|
+
* | ----------- | ----- | ----- | -------- | -------------- | --------------------- |
|
|
7
|
+
* | normal | allow | allow | permit | permit | permit, no rewrite |
|
|
8
|
+
* | constrained | allow | allow | permit 1 | permit 1 | permit 1, no rewrite |
|
|
9
|
+
* | critical | allow | allow | permit 1 | block/defer | block/defer |
|
|
10
|
+
*/
|
|
11
|
+
export function decideResourceSafetyGate(input) {
|
|
12
|
+
const { classification, decision } = input;
|
|
13
|
+
const critical = decision.pressure === "critical";
|
|
14
|
+
if (classification.workloadClass === "light") {
|
|
15
|
+
return { kind: "allow" };
|
|
16
|
+
}
|
|
17
|
+
if (classification.workloadClass === "io") {
|
|
18
|
+
// Critical still allows bounded IO; the run lease already caps overall
|
|
19
|
+
// tool concurrency (§11.2 "allow with cap").
|
|
20
|
+
return { kind: "allow" };
|
|
21
|
+
}
|
|
22
|
+
if (classification.workloadClass === "cpu") {
|
|
23
|
+
return { kind: "require-permit", weight: 1 };
|
|
24
|
+
}
|
|
25
|
+
// heavy, memory (heavy-equivalent — the §11.2 table has no softer column
|
|
26
|
+
// for memory-bound work), and unknown workloads.
|
|
27
|
+
const heavyEquivalent = classification.workloadClass === "heavy" || classification.workloadClass === "memory";
|
|
28
|
+
const opaqueComplexShell = classification.workloadClass === "unknown" && classification.complexity === "complex-shell";
|
|
29
|
+
if (critical && (heavyEquivalent || opaqueComplexShell)) {
|
|
30
|
+
return {
|
|
31
|
+
kind: "block",
|
|
32
|
+
block: {
|
|
33
|
+
kind: "resource_pressure",
|
|
34
|
+
pressure: decision.pressure,
|
|
35
|
+
action: "defer-heavy",
|
|
36
|
+
reasonCodes: decision.reasons,
|
|
37
|
+
requiredAction: RESOURCE_PRESSURE_REQUIRED_ACTION,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (heavyEquivalent) {
|
|
42
|
+
// §10.3: container builds may consume double weight in the permit pool.
|
|
43
|
+
return { kind: "require-permit", weight: classification.commandFamily === "container-build" ? 2 : 1 };
|
|
44
|
+
}
|
|
45
|
+
// unknown (simple argv or, below critical, complex shell): permit-gated so
|
|
46
|
+
// fanout stays bounded, but never blocked outright below critical, and a
|
|
47
|
+
// simple unknown binary stays runnable even at critical (§21: the agent
|
|
48
|
+
// must remain usable).
|
|
49
|
+
return { kind: "require-permit", weight: 1 };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=resource-safety-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-safety-gate.js","sourceRoot":"","sources":["../../src/core/resource-safety-gate.ts"],"names":[],"mappings":"AA0CA,MAAM,CAAC,MAAM,iCAAiC,GAAG,gEAAgE,CAAC;AAElH;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAA8B,EAA6B;IACnG,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,KAAK,UAAU,CAAC;IAElD,IAAI,cAAc,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;QAC9C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC1B,CAAC;IACD,IAAI,cAAc,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3C,uEAAuE;QACvE,8CAA6C;QAC7C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC1B,CAAC;IACD,IAAI,cAAc,CAAC,aAAa,KAAK,KAAK,EAAE,CAAC;QAC5C,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,4EAAyE;IACzE,iDAAiD;IACjD,MAAM,eAAe,GAAG,cAAc,CAAC,aAAa,KAAK,OAAO,IAAI,cAAc,CAAC,aAAa,KAAK,QAAQ,CAAC;IAC9G,MAAM,kBAAkB,GACvB,cAAc,CAAC,aAAa,KAAK,SAAS,IAAI,cAAc,CAAC,UAAU,KAAK,eAAe,CAAC;IAE7F,IAAI,QAAQ,IAAI,CAAC,eAAe,IAAI,kBAAkB,CAAC,EAAE,CAAC;QACzD,OAAO;YACN,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACN,IAAI,EAAE,mBAAmB;gBACzB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,MAAM,EAAE,aAAa;gBACrB,WAAW,EAAE,QAAQ,CAAC,OAAO;gBAC7B,cAAc,EAAE,iCAAiC;aACjD;SACD,CAAC;IACH,CAAC;IACD,IAAI,eAAe,EAAE,CAAC;QACrB,yEAAwE;QACxE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,cAAc,CAAC,aAAa,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvG,CAAC;IACD,2EAA2E;IAC3E,yEAAyE;IACzE,yEAAwE;IACxE,uBAAuB;IACvB,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AAAA,CAC7C","sourcesContent":["import type { ResourceAdmissionDecision, ResourcePressure, ResourceReasonCode } from \"./resource-admission.ts\";\nimport type { WorkloadClassification } from \"./workload-classifier.ts\";\n\n/**\n * Pure resource safety gate decision (OMK v0.97.x roadmap §11, M3/PR4).\n *\n * Maps (workload classification × admission decision) to a gate verdict.\n * This module holds no permits and spawns nothing — the shared permit pool\n * and the bash/launch integration consume these verdicts in the next slice.\n *\n * Order contract (§9.4, §22.2): command safety runs FIRST and stays\n * authoritative. The input requires the literal `commandSafety: \"allowed\"`\n * so a call site cannot even type-check unless the command already passed\n * the safety gate; resource pressure can only throttle or defer an\n * already-allowed command, never re-admit a blocked one.\n *\n * Fail-closed only where side effects matter (§4.6): heavy work and opaque\n * complex shell are deferred at critical pressure, while light reads and\n * bounded IO stay allowed so the agent remains usable (§21).\n */\n\nexport interface ResourceSafetyGateInput {\n\t/** §9.4: structurally requires the command-safety gate to have allowed the command. */\n\treadonly commandSafety: \"allowed\";\n\treadonly classification: WorkloadClassification;\n\treadonly decision: ResourceAdmissionDecision;\n}\n\n/** §11.3 structured block result. Bounded: no raw host values, paths, or identities. */\nexport interface ResourcePressureBlock {\n\treadonly kind: \"resource_pressure\";\n\treadonly pressure: ResourcePressure;\n\treadonly action: \"defer-heavy\";\n\treadonly reasonCodes: readonly ResourceReasonCode[];\n\treadonly requiredAction: string;\n}\n\nexport type ResourceSafetyGateVerdict =\n\t| { readonly kind: \"allow\" }\n\t| { readonly kind: \"require-permit\"; readonly weight: 1 | 2 }\n\t| { readonly kind: \"block\"; readonly block: ResourcePressureBlock };\n\nexport const RESOURCE_PRESSURE_REQUIRED_ACTION = \"Create a bounded shard plan or free resources before retrying.\";\n\n/**\n * Decide the §11.2 gate behavior for one already-safety-allowed command.\n *\n * | pressure | light | io | cpu | heavy / memory | unknown complex shell |\n * | ----------- | ----- | ----- | -------- | -------------- | --------------------- |\n * | normal | allow | allow | permit | permit | permit, no rewrite |\n * | constrained | allow | allow | permit 1 | permit 1 | permit 1, no rewrite |\n * | critical | allow | allow | permit 1 | block/defer | block/defer |\n */\nexport function decideResourceSafetyGate(input: ResourceSafetyGateInput): ResourceSafetyGateVerdict {\n\tconst { classification, decision } = input;\n\tconst critical = decision.pressure === \"critical\";\n\n\tif (classification.workloadClass === \"light\") {\n\t\treturn { kind: \"allow\" };\n\t}\n\tif (classification.workloadClass === \"io\") {\n\t\t// Critical still allows bounded IO; the run lease already caps overall\n\t\t// tool concurrency (§11.2 \"allow with cap\").\n\t\treturn { kind: \"allow\" };\n\t}\n\tif (classification.workloadClass === \"cpu\") {\n\t\treturn { kind: \"require-permit\", weight: 1 };\n\t}\n\n\t// heavy, memory (heavy-equivalent — the §11.2 table has no softer column\n\t// for memory-bound work), and unknown workloads.\n\tconst heavyEquivalent = classification.workloadClass === \"heavy\" || classification.workloadClass === \"memory\";\n\tconst opaqueComplexShell =\n\t\tclassification.workloadClass === \"unknown\" && classification.complexity === \"complex-shell\";\n\n\tif (critical && (heavyEquivalent || opaqueComplexShell)) {\n\t\treturn {\n\t\t\tkind: \"block\",\n\t\t\tblock: {\n\t\t\t\tkind: \"resource_pressure\",\n\t\t\t\tpressure: decision.pressure,\n\t\t\t\taction: \"defer-heavy\",\n\t\t\t\treasonCodes: decision.reasons,\n\t\t\t\trequiredAction: RESOURCE_PRESSURE_REQUIRED_ACTION,\n\t\t\t},\n\t\t};\n\t}\n\tif (heavyEquivalent) {\n\t\t// §10.3: container builds may consume double weight in the permit pool.\n\t\treturn { kind: \"require-permit\", weight: classification.commandFamily === \"container-build\" ? 2 : 1 };\n\t}\n\t// unknown (simple argv or, below critical, complex shell): permit-gated so\n\t// fanout stays bounded, but never blocked outright below critical, and a\n\t// simple unknown binary stays runnable even at critical (§21: the agent\n\t// must remain usable).\n\treturn { kind: \"require-permit\", weight: 1 };\n}\n"]}
|