open-multi-agent-kit 0.95.1 → 0.96.0
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 +37 -0
- package/README.md +16 -1
- package/dist/approvals/approval-receipt-store.d.ts +18 -0
- package/dist/approvals/approval-receipt-store.d.ts.map +1 -0
- package/dist/approvals/approval-receipt-store.js +194 -0
- package/dist/approvals/approval-receipt-store.js.map +1 -0
- package/dist/approvals/approval-receipt.d.ts +43 -0
- package/dist/approvals/approval-receipt.d.ts.map +1 -0
- package/dist/approvals/approval-receipt.js +208 -0
- package/dist/approvals/approval-receipt.js.map +1 -0
- package/dist/approvals/approval-verifier.d.ts +17 -0
- package/dist/approvals/approval-verifier.d.ts.map +1 -0
- package/dist/approvals/approval-verifier.js +23 -0
- package/dist/approvals/approval-verifier.js.map +1 -0
- package/dist/approvals/plannotator-approval-bridge.d.ts +58 -0
- package/dist/approvals/plannotator-approval-bridge.d.ts.map +1 -0
- package/dist/approvals/plannotator-approval-bridge.js +169 -0
- package/dist/approvals/plannotator-approval-bridge.js.map +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/commands/package-doctor-cli.d.ts +13 -0
- package/dist/commands/package-doctor-cli.d.ts.map +1 -0
- package/dist/commands/package-doctor-cli.js +80 -0
- package/dist/commands/package-doctor-cli.js.map +1 -0
- package/dist/commands/router-feedback-cli.d.ts +11 -0
- package/dist/commands/router-feedback-cli.d.ts.map +1 -0
- package/dist/commands/router-feedback-cli.js +99 -0
- package/dist/commands/router-feedback-cli.js.map +1 -0
- package/dist/commands/stats-cli.d.ts +20 -0
- package/dist/commands/stats-cli.d.ts.map +1 -0
- package/dist/commands/stats-cli.js +99 -0
- package/dist/commands/stats-cli.js.map +1 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +4 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +99 -31
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +624 -216
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +8 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/transaction.d.ts +9 -0
- package/dist/core/compaction/transaction.d.ts.map +1 -1
- package/dist/core/compaction/transaction.js +17 -2
- package/dist/core/compaction/transaction.js.map +1 -1
- package/dist/core/context-budget-governor-v2.d.ts +1 -1
- package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
- package/dist/core/context-budget-governor-v2.js +1 -1
- package/dist/core/context-budget-governor-v2.js.map +1 -1
- package/dist/core/context-budget-system-prompt.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt.js +18 -2
- package/dist/core/context-budget-system-prompt.js.map +1 -1
- package/dist/core/context-budget-v2-cache-disk.d.ts +109 -0
- package/dist/core/context-budget-v2-cache-disk.d.ts.map +1 -0
- package/dist/core/context-budget-v2-cache-disk.js +343 -0
- package/dist/core/context-budget-v2-cache-disk.js.map +1 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts +22 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.js +4 -4
- package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-cache.d.ts +1 -0
- package/dist/core/context-budget-v2-cache.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache.js +1 -0
- package/dist/core/context-budget-v2-cache.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +17 -14
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +1 -0
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +45 -22
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +4 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/mcp/client.d.ts +105 -0
- package/dist/core/mcp/client.d.ts.map +1 -0
- package/dist/core/mcp/client.js +198 -0
- package/dist/core/mcp/client.js.map +1 -0
- package/dist/core/mcp/config.d.ts +23 -0
- package/dist/core/mcp/config.d.ts.map +1 -0
- package/dist/core/mcp/config.js +89 -0
- package/dist/core/mcp/config.js.map +1 -0
- package/dist/core/mcp/index.d.ts +15 -0
- package/dist/core/mcp/index.d.ts.map +1 -0
- package/dist/core/mcp/index.js +15 -0
- package/dist/core/mcp/index.js.map +1 -0
- package/dist/core/mcp/manager.d.ts +84 -0
- package/dist/core/mcp/manager.d.ts.map +1 -0
- package/dist/core/mcp/manager.js +173 -0
- package/dist/core/mcp/manager.js.map +1 -0
- package/dist/core/mcp/protocol.d.ts +59 -0
- package/dist/core/mcp/protocol.d.ts.map +1 -0
- package/dist/core/mcp/protocol.js +103 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/stdio-transport.d.ts +63 -0
- package/dist/core/mcp/stdio-transport.d.ts.map +1 -0
- package/dist/core/mcp/stdio-transport.js +132 -0
- package/dist/core/mcp/stdio-transport.js.map +1 -0
- package/dist/core/mcp/tools.d.ts +47 -0
- package/dist/core/mcp/tools.d.ts.map +1 -0
- package/dist/core/mcp/tools.js +102 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/package-archive.d.ts +3 -0
- package/dist/core/package-archive.d.ts.map +1 -0
- package/dist/core/package-archive.js +161 -0
- package/dist/core/package-archive.js.map +1 -0
- package/dist/core/package-doctor-source-scan.d.ts +13 -0
- package/dist/core/package-doctor-source-scan.d.ts.map +1 -0
- package/dist/core/package-doctor-source-scan.js +124 -0
- package/dist/core/package-doctor-source-scan.js.map +1 -0
- package/dist/core/package-doctor.d.ts +41 -0
- package/dist/core/package-doctor.d.ts.map +1 -0
- package/dist/core/package-doctor.js +145 -0
- package/dist/core/package-doctor.js.map +1 -0
- package/dist/core/package-manager.d.ts +10 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +175 -42
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/package-manifest.d.ts +26 -0
- package/dist/core/package-manifest.d.ts.map +1 -0
- package/dist/core/package-manifest.js +85 -0
- package/dist/core/package-manifest.js.map +1 -0
- package/dist/core/pi-compat.d.ts +5 -0
- package/dist/core/pi-compat.d.ts.map +1 -0
- package/dist/core/pi-compat.js +18 -0
- package/dist/core/pi-compat.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +7 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +11 -0
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/reasoning-router-bias.d.ts +10 -14
- package/dist/core/reasoning-router-bias.d.ts.map +1 -1
- package/dist/core/reasoning-router-bias.js +22 -15
- package/dist/core/reasoning-router-bias.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +9 -1
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +20 -5
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/redaction.d.ts +2 -5
- package/dist/core/redaction.d.ts.map +1 -1
- package/dist/core/redaction.js +14 -1
- package/dist/core/redaction.js.map +1 -1
- package/dist/core/repository-learning-scope.d.ts +10 -0
- package/dist/core/repository-learning-scope.d.ts.map +1 -0
- package/dist/core/repository-learning-scope.js +42 -0
- package/dist/core/repository-learning-scope.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +16 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/router-feedback-collector.d.ts +2 -1
- package/dist/core/router-feedback-collector.d.ts.map +1 -1
- package/dist/core/router-feedback-collector.js +2 -2
- package/dist/core/router-feedback-collector.js.map +1 -1
- package/dist/core/runtime-provenance.d.ts +54 -0
- package/dist/core/runtime-provenance.d.ts.map +1 -0
- package/dist/core/runtime-provenance.js +115 -0
- package/dist/core/runtime-provenance.js.map +1 -0
- package/dist/core/sandbox/backend.d.ts.map +1 -1
- package/dist/core/sandbox/backend.js +39 -21
- package/dist/core/sandbox/backend.js.map +1 -1
- package/dist/core/sandbox/default-policy.d.ts +4 -5
- package/dist/core/sandbox/default-policy.d.ts.map +1 -1
- package/dist/core/sandbox/default-policy.js +9 -11
- package/dist/core/sandbox/default-policy.js.map +1 -1
- package/dist/core/session-bash-runtime.d.ts +4 -4
- package/dist/core/session-bash-runtime.d.ts.map +1 -1
- package/dist/core/session-bash-runtime.js +6 -5
- package/dist/core/session-bash-runtime.js.map +1 -1
- package/dist/core/session-compaction-service.d.ts.map +1 -1
- package/dist/core/session-compaction-service.js +7 -7
- package/dist/core/session-compaction-service.js.map +1 -1
- package/dist/core/session-manager.d.ts +4 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +47 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +11 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-orchestration.d.ts.map +1 -1
- package/dist/core/subagent-orchestration.js +4 -2
- package/dist/core/subagent-orchestration.js.map +1 -1
- package/dist/core/system-prompt.d.ts +9 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +10 -4
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/diagnostics.d.ts.map +1 -1
- package/dist/core/tools/diagnostics.js +8 -2
- package/dist/core/tools/diagnostics.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +15 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/turn-metrics.d.ts +135 -0
- package/dist/core/turn-metrics.d.ts.map +1 -0
- package/dist/core/turn-metrics.js +261 -0
- package/dist/core/turn-metrics.js.map +1 -0
- package/dist/core/verified-bash-runtime.d.ts.map +1 -1
- package/dist/core/verified-bash-runtime.js +10 -4
- package/dist/core/verified-bash-runtime.js.map +1 -1
- package/dist/guardrails/evidence-protocol.d.ts +10 -0
- package/dist/guardrails/evidence-protocol.d.ts.map +1 -0
- package/dist/guardrails/evidence-protocol.js +34 -0
- package/dist/guardrails/evidence-protocol.js.map +1 -0
- package/dist/guardrails/evidence-system.d.ts +3 -1
- package/dist/guardrails/evidence-system.d.ts.map +1 -1
- package/dist/guardrails/evidence-system.js +22 -14
- package/dist/guardrails/evidence-system.js.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.d.ts +7 -0
- package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.js +42 -1
- package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -1
- package/dist/guardrails/replay-payload-hash.d.ts +6 -0
- package/dist/guardrails/replay-payload-hash.d.ts.map +1 -0
- package/dist/guardrails/replay-payload-hash.js +24 -0
- package/dist/guardrails/replay-payload-hash.js.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +18 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.js +2 -2
- package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +3 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +40 -12
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.d.ts +14 -2
- package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.js +106 -19
- package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +104 -17
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +1 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/types/evidence.d.ts +11 -3
- package/dist/types/evidence.d.ts.map +1 -1
- package/dist/types/evidence.js.map +1 -1
- package/docs/book-to-skill.md +79 -0
- package/docs/compaction.md +35 -3
- package/docs/containerization.md +14 -2
- package/docs/docs.json +16 -0
- package/docs/environment-variables.md +1 -1
- package/docs/extensions.md +75 -16
- package/docs/index.md +3 -0
- package/docs/mcp.md +97 -0
- package/docs/metrics.md +87 -0
- package/docs/models.md +12 -0
- package/docs/packages.md +25 -4
- package/docs/provider-resilience.md +37 -56
- package/docs/providers.md +5 -1
- package/docs/run-protocol.md +72 -0
- package/docs/sdk.md +40 -6
- package/docs/sessions.md +6 -0
- package/docs/settings.md +10 -7
- package/docs/skills.md +9 -1
- package/docs/usage.md +14 -4
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/plannotator-approval-bridge.ts +83 -0
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +21 -11
- package/examples/extensions/subagent/adaptive-agent-runtime.ts +9 -3
- package/examples/extensions/subagent/agents/planner.md +0 -2
- package/examples/extensions/subagent/agents/reviewer.md +0 -2
- package/examples/extensions/subagent/agents/scout.md +0 -2
- package/examples/extensions/subagent/agents/worker.md +0 -1
- package/examples/extensions/subagent/agents.test.ts +9 -0
- package/examples/extensions/subagent/agents.ts +11 -4
- package/examples/extensions/subagent/deadline-budget.test.ts +32 -0
- package/examples/extensions/subagent/deadline-budget.ts +25 -1
- package/examples/extensions/subagent/fixtures/fake-omk-json.mjs +10 -0
- package/examples/extensions/subagent/index.ts +234 -55
- package/examples/extensions/subagent/subagent-execution-policy.test.ts +27 -0
- package/examples/extensions/subagent/subagent-extension-smoke.test.ts +167 -2
- package/examples/extensions/subagent/workflow-graph.test.ts +80 -0
- package/examples/extensions/subagent/workflow-graph.ts +89 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +275 -439
- package/package.json +11 -8
|
@@ -11,6 +11,7 @@ interface SmokeToolResult {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
interface SmokeTool {
|
|
14
|
+
resolveTimeoutMs?(context: { thinkingLevel?: string }): number | undefined;
|
|
14
15
|
execute(
|
|
15
16
|
toolCallId: string,
|
|
16
17
|
params: unknown,
|
|
@@ -28,26 +29,31 @@ interface SmokeDetails {
|
|
|
28
29
|
readonly deadline?: { readonly outcome: string; readonly attempts: readonly unknown[] };
|
|
29
30
|
}[];
|
|
30
31
|
readonly executionBudget: {
|
|
32
|
+
readonly unbounded?: boolean;
|
|
31
33
|
readonly hardDeadlineMs: number;
|
|
32
34
|
readonly plannedShards: number;
|
|
33
35
|
readonly completedShards: number;
|
|
34
36
|
readonly resumeCount: number;
|
|
35
37
|
};
|
|
38
|
+
readonly graph?: { readonly waves: readonly (readonly string[])[]; readonly completedNodeIds: readonly string[] };
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
const cleanupPaths: string[] = [];
|
|
39
42
|
const originalArgvEntry = process.argv[1];
|
|
40
43
|
const originalAgentDir = process.env.OMK_CODING_AGENT_DIR;
|
|
44
|
+
const originalExpectedModel = process.env.OMK_EXPECTED_MODEL;
|
|
41
45
|
|
|
42
46
|
afterEach(async () => {
|
|
43
47
|
process.argv[1] = originalArgvEntry;
|
|
44
48
|
if (originalAgentDir === undefined) delete process.env.OMK_CODING_AGENT_DIR;
|
|
45
49
|
else process.env.OMK_CODING_AGENT_DIR = originalAgentDir;
|
|
50
|
+
if (originalExpectedModel === undefined) delete process.env.OMK_EXPECTED_MODEL;
|
|
51
|
+
else process.env.OMK_EXPECTED_MODEL = originalExpectedModel;
|
|
46
52
|
await Promise.all(cleanupPaths.splice(0).map((entry) => fs.promises.rm(entry, { recursive: true, force: true })));
|
|
47
53
|
});
|
|
48
54
|
|
|
49
55
|
describe("subagent extension registration and spawn smoke", () => {
|
|
50
|
-
it("
|
|
56
|
+
it("inherits the selected session model across the managed process boundary", async () => {
|
|
51
57
|
const cwd = await fs.promises.mkdtemp(path.join(os.tmpdir(), "omk-subagent-extension-smoke-"));
|
|
52
58
|
cleanupPaths.push(cwd);
|
|
53
59
|
const projectAgentsDir = path.join(cwd, ".omk", "agents");
|
|
@@ -61,6 +67,7 @@ describe("subagent extension registration and spawn smoke", () => {
|
|
|
61
67
|
);
|
|
62
68
|
process.argv[1] = path.join(import.meta.dirname, "fixtures", "fake-omk-json.mjs");
|
|
63
69
|
process.env.OMK_CODING_AGENT_DIR = agentHome;
|
|
70
|
+
process.env.OMK_EXPECTED_MODEL = "openai-codex/session-selected-model";
|
|
64
71
|
|
|
65
72
|
let registered: unknown;
|
|
66
73
|
const api = {
|
|
@@ -84,7 +91,7 @@ describe("subagent extension registration and spawn smoke", () => {
|
|
|
84
91
|
},
|
|
85
92
|
new AbortController().signal,
|
|
86
93
|
undefined,
|
|
87
|
-
{ cwd, hasUI: false },
|
|
94
|
+
{ cwd, hasUI: false, model: { provider: "openai-codex", id: "session-selected-model" } },
|
|
88
95
|
);
|
|
89
96
|
const details = result.details as SmokeDetails;
|
|
90
97
|
|
|
@@ -105,6 +112,164 @@ describe("subagent extension registration and spawn smoke", () => {
|
|
|
105
112
|
});
|
|
106
113
|
expect(await fs.promises.stat(path.join(agentHome, "state", "subagent-deadline-profiles.json"))).toBeDefined();
|
|
107
114
|
}, 120_000);
|
|
115
|
+
|
|
116
|
+
it("prefers an explicit agent model over the inherited session model", async () => {
|
|
117
|
+
const cwd = await fs.promises.mkdtemp(path.join(os.tmpdir(), "omk-subagent-model-smoke-"));
|
|
118
|
+
cleanupPaths.push(cwd);
|
|
119
|
+
const projectAgentsDir = path.join(cwd, ".omk", "agents");
|
|
120
|
+
const agentHome = path.join(cwd, "agent-home");
|
|
121
|
+
await fs.promises.mkdir(projectAgentsDir, { recursive: true });
|
|
122
|
+
await fs.promises.mkdir(agentHome, { recursive: true });
|
|
123
|
+
await fs.promises.writeFile(
|
|
124
|
+
path.join(projectAgentsDir, "fixture-agent.md"),
|
|
125
|
+
"---\nname: fixture-agent\ndescription: Offline extension smoke fixture\nmodel: agent-pinned-model\n---\nReturn the fixture result.\n",
|
|
126
|
+
"utf8",
|
|
127
|
+
);
|
|
128
|
+
process.argv[1] = path.join(import.meta.dirname, "fixtures", "fake-omk-json.mjs");
|
|
129
|
+
process.env.OMK_CODING_AGENT_DIR = agentHome;
|
|
130
|
+
process.env.OMK_EXPECTED_MODEL = "agent-pinned-model";
|
|
131
|
+
|
|
132
|
+
let registered: unknown;
|
|
133
|
+
const api = {
|
|
134
|
+
registerTool(tool: unknown) {
|
|
135
|
+
registered = tool;
|
|
136
|
+
},
|
|
137
|
+
} as unknown as ExtensionAPI;
|
|
138
|
+
const { default: registerSubagent } = await import("./index.ts");
|
|
139
|
+
registerSubagent(api);
|
|
140
|
+
if (!isSmokeTool(registered)) throw new Error("subagent tool was not registered");
|
|
141
|
+
|
|
142
|
+
const result = await registered.execute(
|
|
143
|
+
"fixture-model-call",
|
|
144
|
+
{
|
|
145
|
+
agent: "fixture-agent",
|
|
146
|
+
task: "Run the pinned-model fixture.",
|
|
147
|
+
agentScope: "project",
|
|
148
|
+
confirmProjectAgents: false,
|
|
149
|
+
},
|
|
150
|
+
new AbortController().signal,
|
|
151
|
+
undefined,
|
|
152
|
+
{ cwd, hasUI: false, model: { id: "session-selected-model" } },
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
expect(result.isError).not.toBe(true);
|
|
156
|
+
expect(result.content[0]?.text).toContain("fixture subagent completed");
|
|
157
|
+
}, 120_000);
|
|
158
|
+
|
|
159
|
+
it("runs validated graph waves and records the graph plan", async () => {
|
|
160
|
+
const cwd = await fs.promises.mkdtemp(path.join(os.tmpdir(), "omk-subagent-graph-smoke-"));
|
|
161
|
+
cleanupPaths.push(cwd);
|
|
162
|
+
const projectAgentsDir = path.join(cwd, ".omk", "agents");
|
|
163
|
+
const agentHome = path.join(cwd, "agent-home");
|
|
164
|
+
await fs.promises.mkdir(projectAgentsDir, { recursive: true });
|
|
165
|
+
await fs.promises.mkdir(agentHome, { recursive: true });
|
|
166
|
+
await fs.promises.writeFile(
|
|
167
|
+
path.join(projectAgentsDir, "fixture-agent.md"),
|
|
168
|
+
"---\nname: fixture-agent\ndescription: Offline extension smoke fixture\n---\nReturn the fixture result.\n",
|
|
169
|
+
"utf8",
|
|
170
|
+
);
|
|
171
|
+
process.argv[1] = path.join(import.meta.dirname, "fixtures", "fake-omk-json.mjs");
|
|
172
|
+
process.env.OMK_CODING_AGENT_DIR = agentHome;
|
|
173
|
+
|
|
174
|
+
let registered: unknown;
|
|
175
|
+
const api = {
|
|
176
|
+
registerTool(tool: unknown) {
|
|
177
|
+
registered = tool;
|
|
178
|
+
},
|
|
179
|
+
} as unknown as ExtensionAPI;
|
|
180
|
+
const { default: registerSubagent } = await import("./index.ts");
|
|
181
|
+
registerSubagent(api);
|
|
182
|
+
if (!isSmokeTool(registered)) throw new Error("subagent tool was not registered");
|
|
183
|
+
|
|
184
|
+
const result = await registered.execute(
|
|
185
|
+
"fixture-graph-call",
|
|
186
|
+
{
|
|
187
|
+
graph: [
|
|
188
|
+
{ id: "research-a", agent: "fixture-agent", task: "Research A." },
|
|
189
|
+
{ id: "research-b", agent: "fixture-agent", task: "Research B." },
|
|
190
|
+
{
|
|
191
|
+
id: "synthesize",
|
|
192
|
+
agent: "fixture-agent",
|
|
193
|
+
task: "Synthesize:\n{dependencies}",
|
|
194
|
+
dependsOn: ["research-a", "research-b"],
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
agentScope: "project",
|
|
198
|
+
confirmProjectAgents: false,
|
|
199
|
+
executionBudgetMs: 120_000,
|
|
200
|
+
},
|
|
201
|
+
new AbortController().signal,
|
|
202
|
+
undefined,
|
|
203
|
+
{ cwd, hasUI: false },
|
|
204
|
+
);
|
|
205
|
+
const details = result.details as SmokeDetails;
|
|
206
|
+
|
|
207
|
+
expect(result.isError).not.toBe(true);
|
|
208
|
+
expect(details.mode).toBe("graph");
|
|
209
|
+
expect(details.results).toHaveLength(3);
|
|
210
|
+
expect(details.graph).toEqual({
|
|
211
|
+
waves: [["research-a", "research-b"], ["synthesize"]],
|
|
212
|
+
completedNodeIds: ["research-a", "research-b", "synthesize"],
|
|
213
|
+
});
|
|
214
|
+
}, 120_000);
|
|
215
|
+
|
|
216
|
+
it("honors an explicit internal execution budget in Ultra while removing parallel limits", async () => {
|
|
217
|
+
const cwd = await fs.promises.mkdtemp(path.join(os.tmpdir(), "omk-subagent-ultra-smoke-"));
|
|
218
|
+
cleanupPaths.push(cwd);
|
|
219
|
+
const projectAgentsDir = path.join(cwd, ".omk", "agents");
|
|
220
|
+
const agentHome = path.join(cwd, "agent-home");
|
|
221
|
+
await fs.promises.mkdir(projectAgentsDir, { recursive: true });
|
|
222
|
+
await fs.promises.mkdir(agentHome, { recursive: true });
|
|
223
|
+
await fs.promises.writeFile(
|
|
224
|
+
path.join(projectAgentsDir, "fixture-agent.md"),
|
|
225
|
+
"---\nname: fixture-agent\ndescription: Offline extension smoke fixture\n---\nReturn the fixture result.\n",
|
|
226
|
+
"utf8",
|
|
227
|
+
);
|
|
228
|
+
process.argv[1] = path.join(import.meta.dirname, "fixtures", "fake-omk-json.mjs");
|
|
229
|
+
process.env.OMK_CODING_AGENT_DIR = agentHome;
|
|
230
|
+
|
|
231
|
+
let registered: unknown;
|
|
232
|
+
const api = {
|
|
233
|
+
registerTool(tool: unknown) {
|
|
234
|
+
registered = tool;
|
|
235
|
+
},
|
|
236
|
+
} as unknown as ExtensionAPI;
|
|
237
|
+
const { default: registerSubagent } = await import("./index.ts");
|
|
238
|
+
registerSubagent(api);
|
|
239
|
+
if (!isSmokeTool(registered)) throw new Error("subagent tool was not registered");
|
|
240
|
+
|
|
241
|
+
expect(registered.resolveTimeoutMs?.({ thinkingLevel: "ultra" })).toBe(0);
|
|
242
|
+
const result = await registered.execute(
|
|
243
|
+
"fixture-ultra-call",
|
|
244
|
+
{
|
|
245
|
+
tasks: Array.from({ length: 9 }, (_, index) => ({
|
|
246
|
+
agent: "fixture-agent",
|
|
247
|
+
task: `Run bounded offline fixture ${index + 1}.`,
|
|
248
|
+
})),
|
|
249
|
+
agentScope: "project",
|
|
250
|
+
confirmProjectAgents: false,
|
|
251
|
+
executionBudgetMs: 120_000,
|
|
252
|
+
maxResumeAttempts: 1,
|
|
253
|
+
},
|
|
254
|
+
new AbortController().signal,
|
|
255
|
+
undefined,
|
|
256
|
+
{ cwd, hasUI: false, thinkingLevel: "ultra" },
|
|
257
|
+
);
|
|
258
|
+
const details = result.details as SmokeDetails;
|
|
259
|
+
|
|
260
|
+
expect(result.isError).not.toBe(true);
|
|
261
|
+
expect(details.mode).toBe("parallel");
|
|
262
|
+
expect(details.results).toHaveLength(9);
|
|
263
|
+
expect(details.results.map((entry) => ({ exitCode: entry.exitCode, outcome: entry.deadline?.outcome }))).toEqual(
|
|
264
|
+
Array.from({ length: 9 }, () => ({ exitCode: 0, outcome: "completed" })),
|
|
265
|
+
);
|
|
266
|
+
expect(details.executionBudget).toMatchObject({
|
|
267
|
+
unbounded: false,
|
|
268
|
+
hardDeadlineMs: 120_000,
|
|
269
|
+
plannedShards: 9,
|
|
270
|
+
completedShards: 9,
|
|
271
|
+
});
|
|
272
|
+
}, 120_000);
|
|
108
273
|
});
|
|
109
274
|
|
|
110
275
|
function isSmokeTool(value: unknown): value is SmokeTool {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { GraphValidationError, planTaskGraph, renderDependencyContext } from "./workflow-graph.ts";
|
|
3
|
+
|
|
4
|
+
describe("subagent workflow graph", () => {
|
|
5
|
+
it("builds deterministic parallel execution waves", () => {
|
|
6
|
+
const plan = planTaskGraph([
|
|
7
|
+
{ id: "research", agent: "scout", task: "Research" },
|
|
8
|
+
{ id: "lint", agent: "reviewer", task: "Lint" },
|
|
9
|
+
{ id: "build", agent: "worker", task: "Build", dependsOn: ["research"] },
|
|
10
|
+
{ id: "review", agent: "reviewer", task: "Review", dependsOn: ["build", "lint"] },
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
expect(plan.waves).toEqual([["research", "lint"], ["build"], ["review"]]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it.each([
|
|
17
|
+
[
|
|
18
|
+
"duplicate ids",
|
|
19
|
+
[
|
|
20
|
+
{ id: "same", agent: "scout", task: "A" },
|
|
21
|
+
{ id: "same", agent: "worker", task: "B" },
|
|
22
|
+
],
|
|
23
|
+
/duplicate node id 'same'/,
|
|
24
|
+
],
|
|
25
|
+
[
|
|
26
|
+
"unknown dependencies",
|
|
27
|
+
[{ id: "build", agent: "worker", task: "Build", dependsOn: ["missing"] }],
|
|
28
|
+
/unknown node 'missing'/,
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
"self dependencies",
|
|
32
|
+
[{ id: "loop", agent: "worker", task: "Build", dependsOn: ["loop"] }],
|
|
33
|
+
/cannot depend on itself/,
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
"cycles",
|
|
37
|
+
[
|
|
38
|
+
{ id: "a", agent: "worker", task: "A", dependsOn: ["b"] },
|
|
39
|
+
{ id: "b", agent: "worker", task: "B", dependsOn: ["a"] },
|
|
40
|
+
],
|
|
41
|
+
/cycle detected: a, b/,
|
|
42
|
+
],
|
|
43
|
+
] as const)("fails closed on %s", (_name, graph, expected) => {
|
|
44
|
+
expect(() => planTaskGraph([...graph])).toThrowError(GraphValidationError);
|
|
45
|
+
expect(() => planTaskGraph([...graph])).toThrow(expected);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("injects only declared dependency outputs", () => {
|
|
49
|
+
const task = {
|
|
50
|
+
id: "build",
|
|
51
|
+
agent: "worker",
|
|
52
|
+
task: "Use this evidence:\n{dependencies}",
|
|
53
|
+
dependsOn: ["research"],
|
|
54
|
+
};
|
|
55
|
+
const rendered = renderDependencyContext(
|
|
56
|
+
task,
|
|
57
|
+
new Map([
|
|
58
|
+
["research", "verified finding"],
|
|
59
|
+
["unrelated", "must not leak"],
|
|
60
|
+
]),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(rendered).toContain("### research\nverified finding");
|
|
64
|
+
expect(rendered).not.toContain("must not leak");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("does not append dependency output unless the task opts in", () => {
|
|
68
|
+
const task = { id: "build", agent: "worker", task: "Build", dependsOn: ["research"] };
|
|
69
|
+
expect(renderDependencyContext(task, new Map([["research", "large output"]]))).toBe("Build");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("bounds each dependency handoff without splitting UTF-8", () => {
|
|
73
|
+
const task = { id: "build", agent: "worker", task: "{dependencies}", dependsOn: ["research"] };
|
|
74
|
+
const rendered = renderDependencyContext(task, new Map([["research", "한".repeat(20_000)]]));
|
|
75
|
+
|
|
76
|
+
expect(Buffer.byteLength(rendered, "utf8")).toBeLessThan(17_000);
|
|
77
|
+
expect(rendered).toContain("[dependency output truncated]");
|
|
78
|
+
expect(rendered).not.toContain("�");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export interface GraphTask {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly agent: string;
|
|
4
|
+
readonly task: string;
|
|
5
|
+
readonly cwd?: string;
|
|
6
|
+
readonly dependsOn?: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface TaskGraphPlan {
|
|
10
|
+
readonly tasks: ReadonlyMap<string, GraphTask>;
|
|
11
|
+
readonly waves: readonly (readonly string[])[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class GraphValidationError extends Error {
|
|
15
|
+
constructor(message: string) {
|
|
16
|
+
super(`Invalid task graph: ${message}`);
|
|
17
|
+
this.name = "GraphValidationError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function planTaskGraph(tasks: readonly GraphTask[]): TaskGraphPlan {
|
|
22
|
+
if (tasks.length === 0) throw new GraphValidationError("at least one node is required");
|
|
23
|
+
|
|
24
|
+
const byId = new Map<string, GraphTask>();
|
|
25
|
+
for (const task of tasks) {
|
|
26
|
+
if (task.id.trim() === "") throw new GraphValidationError("node id must not be empty");
|
|
27
|
+
if (byId.has(task.id)) throw new GraphValidationError(`duplicate node id '${task.id}'`);
|
|
28
|
+
byId.set(task.id, task);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const dependents = new Map<string, string[]>();
|
|
32
|
+
const remainingDependencies = new Map<string, number>();
|
|
33
|
+
for (const task of tasks) {
|
|
34
|
+
const dependencies = new Set(task.dependsOn ?? []);
|
|
35
|
+
if (dependencies.has(task.id)) throw new GraphValidationError(`node '${task.id}' cannot depend on itself`);
|
|
36
|
+
for (const dependency of dependencies) {
|
|
37
|
+
if (!byId.has(dependency)) {
|
|
38
|
+
throw new GraphValidationError(`node '${task.id}' depends on unknown node '${dependency}'`);
|
|
39
|
+
}
|
|
40
|
+
const targets = dependents.get(dependency) ?? [];
|
|
41
|
+
targets.push(task.id);
|
|
42
|
+
dependents.set(dependency, targets);
|
|
43
|
+
}
|
|
44
|
+
remainingDependencies.set(task.id, dependencies.size);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const waves: string[][] = [];
|
|
48
|
+
let ready = tasks.filter((task) => remainingDependencies.get(task.id) === 0).map((task) => task.id);
|
|
49
|
+
let visited = 0;
|
|
50
|
+
while (ready.length > 0) {
|
|
51
|
+
waves.push(ready);
|
|
52
|
+
visited += ready.length;
|
|
53
|
+
const next = new Set<string>();
|
|
54
|
+
for (const id of ready) {
|
|
55
|
+
for (const dependent of dependents.get(id) ?? []) {
|
|
56
|
+
const remaining = (remainingDependencies.get(dependent) ?? 0) - 1;
|
|
57
|
+
remainingDependencies.set(dependent, remaining);
|
|
58
|
+
if (remaining === 0) next.add(dependent);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
ready = tasks.filter((task) => next.has(task.id)).map((task) => task.id);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (visited !== tasks.length) {
|
|
65
|
+
const cycleNodes = tasks.filter((task) => (remainingDependencies.get(task.id) ?? 0) > 0).map((task) => task.id);
|
|
66
|
+
throw new GraphValidationError(`cycle detected: ${cycleNodes.join(", ")}`);
|
|
67
|
+
}
|
|
68
|
+
return { tasks: byId, waves };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const MAX_DEPENDENCY_OUTPUT_BYTES = 16 * 1024;
|
|
72
|
+
|
|
73
|
+
function truncateUtf8(value: string): string {
|
|
74
|
+
const encoded = Buffer.from(value, "utf8");
|
|
75
|
+
if (encoded.length <= MAX_DEPENDENCY_OUTPUT_BYTES) return value;
|
|
76
|
+
const suffix = "\n\n[dependency output truncated]";
|
|
77
|
+
const bodyLimit = MAX_DEPENDENCY_OUTPUT_BYTES - Buffer.byteLength(suffix, "utf8");
|
|
78
|
+
let body = encoded.subarray(0, bodyLimit).toString("utf8");
|
|
79
|
+
if (body.endsWith("�")) body = body.slice(0, -1);
|
|
80
|
+
return `${body}${suffix}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function renderDependencyContext(task: GraphTask, outputs: ReadonlyMap<string, string>): string {
|
|
84
|
+
if (!task.task.includes("{dependencies}")) return task.task;
|
|
85
|
+
const context = (task.dependsOn ?? [])
|
|
86
|
+
.map((id) => `### ${id}\n${truncateUtf8(outputs.get(id) ?? "(no output)")}`)
|
|
87
|
+
.join("\n\n");
|
|
88
|
+
return task.task.split("{dependencies}").join(context || "(no dependencies)");
|
|
89
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omk-extension-with-deps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.96.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omk-extension-with-deps",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.96.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "2.1.3"
|
|
12
12
|
},
|