@responsibleai/agent-hooks 0.1.0-alpha.5 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,8 @@ TypeScript implementation of
5
5
  over the canonical Rust core (napi-rs native module): interception
6
6
  points, `AgentContextBuilder`, `Verdict` types, host-side
7
7
  `InterceptionEmitter` with the four composition profiles, the
8
- identity-provider seam, and the CTK runner.
8
+ identity-provider seam, the host declaration loader, and the CTK
9
+ runner.
9
10
 
10
11
  > **Trust model.** agent-hooks is a *cooperative contract*, not a security
11
12
  > boundary: the host framework is fully trusted, interceptors run in-process
@@ -15,11 +16,15 @@ identity-provider seam, and the CTK runner.
15
16
  > before relying on it.
16
17
 
17
18
  ```bash
18
- # Not yet published to npm — install from source:
19
- git clone https://github.com/responsibleai/agent-hooks && cd agent-hooks/sdk/typescript
20
- npm install && npm run build # builds the native module (needs a Rust toolchain)
19
+ npm install @responsibleai/agent-hooks@alpha
21
20
  ```
22
21
 
22
+ Keep the `@alpha` tag (or pin an exact published version) while the
23
+ package is pre-release: npm's `latest` tag can lag the newest
24
+ pre-release, so a plain `npm install` may fetch an older build. Check
25
+ what the tags resolve to with
26
+ `npm view @responsibleai/agent-hooks dist-tags`.
27
+
23
28
  ## Usage
24
29
 
25
30
  ```ts
@@ -40,11 +45,75 @@ const ctx = builder.preToolCall("tc-1", "http_get", { url });
40
45
  await emitter.emit(ctx); // throws InterceptionBlocked on a combined deny
41
46
  ```
42
47
 
48
+ `register(interceptor, name?, at?)` also takes the points an
49
+ interceptor runs at. At a point, `interceptors_registered`,
50
+ `verdicts[].index` and `decided_by` count and index the interceptors
51
+ bound there, in registration order.
52
+
53
+ ## Host declaration
54
+
55
+ A host can load its configuration, declared surface and interceptor
56
+ bindings from one JSON document (spec §7.7) instead of calling the
57
+ setters. The document is a versioned contract,
58
+ `agent-hooks-declaration/1.0`, separate from the wire version
59
+ `agent-hooks/0.1`. The SDK exports the version it writes
60
+ (`DECLARATION_VERSION`) and the set it accepts
61
+ (`SUPPORTED_DECLARATION_VERSIONS`). A document of any other version is
62
+ refused.
63
+
64
+ ```ts
65
+ import {
66
+ HostDeclaration,
67
+ HostRegistry,
68
+ HostSurface,
69
+ InterceptionEmitter,
70
+ } from "@responsibleai/agent-hooks";
71
+
72
+ // What the code can honour. A document may select a subset, never more.
73
+ const surface = HostSurface.fromCapabilities(["model_calls", "tool_calls", "host_declaration"]);
74
+
75
+ // Kind resolvers turn a binding's `config` into an interceptor. A kind
76
+ // is a lookup key the host names; the spec defines none.
77
+ const registry = new HostRegistry(surface)
78
+ .kind("com.example.egress", (config, ctx) => new EgressGuard(config))
79
+ .approvalResolver("operator-queue", queue);
80
+
81
+ const emitter = await InterceptionEmitter.fromDeclarationPath(
82
+ "agent-hooks.declaration.json",
83
+ registry,
84
+ );
85
+ ```
86
+
87
+ The three construction paths yield the same emitter and the same
88
+ records: `fromDeclarationPath` reads a file, `fromDeclarationJson`
89
+ takes the text, `fromDeclarationValue` takes a parsed object, and
90
+ `fromDeclaration` takes a `HostDeclaration` (for example from
91
+ `HostDeclaration.builder()`, one setter per member and `bind(...)` per
92
+ binding). `emitter.declaration` is the resolved form with every default
93
+ filled; `canonicalDeclaration(emitter.declaration)` is its RFC 8785
94
+ canonical JSON, the equivalence oracle.
95
+
96
+ A document that names anything the host cannot honour is refused at
97
+ load, before any emission, with a `DeclarationError`. The error carries
98
+ `code` (one of eleven `declaration_error:*` classes), `findings` (JSON
99
+ pointer plus detail, never binding configuration) and, for
100
+ `version_unsupported`, `accepted`. The Rust core runs every check, so
101
+ the class is the same as in the other SDKs. An emitter built from a
102
+ declaration is sealed: `register` and the setters throw
103
+ `EmitterSealed`; `setRecordSink` and `takeRecords` stay allowed.
104
+ Records from such an emitter carry `declaration:
105
+ "agent-hooks-declaration/1.0"`; records from an emitter configured in
106
+ code do not and are unchanged.
107
+
43
108
  **JavaScript value-domain caveat (spec §4.4):** `JSON.parse` rounds
