opsveritas-sdk 0.2.0 → 0.3.1
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 +79 -65
- package/dist/index.d.mts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +111 -3
- package/dist/index.mjs +110 -3
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,65 +1,79 @@
|
|
|
1
|
-
# opsveritas-sdk
|
|
2
|
-
|
|
3
|
-
Monitor your AI agents in **three lines of code**. Tracks tokens, cost, latency, model, and silent failures (200 OK with empty output) — and routes alerts to Slack / Email / Teams via [OpsVeritas AI Agents Control Tower](https://agents.opsveritas.com).
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npm install opsveritas-sdk
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
## Quick start (3 lines)
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import { OpsVeritas } from 'opsveritas-sdk';
|
|
13
|
-
|
|
14
|
-
OpsVeritas.init('<your-ingest-key>'); // key from Settings → Integrations
|
|
15
|
-
const client = OpsVeritas.wrap(new OpenAI(), { agentName: 'Support Bot' });
|
|
16
|
-
// use `client` exactly as before — runs appear in your dashboard automatically
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Works the same for Anthropic and Gemini clients. Prefer manual control? Wrap a function:
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
await OpsVeritas.trace('Nightly Report', async () => runReport());
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
##
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
# opsveritas-sdk
|
|
2
|
+
|
|
3
|
+
Monitor your AI agents in **three lines of code**. Tracks tokens, cost, latency, model, and silent failures (200 OK with empty output) — and routes alerts to Slack / Email / Teams via [OpsVeritas AI Agents Control Tower](https://agents.opsveritas.com).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install opsveritas-sdk
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Quick start (3 lines)
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { OpsVeritas } from 'opsveritas-sdk';
|
|
13
|
+
|
|
14
|
+
OpsVeritas.init('<your-ingest-key>'); // key from Settings → Integrations
|
|
15
|
+
const client = OpsVeritas.wrap(new OpenAI(), { agentName: 'Support Bot' });
|
|
16
|
+
// use `client` exactly as before — runs appear in your dashboard automatically
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Works the same for Anthropic and Gemini clients. Prefer manual control? Wrap a function:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
await OpsVeritas.trace('Nightly Report', async () => runReport());
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## LangChain (one line)
|
|
26
|
+
|
|
27
|
+
Attach the handler to any LangChain chat model, LLM or chain — every call reports token / cost / latency / silent-failure automatically:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
31
|
+
import { OpsVeritas } from 'opsveritas-sdk';
|
|
32
|
+
|
|
33
|
+
OpsVeritas.init('<your-ingest-key>');
|
|
34
|
+
const model = new ChatOpenAI({ callbacks: [OpsVeritas.langchain('My Agent')] });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
No extra dependency — it's a plain LangChain callback handler. Works with any LangChain-backed provider (OpenAI, Anthropic, Gemini, Groq…). Inside `OpsVeritas.run(...)` the handler aggregates into a single execution instead of double-counting.
|
|
38
|
+
|
|
39
|
+
## What data is sent
|
|
40
|
+
|
|
41
|
+
By design the SDK sends **metadata only, plus a short output snippet** — never your prompts/inputs:
|
|
42
|
+
|
|
43
|
+
| Sent | Detail |
|
|
44
|
+
|------|--------|
|
|
45
|
+
| ✅ Metadata | agent name, status, timestamps, duration, token counts, model, cost, tool-call count |
|
|
46
|
+
| ⚠️ Output snippet | first 300 chars of the response (`output_summary`) — powers silent-failure detection |
|
|
47
|
+
| ⚠️ Error message | the exception text, if a call fails |
|
|
48
|
+
| ❌ Prompts / inputs | **never sent** — only token counts |
|
|
49
|
+
|
|
50
|
+
### Metadata-only mode (for regulated / client data)
|
|
51
|
+
|
|
52
|
+
Drop the output snippet and redact error text so **no response content ever leaves your environment** — token/cost/latency metadata still flows:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
OpsVeritas.init('<your-ingest-key>', { metadataOnly: true });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or set the environment variable:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
OPSVERITAS_METADATA_ONLY=true
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Reliability
|
|
65
|
+
|
|
66
|
+
Telemetry is **non-blocking and fire-and-forget** — it never throws into your code and never slows your agent. If the ingest endpoint is briefly unreachable, sends are **retried with backoff** and **buffered in memory** (bounded), then flushed on the next event — so a transient outage doesn't lose telemetry.
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
OpsVeritas.init(apiKey, {
|
|
72
|
+
endpoint, // optional — defaults to https://agents.opsveritas.com
|
|
73
|
+
metadataOnly, // optional — default false; when true, no response content is sent
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -20,6 +20,26 @@ interface WrapOptions {
|
|
|
20
20
|
}
|
|
21
21
|
declare function wrap<T extends object>(client: T, opts: WrapOptions): T;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* LangChain integration — one-line callback handler.
|
|
25
|
+
*
|
|
26
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
27
|
+
* import opsveritas from 'opsveritas-sdk';
|
|
28
|
+
*
|
|
29
|
+
* opsveritas.init('<key>');
|
|
30
|
+
* const model = new ChatOpenAI({ callbacks: [opsveritas.langchain('My Agent')] });
|
|
31
|
+
* // every LLM call now reports token / cost / latency / silent-failure to OpsVeritas
|
|
32
|
+
*
|
|
33
|
+
* Returns a plain CallbackHandlerMethods object — LangChain.js accepts this shape
|
|
34
|
+
* directly in the `callbacks` array, so there's no @langchain/core dependency.
|
|
35
|
+
* Reuses the same ingest, pricing and silent-failure semantics as wrap()/run().
|
|
36
|
+
*/
|
|
37
|
+
interface LangChainOptions {
|
|
38
|
+
platform?: string;
|
|
39
|
+
userId?: string;
|
|
40
|
+
}
|
|
41
|
+
declare function langchain(agentName: string, opts?: LangChainOptions): Record<string, unknown>;
|
|
42
|
+
|
|
23
43
|
interface ExecutionPayload {
|
|
24
44
|
platform: string;
|
|
25
45
|
agent_name: string;
|
|
@@ -43,6 +63,7 @@ declare const OpsVeritas: {
|
|
|
43
63
|
run: typeof run;
|
|
44
64
|
trace: typeof trace;
|
|
45
65
|
wrap: typeof wrap;
|
|
66
|
+
langchain: typeof langchain;
|
|
46
67
|
};
|
|
47
68
|
|
|
48
|
-
export { type ExecutionPayload, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, run, trace, wrap };
|
|
69
|
+
export { type ExecutionPayload, type LangChainOptions, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, langchain, run, trace, wrap };
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,26 @@ interface WrapOptions {
|
|
|
20
20
|
}
|
|
21
21
|
declare function wrap<T extends object>(client: T, opts: WrapOptions): T;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* LangChain integration — one-line callback handler.
|
|
25
|
+
*
|
|
26
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
27
|
+
* import opsveritas from 'opsveritas-sdk';
|
|
28
|
+
*
|
|
29
|
+
* opsveritas.init('<key>');
|
|
30
|
+
* const model = new ChatOpenAI({ callbacks: [opsveritas.langchain('My Agent')] });
|
|
31
|
+
* // every LLM call now reports token / cost / latency / silent-failure to OpsVeritas
|
|
32
|
+
*
|
|
33
|
+
* Returns a plain CallbackHandlerMethods object — LangChain.js accepts this shape
|
|
34
|
+
* directly in the `callbacks` array, so there's no @langchain/core dependency.
|
|
35
|
+
* Reuses the same ingest, pricing and silent-failure semantics as wrap()/run().
|
|
36
|
+
*/
|
|
37
|
+
interface LangChainOptions {
|
|
38
|
+
platform?: string;
|
|
39
|
+
userId?: string;
|
|
40
|
+
}
|
|
41
|
+
declare function langchain(agentName: string, opts?: LangChainOptions): Record<string, unknown>;
|
|
42
|
+
|
|
23
43
|
interface ExecutionPayload {
|
|
24
44
|
platform: string;
|
|
25
45
|
agent_name: string;
|
|
@@ -43,6 +63,7 @@ declare const OpsVeritas: {
|
|
|
43
63
|
run: typeof run;
|
|
44
64
|
trace: typeof trace;
|
|
45
65
|
wrap: typeof wrap;
|
|
66
|
+
langchain: typeof langchain;
|
|
46
67
|
};
|
|
47
68
|
|
|
48
|
-
export { type ExecutionPayload, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, run, trace, wrap };
|
|
69
|
+
export { type ExecutionPayload, type LangChainOptions, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, langchain, run, trace, wrap };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
OpsVeritas: () => OpsVeritas,
|
|
24
24
|
default: () => index_default,
|
|
25
25
|
init: () => init,
|
|
26
|
+
langchain: () => langchain,
|
|
26
27
|
run: () => run,
|
|
27
28
|
trace: () => trace,
|
|
28
29
|
wrap: () => wrap
|
|
@@ -355,17 +356,18 @@ async function trace(agentName, fn, options) {
|
|
|
355
356
|
|
|
356
357
|
// src/wrap.ts
|
|
357
358
|
var PATCHED = /* @__PURE__ */ Symbol("opsveritas.patched");
|
|
359
|
+
var OUTPUT_SUMMARY_MAX = 3e3;
|
|
358
360
|
function extractOutput(resp) {
|
|
359
361
|
if (!resp) return void 0;
|
|
360
362
|
const choices = resp.choices;
|
|
361
363
|
if (Array.isArray(choices) && choices[0]) {
|
|
362
364
|
const content = choices[0].message?.content;
|
|
363
|
-
if (typeof content === "string" && content.trim()) return content.slice(0,
|
|
365
|
+
if (typeof content === "string" && content.trim()) return content.slice(0, OUTPUT_SUMMARY_MAX);
|
|
364
366
|
}
|
|
365
367
|
const blocks = resp.content;
|
|
366
368
|
if (Array.isArray(blocks)) {
|
|
367
369
|
const tb = blocks.find((b) => b.type === "text");
|
|
368
|
-
if (typeof tb?.text === "string" && tb.text.trim()) return tb.text.slice(0,
|
|
370
|
+
if (typeof tb?.text === "string" && tb.text.trim()) return tb.text.slice(0, OUTPUT_SUMMARY_MAX);
|
|
369
371
|
}
|
|
370
372
|
return void 0;
|
|
371
373
|
}
|
|
@@ -532,13 +534,119 @@ function wrap(client, opts) {
|
|
|
532
534
|
return client;
|
|
533
535
|
}
|
|
534
536
|
|
|
537
|
+
// src/langchain.ts
|
|
538
|
+
function extractUsage2(output) {
|
|
539
|
+
let model;
|
|
540
|
+
let inputTokens;
|
|
541
|
+
let outputTokens;
|
|
542
|
+
const lo = output?.llmOutput;
|
|
543
|
+
if (lo && typeof lo === "object") {
|
|
544
|
+
const tu = lo.tokenUsage ?? lo.token_usage ?? lo.usage;
|
|
545
|
+
if (tu && typeof tu === "object") {
|
|
546
|
+
inputTokens = tu.promptTokens ?? tu.prompt_tokens ?? tu.inputTokens ?? tu.input_tokens;
|
|
547
|
+
outputTokens = tu.completionTokens ?? tu.completion_tokens ?? tu.outputTokens ?? tu.output_tokens;
|
|
548
|
+
}
|
|
549
|
+
model = lo.model_name ?? lo.modelName ?? lo.model;
|
|
550
|
+
}
|
|
551
|
+
if (inputTokens == null || !model) {
|
|
552
|
+
try {
|
|
553
|
+
for (const genList of output?.generations ?? []) {
|
|
554
|
+
for (const gen of genList) {
|
|
555
|
+
const msg = gen?.message;
|
|
556
|
+
const um = msg?.usage_metadata ?? msg?.usageMetadata;
|
|
557
|
+
if (um && inputTokens == null) {
|
|
558
|
+
inputTokens = um.input_tokens ?? um.inputTokens;
|
|
559
|
+
outputTokens = um.output_tokens ?? um.outputTokens;
|
|
560
|
+
}
|
|
561
|
+
const rm = msg?.response_metadata ?? msg?.responseMetadata;
|
|
562
|
+
if (rm && !model) model = rm.model_name ?? rm.modelName ?? rm.model;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
} catch {
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return { model: model != null ? String(model) : void 0, inputTokens, outputTokens };
|
|
569
|
+
}
|
|
570
|
+
function extractText(output) {
|
|
571
|
+
try {
|
|
572
|
+
for (const genList of output?.generations ?? []) {
|
|
573
|
+
for (const gen of genList) {
|
|
574
|
+
let t = gen?.text;
|
|
575
|
+
if (!t) {
|
|
576
|
+
const c = gen?.message?.content;
|
|
577
|
+
if (typeof c === "string") t = c;
|
|
578
|
+
}
|
|
579
|
+
if (typeof t === "string" && t.trim()) return t.slice(0, 3e3);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
} catch {
|
|
583
|
+
}
|
|
584
|
+
return void 0;
|
|
585
|
+
}
|
|
586
|
+
function langchain(agentName, opts = {}) {
|
|
587
|
+
const platform = opts.platform ?? "sdk";
|
|
588
|
+
const starts = /* @__PURE__ */ new Map();
|
|
589
|
+
const begin = (runId) => {
|
|
590
|
+
starts.set(runId, { t0: Date.now(), executedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
591
|
+
};
|
|
592
|
+
const finish = (status, output, errorMessage, runId) => {
|
|
593
|
+
const s = starts.get(runId);
|
|
594
|
+
starts.delete(runId);
|
|
595
|
+
const duration_ms = s ? Date.now() - s.t0 : 0;
|
|
596
|
+
const executed_at = s?.executedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
597
|
+
const { model, inputTokens, outputTokens } = output ? extractUsage2(output) : {};
|
|
598
|
+
const cost_usd = model && inputTokens != null && outputTokens != null ? calcCost(model, inputTokens, outputTokens) : void 0;
|
|
599
|
+
const activeRun = getActiveRun();
|
|
600
|
+
if (activeRun) {
|
|
601
|
+
activeRun.calls.push({ platform, model, inputTokens, outputTokens, costUsd: cost_usd, status });
|
|
602
|
+
} else {
|
|
603
|
+
void sendExecution({
|
|
604
|
+
platform,
|
|
605
|
+
agent_name: agentName,
|
|
606
|
+
status,
|
|
607
|
+
executed_at,
|
|
608
|
+
duration_ms,
|
|
609
|
+
model,
|
|
610
|
+
input_tokens: inputTokens,
|
|
611
|
+
output_tokens: outputTokens,
|
|
612
|
+
cost_usd,
|
|
613
|
+
error_message: errorMessage ?? null,
|
|
614
|
+
output_summary: output ? extractText(output) : void 0,
|
|
615
|
+
user_id: opts.userId
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
return {
|
|
620
|
+
name: "opsveritas",
|
|
621
|
+
handleLLMStart(_llm, _prompts, runId) {
|
|
622
|
+
begin(runId);
|
|
623
|
+
},
|
|
624
|
+
handleChatModelStart(_llm, _messages, runId) {
|
|
625
|
+
begin(runId);
|
|
626
|
+
},
|
|
627
|
+
handleLLMEnd(output, runId) {
|
|
628
|
+
try {
|
|
629
|
+
finish("success", output, void 0, runId);
|
|
630
|
+
} catch {
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
handleLLMError(err, runId) {
|
|
634
|
+
try {
|
|
635
|
+
finish("failed", void 0, err instanceof Error ? err.message : String(err), runId);
|
|
636
|
+
} catch {
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
|
|
535
642
|
// src/index.ts
|
|
536
|
-
var OpsVeritas = { init, run, trace, wrap };
|
|
643
|
+
var OpsVeritas = { init, run, trace, wrap, langchain };
|
|
537
644
|
var index_default = OpsVeritas;
|
|
538
645
|
// Annotate the CommonJS export names for ESM import in node:
|
|
539
646
|
0 && (module.exports = {
|
|
540
647
|
OpsVeritas,
|
|
541
648
|
init,
|
|
649
|
+
langchain,
|
|
542
650
|
run,
|
|
543
651
|
trace,
|
|
544
652
|
wrap
|
package/dist/index.mjs
CHANGED
|
@@ -324,17 +324,18 @@ async function trace(agentName, fn, options) {
|
|
|
324
324
|
|
|
325
325
|
// src/wrap.ts
|
|
326
326
|
var PATCHED = /* @__PURE__ */ Symbol("opsveritas.patched");
|
|
327
|
+
var OUTPUT_SUMMARY_MAX = 3e3;
|
|
327
328
|
function extractOutput(resp) {
|
|
328
329
|
if (!resp) return void 0;
|
|
329
330
|
const choices = resp.choices;
|
|
330
331
|
if (Array.isArray(choices) && choices[0]) {
|
|
331
332
|
const content = choices[0].message?.content;
|
|
332
|
-
if (typeof content === "string" && content.trim()) return content.slice(0,
|
|
333
|
+
if (typeof content === "string" && content.trim()) return content.slice(0, OUTPUT_SUMMARY_MAX);
|
|
333
334
|
}
|
|
334
335
|
const blocks = resp.content;
|
|
335
336
|
if (Array.isArray(blocks)) {
|
|
336
337
|
const tb = blocks.find((b) => b.type === "text");
|
|
337
|
-
if (typeof tb?.text === "string" && tb.text.trim()) return tb.text.slice(0,
|
|
338
|
+
if (typeof tb?.text === "string" && tb.text.trim()) return tb.text.slice(0, OUTPUT_SUMMARY_MAX);
|
|
338
339
|
}
|
|
339
340
|
return void 0;
|
|
340
341
|
}
|
|
@@ -501,13 +502,119 @@ function wrap(client, opts) {
|
|
|
501
502
|
return client;
|
|
502
503
|
}
|
|
503
504
|
|
|
505
|
+
// src/langchain.ts
|
|
506
|
+
function extractUsage2(output) {
|
|
507
|
+
let model;
|
|
508
|
+
let inputTokens;
|
|
509
|
+
let outputTokens;
|
|
510
|
+
const lo = output?.llmOutput;
|
|
511
|
+
if (lo && typeof lo === "object") {
|
|
512
|
+
const tu = lo.tokenUsage ?? lo.token_usage ?? lo.usage;
|
|
513
|
+
if (tu && typeof tu === "object") {
|
|
514
|
+
inputTokens = tu.promptTokens ?? tu.prompt_tokens ?? tu.inputTokens ?? tu.input_tokens;
|
|
515
|
+
outputTokens = tu.completionTokens ?? tu.completion_tokens ?? tu.outputTokens ?? tu.output_tokens;
|
|
516
|
+
}
|
|
517
|
+
model = lo.model_name ?? lo.modelName ?? lo.model;
|
|
518
|
+
}
|
|
519
|
+
if (inputTokens == null || !model) {
|
|
520
|
+
try {
|
|
521
|
+
for (const genList of output?.generations ?? []) {
|
|
522
|
+
for (const gen of genList) {
|
|
523
|
+
const msg = gen?.message;
|
|
524
|
+
const um = msg?.usage_metadata ?? msg?.usageMetadata;
|
|
525
|
+
if (um && inputTokens == null) {
|
|
526
|
+
inputTokens = um.input_tokens ?? um.inputTokens;
|
|
527
|
+
outputTokens = um.output_tokens ?? um.outputTokens;
|
|
528
|
+
}
|
|
529
|
+
const rm = msg?.response_metadata ?? msg?.responseMetadata;
|
|
530
|
+
if (rm && !model) model = rm.model_name ?? rm.modelName ?? rm.model;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
} catch {
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return { model: model != null ? String(model) : void 0, inputTokens, outputTokens };
|
|
537
|
+
}
|
|
538
|
+
function extractText(output) {
|
|
539
|
+
try {
|
|
540
|
+
for (const genList of output?.generations ?? []) {
|
|
541
|
+
for (const gen of genList) {
|
|
542
|
+
let t = gen?.text;
|
|
543
|
+
if (!t) {
|
|
544
|
+
const c = gen?.message?.content;
|
|
545
|
+
if (typeof c === "string") t = c;
|
|
546
|
+
}
|
|
547
|
+
if (typeof t === "string" && t.trim()) return t.slice(0, 3e3);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
} catch {
|
|
551
|
+
}
|
|
552
|
+
return void 0;
|
|
553
|
+
}
|
|
554
|
+
function langchain(agentName, opts = {}) {
|
|
555
|
+
const platform = opts.platform ?? "sdk";
|
|
556
|
+
const starts = /* @__PURE__ */ new Map();
|
|
557
|
+
const begin = (runId) => {
|
|
558
|
+
starts.set(runId, { t0: Date.now(), executedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
559
|
+
};
|
|
560
|
+
const finish = (status, output, errorMessage, runId) => {
|
|
561
|
+
const s = starts.get(runId);
|
|
562
|
+
starts.delete(runId);
|
|
563
|
+
const duration_ms = s ? Date.now() - s.t0 : 0;
|
|
564
|
+
const executed_at = s?.executedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
565
|
+
const { model, inputTokens, outputTokens } = output ? extractUsage2(output) : {};
|
|
566
|
+
const cost_usd = model && inputTokens != null && outputTokens != null ? calcCost(model, inputTokens, outputTokens) : void 0;
|
|
567
|
+
const activeRun = getActiveRun();
|
|
568
|
+
if (activeRun) {
|
|
569
|
+
activeRun.calls.push({ platform, model, inputTokens, outputTokens, costUsd: cost_usd, status });
|
|
570
|
+
} else {
|
|
571
|
+
void sendExecution({
|
|
572
|
+
platform,
|
|
573
|
+
agent_name: agentName,
|
|
574
|
+
status,
|
|
575
|
+
executed_at,
|
|
576
|
+
duration_ms,
|
|
577
|
+
model,
|
|
578
|
+
input_tokens: inputTokens,
|
|
579
|
+
output_tokens: outputTokens,
|
|
580
|
+
cost_usd,
|
|
581
|
+
error_message: errorMessage ?? null,
|
|
582
|
+
output_summary: output ? extractText(output) : void 0,
|
|
583
|
+
user_id: opts.userId
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
return {
|
|
588
|
+
name: "opsveritas",
|
|
589
|
+
handleLLMStart(_llm, _prompts, runId) {
|
|
590
|
+
begin(runId);
|
|
591
|
+
},
|
|
592
|
+
handleChatModelStart(_llm, _messages, runId) {
|
|
593
|
+
begin(runId);
|
|
594
|
+
},
|
|
595
|
+
handleLLMEnd(output, runId) {
|
|
596
|
+
try {
|
|
597
|
+
finish("success", output, void 0, runId);
|
|
598
|
+
} catch {
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
handleLLMError(err, runId) {
|
|
602
|
+
try {
|
|
603
|
+
finish("failed", void 0, err instanceof Error ? err.message : String(err), runId);
|
|
604
|
+
} catch {
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
504
610
|
// src/index.ts
|
|
505
|
-
var OpsVeritas = { init, run, trace, wrap };
|
|
611
|
+
var OpsVeritas = { init, run, trace, wrap, langchain };
|
|
506
612
|
var index_default = OpsVeritas;
|
|
507
613
|
export {
|
|
508
614
|
OpsVeritas,
|
|
509
615
|
index_default as default,
|
|
510
616
|
init,
|
|
617
|
+
langchain,
|
|
511
618
|
run,
|
|
512
619
|
trace,
|
|
513
620
|
wrap
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opsveritas-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Monitor your AI agents in 3 lines of code — tokens, cost, latency, and silent failures",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -30,12 +30,16 @@
|
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"@anthropic-ai/sdk": ">=0.20.0",
|
|
33
|
+
"@langchain/core": ">=0.2.0",
|
|
33
34
|
"openai": ">=4.0.0"
|
|
34
35
|
},
|
|
35
36
|
"peerDependenciesMeta": {
|
|
36
37
|
"@anthropic-ai/sdk": {
|
|
37
38
|
"optional": true
|
|
38
39
|
},
|
|
40
|
+
"@langchain/core": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
39
43
|
"openai": {
|
|
40
44
|
"optional": true
|
|
41
45
|
}
|