agentmetrics-langchain 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -0
- package/dist/callback.d.ts +31 -0
- package/dist/callback.d.ts.map +1 -0
- package/dist/callback.js +247 -0
- package/dist/callback.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
- package/src/callback.ts +334 -0
- package/src/index.ts +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# agentmetrics-langchain (JS/TS)
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/agentmetrics-langchain)
|
|
4
|
+
[](../../LICENSE)
|
|
5
|
+
|
|
6
|
+
AgentMetrics integration for [LangChain.js](https://js.langchain.com). Pass one callback to any chain or agent `.invoke()` call and every run reports back to your dashboard showing latency, cost, token counts, tool calls, and errors, with no changes to your agent logic.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install agentmetrics-langchain
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Quickstart
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { AgentMetricsCallback } from "agentmetrics-langchain";
|
|
22
|
+
|
|
23
|
+
const cb = new AgentMetricsCallback({
|
|
24
|
+
agentId: "my-langchain-agent",
|
|
25
|
+
baseUrl: "http://localhost:8099",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const result = await agent.invoke(
|
|
29
|
+
{ input: "What is the weather in Paris?" },
|
|
30
|
+
{ callbacks: [cb] },
|
|
31
|
+
);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## API
|
|
37
|
+
|
|
38
|
+
### `new AgentMetricsCallback(opts)`
|
|
39
|
+
|
|
40
|
+
| Option | Default | Description |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `agentId` | `"langchain-agent"` | Label shown in the dashboard |
|
|
43
|
+
| `baseUrl` | `"http://localhost:8099"` | AgentMetrics server address |
|
|
44
|
+
|
|
45
|
+
Pass the callback via the `callbacks` array in the second argument to `.invoke()`. It implements `BaseCallbackHandler` from `@langchain/core` and tracks the top-level chain only, with all nested sub-chains aggregated into the same run.
|
|
46
|
+
|
|
47
|
+
Supports both OpenAI (`usage_metadata`) and Anthropic (`input_token_details`) token counting paths.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## What gets tracked
|
|
52
|
+
|
|
53
|
+
Each top-level chain invocation emits one event to `/v1/events` on completion or error:
|
|
54
|
+
|
|
55
|
+
| Field | Description |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `status` | `success` or `failed` |
|
|
58
|
+
| `duration_ms` | Wall-clock chain duration |
|
|
59
|
+
| `input_tokens` / `output_tokens` | Aggregated across all LLM calls |
|
|
60
|
+
| `cache_read_tokens` / `cache_write_tokens` | Cache token counts (Anthropic) |
|
|
61
|
+
| `llm_calls` | Number of LLM requests in the chain |
|
|
62
|
+
| `tool_calls` / `tool_errors` | Tool usage counts |
|
|
63
|
+
| `tool_names` | Array of tools invoked |
|
|
64
|
+
| `model` | Model name from the first LLM call |
|
|
65
|
+
| `estimated_cost_usd` | Computed from token counts and model pricing |
|
|
66
|
+
| `error` | First 500 chars of the error message on failure |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## LangGraph.js
|
|
71
|
+
|
|
72
|
+
Works with LangGraph.js the same way:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { AgentMetricsCallback } from "agentmetrics-langchain";
|
|
76
|
+
|
|
77
|
+
const cb = new AgentMetricsCallback({ baseUrl: "http://localhost:8099" });
|
|
78
|
+
const app = buildGraph().compile();
|
|
79
|
+
|
|
80
|
+
const result = await app.invoke(state, { callbacks: [cb] });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
[MIT](../../LICENSE)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
|
|
2
|
+
import type { Serialized } from "@langchain/core/load/serializable";
|
|
3
|
+
import type { LLMResult } from "@langchain/core/outputs";
|
|
4
|
+
import type { ChainValues } from "@langchain/core/utils/types";
|
|
5
|
+
export declare class AgentMetricsCallback extends BaseCallbackHandler {
|
|
6
|
+
name: string;
|
|
7
|
+
private readonly _apiKey;
|
|
8
|
+
private readonly _agentId;
|
|
9
|
+
private readonly _baseUrl;
|
|
10
|
+
private readonly _runs;
|
|
11
|
+
private readonly _parentMap;
|
|
12
|
+
private readonly _pendingToolNames;
|
|
13
|
+
constructor(opts: {
|
|
14
|
+
apiKey: string;
|
|
15
|
+
agentId?: string;
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
});
|
|
18
|
+
handleChainStart(_serialized: Serialized, _inputs: ChainValues, runId: string, parentRunId?: string): Promise<void>;
|
|
19
|
+
handleChainEnd(_outputs: ChainValues, runId: string, parentRunId?: string): Promise<void>;
|
|
20
|
+
handleChainError(err: Error, runId: string, parentRunId?: string): Promise<void>;
|
|
21
|
+
handleLLMStart(_llm: Serialized, _prompts: string[], runId: string, parentRunId?: string): Promise<void>;
|
|
22
|
+
handleChatModelStart(_llm: Serialized, _messages: unknown[][], runId: string, parentRunId?: string): Promise<void>;
|
|
23
|
+
handleLLMEnd(output: LLMResult, runId: string): Promise<void>;
|
|
24
|
+
handleLLMError(_err: Error, _runId: string): Promise<void>;
|
|
25
|
+
handleToolStart(serialized: Serialized, _input: string, runId: string, parentRunId?: string): Promise<void>;
|
|
26
|
+
handleToolEnd(_output: unknown, runId: string): Promise<void>;
|
|
27
|
+
handleToolError(err: Error, runId: string): Promise<void>;
|
|
28
|
+
private _findTopRun;
|
|
29
|
+
private _emit;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=callback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../src/callback.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AA2G/D,qBAAa,oBAAqB,SAAQ,mBAAmB;IAC3D,IAAI,SAAkB;IAEtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IAGnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IAExD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;gBAEnD,IAAI,EAAE;QAChB,MAAM,EAAI,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;IAQK,gBAAgB,CACpB,WAAW,EAAE,UAAU,EACvB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAQV,cAAc,CAClB,QAAQ,EAAE,WAAW,EACrB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAMV,gBAAgB,CACpB,GAAG,EAAE,KAAK,EACV,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAYV,cAAc,CAClB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAIV,oBAAoB,CACxB,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,OAAO,EAAE,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAIV,YAAY,CAChB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;IAuCV,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1D,eAAe,CACnB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAQV,aAAa,CACjB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;IAUV,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/D,OAAO,CAAC,WAAW;YAYL,KAAK;CA0CpB"}
|
package/dist/callback.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
|
|
3
|
+
const PRICING = {
|
|
4
|
+
// [input, output, cache_read, cache_write]
|
|
5
|
+
"gpt-4o": [2.50, 10.00, 1.25, 0],
|
|
6
|
+
"gpt-4o-mini": [0.15, 0.60, 0.075, 0],
|
|
7
|
+
"gpt-4-turbo": [10.00, 30.00, 0, 0],
|
|
8
|
+
"gpt-3.5-turbo": [0.50, 1.50, 0, 0],
|
|
9
|
+
"claude-3-5-sonnet-20241022": [3.00, 15.00, 0.30, 3.75],
|
|
10
|
+
"claude-3-5-haiku-20241022": [0.80, 4.00, 0.08, 1.00],
|
|
11
|
+
"claude-3-opus-20240229": [15.00, 75.00, 1.50, 18.75],
|
|
12
|
+
"claude-sonnet-4-6": [3.00, 15.00, 0.30, 3.75],
|
|
13
|
+
"claude-opus-4-7": [15.00, 75.00, 1.50, 18.75],
|
|
14
|
+
"claude-haiku-4-5-20251001": [0.80, 4.00, 0.08, 1.00],
|
|
15
|
+
"gemini-1.5-pro": [1.25, 5.00, 0, 0],
|
|
16
|
+
"gemini-1.5-flash": [0.075, 0.30, 0, 0],
|
|
17
|
+
};
|
|
18
|
+
function estimateCost(model, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens) {
|
|
19
|
+
if (!model)
|
|
20
|
+
return null;
|
|
21
|
+
const key = Object.keys(PRICING).find(k => model.startsWith(k)) ?? null;
|
|
22
|
+
if (!key)
|
|
23
|
+
return null;
|
|
24
|
+
const [ip, op, cr, cw] = PRICING[key];
|
|
25
|
+
return ((inputTokens * ip + outputTokens * op +
|
|
26
|
+
cacheReadTokens * cr + cacheWriteTokens * cw) / 1_000_000);
|
|
27
|
+
}
|
|
28
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
29
|
+
function sleep(ms) {
|
|
30
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
31
|
+
}
|
|
32
|
+
async function sendWithRetry(url, apiKey, payload) {
|
|
33
|
+
const body = JSON.stringify(payload);
|
|
34
|
+
for (let attempt = 0; attempt < MAX_RETRY_ATTEMPTS; attempt++) {
|
|
35
|
+
try {
|
|
36
|
+
const res = await fetch(`${url}/v1/events`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: {
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
Authorization: `Bearer ${apiKey}`,
|
|
41
|
+
},
|
|
42
|
+
body,
|
|
43
|
+
});
|
|
44
|
+
if (res.ok || (res.status >= 400 && res.status < 500))
|
|
45
|
+
return;
|
|
46
|
+
if (attempt < MAX_RETRY_ATTEMPTS - 1) {
|
|
47
|
+
await sleep(Math.min(1000 * 2 ** attempt + Math.random() * 200, 10_000));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
if (attempt < MAX_RETRY_ATTEMPTS - 1) {
|
|
52
|
+
await sleep(Math.min(1000 * 2 ** attempt + Math.random() * 200, 10_000));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function newRunState(agentId) {
|
|
58
|
+
return {
|
|
59
|
+
agentId,
|
|
60
|
+
startMs: performance.now(),
|
|
61
|
+
inputTokens: 0,
|
|
62
|
+
outputTokens: 0,
|
|
63
|
+
cacheReadTokens: 0,
|
|
64
|
+
cacheWriteTokens: 0,
|
|
65
|
+
llmCalls: 0,
|
|
66
|
+
toolCalls: 0,
|
|
67
|
+
toolErrors: 0,
|
|
68
|
+
toolNames: new Set(),
|
|
69
|
+
model: null,
|
|
70
|
+
status: "success",
|
|
71
|
+
error: null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export class AgentMetricsCallback extends BaseCallbackHandler {
|
|
75
|
+
name = "agentmetrics";
|
|
76
|
+
_apiKey;
|
|
77
|
+
_agentId;
|
|
78
|
+
_baseUrl;
|
|
79
|
+
// top-level run_id → RunState
|
|
80
|
+
_runs = new Map();
|
|
81
|
+
// run_id → parent run_id (ancestry chain)
|
|
82
|
+
_parentMap = new Map();
|
|
83
|
+
// tool run_id → tool name (resolved on end/error)
|
|
84
|
+
_pendingToolNames = new Map();
|
|
85
|
+
constructor(opts) {
|
|
86
|
+
super();
|
|
87
|
+
this._apiKey = opts.apiKey;
|
|
88
|
+
this._agentId = opts.agentId ?? "langchain-agent";
|
|
89
|
+
this._baseUrl = opts.baseUrl ?? "http://localhost:8099";
|
|
90
|
+
}
|
|
91
|
+
async handleChainStart(_serialized, _inputs, runId, parentRunId) {
|
|
92
|
+
if (!parentRunId) {
|
|
93
|
+
this._runs.set(runId, newRunState(this._agentId));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this._parentMap.set(runId, parentRunId);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async handleChainEnd(_outputs, runId, parentRunId) {
|
|
100
|
+
if (!parentRunId) {
|
|
101
|
+
await this._emit(runId);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async handleChainError(err, runId, parentRunId) {
|
|
105
|
+
if (!parentRunId) {
|
|
106
|
+
const run = this._runs.get(runId);
|
|
107
|
+
if (run) {
|
|
108
|
+
run.status = "failed";
|
|
109
|
+
run.error = String(err).slice(0, 500);
|
|
110
|
+
}
|
|
111
|
+
await this._emit(runId);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async handleLLMStart(_llm, _prompts, runId, parentRunId) {
|
|
115
|
+
if (parentRunId)
|
|
116
|
+
this._parentMap.set(runId, parentRunId);
|
|
117
|
+
}
|
|
118
|
+
async handleChatModelStart(_llm, _messages, runId, parentRunId) {
|
|
119
|
+
if (parentRunId)
|
|
120
|
+
this._parentMap.set(runId, parentRunId);
|
|
121
|
+
}
|
|
122
|
+
async handleLLMEnd(output, runId) {
|
|
123
|
+
const run = this._findTopRun(runId);
|
|
124
|
+
if (!run)
|
|
125
|
+
return;
|
|
126
|
+
run.llmCalls++;
|
|
127
|
+
// Path 1: ChatGeneration → message.usage_metadata (Anthropic / OpenAI)
|
|
128
|
+
let foundUsage = false;
|
|
129
|
+
for (const genList of output.generations) {
|
|
130
|
+
for (const gen of genList) {
|
|
131
|
+
const msg = gen.message;
|
|
132
|
+
const umeta = msg?.usage_metadata;
|
|
133
|
+
if (umeta) {
|
|
134
|
+
run.inputTokens += umeta["input_tokens"] ?? 0;
|
|
135
|
+
run.outputTokens += umeta["output_tokens"] ?? 0;
|
|
136
|
+
const details = umeta["input_token_details"] ?? {};
|
|
137
|
+
run.cacheReadTokens += details["cache_read"] ?? 0;
|
|
138
|
+
run.cacheWriteTokens += details["cache_creation"] ?? 0;
|
|
139
|
+
if (!run.model) {
|
|
140
|
+
const rmeta = msg?.response_metadata;
|
|
141
|
+
run.model = rmeta?.["model_name"] ?? rmeta?.["model"] ?? null;
|
|
142
|
+
}
|
|
143
|
+
foundUsage = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (foundUsage)
|
|
148
|
+
return;
|
|
149
|
+
// Path 2: llm_output dict (older/non-chat)
|
|
150
|
+
const lo = (output.llmOutput ?? {});
|
|
151
|
+
const usage = (lo["token_usage"] ?? lo["usage"] ?? {});
|
|
152
|
+
run.inputTokens += usage["prompt_tokens"] ?? 0;
|
|
153
|
+
run.outputTokens += usage["completion_tokens"] ?? 0;
|
|
154
|
+
run.cacheReadTokens += usage["cache_read_input_tokens"] ?? 0;
|
|
155
|
+
run.cacheWriteTokens += usage["cache_creation_input_tokens"] ?? 0;
|
|
156
|
+
if (!run.model) {
|
|
157
|
+
run.model = lo["model_name"] ?? lo["model"] ?? null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async handleLLMError(_err, _runId) {
|
|
161
|
+
// LLM errors do not affect tool error counts
|
|
162
|
+
}
|
|
163
|
+
async handleToolStart(serialized, _input, runId, parentRunId) {
|
|
164
|
+
const name = serialized.name
|
|
165
|
+
?? serialized.id?.at(-1)
|
|
166
|
+
?? "unknown";
|
|
167
|
+
this._pendingToolNames.set(runId, String(name));
|
|
168
|
+
if (parentRunId)
|
|
169
|
+
this._parentMap.set(runId, parentRunId);
|
|
170
|
+
}
|
|
171
|
+
async handleToolEnd(_output, runId) {
|
|
172
|
+
const run = this._findTopRun(runId);
|
|
173
|
+
if (run) {
|
|
174
|
+
run.toolCalls++;
|
|
175
|
+
const name = this._pendingToolNames.get(runId);
|
|
176
|
+
if (name)
|
|
177
|
+
run.toolNames.add(name);
|
|
178
|
+
}
|
|
179
|
+
this._pendingToolNames.delete(runId);
|
|
180
|
+
}
|
|
181
|
+
async handleToolError(err, runId) {
|
|
182
|
+
const run = this._findTopRun(runId);
|
|
183
|
+
if (run) {
|
|
184
|
+
run.toolCalls++;
|
|
185
|
+
run.toolErrors++;
|
|
186
|
+
const name = this._pendingToolNames.get(runId);
|
|
187
|
+
if (name)
|
|
188
|
+
run.toolNames.add(name);
|
|
189
|
+
}
|
|
190
|
+
this._pendingToolNames.delete(runId);
|
|
191
|
+
}
|
|
192
|
+
_findTopRun(runId) {
|
|
193
|
+
const seen = new Set();
|
|
194
|
+
let rid = runId;
|
|
195
|
+
while (rid && !seen.has(rid)) {
|
|
196
|
+
seen.add(rid);
|
|
197
|
+
const state = this._runs.get(rid);
|
|
198
|
+
if (state)
|
|
199
|
+
return state;
|
|
200
|
+
rid = this._parentMap.get(rid);
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
async _emit(runId) {
|
|
205
|
+
const run = this._runs.get(runId);
|
|
206
|
+
if (!run)
|
|
207
|
+
return;
|
|
208
|
+
this._runs.delete(runId);
|
|
209
|
+
// clean up orphan parent-map entries
|
|
210
|
+
for (const [k, v] of this._parentMap) {
|
|
211
|
+
if (v === runId)
|
|
212
|
+
this._parentMap.delete(k);
|
|
213
|
+
}
|
|
214
|
+
const durationMs = performance.now() - run.startMs;
|
|
215
|
+
const est = estimateCost(run.model, run.inputTokens, run.outputTokens, run.cacheReadTokens, run.cacheWriteTokens);
|
|
216
|
+
const payload = {
|
|
217
|
+
event_id: randomUUID(),
|
|
218
|
+
trace_id: runId,
|
|
219
|
+
agent_id: run.agentId,
|
|
220
|
+
platform: "langchain",
|
|
221
|
+
event_name: "agent_end",
|
|
222
|
+
ts: Date.now(),
|
|
223
|
+
redaction_policy_version: "v1-strict",
|
|
224
|
+
status: run.status,
|
|
225
|
+
duration_ms: Math.round(durationMs * 100) / 100,
|
|
226
|
+
tool_calls: run.toolCalls,
|
|
227
|
+
tool_errors: run.toolErrors,
|
|
228
|
+
tool_names: [...run.toolNames],
|
|
229
|
+
llm_calls: run.llmCalls,
|
|
230
|
+
input_tokens: run.inputTokens,
|
|
231
|
+
output_tokens: run.outputTokens,
|
|
232
|
+
};
|
|
233
|
+
if (run.model)
|
|
234
|
+
payload["model"] = run.model;
|
|
235
|
+
if (run.error)
|
|
236
|
+
payload["error"] = run.error;
|
|
237
|
+
if (run.cacheReadTokens)
|
|
238
|
+
payload["cache_read_tokens"] = run.cacheReadTokens;
|
|
239
|
+
if (run.cacheWriteTokens)
|
|
240
|
+
payload["cache_write_tokens"] = run.cacheWriteTokens;
|
|
241
|
+
if (est !== null)
|
|
242
|
+
payload["estimated_cost_usd"] = est;
|
|
243
|
+
// fire-and-forget: don't block the caller
|
|
244
|
+
sendWithRetry(this._baseUrl, this._apiKey, payload).catch(() => { });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=callback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback.js","sourceRoot":"","sources":["../src/callback.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentmetrics-langchain",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "AgentMetrics observability integration for LangChain.js",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/andalabx/agentmetrics",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/andalabx/agentmetrics.git"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"langchain",
|
|
14
|
+
"agentmetrics",
|
|
15
|
+
"observability",
|
|
16
|
+
"ai-agents",
|
|
17
|
+
"monitoring"
|
|
18
|
+
],
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"src"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc",
|
|
33
|
+
"prepublishOnly": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@langchain/core": ">=0.2.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@langchain/core": ">=0.2.0",
|
|
40
|
+
"typescript": "^5.0.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/callback.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
|
|
3
|
+
import type { Serialized } from "@langchain/core/load/serializable";
|
|
4
|
+
import type { LLMResult } from "@langchain/core/outputs";
|
|
5
|
+
import type { ChainValues } from "@langchain/core/utils/types";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const PRICING: Record<string, [number, number, number, number]> = {
|
|
9
|
+
// [input, output, cache_read, cache_write]
|
|
10
|
+
"gpt-4o": [2.50, 10.00, 1.25, 0],
|
|
11
|
+
"gpt-4o-mini": [0.15, 0.60, 0.075, 0],
|
|
12
|
+
"gpt-4-turbo": [10.00, 30.00, 0, 0],
|
|
13
|
+
"gpt-3.5-turbo": [0.50, 1.50, 0, 0],
|
|
14
|
+
"claude-3-5-sonnet-20241022":[3.00, 15.00, 0.30, 3.75],
|
|
15
|
+
"claude-3-5-haiku-20241022": [0.80, 4.00, 0.08, 1.00],
|
|
16
|
+
"claude-3-opus-20240229": [15.00, 75.00, 1.50, 18.75],
|
|
17
|
+
"claude-sonnet-4-6": [3.00, 15.00, 0.30, 3.75],
|
|
18
|
+
"claude-opus-4-7": [15.00, 75.00, 1.50, 18.75],
|
|
19
|
+
"claude-haiku-4-5-20251001": [0.80, 4.00, 0.08, 1.00],
|
|
20
|
+
"gemini-1.5-pro": [1.25, 5.00, 0, 0],
|
|
21
|
+
"gemini-1.5-flash": [0.075, 0.30, 0, 0],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function estimateCost(
|
|
25
|
+
model: string | null,
|
|
26
|
+
inputTokens: number,
|
|
27
|
+
outputTokens: number,
|
|
28
|
+
cacheReadTokens: number,
|
|
29
|
+
cacheWriteTokens: number,
|
|
30
|
+
): number | null {
|
|
31
|
+
if (!model) return null;
|
|
32
|
+
const key = Object.keys(PRICING).find(k => model.startsWith(k)) ?? null;
|
|
33
|
+
if (!key) return null;
|
|
34
|
+
const [ip, op, cr, cw] = PRICING[key];
|
|
35
|
+
return (
|
|
36
|
+
(inputTokens * ip + outputTokens * op +
|
|
37
|
+
cacheReadTokens * cr + cacheWriteTokens * cw) / 1_000_000
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
43
|
+
|
|
44
|
+
function sleep(ms: number): Promise<void> {
|
|
45
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function sendWithRetry(
|
|
49
|
+
url: string,
|
|
50
|
+
apiKey: string,
|
|
51
|
+
payload: Record<string, unknown>,
|
|
52
|
+
): Promise<void> {
|
|
53
|
+
const body = JSON.stringify(payload);
|
|
54
|
+
for (let attempt = 0; attempt < MAX_RETRY_ATTEMPTS; attempt++) {
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(`${url}/v1/events`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: {
|
|
59
|
+
"Content-Type": "application/json",
|
|
60
|
+
Authorization: `Bearer ${apiKey}`,
|
|
61
|
+
},
|
|
62
|
+
body,
|
|
63
|
+
});
|
|
64
|
+
if (res.ok || (res.status >= 400 && res.status < 500)) return;
|
|
65
|
+
if (attempt < MAX_RETRY_ATTEMPTS - 1) {
|
|
66
|
+
await sleep(Math.min(1000 * 2 ** attempt + Math.random() * 200, 10_000));
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
if (attempt < MAX_RETRY_ATTEMPTS - 1) {
|
|
70
|
+
await sleep(Math.min(1000 * 2 ** attempt + Math.random() * 200, 10_000));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
interface RunState {
|
|
78
|
+
agentId: string;
|
|
79
|
+
startMs: number;
|
|
80
|
+
inputTokens: number;
|
|
81
|
+
outputTokens: number;
|
|
82
|
+
cacheReadTokens: number;
|
|
83
|
+
cacheWriteTokens: number;
|
|
84
|
+
llmCalls: number;
|
|
85
|
+
toolCalls: number;
|
|
86
|
+
toolErrors: number;
|
|
87
|
+
toolNames: Set<string>;
|
|
88
|
+
model: string | null;
|
|
89
|
+
status: "success" | "failed";
|
|
90
|
+
error: string | null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function newRunState(agentId: string): RunState {
|
|
94
|
+
return {
|
|
95
|
+
agentId,
|
|
96
|
+
startMs: performance.now(),
|
|
97
|
+
inputTokens: 0,
|
|
98
|
+
outputTokens: 0,
|
|
99
|
+
cacheReadTokens: 0,
|
|
100
|
+
cacheWriteTokens: 0,
|
|
101
|
+
llmCalls: 0,
|
|
102
|
+
toolCalls: 0,
|
|
103
|
+
toolErrors: 0,
|
|
104
|
+
toolNames: new Set(),
|
|
105
|
+
model: null,
|
|
106
|
+
status: "success",
|
|
107
|
+
error: null,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
export class AgentMetricsCallback extends BaseCallbackHandler {
|
|
113
|
+
name = "agentmetrics";
|
|
114
|
+
|
|
115
|
+
private readonly _apiKey: string;
|
|
116
|
+
private readonly _agentId: string;
|
|
117
|
+
private readonly _baseUrl: string;
|
|
118
|
+
|
|
119
|
+
// top-level run_id → RunState
|
|
120
|
+
private readonly _runs = new Map<string, RunState>();
|
|
121
|
+
// run_id → parent run_id (ancestry chain)
|
|
122
|
+
private readonly _parentMap = new Map<string, string>();
|
|
123
|
+
// tool run_id → tool name (resolved on end/error)
|
|
124
|
+
private readonly _pendingToolNames = new Map<string, string>();
|
|
125
|
+
|
|
126
|
+
constructor(opts: {
|
|
127
|
+
apiKey: string;
|
|
128
|
+
agentId?: string;
|
|
129
|
+
baseUrl?: string;
|
|
130
|
+
}) {
|
|
131
|
+
super();
|
|
132
|
+
this._apiKey = opts.apiKey;
|
|
133
|
+
this._agentId = opts.agentId ?? "langchain-agent";
|
|
134
|
+
this._baseUrl = opts.baseUrl ?? "http://localhost:8099";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
async handleChainStart(
|
|
139
|
+
_serialized: Serialized,
|
|
140
|
+
_inputs: ChainValues,
|
|
141
|
+
runId: string,
|
|
142
|
+
parentRunId?: string,
|
|
143
|
+
): Promise<void> {
|
|
144
|
+
if (!parentRunId) {
|
|
145
|
+
this._runs.set(runId, newRunState(this._agentId));
|
|
146
|
+
} else {
|
|
147
|
+
this._parentMap.set(runId, parentRunId);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async handleChainEnd(
|
|
152
|
+
_outputs: ChainValues,
|
|
153
|
+
runId: string,
|
|
154
|
+
parentRunId?: string,
|
|
155
|
+
): Promise<void> {
|
|
156
|
+
if (!parentRunId) {
|
|
157
|
+
await this._emit(runId);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async handleChainError(
|
|
162
|
+
err: Error,
|
|
163
|
+
runId: string,
|
|
164
|
+
parentRunId?: string,
|
|
165
|
+
): Promise<void> {
|
|
166
|
+
if (!parentRunId) {
|
|
167
|
+
const run = this._runs.get(runId);
|
|
168
|
+
if (run) {
|
|
169
|
+
run.status = "failed";
|
|
170
|
+
run.error = String(err).slice(0, 500);
|
|
171
|
+
}
|
|
172
|
+
await this._emit(runId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
async handleLLMStart(
|
|
178
|
+
_llm: Serialized,
|
|
179
|
+
_prompts: string[],
|
|
180
|
+
runId: string,
|
|
181
|
+
parentRunId?: string,
|
|
182
|
+
): Promise<void> {
|
|
183
|
+
if (parentRunId) this._parentMap.set(runId, parentRunId);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async handleChatModelStart(
|
|
187
|
+
_llm: Serialized,
|
|
188
|
+
_messages: unknown[][],
|
|
189
|
+
runId: string,
|
|
190
|
+
parentRunId?: string,
|
|
191
|
+
): Promise<void> {
|
|
192
|
+
if (parentRunId) this._parentMap.set(runId, parentRunId);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async handleLLMEnd(
|
|
196
|
+
output: LLMResult,
|
|
197
|
+
runId: string,
|
|
198
|
+
): Promise<void> {
|
|
199
|
+
const run = this._findTopRun(runId);
|
|
200
|
+
if (!run) return;
|
|
201
|
+
run.llmCalls++;
|
|
202
|
+
|
|
203
|
+
// Path 1: ChatGeneration → message.usage_metadata (Anthropic / OpenAI)
|
|
204
|
+
let foundUsage = false;
|
|
205
|
+
for (const genList of output.generations) {
|
|
206
|
+
for (const gen of genList) {
|
|
207
|
+
const msg = (gen as any).message;
|
|
208
|
+
const umeta = msg?.usage_metadata as Record<string, any> | undefined;
|
|
209
|
+
if (umeta) {
|
|
210
|
+
run.inputTokens += (umeta["input_tokens"] as number | null) ?? 0;
|
|
211
|
+
run.outputTokens += (umeta["output_tokens"] as number | null) ?? 0;
|
|
212
|
+
const details = (umeta["input_token_details"] as Record<string, number> | null) ?? {};
|
|
213
|
+
run.cacheReadTokens += details["cache_read"] ?? 0;
|
|
214
|
+
run.cacheWriteTokens += details["cache_creation"] ?? 0;
|
|
215
|
+
if (!run.model) {
|
|
216
|
+
const rmeta = msg?.response_metadata as Record<string, string> | undefined;
|
|
217
|
+
run.model = rmeta?.["model_name"] ?? rmeta?.["model"] ?? null;
|
|
218
|
+
}
|
|
219
|
+
foundUsage = true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (foundUsage) return;
|
|
224
|
+
|
|
225
|
+
// Path 2: llm_output dict (older/non-chat)
|
|
226
|
+
const lo = (output.llmOutput ?? {}) as Record<string, any>;
|
|
227
|
+
const usage = (lo["token_usage"] ?? lo["usage"] ?? {}) as Record<string, number>;
|
|
228
|
+
run.inputTokens += usage["prompt_tokens"] ?? 0;
|
|
229
|
+
run.outputTokens += usage["completion_tokens"] ?? 0;
|
|
230
|
+
run.cacheReadTokens += usage["cache_read_input_tokens"] ?? 0;
|
|
231
|
+
run.cacheWriteTokens += usage["cache_creation_input_tokens"] ?? 0;
|
|
232
|
+
if (!run.model) {
|
|
233
|
+
run.model = lo["model_name"] ?? lo["model"] ?? null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async handleLLMError(_err: Error, _runId: string): Promise<void> {
|
|
238
|
+
// LLM errors do not affect tool error counts
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
async handleToolStart(
|
|
243
|
+
serialized: Serialized,
|
|
244
|
+
_input: string,
|
|
245
|
+
runId: string,
|
|
246
|
+
parentRunId?: string,
|
|
247
|
+
): Promise<void> {
|
|
248
|
+
const name = (serialized as any).name
|
|
249
|
+
?? ((serialized as any).id as string[] | undefined)?.at(-1)
|
|
250
|
+
?? "unknown";
|
|
251
|
+
this._pendingToolNames.set(runId, String(name));
|
|
252
|
+
if (parentRunId) this._parentMap.set(runId, parentRunId);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async handleToolEnd(
|
|
256
|
+
_output: unknown,
|
|
257
|
+
runId: string,
|
|
258
|
+
): Promise<void> {
|
|
259
|
+
const run = this._findTopRun(runId);
|
|
260
|
+
if (run) {
|
|
261
|
+
run.toolCalls++;
|
|
262
|
+
const name = this._pendingToolNames.get(runId);
|
|
263
|
+
if (name) run.toolNames.add(name);
|
|
264
|
+
}
|
|
265
|
+
this._pendingToolNames.delete(runId);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async handleToolError(err: Error, runId: string): Promise<void> {
|
|
269
|
+
const run = this._findTopRun(runId);
|
|
270
|
+
if (run) {
|
|
271
|
+
run.toolCalls++;
|
|
272
|
+
run.toolErrors++;
|
|
273
|
+
const name = this._pendingToolNames.get(runId);
|
|
274
|
+
if (name) run.toolNames.add(name);
|
|
275
|
+
}
|
|
276
|
+
this._pendingToolNames.delete(runId);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
private _findTopRun(runId: string): RunState | null {
|
|
281
|
+
const seen = new Set<string>();
|
|
282
|
+
let rid: string | undefined = runId;
|
|
283
|
+
while (rid && !seen.has(rid)) {
|
|
284
|
+
seen.add(rid);
|
|
285
|
+
const state = this._runs.get(rid);
|
|
286
|
+
if (state) return state;
|
|
287
|
+
rid = this._parentMap.get(rid);
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private async _emit(runId: string): Promise<void> {
|
|
293
|
+
const run = this._runs.get(runId);
|
|
294
|
+
if (!run) return;
|
|
295
|
+
this._runs.delete(runId);
|
|
296
|
+
|
|
297
|
+
// clean up orphan parent-map entries
|
|
298
|
+
for (const [k, v] of this._parentMap) {
|
|
299
|
+
if (v === runId) this._parentMap.delete(k);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const durationMs = performance.now() - run.startMs;
|
|
303
|
+
const est = estimateCost(
|
|
304
|
+
run.model, run.inputTokens, run.outputTokens,
|
|
305
|
+
run.cacheReadTokens, run.cacheWriteTokens,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
const payload: Record<string, unknown> = {
|
|
309
|
+
event_id: randomUUID(),
|
|
310
|
+
trace_id: runId,
|
|
311
|
+
agent_id: run.agentId,
|
|
312
|
+
platform: "langchain",
|
|
313
|
+
event_name: "agent_end",
|
|
314
|
+
ts: Date.now(),
|
|
315
|
+
redaction_policy_version: "v1-strict",
|
|
316
|
+
status: run.status,
|
|
317
|
+
duration_ms: Math.round(durationMs * 100) / 100,
|
|
318
|
+
tool_calls: run.toolCalls,
|
|
319
|
+
tool_errors: run.toolErrors,
|
|
320
|
+
tool_names: [...run.toolNames],
|
|
321
|
+
llm_calls: run.llmCalls,
|
|
322
|
+
input_tokens: run.inputTokens,
|
|
323
|
+
output_tokens: run.outputTokens,
|
|
324
|
+
};
|
|
325
|
+
if (run.model) payload["model"] = run.model;
|
|
326
|
+
if (run.error) payload["error"] = run.error;
|
|
327
|
+
if (run.cacheReadTokens) payload["cache_read_tokens"] = run.cacheReadTokens;
|
|
328
|
+
if (run.cacheWriteTokens) payload["cache_write_tokens"] = run.cacheWriteTokens;
|
|
329
|
+
if (est !== null) payload["estimated_cost_usd"] = est;
|
|
330
|
+
|
|
331
|
+
// fire-and-forget: don't block the caller
|
|
332
|
+
sendWithRetry(this._baseUrl, this._apiKey, payload).catch(() => {});
|
|
333
|
+
}
|
|
334
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AgentMetricsCallback } from "./callback.js";
|