@tenova/swt3-ai 0.2.9 → 0.3.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 +241 -244
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
Witness your AI. Prove it followed the rules. Cryptographic accountability for every inference, tool call, and resource access.
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@tenova/swt3-ai)
|
|
4
4
|
[](https://www.npmjs.com/package/@tenova/swt3-ai)
|
|
@@ -6,26 +6,22 @@ Deterministic AI Governance for production agents. Zero latency. Zero data reten
|
|
|
6
6
|
|
|
7
7
|
# @tenova/swt3-ai
|
|
8
8
|
|
|
9
|
-
**SWT3 AI Witness SDK for TypeScript**:
|
|
9
|
+
**SWT3 AI Witness SDK for TypeScript**: tamper-proof evidence that your AI is doing what you say it does. Every inference hashed. Every tool call recorded. Every resource access checked against scope. No prompts or responses ever leave your infrastructure.
|
|
10
10
|
|
|
11
11
|
Works with OpenAI, Anthropic, Vercel AI SDK, and any OpenAI-compatible endpoint (vLLM, Ollama, Azure, Llama.cpp).
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The EU AI Act takes effect **August 2, 2026**. When regulators ask "prove your AI followed the rules," you need more than logs. You need cryptographic proof.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
## See It Work in 10 Seconds
|
|
18
|
-
|
|
19
|
-
No API keys. No account. No network calls.
|
|
15
|
+
## See It Work (No Account Needed)
|
|
20
16
|
|
|
21
17
|
```bash
|
|
22
18
|
npm install @tenova/swt3-ai
|
|
23
19
|
npx swt3-demo
|
|
24
20
|
```
|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
The demo runs the full pipeline locally: hash, extract, clear, anchor, verify. It shows a Regulatory Coverage Summary mapping each check to EU AI Act articles, with gaps highlighted. No API keys, no network calls.
|
|
27
23
|
|
|
28
|
-
## Three Lines
|
|
24
|
+
## Three Lines to Start Witnessing
|
|
29
25
|
|
|
30
26
|
### OpenAI
|
|
31
27
|
|
|
@@ -34,21 +30,21 @@ import { Witness } from "@tenova/swt3-ai";
|
|
|
34
30
|
import OpenAI from "openai";
|
|
35
31
|
|
|
36
32
|
const witness = new Witness({
|
|
37
|
-
endpoint: "https://
|
|
33
|
+
endpoint: "https://your-witness-endpoint.example.com",
|
|
38
34
|
apiKey: "axm_live_...",
|
|
39
|
-
tenantId: "
|
|
35
|
+
tenantId: "YOUR_TENANT",
|
|
40
36
|
});
|
|
41
37
|
|
|
42
38
|
const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
43
39
|
|
|
44
|
-
// Non-streaming
|
|
40
|
+
// Non-streaming
|
|
45
41
|
const response = await client.chat.completions.create({
|
|
46
42
|
model: "gpt-4o",
|
|
47
43
|
messages: [{ role: "user", content: "Summarize this contract..." }],
|
|
48
44
|
});
|
|
49
45
|
console.log(response.choices[0].message.content);
|
|
50
46
|
|
|
51
|
-
// Streaming
|
|
47
|
+
// Streaming works too. Chunks arrive in real-time, witnessing happens after.
|
|
52
48
|
const stream = await client.chat.completions.create({
|
|
53
49
|
model: "gpt-4o",
|
|
54
50
|
messages: [{ role: "user", content: "Explain quantum computing" }],
|
|
@@ -66,9 +62,9 @@ import { Witness } from "@tenova/swt3-ai";
|
|
|
66
62
|
import Anthropic from "@anthropic-ai/sdk";
|
|
67
63
|
|
|
68
64
|
const witness = new Witness({
|
|
69
|
-
endpoint: "https://
|
|
65
|
+
endpoint: "https://your-witness-endpoint.example.com",
|
|
70
66
|
apiKey: "axm_live_...",
|
|
71
|
-
tenantId: "
|
|
67
|
+
tenantId: "YOUR_TENANT",
|
|
72
68
|
});
|
|
73
69
|
|
|
74
70
|
const client = witness.wrap(new Anthropic()) as Anthropic;
|
|
@@ -78,17 +74,6 @@ const message = await client.messages.create({
|
|
|
78
74
|
max_tokens: 1024,
|
|
79
75
|
messages: [{ role: "user", content: "Draft a compliance memo" }],
|
|
80
76
|
});
|
|
81
|
-
|
|
82
|
-
// Streaming with Anthropic
|
|
83
|
-
const stream = await client.messages.create({
|
|
84
|
-
model: "claude-sonnet-4-20250514",
|
|
85
|
-
max_tokens: 1024,
|
|
86
|
-
messages: [{ role: "user", content: "Analyze this dataset" }],
|
|
87
|
-
stream: true,
|
|
88
|
-
});
|
|
89
|
-
for await (const event of stream) {
|
|
90
|
-
// events arrive in real-time, witnessing happens after stream ends
|
|
91
|
-
}
|
|
92
77
|
```
|
|
93
78
|
|
|
94
79
|
### Vercel AI SDK (Next.js / React)
|
|
@@ -99,9 +84,9 @@ import { streamText } from "ai";
|
|
|
99
84
|
import { openai } from "@ai-sdk/openai";
|
|
100
85
|
|
|
101
86
|
const witness = new Witness({
|
|
102
|
-
endpoint: "https://
|
|
87
|
+
endpoint: "https://your-witness-endpoint.example.com",
|
|
103
88
|
apiKey: "axm_live_...",
|
|
104
|
-
tenantId: "
|
|
89
|
+
tenantId: "YOUR_TENANT",
|
|
105
90
|
});
|
|
106
91
|
|
|
107
92
|
const prompt = "Summarize this contract for the board";
|
|
@@ -111,303 +96,315 @@ const result = await streamText({
|
|
|
111
96
|
prompt,
|
|
112
97
|
onFinish: witness.vercelOnFinish({ promptText: prompt }),
|
|
113
98
|
});
|
|
114
|
-
|
|
115
|
-
// Works with any Vercel AI SDK provider:OpenAI, Anthropic, Google, Mistral, custom
|
|
116
99
|
```
|
|
117
100
|
|
|
118
|
-
The `onFinish` hook is framework-
|
|
101
|
+
The `onFinish` hook is framework-native. No wrapping, no proxying. It fires after the stream completes and works with any Vercel AI SDK provider.
|
|
119
102
|
|
|
120
|
-
##
|
|
121
|
-
|
|
122
|
-
The SDK works out-of-the-box with any OpenAI-compatible endpoint. Run Llama 3 on vLLM, Mistral on Ollama, or any model behind an OpenAI-compatible API:every inference is witnessed identically.
|
|
103
|
+
## What the SDK Does
|
|
123
104
|
|
|
124
|
-
|
|
125
|
-
// vLLM with Llama 3, sovereign cloud, your hardware
|
|
126
|
-
const client = witness.wrap(
|
|
127
|
-
new OpenAI({ baseURL: "http://gpu-cluster.internal:8000/v1" }),
|
|
128
|
-
) as OpenAI;
|
|
129
|
-
|
|
130
|
-
const response = await client.chat.completions.create({
|
|
131
|
-
model: "meta-llama/Meta-Llama-3-70B-Instruct",
|
|
132
|
-
messages: [{ role: "user", content: "Classify this threat indicator" }],
|
|
133
|
-
});
|
|
134
|
-
// Same SWT3 anchor, same ledger, same audit trail:regardless of where the model runs
|
|
105
|
+
When your AI makes a call, the SDK:
|
|
135
106
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
107
|
+
1. **Hashes** the prompt and response locally using SHA-256 (raw text never leaves your machine)
|
|
108
|
+
2. **Extracts** numeric factors: model version, latency, token count, guardrail status
|
|
109
|
+
3. **Clears** sensitive metadata based on your clearing level (you control what goes on the wire)
|
|
110
|
+
4. **Anchors** the factors into a cryptographic fingerprint anyone can independently verify
|
|
111
|
+
5. **Buffers** and flushes anchors in the background (median overhead: under 1ms)
|
|
112
|
+
6. **Returns** your original response completely untouched
|
|
140
113
|
|
|
141
|
-
|
|
142
|
-
const azureClient = witness.wrap(
|
|
143
|
-
new OpenAI({
|
|
144
|
-
apiKey: process.env.AZURE_OPENAI_KEY,
|
|
145
|
-
baseURL: "https://your-resource.openai.azure.com/openai/deployments/gpt-4o",
|
|
146
|
-
}),
|
|
147
|
-
) as OpenAI;
|
|
148
|
-
```
|
|
114
|
+
For streaming: chunks arrive to the developer in real-time. The SDK accumulates content in the background and witnesses after the stream completes.
|
|
149
115
|
|
|
150
|
-
##
|
|
116
|
+
## Witness Agent Tool Calls
|
|
151
117
|
|
|
152
|
-
|
|
118
|
+
If your AI agent calls tools or functions, wrap them to create a record of every invocation:
|
|
153
119
|
|
|
154
120
|
```typescript
|
|
155
|
-
|
|
156
|
-
|
|
121
|
+
const search = witness.wrapTool(
|
|
122
|
+
(query: string) => db.execute(query),
|
|
123
|
+
"search_database"
|
|
124
|
+
);
|
|
157
125
|
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
apiKey: "test", // any string, handoff runs before network flush
|
|
161
|
-
tenantId: "LOCAL_TEST",
|
|
162
|
-
factorHandoff: "file", // write anchors to ./swt3-handoff/ as JSON
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
166
|
-
|
|
167
|
-
const response = await client.chat.completions.create({
|
|
168
|
-
model: "gpt-4o",
|
|
169
|
-
messages: [{ role: "user", content: "What is the EU AI Act?" }],
|
|
170
|
-
});
|
|
171
|
-
console.log(response.choices[0].message.content);
|
|
172
|
-
|
|
173
|
-
// Check ./swt3-handoff/ - you'll see a JSON file per inference with:
|
|
174
|
-
// - SHA-256 fingerprint
|
|
175
|
-
// - Model ID, latency, token count
|
|
176
|
-
// - Clearing level applied
|
|
177
|
-
// - Full factor data for independent verification
|
|
126
|
+
const results = await search("SELECT * FROM transactions WHERE amount > 10000");
|
|
127
|
+
// An AI-TOOL.1 anchor is minted recording: tool name, latency, success/failure
|
|
178
128
|
```
|
|
179
129
|
|
|
180
|
-
When
|
|
130
|
+
When an auditor asks "what tools did your agent use?" you have the cryptographic record.
|
|
181
131
|
|
|
182
|
-
##
|
|
132
|
+
## Witness Agent Resource Access
|
|
183
133
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
134
|
+
New in v0.2.10. Wrap any function your agent uses to access external resources. The SDK records what was accessed and whether it was within the agent's declared scope:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const queryCustomers = witness.wrapAccess(
|
|
138
|
+
(sql: string) => db.execute(sql),
|
|
139
|
+
"customer-database", // resource name
|
|
140
|
+
"read-only analytics" // declared authorization scope
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const results = await queryCustomers("SELECT name FROM customers");
|
|
144
|
+
// An AI-ACC.1 anchor is minted recording:
|
|
145
|
+
// - Was it accessed? (yes)
|
|
146
|
+
// - Was it within scope? (yes)
|
|
147
|
+
// - Was access granted? (yes)
|
|
148
|
+
```
|
|
195
149
|
|
|
196
|
-
|
|
197
|
-
> [Create a free account →](https://sovereign.tenova.io/signup?ref=sdk)
|
|
150
|
+
If the agent tries to access something outside its declared scope, the anchor records a FAIL verdict. When a CISO asks "can you prove your AI agent only accessed what it was authorized to access?" this is the answer.
|
|
198
151
|
|
|
199
|
-
##
|
|
152
|
+
## Detect Instruction Drift
|
|
200
153
|
|
|
201
|
-
|
|
202
|
-
2. **Hash**: Prompts and responses are SHA-256 hashed in-process
|
|
203
|
-
3. **Extract**: Model hash, latency, token count, refusal status as numeric factors
|
|
204
|
-
4. **Clear**: Raw text is purged from the wire payload (configurable clearing level)
|
|
205
|
-
5. **Buffer**: Factors queued in background, flushed to the SWT3 ledger asynchronously
|
|
206
|
-
6. **Return**: Your original response returns untouched. Witnessing runs in a background thread — median overhead is <1ms on the hot path (hash + buffer, no network call)
|
|
154
|
+
New in v0.2.10. The SDK separately hashes the system prompt (base instructions) for each inference. If your agent's instructions change between audit periods, the hash changes and the platform flags it as instruction drift.
|
|
207
155
|
|
|
208
|
-
|
|
156
|
+
This happens automatically. No configuration needed. The system prompt hash is extracted from:
|
|
157
|
+
- OpenAI: messages where `role === "system"`
|
|
158
|
+
- Anthropic: the `system` parameter
|
|
209
159
|
|
|
210
|
-
|
|
160
|
+
The hash is included at clearing levels 0 and 1, stripped at levels 2 and 3.
|
|
211
161
|
|
|
212
|
-
|
|
213
|
-
|-------|------|------------|----------|
|
|
214
|
-
| 0 | Analytics | Hashes + factors + model + provider + guardrails | Internal analytics |
|
|
215
|
-
| 1 | Standard | Hashes + factors + model + provider | **Default.** Production apps |
|
|
216
|
-
| 2 | Sensitive | Hashes + factors + model only | Healthcare, legal, PII |
|
|
217
|
-
| 3 | Classified | Numeric factors only. Model ID hashed. | Defense, air-gapped |
|
|
162
|
+
## Agent Identity
|
|
218
163
|
|
|
219
|
-
|
|
164
|
+
Bind a unique identity to every anchor your agent produces:
|
|
220
165
|
|
|
221
166
|
```typescript
|
|
222
|
-
// Healthcare deployment: Level 2
|
|
223
167
|
const witness = new Witness({
|
|
224
|
-
endpoint: "
|
|
225
|
-
apiKey: "
|
|
226
|
-
tenantId: "
|
|
227
|
-
|
|
168
|
+
endpoint: "...",
|
|
169
|
+
apiKey: "axm_...",
|
|
170
|
+
tenantId: "...",
|
|
171
|
+
agentId: "fraud-detector-prod",
|
|
172
|
+
signingKey: "swt3_sk_...", // HMAC-SHA256 signing for non-repudiation
|
|
228
173
|
});
|
|
229
174
|
```
|
|
230
175
|
|
|
176
|
+
The `agentId` survives all clearing levels. The `signingKey` produces a cryptographic signature on every anchor, proving which agent instance created it. This enables:
|
|
177
|
+
- Per-agent compliance passports
|
|
178
|
+
- Fleet-wide governance dashboards
|
|
179
|
+
- Agent-scoped evidence packages for auditors
|
|
180
|
+
|
|
231
181
|
## What Gets Witnessed
|
|
232
182
|
|
|
233
|
-
|
|
234
|
-
|-----------|---------------|-------------------|
|
|
235
|
-
| AI-INF.1 | Inference provenance (prompt + response hashed) | EU AI Act Art. 12 |
|
|
236
|
-
| AI-INF.2 | Latency within threshold (detects model swaps) | NIST AI RMF MEASURE 2.6 |
|
|
237
|
-
| AI-MDL.1 | Model hash matches approved version | EU AI Act Art. 9 |
|
|
238
|
-
| AI-MDL.2 | Model version identifier recorded | EU AI Act Art. 72 |
|
|
239
|
-
| AI-GRD.1 | Required guardrails were active | NIST AI RMF MANAGE 4.1 |
|
|
240
|
-
| AI-GRD.2 | No content filter / refusal triggered | EU AI Act Art. 9 |
|
|
241
|
-
| AI-TOOL.1 | Agent tool/function call recorded (latency, success) | NIST AI RMF MANAGE 4.1 |
|
|
242
|
-
| AI-ID.1 | Witness instance identity attested (agent accountability) | EU AI Act Art. 13 |
|
|
243
|
-
|
|
244
|
-
## View an Anchor
|
|
245
|
-
|
|
246
|
-
A Level 1 anchor for AI-INF.1 (Inference Provenance). This is what reaches the witness ledger. No prompts, no responses, just cryptographic proof.
|
|
247
|
-
|
|
248
|
-
```json
|
|
249
|
-
{
|
|
250
|
-
"procedure_id": "AI-INF.1",
|
|
251
|
-
"factor_a": 1,
|
|
252
|
-
"factor_b": 1,
|
|
253
|
-
"factor_c": 0,
|
|
254
|
-
"clearing_level": 1,
|
|
255
|
-
"anchor_fingerprint": "c059eb5938c0",
|
|
256
|
-
"anchor_epoch": 1774800000,
|
|
257
|
-
"fingerprint_timestamp_ms": 1774800000000,
|
|
258
|
-
"ai_prompt_hash": "315f5bdb76d078c4",
|
|
259
|
-
"ai_response_hash": "a1b2c3d4e5f60718",
|
|
260
|
-
"ai_latency_ms": 842,
|
|
261
|
-
"ai_model_id": "gpt-4o",
|
|
262
|
-
"ai_context": {
|
|
263
|
-
"provider": "openai",
|
|
264
|
-
"guardrails": ["content-filter", "pii-redaction"]
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
```
|
|
183
|
+
Each inference produces anchors for these checks. Every check maps to a regulation.
|
|
268
184
|
|
|
269
|
-
|
|
185
|
+
| Check | What It Proves | Plain English | Regulation |
|
|
186
|
+
|-------|---------------|---------------|------------|
|
|
187
|
+
| AI-INF.1 | Prompt and response were captured | "Was the inference logged?" | EU AI Act Art. 12 |
|
|
188
|
+
| AI-INF.2 | Latency was within threshold | "Was response time acceptable?" | NIST AI RMF MEASURE 2.6 |
|
|
189
|
+
| AI-MDL.1 | Deployed model matches approved hash | "Is this the right model?" | EU AI Act Art. 9 |
|
|
190
|
+
| AI-MDL.2 | Model version was recorded | "Is the model version tracked?" | EU AI Act Art. 72 |
|
|
191
|
+
| AI-GRD.1 | Required safety guardrails were active | "Are enough guardrails running?" | NIST AI RMF MANAGE 4.1 |
|
|
192
|
+
| AI-GRD.2 | No refusal or content filter triggered | "Did a safety filter trigger?" | EU AI Act Art. 9 |
|
|
193
|
+
| AI-TOOL.1 | Tool/function call was recorded | "Did the tool call succeed?" | NIST AI RMF MANAGE 4.1 |
|
|
194
|
+
| AI-ACC.1 | Resource access was within scope | "Was the access authorized?" | EU AI Act Art. 14 |
|
|
195
|
+
| AI-ID.1 | Agent identity was attested | "Is the agent identified?" | EU AI Act Art. 13 |
|
|
270
196
|
|
|
271
|
-
##
|
|
197
|
+
## How Verdicts Work
|
|
272
198
|
|
|
273
|
-
|
|
199
|
+
Every anchor carries three numbers:
|
|
274
200
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
apiKey: "axm_...",
|
|
279
|
-
tenantId: "...",
|
|
280
|
-
bufferSize: 50, // flush every 50 anchors
|
|
281
|
-
flushInterval: 10, // or every 10 seconds
|
|
282
|
-
maxRetries: 5, // retry before dead-lettering
|
|
283
|
-
});
|
|
284
|
-
```
|
|
201
|
+
- **factor_a** = the threshold (what should happen)
|
|
202
|
+
- **factor_b** = the observation (what actually happened)
|
|
203
|
+
- **factor_c** = context (extra detail)
|
|
285
204
|
|
|
286
|
-
|
|
205
|
+
The verdict is a simple comparison. No AI, no probability. Just math.
|
|
287
206
|
|
|
288
|
-
|
|
207
|
+
### Reading an Anchor
|
|
289
208
|
|
|
290
|
-
|
|
209
|
+
```
|
|
210
|
+
Check: AI-GRD.1 factor_a: 2 factor_b: 3 factor_c: 1 Verdict: PASS
|
|
291
211
|
|
|
292
|
-
|
|
212
|
+
Translation: "We required 2 guardrails. 3 were active. All passed."
|
|
213
|
+
```
|
|
293
214
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
| Backend services | Python | `swt3-ai` |
|
|
297
|
-
| API routes / Edge | TypeScript | `@tenova/swt3-ai` |
|
|
298
|
-
| Frontend (Next.js) | TypeScript | `@tenova/swt3-ai` + Vercel AI SDK |
|
|
299
|
-
| CLI / scripts | Python | `swt3-ai` |
|
|
215
|
+
```
|
|
216
|
+
Check: AI-ACC.1 factor_a: 1 factor_b: 0 factor_c: 0 Verdict: FAIL
|
|
300
217
|
|
|
301
|
-
|
|
218
|
+
Translation: "Access attempt occurred. Target was outside declared scope. Access denied."
|
|
219
|
+
```
|
|
302
220
|
|
|
303
|
-
|
|
221
|
+
### Factor Reference
|
|
304
222
|
|
|
305
|
-
|
|
306
|
-
|
|
223
|
+
| Check | factor_a | factor_b | factor_c | Verdict Rule |
|
|
224
|
+
|-------|----------|----------|----------|-------------|
|
|
225
|
+
| AI-INF.1 | 1 (required) | 1 if hashes present | 0 | PASS if b >= a |
|
|
226
|
+
| AI-INF.2 | Latency limit (ms) | Actual latency (ms) | 1 if over limit | PASS if b <= a |
|
|
227
|
+
| AI-MDL.1 | 1 (required) | 1 if hash present | 0 | PASS if b >= a |
|
|
228
|
+
| AI-MDL.2 | 1 (required) | 1 if version recorded | 0 | PASS if b >= a |
|
|
229
|
+
| AI-GRD.1 | Required count | Active count | 1 if all passed | PASS if b >= a |
|
|
230
|
+
| AI-GRD.2 | 1 (clean expected) | 0 if refusal | 0 | PASS if b >= a |
|
|
231
|
+
| AI-TOOL.1 | 1 (called) | Latency (ms) | 1=success, 0=error | PASS if b >= a |
|
|
232
|
+
| AI-ACC.1 | 1 (accessed) | 1=in scope, 0=out | 1=granted, 0=denied | PASS if b >= a |
|
|
233
|
+
| AI-ID.1 | 1 (required) | 1 if identity present | 0 | PASS if b >= a |
|
|
307
234
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
235
|
+
### Verify Any Anchor From Your Terminal
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
echo -n "WITNESS:DEMO_TENANT:AI-INF.1:1:1:0:1774800000000" | sha256sum | cut -c1-12
|
|
239
|
+
# Produces a 12-character fingerprint. Compare it to the anchor. If it matches, the anchor is real.
|
|
311
240
|
```
|
|
312
241
|
|
|
313
|
-
|
|
242
|
+
No SDK needed. Works on any machine, any language.
|
|
314
243
|
|
|
315
|
-
|
|
244
|
+
## Sovereign Cloud Support
|
|
316
245
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
| `flushInterval` | `5` | Flush after N seconds |
|
|
325
|
-
| `timeout` | `10000` | HTTP timeout (ms) |
|
|
326
|
-
| `maxRetries` | `3` | Retries before dead-letter |
|
|
327
|
-
| `guardrailNames` | `[]` | Active guardrail names |
|
|
328
|
-
| `factorHandoff` | - | `"file"` to enable local factor export |
|
|
329
|
-
| `factorHandoffPath` | - | Directory for factor handoff files |
|
|
246
|
+
The SDK works with any OpenAI-compatible endpoint. Run models on your own infrastructure and witness every inference identically:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// vLLM with Llama 3 on your hardware
|
|
250
|
+
const client = witness.wrap(
|
|
251
|
+
new OpenAI({ baseURL: "http://gpu-cluster.internal:8000/v1" }),
|
|
252
|
+
) as OpenAI;
|
|
330
253
|
|
|
331
|
-
|
|
254
|
+
// Ollama for local development
|
|
255
|
+
const localClient = witness.wrap(
|
|
256
|
+
new OpenAI({ baseURL: "http://localhost:11434/v1" }),
|
|
257
|
+
) as OpenAI;
|
|
332
258
|
|
|
333
|
-
|
|
259
|
+
// Azure OpenAI
|
|
260
|
+
const azureClient = witness.wrap(
|
|
261
|
+
new OpenAI({
|
|
262
|
+
apiKey: process.env.AZURE_OPENAI_KEY,
|
|
263
|
+
baseURL: "https://your-resource.openai.azure.com/openai/deployments/gpt-4o",
|
|
264
|
+
}),
|
|
265
|
+
) as OpenAI;
|
|
266
|
+
```
|
|
334
267
|
|
|
335
|
-
|
|
268
|
+
Same anchors, same ledger, same audit trail. Regardless of where the model runs.
|
|
336
269
|
|
|
337
|
-
|
|
270
|
+
## Clearing Levels (Privacy Control)
|
|
338
271
|
|
|
339
|
-
|
|
272
|
+
You control what leaves your infrastructure. The SDK always returns the full response to your code. Clearing only affects the witness payload.
|
|
340
273
|
|
|
341
|
-
|
|
274
|
+
| Level | Name | What Goes on the Wire | Use Case |
|
|
275
|
+
|-------|------|-----------------------|----------|
|
|
276
|
+
| 0 | Analytics | Everything: hashes, factors, model, provider, guardrails, prompt hash | Internal analytics |
|
|
277
|
+
| 1 | Standard | Hashes, factors, model, provider (no raw text ever) | **Default.** Production apps |
|
|
278
|
+
| 2 | Sensitive | Hashes, factors, model only. No provider, no guardrail names | Healthcare, legal, PII |
|
|
279
|
+
| 3 | Classified | Numeric factors only. Model name hashed. Zero metadata | Defense, air-gapped |
|
|
342
280
|
|
|
343
|
-
|
|
281
|
+
```typescript
|
|
282
|
+
const witness = new Witness({
|
|
283
|
+
endpoint: "...",
|
|
284
|
+
apiKey: "axm_...",
|
|
285
|
+
tenantId: "...",
|
|
286
|
+
clearingLevel: 2, // Sensitive: strips provider and guardrail names
|
|
287
|
+
});
|
|
288
|
+
```
|
|
344
289
|
|
|
345
|
-
|
|
290
|
+
At every level, raw prompts and responses **never leave your infrastructure**. Only SHA-256 hashes and numeric factors travel on the wire.
|
|
346
291
|
|
|
347
|
-
##
|
|
292
|
+
## Local Mode (No Account Needed)
|
|
348
293
|
|
|
349
|
-
|
|
294
|
+
Try the SDK locally before connecting to a live endpoint:
|
|
350
295
|
|
|
351
296
|
```typescript
|
|
352
297
|
const witness = new Witness({
|
|
353
|
-
endpoint: "https://
|
|
354
|
-
apiKey: "
|
|
355
|
-
tenantId: "
|
|
356
|
-
|
|
357
|
-
factorHandoff: "file",
|
|
358
|
-
factorHandoffPath: "/secure/vault/factors/",
|
|
298
|
+
endpoint: "https://your-witness-endpoint.example.com",
|
|
299
|
+
apiKey: "test",
|
|
300
|
+
tenantId: "LOCAL_TEST",
|
|
301
|
+
factorHandoff: "file", // Writes anchors to ./swt3-handoff/ as JSON
|
|
359
302
|
});
|
|
360
303
|
```
|
|
361
304
|
|
|
362
|
-
|
|
305
|
+
## Local SDK vs Connected
|
|
363
306
|
|
|
364
|
-
|
|
307
|
+
| Capability | Local SDK | Connected (free tier) |
|
|
308
|
+
|---|---|---|
|
|
309
|
+
| Mint anchors | Yes | Yes |
|
|
310
|
+
| Verify one anchor | Yes | Yes |
|
|
311
|
+
| Evidence retention | Files on disk | 7 days (free) / 90 days (Pro) |
|
|
312
|
+
| Compliance dashboard | No | Yes |
|
|
313
|
+
| Agent Passport | No | Yes (Pro) |
|
|
314
|
+
| Fleet dashboard | No | Yes (Pro) |
|
|
315
|
+
| EU AI Act conformity | No | Yes (Pro) |
|
|
316
|
+
| Auditor evidence packages | No | Yes (Pro) |
|
|
317
|
+
| Access violation tracking | No | Yes (Pro) |
|
|
318
|
+
| **Survives an audit** | **No** | **Yes** |
|
|
365
319
|
|
|
366
|
-
|
|
320
|
+
> Local anchors prove it to you. A connected engine proves it to your auditor.
|
|
367
321
|
|
|
368
|
-
|
|
322
|
+
## Resilience (Flight Recorder)
|
|
369
323
|
|
|
370
|
-
|
|
371
|
-
|------|-----------|-------------|-------|
|
|
372
|
-
| **Open** | 7 days | SDK, dashboard, public verify | Free |
|
|
373
|
-
| **Pro** | 90 days | + AI conformity exports, regulatory reports | $499/mo |
|
|
374
|
-
| **Enclave** | 1 year | + OSCAL, Gate API, attestations, webhook feeds | $9,500/mo |
|
|
375
|
-
| **Sovereign** | Custom | + White-glove ATO sprint, mock assessment, on-prem | [Book Assessment](https://calendly.com/tenova-axiom/30min) |
|
|
324
|
+
The SDK never blocks your inference. If the witness endpoint is unreachable, payloads move to a dead-letter queue. When connectivity returns, the backlog drains automatically. Your production system is never affected.
|
|
376
325
|
|
|
377
|
-
|
|
326
|
+
```typescript
|
|
327
|
+
const witness = new Witness({
|
|
328
|
+
endpoint: "...",
|
|
329
|
+
apiKey: "axm_...",
|
|
330
|
+
tenantId: "...",
|
|
331
|
+
bufferSize: 50, // flush every 50 anchors
|
|
332
|
+
flushInterval: 10, // or every 10 seconds
|
|
333
|
+
maxRetries: 5, // retry before dead-lettering
|
|
334
|
+
});
|
|
335
|
+
```
|
|
378
336
|
|
|
379
|
-
##
|
|
337
|
+
## API Reference
|
|
380
338
|
|
|
381
|
-
|
|
339
|
+
### `new Witness(options)`
|
|
382
340
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
341
|
+
| Option | Default | Description |
|
|
342
|
+
|--------|---------|-------------|
|
|
343
|
+
| `endpoint` | required | Witness endpoint URL |
|
|
344
|
+
| `apiKey` | required | API key (axm_ prefix) |
|
|
345
|
+
| `tenantId` | required | Your tenant identifier |
|
|
346
|
+
| `clearingLevel` | 1 | Privacy level (0-3) |
|
|
347
|
+
| `bufferSize` | 10 | Flush after N anchors |
|
|
348
|
+
| `flushInterval` | 5 | Flush after N seconds |
|
|
349
|
+
| `timeout` | 10000 | HTTP timeout (ms) |
|
|
350
|
+
| `maxRetries` | 3 | Retries before dead-letter |
|
|
351
|
+
| `guardrailNames` | [] | Active guardrail names |
|
|
352
|
+
| `agentId` | - | Agent identity (survives all clearing levels) |
|
|
353
|
+
| `signingKey` | - | HMAC-SHA256 key for payload signing |
|
|
354
|
+
| `factorHandoff` | - | "file" for local factor export |
|
|
355
|
+
| `factorHandoffPath` | - | Directory for handoff files |
|
|
356
|
+
|
|
357
|
+
### Methods
|
|
358
|
+
|
|
359
|
+
| Method | Description |
|
|
360
|
+
|--------|-------------|
|
|
361
|
+
| `witness.wrap(client)` | Returns a Proxy that behaves identically to the original client. Supports OpenAI and Anthropic. |
|
|
362
|
+
| `witness.wrapTool(fn, name?)` | Wraps a function for tool call witnessing (AI-TOOL.1). |
|
|
363
|
+
| `witness.wrapAccess(fn, resource?, scope?)` | Wraps a function for resource access witnessing (AI-ACC.1). |
|
|
364
|
+
| `witness.vercelOnFinish(opts?)` | Returns an onFinish callback for Vercel AI SDK streamText/generateText. |
|
|
365
|
+
| `witness.flush()` | Force-flush all buffered payloads. Returns receipts. |
|
|
366
|
+
| `witness.stop()` | Stop the witness and flush remaining payloads. |
|
|
386
367
|
|
|
387
|
-
##
|
|
368
|
+
## Installation
|
|
388
369
|
|
|
389
|
-
|
|
370
|
+
```bash
|
|
371
|
+
npm install @tenova/swt3-ai
|
|
390
372
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
373
|
+
# Peer dependencies (install whichever you use)
|
|
374
|
+
npm install openai # for OpenAI adapter
|
|
375
|
+
npm install @anthropic-ai/sdk # for Anthropic adapter
|
|
376
|
+
```
|
|
394
377
|
|
|
395
|
-
##
|
|
378
|
+
## Regulatory Coverage
|
|
396
379
|
|
|
397
|
-
|
|
398
|
-
- [Factor Handoff Protocol](https://sovereign.tenova.io/docs/factor-handoff-protocol.html) - How factors are securely transferred to your custody
|
|
399
|
-
- [CMMC Compliance Overlay](https://sovereign.tenova.io/guides/cmmc-overlay.html) - Control mappings for defense industrial base
|
|
380
|
+
The SWT3 AI Witnessing Profile maps to:
|
|
400
381
|
|
|
401
|
-
|
|
382
|
+
- **EU AI Act**: Articles 9, 10, 12, 13, 14, 53, 72
|
|
383
|
+
- **NIST AI RMF**: GOVERN, MAP, MEASURE, MANAGE functions
|
|
384
|
+
- **ISO 42001**: Annex A AI management controls
|
|
385
|
+
- **NIST 800-53**: SI-7 (integrity), AU-2/AU-3 (audit), AC controls
|
|
386
|
+
- **SR 11-7**: Model risk management (financial services)
|
|
402
387
|
|
|
403
|
-
##
|
|
388
|
+
## Zero Lock-in
|
|
404
389
|
|
|
405
|
-
|
|
390
|
+
Remove the `witness.wrap()` call. Your code works exactly as before. Anchors already minted stay in the ledger. There is nothing to undo.
|
|
391
|
+
|
|
392
|
+
## Cross-Language Parity
|
|
393
|
+
|
|
394
|
+
This SDK produces identical fingerprints to the Python SDK (`swt3-ai`). A unified audit trail across your entire stack, verified by shared test vectors at build time.
|
|
395
|
+
|
|
396
|
+
| Layer | Language | Package |
|
|
397
|
+
|-------|----------|---------|
|
|
398
|
+
| Backend services | Python | swt3-ai |
|
|
399
|
+
| API routes / Edge | TypeScript | @tenova/swt3-ai |
|
|
400
|
+
| Frontend (Next.js) | TypeScript | @tenova/swt3-ai + Vercel AI SDK |
|
|
401
|
+
|
|
402
|
+
## Privacy
|
|
403
|
+
|
|
404
|
+
Your prompts and responses **never leave your infrastructure**. The SDK computes SHA-256 hashes locally and transmits only irreversible hashes and numeric factors. At Clearing Level 3, even the model name is hashed. The witness endpoint is a blind registrar: it stores cryptographic proofs, not your data.
|
|
406
405
|
|
|
407
406
|
---
|
|
408
407
|
|
|
409
408
|
*SWT3: Sovereign Witness Traceability. We don't run your models. We witness them.*
|
|
410
409
|
|
|
411
|
-
*TeNova: Defining the AI Accountability Standard. One protocol. Zero Integrity Debt. Total Sovereignty.*
|
|
412
|
-
|
|
413
410
|
SWT3 and Sovereign Witness Traceability are trademarks of Tenable Nova LLC. Patent pending. Apache 2.0 licensed.
|