@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.
@@ -0,0 +1,252 @@
1
+ /**
2
+ * SWT3 AI Witness SDK — OpenAI Adapter (ES6 Proxy).
3
+ *
4
+ * Uses JavaScript's native Proxy to intercept property access on the
5
+ * OpenAI client, following the chain: client.chat.completions.create()
6
+ *
7
+ * Handles both:
8
+ * - Non-streaming: ChatCompletion response object
9
+ * - Streaming: AsyncIterable<ChatCompletionChunk> — accumulates chunks
10
+ * for hashing, then witnesses after stream completes
11
+ *
12
+ * The developer's code sees zero difference from using the raw client.
13
+ */
14
+ import { sha256Truncated } from "../fingerprint.js";
15
+ /**
16
+ * Methods to intercept at each path level.
17
+ * "chat.completions" → intercept "create"
18
+ */
19
+ const INTERCEPT_PATHS = {
20
+ "chat.completions": new Set(["create"]),
21
+ };
22
+ /**
23
+ * Wrap an OpenAI client with an ES6 Proxy for transparent witnessing.
24
+ */
25
+ export function wrapOpenAI(client, witness) {
26
+ return createProxy(client, witness, "");
27
+ }
28
+ function createProxy(target, witness, path) {
29
+ return new Proxy(target, {
30
+ get(obj, prop) {
31
+ if (typeof prop === "symbol")
32
+ return Reflect.get(obj, prop);
33
+ const realValue = Reflect.get(obj, prop);
34
+ const currentPath = path ? `${path}.${prop}` : prop;
35
+ // Check if this property is an interceptable method
36
+ if (path in INTERCEPT_PATHS && INTERCEPT_PATHS[path].has(prop)) {
37
+ // This IS the method to intercept
38
+ return createInterceptor(realValue, witness);
39
+ }
40
+ // Check if this path could lead to interceptable methods
41
+ const hasChildren = Object.keys(INTERCEPT_PATHS).some((p) => p === currentPath || p.startsWith(currentPath + "."));
42
+ if (hasChildren && typeof realValue === "object" && realValue !== null) {
43
+ return createProxy(realValue, witness, currentPath);
44
+ }
45
+ // Pass through
46
+ return realValue;
47
+ },
48
+ });
49
+ }
50
+ function createInterceptor(realMethod, witness) {
51
+ return function interceptedCreate(...args) {
52
+ const kwargs = (args[0] ?? {});
53
+ const messages = kwargs.messages;
54
+ const model = kwargs.model ?? "unknown";
55
+ const isStreaming = kwargs.stream === true;
56
+ // Hash prompt before the call
57
+ const promptText = extractPromptText(messages);
58
+ const promptHash = sha256Truncated(promptText);
59
+ // Start latency timer
60
+ const start = performance.now();
61
+ // Call the real method (bound to its original this)
62
+ const result = realMethod.call(this, ...args);
63
+ if (isStreaming) {
64
+ // Streaming: wrap the async iterable to accumulate chunks
65
+ return handleStreaming(result, witness, model, promptHash, start);
66
+ }
67
+ // Non-streaming: result is a Promise<ChatCompletion>
68
+ return result.then((response) => {
69
+ const elapsedMs = Math.round(performance.now() - start);
70
+ const record = extractRecord(response, model, promptHash, elapsedMs);
71
+ witness.record(record);
72
+ return response; // Return UNTOUCHED
73
+ });
74
+ };
75
+ }
76
+ // ── Streaming Handler ──────────────────────────────────────────────
77
+ //
78
+ // OpenAI's streaming returns an object with:
79
+ // - Symbol.asyncIterator (for `for await...of`)
80
+ // - .controller for abort
81
+ // - .toReadableStream() for web streams
82
+ //
83
+ // We wrap the async iterator to accumulate content chunks, then
84
+ // witness after the stream completes. The developer's stream
85
+ // behavior is completely unchanged.
86
+ async function* streamAccumulator(stream, witness, model, promptHash, startTime) {
87
+ const textParts = [];
88
+ let actualModel = model;
89
+ let systemFingerprint;
90
+ let hasRefusal = false;
91
+ let finishReason = "";
92
+ let inputTokens;
93
+ let outputTokens;
94
+ for await (const chunk of stream) {
95
+ // Yield chunk to the developer immediately (untouched)
96
+ yield chunk;
97
+ // Extract data from chunk for witnessing
98
+ const c = chunk;
99
+ if (c.model)
100
+ actualModel = c.model;
101
+ if (c.system_fingerprint)
102
+ systemFingerprint = c.system_fingerprint;
103
+ const choices = c.choices;
104
+ if (choices?.[0]) {
105
+ const delta = choices[0].delta;
106
+ if (delta?.content) {
107
+ textParts.push(delta.content);
108
+ }
109
+ if (delta?.refusal) {
110
+ hasRefusal = true;
111
+ }
112
+ if (choices[0].finish_reason) {
113
+ finishReason = choices[0].finish_reason;
114
+ }
115
+ }
116
+ // Usage info comes in the final chunk (stream_options: {include_usage: true})
117
+ const usage = c.usage;
118
+ if (usage) {
119
+ inputTokens = usage.prompt_tokens;
120
+ outputTokens = usage.completion_tokens;
121
+ }
122
+ }
123
+ // Stream complete — witness the full inference
124
+ const elapsedMs = Math.round(performance.now() - startTime);
125
+ const responseText = textParts.join("");
126
+ if (finishReason === "content_filter")
127
+ hasRefusal = true;
128
+ const modelHashInput = systemFingerprint
129
+ ? `${actualModel}:${systemFingerprint}`
130
+ : actualModel;
131
+ const record = {
132
+ modelId: actualModel,
133
+ modelHash: sha256Truncated(modelHashInput),
134
+ promptHash,
135
+ responseHash: sha256Truncated(responseText),
136
+ latencyMs: elapsedMs,
137
+ inputTokens,
138
+ outputTokens,
139
+ guardrailsActive: 0,
140
+ guardrailsRequired: 0,
141
+ guardrailPassed: true,
142
+ hasRefusal,
143
+ provider: "openai",
144
+ systemFingerprint,
145
+ guardrailNames: [],
146
+ };
147
+ witness.record(record);
148
+ }
149
+ function handleStreaming(streamResult, witness, model, promptHash, startTime) {
150
+ // The stream result is a Promise that resolves to the stream object
151
+ // (OpenAI SDK returns Promise<Stream<ChatCompletionChunk>>)
152
+ if (streamResult && typeof streamResult.then === "function") {
153
+ return streamResult.then((stream) => {
154
+ return wrapStream(stream, witness, model, promptHash, startTime);
155
+ });
156
+ }
157
+ // Direct stream object (shouldn't happen but handle gracefully)
158
+ return wrapStream(streamResult, witness, model, promptHash, startTime);
159
+ }
160
+ function wrapStream(stream, witness, model, promptHash, startTime) {
161
+ const s = stream;
162
+ // Create the accumulating async generator
163
+ const gen = streamAccumulator(s, witness, model, promptHash, startTime);
164
+ // Return a proxy that preserves all stream methods but overrides the iterator
165
+ return new Proxy(s, {
166
+ get(target, prop) {
167
+ // Override the async iterator
168
+ if (prop === Symbol.asyncIterator) {
169
+ return () => gen;
170
+ }
171
+ // Preserve other methods (controller, toReadableStream, etc.)
172
+ const value = Reflect.get(target, prop);
173
+ if (typeof value === "function") {
174
+ return value.bind(target);
175
+ }
176
+ return value;
177
+ },
178
+ });
179
+ }
180
+ // ── Factor Extraction ──────────────────────────────────────────────
181
+ function extractPromptText(messages) {
182
+ if (typeof messages === "string")
183
+ return messages;
184
+ if (!Array.isArray(messages))
185
+ return "";
186
+ const parts = [];
187
+ for (const msg of messages) {
188
+ if (typeof msg === "object" && msg !== null) {
189
+ const m = msg;
190
+ const content = m.content;
191
+ if (typeof content === "string") {
192
+ parts.push(content);
193
+ }
194
+ else if (Array.isArray(content)) {
195
+ for (const part of content) {
196
+ if (typeof part === "object" && part !== null) {
197
+ const p = part;
198
+ if (p.type === "text" && typeof p.text === "string") {
199
+ parts.push(p.text);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+ return parts.join("\n");
207
+ }
208
+ function extractRecord(response, model, promptHash, elapsedMs) {
209
+ const r = response;
210
+ let responseText = "";
211
+ let hasRefusal = false;
212
+ const choices = r.choices;
213
+ if (choices?.[0]) {
214
+ const message = choices[0].message;
215
+ if (message) {
216
+ responseText = message.content ?? "";
217
+ if (message.refusal)
218
+ hasRefusal = true;
219
+ }
220
+ if (choices[0].finish_reason === "content_filter")
221
+ hasRefusal = true;
222
+ }
223
+ let inputTokens;
224
+ let outputTokens;
225
+ const usage = r.usage;
226
+ if (usage) {
227
+ inputTokens = usage.prompt_tokens;
228
+ outputTokens = usage.completion_tokens;
229
+ }
230
+ const actualModel = r.model ?? model;
231
+ const systemFingerprint = r.system_fingerprint;
232
+ const modelHashInput = systemFingerprint
233
+ ? `${actualModel}:${systemFingerprint}`
234
+ : actualModel;
235
+ return {
236
+ modelId: actualModel,
237
+ modelHash: sha256Truncated(modelHashInput),
238
+ promptHash,
239
+ responseHash: sha256Truncated(responseText),
240
+ latencyMs: elapsedMs,
241
+ inputTokens,
242
+ outputTokens,
243
+ guardrailsActive: 0,
244
+ guardrailsRequired: 0,
245
+ guardrailPassed: true,
246
+ hasRefusal,
247
+ provider: "openai",
248
+ systemFingerprint,
249
+ guardrailNames: [],
250
+ };
251
+ }
252
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/adapters/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;GAGG;AACH,MAAM,eAAe,GAAgC;IACnD,kBAAkB,EAAE,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;CACxC,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAe,EAAE,OAAgB;IAC1D,OAAO,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,WAAW,CAAC,MAAe,EAAE,OAAgB,EAAE,IAAY;IAClE,OAAO,IAAI,KAAK,CAAC,MAAgB,EAAE;QACjC,GAAG,CAAC,GAAW,EAAE,IAAqB;YACpC,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAE5D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAEpD,oDAAoD;YACpD,IAAI,IAAI,IAAI,eAAe,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/D,kCAAkC;gBAClC,OAAO,iBAAiB,CAAC,SAA4C,EAAE,OAAO,CAAC,CAAC;YAClF,CAAC;YAED,yDAAyD;YACzD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CACnD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,WAAW,IAAI,CAAC,CAAC,UAAU,CAAC,WAAW,GAAG,GAAG,CAAC,CAC5D,CAAC;YAEF,IAAI,WAAW,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvE,OAAO,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;YACtD,CAAC;YAED,eAAe;YACf,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CACxB,UAA2C,EAC3C,OAAgB;IAEhB,OAAO,SAAS,iBAAiB,CAAgB,GAAG,IAAe;QACjE,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;QAC1D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAqB,CAAC;QAC9C,MAAM,KAAK,GAAI,MAAM,CAAC,KAAgB,IAAI,SAAS,CAAC;QACpD,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC;QAE3C,8BAA8B;QAC9B,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QAE/C,sBAAsB;QACtB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAEhC,oDAAoD;QACpD,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;QAE9C,IAAI,WAAW,EAAE,CAAC;YAChB,0DAA0D;YAC1D,OAAO,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACpE,CAAC;QAED,qDAAqD;QACrD,OAAQ,MAA2B,CAAC,IAAI,CAAC,CAAC,QAAiB,EAAE,EAAE;YAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;YACrE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvB,OAAO,QAAQ,CAAC,CAAC,mBAAmB;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,EAAE;AACF,6CAA6C;AAC7C,kDAAkD;AAClD,4BAA4B;AAC5B,0CAA0C;AAC1C,EAAE;AACF,gEAAgE;AAChE,6DAA6D;AAC7D,oCAAoC;AAEpC,KAAK,SAAS,CAAC,CAAC,iBAAiB,CAC/B,MAA8B,EAC9B,OAAgB,EAChB,KAAa,EACb,UAAkB,EAClB,SAAiB;IAEjB,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,iBAAqC,CAAC;IAC1C,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,WAA+B,CAAC;IACpC,IAAI,YAAgC,CAAC;IAErC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACjC,uDAAuD;QACvD,MAAM,KAAK,CAAC;QAEZ,yCAAyC;QACzC,MAAM,CAAC,GAAG,KAAgC,CAAC;QAE3C,IAAI,CAAC,CAAC,KAAK;YAAE,WAAW,GAAG,CAAC,CAAC,KAAe,CAAC;QAC7C,IAAI,CAAC,CAAC,kBAAkB;YAAE,iBAAiB,GAAG,CAAC,CAAC,kBAA4B,CAAC;QAE7E,MAAM,OAAO,GAAG,CAAC,CAAC,OAAqD,CAAC;QACxE,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAA4C,CAAC;YACtE,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;gBACnB,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAiB,CAAC,CAAC;YAC1C,CAAC;YACD,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;gBACnB,UAAU,GAAG,IAAI,CAAC;YACpB,CAAC;YACD,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;gBAC7B,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,aAAuB,CAAC;YACpD,CAAC;QACH,CAAC;QAED,8EAA8E;QAC9E,MAAM,KAAK,GAAG,CAAC,CAAC,KAA4C,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC;YACV,WAAW,GAAG,KAAK,CAAC,aAAmC,CAAC;YACxD,YAAY,GAAG,KAAK,CAAC,iBAAuC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAExC,IAAI,YAAY,KAAK,gBAAgB;QAAE,UAAU,GAAG,IAAI,CAAC;IAEzD,MAAM,cAAc,GAAG,iBAAiB;QACtC,CAAC,CAAC,GAAG,WAAW,IAAI,iBAAiB,EAAE;QACvC,CAAC,CAAC,WAAW,CAAC;IAEhB,MAAM,MAAM,GAAoB;QAC9B,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,eAAe,CAAC,cAAc,CAAC;QAC1C,UAAU;QACV,YAAY,EAAE,eAAe,CAAC,YAAY,CAAC;QAC3C,SAAS,EAAE,SAAS;QACpB,WAAW;QACX,YAAY;QACZ,gBAAgB,EAAE,CAAC;QACnB,kBAAkB,EAAE,CAAC;QACrB,eAAe,EAAE,IAAI;QACrB,UAAU;QACV,QAAQ,EAAE,QAAQ;QAClB,iBAAiB;QACjB,cAAc,EAAE,EAAE;KACnB,CAAC;IAEF,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,eAAe,CACtB,YAAqB,EACrB,OAAgB,EAChB,KAAa,EACb,UAAkB,EAClB,SAAiB;IAEjB,oEAAoE;IACpE,4DAA4D;IAC5D,IAAI,YAAY,IAAI,OAAQ,YAAiC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAClF,OAAQ,YAAiC,CAAC,IAAI,CAAC,CAAC,MAAe,EAAE,EAAE;YACjE,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gEAAgE;IAChE,OAAO,UAAU,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,UAAU,CACjB,MAAe,EACf,OAAgB,EAChB,KAAa,EACb,UAAkB,EAClB,SAAiB;IAEjB,MAAM,CAAC,GAAG,MAA0C,CAAC;IAErD,0CAA0C;IAC1C,MAAM,GAAG,GAAG,iBAAiB,CAC3B,CAAsC,EACtC,OAAO,EACP,KAAK,EACL,UAAU,EACV,SAAS,CACV,CAAC;IAEF,8EAA8E;IAC9E,OAAO,IAAI,KAAK,CAAC,CAAC,EAAE;QAClB,GAAG,CAAC,MAAwC,EAAE,IAAqB;YACjE,8BAA8B;YAC9B,IAAI,IAAI,KAAK,MAAM,CAAC,aAAa,EAAE,CAAC;gBAClC,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC;YACnB,CAAC;YAED,8DAA8D;YAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACxC,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;gBAChC,OAAQ,KAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,sEAAsE;AAEtE,SAAS,iBAAiB,CAAC,QAAiB;IAC1C,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC5C,MAAM,CAAC,GAAG,GAA8B,CAAC;YACzC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;YAC1B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAChC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;oBAC3B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;wBAC9C,MAAM,CAAC,GAAG,IAA+B,CAAC;wBAC1C,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;4BACpD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;wBACrB,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,aAAa,CACpB,QAAiB,EACjB,KAAa,EACb,UAAkB,EAClB,SAAiB;IAEjB,MAAM,CAAC,GAAG,QAAmC,CAAC;IAC9C,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,MAAM,OAAO,GAAG,CAAC,CAAC,OAAqD,CAAC;IACxE,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,OAA8C,CAAC;QAC1E,IAAI,OAAO,EAAE,CAAC;YACZ,YAAY,GAAI,OAAO,CAAC,OAAkB,IAAI,EAAE,CAAC;YACjD,IAAI,OAAO,CAAC,OAAO;gBAAE,UAAU,GAAG,IAAI,CAAC;QACzC,CAAC;QACD,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,KAAK,gBAAgB;YAAE,UAAU,GAAG,IAAI,CAAC;IACvE,CAAC;IAED,IAAI,WAA+B,CAAC;IACpC,IAAI,YAAgC,CAAC;IACrC,MAAM,KAAK,GAAG,CAAC,CAAC,KAA4C,CAAC;IAC7D,IAAI,KAAK,EAAE,CAAC;QACV,WAAW,GAAG,KAAK,CAAC,aAAmC,CAAC;QACxD,YAAY,GAAG,KAAK,CAAC,iBAAuC,CAAC;IAC/D,CAAC;IAED,MAAM,WAAW,GAAI,CAAC,CAAC,KAAgB,IAAI,KAAK,CAAC;IACjD,MAAM,iBAAiB,GAAG,CAAC,CAAC,kBAAwC,CAAC;IAErE,MAAM,cAAc,GAAG,iBAAiB;QACtC,CAAC,CAAC,GAAG,WAAW,IAAI,iBAAiB,EAAE;QACvC,CAAC,CAAC,WAAW,CAAC;IAEhB,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,eAAe,CAAC,cAAc,CAAC;QAC1C,UAAU;QACV,YAAY,EAAE,eAAe,CAAC,YAAY,CAAC;QAC3C,SAAS,EAAE,SAAS;QACpB,WAAW;QACX,YAAY;QACZ,gBAAgB,EAAE,CAAC;QACnB,kBAAkB,EAAE,CAAC;QACrB,eAAe,EAAE,IAAI;QACrB,UAAU;QACV,QAAQ,EAAE,QAAQ;QAClB,iBAAiB;QACjB,cAAc,EAAE,EAAE;KACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * SWT3 AI Witness SDK — Vercel AI SDK Integration.
3
+ *
4
+ * Provides an `onFinish` callback factory for the Vercel AI SDK's
5
+ * `streamText()` and `generateText()` functions. This is the most
6
+ * idiomatic integration for Next.js / React developers.
7
+ *
8
+ * Usage:
9
+ * import { streamText } from "ai";
10
+ * import { openai } from "@ai-sdk/openai";
11
+ *
12
+ * const result = await streamText({
13
+ * model: openai("gpt-4o"),
14
+ * prompt: "Summarize this contract...",
15
+ * onFinish: witness.vercelOnFinish(),
16
+ * });
17
+ *
18
+ * The `onFinish` callback receives a normalized result regardless of
19
+ * provider (OpenAI, Anthropic, Google, custom), so this single hook
20
+ * works with any Vercel AI SDK provider — no per-provider adapters needed.
21
+ *
22
+ * Vercel AI SDK onFinish payload:
23
+ * {
24
+ * text: string, // Complete response text
25
+ * usage: { promptTokens, completionTokens },
26
+ * finishReason: "stop" | "length" | "content-filter" | "tool-calls" | ...,
27
+ * response: { id, model, timestamp, headers },
28
+ * experimental_providerMetadata?: { ... },
29
+ * }
30
+ */
31
+ import type { Witness } from "../witness.js";
32
+ /**
33
+ * Vercel AI SDK onFinish callback shape.
34
+ * We define this locally to avoid requiring `ai` as a dependency.
35
+ */
36
+ interface VercelOnFinishResult {
37
+ text: string;
38
+ usage: {
39
+ promptTokens: number;
40
+ completionTokens: number;
41
+ };
42
+ finishReason: string;
43
+ response: {
44
+ id?: string;
45
+ model?: string;
46
+ timestamp?: Date;
47
+ headers?: Record<string, string>;
48
+ };
49
+ experimental_providerMetadata?: Record<string, unknown>;
50
+ }
51
+ export interface VercelOnFinishOptions {
52
+ /** Override the prompt text for hashing (if not using the `prompt` param). */
53
+ promptText?: string;
54
+ /** Model name override (if response.model is missing). */
55
+ modelId?: string;
56
+ }
57
+ /**
58
+ * Create a Vercel AI SDK `onFinish` callback that witnesses the inference.
59
+ *
60
+ * Works with both `streamText()` and `generateText()`.
61
+ */
62
+ export declare function createVercelOnFinish(witness: Witness, options?: VercelOnFinishOptions): (result: VercelOnFinishResult) => void;
63
+ export {};
64
+ //# sourceMappingURL=vercel-ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel-ai.d.ts","sourceRoot":"","sources":["../../src/adapters/vercel-ai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C;;;GAGG;AACH,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE;QACR,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClC,CAAC;IACF,6BAA6B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,qBAA0B,GAClC,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAoCxC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * SWT3 AI Witness SDK — Vercel AI SDK Integration.
3
+ *
4
+ * Provides an `onFinish` callback factory for the Vercel AI SDK's
5
+ * `streamText()` and `generateText()` functions. This is the most
6
+ * idiomatic integration for Next.js / React developers.
7
+ *
8
+ * Usage:
9
+ * import { streamText } from "ai";
10
+ * import { openai } from "@ai-sdk/openai";
11
+ *
12
+ * const result = await streamText({
13
+ * model: openai("gpt-4o"),
14
+ * prompt: "Summarize this contract...",
15
+ * onFinish: witness.vercelOnFinish(),
16
+ * });
17
+ *
18
+ * The `onFinish` callback receives a normalized result regardless of
19
+ * provider (OpenAI, Anthropic, Google, custom), so this single hook
20
+ * works with any Vercel AI SDK provider — no per-provider adapters needed.
21
+ *
22
+ * Vercel AI SDK onFinish payload:
23
+ * {
24
+ * text: string, // Complete response text
25
+ * usage: { promptTokens, completionTokens },
26
+ * finishReason: "stop" | "length" | "content-filter" | "tool-calls" | ...,
27
+ * response: { id, model, timestamp, headers },
28
+ * experimental_providerMetadata?: { ... },
29
+ * }
30
+ */
31
+ import { sha256Truncated } from "../fingerprint.js";
32
+ /**
33
+ * Create a Vercel AI SDK `onFinish` callback that witnesses the inference.
34
+ *
35
+ * Works with both `streamText()` and `generateText()`.
36
+ */
37
+ export function createVercelOnFinish(witness, options = {}) {
38
+ const capturedStart = performance.now();
39
+ return (result) => {
40
+ const elapsedMs = Math.round(performance.now() - capturedStart);
41
+ const model = result.response?.model ?? options.modelId ?? "unknown";
42
+ const responseText = result.text ?? "";
43
+ // Prompt text: caller can provide it, or we hash empty
44
+ // (The Vercel AI SDK doesn't expose the prompt in onFinish,
45
+ // so the caller should pass it via options for full provenance)
46
+ const promptText = options.promptText ?? "";
47
+ // Detect content filtering / refusal
48
+ const hasRefusal = result.finishReason === "content-filter" ||
49
+ result.finishReason === "error";
50
+ const record = {
51
+ modelId: model,
52
+ modelHash: sha256Truncated(model),
53
+ promptHash: sha256Truncated(promptText),
54
+ responseHash: sha256Truncated(responseText),
55
+ latencyMs: elapsedMs,
56
+ inputTokens: result.usage?.promptTokens,
57
+ outputTokens: result.usage?.completionTokens,
58
+ guardrailsActive: 0,
59
+ guardrailsRequired: 0,
60
+ guardrailPassed: true,
61
+ hasRefusal,
62
+ provider: "vercel-ai",
63
+ guardrailNames: [],
64
+ };
65
+ witness.record(record);
66
+ };
67
+ }
68
+ //# sourceMappingURL=vercel-ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel-ai.js","sourceRoot":"","sources":["../../src/adapters/vercel-ai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AA+BpD;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAgB,EAChB,UAAiC,EAAE;IAEnC,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAExC,OAAO,CAAC,MAA4B,EAAE,EAAE;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC;QACrE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QAEvC,uDAAuD;QACvD,4DAA4D;QAC5D,iEAAiE;QACjE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;QAE5C,qCAAqC;QACrC,MAAM,UAAU,GACd,MAAM,CAAC,YAAY,KAAK,gBAAgB;YACxC,MAAM,CAAC,YAAY,KAAK,OAAO,CAAC;QAElC,MAAM,MAAM,GAAoB;YAC9B,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC;YACjC,UAAU,EAAE,eAAe,CAAC,UAAU,CAAC;YACvC,YAAY,EAAE,eAAe,CAAC,YAAY,CAAC;YAC3C,SAAS,EAAE,SAAS;YACpB,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,YAAY;YACvC,YAAY,EAAE,MAAM,CAAC,KAAK,EAAE,gBAAgB;YAC5C,gBAAgB,EAAE,CAAC;YACnB,kBAAkB,EAAE,CAAC;YACrB,eAAe,EAAE,IAAI;YACrB,UAAU;YACV,QAAQ,EAAE,WAAW;YACrB,cAAc,EAAE,EAAE;SACnB,CAAC;QAEF,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * SWT3 AI Witness SDK — Flush Buffer.
3
+ *
4
+ * Non-blocking buffer that collects witness payloads and flushes them
5
+ * to the /api/v1/witness/batch endpoint. Uses setTimeout for periodic
6
+ * flushing and a dead-letter array for resilience.
7
+ *
8
+ * Flight Recorder: When the endpoint is unreachable, payloads move to
9
+ * a dead-letter array and retry on the next cycle. Configurable cap
10
+ * prevents unbounded memory growth.
11
+ */
12
+ import type { WitnessConfig, WitnessPayload, WitnessReceipt } from "./types.js";
13
+ export declare class WitnessBuffer {
14
+ private config;
15
+ private queue;
16
+ private deadLetter;
17
+ private maxRetryBuffer;
18
+ private allReceipts;
19
+ private timer;
20
+ private stopped;
21
+ private consecutiveFailures;
22
+ constructor(config: WitnessConfig, maxRetryBuffer?: number);
23
+ /** Add a single payload to the buffer. */
24
+ enqueue(payload: WitnessPayload): void;
25
+ /** Add multiple payloads. */
26
+ enqueueMany(payloads: WitnessPayload[]): void;
27
+ /** Force-flush all buffered payloads. */
28
+ flush(): Promise<WitnessReceipt[]>;
29
+ /** Stop the buffer and flush remaining payloads. */
30
+ stop(): Promise<WitnessReceipt[]>;
31
+ /** Number of payloads waiting (includes dead-letter). */
32
+ get pending(): number;
33
+ /** Payloads in dead-letter queue awaiting retry. */
34
+ get deadLetterCount(): number;
35
+ /** All receipts from completed flushes. */
36
+ get receipts(): WitnessReceipt[];
37
+ private startTimer;
38
+ private flushInternal;
39
+ private sendBatch;
40
+ }
41
+ //# sourceMappingURL=buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../src/buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAiB,MAAM,YAAY,CAAC;AAI/F,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,mBAAmB,CAAK;gBAEpB,MAAM,EAAE,aAAa,EAAE,cAAc,SAA2B;IAM5E,0CAA0C;IAC1C,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAQtC,6BAA6B;IAC7B,WAAW,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,IAAI;IAI7C,yCAAyC;IACnC,KAAK,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAIxC,oDAAoD;IAC9C,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAgBvC,yDAAyD;IACzD,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,oDAAoD;IACpD,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,2CAA2C;IAC3C,IAAI,QAAQ,IAAI,cAAc,EAAE,CAE/B;IAED,OAAO,CAAC,UAAU;YAYJ,aAAa;YAWb,SAAS;CA+ExB"}
package/dist/buffer.js ADDED
@@ -0,0 +1,154 @@
1
+ /**
2
+ * SWT3 AI Witness SDK — Flush Buffer.
3
+ *
4
+ * Non-blocking buffer that collects witness payloads and flushes them
5
+ * to the /api/v1/witness/batch endpoint. Uses setTimeout for periodic
6
+ * flushing and a dead-letter array for resilience.
7
+ *
8
+ * Flight Recorder: When the endpoint is unreachable, payloads move to
9
+ * a dead-letter array and retry on the next cycle. Configurable cap
10
+ * prevents unbounded memory growth.
11
+ */
12
+ const DEFAULT_MAX_RETRY_BUFFER = 5000;
13
+ export class WitnessBuffer {
14
+ config;
15
+ queue = [];
16
+ deadLetter = [];
17
+ maxRetryBuffer;
18
+ allReceipts = [];
19
+ timer = null;
20
+ stopped = false;
21
+ consecutiveFailures = 0;
22
+ constructor(config, maxRetryBuffer = DEFAULT_MAX_RETRY_BUFFER) {
23
+ this.config = config;
24
+ this.maxRetryBuffer = maxRetryBuffer;
25
+ this.startTimer();
26
+ }
27
+ /** Add a single payload to the buffer. */
28
+ enqueue(payload) {
29
+ if (this.stopped)
30
+ return;
31
+ this.queue.push(payload);
32
+ if (this.queue.length >= this.config.bufferSize) {
33
+ this.flushInternal();
34
+ }
35
+ }
36
+ /** Add multiple payloads. */
37
+ enqueueMany(payloads) {
38
+ for (const p of payloads)
39
+ this.enqueue(p);
40
+ }
41
+ /** Force-flush all buffered payloads. */
42
+ async flush() {
43
+ return this.flushInternal();
44
+ }
45
+ /** Stop the buffer and flush remaining payloads. */
46
+ async stop() {
47
+ if (this.stopped)
48
+ return [];
49
+ this.stopped = true;
50
+ if (this.timer) {
51
+ clearTimeout(this.timer);
52
+ this.timer = null;
53
+ }
54
+ const receipts = await this.flushInternal();
55
+ if (this.deadLetter.length > 0) {
56
+ console.warn(`[swt3-ai] Buffer stopped with ${this.deadLetter.length} payloads in dead-letter queue`);
57
+ }
58
+ return receipts;
59
+ }
60
+ /** Number of payloads waiting (includes dead-letter). */
61
+ get pending() {
62
+ return this.queue.length + this.deadLetter.length;
63
+ }
64
+ /** Payloads in dead-letter queue awaiting retry. */
65
+ get deadLetterCount() {
66
+ return this.deadLetter.length;
67
+ }
68
+ /** All receipts from completed flushes. */
69
+ get receipts() {
70
+ return [...this.allReceipts];
71
+ }
72
+ startTimer() {
73
+ if (this.stopped)
74
+ return;
75
+ this.timer = setTimeout(() => {
76
+ this.flushInternal().catch(() => { });
77
+ this.startTimer();
78
+ }, this.config.flushInterval * 1000);
79
+ // Unref so the timer doesn't keep the process alive
80
+ if (typeof this.timer === "object" && "unref" in this.timer) {
81
+ this.timer.unref();
82
+ }
83
+ }
84
+ async flushInternal() {
85
+ // Drain queue
86
+ const payloads = [...this.deadLetter, ...this.queue];
87
+ this.deadLetter = [];
88
+ this.queue = [];
89
+ if (payloads.length === 0)
90
+ return [];
91
+ return this.sendBatch(payloads);
92
+ }
93
+ async sendBatch(payloads) {
94
+ if (payloads.length === 0)
95
+ return [];
96
+ const url = `${this.config.endpoint}/api/v1/witness/batch`;
97
+ const body = JSON.stringify({ witnesses: payloads });
98
+ const headers = {
99
+ "Content-Type": "application/json",
100
+ Authorization: `Bearer ${this.config.apiKey}`,
101
+ };
102
+ let lastError = null;
103
+ for (let attempt = 0; attempt < this.config.maxRetries; attempt++) {
104
+ try {
105
+ const controller = new AbortController();
106
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
107
+ const resp = await fetch(url, {
108
+ method: "POST",
109
+ headers,
110
+ body,
111
+ signal: controller.signal,
112
+ });
113
+ clearTimeout(timeoutId);
114
+ if (resp.status >= 400 && resp.status < 500) {
115
+ // Client error — don't retry, don't dead-letter
116
+ const text = await resp.text();
117
+ console.error(`[swt3-ai] Batch flush failed (${resp.status}): ${text.slice(0, 200)}`);
118
+ return [];
119
+ }
120
+ const result = (await resp.json());
121
+ const receipts = result.receipts ?? [];
122
+ this.allReceipts.push(...receipts);
123
+ this.consecutiveFailures = 0;
124
+ if (result.rejected > 0) {
125
+ console.warn(`[swt3-ai] Batch flush: ${result.accepted} accepted, ${result.rejected} rejected`);
126
+ }
127
+ return receipts;
128
+ }
129
+ catch (err) {
130
+ lastError = err instanceof Error ? err.message : String(err);
131
+ console.warn(`[swt3-ai] Batch flush attempt ${attempt + 1} failed: ${lastError}`);
132
+ // Exponential backoff: 1s, 2s, 4s
133
+ if (attempt < this.config.maxRetries - 1) {
134
+ await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
135
+ }
136
+ }
137
+ }
138
+ // All retries exhausted — move to dead-letter queue
139
+ this.consecutiveFailures++;
140
+ const before = this.deadLetter.length;
141
+ this.deadLetter.push(...payloads);
142
+ // Cap the dead-letter queue
143
+ if (this.deadLetter.length > this.maxRetryBuffer) {
144
+ const dropped = this.deadLetter.length - this.maxRetryBuffer;
145
+ this.deadLetter = this.deadLetter.slice(dropped);
146
+ console.error(`[swt3-ai] Dead-letter queue full: ${dropped} oldest payloads dropped (cap: ${this.maxRetryBuffer})`);
147
+ }
148
+ else {
149
+ console.warn(`[swt3-ai] Endpoint unreachable — ${payloads.length} payloads moved to dead-letter (total: ${this.deadLetter.length}). Error: ${lastError}`);
150
+ }
151
+ return [];
152
+ }
153
+ }
154
+ //# sourceMappingURL=buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.js","sourceRoot":"","sources":["../src/buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
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 type { InferenceRecord, WitnessPayload } from "./types.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 declare function extractPayloads(record: InferenceRecord, tenantId: string, clearingLevel: 0 | 1 | 2 | 3, latencyThresholdMs?: number, guardrailsRequired?: number, procedures?: string[]): WitnessPayload[];
20
+ //# sourceMappingURL=clearing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clearing.d.ts","sourceRoot":"","sources":["../src/clearing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAElE;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAC5B,kBAAkB,GAAE,MAAc,EAClC,kBAAkB,GAAE,MAAU,EAC9B,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,cAAc,EAAE,CA6FlB"}