@evalguard/langchain 1.0.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/LICENSE +201 -0
- package/README.md +334 -0
- package/dist/cost.d.ts +4 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +18 -0
- package/dist/cost.js.map +1 -0
- package/dist/guardrail-client.d.ts +3 -0
- package/dist/guardrail-client.d.ts.map +1 -0
- package/dist/guardrail-client.js +15 -0
- package/dist/guardrail-client.js.map +1 -0
- package/dist/index.d.ts +231 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +592 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EvalGuard instrumentation for LangChain + LangGraph.
|
|
3
|
+
*
|
|
4
|
+
* LangChain's instrumentation surface is `@langchain/core/callbacks`. The
|
|
5
|
+
* recommended integration shape is a class that extends `BaseCallbackHandler`
|
|
6
|
+
* and overrides `handleLLMStart` / `handleLLMEnd` (and friends). The same
|
|
7
|
+
* handler works across LangChain.js + LangGraph because LangGraph reuses
|
|
8
|
+
* LangChain's callback dispatching for node-level events.
|
|
9
|
+
*
|
|
10
|
+
* Two usage patterns:
|
|
11
|
+
*
|
|
12
|
+
* // 1. Pass directly to a chain/runnable
|
|
13
|
+
* import { ChatOpenAI } from "@langchain/openai";
|
|
14
|
+
* import { EvalGuardCallbackHandler } from "@evalguard/langchain";
|
|
15
|
+
*
|
|
16
|
+
* const handler = new EvalGuardCallbackHandler({
|
|
17
|
+
* apiKey: process.env.EVALGUARD_API_KEY!,
|
|
18
|
+
* projectId: "proj-123",
|
|
19
|
+
* });
|
|
20
|
+
* const model = new ChatOpenAI({ model: "gpt-4o", callbacks: [handler] });
|
|
21
|
+
*
|
|
22
|
+
* // 2. Or globally via env (auto-installed when present)
|
|
23
|
+
* import { autoInstall } from "@evalguard/langchain";
|
|
24
|
+
* autoInstall(); // reads EVALGUARD_API_KEY + EVALGUARD_PROJECT_ID
|
|
25
|
+
*
|
|
26
|
+
* Implementation notes:
|
|
27
|
+
* - We do NOT depend on `@langchain/core` at install time. The handler
|
|
28
|
+
* extends a duck-typed `BaseCallbackHandler` shape so the package
|
|
29
|
+
* compiles + tests without LangChain present. Customers get full types
|
|
30
|
+
* from their own `@langchain/core` install via TypeScript's module
|
|
31
|
+
* resolution.
|
|
32
|
+
* - Fail-CLOSED semantics match openai-wrapper / anthropic-wrapper /
|
|
33
|
+
* llamaindex-wrapper (changed 2026-05-28): when `blockOnViolation` is
|
|
34
|
+
* on (the default), an UNREACHABLE guardrail blocks the run rather
|
|
35
|
+
* than waving it through. Set `blockOnViolation: false` for
|
|
36
|
+
* monitor-only/availability-first deployments.
|
|
37
|
+
* - `blockOnViolation` raises `EvalguardBlockedError` from `handleLLMStart`,
|
|
38
|
+
* which aborts the run ONLY because this handler sets
|
|
39
|
+
* `raiseError = true` and `awaitHandlers = true` (see the class body).
|
|
40
|
+
* LangChain swallows handler throws by default. The customer catches
|
|
41
|
+
* via `try { await chain.invoke(...) } catch {}`. Verified end-to-end
|
|
42
|
+
* against @langchain/core@1.1.48 through `model.invoke`, `model.stream`
|
|
43
|
+
* and a `RunnableSequence` in
|
|
44
|
+
* `src/__tests__/blocking-enforcement.test.ts` — NOT by inspection.
|
|
45
|
+
* - Because `raiseError = true` makes every throw from this class abort
|
|
46
|
+
* the customer's run, the split is strict: the guardrail path is the
|
|
47
|
+
* ONLY thing allowed to throw. Prompt-extraction failure fails CLOSED
|
|
48
|
+
* (an unscannable prompt is rejected, never silently skipped); model-name
|
|
49
|
+
* resolution degrades to "unknown"; every logging hook is wrapped in
|
|
50
|
+
* `safeLog` so a trace-log failure can never bubble into the chain.
|
|
51
|
+
* - Options that cannot be honoured are rejected in the constructor
|
|
52
|
+
* (`EvalguardConfigError`) rather than accepted and ignored.
|
|
53
|
+
* - **OpenInference compatibility**: every trace emits a `openinference`
|
|
54
|
+
* sidecar with the standard `openinference.span.kind`, `llm.input_messages`,
|
|
55
|
+
* `llm.output_messages`, `llm.model_name`, `llm.token_count.*` attributes.
|
|
56
|
+
* This frees rendering in Phoenix / Arize / any OpenInference-aware viewer.
|
|
57
|
+
* - LangGraph: the same handler emits `chain` + `tool` + `agent` events
|
|
58
|
+
* so node-level activity in a graph shows up as nested spans, mirroring
|
|
59
|
+
* LangSmith's per-node evaluator surface.
|
|
60
|
+
*/
|
|
61
|
+
import { GuardrailClient } from "./guardrail-client.js";
|
|
62
|
+
import { collapseMessageText } from "@evalguard/wrapper-core";
|
|
63
|
+
import { estimateCostDetailed } from "./cost.js";
|
|
64
|
+
export class EvalguardBlockedError extends Error {
|
|
65
|
+
violations;
|
|
66
|
+
constructor(message, violations) {
|
|
67
|
+
super(message);
|
|
68
|
+
this.name = "EvalguardBlockedError";
|
|
69
|
+
this.violations = violations;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Thrown from the constructor when the supplied options cannot all be
|
|
74
|
+
* honoured. A security option that the handler is structurally unable to
|
|
75
|
+
* enforce must fail loudly at wiring time — silently accepting it is how
|
|
76
|
+
* a customer ends up believing they are protected when they are not.
|
|
77
|
+
*/
|
|
78
|
+
export class EvalguardConfigError extends Error {
|
|
79
|
+
constructor(message) {
|
|
80
|
+
super(message);
|
|
81
|
+
this.name = "EvalguardConfigError";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The handler keeps state per runId so async overlapping calls are tracked
|
|
86
|
+
* correctly. LangChain assigns each LLM/chain/tool invocation a unique runId
|
|
87
|
+
* (UUID) which is passed to every handle* method.
|
|
88
|
+
*/
|
|
89
|
+
export class EvalGuardCallbackHandler {
|
|
90
|
+
// BaseCallbackHandler's required `name` property (LangChain uses this to
|
|
91
|
+
// disambiguate handlers in stack traces). Set explicitly so callers
|
|
92
|
+
// adding multiple handlers can debug ordering.
|
|
93
|
+
name = "evalguard-handler";
|
|
94
|
+
// 2026-07-29 (audit A277): `blockOnViolation` was a COMPLETE no-op
|
|
95
|
+
// against real LangChain. `CallbackManager.handleLLMStart` /
|
|
96
|
+
// `handleChatModelStart` invoke each handler inside
|
|
97
|
+
// consumeCallback(async () => { try { await handler.handleLLMStart(...) }
|
|
98
|
+
// catch (err) { (handler.raiseError ? console.error : console.warn)(...);
|
|
99
|
+
// if (handler.raiseError) throw err; } }, handler.awaitHandlers)
|
|
100
|
+
// (@langchain/core@1.1.48 dist/callbacks/manager.js:294-301, :312-323).
|
|
101
|
+
//
|
|
102
|
+
// Because this class is duck-typed rather than extending
|
|
103
|
+
// BaseCallbackHandler, `raiseError` and `awaitHandlers` were both
|
|
104
|
+
// `undefined`, so:
|
|
105
|
+
// 1. awaitHandlers falsy → consumeCallback queued the guardrail check
|
|
106
|
+
// in the background and the LLM call proceeded WITHOUT waiting;
|
|
107
|
+
// 2. raiseError falsy → EvalguardBlockedError was console.warn'd
|
|
108
|
+
// and swallowed, so `chain.invoke()` resolved normally.
|
|
109
|
+
// A blocked prompt reached the model every time.
|
|
110
|
+
//
|
|
111
|
+
// Both flags are read off the handler instance by LangChain, so setting
|
|
112
|
+
// them here is the whole fix. They are declared unconditionally (not
|
|
113
|
+
// `blockOnViolation ? true : false`) because trace correctness also
|
|
114
|
+
// requires the start hook to complete before the LLM call — a
|
|
115
|
+
// background-queued handleLLMStart can lose the race with handleLLMEnd
|
|
116
|
+
// and drop the span.
|
|
117
|
+
awaitHandlers = true;
|
|
118
|
+
raiseError = true;
|
|
119
|
+
client;
|
|
120
|
+
config;
|
|
121
|
+
inflight = new Map();
|
|
122
|
+
blockOnViolation;
|
|
123
|
+
enableLogging;
|
|
124
|
+
enableGuardrails;
|
|
125
|
+
constructor(config) {
|
|
126
|
+
// `disableGuardrails` removes the only code path that can produce a
|
|
127
|
+
// block, so an EXPLICIT `blockOnViolation: true` alongside it can never
|
|
128
|
+
// be honoured. Accepting the pair silently is the same failure mode as
|
|
129
|
+
// the callback no-op this class was fixed for: the customer configures
|
|
130
|
+
// enforcement and gets none. Only the explicit combination is rejected —
|
|
131
|
+
// `disableGuardrails: true` on its own is a valid tracing-only setup.
|
|
132
|
+
if (config.disableGuardrails === true && config.blockOnViolation === true) {
|
|
133
|
+
throw new EvalguardConfigError("EvalGuard: `blockOnViolation: true` cannot be honoured together with " +
|
|
134
|
+
"`disableGuardrails: true` — with the firewall disabled there is nothing " +
|
|
135
|
+
"to block on. Drop one of the two options.");
|
|
136
|
+
}
|
|
137
|
+
this.config = config;
|
|
138
|
+
// wrapper-core's GuardrailClient takes a config object (not positional
|
|
139
|
+
// apiKey/baseUrl) — #40 convergence.
|
|
140
|
+
this.client = new GuardrailClient({ apiKey: config.apiKey, baseUrl: config.baseUrl });
|
|
141
|
+
this.blockOnViolation = config.blockOnViolation ?? true;
|
|
142
|
+
this.enableLogging = !config.disableLogging;
|
|
143
|
+
this.enableGuardrails = !config.disableGuardrails;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Called when an LLM (completion-style) starts. LangChain emits both
|
|
147
|
+
* `handleLLMStart` and `handleChatModelStart` — we cover both so the
|
|
148
|
+
* same handler works across `LLM` and `BaseChatModel` subclasses.
|
|
149
|
+
*/
|
|
150
|
+
async handleLLMStart(llm, prompts, runId, _parentRunId, extraParams) {
|
|
151
|
+
const model = this.safeResolveModel(llm, extraParams);
|
|
152
|
+
let prompt;
|
|
153
|
+
try {
|
|
154
|
+
prompt = prompts.join("\n");
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
return this.onUnreadablePrompt(runId, model, err);
|
|
158
|
+
}
|
|
159
|
+
await this.startRun(runId, prompt, model);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Called when a chat-style LLM (e.g. ChatOpenAI, ChatAnthropic) starts.
|
|
163
|
+
* `messages` is `BaseMessage[][]` — one inner array per parallel
|
|
164
|
+
* generation. We collapse EVERY role into a single prompt for the
|
|
165
|
+
* guardrail check (A287: user-only collapse hid tool results and
|
|
166
|
+
* retrieved documents from the firewall).
|
|
167
|
+
*/
|
|
168
|
+
async handleChatModelStart(llm, messages, runId, _parentRunId, extraParams) {
|
|
169
|
+
const model = this.safeResolveModel(llm, extraParams);
|
|
170
|
+
let prompt;
|
|
171
|
+
try {
|
|
172
|
+
prompt = collapseMessages(messages.flat());
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
return this.onUnreadablePrompt(runId, model, err);
|
|
176
|
+
}
|
|
177
|
+
await this.startRun(runId, prompt, model);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Called when the LLM finishes (success). Emits a trace with latency,
|
|
181
|
+
* token usage, cost, and OpenInference-compliant span attributes.
|
|
182
|
+
*/
|
|
183
|
+
async handleLLMEnd(output, runId) {
|
|
184
|
+
const run = this.inflight.get(runId);
|
|
185
|
+
if (!run)
|
|
186
|
+
return;
|
|
187
|
+
this.inflight.delete(runId);
|
|
188
|
+
if (!this.enableLogging)
|
|
189
|
+
return;
|
|
190
|
+
this.safeLog(() => {
|
|
191
|
+
const latencyMs = Math.round(performance.now() - run.startedAt);
|
|
192
|
+
const usage = output.llmOutput?.tokenUsage ?? {};
|
|
193
|
+
const inputTokens = usage.promptTokens ?? 0;
|
|
194
|
+
const outputTokens = usage.completionTokens ?? 0;
|
|
195
|
+
const completion = extractCompletion(output);
|
|
196
|
+
const model = output.llmOutput?.modelName ??
|
|
197
|
+
output.llmOutput?.model_name ??
|
|
198
|
+
output.llmOutput?.model ??
|
|
199
|
+
run.model;
|
|
200
|
+
const { costUsd: cost, pricingSource: costPricingSource } = estimateCostDetailed(model, inputTokens, outputTokens);
|
|
201
|
+
return {
|
|
202
|
+
model,
|
|
203
|
+
provider: "langchain",
|
|
204
|
+
input: run.prompt,
|
|
205
|
+
output: completion,
|
|
206
|
+
latencyMs,
|
|
207
|
+
tokenUsage: { input: inputTokens, output: outputTokens },
|
|
208
|
+
cost,
|
|
209
|
+
costPricingSource,
|
|
210
|
+
projectId: this.config.projectId,
|
|
211
|
+
metadata: this.config.metadata,
|
|
212
|
+
guardrailResult: run.guardrailResult,
|
|
213
|
+
openinference: buildOpenInferenceAttrs({
|
|
214
|
+
kind: "llm",
|
|
215
|
+
model,
|
|
216
|
+
input: run.prompt,
|
|
217
|
+
output: completion,
|
|
218
|
+
promptTokens: inputTokens,
|
|
219
|
+
completionTokens: outputTokens,
|
|
220
|
+
latencyMs,
|
|
221
|
+
}),
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Called when the LLM call errors. We still emit a trace so customers
|
|
227
|
+
* can see failed calls in the dashboard (latency + error type + model).
|
|
228
|
+
*/
|
|
229
|
+
async handleLLMError(err, runId) {
|
|
230
|
+
const run = this.inflight.get(runId);
|
|
231
|
+
if (!run)
|
|
232
|
+
return;
|
|
233
|
+
this.inflight.delete(runId);
|
|
234
|
+
if (!this.enableLogging)
|
|
235
|
+
return;
|
|
236
|
+
this.safeLog(() => {
|
|
237
|
+
const latencyMs = Math.round(performance.now() - run.startedAt);
|
|
238
|
+
const errorMessage = err instanceof Error ? err.message : String(err ?? "unknown error");
|
|
239
|
+
return {
|
|
240
|
+
model: run.model,
|
|
241
|
+
provider: "langchain",
|
|
242
|
+
input: run.prompt,
|
|
243
|
+
output: null,
|
|
244
|
+
latencyMs,
|
|
245
|
+
tokenUsage: { input: 0, output: 0 },
|
|
246
|
+
cost: 0,
|
|
247
|
+
projectId: this.config.projectId,
|
|
248
|
+
metadata: {
|
|
249
|
+
...this.config.metadata,
|
|
250
|
+
error: errorMessage,
|
|
251
|
+
errorKind: err instanceof Error ? err.name : "Unknown",
|
|
252
|
+
},
|
|
253
|
+
guardrailResult: run.guardrailResult,
|
|
254
|
+
openinference: buildOpenInferenceAttrs({
|
|
255
|
+
kind: "llm",
|
|
256
|
+
model: run.model,
|
|
257
|
+
input: run.prompt,
|
|
258
|
+
output: null,
|
|
259
|
+
promptTokens: 0,
|
|
260
|
+
completionTokens: 0,
|
|
261
|
+
latencyMs,
|
|
262
|
+
statusCode: "ERROR",
|
|
263
|
+
statusMessage: errorMessage,
|
|
264
|
+
}),
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Chain start — covers LangChain Runnables + LangGraph node entry.
|
|
270
|
+
* We log these as nested spans via OpenInference `chain` kind so the
|
|
271
|
+
* trace tree mirrors the customer's actual graph topology.
|
|
272
|
+
*/
|
|
273
|
+
async handleChainStart(chain, inputs, runId) {
|
|
274
|
+
if (!this.enableLogging)
|
|
275
|
+
return;
|
|
276
|
+
this.safeLog(() => ({
|
|
277
|
+
model: chain.name ?? "chain",
|
|
278
|
+
provider: "langchain",
|
|
279
|
+
input: inputs,
|
|
280
|
+
output: null,
|
|
281
|
+
latencyMs: 0,
|
|
282
|
+
tokenUsage: { input: 0, output: 0 },
|
|
283
|
+
cost: 0,
|
|
284
|
+
projectId: this.config.projectId,
|
|
285
|
+
metadata: {
|
|
286
|
+
...this.config.metadata,
|
|
287
|
+
runId,
|
|
288
|
+
spanKind: "chain.start",
|
|
289
|
+
},
|
|
290
|
+
openinference: buildOpenInferenceAttrs({
|
|
291
|
+
kind: "chain",
|
|
292
|
+
model: chain.name ?? "chain",
|
|
293
|
+
input: inputs,
|
|
294
|
+
}),
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Tool execution start (LangGraph node calling a tool). Treated as its
|
|
299
|
+
* own span so trajectory-style assertions can recover the tool-call
|
|
300
|
+
* sequence from the trace.
|
|
301
|
+
*/
|
|
302
|
+
async handleToolStart(tool, input, runId) {
|
|
303
|
+
if (!this.enableLogging)
|
|
304
|
+
return;
|
|
305
|
+
this.safeLog(() => ({
|
|
306
|
+
model: tool.name ?? "tool",
|
|
307
|
+
provider: "langchain",
|
|
308
|
+
input,
|
|
309
|
+
output: null,
|
|
310
|
+
latencyMs: 0,
|
|
311
|
+
tokenUsage: { input: 0, output: 0 },
|
|
312
|
+
cost: 0,
|
|
313
|
+
projectId: this.config.projectId,
|
|
314
|
+
metadata: {
|
|
315
|
+
...this.config.metadata,
|
|
316
|
+
runId,
|
|
317
|
+
spanKind: "tool.start",
|
|
318
|
+
toolName: tool.name,
|
|
319
|
+
},
|
|
320
|
+
openinference: buildOpenInferenceAttrs({
|
|
321
|
+
kind: "tool",
|
|
322
|
+
model: tool.name ?? "tool",
|
|
323
|
+
input,
|
|
324
|
+
}),
|
|
325
|
+
}));
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Agent action (LangChain agents + LangGraph). Captures the decided
|
|
329
|
+
* action so trajectory-grading metrics can score whether the action
|
|
330
|
+
* was the right next step.
|
|
331
|
+
*/
|
|
332
|
+
async handleAgentAction(action, runId) {
|
|
333
|
+
if (!this.enableLogging)
|
|
334
|
+
return;
|
|
335
|
+
this.safeLog(() => ({
|
|
336
|
+
model: action.tool,
|
|
337
|
+
provider: "langchain",
|
|
338
|
+
input: action.toolInput,
|
|
339
|
+
output: action.log ?? null,
|
|
340
|
+
latencyMs: 0,
|
|
341
|
+
tokenUsage: { input: 0, output: 0 },
|
|
342
|
+
cost: 0,
|
|
343
|
+
projectId: this.config.projectId,
|
|
344
|
+
metadata: {
|
|
345
|
+
...this.config.metadata,
|
|
346
|
+
runId,
|
|
347
|
+
spanKind: "agent.action",
|
|
348
|
+
decidedTool: action.tool,
|
|
349
|
+
},
|
|
350
|
+
openinference: buildOpenInferenceAttrs({
|
|
351
|
+
kind: "agent",
|
|
352
|
+
model: action.tool,
|
|
353
|
+
input: action.toolInput,
|
|
354
|
+
output: action.log ?? null,
|
|
355
|
+
}),
|
|
356
|
+
}));
|
|
357
|
+
}
|
|
358
|
+
/** Shared startup path for both `handleLLMStart` and `handleChatModelStart`. */
|
|
359
|
+
async startRun(runId, prompt, model) {
|
|
360
|
+
const startedAt = performance.now();
|
|
361
|
+
const run = { startedAt, prompt, model };
|
|
362
|
+
if (this.enableGuardrails && prompt) {
|
|
363
|
+
try {
|
|
364
|
+
const result = await this.client.checkInput(prompt, {
|
|
365
|
+
provider: "langchain",
|
|
366
|
+
model,
|
|
367
|
+
...this.config.metadata,
|
|
368
|
+
});
|
|
369
|
+
run.guardrailResult = result;
|
|
370
|
+
if (!result.allowed && this.blockOnViolation) {
|
|
371
|
+
// Throwing here aborts the LangChain run. Customers catch via
|
|
372
|
+
// `try { await chain.invoke(...) } catch (err) { ... }`.
|
|
373
|
+
throw new EvalguardBlockedError(`Request blocked by EvalGuard guardrails: ${result.violations
|
|
374
|
+
.map((v) => v.type)
|
|
375
|
+
.join(", ")}`, result.violations);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
catch (err) {
|
|
379
|
+
if (err instanceof EvalguardBlockedError)
|
|
380
|
+
throw err;
|
|
381
|
+
// 2026-05-28: previously silently fell through ("fail-open") on
|
|
382
|
+
// any guardrail outage — defeats blockOnViolation:true callers
|
|
383
|
+
// who expect fail-CLOSED. Per check.txt audit P1 fix, an
|
|
384
|
+
// unreachable guardrail now blocks the run when blockOnViolation
|
|
385
|
+
// is on; otherwise fall through to keep availability.
|
|
386
|
+
if (this.blockOnViolation) {
|
|
387
|
+
throw new EvalguardBlockedError(`Request blocked: guardrail unavailable (${err instanceof Error ? err.message : "unknown"})`, [{
|
|
388
|
+
type: "guardrail_unavailable",
|
|
389
|
+
severity: "high",
|
|
390
|
+
message: err instanceof Error ? err.message : "guardrail check failed",
|
|
391
|
+
}]);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
this.inflight.set(runId, run);
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Model name is trace METADATA, not a security input. A failure to
|
|
399
|
+
* resolve it must never abort the customer's run and must never skip the
|
|
400
|
+
* firewall — degrade to "unknown" and carry on to the scan.
|
|
401
|
+
*/
|
|
402
|
+
safeResolveModel(llm, extraParams) {
|
|
403
|
+
try {
|
|
404
|
+
return this.resolveModel(llm, extraParams);
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
return "unknown";
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* The prompt could not be read, so the firewall cannot see the bytes that
|
|
412
|
+
* are about to reach the model. Silently returning here (what this handler
|
|
413
|
+
* did until 2026-07-30) skipped the scan entirely and let the call through
|
|
414
|
+
* unguarded — a total bypass for any customer using a message class whose
|
|
415
|
+
* `_getType()`/content accessor throws.
|
|
416
|
+
*
|
|
417
|
+
* Fail CLOSED instead, with an explicit `prompt_unreadable` marker so the
|
|
418
|
+
* trace records that nothing was scanned. Note this is a REJECTION, not a
|
|
419
|
+
* shortened/partial scan: never hand the scanner less than the real input.
|
|
420
|
+
*/
|
|
421
|
+
async onUnreadablePrompt(runId, model, err) {
|
|
422
|
+
const detail = err instanceof Error ? err.message : String(err ?? "unknown error");
|
|
423
|
+
const violations = [
|
|
424
|
+
{
|
|
425
|
+
type: "prompt_unreadable",
|
|
426
|
+
severity: "high",
|
|
427
|
+
message: `EvalGuard could not extract the prompt for scanning: ${detail}`,
|
|
428
|
+
},
|
|
429
|
+
];
|
|
430
|
+
if (this.enableGuardrails && this.blockOnViolation) {
|
|
431
|
+
throw new EvalguardBlockedError(`Request blocked: EvalGuard could not read the prompt to scan it (${detail})`, violations);
|
|
432
|
+
}
|
|
433
|
+
// Monitor-only / guardrails-off: the call proceeds, but the trace must
|
|
434
|
+
// still say the input was never scanned.
|
|
435
|
+
this.inflight.set(runId, {
|
|
436
|
+
startedAt: performance.now(),
|
|
437
|
+
prompt: "",
|
|
438
|
+
model,
|
|
439
|
+
guardrailResult: { allowed: true, violations },
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Fire-and-forget trace logging that can NEVER throw into the customer's
|
|
444
|
+
* chain. This class sets `raiseError = true` so LangChain propagates our
|
|
445
|
+
* throws — that is required for a guardrail block to actually block, but
|
|
446
|
+
* it also means an incidental failure in a logging-only hook would abort a
|
|
447
|
+
* perfectly good LLM call. The published contract (README, "Outage
|
|
448
|
+
* semantics") is that a trace-log failure never bubbles into your chain;
|
|
449
|
+
* this is where that contract is enforced.
|
|
450
|
+
*
|
|
451
|
+
* `GuardrailClient.logTrace` already resolves to null on transport failure
|
|
452
|
+
* (wrapper-core `withRetry`), so this guards the synchronous payload
|
|
453
|
+
* construction and any future rejection path.
|
|
454
|
+
*/
|
|
455
|
+
safeLog(build) {
|
|
456
|
+
try {
|
|
457
|
+
void this.client.logTrace(build()).catch(() => {
|
|
458
|
+
/* trace logging never affects the customer's run */
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
catch {
|
|
462
|
+
/* trace logging never affects the customer's run */
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
resolveModel(llm, extraParams) {
|
|
466
|
+
// Best-effort model resolution across LangChain's varying serialized
|
|
467
|
+
// shapes. Order matters: kwargs.model is the most specific (set by
|
|
468
|
+
// ChatOpenAI/ChatAnthropic constructor), then extraParams.invocation_
|
|
469
|
+
// params.model (set on call), then the serialized id chain.
|
|
470
|
+
const kwModel = llm.kwargs?.["model"];
|
|
471
|
+
if (kwModel)
|
|
472
|
+
return kwModel;
|
|
473
|
+
const kwModelName = llm.kwargs?.["modelName"];
|
|
474
|
+
if (kwModelName)
|
|
475
|
+
return kwModelName;
|
|
476
|
+
const invParams = extraParams?.["invocation_params"];
|
|
477
|
+
const invModel = invParams?.["model"];
|
|
478
|
+
if (invModel)
|
|
479
|
+
return invModel;
|
|
480
|
+
if (llm.id && llm.id.length > 0)
|
|
481
|
+
return llm.id[llm.id.length - 1] ?? "unknown";
|
|
482
|
+
return llm.name ?? "unknown";
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Auto-install path for the lazy customer. Reads EVALGUARD_API_KEY from env.
|
|
487
|
+
* Returns the handler instance if installed; null if EVALGUARD_API_KEY is
|
|
488
|
+
* not set (no-op safe to call at module load).
|
|
489
|
+
*
|
|
490
|
+
* Usage:
|
|
491
|
+
*
|
|
492
|
+
* import { autoInstall } from "@evalguard/langchain";
|
|
493
|
+
* autoInstall();
|
|
494
|
+
*
|
|
495
|
+
* Then pass the returned handler to a Runnable's `callbacks` array, OR set
|
|
496
|
+
* the global LangChain callbacks via `setGlobalCallbacks([handler])` from
|
|
497
|
+
* `@langchain/core/callbacks/manager`.
|
|
498
|
+
*/
|
|
499
|
+
export function autoInstall() {
|
|
500
|
+
const apiKey = process.env["EVALGUARD_API_KEY"];
|
|
501
|
+
if (!apiKey)
|
|
502
|
+
return null;
|
|
503
|
+
return new EvalGuardCallbackHandler({
|
|
504
|
+
apiKey,
|
|
505
|
+
projectId: process.env["EVALGUARD_PROJECT_ID"],
|
|
506
|
+
baseUrl: process.env["EVALGUARD_BASE_URL"],
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
510
|
+
/**
|
|
511
|
+
* 2026-07-29 (audit A287): this used to `.filter(type === "human"|"user")`
|
|
512
|
+
* before handing text to the firewall, so `ToolMessage` results and
|
|
513
|
+
* retrieved RAG documents (which arrive as `tool`/`function`/`system`
|
|
514
|
+
* messages) were never scanned — the exact channels an agent-app attacker
|
|
515
|
+
* controls. It now delegates to wrapper-core's canonical
|
|
516
|
+
* `collapseMessageText`, which scans every role and is shared with the
|
|
517
|
+
* llamaindex and vercel-ai wrappers so the three copies cannot drift again.
|
|
518
|
+
*
|
|
519
|
+
* LangChain BaseMessages expose their role via `_getType()` rather than a
|
|
520
|
+
* `role` field, so normalize that here before delegating.
|
|
521
|
+
*/
|
|
522
|
+
function collapseMessages(messages) {
|
|
523
|
+
if (!messages || messages.length === 0)
|
|
524
|
+
return "";
|
|
525
|
+
const normalized = messages.map((m) => ({
|
|
526
|
+
role: typeof m._getType === "function" ? m._getType() : m.type,
|
|
527
|
+
content: m.content,
|
|
528
|
+
}));
|
|
529
|
+
return collapseMessageText(normalized);
|
|
530
|
+
}
|
|
531
|
+
function extractCompletion(output) {
|
|
532
|
+
const firstGeneration = output.generations[0]?.[0];
|
|
533
|
+
if (!firstGeneration)
|
|
534
|
+
return "";
|
|
535
|
+
if (firstGeneration.message?.content)
|
|
536
|
+
return firstGeneration.message.content;
|
|
537
|
+
return firstGeneration.text ?? "";
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Build OpenInference-compliant span attributes. OpenInference is the
|
|
541
|
+
* tracing semantic convention authored by Arize and adopted across the
|
|
542
|
+
* industry (Phoenix, Arize AX, OpenLLMetry). Emitting these attributes
|
|
543
|
+
* lets EvalGuard traces render natively in any OpenInference-aware
|
|
544
|
+
* viewer without conversion.
|
|
545
|
+
*
|
|
546
|
+
* Spec: https://github.com/Arize-ai/openinference/tree/main/spec
|
|
547
|
+
*/
|
|
548
|
+
function buildOpenInferenceAttrs(args) {
|
|
549
|
+
const attrs = {
|
|
550
|
+
"openinference.span.kind": args.kind.toUpperCase(),
|
|
551
|
+
"llm.model_name": args.model,
|
|
552
|
+
"input.value": stringifyForAttr(args.input),
|
|
553
|
+
};
|
|
554
|
+
if (args.output !== undefined) {
|
|
555
|
+
attrs["output.value"] = stringifyForAttr(args.output);
|
|
556
|
+
}
|
|
557
|
+
if (args.promptTokens != null) {
|
|
558
|
+
attrs["llm.token_count.prompt"] = args.promptTokens;
|
|
559
|
+
}
|
|
560
|
+
if (args.completionTokens != null) {
|
|
561
|
+
attrs["llm.token_count.completion"] = args.completionTokens;
|
|
562
|
+
}
|
|
563
|
+
if (args.promptTokens != null && args.completionTokens != null) {
|
|
564
|
+
attrs["llm.token_count.total"] = args.promptTokens + args.completionTokens;
|
|
565
|
+
}
|
|
566
|
+
if (args.statusCode)
|
|
567
|
+
attrs["status.code"] = args.statusCode;
|
|
568
|
+
if (args.statusMessage)
|
|
569
|
+
attrs["status.message"] = args.statusMessage;
|
|
570
|
+
return attrs;
|
|
571
|
+
}
|
|
572
|
+
function stringifyForAttr(value) {
|
|
573
|
+
if (value == null)
|
|
574
|
+
return "";
|
|
575
|
+
if (typeof value === "string")
|
|
576
|
+
return value;
|
|
577
|
+
try {
|
|
578
|
+
return JSON.stringify(value);
|
|
579
|
+
}
|
|
580
|
+
catch {
|
|
581
|
+
return String(value);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
// ── Cost estimation (public surface) ────────────────────────────────────────
|
|
585
|
+
// The README's "Cost estimates" section tells the customer to
|
|
586
|
+
// `import { estimateCostDetailed, isModelPriced } from "@evalguard/langchain"`.
|
|
587
|
+
// Until 2026-08-01 these lived only in `./cost.ts`, which is NOT an `exports`
|
|
588
|
+
// subpath, so that documented import resolved to nothing from the published
|
|
589
|
+
// tarball. The three SDK-shaped wrappers (openai / anthropic / gemini) already
|
|
590
|
+
// re-exported them; the three framework-shaped ones did not.
|
|
591
|
+
export { estimateCost, estimateCostDetailed, isModelPriced } from "./cost.js";
|
|
592
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|