44
109
  integers beyond 2^53 before any guard can run, so this SDK cannot claim
45
110
  the `int64_json`/`bigint_json` CTK capabilities — string-encode
46
111
  64-bit identifiers at the adapter boundary. Non-finite numbers are
47
- rejected fail-closed by a pre-serialization scan.
112
+ rejected fail-closed by a pre-serialization scan. The same rounding
113
+ applies to `bindings[].config`: the loader hands the core the validated
114
+ text, so the load checks see the integers the file had, but the
115
+ resolved form and a kind resolver receive JavaScript values.
116
+ String-encode 64-bit values in binding configuration too.
48
117
 
49
118
  ## Native module deployment
50
119
 
package/binding.d.ts CHANGED
@@ -1,5 +1,14 @@
1
1
  /* auto-generated by NAPI-RS */
2
2
  /* eslint-disable */
3
+
4
+ /**
5
+ * Which binding artifact the generated loader actually loaded: `'native'` for
6
+ * a native addon, otherwise the `platformArchABI` of the WASI flavor. Every
7
+ * flavor napi-rs can build is listed, because `NAPI_RS_NATIVE_LIBRARY_PATH`
8
+ * can point the loader at a WASI artifact this package does not build itself.
9
+ */
10
+ export declare const __napiBindingTarget: 'native' | 'wasm32-wasi' | 'wasm32-wasip1'
11
+
3
12
  export declare function applyTransform(targetJson: string, path: string, valueJson: string): string
4
13
 
5
14
  export declare function applyTransformCtx(ctxJson: string, path: string, valueJson: string): string
@@ -18,6 +27,31 @@ export declare function ctkScriptedResolve(rulesJson: string, ctxJson: string, i
18
27
 
19
28
  export declare function ctkShouldSkip(vectorJson: string, harnessCapsJson: string): string
20
29
 
30
+ /**
31
+ * Steps 2 to 10 of §7.7.6 against the wrapper's host description
32
+ * (`{surface, identity_providers, approval_resolvers,
33
+ * approval_redactors, kinds}`). Returns the resolved declaration JSON.
34
+ */
35
+ export declare function declarationResolve(documentJson: string, hostJson: string): string
36
+
37
+ /**
38
+ * Steps 2 to 8 of §7.7.6 against a code surface alone, no registry:
39
+ * what the CTK runner needs to read a harness's own document
40
+ * (§7.7.9). A surface that does not parse or that the core rejects is
41
+ * a wrapper defect and comes back as `marshal_error`, never as a
42
+ * refusal of the document.
43
+ */
44
+ export declare function declarationResolveSurface(documentJson: string, surfaceJson: string): string
45
+
46
+ /**
47
+ * Steps 2 to 7 of §7.7.6 over JSON text. Returns the validated
48
+ * document as JSON (verbatim, `$schema` included).
49
+ */
50
+ export declare function declarationValidate(documentJson: string): string
51
+
52
+ /** `{"current": "...", "supported": [...]}` (§7.7.2). */
53
+ export declare function declarationVersions(): string
54
+
21
55
  export declare function finalize(ctxJson: string, verdictJson: string, mode: string, optionsJson: string): string
22
56
 
23
57
  export declare function specVersion(): string