opsveritas-sdk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/index.d.mts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +108 -1
- package/dist/index.mjs +107 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -22,6 +22,20 @@ Works the same for Anthropic and Gemini clients. Prefer manual control? Wrap a f
|
|
|
22
22
|
await OpsVeritas.trace('Nightly Report', async () => runReport());
|
|
23
23
|
```
|
|
24
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
|
+
|
|
25
39
|
## What data is sent
|
|
26
40
|
|
|
27
41
|
By design the SDK sends **metadata only, plus a short output snippet** — never your prompts/inputs:
|
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
|
|
@@ -532,13 +533,119 @@ function wrap(client, opts) {
|
|
|
532
533
|
return client;
|
|
533
534
|
}
|
|
534
535
|
|
|
536
|
+
// src/langchain.ts
|
|
537
|
+
function extractUsage2(output) {
|
|
538
|
+
let model;
|
|
539
|
+
let inputTokens;
|
|
540
|
+
let outputTokens;
|
|
541
|
+
const lo = output?.llmOutput;
|
|
542
|
+
if (lo && typeof lo === "object") {
|
|
543
|
+
const tu = lo.tokenUsage ?? lo.token_usage ?? lo.usage;
|
|
544
|
+
if (tu && typeof tu === "object") {
|
|
545
|
+
inputTokens = tu.promptTokens ?? tu.prompt_tokens ?? tu.inputTokens ?? tu.input_tokens;
|
|
546
|
+
outputTokens = tu.completionTokens ?? tu.completion_tokens ?? tu.outputTokens ?? tu.output_tokens;
|
|
547
|
+
}
|
|
548
|
+
model = lo.model_name ?? lo.modelName ?? lo.model;
|
|
549
|
+
}
|
|
550
|
+
if (inputTokens == null || !model) {
|
|
551
|
+
try {
|
|
552
|
+
for (const genList of output?.generations ?? []) {
|
|
553
|
+
for (const gen of genList) {
|
|
554
|
+
const msg = gen?.message;
|
|
555
|
+
const um = msg?.usage_metadata ?? msg?.usageMetadata;
|
|
556
|
+
if (um && inputTokens == null) {
|
|
557
|
+
inputTokens = um.input_tokens ?? um.inputTokens;
|
|
558
|
+
outputTokens = um.output_tokens ?? um.outputTokens;
|
|
559
|
+
}
|
|
560
|
+
const rm = msg?.response_metadata ?? msg?.responseMetadata;
|
|
561
|
+
if (rm && !model) model = rm.model_name ?? rm.modelName ?? rm.model;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
} catch {
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return { model: model != null ? String(model) : void 0, inputTokens, outputTokens };
|
|
568
|
+
}
|
|
569
|
+
function extractText(output) {
|
|
570
|
+
try {
|
|
571
|
+
for (const genList of output?.generations ?? []) {
|
|
572
|
+
for (const gen of genList) {
|
|
573
|
+
let t = gen?.text;
|
|
574
|
+
if (!t) {
|
|
575
|
+
const c = gen?.message?.content;
|
|
576
|
+
if (typeof c === "string") t = c;
|
|
577
|
+
}
|
|
578
|
+
if (typeof t === "string" && t.trim()) return t.slice(0, 300);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
} catch {
|
|
582
|
+
}
|
|
583
|
+
return void 0;
|
|
584
|
+
}
|
|
585
|
+
function langchain(agentName, opts = {}) {
|
|
586
|
+
const platform = opts.platform ?? "sdk";
|
|
587
|
+
const starts = /* @__PURE__ */ new Map();
|
|
588
|
+
const begin = (runId) => {
|
|
589
|
+
starts.set(runId, { t0: Date.now(), executedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
590
|
+
};
|
|
591
|
+
const finish = (status, output, errorMessage, runId) => {
|
|
592
|
+
const s = starts.get(runId);
|
|
593
|
+
starts.delete(runId);
|
|
594
|
+
const duration_ms = s ? Date.now() - s.t0 : 0;
|
|
595
|
+
const executed_at = s?.executedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
596
|
+
const { model, inputTokens, outputTokens } = output ? extractUsage2(output) : {};
|
|
597
|
+
const cost_usd = model && inputTokens != null && outputTokens != null ? calcCost(model, inputTokens, outputTokens) : void 0;
|
|
598
|
+
const activeRun = getActiveRun();
|
|
599
|
+
if (activeRun) {
|
|
600
|
+
activeRun.calls.push({ platform, model, inputTokens, outputTokens, costUsd: cost_usd, status });
|
|
601
|
+
} else {
|
|
602
|
+
void sendExecution({
|
|
603
|
+
platform,
|
|
604
|
+
agent_name: agentName,
|
|
605
|
+
status,
|
|
606
|
+
executed_at,
|
|
607
|
+
duration_ms,
|
|
608
|
+
model,
|
|
609
|
+
input_tokens: inputTokens,
|
|
610
|
+
output_tokens: outputTokens,
|
|
611
|
+
cost_usd,
|
|
612
|
+
error_message: errorMessage ?? null,
|
|
613
|
+
output_summary: output ? extractText(output) : void 0,
|
|
614
|
+
user_id: opts.userId
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
return {
|
|
619
|
+
name: "opsveritas",
|
|
620
|
+
handleLLMStart(_llm, _prompts, runId) {
|
|
621
|
+
begin(runId);
|
|
622
|
+
},
|
|
623
|
+
handleChatModelStart(_llm, _messages, runId) {
|
|
624
|
+
begin(runId);
|
|
625
|
+
},
|
|
626
|
+
handleLLMEnd(output, runId) {
|
|
627
|
+
try {
|
|
628
|
+
finish("success", output, void 0, runId);
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
handleLLMError(err, runId) {
|
|
633
|
+
try {
|
|
634
|
+
finish("failed", void 0, err instanceof Error ? err.message : String(err), runId);
|
|
635
|
+
} catch {
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
535
641
|
// src/index.ts
|
|
536
|
-
var OpsVeritas = { init, run, trace, wrap };
|
|
642
|
+
var OpsVeritas = { init, run, trace, wrap, langchain };
|
|
537
643
|
var index_default = OpsVeritas;
|
|
538
644
|
// Annotate the CommonJS export names for ESM import in node:
|
|
539
645
|
0 && (module.exports = {
|
|
540
646
|
OpsVeritas,
|
|
541
647
|
init,
|
|
648
|
+
langchain,
|
|
542
649
|
run,
|
|
543
650
|
trace,
|
|
544
651
|
wrap
|
package/dist/index.mjs
CHANGED
|
@@ -501,13 +501,119 @@ function wrap(client, opts) {
|
|
|
501
501
|
return client;
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
// src/langchain.ts
|
|
505
|
+
function extractUsage2(output) {
|
|
506
|
+
let model;
|
|
507
|
+
let inputTokens;
|
|
508
|
+
let outputTokens;
|
|
509
|
+
const lo = output?.llmOutput;
|
|
510
|
+
if (lo && typeof lo === "object") {
|
|
511
|
+
const tu = lo.tokenUsage ?? lo.token_usage ?? lo.usage;
|
|
512
|
+
if (tu && typeof tu === "object") {
|
|
513
|
+
inputTokens = tu.promptTokens ?? tu.prompt_tokens ?? tu.inputTokens ?? tu.input_tokens;
|
|
514
|
+
outputTokens = tu.completionTokens ?? tu.completion_tokens ?? tu.outputTokens ?? tu.output_tokens;
|
|
515
|
+
}
|
|
516
|
+
model = lo.model_name ?? lo.modelName ?? lo.model;
|
|
517
|
+
}
|
|
518
|
+
if (inputTokens == null || !model) {
|
|
519
|
+
try {
|
|
520
|
+
for (const genList of output?.generations ?? []) {
|
|
521
|
+
for (const gen of genList) {
|
|
522
|
+
const msg = gen?.message;
|
|
523
|
+
const um = msg?.usage_metadata ?? msg?.usageMetadata;
|
|
524
|
+
if (um && inputTokens == null) {
|
|
525
|
+
inputTokens = um.input_tokens ?? um.inputTokens;
|
|
526
|
+
outputTokens = um.output_tokens ?? um.outputTokens;
|
|
527
|
+
}
|
|
528
|
+
const rm = msg?.response_metadata ?? msg?.responseMetadata;
|
|
529
|
+
if (rm && !model) model = rm.model_name ?? rm.modelName ?? rm.model;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
} catch {
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return { model: model != null ? String(model) : void 0, inputTokens, outputTokens };
|
|
536
|
+
}
|
|
537
|
+
function extractText(output) {
|
|
538
|
+
try {
|
|
539
|
+
for (const genList of output?.generations ?? []) {
|
|
540
|
+
for (const gen of genList) {
|
|
541
|
+
let t = gen?.text;
|
|
542
|
+
if (!t) {
|
|
543
|
+
const c = gen?.message?.content;
|
|
544
|
+
if (typeof c === "string") t = c;
|
|
545
|
+
}
|
|
546
|
+
if (typeof t === "string" && t.trim()) return t.slice(0, 300);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
} catch {
|
|
550
|
+
}
|
|
551
|
+
return void 0;
|
|
552
|
+
}
|
|
553
|
+
function langchain(agentName, opts = {}) {
|
|
554
|
+
const platform = opts.platform ?? "sdk";
|
|
555
|
+
const starts = /* @__PURE__ */ new Map();
|
|
556
|
+
const begin = (runId) => {
|
|
557
|
+
starts.set(runId, { t0: Date.now(), executedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
558
|
+
};
|
|
559
|
+
const finish = (status, output, errorMessage, runId) => {
|
|
560
|
+
const s = starts.get(runId);
|
|
561
|
+
starts.delete(runId);
|
|
562
|
+
const duration_ms = s ? Date.now() - s.t0 : 0;
|
|
563
|
+
const executed_at = s?.executedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
564
|
+
const { model, inputTokens, outputTokens } = output ? extractUsage2(output) : {};
|
|
565
|
+
const cost_usd = model && inputTokens != null && outputTokens != null ? calcCost(model, inputTokens, outputTokens) : void 0;
|
|
566
|
+
const activeRun = getActiveRun();
|
|
567
|
+
if (activeRun) {
|
|
568
|
+
activeRun.calls.push({ platform, model, inputTokens, outputTokens, costUsd: cost_usd, status });
|
|
569
|
+
} else {
|
|
570
|
+
void sendExecution({
|
|
571
|
+
platform,
|
|
572
|
+
agent_name: agentName,
|
|
573
|
+
status,
|
|
574
|
+
executed_at,
|
|
575
|
+
duration_ms,
|
|
576
|
+
model,
|
|
577
|
+
input_tokens: inputTokens,
|
|
578
|
+
output_tokens: outputTokens,
|
|
579
|
+
cost_usd,
|
|
580
|
+
error_message: errorMessage ?? null,
|
|
581
|
+
output_summary: output ? extractText(output) : void 0,
|
|
582
|
+
user_id: opts.userId
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
return {
|
|
587
|
+
name: "opsveritas",
|
|
588
|
+
handleLLMStart(_llm, _prompts, runId) {
|
|
589
|
+
begin(runId);
|
|
590
|
+
},
|
|
591
|
+
handleChatModelStart(_llm, _messages, runId) {
|
|
592
|
+
begin(runId);
|
|
593
|
+
},
|
|
594
|
+
handleLLMEnd(output, runId) {
|
|
595
|
+
try {
|
|
596
|
+
finish("success", output, void 0, runId);
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
handleLLMError(err, runId) {
|
|
601
|
+
try {
|
|
602
|
+
finish("failed", void 0, err instanceof Error ? err.message : String(err), runId);
|
|
603
|
+
} catch {
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
504
609
|
// src/index.ts
|
|
505
|
-
var OpsVeritas = { init, run, trace, wrap };
|
|
610
|
+
var OpsVeritas = { init, run, trace, wrap, langchain };
|
|
506
611
|
var index_default = OpsVeritas;
|
|
507
612
|
export {
|
|
508
613
|
OpsVeritas,
|
|
509
614
|
index_default as default,
|
|
510
615
|
init,
|
|
616
|
+
langchain,
|
|
511
617
|
run,
|
|
512
618
|
trace,
|
|
513
619
|
wrap
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opsveritas-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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
|
}
|