@consensus-tools/universal 0.9.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/LICENSE +201 -0
- package/README.md +451 -0
- package/dist/__tests__/defaults.test.d.ts +2 -0
- package/dist/__tests__/defaults.test.d.ts.map +1 -0
- package/dist/__tests__/defaults.test.js +55 -0
- package/dist/__tests__/defaults.test.js.map +1 -0
- package/dist/__tests__/fail-policy.test.d.ts +2 -0
- package/dist/__tests__/fail-policy.test.d.ts.map +1 -0
- package/dist/__tests__/fail-policy.test.js +80 -0
- package/dist/__tests__/fail-policy.test.js.map +1 -0
- package/dist/__tests__/frameworks.test.d.ts +2 -0
- package/dist/__tests__/frameworks.test.d.ts.map +1 -0
- package/dist/__tests__/frameworks.test.js +86 -0
- package/dist/__tests__/frameworks.test.js.map +1 -0
- package/dist/__tests__/logger.test.d.ts +2 -0
- package/dist/__tests__/logger.test.d.ts.map +1 -0
- package/dist/__tests__/logger.test.js +77 -0
- package/dist/__tests__/logger.test.js.map +1 -0
- package/dist/__tests__/resolve.test.d.ts +2 -0
- package/dist/__tests__/resolve.test.d.ts.map +1 -0
- package/dist/__tests__/resolve.test.js +71 -0
- package/dist/__tests__/resolve.test.js.map +1 -0
- package/dist/__tests__/wrap.test.d.ts +2 -0
- package/dist/__tests__/wrap.test.d.ts.map +1 -0
- package/dist/__tests__/wrap.test.js +90 -0
- package/dist/__tests__/wrap.test.js.map +1 -0
- package/dist/defaults.d.ts +20 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +48 -0
- package/dist/defaults.js.map +1 -0
- package/dist/errors.d.ts +23 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +31 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +239 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +55 -0
- package/dist/logger.js.map +1 -0
- package/dist/resolve.d.ts +9 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +25 -0
- package/dist/resolve.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +82 -0
- package/src/__tests__/defaults.test.ts +71 -0
- package/src/__tests__/fail-policy.test.ts +107 -0
- package/src/__tests__/frameworks.test.ts +106 -0
- package/src/__tests__/logger.test.ts +93 -0
- package/src/__tests__/resolve.test.ts +80 -0
- package/src/__tests__/wrap.test.ts +110 -0
- package/src/consensus-llm.test.ts +260 -0
- package/src/defaults.ts +124 -0
- package/src/errors.ts +35 -0
- package/src/index.ts +386 -0
- package/src/logger.ts +65 -0
- package/src/persona-reviewer-factory.ts +387 -0
- package/src/reputation-manager.test.ts +131 -0
- package/src/reputation-manager.ts +168 -0
- package/src/resolve.ts +30 -0
- package/src/risk-tiers.test.ts +36 -0
- package/src/risk-tiers.ts +49 -0
- package/src/types.ts +127 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { DEFAULTS, DEFAULT_GUARD, DEFAULT_POLICY, DEFAULT_PERSONA_COUNT, DEFAULT_PERSONA_TRIO, policyToStrategy, } from "../defaults.js";
|
|
3
|
+
import { ConfigError } from "../errors.js";
|
|
4
|
+
describe("DEFAULTS", () => {
|
|
5
|
+
it("provides full defaults matching expected values", () => {
|
|
6
|
+
expect(DEFAULTS.policy).toBe("majority");
|
|
7
|
+
expect(DEFAULTS.guards).toEqual(["agent_action"]);
|
|
8
|
+
expect(DEFAULTS.failPolicy).toBe("closed");
|
|
9
|
+
expect(DEFAULTS.storage).toBe("memory");
|
|
10
|
+
expect(DEFAULTS.logger).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
it("exports expected guard and policy constants", () => {
|
|
13
|
+
expect(DEFAULT_GUARD).toBe("agent_action");
|
|
14
|
+
expect(DEFAULT_POLICY).toBe("majority");
|
|
15
|
+
expect(DEFAULT_PERSONA_COUNT).toBe(3);
|
|
16
|
+
expect(DEFAULT_PERSONA_TRIO).toEqual(["security", "compliance", "user-impact"]);
|
|
17
|
+
});
|
|
18
|
+
it("merges partial config with defaults", () => {
|
|
19
|
+
const partial = { policy: "unanimous", failPolicy: "open" };
|
|
20
|
+
const merged = { ...DEFAULTS, ...partial };
|
|
21
|
+
expect(merged.policy).toBe("unanimous");
|
|
22
|
+
expect(merged.failPolicy).toBe("open");
|
|
23
|
+
// Untouched defaults remain
|
|
24
|
+
expect(merged.guards).toEqual(["agent_action"]);
|
|
25
|
+
expect(merged.storage).toBe("memory");
|
|
26
|
+
expect(merged.logger).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe("policyToStrategy", () => {
|
|
30
|
+
it("maps 'majority' to { strategy: 'majority' }", () => {
|
|
31
|
+
expect(policyToStrategy("majority")).toEqual({ strategy: "majority" });
|
|
32
|
+
});
|
|
33
|
+
it("maps 'supermajority' to { strategy: 'threshold', threshold: 0.67 }", () => {
|
|
34
|
+
expect(policyToStrategy("supermajority")).toEqual({ strategy: "threshold", threshold: 0.67 });
|
|
35
|
+
});
|
|
36
|
+
it("maps 'unanimous' to { strategy: 'unanimous' }", () => {
|
|
37
|
+
expect(policyToStrategy("unanimous")).toEqual({ strategy: "unanimous" });
|
|
38
|
+
});
|
|
39
|
+
it("maps 'threshold:0.8' to { strategy: 'threshold', threshold: 0.8 }", () => {
|
|
40
|
+
expect(policyToStrategy("threshold:0.8")).toEqual({ strategy: "threshold", threshold: 0.8 });
|
|
41
|
+
});
|
|
42
|
+
it("throws ConfigError for unknown policy name", () => {
|
|
43
|
+
expect(() => policyToStrategy("bogus")).toThrow(ConfigError);
|
|
44
|
+
expect(() => policyToStrategy("bogus")).toThrow('Unknown policy "bogus"');
|
|
45
|
+
});
|
|
46
|
+
it("throws ConfigError for invalid threshold value", () => {
|
|
47
|
+
expect(() => policyToStrategy("threshold:abc")).toThrow(ConfigError);
|
|
48
|
+
expect(() => policyToStrategy("threshold:abc")).toThrow("Invalid threshold value");
|
|
49
|
+
});
|
|
50
|
+
it("throws ConfigError for threshold out of range", () => {
|
|
51
|
+
expect(() => policyToStrategy("threshold:1.5")).toThrow(ConfigError);
|
|
52
|
+
expect(() => policyToStrategy("threshold:-0.1")).toThrow(ConfigError);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=defaults.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.test.js","sourceRoot":"","sources":["../../src/__tests__/defaults.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fail-policy.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fail-policy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { ConsensusBlockedError } from "../errors.js";
|
|
3
|
+
// Mock the wrapper's consensus function and guards' createGuardTemplate
|
|
4
|
+
const mockWrapped = vi.fn();
|
|
5
|
+
vi.mock("@consensus-tools/wrapper", () => ({
|
|
6
|
+
consensus: vi.fn(() => mockWrapped),
|
|
7
|
+
}));
|
|
8
|
+
vi.mock("@consensus-tools/guards", () => ({
|
|
9
|
+
createGuardTemplate: vi.fn((_name, _config) => ({
|
|
10
|
+
asReviewer: () => vi.fn(),
|
|
11
|
+
})),
|
|
12
|
+
GUARD_CONFIGS: {
|
|
13
|
+
security: { description: "Security reviewer", rules: () => [] },
|
|
14
|
+
compliance: { description: "Compliance reviewer", rules: () => [] },
|
|
15
|
+
"user-impact": { description: "User-impact reviewer", rules: () => [] },
|
|
16
|
+
},
|
|
17
|
+
DEFAULT_PERSONA_TRIO: ["security", "compliance", "user-impact"],
|
|
18
|
+
}));
|
|
19
|
+
const { consensus } = await import("../index.js");
|
|
20
|
+
describe("failPolicy behavior", () => {
|
|
21
|
+
let originalNodeEnv;
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
originalNodeEnv = process.env["NODE_ENV"];
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
if (originalNodeEnv === undefined) {
|
|
28
|
+
delete process.env["NODE_ENV"];
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
process.env["NODE_ENV"] = originalNodeEnv;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
it("failPolicy: 'closed' + error -> ConsensusBlockedError thrown", async () => {
|
|
35
|
+
const fn = vi.fn(async () => "result");
|
|
36
|
+
mockWrapped.mockRejectedValueOnce(new Error("deliberation crashed"));
|
|
37
|
+
const wrapped = consensus.wrap(fn, { failPolicy: "closed" });
|
|
38
|
+
await expect(wrapped("myTool", {})).rejects.toThrow(ConsensusBlockedError);
|
|
39
|
+
// Second call: verify message
|
|
40
|
+
mockWrapped.mockRejectedValueOnce(new Error("deliberation crashed again"));
|
|
41
|
+
const wrapped2 = consensus.wrap(fn, { failPolicy: "closed" });
|
|
42
|
+
await expect(wrapped2("myTool", {})).rejects.toThrow("Consensus deliberation failed");
|
|
43
|
+
});
|
|
44
|
+
it("failPolicy: 'open' + error -> fn result returned", async () => {
|
|
45
|
+
const fn = vi.fn(async (_name, _args) => "fallback-result");
|
|
46
|
+
// First call: mockWrapped rejects (deliberation error)
|
|
47
|
+
mockWrapped.mockRejectedValueOnce(new Error("deliberation crashed"));
|
|
48
|
+
const wrapped = consensus.wrap(fn, { failPolicy: "open" });
|
|
49
|
+
const result = await wrapped("myTool", { key: "val" });
|
|
50
|
+
// failPolicy 'open' should call fn directly and return its result
|
|
51
|
+
expect(result).toBe("fallback-result");
|
|
52
|
+
expect(fn).toHaveBeenCalledWith("myTool", { key: "val" });
|
|
53
|
+
});
|
|
54
|
+
it("NODE_ENV=production + failPolicy:'open' -> console.warn emitted", () => {
|
|
55
|
+
process.env["NODE_ENV"] = "production";
|
|
56
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
|
|
57
|
+
const fn = vi.fn(async () => "result");
|
|
58
|
+
consensus.wrap(fn, { failPolicy: "open" });
|
|
59
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("failPolicy 'open' in production"));
|
|
60
|
+
warnSpy.mockRestore();
|
|
61
|
+
});
|
|
62
|
+
it("NODE_ENV=production + storage:'memory' -> console.warn emitted", () => {
|
|
63
|
+
process.env["NODE_ENV"] = "production";
|
|
64
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
|
|
65
|
+
const fn = vi.fn(async () => "result");
|
|
66
|
+
// storage defaults to 'memory', so no explicit override needed
|
|
67
|
+
consensus.wrap(fn, { storage: "memory" });
|
|
68
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("storage 'memory' in production"));
|
|
69
|
+
warnSpy.mockRestore();
|
|
70
|
+
});
|
|
71
|
+
it("NODE_ENV=development -> no warnings emitted", () => {
|
|
72
|
+
process.env["NODE_ENV"] = "development";
|
|
73
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
|
|
74
|
+
const fn = vi.fn(async () => "result");
|
|
75
|
+
consensus.wrap(fn, { failPolicy: "open", storage: "memory" });
|
|
76
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
77
|
+
warnSpy.mockRestore();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=fail-policy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fail-policy.test.js","sourceRoot":"","sources":["../../src/__tests__/fail-policy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frameworks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/frameworks.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { MissingDependencyError } from "../errors.js";
|
|
3
|
+
// Mock the wrapper and guards (needed for module load)
|
|
4
|
+
vi.mock("@consensus-tools/wrapper", () => ({
|
|
5
|
+
consensus: vi.fn(() => vi.fn()),
|
|
6
|
+
}));
|
|
7
|
+
vi.mock("@consensus-tools/guards", () => ({
|
|
8
|
+
createGuardTemplate: vi.fn((_name, _config) => ({
|
|
9
|
+
asReviewer: () => vi.fn(),
|
|
10
|
+
})),
|
|
11
|
+
}));
|
|
12
|
+
// Mock the optional adapter packages to simulate them not being installed
|
|
13
|
+
vi.mock("@consensus-tools/langchain", () => {
|
|
14
|
+
throw new Error("Cannot find module '@consensus-tools/langchain'");
|
|
15
|
+
});
|
|
16
|
+
vi.mock("@consensus-tools/ai-sdk", () => {
|
|
17
|
+
throw new Error("Cannot find module '@consensus-tools/ai-sdk'");
|
|
18
|
+
});
|
|
19
|
+
vi.mock("@consensus-tools/mcp", () => {
|
|
20
|
+
throw new Error("Cannot find module '@consensus-tools/mcp'");
|
|
21
|
+
});
|
|
22
|
+
const { consensus } = await import("../index.js");
|
|
23
|
+
describe("framework shortcuts", () => {
|
|
24
|
+
it("consensus.langchain() throws MissingDependencyError when adapter not installed", async () => {
|
|
25
|
+
await expect(consensus.langchain({})).rejects.toThrow(MissingDependencyError);
|
|
26
|
+
await expect(consensus.langchain({})).rejects.toThrow("@consensus-tools/langchain");
|
|
27
|
+
});
|
|
28
|
+
it("consensus.aiSdk() throws MissingDependencyError when adapter not installed", async () => {
|
|
29
|
+
await expect(consensus.aiSdk(() => { })).rejects.toThrow(MissingDependencyError);
|
|
30
|
+
await expect(consensus.aiSdk(() => { })).rejects.toThrow("@consensus-tools/ai-sdk");
|
|
31
|
+
});
|
|
32
|
+
it("consensus.mcp() throws MissingDependencyError when adapter not installed", async () => {
|
|
33
|
+
await expect(consensus.mcp()).rejects.toThrow(MissingDependencyError);
|
|
34
|
+
await expect(consensus.mcp()).rejects.toThrow("@consensus-tools/mcp");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe("consensus.langchain() with adapter installed", () => {
|
|
38
|
+
it("returns a handler instance when adapter is available", async () => {
|
|
39
|
+
// Create a mock handler class
|
|
40
|
+
class MockGuardHandler {
|
|
41
|
+
name = "consensus-guard";
|
|
42
|
+
config;
|
|
43
|
+
constructor(config) {
|
|
44
|
+
this.config = config;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Temporarily override the langchain mock to return a working module
|
|
48
|
+
const mockMod = {
|
|
49
|
+
ConsensusGuardCallbackHandler: MockGuardHandler,
|
|
50
|
+
};
|
|
51
|
+
// We need to test with a fresh import; use vi.doMock to override for a scoped import
|
|
52
|
+
vi.doMock("@consensus-tools/langchain", () => mockMod);
|
|
53
|
+
// Re-import to pick up the new mock
|
|
54
|
+
const { consensus: freshConsensus } = await import("../index.js");
|
|
55
|
+
const handler = await freshConsensus.langchain(null, { policy: "supermajority", guards: ["security"] });
|
|
56
|
+
expect(handler).toBeInstanceOf(MockGuardHandler);
|
|
57
|
+
expect(handler.config).toEqual({
|
|
58
|
+
policy: "supermajority",
|
|
59
|
+
guards: ["security"],
|
|
60
|
+
onDecision: undefined,
|
|
61
|
+
});
|
|
62
|
+
// Restore the original mock (not installed)
|
|
63
|
+
vi.doMock("@consensus-tools/langchain", () => {
|
|
64
|
+
throw new Error("Cannot find module '@consensus-tools/langchain'");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
it("uses default policy 'majority' when no config provided", async () => {
|
|
68
|
+
class MockGuardHandler {
|
|
69
|
+
name = "consensus-guard";
|
|
70
|
+
config;
|
|
71
|
+
constructor(config) {
|
|
72
|
+
this.config = config;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
vi.doMock("@consensus-tools/langchain", () => ({
|
|
76
|
+
ConsensusGuardCallbackHandler: MockGuardHandler,
|
|
77
|
+
}));
|
|
78
|
+
const { consensus: freshConsensus } = await import("../index.js");
|
|
79
|
+
const handler = await freshConsensus.langchain(null);
|
|
80
|
+
expect(handler.config.policy).toBe("majority");
|
|
81
|
+
vi.doMock("@consensus-tools/langchain", () => {
|
|
82
|
+
throw new Error("Cannot find module '@consensus-tools/langchain'");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=frameworks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frameworks.test.js","sourceRoot":"","sources":["../../src/__tests__/frameworks.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/logger.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { createLogger } from "../logger.js";
|
|
3
|
+
describe("createLogger", () => {
|
|
4
|
+
it("emits deliberation.start event via beforeSubmit hook", () => {
|
|
5
|
+
const logFn = vi.fn();
|
|
6
|
+
const hooks = createLogger({ logger: logFn });
|
|
7
|
+
hooks.beforeSubmit(["arg1", "arg2"]);
|
|
8
|
+
expect(logFn).toHaveBeenCalledOnce();
|
|
9
|
+
const event = logFn.mock.calls[0][0];
|
|
10
|
+
expect(event.event).toBe("deliberation.start");
|
|
11
|
+
expect(event.data).toEqual({ args: ["arg1", "arg2"] });
|
|
12
|
+
expect(typeof event.timestamp).toBe("number");
|
|
13
|
+
});
|
|
14
|
+
it("emits deliberation.result event via afterResolve hook", () => {
|
|
15
|
+
const logFn = vi.fn();
|
|
16
|
+
const hooks = createLogger({ logger: logFn });
|
|
17
|
+
const mockResult = {
|
|
18
|
+
action: "allow",
|
|
19
|
+
output: "ok",
|
|
20
|
+
scores: [{ score: 0.9, rationale: "safe" }],
|
|
21
|
+
aggregateScore: 0.9,
|
|
22
|
+
attempt: 1,
|
|
23
|
+
};
|
|
24
|
+
hooks.afterResolve(mockResult);
|
|
25
|
+
expect(logFn).toHaveBeenCalledOnce();
|
|
26
|
+
const event = logFn.mock.calls[0][0];
|
|
27
|
+
expect(event.event).toBe("deliberation.result");
|
|
28
|
+
expect(event.data).toEqual({
|
|
29
|
+
action: "allow",
|
|
30
|
+
aggregateScore: 0.9,
|
|
31
|
+
attempt: 1,
|
|
32
|
+
scoresCount: 1,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
it("emits deliberation.error-level event via onBlock hook", () => {
|
|
36
|
+
const logFn = vi.fn();
|
|
37
|
+
const hooks = createLogger({ logger: logFn });
|
|
38
|
+
const mockResult = {
|
|
39
|
+
action: "block",
|
|
40
|
+
output: null,
|
|
41
|
+
scores: [{ score: 0, rationale: "blocked" }],
|
|
42
|
+
aggregateScore: 0,
|
|
43
|
+
attempt: 1,
|
|
44
|
+
};
|
|
45
|
+
hooks.onBlock(mockResult);
|
|
46
|
+
expect(logFn).toHaveBeenCalledOnce();
|
|
47
|
+
const event = logFn.mock.calls[0][0];
|
|
48
|
+
expect(event.event).toBe("deliberation.result");
|
|
49
|
+
expect(event.data.action).toBe("block");
|
|
50
|
+
});
|
|
51
|
+
it("returns empty hooks when logger is false (suppresses all events)", () => {
|
|
52
|
+
const hooks = createLogger({ logger: false });
|
|
53
|
+
expect(hooks.beforeSubmit).toBeUndefined();
|
|
54
|
+
expect(hooks.afterResolve).toBeUndefined();
|
|
55
|
+
expect(hooks.onBlock).toBeUndefined();
|
|
56
|
+
expect(hooks.onEscalate).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
it("uses custom logger function to receive events", () => {
|
|
59
|
+
const events = [];
|
|
60
|
+
const customLogger = (event) => {
|
|
61
|
+
events.push(event);
|
|
62
|
+
};
|
|
63
|
+
const hooks = createLogger({ logger: customLogger });
|
|
64
|
+
hooks.beforeSubmit(["hello"]);
|
|
65
|
+
hooks.afterResolve({
|
|
66
|
+
action: "allow",
|
|
67
|
+
output: "world",
|
|
68
|
+
scores: [],
|
|
69
|
+
aggregateScore: 1.0,
|
|
70
|
+
attempt: 1,
|
|
71
|
+
});
|
|
72
|
+
expect(events).toHaveLength(2);
|
|
73
|
+
expect(events[0].event).toBe("deliberation.start");
|
|
74
|
+
expect(events[1].event).toBe("deliberation.result");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=logger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.js","sourceRoot":"","sources":["../../src/__tests__/logger.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/resolve.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { resolveWrappable } from "../resolve.js";
|
|
3
|
+
describe("resolveWrappable", () => {
|
|
4
|
+
it("returns the function directly when input is a function", () => {
|
|
5
|
+
const fn = async (name, args) => ({ name, args });
|
|
6
|
+
const result = resolveWrappable(fn);
|
|
7
|
+
expect(result).toBe(fn);
|
|
8
|
+
});
|
|
9
|
+
it("returns .execute when input has .execute", async () => {
|
|
10
|
+
const obj = {
|
|
11
|
+
state: "bound",
|
|
12
|
+
execute: async function (name, args) {
|
|
13
|
+
return { name, args, state: this.state };
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
const resolved = resolveWrappable(obj);
|
|
17
|
+
const output = await resolved("test", { a: 1 });
|
|
18
|
+
expect(output).toEqual({ name: "test", args: { a: 1 }, state: "bound" });
|
|
19
|
+
});
|
|
20
|
+
it("returns .invoke when input has .invoke", async () => {
|
|
21
|
+
const obj = {
|
|
22
|
+
state: "invoked",
|
|
23
|
+
invoke: async function (name, args) {
|
|
24
|
+
return { name, args, state: this.state };
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
const resolved = resolveWrappable(obj);
|
|
28
|
+
const output = await resolved("test", { b: 2 });
|
|
29
|
+
expect(output).toEqual({ name: "test", args: { b: 2 }, state: "invoked" });
|
|
30
|
+
});
|
|
31
|
+
it("returns .call when input has .call", async () => {
|
|
32
|
+
const obj = {
|
|
33
|
+
state: "called",
|
|
34
|
+
call: async function (name, args) {
|
|
35
|
+
return { name, args, state: this.state };
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
const resolved = resolveWrappable(obj);
|
|
39
|
+
const output = await resolved("test", { c: 3 });
|
|
40
|
+
expect(output).toEqual({ name: "test", args: { c: 3 }, state: "called" });
|
|
41
|
+
});
|
|
42
|
+
it("prefers .execute over .invoke when both exist (resolution order)", async () => {
|
|
43
|
+
const obj = {
|
|
44
|
+
execute: async (_name, _args) => "execute-wins",
|
|
45
|
+
invoke: async (_name, _args) => "invoke-loses",
|
|
46
|
+
};
|
|
47
|
+
const resolved = resolveWrappable(obj);
|
|
48
|
+
const output = await resolved("test", {});
|
|
49
|
+
expect(output).toBe("execute-wins");
|
|
50
|
+
});
|
|
51
|
+
it("throws TypeError for null", () => {
|
|
52
|
+
expect(() => resolveWrappable(null)).toThrow(TypeError);
|
|
53
|
+
expect(() => resolveWrappable(null)).toThrow("Expected a Wrappable");
|
|
54
|
+
});
|
|
55
|
+
it("throws TypeError for undefined", () => {
|
|
56
|
+
expect(() => resolveWrappable(undefined)).toThrow(TypeError);
|
|
57
|
+
expect(() => resolveWrappable(undefined)).toThrow("Expected a Wrappable");
|
|
58
|
+
});
|
|
59
|
+
it("throws TypeError for object with no matching methods", () => {
|
|
60
|
+
const obj = { foo: () => "bar" };
|
|
61
|
+
expect(() => resolveWrappable(obj)).toThrow(TypeError);
|
|
62
|
+
expect(() => resolveWrappable(obj)).toThrow("Expected a Wrappable");
|
|
63
|
+
});
|
|
64
|
+
it("throws TypeError for string primitive", () => {
|
|
65
|
+
expect(() => resolveWrappable("hello")).toThrow(TypeError);
|
|
66
|
+
});
|
|
67
|
+
it("throws TypeError for number primitive", () => {
|
|
68
|
+
expect(() => resolveWrappable(42)).toThrow(TypeError);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=resolve.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.test.js","sourceRoot":"","sources":["../../src/__tests__/resolve.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/wrap.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { ConsensusBlockedError } from "../errors.js";
|
|
3
|
+
// Mock the wrapper's consensus function and guards' createGuardTemplate
|
|
4
|
+
const mockWrapped = vi.fn();
|
|
5
|
+
vi.mock("@consensus-tools/wrapper", () => ({
|
|
6
|
+
consensus: vi.fn(() => mockWrapped),
|
|
7
|
+
}));
|
|
8
|
+
vi.mock("@consensus-tools/guards", () => ({
|
|
9
|
+
createGuardTemplate: vi.fn((_name, _config) => ({
|
|
10
|
+
asReviewer: () => vi.fn(),
|
|
11
|
+
})),
|
|
12
|
+
GUARD_CONFIGS: {
|
|
13
|
+
security: { description: "Security reviewer", rules: () => [] },
|
|
14
|
+
compliance: { description: "Compliance reviewer", rules: () => [] },
|
|
15
|
+
"user-impact": { description: "User-impact reviewer", rules: () => [] },
|
|
16
|
+
},
|
|
17
|
+
DEFAULT_PERSONA_TRIO: ["security", "compliance", "user-impact"],
|
|
18
|
+
}));
|
|
19
|
+
// Import after mocks are set up
|
|
20
|
+
const { consensus } = await import("../index.js");
|
|
21
|
+
describe("consensus.wrap()", () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
it("happy path: wrap function, reviewers run, decision returned", async () => {
|
|
26
|
+
const fn = vi.fn(async (_name, _args) => "tool-result");
|
|
27
|
+
mockWrapped.mockResolvedValueOnce({
|
|
28
|
+
action: "allow",
|
|
29
|
+
output: "tool-result",
|
|
30
|
+
scores: [{ score: 0.9, rationale: "approved" }],
|
|
31
|
+
aggregateScore: 0.9,
|
|
32
|
+
attempt: 1,
|
|
33
|
+
});
|
|
34
|
+
const wrapped = consensus.wrap(fn);
|
|
35
|
+
const result = await wrapped("myTool", { input: "data" });
|
|
36
|
+
expect(result).toBe("tool-result");
|
|
37
|
+
expect(mockWrapped).toHaveBeenCalledWith("myTool", { input: "data" });
|
|
38
|
+
});
|
|
39
|
+
it("wrapped fn returns undefined -> reviewers evaluate undefined", async () => {
|
|
40
|
+
const fn = vi.fn(async () => undefined);
|
|
41
|
+
mockWrapped.mockResolvedValueOnce({
|
|
42
|
+
action: "allow",
|
|
43
|
+
output: undefined,
|
|
44
|
+
scores: [{ score: 0.8 }],
|
|
45
|
+
aggregateScore: 0.8,
|
|
46
|
+
attempt: 1,
|
|
47
|
+
});
|
|
48
|
+
const wrapped = consensus.wrap(fn);
|
|
49
|
+
const result = await wrapped("myTool", {});
|
|
50
|
+
expect(result).toBeUndefined();
|
|
51
|
+
});
|
|
52
|
+
it("wrapped fn throws synchronously -> failPolicy 'closed' throws ConsensusBlockedError", async () => {
|
|
53
|
+
const fn = vi.fn(() => {
|
|
54
|
+
throw new Error("sync explosion");
|
|
55
|
+
});
|
|
56
|
+
mockWrapped.mockRejectedValueOnce(new Error("sync explosion"));
|
|
57
|
+
const wrapped = consensus.wrap(fn, { failPolicy: "closed" });
|
|
58
|
+
await expect(wrapped("myTool", {})).rejects.toThrow(ConsensusBlockedError);
|
|
59
|
+
});
|
|
60
|
+
it("all reviewers return score=0 -> unanimous block with failPolicy closed", async () => {
|
|
61
|
+
const fn = vi.fn(async () => "result");
|
|
62
|
+
mockWrapped.mockResolvedValueOnce({
|
|
63
|
+
action: "block",
|
|
64
|
+
output: null,
|
|
65
|
+
scores: [
|
|
66
|
+
{ score: 0, rationale: "blocked-1" },
|
|
67
|
+
{ score: 0, rationale: "blocked-2" },
|
|
68
|
+
{ score: 0, rationale: "blocked-3" },
|
|
69
|
+
],
|
|
70
|
+
aggregateScore: 0,
|
|
71
|
+
attempt: 1,
|
|
72
|
+
});
|
|
73
|
+
const wrapped = consensus.wrap(fn, { failPolicy: "closed" });
|
|
74
|
+
await expect(wrapped("dangerousTool", {})).rejects.toThrow(ConsensusBlockedError);
|
|
75
|
+
// Second call to verify message content
|
|
76
|
+
mockWrapped.mockResolvedValueOnce({
|
|
77
|
+
action: "block",
|
|
78
|
+
output: null,
|
|
79
|
+
scores: [
|
|
80
|
+
{ score: 0, rationale: "blocked-1" },
|
|
81
|
+
{ score: 0, rationale: "blocked-2" },
|
|
82
|
+
{ score: 0, rationale: "blocked-3" },
|
|
83
|
+
],
|
|
84
|
+
aggregateScore: 0,
|
|
85
|
+
attempt: 1,
|
|
86
|
+
});
|
|
87
|
+
await expect(wrapped("dangerousTool", {})).rejects.toThrow(/Consensus block/);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=wrap.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.test.js","sourceRoot":"","sources":["../../src/__tests__/wrap.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { StrategyConfig } from "@consensus-tools/wrapper";
|
|
2
|
+
import type { UniversalConfig } from "./types.js";
|
|
3
|
+
export { DEFAULT_PERSONA_TRIO } from "@consensus-tools/guards";
|
|
4
|
+
export declare const DEFAULT_GUARD = "agent_action";
|
|
5
|
+
export declare const DEFAULT_POLICY = "majority";
|
|
6
|
+
export declare const DEFAULT_PERSONA_COUNT = 3;
|
|
7
|
+
export declare const DEFAULTS: Required<Pick<UniversalConfig, "policy" | "guards" | "failPolicy" | "storage" | "logger">>;
|
|
8
|
+
/**
|
|
9
|
+
* Maps a user-facing policy name to a wrapper StrategyConfig.
|
|
10
|
+
*
|
|
11
|
+
* Supported names:
|
|
12
|
+
* 'majority' -> { strategy: 'majority' }
|
|
13
|
+
* 'supermajority' -> { strategy: 'threshold', threshold: 0.67 }
|
|
14
|
+
* 'unanimous' -> { strategy: 'unanimous' }
|
|
15
|
+
* 'threshold:X' -> { strategy: 'threshold', threshold: X }
|
|
16
|
+
*
|
|
17
|
+
* @throws ConfigError for unrecognized policy names.
|
|
18
|
+
*/
|
|
19
|
+
export declare function policyToStrategy(policy: string): StrategyConfig;
|
|
20
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAI/D,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAC5C,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAC7B,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC,CAOjF,CAAC;AAIF;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CA0B/D"}
|
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ConfigError } from "./errors.js";
|
|
2
|
+
export { DEFAULT_PERSONA_TRIO } from "@consensus-tools/guards";
|
|
3
|
+
// ── Default Configuration ────────────────────────────────────────────
|
|
4
|
+
export const DEFAULT_GUARD = "agent_action";
|
|
5
|
+
export const DEFAULT_POLICY = "majority";
|
|
6
|
+
export const DEFAULT_PERSONA_COUNT = 3;
|
|
7
|
+
export const DEFAULTS = {
|
|
8
|
+
policy: DEFAULT_POLICY,
|
|
9
|
+
guards: [DEFAULT_GUARD],
|
|
10
|
+
failPolicy: "closed",
|
|
11
|
+
storage: "memory",
|
|
12
|
+
logger: true,
|
|
13
|
+
};
|
|
14
|
+
// ── Policy-to-Strategy Mapping ───────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* Maps a user-facing policy name to a wrapper StrategyConfig.
|
|
17
|
+
*
|
|
18
|
+
* Supported names:
|
|
19
|
+
* 'majority' -> { strategy: 'majority' }
|
|
20
|
+
* 'supermajority' -> { strategy: 'threshold', threshold: 0.67 }
|
|
21
|
+
* 'unanimous' -> { strategy: 'unanimous' }
|
|
22
|
+
* 'threshold:X' -> { strategy: 'threshold', threshold: X }
|
|
23
|
+
*
|
|
24
|
+
* @throws ConfigError for unrecognized policy names.
|
|
25
|
+
*/
|
|
26
|
+
export function policyToStrategy(policy) {
|
|
27
|
+
switch (policy) {
|
|
28
|
+
case "majority":
|
|
29
|
+
return { strategy: "majority" };
|
|
30
|
+
case "supermajority":
|
|
31
|
+
return { strategy: "threshold", threshold: 0.67 };
|
|
32
|
+
case "unanimous":
|
|
33
|
+
return { strategy: "unanimous" };
|
|
34
|
+
default: {
|
|
35
|
+
// Handle 'threshold:X' pattern
|
|
36
|
+
if (policy.startsWith("threshold:")) {
|
|
37
|
+
const value = Number(policy.slice("threshold:".length));
|
|
38
|
+
if (Number.isNaN(value) || value < 0 || value > 1) {
|
|
39
|
+
throw new ConfigError(`Invalid threshold value in policy "${policy}". Expected a number between 0 and 1.`);
|
|
40
|
+
}
|
|
41
|
+
return { strategy: "threshold", threshold: value };
|
|
42
|
+
}
|
|
43
|
+
throw new ConfigError(`Unknown policy "${policy}". ` +
|
|
44
|
+
`Supported: 'majority', 'supermajority', 'unanimous', 'threshold:X' (where X is 0-1).`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=defaults.js.map
|