aae-protocol 0.0.1 → 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/README.md CHANGED
@@ -1,8 +1,51 @@
1
- # aae-protocol (name reservation)
1
+ # @aae/protocol (TypeScript)
2
2
 
3
- Placeholder reserving the `aae-protocol` name for **Accountable Agentic
4
- Execution** — a protocol for governing what AI agents do.
3
+ TypeScript / JavaScript SDK for the [Accountable Agentic Execution (AAE)](https://github.com/r3moteBee/aae) protocol.
5
4
 
6
- This 0.0.1 release contains no implementation. The real SDK lands at 0.7.0+.
5
+ ## Install
7
6
 
8
- Project: https://github.com/r3moteBee/aae
7
+ ```bash
8
+ npm install @aae/protocol
9
+ # or
10
+ pnpm add @aae/protocol
11
+ ```
12
+
13
+ ## What this provides
14
+
15
+ - Zod schemas for every AAE protocol type (parse-and-validate at runtime, infer TS types at compile time)
16
+ - Hash chain helpers (RFC 8785 canonicalization via `json-canonicalize`, SHA-256 chain construction, verification)
17
+ - Capability token mint/verify (JWT via `jose`)
18
+ - Reference adapters for policy, audit sink, and approval delivery (TODO)
19
+
20
+ ## Quick example
21
+
22
+ ```ts
23
+ import { ProposalSchema, type Proposal, BlastRadius } from "@aae/protocol";
24
+ import { verifyChain } from "@aae/protocol/hashchain";
25
+ import { ulid } from "ulid";
26
+
27
+ const proposal: Proposal = ProposalSchema.parse({
28
+ aae_version: "0.1",
29
+ proposal_id: ulid(),
30
+ agent_id: "ops-agent-v3",
31
+ tenant_id: "default",
32
+ intent: "restart_test_service",
33
+ context: { rationale: "QA asked" },
34
+ steps: [
35
+ {
36
+ tool: "ssh_exec",
37
+ args: { host: "test-01", command: "systemctl restart test" },
38
+ blast_radius: BlastRadius.SINGLE_SERVICE,
39
+ },
40
+ ],
41
+ submitted_at: new Date().toISOString(),
42
+ });
43
+ ```
44
+
45
+ ## Status
46
+
47
+ v0.1 — early development. APIs may shift before v1.0.
48
+
49
+ ## License
50
+
51
+ MIT OR Apache-2.0
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Hash chain helpers: RFC 8785 canonicalization, chain construction, verification.
3
+ *
4
+ * Verification semantics match the Python and Rust SDKs; conformance fixtures
5
+ * in reference-tests/conformance.json validate cross-SDK byte-for-byte equality.
6
+ */
7
+ import type { AuditEvent } from "./models.js";
8
+ export declare const HASH_PREFIX: "sha256:";
9
+ export declare class ChainError extends Error {
10
+ readonly eventId?: string | undefined;
11
+ name: string;
12
+ constructor(message: string, eventId?: string | undefined);
13
+ }
14
+ /**
15
+ * Produce the hashing view of an event (normative; mirrors the Python SDK's
16
+ * `_event_to_canonical_dict`, the single point of truth):
17
+ * - `this_event_hash` is excluded.
18
+ * - `signature` is excluded when null/undefined (None-valued optional
19
+ * fields don't pollute the hash).
20
+ * - `prev_event_hash` is INCLUDED even when null (genesis marker is
21
+ * structurally significant).
22
+ */
23
+ export declare function eventForHashing(event: Record<string, unknown>): Record<string, unknown>;
24
+ /**
25
+ * Compute this_event_hash from an event-shaped object that does NOT include
26
+ * this_event_hash itself, plus the previous chain tip.
27
+ */
28
+ export declare function computeEventHash(eventWithoutHash: Record<string, unknown>, prevEventHash: string | null): string;
29
+ /**
30
+ * Append an event to the chain by computing and assigning this_event_hash.
31
+ * Returns a new event object; does not mutate the input.
32
+ */
33
+ export declare function appendEvent(event: AuditEvent, prevEventHash: string | null): AuditEvent;
34
+ /**
35
+ * Value-based chain production: seal a raw event object onto the chain.
36
+ * Sets prev_event_hash and this_event_hash on a copy and returns it.
37
+ * Producers using this path control their serialization byte-for-byte
38
+ * (C-3: no typed round-trip can alter timestamp precision).
39
+ */
40
+ export declare function appendEventValue(event: Record<string, unknown>, prevEventHash: string | null): Record<string, unknown>;
41
+ /**
42
+ * Value-based chain verification for chains produced by other
43
+ * implementations (C-3-safe: hashes the received JSON as-is). Returns the
44
+ * tip hash; throws ChainError on any break.
45
+ */
46
+ export declare function verifyChainValues(events: Record<string, unknown>[]): string;
47
+ /**
48
+ * Verify a single event's this_event_hash matches its recomputed hash.
49
+ */
50
+ export declare function verifyEvent(event: AuditEvent): boolean;
51
+ /**
52
+ * Verify a sequence of events forms a valid hash chain. Returns the tip hash
53
+ * on success; throws ChainError on the first detected problem.
54
+ */
55
+ export declare function verifyChain(events: AuditEvent[]): string;
56
+ //# sourceMappingURL=hashchain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashchain.d.ts","sourceRoot":"","sources":["../src/hashchain.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,eAAO,MAAM,WAAW,EAAG,SAAkB,CAAC;AAE9C,qBAAa,UAAW,SAAQ,KAAK;aAInB,OAAO,CAAC,EAAE,MAAM;IAHxB,IAAI,SAAgB;gBAE5B,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,YAAA;CAIjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC/B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzC,aAAa,EAAE,MAAM,GAAG,IAAI,GAC1B,MAAM,CAMR;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,KAAK,EAAE,UAAU,EACjB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC1B,UAAU,CAIZ;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAyB3E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAMtD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAoCxD"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Hash chain helpers: RFC 8785 canonicalization, chain construction, verification.
3
+ *
4
+ * Verification semantics match the Python and Rust SDKs; conformance fixtures
5
+ * in reference-tests/conformance.json validate cross-SDK byte-for-byte equality.
6
+ */
7
+ import { createHash } from "node:crypto";
8
+ import { canonicalize } from "json-canonicalize";
9
+ export const HASH_PREFIX = "sha256:";
10
+ export class ChainError extends Error {
11
+ eventId;
12
+ name = "ChainError";
13
+ constructor(message, eventId) {
14
+ super(message);
15
+ this.eventId = eventId;
16
+ }
17
+ }
18
+ /**
19
+ * Produce the hashing view of an event (normative; mirrors the Python SDK's
20
+ * `_event_to_canonical_dict`, the single point of truth):
21
+ * - `this_event_hash` is excluded.
22
+ * - `signature` is excluded when null/undefined (None-valued optional
23
+ * fields don't pollute the hash).
24
+ * - `prev_event_hash` is INCLUDED even when null (genesis marker is
25
+ * structurally significant).
26
+ */
27
+ export function eventForHashing(event) {
28
+ const { this_event_hash: _omit, signature, ...view } = event;
29
+ void _omit;
30
+ if (signature !== null && signature !== undefined) {
31
+ return { ...view, signature };
32
+ }
33
+ return view;
34
+ }
35
+ /**
36
+ * Compute this_event_hash from an event-shaped object that does NOT include
37
+ * this_event_hash itself, plus the previous chain tip.
38
+ */
39
+ export function computeEventHash(eventWithoutHash, prevEventHash) {
40
+ const canonical = canonicalize(eventWithoutHash);
41
+ const hasher = createHash("sha256");
42
+ hasher.update(canonical, "utf8");
43
+ hasher.update(prevEventHash ?? "", "utf8");
44
+ return `${HASH_PREFIX}${hasher.digest("hex")}`;
45
+ }
46
+ /**
47
+ * Append an event to the chain by computing and assigning this_event_hash.
48
+ * Returns a new event object; does not mutate the input.
49
+ */
50
+ export function appendEvent(event, prevEventHash) {
51
+ const withPrev = { ...event, prev_event_hash: prevEventHash };
52
+ const newHash = computeEventHash(eventForHashing(withPrev), prevEventHash);
53
+ return { ...withPrev, this_event_hash: newHash };
54
+ }
55
+ /**
56
+ * Value-based chain production: seal a raw event object onto the chain.
57
+ * Sets prev_event_hash and this_event_hash on a copy and returns it.
58
+ * Producers using this path control their serialization byte-for-byte
59
+ * (C-3: no typed round-trip can alter timestamp precision).
60
+ */
61
+ export function appendEventValue(event, prevEventHash) {
62
+ const sealed = {
63
+ ...event,
64
+ prev_event_hash: prevEventHash,
65
+ };
66
+ const hash = computeEventHash(eventForHashing(sealed), prevEventHash);
67
+ sealed.this_event_hash = hash;
68
+ return sealed;
69
+ }
70
+ /**
71
+ * Value-based chain verification for chains produced by other
72
+ * implementations (C-3-safe: hashes the received JSON as-is). Returns the
73
+ * tip hash; throws ChainError on any break.
74
+ */
75
+ export function verifyChainValues(events) {
76
+ if (events.length === 0)
77
+ throw new ChainError("empty chain");
78
+ const first = events[0];
79
+ if (first === undefined || first.prev_event_hash !== null) {
80
+ throw new ChainError("genesis event must have prev_event_hash=null");
81
+ }
82
+ let prev = null;
83
+ for (const ev of events) {
84
+ if ((ev.prev_event_hash ?? null) !== prev) {
85
+ throw new ChainError(`prev_event_hash mismatch at ${String(ev.event_id)}`, String(ev.event_id));
86
+ }
87
+ const expected = computeEventHash(eventForHashing(ev), prev);
88
+ if (expected !== ev.this_event_hash) {
89
+ throw new ChainError(`this_event_hash mismatch at ${String(ev.event_id)}`, String(ev.event_id));
90
+ }
91
+ prev = ev.this_event_hash;
92
+ }
93
+ if (prev === null)
94
+ throw new ChainError("empty chain");
95
+ return prev;
96
+ }
97
+ /**
98
+ * Verify a single event's this_event_hash matches its recomputed hash.
99
+ */
100
+ export function verifyEvent(event) {
101
+ const expected = computeEventHash(eventForHashing(event), event.prev_event_hash);
102
+ return expected === event.this_event_hash;
103
+ }
104
+ /**
105
+ * Verify a sequence of events forms a valid hash chain. Returns the tip hash
106
+ * on success; throws ChainError on the first detected problem.
107
+ */
108
+ export function verifyChain(events) {
109
+ if (events.length === 0) {
110
+ throw new ChainError("empty chain");
111
+ }
112
+ const first = events[0];
113
+ if (first === undefined) {
114
+ throw new ChainError("empty chain");
115
+ }
116
+ if (first.prev_event_hash !== null) {
117
+ throw new ChainError("genesis event must have prev_event_hash=null", first.event_id);
118
+ }
119
+ let prev = null;
120
+ for (const ev of events) {
121
+ if (ev.prev_event_hash !== prev) {
122
+ throw new ChainError(`prev_event_hash mismatch: expected ${prev}, got ${ev.prev_event_hash}`, ev.event_id);
123
+ }
124
+ if (!verifyEvent(ev)) {
125
+ throw new ChainError("this_event_hash does not match recomputed", ev.event_id);
126
+ }
127
+ prev = ev.this_event_hash;
128
+ }
129
+ if (prev === null) {
130
+ throw new ChainError("empty chain after iteration");
131
+ }
132
+ return prev;
133
+ }
134
+ //# sourceMappingURL=hashchain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashchain.js","sourceRoot":"","sources":["../src/hashchain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @aae/protocol — Accountable Agentic Execution protocol SDK for TypeScript.
3
+ *
4
+ * See https://github.com/r3moteBee/aae for the protocol specification.
5
+ */
6
+ export * from "./models.js";
7
+ export * as hashchain from "./hashchain.js";
8
+ export * as signing from "./signing.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @aae/protocol — Accountable Agentic Execution protocol SDK for TypeScript.
3
+ *
4
+ * See https://github.com/r3moteBee/aae for the protocol specification.
5
+ */
6
+ export * from "./models.js";
7
+ export * as hashchain from "./hashchain.js";
8
+ export * as signing from "./signing.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC"}