authority-layer 0.1.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/dist/AuthorityLayer.d.ts +70 -0
- package/dist/AuthorityLayer.d.ts.map +1 -0
- package/dist/AuthorityLayer.js +175 -0
- package/dist/AuthorityLayer.js.map +1 -0
- package/dist/EnforcementHalt.d.ts +10 -0
- package/dist/EnforcementHalt.d.ts.map +1 -0
- package/dist/EnforcementHalt.js +34 -0
- package/dist/EnforcementHalt.js.map +1 -0
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +81 -0
- package/dist/doctor.js.map +1 -0
- package/dist/enforcement/budgetGuard.d.ts +14 -0
- package/dist/enforcement/budgetGuard.d.ts.map +1 -0
- package/dist/enforcement/budgetGuard.js +43 -0
- package/dist/enforcement/budgetGuard.js.map +1 -0
- package/dist/enforcement/loopGuard.d.ts +17 -0
- package/dist/enforcement/loopGuard.d.ts.map +1 -0
- package/dist/enforcement/loopGuard.js +43 -0
- package/dist/enforcement/loopGuard.js.map +1 -0
- package/dist/enforcement/toolThrottle.d.ts +20 -0
- package/dist/enforcement/toolThrottle.d.ts.map +1 -0
- package/dist/enforcement/toolThrottle.js +50 -0
- package/dist/enforcement/toolThrottle.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/integrity/hashChain.d.ts +27 -0
- package/dist/integrity/hashChain.d.ts.map +1 -0
- package/dist/integrity/hashChain.js +87 -0
- package/dist/integrity/hashChain.js.map +1 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { AuthorityConfig } from "./types";
|
|
2
|
+
export declare class AuthorityLayer {
|
|
3
|
+
private readonly mode;
|
|
4
|
+
private readonly budgetGuard?;
|
|
5
|
+
private readonly loopGuard?;
|
|
6
|
+
private readonly toolThrottle?;
|
|
7
|
+
private readonly chain;
|
|
8
|
+
constructor(config: AuthorityConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Convert a guard's PendingHalt into a logged HaltResult, then either
|
|
11
|
+
* throw an EnforcementHalt (strict) or emit a console warning (warn/stub).
|
|
12
|
+
*/
|
|
13
|
+
private enforce;
|
|
14
|
+
/**
|
|
15
|
+
* Wrap an agent run with enforcement.
|
|
16
|
+
*
|
|
17
|
+
* - Resets per-run counters (loop guard).
|
|
18
|
+
* - Logs run.start and run.complete events to the chain.
|
|
19
|
+
* - Re-throws EnforcementHalt cleanly; logs unexpected errors to the chain
|
|
20
|
+
* before re-throwing so they appear in the audit log.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* await authority.wrap(async () => {
|
|
24
|
+
* const result = await authority.tool("openai.chat", () => openai.chat(...));
|
|
25
|
+
* authority.recordSpend(result.usage.cost);
|
|
26
|
+
* });
|
|
27
|
+
*/
|
|
28
|
+
wrap(fn: () => Promise<void>): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Wrap a single tool call with loop guard and throttle enforcement.
|
|
31
|
+
*
|
|
32
|
+
* This is the sole mechanism for calling external tools within wrap().
|
|
33
|
+
* Both guards are checked before the tool function executes — the tool
|
|
34
|
+
* function is never called if a limit has already been breached.
|
|
35
|
+
*
|
|
36
|
+
* @param name Human-readable tool name, logged to the event chain.
|
|
37
|
+
* @param fn Async function that performs the actual tool call.
|
|
38
|
+
* @returns The resolved return value of fn().
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* const data = await authority.tool("stripe.charge", () =>
|
|
42
|
+
* stripe.charges.create({ amount: 100, currency: "usd" })
|
|
43
|
+
* );
|
|
44
|
+
*/
|
|
45
|
+
tool<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Report token or API spend in USD.
|
|
48
|
+
*
|
|
49
|
+
* Call this after each model or billable API call. AuthorityLayer does not
|
|
50
|
+
* intercept pricing automatically — different providers expose cost
|
|
51
|
+
* differently, so the host is responsible for calculating the USD amount.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const response = await openai.chat.completions.create({ ... });
|
|
55
|
+
* const costUSD = response.usage.total_tokens * PRICE_PER_TOKEN;
|
|
56
|
+
* authority.recordSpend(costUSD);
|
|
57
|
+
*/
|
|
58
|
+
recordSpend(amountUSD: number): void;
|
|
59
|
+
/**
|
|
60
|
+
* Return a read-only copy of the enforcement event chain.
|
|
61
|
+
* Useful for inspecting what happened during a run or persisting to disk.
|
|
62
|
+
*/
|
|
63
|
+
getChain(): readonly import("./types").EnforcementEvent[];
|
|
64
|
+
/**
|
|
65
|
+
* Verify the integrity of the in-memory event chain.
|
|
66
|
+
* Returns false if any event has been tampered with.
|
|
67
|
+
*/
|
|
68
|
+
verifyChain(): boolean;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=AuthorityLayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthorityLayer.d.ts","sourceRoot":"","sources":["../src/AuthorityLayer.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,eAAe,EAA4C,MAAM,SAAS,CAAC;AAOzF,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;gBAEtB,MAAM,EAAE,eAAe;IAiBnC;;;OAGG;IACH,OAAO,CAAC,OAAO;IAgCf;;;;;;;;;;;;;OAaG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlD;;;;;;;;;;;;;;;OAeG;IACG,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgB7D;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAOpC;;;OAGG;IACH,QAAQ;IAIR;;;OAGG;IACH,WAAW,IAAI,OAAO;CAGzB"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
// AuthorityLayer — Main Enforcement Class
|
|
4
|
+
//
|
|
5
|
+
// This is the single public surface of the SDK. Instantiate once, pass config,
|
|
6
|
+
// then route all agent execution through wrap() and all tool calls through
|
|
7
|
+
// tool(). recordSpend() is the only other public method — it exists because
|
|
8
|
+
// token pricing is framework-specific and must be reported explicitly.
|
|
9
|
+
//
|
|
10
|
+
// Design decisions:
|
|
11
|
+
//
|
|
12
|
+
// 1. Guards are instantiated only when their config section is present.
|
|
13
|
+
// Omitting a config key disables that primitive entirely — no silent
|
|
14
|
+
// defaults that appear inactive but still run.
|
|
15
|
+
//
|
|
16
|
+
// 2. tool() is the single composable hook for all external tool calls.
|
|
17
|
+
// It bundles loop guard + throttle in one call, keeping adoption simple
|
|
18
|
+
// and preventing the misuse that separate checkLoop() / checkThrottle()
|
|
19
|
+
// methods would invite (forgetting to call one, calling them twice, etc.).
|
|
20
|
+
//
|
|
21
|
+
// 3. EnforcementHalt is a typed error, not a raw throw. Its .enforcement
|
|
22
|
+
// property carries the full structured HaltResult so callers never need
|
|
23
|
+
// to parse error messages.
|
|
24
|
+
//
|
|
25
|
+
// 4. mode: "warn" is stubbed in V1. The config option is accepted and stored
|
|
26
|
+
// so existing configs won't break when warn mode is implemented.
|
|
27
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.AuthorityLayer = void 0;
|
|
30
|
+
const budgetGuard_1 = require("./enforcement/budgetGuard");
|
|
31
|
+
const loopGuard_1 = require("./enforcement/loopGuard");
|
|
32
|
+
const toolThrottle_1 = require("./enforcement/toolThrottle");
|
|
33
|
+
const hashChain_1 = require("./integrity/hashChain");
|
|
34
|
+
const EnforcementHalt_1 = require("./EnforcementHalt");
|
|
35
|
+
class AuthorityLayer {
|
|
36
|
+
constructor(config) {
|
|
37
|
+
this.mode = config.mode ?? "strict";
|
|
38
|
+
this.chain = new hashChain_1.HashChain();
|
|
39
|
+
if (config.budget) {
|
|
40
|
+
this.budgetGuard = new budgetGuard_1.BudgetGuard(config.budget);
|
|
41
|
+
}
|
|
42
|
+
if (config.loopGuard) {
|
|
43
|
+
this.loopGuard = new loopGuard_1.LoopGuard(config.loopGuard);
|
|
44
|
+
}
|
|
45
|
+
if (config.toolThrottle) {
|
|
46
|
+
this.toolThrottle = new toolThrottle_1.ToolThrottle(config.toolThrottle);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
50
|
+
/**
|
|
51
|
+
* Convert a guard's PendingHalt into a logged HaltResult, then either
|
|
52
|
+
* throw an EnforcementHalt (strict) or emit a console warning (warn/stub).
|
|
53
|
+
*/
|
|
54
|
+
enforce(result, context) {
|
|
55
|
+
if (result.status !== "halted")
|
|
56
|
+
return;
|
|
57
|
+
const event = this.chain.append("enforcement.halt", {
|
|
58
|
+
reason: result.reason,
|
|
59
|
+
limit: result.limit,
|
|
60
|
+
spent: result.spent,
|
|
61
|
+
...context,
|
|
62
|
+
});
|
|
63
|
+
const haltResult = {
|
|
64
|
+
status: "halted",
|
|
65
|
+
reason: result.reason,
|
|
66
|
+
limit: result.limit,
|
|
67
|
+
spent: result.spent,
|
|
68
|
+
event_id: event.event_id,
|
|
69
|
+
};
|
|
70
|
+
if (this.mode === "strict") {
|
|
71
|
+
throw new EnforcementHalt_1.EnforcementHalt(haltResult);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// V1 stub: warn mode is accepted in config but not yet implemented.
|
|
75
|
+
// In a future release this will emit a structured warning and continue.
|
|
76
|
+
console.warn("[AuthorityLayer] WARN (warn mode stub):", haltResult);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* Wrap an agent run with enforcement.
|
|
82
|
+
*
|
|
83
|
+
* - Resets per-run counters (loop guard).
|
|
84
|
+
* - Logs run.start and run.complete events to the chain.
|
|
85
|
+
* - Re-throws EnforcementHalt cleanly; logs unexpected errors to the chain
|
|
86
|
+
* before re-throwing so they appear in the audit log.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* await authority.wrap(async () => {
|
|
90
|
+
* const result = await authority.tool("openai.chat", () => openai.chat(...));
|
|
91
|
+
* authority.recordSpend(result.usage.cost);
|
|
92
|
+
* });
|
|
93
|
+
*/
|
|
94
|
+
async wrap(fn) {
|
|
95
|
+
// Per-run reset
|
|
96
|
+
this.loopGuard?.reset();
|
|
97
|
+
this.chain.append("run.start", { timestamp: new Date().toISOString() });
|
|
98
|
+
try {
|
|
99
|
+
await fn();
|
|
100
|
+
this.chain.append("run.complete", { timestamp: new Date().toISOString() });
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
if (err instanceof EnforcementHalt_1.EnforcementHalt) {
|
|
104
|
+
// Already logged by enforce() — just propagate.
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
// Unexpected error — log it to the chain for auditability, then rethrow.
|
|
108
|
+
this.chain.append("run.error", {
|
|
109
|
+
message: err instanceof Error ? err.message : String(err),
|
|
110
|
+
});
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Wrap a single tool call with loop guard and throttle enforcement.
|
|
116
|
+
*
|
|
117
|
+
* This is the sole mechanism for calling external tools within wrap().
|
|
118
|
+
* Both guards are checked before the tool function executes — the tool
|
|
119
|
+
* function is never called if a limit has already been breached.
|
|
120
|
+
*
|
|
121
|
+
* @param name Human-readable tool name, logged to the event chain.
|
|
122
|
+
* @param fn Async function that performs the actual tool call.
|
|
123
|
+
* @returns The resolved return value of fn().
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* const data = await authority.tool("stripe.charge", () =>
|
|
127
|
+
* stripe.charges.create({ amount: 100, currency: "usd" })
|
|
128
|
+
* );
|
|
129
|
+
*/
|
|
130
|
+
async tool(name, fn) {
|
|
131
|
+
const ctx = { tool: name };
|
|
132
|
+
if (this.loopGuard) {
|
|
133
|
+
this.enforce(this.loopGuard.tick(), ctx);
|
|
134
|
+
}
|
|
135
|
+
if (this.toolThrottle) {
|
|
136
|
+
this.enforce(this.toolThrottle.tick(), ctx);
|
|
137
|
+
}
|
|
138
|
+
this.chain.append("tool.call", { name });
|
|
139
|
+
return fn();
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Report token or API spend in USD.
|
|
143
|
+
*
|
|
144
|
+
* Call this after each model or billable API call. AuthorityLayer does not
|
|
145
|
+
* intercept pricing automatically — different providers expose cost
|
|
146
|
+
* differently, so the host is responsible for calculating the USD amount.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* const response = await openai.chat.completions.create({ ... });
|
|
150
|
+
* const costUSD = response.usage.total_tokens * PRICE_PER_TOKEN;
|
|
151
|
+
* authority.recordSpend(costUSD);
|
|
152
|
+
*/
|
|
153
|
+
recordSpend(amountUSD) {
|
|
154
|
+
if (!this.budgetGuard)
|
|
155
|
+
return;
|
|
156
|
+
this.enforce(this.budgetGuard.record(amountUSD));
|
|
157
|
+
}
|
|
158
|
+
// ── Audit / integrity ───────────────────────────────────────────────────────
|
|
159
|
+
/**
|
|
160
|
+
* Return a read-only copy of the enforcement event chain.
|
|
161
|
+
* Useful for inspecting what happened during a run or persisting to disk.
|
|
162
|
+
*/
|
|
163
|
+
getChain() {
|
|
164
|
+
return this.chain.getChain();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Verify the integrity of the in-memory event chain.
|
|
168
|
+
* Returns false if any event has been tampered with.
|
|
169
|
+
*/
|
|
170
|
+
verifyChain() {
|
|
171
|
+
return this.chain.verify();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.AuthorityLayer = AuthorityLayer;
|
|
175
|
+
//# sourceMappingURL=AuthorityLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthorityLayer.js","sourceRoot":"","sources":["../src/AuthorityLayer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { HaltResult } from "./types";
|
|
2
|
+
export declare class EnforcementHalt extends Error {
|
|
3
|
+
/**
|
|
4
|
+
* The full, structured enforcement result.
|
|
5
|
+
* This is the canonical way to inspect why execution was halted.
|
|
6
|
+
*/
|
|
7
|
+
readonly enforcement: HaltResult;
|
|
8
|
+
constructor(result: HaltResult);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=EnforcementHalt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnforcementHalt.d.ts","sourceRoot":"","sources":["../src/EnforcementHalt.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,qBAAa,eAAgB,SAAQ,KAAK;IACtC;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;gBAErB,MAAM,EAAE,UAAU;CAWjC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
// EnforcementHalt — Typed Enforcement Error
|
|
4
|
+
//
|
|
5
|
+
// Thrown by AuthorityLayer in strict mode when a guard limit is breached.
|
|
6
|
+
//
|
|
7
|
+
// IMPORTANT: always access halt details via the `.enforcement` property,
|
|
8
|
+
// not by parsing the error message. The structured object is stable API;
|
|
9
|
+
// the message string is not.
|
|
10
|
+
//
|
|
11
|
+
// @example
|
|
12
|
+
// try {
|
|
13
|
+
// await authority.wrap(async () => { ... });
|
|
14
|
+
// } catch (err) {
|
|
15
|
+
// if (err instanceof EnforcementHalt) {
|
|
16
|
+
// console.log(err.enforcement);
|
|
17
|
+
// // { status: "halted", reason: "budget_exceeded", limit: 50, spent: 52.14, event_id: "evt_..." }
|
|
18
|
+
// }
|
|
19
|
+
// }
|
|
20
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.EnforcementHalt = void 0;
|
|
23
|
+
class EnforcementHalt extends Error {
|
|
24
|
+
constructor(result) {
|
|
25
|
+
super(`[AuthorityLayer] Execution halted — ${result.reason} ` +
|
|
26
|
+
`(limit: ${result.limit}, spent: ${result.spent}, event: ${result.event_id})`);
|
|
27
|
+
this.name = "EnforcementHalt";
|
|
28
|
+
this.enforcement = result;
|
|
29
|
+
// Restore prototype chain for instanceof checks across transpilation targets
|
|
30
|
+
Object.setPrototypeOf(this, EnforcementHalt.prototype);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.EnforcementHalt = EnforcementHalt;
|
|
34
|
+
//# sourceMappingURL=EnforcementHalt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnforcementHalt.js","sourceRoot":"","sources":["../src/EnforcementHalt.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,4CAA4C;AAC5C,EAAE;AACF,0EAA0E;AAC1E,EAAE;AACF,yEAAyE;AACzE,yEAAyE;AACzE,6BAA6B;AAC7B,EAAE;AACF,WAAW;AACX,QAAQ;AACR,+CAA+C;AAC/C,kBAAkB;AAClB,0CAA0C;AAC1C,oCAAoC;AACpC,uGAAuG;AACvG,MAAM;AACN,IAAI;AACJ,gFAAgF;;;AAIhF,MAAa,eAAgB,SAAQ,KAAK;IAOtC,YAAY,MAAkB;QAC1B,KAAK,CACD,uCAAuC,MAAM,CAAC,MAAM,GAAG;YACvD,WAAW,MAAM,CAAC,KAAK,YAAY,MAAM,CAAC,KAAK,YAAY,MAAM,CAAC,QAAQ,GAAG,CAChF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;QAE1B,6EAA6E;QAC7E,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IAC3D,CAAC;CACJ;AAlBD,0CAkBC"}
|
package/dist/doctor.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":""}
|
package/dist/doctor.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// authority-layer doctor
|
|
5
|
+
//
|
|
6
|
+
// Runs a series of guardrail checks and prints results to stdout.
|
|
7
|
+
// Exit 0 = all checks pass. Exit 1 = one or more checks failed.
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// npx authority-layer doctor
|
|
11
|
+
// authority-layer doctor (if installed globally)
|
|
12
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
const crypto_1 = require("crypto");
|
|
15
|
+
const RESET = "\x1b[0m";
|
|
16
|
+
const GREEN = "\x1b[1;32m";
|
|
17
|
+
const RED = "\x1b[1;31m";
|
|
18
|
+
const YELLOW = "\x1b[1;33m";
|
|
19
|
+
const BOLD = "\x1b[1m";
|
|
20
|
+
const results = [];
|
|
21
|
+
function check(name, ok, note) {
|
|
22
|
+
results.push({ name, ok, note });
|
|
23
|
+
}
|
|
24
|
+
// ── Guardrail checks ──────────────────────────────────────────────────────────
|
|
25
|
+
// 1. Node version
|
|
26
|
+
const [major] = process.versions.node.split(".").map(Number);
|
|
27
|
+
check("Node.js version >= 18", major >= 18, `found ${process.versions.node}`);
|
|
28
|
+
// 2. crypto module (required by hash chain)
|
|
29
|
+
try {
|
|
30
|
+
(0, crypto_1.createHash)("sha256").update("test").digest("hex");
|
|
31
|
+
check("crypto module (sha256)", true);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
check("crypto module (sha256)", false, "built-in crypto unavailable");
|
|
35
|
+
}
|
|
36
|
+
// 3. No AUTHORITY_LAYER_DISABLE env flag set
|
|
37
|
+
const disabled = process.env["AUTHORITY_LAYER_DISABLE"] === "1";
|
|
38
|
+
check("AUTHORITY_LAYER_DISABLE not set", !disabled, disabled ? "enforcement is currently disabled via env" : undefined);
|
|
39
|
+
// 4. Offline capable — confirm no network is required for import
|
|
40
|
+
try {
|
|
41
|
+
// Dynamic require — avoids top-level import that would run before checks
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
|
+
require("./index");
|
|
44
|
+
check("core module loads offline", true);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
check("core module loads offline", false, String(err));
|
|
48
|
+
}
|
|
49
|
+
// 5. Sanity: AuthorityLayer instantiates with a minimal config
|
|
50
|
+
try {
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
52
|
+
const { AuthorityLayer } = require("./index");
|
|
53
|
+
const a = new AuthorityLayer({ budget: { dailyUSD: 1 } });
|
|
54
|
+
const chain = a.getChain();
|
|
55
|
+
check("AuthorityLayer instantiates", true, `chain length: ${chain.length}`);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
check("AuthorityLayer instantiates", false, String(err));
|
|
59
|
+
}
|
|
60
|
+
// ── Output ────────────────────────────────────────────────────────────────────
|
|
61
|
+
const pkg = require("../package.json");
|
|
62
|
+
console.log(`\n${BOLD}AuthorityLayer Doctor${RESET} ${YELLOW}${pkg.name}@${pkg.version}${RESET}\n`);
|
|
63
|
+
let failed = 0;
|
|
64
|
+
for (const r of results) {
|
|
65
|
+
const icon = r.ok ? `${GREEN}✔${RESET}` : `${RED}✘${RESET}`;
|
|
66
|
+
const status = r.ok ? `${GREEN}pass${RESET}` : `${RED}FAIL${RESET}`;
|
|
67
|
+
const note = r.note ? ` ${YELLOW}(${r.note})${RESET}` : "";
|
|
68
|
+
console.log(` ${icon} ${r.name.padEnd(38)} ${status}${note}`);
|
|
69
|
+
if (!r.ok)
|
|
70
|
+
failed++;
|
|
71
|
+
}
|
|
72
|
+
console.log();
|
|
73
|
+
if (failed === 0) {
|
|
74
|
+
console.log(`${GREEN}All checks passed.${RESET} AuthorityLayer is ready.\n`);
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
console.log(`${RED}${failed} check(s) failed.${RESET} Review the output above.\n`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BudgetConfig, GuardResult } from "../types";
|
|
2
|
+
export declare class BudgetGuard {
|
|
3
|
+
private spent;
|
|
4
|
+
private readonly limit;
|
|
5
|
+
constructor(config: BudgetConfig);
|
|
6
|
+
/**
|
|
7
|
+
* Record additional spend and check against the hard limit.
|
|
8
|
+
* Returns a PendingHalt if the cumulative spend now exceeds the limit.
|
|
9
|
+
*/
|
|
10
|
+
record(amountUSD: number): GuardResult;
|
|
11
|
+
getSpent(): number;
|
|
12
|
+
getLimit(): number;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=budgetGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budgetGuard.d.ts","sourceRoot":"","sources":["../../src/enforcement/budgetGuard.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE1D,qBAAa,WAAW;IACpB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,MAAM,EAAE,YAAY;IAIhC;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW;IAetC,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;CAGrB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
// BudgetGuard — Hard USD Spend Cap
|
|
4
|
+
//
|
|
5
|
+
// Tracks cumulative USD spend across a run and halts execution when it
|
|
6
|
+
// exceeds the configured dailyUSD limit.
|
|
7
|
+
//
|
|
8
|
+
// Spend is reported explicitly by the host via AuthorityLayer.recordSpend().
|
|
9
|
+
// This keeps the core framework-agnostic — different model providers expose
|
|
10
|
+
// pricing differently, so the host is responsible for conversion.
|
|
11
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.BudgetGuard = void 0;
|
|
14
|
+
class BudgetGuard {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.spent = 0;
|
|
17
|
+
this.limit = config.dailyUSD;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Record additional spend and check against the hard limit.
|
|
21
|
+
* Returns a PendingHalt if the cumulative spend now exceeds the limit.
|
|
22
|
+
*/
|
|
23
|
+
record(amountUSD) {
|
|
24
|
+
this.spent += amountUSD;
|
|
25
|
+
if (this.spent > this.limit) {
|
|
26
|
+
return {
|
|
27
|
+
status: "halted",
|
|
28
|
+
reason: "budget_exceeded",
|
|
29
|
+
limit: this.limit,
|
|
30
|
+
spent: this.spent,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return { status: "ok" };
|
|
34
|
+
}
|
|
35
|
+
getSpent() {
|
|
36
|
+
return this.spent;
|
|
37
|
+
}
|
|
38
|
+
getLimit() {
|
|
39
|
+
return this.limit;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.BudgetGuard = BudgetGuard;
|
|
43
|
+
//# sourceMappingURL=budgetGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budgetGuard.js","sourceRoot":"","sources":["../../src/enforcement/budgetGuard.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,mCAAmC;AACnC,EAAE;AACF,uEAAuE;AACvE,yCAAyC;AACzC,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,kEAAkE;AAClE,gFAAgF;;;AAIhF,MAAa,WAAW;IAIpB,YAAY,MAAoB;QAHxB,UAAK,GAAG,CAAC,CAAC;QAId,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,SAAiB;QACpB,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;QAExB,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,iBAAiB;gBACzB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;aACpB,CAAC;QACN,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;CACJ;AAlCD,kCAkCC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LoopGuardConfig, GuardResult } from "../types";
|
|
2
|
+
export declare class LoopGuard {
|
|
3
|
+
private count;
|
|
4
|
+
private readonly limit;
|
|
5
|
+
constructor(config: LoopGuardConfig);
|
|
6
|
+
/**
|
|
7
|
+
* Reset the call counter. Called by AuthorityLayer at the start of wrap().
|
|
8
|
+
*/
|
|
9
|
+
reset(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Increment the counter and check against the per-run limit.
|
|
12
|
+
* Returns a PendingHalt once the count exceeds the limit.
|
|
13
|
+
*/
|
|
14
|
+
tick(): GuardResult;
|
|
15
|
+
getCount(): number;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=loopGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopGuard.d.ts","sourceRoot":"","sources":["../../src/enforcement/loopGuard.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE7D,qBAAa,SAAS;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,MAAM,EAAE,eAAe;IAInC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,IAAI,IAAI,WAAW;IAenB,QAAQ,IAAI,MAAM;CAGrB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
// LoopGuard — Per-Run Tool Call Limiter
|
|
4
|
+
//
|
|
5
|
+
// Prevents infinite tool loops within a single agent run by counting every
|
|
6
|
+
// call routed through authority.tool(). The counter resets at the start of
|
|
7
|
+
// each wrap() invocation, so limits apply per-run, not globally.
|
|
8
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.LoopGuard = void 0;
|
|
11
|
+
class LoopGuard {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.count = 0;
|
|
14
|
+
this.limit = config.maxToolCallsPerRun;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reset the call counter. Called by AuthorityLayer at the start of wrap().
|
|
18
|
+
*/
|
|
19
|
+
reset() {
|
|
20
|
+
this.count = 0;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Increment the counter and check against the per-run limit.
|
|
24
|
+
* Returns a PendingHalt once the count exceeds the limit.
|
|
25
|
+
*/
|
|
26
|
+
tick() {
|
|
27
|
+
this.count += 1;
|
|
28
|
+
if (this.count > this.limit) {
|
|
29
|
+
return {
|
|
30
|
+
status: "halted",
|
|
31
|
+
reason: "loop_limit_exceeded",
|
|
32
|
+
limit: this.limit,
|
|
33
|
+
spent: this.count,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { status: "ok" };
|
|
37
|
+
}
|
|
38
|
+
getCount() {
|
|
39
|
+
return this.count;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.LoopGuard = LoopGuard;
|
|
43
|
+
//# sourceMappingURL=loopGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopGuard.js","sourceRoot":"","sources":["../../src/enforcement/loopGuard.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,wCAAwC;AACxC,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,iEAAiE;AACjE,gFAAgF;;;AAIhF,MAAa,SAAS;IAIlB,YAAY,MAAuB;QAH3B,UAAK,GAAG,CAAC,CAAC;QAId,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK;QACD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,IAAI;QACA,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAEhB,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,qBAAqB;gBAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;aACpB,CAAC;QACN,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;CACJ;AArCD,8BAqCC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ToolThrottleConfig, GuardResult } from "../types";
|
|
2
|
+
export declare class ToolThrottle {
|
|
3
|
+
/**
|
|
4
|
+
* Stores the timestamp (ms since epoch) of each tool call inside the
|
|
5
|
+
* current sliding window. Entries older than WINDOW_MS are pruned on
|
|
6
|
+
* every tick so the array never grows unbounded.
|
|
7
|
+
*/
|
|
8
|
+
private callTimestamps;
|
|
9
|
+
private readonly limit;
|
|
10
|
+
constructor(config: ToolThrottleConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Record a tool call and check the rate against the configured limit.
|
|
13
|
+
* Returns a PendingHalt if the call count in the last 60 seconds exceeds
|
|
14
|
+
* maxCallsPerMinute.
|
|
15
|
+
*/
|
|
16
|
+
tick(): GuardResult;
|
|
17
|
+
/** Returns the number of calls recorded in the current window (for diagnostics). */
|
|
18
|
+
getWindowCount(): number;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=toolThrottle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolThrottle.d.ts","sourceRoot":"","sources":["../../src/enforcement/toolThrottle.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAIhE,qBAAa,YAAY;IACrB;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,MAAM,EAAE,kBAAkB;IAItC;;;;OAIG;IACH,IAAI,IAAI,WAAW;IAuBnB,oFAAoF;IACpF,cAAc,IAAI,MAAM;CAI3B"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
// ToolThrottle — Sliding-Window Rate Limiter
|
|
4
|
+
//
|
|
5
|
+
// Caps the number of tool calls within any 60-second window using a sliding
|
|
6
|
+
// timestamp array. Unlike a fixed-bucket approach, this never resets abruptly
|
|
7
|
+
// mid-window — it always reflects the true call density in the last minute.
|
|
8
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ToolThrottle = void 0;
|
|
11
|
+
const WINDOW_MS = 60000; // 1-minute sliding window
|
|
12
|
+
class ToolThrottle {
|
|
13
|
+
constructor(config) {
|
|
14
|
+
/**
|
|
15
|
+
* Stores the timestamp (ms since epoch) of each tool call inside the
|
|
16
|
+
* current sliding window. Entries older than WINDOW_MS are pruned on
|
|
17
|
+
* every tick so the array never grows unbounded.
|
|
18
|
+
*/
|
|
19
|
+
this.callTimestamps = [];
|
|
20
|
+
this.limit = config.maxCallsPerMinute;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Record a tool call and check the rate against the configured limit.
|
|
24
|
+
* Returns a PendingHalt if the call count in the last 60 seconds exceeds
|
|
25
|
+
* maxCallsPerMinute.
|
|
26
|
+
*/
|
|
27
|
+
tick() {
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
// Evict calls that have slid out of the window
|
|
30
|
+
this.callTimestamps = this.callTimestamps.filter((t) => now - t < WINDOW_MS);
|
|
31
|
+
this.callTimestamps.push(now);
|
|
32
|
+
const callsInWindow = this.callTimestamps.length;
|
|
33
|
+
if (callsInWindow > this.limit) {
|
|
34
|
+
return {
|
|
35
|
+
status: "halted",
|
|
36
|
+
reason: "tool_throttle_exceeded",
|
|
37
|
+
limit: this.limit,
|
|
38
|
+
spent: callsInWindow,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { status: "ok" };
|
|
42
|
+
}
|
|
43
|
+
/** Returns the number of calls recorded in the current window (for diagnostics). */
|
|
44
|
+
getWindowCount() {
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
return this.callTimestamps.filter((t) => now - t < WINDOW_MS).length;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.ToolThrottle = ToolThrottle;
|
|
50
|
+
//# sourceMappingURL=toolThrottle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolThrottle.js","sourceRoot":"","sources":["../../src/enforcement/toolThrottle.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,6CAA6C;AAC7C,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,4EAA4E;AAC5E,gFAAgF;;;AAIhF,MAAM,SAAS,GAAG,KAAM,CAAC,CAAC,0BAA0B;AAEpD,MAAa,YAAY;IASrB,YAAY,MAA0B;QARtC;;;;WAIG;QACK,mBAAc,GAAa,EAAE,CAAC;QAIlC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,+CAA+C;QAC/C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAC5C,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAC7B,CAAC;QAEF,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC;QAEjD,IAAI,aAAa,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7B,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,wBAAwB;gBAChC,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,aAAa;aACvB,CAAC;QACN,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,oFAAoF;IACpF,cAAc;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC;IACzE,CAAC;CACJ;AA9CD,oCA8CC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AuthorityLayer } from "./AuthorityLayer";
|
|
2
|
+
export { EnforcementHalt } from "./EnforcementHalt";
|
|
3
|
+
export type { AuthorityConfig, BudgetConfig, LoopGuardConfig, ToolThrottleConfig, EnforcementMode, HaltResult, HaltReason, PassResult, GuardResult, EnforcementEvent, } from "./types";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,YAAY,EACR,eAAe,EACf,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,gBAAgB,GACnB,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Public surface of the authority-layer package.
|
|
3
|
+
// Import from here, not from internal module paths.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.EnforcementHalt = exports.AuthorityLayer = void 0;
|
|
6
|
+
var AuthorityLayer_1 = require("./AuthorityLayer");
|
|
7
|
+
Object.defineProperty(exports, "AuthorityLayer", { enumerable: true, get: function () { return AuthorityLayer_1.AuthorityLayer; } });
|
|
8
|
+
var EnforcementHalt_1 = require("./EnforcementHalt");
|
|
9
|
+
Object.defineProperty(exports, "EnforcementHalt", { enumerable: true, get: function () { return EnforcementHalt_1.EnforcementHalt; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,oDAAoD;;;AAEpD,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EnforcementEvent } from "../types";
|
|
2
|
+
export declare class HashChain {
|
|
3
|
+
private readonly chain;
|
|
4
|
+
private previousHash;
|
|
5
|
+
/**
|
|
6
|
+
* Append a new event to the chain.
|
|
7
|
+
*
|
|
8
|
+
* The hash covers the serialized event fields (event_id, type, timestamp,
|
|
9
|
+
* data) concatenated with the previous event's hash. This means you cannot
|
|
10
|
+
* alter any event — or its position in the chain — without invalidating all
|
|
11
|
+
* subsequent hashes.
|
|
12
|
+
*/
|
|
13
|
+
append(type: string, data: Record<string, unknown>): EnforcementEvent;
|
|
14
|
+
/**
|
|
15
|
+
* Return an immutable copy of the full event chain.
|
|
16
|
+
*/
|
|
17
|
+
getChain(): ReadonlyArray<EnforcementEvent>;
|
|
18
|
+
/**
|
|
19
|
+
* Verify the integrity of the entire chain locally.
|
|
20
|
+
*
|
|
21
|
+
* Re-derives each event's hash from its fields and previousHash, then
|
|
22
|
+
* compares against the stored hash. Returns false if any event has been
|
|
23
|
+
* tampered with or if the linkage is broken.
|
|
24
|
+
*/
|
|
25
|
+
verify(): boolean;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=hashChain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashChain.d.ts","sourceRoot":"","sources":["../../src/integrity/hashChain.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAKjD,qBAAa,SAAS;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,YAAY,CAAwB;IAE5C;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB;IAyBrE;;OAEG;IACH,QAAQ,IAAI,aAAa,CAAC,gBAAgB,CAAC;IAI3C;;;;;;OAMG;IACH,MAAM,IAAI,OAAO;CA4BpB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
// HashChain — Tamper-Evident Enforcement Event Log
|
|
4
|
+
//
|
|
5
|
+
// Stores enforcement events in memory as a hash-linked chain. Each event
|
|
6
|
+
// includes a SHA-256 hash chained to the previous event's hash, making it
|
|
7
|
+
// detectable if any event is retroactively altered or removed.
|
|
8
|
+
//
|
|
9
|
+
// V1: in-memory only. No disk persistence or cloud anchoring.
|
|
10
|
+
// Future: optional disk flush and independent cloud anchor.
|
|
11
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.HashChain = void 0;
|
|
14
|
+
const crypto_1 = require("crypto");
|
|
15
|
+
/** Sentinel value used as the previousHash for the first event in the chain. */
|
|
16
|
+
const GENESIS_HASH = "genesis";
|
|
17
|
+
class HashChain {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.chain = [];
|
|
20
|
+
this.previousHash = GENESIS_HASH;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Append a new event to the chain.
|
|
24
|
+
*
|
|
25
|
+
* The hash covers the serialized event fields (event_id, type, timestamp,
|
|
26
|
+
* data) concatenated with the previous event's hash. This means you cannot
|
|
27
|
+
* alter any event — or its position in the chain — without invalidating all
|
|
28
|
+
* subsequent hashes.
|
|
29
|
+
*/
|
|
30
|
+
append(type, data) {
|
|
31
|
+
const event_id = `evt_${(0, crypto_1.randomBytes)(8).toString("hex")}`;
|
|
32
|
+
const timestamp = new Date().toISOString();
|
|
33
|
+
// Hash covers content + chain position (previousHash)
|
|
34
|
+
const payload = JSON.stringify({ event_id, type, timestamp, data });
|
|
35
|
+
const hash = (0, crypto_1.createHash)("sha256")
|
|
36
|
+
.update(payload + this.previousHash)
|
|
37
|
+
.digest("hex");
|
|
38
|
+
const event = {
|
|
39
|
+
event_id,
|
|
40
|
+
type,
|
|
41
|
+
timestamp,
|
|
42
|
+
data,
|
|
43
|
+
hash,
|
|
44
|
+
previousHash: this.previousHash,
|
|
45
|
+
};
|
|
46
|
+
this.chain.push(event);
|
|
47
|
+
this.previousHash = hash;
|
|
48
|
+
return event;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Return an immutable copy of the full event chain.
|
|
52
|
+
*/
|
|
53
|
+
getChain() {
|
|
54
|
+
return Object.freeze([...this.chain]);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Verify the integrity of the entire chain locally.
|
|
58
|
+
*
|
|
59
|
+
* Re-derives each event's hash from its fields and previousHash, then
|
|
60
|
+
* compares against the stored hash. Returns false if any event has been
|
|
61
|
+
* tampered with or if the linkage is broken.
|
|
62
|
+
*/
|
|
63
|
+
verify() {
|
|
64
|
+
let prev = GENESIS_HASH;
|
|
65
|
+
for (const event of this.chain) {
|
|
66
|
+
if (event.previousHash !== prev) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const payload = JSON.stringify({
|
|
70
|
+
event_id: event.event_id,
|
|
71
|
+
type: event.type,
|
|
72
|
+
timestamp: event.timestamp,
|
|
73
|
+
data: event.data,
|
|
74
|
+
});
|
|
75
|
+
const expected = (0, crypto_1.createHash)("sha256")
|
|
76
|
+
.update(payload + prev)
|
|
77
|
+
.digest("hex");
|
|
78
|
+
if (expected !== event.hash) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
prev = event.hash;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.HashChain = HashChain;
|
|
87
|
+
//# sourceMappingURL=hashChain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashChain.js","sourceRoot":"","sources":["../../src/integrity/hashChain.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,mDAAmD;AACnD,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAC1E,+DAA+D;AAC/D,EAAE;AACF,8DAA8D;AAC9D,4DAA4D;AAC5D,gFAAgF;;;AAEhF,mCAAiD;AAGjD,gFAAgF;AAChF,MAAM,YAAY,GAAG,SAAS,CAAC;AAE/B,MAAa,SAAS;IAAtB;QACqB,UAAK,GAAuB,EAAE,CAAC;QACxC,iBAAY,GAAW,YAAY,CAAC;IA6EhD,CAAC;IA3EG;;;;;;;OAOG;IACH,MAAM,CAAC,IAAY,EAAE,IAA6B;QAC9C,MAAM,QAAQ,GAAG,OAAO,IAAA,oBAAW,EAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE3C,sDAAsD;QACtD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC;aAC5B,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;aACnC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEnB,MAAM,KAAK,GAAqB;YAC5B,QAAQ;YACR,IAAI;YACJ,SAAS;YACT,IAAI;YACJ,IAAI;YACJ,YAAY,EAAE,IAAI,CAAC,YAAY;SAClC,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAEzB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,QAAQ;QACJ,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;OAMG;IACH,MAAM;QACF,IAAI,IAAI,GAAG,YAAY,CAAC;QAExB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;gBAC9B,OAAO,KAAK,CAAC;YACjB,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;aACnB,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC;iBAChC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;iBACtB,MAAM,CAAC,KAAK,CAAC,CAAC;YAEnB,IAAI,QAAQ,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC1B,OAAO,KAAK,CAAC;YACjB,CAAC;YAED,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACtB,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AA/ED,8BA+EC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enforcement mode.
|
|
3
|
+
* "strict" — limits halt execution immediately (default, V1 implemented)
|
|
4
|
+
* "warn" — limits emit a warning but allow continuation (V1 stubbed)
|
|
5
|
+
*/
|
|
6
|
+
export type EnforcementMode = "strict" | "warn";
|
|
7
|
+
export interface BudgetConfig {
|
|
8
|
+
/** Hard daily spend cap in USD. Execution halts if cumulative spend exceeds this. */
|
|
9
|
+
dailyUSD: number;
|
|
10
|
+
}
|
|
11
|
+
export interface LoopGuardConfig {
|
|
12
|
+
/** Maximum number of tool calls allowed per wrap() invocation. */
|
|
13
|
+
maxToolCallsPerRun: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ToolThrottleConfig {
|
|
16
|
+
/** Maximum number of tool calls allowed within any 60-second sliding window. */
|
|
17
|
+
maxCallsPerMinute: number;
|
|
18
|
+
}
|
|
19
|
+
export interface AuthorityConfig {
|
|
20
|
+
/**
|
|
21
|
+
* Enforcement mode. Defaults to "strict".
|
|
22
|
+
* In V1, only "strict" is fully implemented. "warn" is stubbed.
|
|
23
|
+
*/
|
|
24
|
+
mode?: EnforcementMode;
|
|
25
|
+
/** Enable hard USD budget cap. Omit to disable. */
|
|
26
|
+
budget?: BudgetConfig;
|
|
27
|
+
/** Enable loop/call-count guard per run. Omit to disable. */
|
|
28
|
+
loopGuard?: LoopGuardConfig;
|
|
29
|
+
/** Enable tool call rate throttle. Omit to disable. */
|
|
30
|
+
toolThrottle?: ToolThrottleConfig;
|
|
31
|
+
}
|
|
32
|
+
export type HaltReason = "budget_exceeded" | "loop_limit_exceeded" | "tool_throttle_exceeded";
|
|
33
|
+
/**
|
|
34
|
+
* Internal guard result before the event chain assigns an event_id.
|
|
35
|
+
* Guards return this; AuthorityLayer promotes it to HaltResult after logging.
|
|
36
|
+
*/
|
|
37
|
+
export interface PendingHalt {
|
|
38
|
+
status: "halted";
|
|
39
|
+
reason: HaltReason;
|
|
40
|
+
/** The configured limit that was breached. */
|
|
41
|
+
limit: number;
|
|
42
|
+
/** The value that exceeded the limit (spend, call count, etc.). */
|
|
43
|
+
spent: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The public enforcement halt object. Returned on the EnforcementHalt error
|
|
47
|
+
* and also accessible via .enforcement on that error instance.
|
|
48
|
+
*
|
|
49
|
+
* Always prefer accessing this via `error.enforcement` rather than parsing
|
|
50
|
+
* the error message string.
|
|
51
|
+
*/
|
|
52
|
+
export interface HaltResult extends PendingHalt {
|
|
53
|
+
/** Unique event ID assigned by the hash-linked event chain. */
|
|
54
|
+
event_id: string;
|
|
55
|
+
}
|
|
56
|
+
export interface PassResult {
|
|
57
|
+
status: "ok";
|
|
58
|
+
}
|
|
59
|
+
/** Union returned by all guard check methods. */
|
|
60
|
+
export type GuardResult = PendingHalt | PassResult;
|
|
61
|
+
/**
|
|
62
|
+
* A single entry in the enforcement event chain.
|
|
63
|
+
* Each event is hash-linked to its predecessor, forming a tamper-evident log.
|
|
64
|
+
*/
|
|
65
|
+
export interface EnforcementEvent {
|
|
66
|
+
/** Unique identifier (evt_<random hex>). */
|
|
67
|
+
event_id: string;
|
|
68
|
+
/** Semantic event type, e.g. "enforcement.halt", "tool.call", "run.start". */
|
|
69
|
+
type: string;
|
|
70
|
+
/** ISO-8601 timestamp of the event. */
|
|
71
|
+
timestamp: string;
|
|
72
|
+
/** Arbitrary structured data for this event. */
|
|
73
|
+
data: Record<string, unknown>;
|
|
74
|
+
/** SHA-256 of (serialized event fields + previousHash). */
|
|
75
|
+
hash: string;
|
|
76
|
+
/** Hash of the preceding event ("genesis" for the first event). */
|
|
77
|
+
previousHash: string;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,CAAC;AAIhD,MAAM,WAAW,YAAY;IAC3B,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAID,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE,eAAe,CAAC;IAEvB,mDAAmD;IACnD,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B,uDAAuD;IACvD,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAID,MAAM,MAAM,UAAU,GAClB,iBAAiB,GACjB,qBAAqB,GACrB,wBAAwB,CAAC;AAE7B;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,IAAI,CAAC;CACd;AAED,iDAAiD;AACjD,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAInD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
// AuthorityLayer — Shared Types
|
|
4
|
+
//
|
|
5
|
+
// All interfaces used across enforcement primitives and the core class live
|
|
6
|
+
// here. Keeping them in one file makes cross-module consistency easy to audit.
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,gCAAgC;AAChC,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,gFAAgF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "authority-layer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Hard execution and budget limits for autonomous agents — enforced locally.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"bin": {
|
|
11
|
+
"authority-layer": "dist/doctor.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
16
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
17
|
+
"validate": "tsc -p tsconfig.json && node dist/index.js",
|
|
18
|
+
"example": "node ../../examples/run.js",
|
|
19
|
+
"doctor": "node dist/doctor.js",
|
|
20
|
+
"prepublishOnly": "npm run build && npm run typecheck"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"ai",
|
|
24
|
+
"agents",
|
|
25
|
+
"guardrails",
|
|
26
|
+
"runtime",
|
|
27
|
+
"budget",
|
|
28
|
+
"limits"
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/032383justin/authority-layer"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/032383justin/authority-layer",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/032383justin/authority-layer/issues"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18.0.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"typescript": "^5.4.0",
|
|
44
|
+
"@types/node": "^20.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|