opsveritas-sdk 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,47 @@
1
+ declare function init(apiKey: string, options?: {
2
+ endpoint?: string;
3
+ }): void;
4
+
5
+ declare function run<T>(agentName: string, fn: () => Promise<T>, opts?: {
6
+ userId?: string;
7
+ }): Promise<T>;
8
+
9
+ interface TraceOptions {
10
+ platform?: string;
11
+ userId?: string;
12
+ }
13
+ declare function trace<T>(agentName: string, fn: () => Promise<T>, options?: TraceOptions): Promise<T>;
14
+
15
+ interface WrapOptions {
16
+ agentName: string;
17
+ platform?: string;
18
+ userId?: string;
19
+ }
20
+ declare function wrap<T extends object>(client: T, opts: WrapOptions): T;
21
+
22
+ interface ExecutionPayload {
23
+ platform: string;
24
+ agent_name: string;
25
+ status: 'success' | 'failed' | 'timeout';
26
+ executed_at: string;
27
+ duration_ms?: number;
28
+ input_tokens?: number;
29
+ output_tokens?: number;
30
+ model?: string;
31
+ models?: string[];
32
+ tool_calls?: number;
33
+ cost_usd?: number;
34
+ total_tokens?: number;
35
+ error_message?: string | null;
36
+ user_id?: string;
37
+ output_summary?: string;
38
+ }
39
+
40
+ declare const OpsVeritas: {
41
+ init: typeof init;
42
+ run: typeof run;
43
+ trace: typeof trace;
44
+ wrap: typeof wrap;
45
+ };
46
+
47
+ export { type ExecutionPayload, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, run, trace, wrap };
@@ -0,0 +1,47 @@
1
+ declare function init(apiKey: string, options?: {
2
+ endpoint?: string;
3
+ }): void;
4
+
5
+ declare function run<T>(agentName: string, fn: () => Promise<T>, opts?: {
6
+ userId?: string;
7
+ }): Promise<T>;
8
+
9
+ interface TraceOptions {
10
+ platform?: string;
11
+ userId?: string;
12
+ }
13
+ declare function trace<T>(agentName: string, fn: () => Promise<T>, options?: TraceOptions): Promise<T>;
14
+
15
+ interface WrapOptions {
16
+ agentName: string;
17
+ platform?: string;
18
+ userId?: string;
19
+ }
20
+ declare function wrap<T extends object>(client: T, opts: WrapOptions): T;
21
+
22
+ interface ExecutionPayload {
23
+ platform: string;
24
+ agent_name: string;
25
+ status: 'success' | 'failed' | 'timeout';
26
+ executed_at: string;
27
+ duration_ms?: number;
28
+ input_tokens?: number;
29
+ output_tokens?: number;
30
+ model?: string;
31
+ models?: string[];
32
+ tool_calls?: number;
33
+ cost_usd?: number;
34
+ total_tokens?: number;
35
+ error_message?: string | null;
36
+ user_id?: string;
37
+ output_summary?: string;
38
+ }
39
+
40
+ declare const OpsVeritas: {
41
+ init: typeof init;
42
+ run: typeof run;
43
+ trace: typeof trace;
44
+ wrap: typeof wrap;
45
+ };
46
+
47
+ export { type ExecutionPayload, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, run, trace, wrap };
package/dist/index.js ADDED
@@ -0,0 +1,414 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ OpsVeritas: () => OpsVeritas,
24
+ default: () => index_default,
25
+ init: () => init,
26
+ run: () => run,
27
+ trace: () => trace,
28
+ wrap: () => wrap
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/config.ts
33
+ var _config = null;
34
+ function init(apiKey, options) {
35
+ if (!apiKey || typeof apiKey !== "string") throw new Error("[OpsVeritas] apiKey is required");
36
+ _config = {
37
+ apiKey,
38
+ endpoint: (options?.endpoint ?? "https://agents.opsveritas.com").replace(/\/$/, "")
39
+ };
40
+ }
41
+ function getConfig() {
42
+ if (!_config) throw new Error("[OpsVeritas] Call OpsVeritas.init(apiKey) before using the SDK");
43
+ return _config;
44
+ }
45
+
46
+ // src/context.ts
47
+ var import_async_hooks = require("async_hooks");
48
+
49
+ // src/http.ts
50
+ async function sendExecution(payload) {
51
+ const { apiKey, endpoint } = getConfig();
52
+ try {
53
+ await fetch(`${endpoint}/webhooks/agent-execution`, {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ "x-opsveritas-key": apiKey
58
+ },
59
+ body: JSON.stringify(payload)
60
+ });
61
+ } catch {
62
+ }
63
+ }
64
+
65
+ // src/context.ts
66
+ var storage = new import_async_hooks.AsyncLocalStorage();
67
+ function getActiveRun() {
68
+ return storage.getStore();
69
+ }
70
+ async function run(agentName, fn, opts) {
71
+ const ctx = {
72
+ agentName,
73
+ userId: opts?.userId,
74
+ startTime: Date.now(),
75
+ executedAt: (/* @__PURE__ */ new Date()).toISOString(),
76
+ calls: [],
77
+ status: "success"
78
+ };
79
+ return storage.run(ctx, async () => {
80
+ try {
81
+ return await fn();
82
+ } catch (err) {
83
+ ctx.status = "failed";
84
+ ctx.errorMessage = err instanceof Error ? err.message : String(err);
85
+ throw err;
86
+ } finally {
87
+ const durationMs = Date.now() - ctx.startTime;
88
+ const totalInput = ctx.calls.reduce((s, c) => s + (c.inputTokens ?? 0), 0);
89
+ const totalOutput = ctx.calls.reduce((s, c) => s + (c.outputTokens ?? 0), 0);
90
+ const totalCost = ctx.calls.reduce((s, c) => s + (c.costUsd ?? 0), 0);
91
+ const models = [...new Set(ctx.calls.map((c) => c.model).filter((m) => !!m))];
92
+ const platform = ctx.calls[0]?.platform ?? "custom_webhook";
93
+ const payload = {
94
+ platform,
95
+ agent_name: agentName,
96
+ status: ctx.status,
97
+ executed_at: ctx.executedAt,
98
+ duration_ms: durationMs,
99
+ error_message: ctx.errorMessage ?? null
100
+ };
101
+ if (totalInput) payload.input_tokens = totalInput;
102
+ if (totalOutput) payload.output_tokens = totalOutput;
103
+ if (totalCost) payload.cost_usd = Math.round(totalCost * 1e6) / 1e6;
104
+ if (models.length) payload.models = models;
105
+ if (ctx.userId) payload.user_id = ctx.userId;
106
+ void sendExecution(payload);
107
+ }
108
+ });
109
+ }
110
+
111
+ // src/pricing.ts
112
+ var PRICING = {
113
+ // ── OpenAI ─────────────────────────────────────────────────────────────────
114
+ // GPT-4.1 family (April 2025) — must be before 'gpt-4' to avoid wrong match
115
+ "gpt-4.1-nano": [0.1, 0.4],
116
+ "gpt-4.1-mini": [0.4, 1.6],
117
+ "gpt-4.1": [2, 8],
118
+ // GPT-4o
119
+ "gpt-4o-mini": [0.15, 0.6],
120
+ "gpt-4o": [2.5, 10],
121
+ // Legacy GPT-4
122
+ "gpt-4-turbo": [10, 30],
123
+ "gpt-4": [30, 60],
124
+ "gpt-3.5-turbo": [0.5, 1.5],
125
+ // Reasoning models
126
+ "o4-mini": [1.1, 4.4],
127
+ "o3-mini": [1.1, 4.4],
128
+ "o3": [10, 40],
129
+ "o1-mini": [3, 12],
130
+ "o1": [15, 60],
131
+ // ── Anthropic ──────────────────────────────────────────────────────────────
132
+ // Claude 4 family (versioned IDs matched by substring, e.g. claude-opus-4-8 → claude-opus-4)
133
+ "claude-opus-4": [15, 75],
134
+ "claude-sonnet-4": [3, 15],
135
+ "claude-haiku-4": [0.8, 4],
136
+ // Claude 3.7
137
+ "claude-3-7-sonnet": [3, 15],
138
+ // Claude 3.5
139
+ "claude-3-5-sonnet": [3, 15],
140
+ "claude-3-5-haiku": [0.8, 4],
141
+ // Claude 3
142
+ "claude-3-opus": [15, 75],
143
+ "claude-3-sonnet": [3, 15],
144
+ "claude-3-haiku": [0.25, 1.25],
145
+ // ── Groq ───────────────────────────────────────────────────────────────────
146
+ // New naming: llama-3.x-…
147
+ "llama-3.3-70b": [0.59, 0.79],
148
+ "llama-3.1-70b": [0.59, 0.79],
149
+ "llama-3.1-8b": [0.05, 0.08],
150
+ // Legacy naming: llama3-…
151
+ "llama3-70b": [0.59, 0.79],
152
+ "llama3-8b": [0.05, 0.08],
153
+ "mixtral-8x7b": [0.24, 0.24],
154
+ "gemma2-9b": [0.2, 0.2],
155
+ // ── Google Gemini ──────────────────────────────────────────────────────────
156
+ "gemini-2.5-pro": [1.25, 10],
157
+ "gemini-2.5-flash": [0.15, 0.6],
158
+ "gemini-2.0-flash": [0.1, 0.4],
159
+ "gemini-1.5-pro": [1.25, 5],
160
+ "gemini-1.5-flash": [0.075, 0.3]
161
+ };
162
+ function calcCost(model, inputTokens, outputTokens) {
163
+ const modelLower = model.toLowerCase();
164
+ const key = Object.keys(PRICING).find((k) => modelLower.includes(k) || k.includes(modelLower));
165
+ if (!key) return void 0;
166
+ const [inputRate, outputRate] = PRICING[key];
167
+ return Math.round((inputTokens * inputRate + outputTokens * outputRate) / 1e6 * 1e6) / 1e6;
168
+ }
169
+
170
+ // src/trace.ts
171
+ function extractUsage(result) {
172
+ if (!result || typeof result !== "object") return {};
173
+ const r = result;
174
+ if (r.usage && typeof r.usage === "object") {
175
+ const u = r.usage;
176
+ const model = typeof r.model === "string" ? r.model : void 0;
177
+ if (typeof u.prompt_tokens === "number") {
178
+ const toolCalls = Array.isArray(r.choices?.[0]?.message?.tool_calls) ? r.choices[0].message.tool_calls.length : void 0;
179
+ return {
180
+ model,
181
+ input_tokens: u.prompt_tokens,
182
+ output_tokens: typeof u.completion_tokens === "number" ? u.completion_tokens : 0,
183
+ tool_calls: toolCalls
184
+ };
185
+ }
186
+ if (typeof u.input_tokens === "number") {
187
+ const toolCalls = Array.isArray(r.content) ? r.content.filter((b) => b?.type === "tool_use").length || void 0 : void 0;
188
+ return {
189
+ model,
190
+ input_tokens: u.input_tokens,
191
+ output_tokens: typeof u.output_tokens === "number" ? u.output_tokens : 0,
192
+ tool_calls: toolCalls
193
+ };
194
+ }
195
+ }
196
+ if (r.response && typeof r.response === "object") {
197
+ const resp = r.response;
198
+ if (resp.usageMetadata && typeof resp.usageMetadata === "object") {
199
+ const um = resp.usageMetadata;
200
+ if (typeof um.promptTokenCount === "number") {
201
+ return {
202
+ model: typeof r.model === "string" ? r.model : void 0,
203
+ input_tokens: um.promptTokenCount,
204
+ output_tokens: typeof um.candidatesTokenCount === "number" ? um.candidatesTokenCount : 0
205
+ };
206
+ }
207
+ }
208
+ }
209
+ return {};
210
+ }
211
+ async function trace(agentName, fn, options) {
212
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
213
+ const t0 = Date.now();
214
+ let status = "success";
215
+ let errorMessage;
216
+ let result;
217
+ try {
218
+ result = await fn();
219
+ } catch (err) {
220
+ status = "failed";
221
+ errorMessage = err instanceof Error ? err.message : String(err);
222
+ throw err;
223
+ } finally {
224
+ const duration_ms = Date.now() - t0;
225
+ const usage = extractUsage(result);
226
+ const cost_usd = usage.model && usage.input_tokens != null && usage.output_tokens != null ? calcCost(usage.model, usage.input_tokens, usage.output_tokens) : void 0;
227
+ void sendExecution({
228
+ platform: options?.platform ?? "custom_webhook",
229
+ agent_name: agentName,
230
+ status,
231
+ executed_at: executedAt,
232
+ duration_ms,
233
+ error_message: errorMessage ?? null,
234
+ user_id: options?.userId,
235
+ ...usage,
236
+ ...cost_usd != null ? { cost_usd } : {}
237
+ });
238
+ }
239
+ return result;
240
+ }
241
+
242
+ // src/wrap.ts
243
+ var PATCHED = /* @__PURE__ */ Symbol("opsveritas.patched");
244
+ function patchOpenAI(client, opts) {
245
+ const completions = client.chat?.completions;
246
+ if (!completions || completions[PATCHED]) return;
247
+ const orig = completions.create.bind(completions);
248
+ completions.create = async function(...args) {
249
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
250
+ const t0 = Date.now();
251
+ let status = "success";
252
+ let errorMessage;
253
+ let resp;
254
+ try {
255
+ resp = await orig(...args);
256
+ } catch (err) {
257
+ status = "failed";
258
+ errorMessage = err instanceof Error ? err.message : String(err);
259
+ throw err;
260
+ } finally {
261
+ const duration_ms = Date.now() - t0;
262
+ const model = resp?.model ?? args[0]?.model;
263
+ const usage = resp?.usage;
264
+ const input_tokens = usage?.prompt_tokens;
265
+ const output_tokens = usage?.completion_tokens;
266
+ const toolCalls = Array.isArray(resp?.choices?.[0]?.message) ? void 0 : Array.isArray(
267
+ resp?.choices?.[0]?.message?.tool_calls
268
+ ) ? (resp?.choices?.[0]?.message?.tool_calls).length : void 0;
269
+ const cost_usd = model && input_tokens != null && output_tokens != null ? calcCost(String(model), input_tokens, output_tokens) : void 0;
270
+ const activeRun = getActiveRun();
271
+ if (activeRun) {
272
+ activeRun.calls.push({ platform: opts.platform ?? "custom_webhook", model: model ? String(model) : void 0, inputTokens: input_tokens, outputTokens: output_tokens, costUsd: cost_usd, status, errorMessage });
273
+ } else {
274
+ void sendExecution({
275
+ platform: opts.platform ?? "custom_webhook",
276
+ agent_name: opts.agentName,
277
+ status,
278
+ executed_at: executedAt,
279
+ duration_ms,
280
+ model: model ? String(model) : void 0,
281
+ input_tokens,
282
+ output_tokens,
283
+ tool_calls: toolCalls,
284
+ cost_usd,
285
+ error_message: errorMessage ?? null,
286
+ user_id: opts.userId
287
+ });
288
+ }
289
+ }
290
+ return resp;
291
+ };
292
+ completions[PATCHED] = true;
293
+ }
294
+ function patchAnthropic(client, opts) {
295
+ const messages = client.messages;
296
+ if (!messages || messages[PATCHED]) return;
297
+ const orig = messages.create.bind(messages);
298
+ messages.create = async function(...args) {
299
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
300
+ const t0 = Date.now();
301
+ let status = "success";
302
+ let errorMessage;
303
+ let resp;
304
+ try {
305
+ resp = await orig(...args);
306
+ } catch (err) {
307
+ status = "failed";
308
+ errorMessage = err instanceof Error ? err.message : String(err);
309
+ throw err;
310
+ } finally {
311
+ const duration_ms = Date.now() - t0;
312
+ const model = resp?.model ?? args[0]?.model;
313
+ const usage = resp?.usage;
314
+ const input_tokens = usage?.input_tokens;
315
+ const output_tokens = usage?.output_tokens;
316
+ const toolCalls = Array.isArray(resp?.content) ? resp.content.filter((b) => b?.type === "tool_use").length || void 0 : void 0;
317
+ const cost_usd = model && input_tokens != null && output_tokens != null ? calcCost(String(model), input_tokens, output_tokens) : void 0;
318
+ const activeRun = getActiveRun();
319
+ if (activeRun) {
320
+ activeRun.calls.push({ platform: opts.platform ?? "custom_webhook", model: model ? String(model) : void 0, inputTokens: input_tokens, outputTokens: output_tokens, costUsd: cost_usd, status, errorMessage });
321
+ } else {
322
+ void sendExecution({
323
+ platform: opts.platform ?? "custom_webhook",
324
+ agent_name: opts.agentName,
325
+ status,
326
+ executed_at: executedAt,
327
+ duration_ms,
328
+ model: model ? String(model) : void 0,
329
+ input_tokens,
330
+ output_tokens,
331
+ tool_calls: toolCalls,
332
+ cost_usd,
333
+ error_message: errorMessage ?? null,
334
+ user_id: opts.userId
335
+ });
336
+ }
337
+ }
338
+ return resp;
339
+ };
340
+ messages[PATCHED] = true;
341
+ }
342
+ function patchGemini(client, opts) {
343
+ if (client[PATCHED]) return;
344
+ const modelName = typeof client.model === "string" ? client.model.replace(/^models\//, "") : void 0;
345
+ const orig = client.generateContent.bind(client);
346
+ client.generateContent = async function(...args) {
347
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
348
+ const t0 = Date.now();
349
+ let status = "success";
350
+ let errorMessage;
351
+ let resp;
352
+ try {
353
+ resp = await orig(...args);
354
+ } catch (err) {
355
+ status = "failed";
356
+ errorMessage = err instanceof Error ? err.message : String(err);
357
+ throw err;
358
+ } finally {
359
+ const duration_ms = Date.now() - t0;
360
+ const um = resp?.response?.usageMetadata;
361
+ const input_tokens = typeof um?.promptTokenCount === "number" ? um.promptTokenCount : void 0;
362
+ const output_tokens = typeof um?.candidatesTokenCount === "number" ? um.candidatesTokenCount : void 0;
363
+ const cost_usd = modelName && input_tokens != null && output_tokens != null ? calcCost(modelName, input_tokens, output_tokens) : void 0;
364
+ const activeRun = getActiveRun();
365
+ if (activeRun) {
366
+ activeRun.calls.push({ platform: opts.platform ?? "custom_webhook", model: modelName, inputTokens: input_tokens, outputTokens: output_tokens, costUsd: cost_usd, status, errorMessage });
367
+ } else {
368
+ void sendExecution({
369
+ platform: opts.platform ?? "custom_webhook",
370
+ agent_name: opts.agentName,
371
+ status,
372
+ executed_at: executedAt,
373
+ duration_ms,
374
+ model: modelName,
375
+ input_tokens,
376
+ output_tokens,
377
+ cost_usd,
378
+ error_message: errorMessage ?? null,
379
+ user_id: opts.userId
380
+ });
381
+ }
382
+ }
383
+ return resp;
384
+ };
385
+ client[PATCHED] = true;
386
+ }
387
+ function wrap(client, opts) {
388
+ const c = client;
389
+ if (c.chat && typeof c.chat?.completions === "object") {
390
+ patchOpenAI(c, opts);
391
+ return client;
392
+ }
393
+ if (c.messages && typeof c.messages?.create === "function") {
394
+ patchAnthropic(c, opts);
395
+ return client;
396
+ }
397
+ if (typeof c.generateContent === "function") {
398
+ patchGemini(c, opts);
399
+ return client;
400
+ }
401
+ return client;
402
+ }
403
+
404
+ // src/index.ts
405
+ var OpsVeritas = { init, run, trace, wrap };
406
+ var index_default = OpsVeritas;
407
+ // Annotate the CommonJS export names for ESM import in node:
408
+ 0 && (module.exports = {
409
+ OpsVeritas,
410
+ init,
411
+ run,
412
+ trace,
413
+ wrap
414
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,383 @@
1
+ // src/config.ts
2
+ var _config = null;
3
+ function init(apiKey, options) {
4
+ if (!apiKey || typeof apiKey !== "string") throw new Error("[OpsVeritas] apiKey is required");
5
+ _config = {
6
+ apiKey,
7
+ endpoint: (options?.endpoint ?? "https://agents.opsveritas.com").replace(/\/$/, "")
8
+ };
9
+ }
10
+ function getConfig() {
11
+ if (!_config) throw new Error("[OpsVeritas] Call OpsVeritas.init(apiKey) before using the SDK");
12
+ return _config;
13
+ }
14
+
15
+ // src/context.ts
16
+ import { AsyncLocalStorage } from "async_hooks";
17
+
18
+ // src/http.ts
19
+ async function sendExecution(payload) {
20
+ const { apiKey, endpoint } = getConfig();
21
+ try {
22
+ await fetch(`${endpoint}/webhooks/agent-execution`, {
23
+ method: "POST",
24
+ headers: {
25
+ "Content-Type": "application/json",
26
+ "x-opsveritas-key": apiKey
27
+ },
28
+ body: JSON.stringify(payload)
29
+ });
30
+ } catch {
31
+ }
32
+ }
33
+
34
+ // src/context.ts
35
+ var storage = new AsyncLocalStorage();
36
+ function getActiveRun() {
37
+ return storage.getStore();
38
+ }
39
+ async function run(agentName, fn, opts) {
40
+ const ctx = {
41
+ agentName,
42
+ userId: opts?.userId,
43
+ startTime: Date.now(),
44
+ executedAt: (/* @__PURE__ */ new Date()).toISOString(),
45
+ calls: [],
46
+ status: "success"
47
+ };
48
+ return storage.run(ctx, async () => {
49
+ try {
50
+ return await fn();
51
+ } catch (err) {
52
+ ctx.status = "failed";
53
+ ctx.errorMessage = err instanceof Error ? err.message : String(err);
54
+ throw err;
55
+ } finally {
56
+ const durationMs = Date.now() - ctx.startTime;
57
+ const totalInput = ctx.calls.reduce((s, c) => s + (c.inputTokens ?? 0), 0);
58
+ const totalOutput = ctx.calls.reduce((s, c) => s + (c.outputTokens ?? 0), 0);
59
+ const totalCost = ctx.calls.reduce((s, c) => s + (c.costUsd ?? 0), 0);
60
+ const models = [...new Set(ctx.calls.map((c) => c.model).filter((m) => !!m))];
61
+ const platform = ctx.calls[0]?.platform ?? "custom_webhook";
62
+ const payload = {
63
+ platform,
64
+ agent_name: agentName,
65
+ status: ctx.status,
66
+ executed_at: ctx.executedAt,
67
+ duration_ms: durationMs,
68
+ error_message: ctx.errorMessage ?? null
69
+ };
70
+ if (totalInput) payload.input_tokens = totalInput;
71
+ if (totalOutput) payload.output_tokens = totalOutput;
72
+ if (totalCost) payload.cost_usd = Math.round(totalCost * 1e6) / 1e6;
73
+ if (models.length) payload.models = models;
74
+ if (ctx.userId) payload.user_id = ctx.userId;
75
+ void sendExecution(payload);
76
+ }
77
+ });
78
+ }
79
+
80
+ // src/pricing.ts
81
+ var PRICING = {
82
+ // ── OpenAI ─────────────────────────────────────────────────────────────────
83
+ // GPT-4.1 family (April 2025) — must be before 'gpt-4' to avoid wrong match
84
+ "gpt-4.1-nano": [0.1, 0.4],
85
+ "gpt-4.1-mini": [0.4, 1.6],
86
+ "gpt-4.1": [2, 8],
87
+ // GPT-4o
88
+ "gpt-4o-mini": [0.15, 0.6],
89
+ "gpt-4o": [2.5, 10],
90
+ // Legacy GPT-4
91
+ "gpt-4-turbo": [10, 30],
92
+ "gpt-4": [30, 60],
93
+ "gpt-3.5-turbo": [0.5, 1.5],
94
+ // Reasoning models
95
+ "o4-mini": [1.1, 4.4],
96
+ "o3-mini": [1.1, 4.4],
97
+ "o3": [10, 40],
98
+ "o1-mini": [3, 12],
99
+ "o1": [15, 60],
100
+ // ── Anthropic ──────────────────────────────────────────────────────────────
101
+ // Claude 4 family (versioned IDs matched by substring, e.g. claude-opus-4-8 → claude-opus-4)
102
+ "claude-opus-4": [15, 75],
103
+ "claude-sonnet-4": [3, 15],
104
+ "claude-haiku-4": [0.8, 4],
105
+ // Claude 3.7
106
+ "claude-3-7-sonnet": [3, 15],
107
+ // Claude 3.5
108
+ "claude-3-5-sonnet": [3, 15],
109
+ "claude-3-5-haiku": [0.8, 4],
110
+ // Claude 3
111
+ "claude-3-opus": [15, 75],
112
+ "claude-3-sonnet": [3, 15],
113
+ "claude-3-haiku": [0.25, 1.25],
114
+ // ── Groq ───────────────────────────────────────────────────────────────────
115
+ // New naming: llama-3.x-…
116
+ "llama-3.3-70b": [0.59, 0.79],
117
+ "llama-3.1-70b": [0.59, 0.79],
118
+ "llama-3.1-8b": [0.05, 0.08],
119
+ // Legacy naming: llama3-…
120
+ "llama3-70b": [0.59, 0.79],
121
+ "llama3-8b": [0.05, 0.08],
122
+ "mixtral-8x7b": [0.24, 0.24],
123
+ "gemma2-9b": [0.2, 0.2],
124
+ // ── Google Gemini ──────────────────────────────────────────────────────────
125
+ "gemini-2.5-pro": [1.25, 10],
126
+ "gemini-2.5-flash": [0.15, 0.6],
127
+ "gemini-2.0-flash": [0.1, 0.4],
128
+ "gemini-1.5-pro": [1.25, 5],
129
+ "gemini-1.5-flash": [0.075, 0.3]
130
+ };
131
+ function calcCost(model, inputTokens, outputTokens) {
132
+ const modelLower = model.toLowerCase();
133
+ const key = Object.keys(PRICING).find((k) => modelLower.includes(k) || k.includes(modelLower));
134
+ if (!key) return void 0;
135
+ const [inputRate, outputRate] = PRICING[key];
136
+ return Math.round((inputTokens * inputRate + outputTokens * outputRate) / 1e6 * 1e6) / 1e6;
137
+ }
138
+
139
+ // src/trace.ts
140
+ function extractUsage(result) {
141
+ if (!result || typeof result !== "object") return {};
142
+ const r = result;
143
+ if (r.usage && typeof r.usage === "object") {
144
+ const u = r.usage;
145
+ const model = typeof r.model === "string" ? r.model : void 0;
146
+ if (typeof u.prompt_tokens === "number") {
147
+ const toolCalls = Array.isArray(r.choices?.[0]?.message?.tool_calls) ? r.choices[0].message.tool_calls.length : void 0;
148
+ return {
149
+ model,
150
+ input_tokens: u.prompt_tokens,
151
+ output_tokens: typeof u.completion_tokens === "number" ? u.completion_tokens : 0,
152
+ tool_calls: toolCalls
153
+ };
154
+ }
155
+ if (typeof u.input_tokens === "number") {
156
+ const toolCalls = Array.isArray(r.content) ? r.content.filter((b) => b?.type === "tool_use").length || void 0 : void 0;
157
+ return {
158
+ model,
159
+ input_tokens: u.input_tokens,
160
+ output_tokens: typeof u.output_tokens === "number" ? u.output_tokens : 0,
161
+ tool_calls: toolCalls
162
+ };
163
+ }
164
+ }
165
+ if (r.response && typeof r.response === "object") {
166
+ const resp = r.response;
167
+ if (resp.usageMetadata && typeof resp.usageMetadata === "object") {
168
+ const um = resp.usageMetadata;
169
+ if (typeof um.promptTokenCount === "number") {
170
+ return {
171
+ model: typeof r.model === "string" ? r.model : void 0,
172
+ input_tokens: um.promptTokenCount,
173
+ output_tokens: typeof um.candidatesTokenCount === "number" ? um.candidatesTokenCount : 0
174
+ };
175
+ }
176
+ }
177
+ }
178
+ return {};
179
+ }
180
+ async function trace(agentName, fn, options) {
181
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
182
+ const t0 = Date.now();
183
+ let status = "success";
184
+ let errorMessage;
185
+ let result;
186
+ try {
187
+ result = await fn();
188
+ } catch (err) {
189
+ status = "failed";
190
+ errorMessage = err instanceof Error ? err.message : String(err);
191
+ throw err;
192
+ } finally {
193
+ const duration_ms = Date.now() - t0;
194
+ const usage = extractUsage(result);
195
+ const cost_usd = usage.model && usage.input_tokens != null && usage.output_tokens != null ? calcCost(usage.model, usage.input_tokens, usage.output_tokens) : void 0;
196
+ void sendExecution({
197
+ platform: options?.platform ?? "custom_webhook",
198
+ agent_name: agentName,
199
+ status,
200
+ executed_at: executedAt,
201
+ duration_ms,
202
+ error_message: errorMessage ?? null,
203
+ user_id: options?.userId,
204
+ ...usage,
205
+ ...cost_usd != null ? { cost_usd } : {}
206
+ });
207
+ }
208
+ return result;
209
+ }
210
+
211
+ // src/wrap.ts
212
+ var PATCHED = /* @__PURE__ */ Symbol("opsveritas.patched");
213
+ function patchOpenAI(client, opts) {
214
+ const completions = client.chat?.completions;
215
+ if (!completions || completions[PATCHED]) return;
216
+ const orig = completions.create.bind(completions);
217
+ completions.create = async function(...args) {
218
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
219
+ const t0 = Date.now();
220
+ let status = "success";
221
+ let errorMessage;
222
+ let resp;
223
+ try {
224
+ resp = await orig(...args);
225
+ } catch (err) {
226
+ status = "failed";
227
+ errorMessage = err instanceof Error ? err.message : String(err);
228
+ throw err;
229
+ } finally {
230
+ const duration_ms = Date.now() - t0;
231
+ const model = resp?.model ?? args[0]?.model;
232
+ const usage = resp?.usage;
233
+ const input_tokens = usage?.prompt_tokens;
234
+ const output_tokens = usage?.completion_tokens;
235
+ const toolCalls = Array.isArray(resp?.choices?.[0]?.message) ? void 0 : Array.isArray(
236
+ resp?.choices?.[0]?.message?.tool_calls
237
+ ) ? (resp?.choices?.[0]?.message?.tool_calls).length : void 0;
238
+ const cost_usd = model && input_tokens != null && output_tokens != null ? calcCost(String(model), input_tokens, output_tokens) : void 0;
239
+ const activeRun = getActiveRun();
240
+ if (activeRun) {
241
+ activeRun.calls.push({ platform: opts.platform ?? "custom_webhook", model: model ? String(model) : void 0, inputTokens: input_tokens, outputTokens: output_tokens, costUsd: cost_usd, status, errorMessage });
242
+ } else {
243
+ void sendExecution({
244
+ platform: opts.platform ?? "custom_webhook",
245
+ agent_name: opts.agentName,
246
+ status,
247
+ executed_at: executedAt,
248
+ duration_ms,
249
+ model: model ? String(model) : void 0,
250
+ input_tokens,
251
+ output_tokens,
252
+ tool_calls: toolCalls,
253
+ cost_usd,
254
+ error_message: errorMessage ?? null,
255
+ user_id: opts.userId
256
+ });
257
+ }
258
+ }
259
+ return resp;
260
+ };
261
+ completions[PATCHED] = true;
262
+ }
263
+ function patchAnthropic(client, opts) {
264
+ const messages = client.messages;
265
+ if (!messages || messages[PATCHED]) return;
266
+ const orig = messages.create.bind(messages);
267
+ messages.create = async function(...args) {
268
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
269
+ const t0 = Date.now();
270
+ let status = "success";
271
+ let errorMessage;
272
+ let resp;
273
+ try {
274
+ resp = await orig(...args);
275
+ } catch (err) {
276
+ status = "failed";
277
+ errorMessage = err instanceof Error ? err.message : String(err);
278
+ throw err;
279
+ } finally {
280
+ const duration_ms = Date.now() - t0;
281
+ const model = resp?.model ?? args[0]?.model;
282
+ const usage = resp?.usage;
283
+ const input_tokens = usage?.input_tokens;
284
+ const output_tokens = usage?.output_tokens;
285
+ const toolCalls = Array.isArray(resp?.content) ? resp.content.filter((b) => b?.type === "tool_use").length || void 0 : void 0;
286
+ const cost_usd = model && input_tokens != null && output_tokens != null ? calcCost(String(model), input_tokens, output_tokens) : void 0;
287
+ const activeRun = getActiveRun();
288
+ if (activeRun) {
289
+ activeRun.calls.push({ platform: opts.platform ?? "custom_webhook", model: model ? String(model) : void 0, inputTokens: input_tokens, outputTokens: output_tokens, costUsd: cost_usd, status, errorMessage });
290
+ } else {
291
+ void sendExecution({
292
+ platform: opts.platform ?? "custom_webhook",
293
+ agent_name: opts.agentName,
294
+ status,
295
+ executed_at: executedAt,
296
+ duration_ms,
297
+ model: model ? String(model) : void 0,
298
+ input_tokens,
299
+ output_tokens,
300
+ tool_calls: toolCalls,
301
+ cost_usd,
302
+ error_message: errorMessage ?? null,
303
+ user_id: opts.userId
304
+ });
305
+ }
306
+ }
307
+ return resp;
308
+ };
309
+ messages[PATCHED] = true;
310
+ }
311
+ function patchGemini(client, opts) {
312
+ if (client[PATCHED]) return;
313
+ const modelName = typeof client.model === "string" ? client.model.replace(/^models\//, "") : void 0;
314
+ const orig = client.generateContent.bind(client);
315
+ client.generateContent = async function(...args) {
316
+ const executedAt = (/* @__PURE__ */ new Date()).toISOString();
317
+ const t0 = Date.now();
318
+ let status = "success";
319
+ let errorMessage;
320
+ let resp;
321
+ try {
322
+ resp = await orig(...args);
323
+ } catch (err) {
324
+ status = "failed";
325
+ errorMessage = err instanceof Error ? err.message : String(err);
326
+ throw err;
327
+ } finally {
328
+ const duration_ms = Date.now() - t0;
329
+ const um = resp?.response?.usageMetadata;
330
+ const input_tokens = typeof um?.promptTokenCount === "number" ? um.promptTokenCount : void 0;
331
+ const output_tokens = typeof um?.candidatesTokenCount === "number" ? um.candidatesTokenCount : void 0;
332
+ const cost_usd = modelName && input_tokens != null && output_tokens != null ? calcCost(modelName, input_tokens, output_tokens) : void 0;
333
+ const activeRun = getActiveRun();
334
+ if (activeRun) {
335
+ activeRun.calls.push({ platform: opts.platform ?? "custom_webhook", model: modelName, inputTokens: input_tokens, outputTokens: output_tokens, costUsd: cost_usd, status, errorMessage });
336
+ } else {
337
+ void sendExecution({
338
+ platform: opts.platform ?? "custom_webhook",
339
+ agent_name: opts.agentName,
340
+ status,
341
+ executed_at: executedAt,
342
+ duration_ms,
343
+ model: modelName,
344
+ input_tokens,
345
+ output_tokens,
346
+ cost_usd,
347
+ error_message: errorMessage ?? null,
348
+ user_id: opts.userId
349
+ });
350
+ }
351
+ }
352
+ return resp;
353
+ };
354
+ client[PATCHED] = true;
355
+ }
356
+ function wrap(client, opts) {
357
+ const c = client;
358
+ if (c.chat && typeof c.chat?.completions === "object") {
359
+ patchOpenAI(c, opts);
360
+ return client;
361
+ }
362
+ if (c.messages && typeof c.messages?.create === "function") {
363
+ patchAnthropic(c, opts);
364
+ return client;
365
+ }
366
+ if (typeof c.generateContent === "function") {
367
+ patchGemini(c, opts);
368
+ return client;
369
+ }
370
+ return client;
371
+ }
372
+
373
+ // src/index.ts
374
+ var OpsVeritas = { init, run, trace, wrap };
375
+ var index_default = OpsVeritas;
376
+ export {
377
+ OpsVeritas,
378
+ index_default as default,
379
+ init,
380
+ run,
381
+ trace,
382
+ wrap
383
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "opsveritas-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Monitor your AI agents with 2 lines of code",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.cjs",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": ["dist"],
16
+ "scripts": {
17
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean",
18
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
19
+ "test": "jest"
20
+ },
21
+ "devDependencies": {
22
+ "@types/jest": "^29.5.12",
23
+ "@types/node": "^20.14.0",
24
+ "jest": "^29.7.0",
25
+ "ts-jest": "^29.1.5",
26
+ "tsup": "^8.1.0",
27
+ "typescript": "^5.4.5"
28
+ },
29
+ "peerDependencies": {
30
+ "@anthropic-ai/sdk": ">=0.20.0",
31
+ "openai": ">=4.0.0"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "@anthropic-ai/sdk": { "optional": true },
35
+ "openai": { "optional": true }
36
+ },
37
+ "keywords": ["ai", "agents", "monitoring", "observability", "openai", "anthropic", "langchain"],
38
+ "license": "MIT"
39
+ }