@tenova/swt3-ai 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/README.md +246 -0
- package/dist/adapters/anthropic.d.ts +32 -0
- package/dist/adapters/anthropic.d.ts.map +1 -0
- package/dist/adapters/anthropic.js +267 -0
- package/dist/adapters/anthropic.js.map +1 -0
- package/dist/adapters/openai.d.ts +19 -0
- package/dist/adapters/openai.d.ts.map +1 -0
- package/dist/adapters/openai.js +252 -0
- package/dist/adapters/openai.js.map +1 -0
- package/dist/adapters/vercel-ai.d.ts +64 -0
- package/dist/adapters/vercel-ai.d.ts.map +1 -0
- package/dist/adapters/vercel-ai.js +68 -0
- package/dist/adapters/vercel-ai.js.map +1 -0
- package/dist/buffer.d.ts +41 -0
- package/dist/buffer.d.ts.map +1 -0
- package/dist/buffer.js +154 -0
- package/dist/buffer.js.map +1 -0
- package/dist/clearing.d.ts +20 -0
- package/dist/clearing.d.ts.map +1 -0
- package/dist/clearing.js +145 -0
- package/dist/clearing.js.map +1 -0
- package/dist/fingerprint.d.ts +29 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +57 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/witness.d.ts +76 -0
- package/dist/witness.d.ts.map +1 -0
- package/dist/witness.js +121 -0
- package/dist/witness.js.map +1 -0
- package/package.json +55 -0
package/dist/clearing.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SWT3 AI Witness SDK — Clearing Engine (Levels 0-3).
|
|
3
|
+
*
|
|
4
|
+
* The "Sovereign Wire" protocol: controls what leaves the developer's
|
|
5
|
+
* infrastructure. Raw prompts/responses NEVER appear in payloads.
|
|
6
|
+
* Clearing operates on the wire payload, not the developer's response.
|
|
7
|
+
*
|
|
8
|
+
* Level 0 — Analytics: All metadata
|
|
9
|
+
* Level 1 — Standard: Hashes + model_id + ai_context
|
|
10
|
+
* Level 2 — Sensitive: Hashes + model_id only. ai_context DELETED.
|
|
11
|
+
* Level 3 — Classified: Factors only. model_id hashed. Everything else DELETED.
|
|
12
|
+
*/
|
|
13
|
+
import { mintFingerprint, sha256Truncated, timestampMs } from "./fingerprint.js";
|
|
14
|
+
/**
|
|
15
|
+
* Extract witness payloads from an inference record.
|
|
16
|
+
* Applies clearing level to each payload via object destructuring (Level 2+
|
|
17
|
+
* fields are simply never assigned, guaranteeing they don't exist on the wire).
|
|
18
|
+
*/
|
|
19
|
+
export function extractPayloads(record, tenantId, clearingLevel, latencyThresholdMs = 30000, guardrailsRequired = 0, procedures) {
|
|
20
|
+
const [ts, epoch] = timestampMs();
|
|
21
|
+
const payloads = [];
|
|
22
|
+
let procFactors = [
|
|
23
|
+
// AI-INF.1: Inference Provenance
|
|
24
|
+
{
|
|
25
|
+
procedureId: "AI-INF.1",
|
|
26
|
+
factorA: 1,
|
|
27
|
+
factorB: record.promptHash && record.responseHash ? 1 : 0,
|
|
28
|
+
factorC: 0,
|
|
29
|
+
},
|
|
30
|
+
// AI-INF.2: Inference Latency
|
|
31
|
+
{
|
|
32
|
+
procedureId: "AI-INF.2",
|
|
33
|
+
factorA: latencyThresholdMs,
|
|
34
|
+
factorB: record.latencyMs,
|
|
35
|
+
factorC: record.latencyMs > latencyThresholdMs ? 1 : 0,
|
|
36
|
+
},
|
|
37
|
+
// AI-MDL.1: Model Weight Integrity
|
|
38
|
+
{
|
|
39
|
+
procedureId: "AI-MDL.1",
|
|
40
|
+
factorA: 1,
|
|
41
|
+
factorB: record.modelHash ? 1 : 0,
|
|
42
|
+
factorC: 0,
|
|
43
|
+
},
|
|
44
|
+
// AI-MDL.2: Model Version Tracking
|
|
45
|
+
{
|
|
46
|
+
procedureId: "AI-MDL.2",
|
|
47
|
+
factorA: 1,
|
|
48
|
+
factorB: record.modelId ? 1 : 0,
|
|
49
|
+
factorC: 0,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
// AI-GRD.1: Guardrail Enforcement (only if guardrails configured)
|
|
53
|
+
const grdRequired = guardrailsRequired || record.guardrailsRequired;
|
|
54
|
+
if (grdRequired > 0) {
|
|
55
|
+
procFactors.push({
|
|
56
|
+
procedureId: "AI-GRD.1",
|
|
57
|
+
factorA: grdRequired,
|
|
58
|
+
factorB: record.guardrailsActive,
|
|
59
|
+
factorC: record.guardrailPassed ? 1 : 0,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// AI-GRD.2: Content Safety Filter
|
|
63
|
+
procFactors.push({
|
|
64
|
+
procedureId: "AI-GRD.2",
|
|
65
|
+
factorA: 1,
|
|
66
|
+
factorB: record.hasRefusal ? 0 : 1,
|
|
67
|
+
factorC: record.hasRefusal ? 1 : 0,
|
|
68
|
+
});
|
|
69
|
+
// Filter to requested procedures
|
|
70
|
+
if (procedures) {
|
|
71
|
+
const allowed = new Set(procedures);
|
|
72
|
+
procFactors = procFactors.filter((p) => allowed.has(p.procedureId));
|
|
73
|
+
}
|
|
74
|
+
// Build payloads with clearing applied
|
|
75
|
+
for (const pf of procFactors) {
|
|
76
|
+
const fp = mintFingerprint(tenantId, pf.procedureId, pf.factorA, pf.factorB, pf.factorC, ts);
|
|
77
|
+
// Base payload — always present regardless of clearing level
|
|
78
|
+
const payload = {
|
|
79
|
+
procedure_id: pf.procedureId,
|
|
80
|
+
factor_a: pf.factorA,
|
|
81
|
+
factor_b: pf.factorB,
|
|
82
|
+
factor_c: pf.factorC,
|
|
83
|
+
clearing_level: clearingLevel,
|
|
84
|
+
anchor_fingerprint: fp,
|
|
85
|
+
anchor_epoch: epoch,
|
|
86
|
+
fingerprint_timestamp_ms: ts,
|
|
87
|
+
};
|
|
88
|
+
// Apply clearing — use conditional assignment so Level 2+ fields
|
|
89
|
+
// are never set (not even as undefined). This guarantees they are
|
|
90
|
+
// absent from JSON.stringify output, not just null.
|
|
91
|
+
applyClearingLevel(payload, record, clearingLevel);
|
|
92
|
+
payloads.push(payload);
|
|
93
|
+
}
|
|
94
|
+
return payloads;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Apply clearing level to a payload using explicit field assignment.
|
|
98
|
+
*
|
|
99
|
+
* Level 0-1: All metadata assigned
|
|
100
|
+
* Level 2: Hashes + model_id only. ai_context NOT assigned (absent from wire).
|
|
101
|
+
* Level 3: model_id hashed. Hashes NOT assigned. No metadata.
|
|
102
|
+
*/
|
|
103
|
+
function applyClearingLevel(payload, record, level) {
|
|
104
|
+
if (level <= 2) {
|
|
105
|
+
// Levels 0-2: include hashes and metrics
|
|
106
|
+
payload.ai_prompt_hash = record.promptHash;
|
|
107
|
+
payload.ai_response_hash = record.responseHash;
|
|
108
|
+
payload.ai_latency_ms = record.latencyMs;
|
|
109
|
+
payload.ai_input_tokens = record.inputTokens;
|
|
110
|
+
payload.ai_output_tokens = record.outputTokens;
|
|
111
|
+
}
|
|
112
|
+
if (level <= 1) {
|
|
113
|
+
// Levels 0-1: include full ai_context
|
|
114
|
+
payload.ai_model_id = record.modelId;
|
|
115
|
+
const ctx = {
|
|
116
|
+
provider: record.provider,
|
|
117
|
+
};
|
|
118
|
+
if (record.guardrailNames.length > 0) {
|
|
119
|
+
ctx.guardrails = record.guardrailNames;
|
|
120
|
+
}
|
|
121
|
+
if (record.systemFingerprint) {
|
|
122
|
+
ctx.system_fingerprint = record.systemFingerprint;
|
|
123
|
+
}
|
|
124
|
+
payload.ai_context = ctx;
|
|
125
|
+
}
|
|
126
|
+
else if (level === 2) {
|
|
127
|
+
// Level 2: model_id in cleartext, NO ai_context
|
|
128
|
+
payload.ai_model_id = record.modelId;
|
|
129
|
+
// ai_context is never assigned — absent from JSON
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Level 3: model_id HASHED, no hashes, no metadata
|
|
133
|
+
payload.ai_model_id = record.modelId
|
|
134
|
+
? sha256Truncated(record.modelId)
|
|
135
|
+
: undefined;
|
|
136
|
+
// Delete hash fields that were set above (Level 3 overrides Level 2 path)
|
|
137
|
+
delete payload.ai_prompt_hash;
|
|
138
|
+
delete payload.ai_response_hash;
|
|
139
|
+
delete payload.ai_latency_ms;
|
|
140
|
+
delete payload.ai_input_tokens;
|
|
141
|
+
delete payload.ai_output_tokens;
|
|
142
|
+
// ai_context is never assigned
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=clearing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clearing.js","sourceRoot":"","sources":["../src/clearing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGjF;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAuB,EACvB,QAAgB,EAChB,aAA4B,EAC5B,qBAA6B,KAAK,EAClC,qBAA6B,CAAC,EAC9B,UAAqB;IAErB,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,WAAW,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAUtC,IAAI,WAAW,GAAiB;QAC9B,iCAAiC;QACjC;YACE,WAAW,EAAE,UAAU;YACvB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzD,OAAO,EAAE,CAAC;SACX;QACD,8BAA8B;QAC9B;YACE,WAAW,EAAE,UAAU;YACvB,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,MAAM,CAAC,SAAS;YACzB,OAAO,EAAE,MAAM,CAAC,SAAS,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACvD;QACD,mCAAmC;QACnC;YACE,WAAW,EAAE,UAAU;YACvB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjC,OAAO,EAAE,CAAC;SACX;QACD,mCAAmC;QACnC;YACE,WAAW,EAAE,UAAU;YACvB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,OAAO,EAAE,CAAC;SACX;KACF,CAAC;IAEF,kEAAkE;IAClE,MAAM,WAAW,GAAG,kBAAkB,IAAI,MAAM,CAAC,kBAAkB,CAAC;IACpE,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QACpB,WAAW,CAAC,IAAI,CAAC;YACf,WAAW,EAAE,UAAU;YACvB,OAAO,EAAE,WAAW;YACpB,OAAO,EAAE,MAAM,CAAC,gBAAgB;YAChC,OAAO,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACxC,CAAC,CAAC;IACL,CAAC;IAED,kCAAkC;IAClC,WAAW,CAAC,IAAI,CAAC;QACf,WAAW,EAAE,UAAU;QACvB,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACnC,CAAC,CAAC;IAEH,iCAAiC;IACjC,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QACpC,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,uCAAuC;IACvC,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,eAAe,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAE7F,6DAA6D;QAC7D,MAAM,OAAO,GAAmB;YAC9B,YAAY,EAAE,EAAE,CAAC,WAAW;YAC5B,QAAQ,EAAE,EAAE,CAAC,OAAO;YACpB,QAAQ,EAAE,EAAE,CAAC,OAAO;YACpB,QAAQ,EAAE,EAAE,CAAC,OAAO;YACpB,cAAc,EAAE,aAAa;YAC7B,kBAAkB,EAAE,EAAE;YACtB,YAAY,EAAE,KAAK;YACnB,wBAAwB,EAAE,EAAE;SAC7B,CAAC;QAEF,iEAAiE;QACjE,kEAAkE;QAClE,oDAAoD;QACpD,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;QAEnD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CACzB,OAAuB,EACvB,MAAuB,EACvB,KAAoB;IAEpB,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,yCAAyC;QACzC,OAAO,CAAC,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC;QAC3C,OAAO,CAAC,gBAAgB,GAAG,MAAM,CAAC,YAAY,CAAC;QAC/C,OAAO,CAAC,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC;QACzC,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC,WAAW,CAAC;QAC7C,OAAO,CAAC,gBAAgB,GAAG,MAAM,CAAC,YAAY,CAAC;IACjD,CAAC;IAED,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,sCAAsC;QACtC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC;QACrC,MAAM,GAAG,GAAiC;YACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC;QACF,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,cAAc,CAAC;QACzC,CAAC;QACD,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;YAC7B,GAAG,CAAC,kBAAkB,GAAG,MAAM,CAAC,iBAAiB,CAAC;QACpD,CAAC;QACD,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC;IAC3B,CAAC;SAAM,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QACvB,gDAAgD;QAChD,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC;QACrC,kDAAkD;IACpD,CAAC;SAAM,CAAC;QACN,mDAAmD;QACnD,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,OAAO;YAClC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC;YACjC,CAAC,CAAC,SAAS,CAAC;QACd,0EAA0E;QAC1E,OAAO,OAAO,CAAC,cAAc,CAAC;QAC9B,OAAO,OAAO,CAAC,gBAAgB,CAAC;QAChC,OAAO,OAAO,CAAC,aAAa,CAAC;QAC7B,OAAO,OAAO,CAAC,eAAe,CAAC;QAC/B,OAAO,OAAO,CAAC,gBAAgB,CAAC;QAChC,+BAA+B;IACjC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SWT3 AI Witness SDK — Fingerprint minting and SHA-256 utilities.
|
|
3
|
+
*
|
|
4
|
+
* The fingerprint formula MUST match the Python SDK and the ingestion endpoint:
|
|
5
|
+
* SHA256("WITNESS:{tenant}:{proc}:{fa}:{fb}:{fc}:{ts_ms}").hex().slice(0, 12)
|
|
6
|
+
*
|
|
7
|
+
* Uses Node.js crypto module for server-side compatibility.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* SHA-256 hash a string, return first `length` hex characters.
|
|
11
|
+
*/
|
|
12
|
+
export declare function sha256Hex(data: string, length?: number): string;
|
|
13
|
+
/**
|
|
14
|
+
* SHA-256 hash a string, return first 16 hex chars (prompt/response hashing).
|
|
15
|
+
*/
|
|
16
|
+
export declare function sha256Truncated(data: string, length?: number): string;
|
|
17
|
+
/**
|
|
18
|
+
* Mint an SWT3 anchor fingerprint.
|
|
19
|
+
*
|
|
20
|
+
* This MUST match the endpoint's `validateFingerprint()` and the Python SDK's
|
|
21
|
+
* `mint_fingerprint()`:
|
|
22
|
+
* SHA256("WITNESS:{tenant}:{proc}:{fa}:{fb}:{fc}:{ts_ms}").hex().slice(0, 12)
|
|
23
|
+
*/
|
|
24
|
+
export declare function mintFingerprint(tenantId: string, procedureId: string, factorA: number, factorB: number, factorC: number, timestampMs: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* Return [millisecond timestamp, epoch seconds] for anchor minting.
|
|
27
|
+
*/
|
|
28
|
+
export declare function timestampMs(): [number, number];
|
|
29
|
+
//# sourceMappingURL=fingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,MAAM,CAEnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,MAAM,CAEzE;AAiBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAI9C"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SWT3 AI Witness SDK — Fingerprint minting and SHA-256 utilities.
|
|
3
|
+
*
|
|
4
|
+
* The fingerprint formula MUST match the Python SDK and the ingestion endpoint:
|
|
5
|
+
* SHA256("WITNESS:{tenant}:{proc}:{fa}:{fb}:{fc}:{ts_ms}").hex().slice(0, 12)
|
|
6
|
+
*
|
|
7
|
+
* Uses Node.js crypto module for server-side compatibility.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from "crypto";
|
|
10
|
+
/**
|
|
11
|
+
* SHA-256 hash a string, return first `length` hex characters.
|
|
12
|
+
*/
|
|
13
|
+
export function sha256Hex(data, length = 64) {
|
|
14
|
+
return createHash("sha256").update(data, "utf-8").digest("hex").slice(0, length);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* SHA-256 hash a string, return first 16 hex chars (prompt/response hashing).
|
|
18
|
+
*/
|
|
19
|
+
export function sha256Truncated(data, length = 16) {
|
|
20
|
+
return sha256Hex(data, length);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Format a numeric factor for the fingerprint formula.
|
|
24
|
+
*
|
|
25
|
+
* CRITICAL: Must match Python's behavior exactly.
|
|
26
|
+
* Integer-valued floats → "1" (no decimal), true floats → "1.5"
|
|
27
|
+
* JavaScript JSON.stringify(1) → "1", JSON.stringify(1.5) → "1.5"
|
|
28
|
+
* so we can use String() which matches.
|
|
29
|
+
*/
|
|
30
|
+
function numStr(v) {
|
|
31
|
+
if (Number.isInteger(v)) {
|
|
32
|
+
return String(v);
|
|
33
|
+
}
|
|
34
|
+
return String(v);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Mint an SWT3 anchor fingerprint.
|
|
38
|
+
*
|
|
39
|
+
* This MUST match the endpoint's `validateFingerprint()` and the Python SDK's
|
|
40
|
+
* `mint_fingerprint()`:
|
|
41
|
+
* SHA256("WITNESS:{tenant}:{proc}:{fa}:{fb}:{fc}:{ts_ms}").hex().slice(0, 12)
|
|
42
|
+
*/
|
|
43
|
+
export function mintFingerprint(tenantId, procedureId, factorA, factorB, factorC, timestampMs) {
|
|
44
|
+
const fpInput = `WITNESS:${tenantId}:${procedureId}` +
|
|
45
|
+
`:${numStr(factorA)}:${numStr(factorB)}:${numStr(factorC)}` +
|
|
46
|
+
`:${timestampMs}`;
|
|
47
|
+
return createHash("sha256").update(fpInput, "utf-8").digest("hex").slice(0, 12);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Return [millisecond timestamp, epoch seconds] for anchor minting.
|
|
51
|
+
*/
|
|
52
|
+
export function timestampMs() {
|
|
53
|
+
const ts = Date.now();
|
|
54
|
+
const epoch = Math.floor(ts / 1000);
|
|
55
|
+
return [ts, epoch];
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,SAAiB,EAAE;IACzD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AACnF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAAiB,EAAE;IAC/D,OAAO,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,MAAM,CAAC,CAAS;IACvB,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,WAAmB,EACnB,OAAe,EACf,OAAe,EACf,OAAe,EACf,WAAmB;IAEnB,MAAM,OAAO,GACX,WAAW,QAAQ,IAAI,WAAW,EAAE;QACpC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,EAAE;QAC3D,IAAI,WAAW,EAAE,CAAC;IACpB,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;AACrB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tenova/swt3-ai — SWT3 AI Witness SDK for TypeScript/Node.js
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { Witness } from "@tenova/swt3-ai";
|
|
6
|
+
* import OpenAI from "openai";
|
|
7
|
+
*
|
|
8
|
+
* const witness = new Witness({
|
|
9
|
+
* endpoint: "https://sovereign.tenova.io",
|
|
10
|
+
* apiKey: "axm_live_...",
|
|
11
|
+
* tenantId: "YOUR_TENANT_ID",
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
15
|
+
*/
|
|
16
|
+
export { Witness } from "./witness.js";
|
|
17
|
+
export type { WitnessOptions } from "./witness.js";
|
|
18
|
+
export type { WitnessConfig, WitnessPayload, WitnessReceipt, InferenceRecord, BatchResponse, } from "./types.js";
|
|
19
|
+
export { mintFingerprint, sha256Truncated, sha256Hex, timestampMs } from "./fingerprint.js";
|
|
20
|
+
export { extractPayloads } from "./clearing.js";
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tenova/swt3-ai — SWT3 AI Witness SDK for TypeScript/Node.js
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { Witness } from "@tenova/swt3-ai";
|
|
6
|
+
* import OpenAI from "openai";
|
|
7
|
+
*
|
|
8
|
+
* const witness = new Witness({
|
|
9
|
+
* endpoint: "https://sovereign.tenova.io",
|
|
10
|
+
* apiKey: "axm_live_...",
|
|
11
|
+
* tenantId: "YOUR_TENANT_ID",
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
15
|
+
*/
|
|
16
|
+
export { Witness } from "./witness.js";
|
|
17
|
+
export { mintFingerprint, sha256Truncated, sha256Hex, timestampMs } from "./fingerprint.js";
|
|
18
|
+
export { extractPayloads } from "./clearing.js";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASvC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SWT3 AI Witness SDK — Type definitions.
|
|
3
|
+
*/
|
|
4
|
+
export interface WitnessConfig {
|
|
5
|
+
endpoint: string;
|
|
6
|
+
apiKey: string;
|
|
7
|
+
tenantId: string;
|
|
8
|
+
clearingLevel: 0 | 1 | 2 | 3;
|
|
9
|
+
bufferSize: number;
|
|
10
|
+
flushInterval: number;
|
|
11
|
+
timeout: number;
|
|
12
|
+
maxRetries: number;
|
|
13
|
+
latencyThresholdMs: number;
|
|
14
|
+
guardrailsRequired: number;
|
|
15
|
+
guardrailNames: string[];
|
|
16
|
+
procedures?: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface WitnessPayload {
|
|
19
|
+
procedure_id: string;
|
|
20
|
+
factor_a: number;
|
|
21
|
+
factor_b: number;
|
|
22
|
+
factor_c: number;
|
|
23
|
+
clearing_level: number;
|
|
24
|
+
anchor_fingerprint: string;
|
|
25
|
+
anchor_epoch: number;
|
|
26
|
+
fingerprint_timestamp_ms: number;
|
|
27
|
+
ai_model_id?: string;
|
|
28
|
+
ai_prompt_hash?: string;
|
|
29
|
+
ai_response_hash?: string;
|
|
30
|
+
ai_latency_ms?: number;
|
|
31
|
+
ai_input_tokens?: number;
|
|
32
|
+
ai_output_tokens?: number;
|
|
33
|
+
ai_context?: {
|
|
34
|
+
provider?: string;
|
|
35
|
+
guardrails?: string[];
|
|
36
|
+
system_fingerprint?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface WitnessReceipt {
|
|
40
|
+
procedure_id: string;
|
|
41
|
+
verdict: "PASS" | "FAIL" | string;
|
|
42
|
+
swt3_anchor: string;
|
|
43
|
+
clearing_level: number;
|
|
44
|
+
witnessed_at: string;
|
|
45
|
+
verification_url: string;
|
|
46
|
+
ok: boolean;
|
|
47
|
+
error?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface BatchResponse {
|
|
50
|
+
ok: boolean;
|
|
51
|
+
tenant_id: string;
|
|
52
|
+
total: number;
|
|
53
|
+
accepted: number;
|
|
54
|
+
rejected: number;
|
|
55
|
+
receipts: WitnessReceipt[];
|
|
56
|
+
}
|
|
57
|
+
export interface InferenceRecord {
|
|
58
|
+
modelId: string;
|
|
59
|
+
modelHash: string;
|
|
60
|
+
promptHash: string;
|
|
61
|
+
responseHash: string;
|
|
62
|
+
latencyMs: number;
|
|
63
|
+
inputTokens?: number;
|
|
64
|
+
outputTokens?: number;
|
|
65
|
+
guardrailsActive: number;
|
|
66
|
+
guardrailsRequired: number;
|
|
67
|
+
guardrailPassed: boolean;
|
|
68
|
+
hasRefusal: boolean;
|
|
69
|
+
provider: string;
|
|
70
|
+
systemFingerprint?: string;
|
|
71
|
+
guardrailNames: string[];
|
|
72
|
+
}
|
|
73
|
+
/** Valid AI procedure IDs from SWT3 Spec v1.2.0 */
|
|
74
|
+
export declare const AI_PROCEDURES: Set<string>;
|
|
75
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,wBAAwB,EAAE,MAAM,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE;QACX,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,mDAAmD;AACnD,eAAO,MAAM,aAAa,aAQxB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SWT3 AI Witness SDK — Type definitions.
|
|
3
|
+
*/
|
|
4
|
+
/** Valid AI procedure IDs from SWT3 Spec v1.2.0 */
|
|
5
|
+
export const AI_PROCEDURES = new Set([
|
|
6
|
+
"AI-INF.1", "AI-INF.2", "AI-INF.3",
|
|
7
|
+
"AI-MDL.1", "AI-MDL.2", "AI-MDL.3",
|
|
8
|
+
"AI-GRD.1", "AI-GRD.2", "AI-GRD.3",
|
|
9
|
+
"AI-FAIR.1", "AI-FAIR.2",
|
|
10
|
+
"AI-DATA.1", "AI-DATA.2",
|
|
11
|
+
"AI-HITL.1", "AI-HITL.2",
|
|
12
|
+
"AI-EXPL.1", "AI-EXPL.2",
|
|
13
|
+
]);
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AA4EH,mDAAmD;AACnD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IACnC,UAAU,EAAE,UAAU,EAAE,UAAU;IAClC,UAAU,EAAE,UAAU,EAAE,UAAU;IAClC,UAAU,EAAE,UAAU,EAAE,UAAU;IAClC,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,WAAW;CACzB,CAAC,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SWT3 AI Witness SDK — Core Witness class.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { Witness } from "@tenova/swt3-ai";
|
|
6
|
+
* import OpenAI from "openai";
|
|
7
|
+
*
|
|
8
|
+
* const witness = new Witness({
|
|
9
|
+
* endpoint: "https://sovereign.tenova.io",
|
|
10
|
+
* apiKey: "axm_live_...",
|
|
11
|
+
* tenantId: "YOUR_TENANT_ID",
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
15
|
+
* const response = await client.chat.completions.create({ ... });
|
|
16
|
+
*
|
|
17
|
+
* // Graceful shutdown
|
|
18
|
+
* await witness.flush();
|
|
19
|
+
*/
|
|
20
|
+
import { type VercelOnFinishOptions } from "./adapters/vercel-ai.js";
|
|
21
|
+
import type { WitnessReceipt, InferenceRecord } from "./types.js";
|
|
22
|
+
export interface WitnessOptions {
|
|
23
|
+
endpoint: string;
|
|
24
|
+
apiKey: string;
|
|
25
|
+
tenantId: string;
|
|
26
|
+
clearingLevel?: 0 | 1 | 2 | 3;
|
|
27
|
+
bufferSize?: number;
|
|
28
|
+
flushInterval?: number;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
maxRetries?: number;
|
|
31
|
+
latencyThresholdMs?: number;
|
|
32
|
+
guardrailsRequired?: number;
|
|
33
|
+
guardrailNames?: string[];
|
|
34
|
+
procedures?: string[];
|
|
35
|
+
}
|
|
36
|
+
export declare class Witness {
|
|
37
|
+
private config;
|
|
38
|
+
private buffer;
|
|
39
|
+
constructor(options: WitnessOptions);
|
|
40
|
+
/**
|
|
41
|
+
* Wrap an AI client with transparent witnessing.
|
|
42
|
+
*
|
|
43
|
+
* Supported: OpenAI, Anthropic
|
|
44
|
+
* Returns a proxy that behaves identically to the original client.
|
|
45
|
+
*
|
|
46
|
+
* Usage:
|
|
47
|
+
* const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
48
|
+
* const client = witness.wrap(new Anthropic()) as Anthropic;
|
|
49
|
+
*/
|
|
50
|
+
wrap(client: unknown): unknown;
|
|
51
|
+
/**
|
|
52
|
+
* Record a witnessed inference. Extracts factors, applies clearing,
|
|
53
|
+
* and enqueues payloads for background flush.
|
|
54
|
+
*/
|
|
55
|
+
record(inference: InferenceRecord): void;
|
|
56
|
+
/**
|
|
57
|
+
* Create a Vercel AI SDK `onFinish` callback for streamText / generateText.
|
|
58
|
+
*
|
|
59
|
+
* Usage:
|
|
60
|
+
* const result = await streamText({
|
|
61
|
+
* model: openai("gpt-4o"),
|
|
62
|
+
* prompt: myPrompt,
|
|
63
|
+
* onFinish: witness.vercelOnFinish({ promptText: myPrompt }),
|
|
64
|
+
* });
|
|
65
|
+
*/
|
|
66
|
+
vercelOnFinish(options?: VercelOnFinishOptions): (result: unknown) => void;
|
|
67
|
+
/** Force-flush all buffered payloads. */
|
|
68
|
+
flush(): Promise<WitnessReceipt[]>;
|
|
69
|
+
/** Stop the witness and flush remaining payloads. */
|
|
70
|
+
stop(): Promise<WitnessReceipt[]>;
|
|
71
|
+
/** Number of payloads waiting. */
|
|
72
|
+
get pending(): number;
|
|
73
|
+
/** All receipts from completed flushes. */
|
|
74
|
+
get receipts(): WitnessReceipt[];
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=witness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"witness.d.ts","sourceRoot":"","sources":["../src/witness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,EAAwB,KAAK,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,KAAK,EAAiC,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEjG,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAgB;gBAElB,OAAO,EAAE,cAAc;IAwBnC;;;;;;;;;OASG;IACH,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAoB9B;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,eAAe,GAAG,IAAI;IAoBxC;;;;;;;;;OASG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;IAI1E,yCAAyC;IACnC,KAAK,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAIxC,qDAAqD;IAC/C,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAIvC,kCAAkC;IAClC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,2CAA2C;IAC3C,IAAI,QAAQ,IAAI,cAAc,EAAE,CAE/B;CACF"}
|
package/dist/witness.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SWT3 AI Witness SDK — Core Witness class.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { Witness } from "@tenova/swt3-ai";
|
|
6
|
+
* import OpenAI from "openai";
|
|
7
|
+
*
|
|
8
|
+
* const witness = new Witness({
|
|
9
|
+
* endpoint: "https://sovereign.tenova.io",
|
|
10
|
+
* apiKey: "axm_live_...",
|
|
11
|
+
* tenantId: "YOUR_TENANT_ID",
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
15
|
+
* const response = await client.chat.completions.create({ ... });
|
|
16
|
+
*
|
|
17
|
+
* // Graceful shutdown
|
|
18
|
+
* await witness.flush();
|
|
19
|
+
*/
|
|
20
|
+
import { extractPayloads } from "./clearing.js";
|
|
21
|
+
import { WitnessBuffer } from "./buffer.js";
|
|
22
|
+
import { wrapOpenAI } from "./adapters/openai.js";
|
|
23
|
+
import { wrapAnthropic } from "./adapters/anthropic.js";
|
|
24
|
+
import { createVercelOnFinish } from "./adapters/vercel-ai.js";
|
|
25
|
+
export class Witness {
|
|
26
|
+
config;
|
|
27
|
+
buffer;
|
|
28
|
+
constructor(options) {
|
|
29
|
+
if (!options.endpoint)
|
|
30
|
+
throw new Error("endpoint is required");
|
|
31
|
+
if (!options.apiKey)
|
|
32
|
+
throw new Error("apiKey is required");
|
|
33
|
+
if (!options.apiKey.startsWith("axm_"))
|
|
34
|
+
throw new Error("apiKey must start with 'axm_'");
|
|
35
|
+
if (!options.tenantId)
|
|
36
|
+
throw new Error("tenantId is required");
|
|
37
|
+
this.config = {
|
|
38
|
+
endpoint: options.endpoint.replace(/\/+$/, ""),
|
|
39
|
+
apiKey: options.apiKey,
|
|
40
|
+
tenantId: options.tenantId,
|
|
41
|
+
clearingLevel: options.clearingLevel ?? 1,
|
|
42
|
+
bufferSize: options.bufferSize ?? 10,
|
|
43
|
+
flushInterval: options.flushInterval ?? 5.0,
|
|
44
|
+
timeout: options.timeout ?? 10000,
|
|
45
|
+
maxRetries: options.maxRetries ?? 3,
|
|
46
|
+
latencyThresholdMs: options.latencyThresholdMs ?? 30000,
|
|
47
|
+
guardrailsRequired: options.guardrailsRequired ?? 0,
|
|
48
|
+
guardrailNames: options.guardrailNames ?? [],
|
|
49
|
+
procedures: options.procedures,
|
|
50
|
+
};
|
|
51
|
+
this.buffer = new WitnessBuffer(this.config);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Wrap an AI client with transparent witnessing.
|
|
55
|
+
*
|
|
56
|
+
* Supported: OpenAI, Anthropic
|
|
57
|
+
* Returns a proxy that behaves identically to the original client.
|
|
58
|
+
*
|
|
59
|
+
* Usage:
|
|
60
|
+
* const client = witness.wrap(new OpenAI()) as OpenAI;
|
|
61
|
+
* const client = witness.wrap(new Anthropic()) as Anthropic;
|
|
62
|
+
*/
|
|
63
|
+
wrap(client) {
|
|
64
|
+
const proto = Object.getPrototypeOf(client);
|
|
65
|
+
const name = proto?.constructor?.name ?? "";
|
|
66
|
+
const obj = client;
|
|
67
|
+
// OpenAI: has client.chat.completions
|
|
68
|
+
if (name === "OpenAI" || obj?.chat) {
|
|
69
|
+
return wrapOpenAI(client, this);
|
|
70
|
+
}
|
|
71
|
+
// Anthropic: has client.messages
|
|
72
|
+
if (name === "Anthropic" || (obj?.messages && !obj?.chat)) {
|
|
73
|
+
return wrapAnthropic(client, this);
|
|
74
|
+
}
|
|
75
|
+
throw new TypeError(`Unsupported client: ${name || "unknown"}. Supported: OpenAI, Anthropic.`);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Record a witnessed inference. Extracts factors, applies clearing,
|
|
79
|
+
* and enqueues payloads for background flush.
|
|
80
|
+
*/
|
|
81
|
+
record(inference) {
|
|
82
|
+
// Merge guardrail config
|
|
83
|
+
if (this.config.guardrailNames.length > 0 && inference.guardrailNames.length === 0) {
|
|
84
|
+
inference.guardrailNames = this.config.guardrailNames;
|
|
85
|
+
inference.guardrailsActive = this.config.guardrailNames.length;
|
|
86
|
+
inference.guardrailsRequired = this.config.guardrailsRequired;
|
|
87
|
+
}
|
|
88
|
+
const payloads = extractPayloads(inference, this.config.tenantId, this.config.clearingLevel, this.config.latencyThresholdMs, this.config.guardrailsRequired, this.config.procedures);
|
|
89
|
+
this.buffer.enqueueMany(payloads);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a Vercel AI SDK `onFinish` callback for streamText / generateText.
|
|
93
|
+
*
|
|
94
|
+
* Usage:
|
|
95
|
+
* const result = await streamText({
|
|
96
|
+
* model: openai("gpt-4o"),
|
|
97
|
+
* prompt: myPrompt,
|
|
98
|
+
* onFinish: witness.vercelOnFinish({ promptText: myPrompt }),
|
|
99
|
+
* });
|
|
100
|
+
*/
|
|
101
|
+
vercelOnFinish(options) {
|
|
102
|
+
return createVercelOnFinish(this, options);
|
|
103
|
+
}
|
|
104
|
+
/** Force-flush all buffered payloads. */
|
|
105
|
+
async flush() {
|
|
106
|
+
return this.buffer.flush();
|
|
107
|
+
}
|
|
108
|
+
/** Stop the witness and flush remaining payloads. */
|
|
109
|
+
async stop() {
|
|
110
|
+
return this.buffer.stop();
|
|
111
|
+
}
|
|
112
|
+
/** Number of payloads waiting. */
|
|
113
|
+
get pending() {
|
|
114
|
+
return this.buffer.pending;
|
|
115
|
+
}
|
|
116
|
+
/** All receipts from completed flushes. */
|
|
117
|
+
get receipts() {
|
|
118
|
+
return this.buffer.receipts;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=witness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"witness.js","sourceRoot":"","sources":["../src/witness.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tenova/swt3-ai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SWT3 AI Witness SDK — cryptographic attestation for AI inference",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"test": "node --experimental-vm-modules node_modules/.bin/vitest run",
|
|
21
|
+
"test:vectors": "npx tsx test/fingerprint.test.ts",
|
|
22
|
+
"typecheck": "tsc --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"ai",
|
|
26
|
+
"compliance",
|
|
27
|
+
"witness",
|
|
28
|
+
"attestation",
|
|
29
|
+
"swt3",
|
|
30
|
+
"eu-ai-act",
|
|
31
|
+
"nist-ai-rmf",
|
|
32
|
+
"openai",
|
|
33
|
+
"anthropic"
|
|
34
|
+
],
|
|
35
|
+
"author": "TeNova <engineering@tenova.io>",
|
|
36
|
+
"license": "Apache-2.0",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/tenova/swt3-ai"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"openai": ">=4.0.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"openai": {
|
|
46
|
+
"optional": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"typescript": "^5.5.0",
|
|
51
|
+
"vitest": "^2.0.0",
|
|
52
|
+
"tsx": "^4.0.0",
|
|
53
|
+
"openai": "^4.70.0"
|
|
54
|
+
}
|
|
55
|
+
}
|