@attest-ai/core 1.0.0-rc.1 → 1.0.0-rc.2
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/dist/cjs/index.cjs +285 -110
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +129 -24
- package/dist/cjs/proto/index.cjs +14 -0
- package/dist/cjs/proto/index.cjs.map +1 -1
- package/dist/cjs/proto/index.d.cts +74 -1
- package/dist/esm/cli.js +2 -2
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/index.d.ts +129 -24
- package/dist/esm/index.js +275 -109
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/proto/index.d.ts +74 -1
- package/dist/esm/proto/index.js +11 -0
- package/dist/esm/proto/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -54,6 +54,7 @@ __export(index_exports, {
|
|
|
54
54
|
GeminiAdapter: () => GeminiAdapter,
|
|
55
55
|
LangChainAdapter: () => LangChainAdapter,
|
|
56
56
|
ManualAdapter: () => ManualAdapter,
|
|
57
|
+
OTLPConversionError: () => OTLPConversionError,
|
|
57
58
|
OTelAdapter: () => OTelAdapter,
|
|
58
59
|
OUTCOME_FAIL: () => OUTCOME_FAIL,
|
|
59
60
|
OUTCOME_PASS: () => OUTCOME_PASS,
|
|
@@ -64,6 +65,8 @@ __export(index_exports, {
|
|
|
64
65
|
ProtocolDesyncError: () => ProtocolDesyncError,
|
|
65
66
|
ProtocolDiagnosticBuffer: () => ProtocolDiagnosticBuffer,
|
|
66
67
|
ProtocolError: () => ProtocolError,
|
|
68
|
+
REASON_BUDGET_EXHAUSTED: () => REASON_BUDGET_EXHAUSTED,
|
|
69
|
+
REASON_JUDGE_ABSTAINED: () => REASON_JUDGE_ABSTAINED,
|
|
67
70
|
REASON_MISSING_EVIDENCE: () => REASON_MISSING_EVIDENCE,
|
|
68
71
|
REASON_PROVIDER_NOT_CONFIGURED: () => REASON_PROVIDER_NOT_CONFIGURED,
|
|
69
72
|
REASON_PROVIDER_UNAVAILABLE: () => REASON_PROVIDER_UNAVAILABLE,
|
|
@@ -93,6 +96,7 @@ __export(index_exports, {
|
|
|
93
96
|
TraceTree: () => TraceTree,
|
|
94
97
|
VERSION: () => VERSION,
|
|
95
98
|
activeBuilder: () => activeBuilder,
|
|
99
|
+
addUsage: () => addUsage,
|
|
96
100
|
agent: () => agent,
|
|
97
101
|
agentId: () => agentId,
|
|
98
102
|
assertionId: () => assertionId,
|
|
@@ -105,11 +109,13 @@ __export(index_exports, {
|
|
|
105
109
|
executePluginAssertion: () => executePluginAssertion,
|
|
106
110
|
extractId: () => extractId,
|
|
107
111
|
extractResult: () => extractResult,
|
|
112
|
+
formatUsage: () => formatUsage,
|
|
108
113
|
getSampleRate: () => getSampleRate,
|
|
109
114
|
isSimulationMode: () => isSimulationMode,
|
|
110
115
|
layerForType: () => layerForType,
|
|
111
116
|
loadLabelsCSV: () => loadLabelsCSV,
|
|
112
117
|
loadLabelsJSONL: () => loadLabelsJSONL,
|
|
118
|
+
parseUsage: () => parseUsage,
|
|
113
119
|
previewLine: () => previewLine,
|
|
114
120
|
promptHash: () => promptHash,
|
|
115
121
|
renderAssertionFailure: () => renderAssertionFailure,
|
|
@@ -118,8 +124,11 @@ __export(index_exports, {
|
|
|
118
124
|
requireSimulationCapability: () => requireSimulationCapability,
|
|
119
125
|
resetConfig: () => resetConfig,
|
|
120
126
|
simulationEnvEnabled: () => simulationEnvEnabled,
|
|
127
|
+
sumUsage: () => sumUsage,
|
|
121
128
|
tier: () => tier,
|
|
122
|
-
traceId: () => traceId
|
|
129
|
+
traceId: () => traceId,
|
|
130
|
+
usageSummaryLine: () => usageSummaryLine,
|
|
131
|
+
zeroUsage: () => zeroUsage
|
|
123
132
|
});
|
|
124
133
|
module.exports = __toCommonJS(index_exports);
|
|
125
134
|
|
|
@@ -137,6 +146,8 @@ var REASON_PROVIDER_NOT_CONFIGURED = "provider_not_configured";
|
|
|
137
146
|
var REASON_SIMULATION = "simulation";
|
|
138
147
|
var REASON_MISSING_EVIDENCE = "missing_evidence";
|
|
139
148
|
var REASON_SHORT_CIRCUITED = "short_circuited";
|
|
149
|
+
var REASON_BUDGET_EXHAUSTED = "budget_exhausted";
|
|
150
|
+
var REASON_JUDGE_ABSTAINED = "judge_abstained";
|
|
140
151
|
var OUTCOME_PASS = "pass";
|
|
141
152
|
var OUTCOME_FAIL = "fail";
|
|
142
153
|
var OUTCOME_SKIP = "skip";
|
|
@@ -227,6 +238,12 @@ var ProtocolDesyncError = class extends Error {
|
|
|
227
238
|
this.diagnostics = diagnostics;
|
|
228
239
|
}
|
|
229
240
|
};
|
|
241
|
+
var OTLPConversionError = class extends Error {
|
|
242
|
+
constructor(message) {
|
|
243
|
+
super(message);
|
|
244
|
+
this.name = "OTLPConversionError";
|
|
245
|
+
}
|
|
246
|
+
};
|
|
230
247
|
|
|
231
248
|
// src/proto/diagnostics.ts
|
|
232
249
|
var DEFAULT_BUFFER_SIZE = 32;
|
|
@@ -333,8 +350,8 @@ function extractId(response) {
|
|
|
333
350
|
}
|
|
334
351
|
|
|
335
352
|
// src/version.ts
|
|
336
|
-
var VERSION = "1.0.0-rc.
|
|
337
|
-
var ENGINE_VERSION = "1.0.0-rc.
|
|
353
|
+
var VERSION = "1.0.0-rc.2";
|
|
354
|
+
var ENGINE_VERSION = "1.0.0-rc.2";
|
|
338
355
|
|
|
339
356
|
// src/engine-manager.ts
|
|
340
357
|
var import_node_child_process = require("child_process");
|
|
@@ -727,6 +744,76 @@ function resetConfig() {
|
|
|
727
744
|
_sampleRate = 0;
|
|
728
745
|
}
|
|
729
746
|
|
|
747
|
+
// src/usage.ts
|
|
748
|
+
var INT_FIELDS = [
|
|
749
|
+
"model_calls",
|
|
750
|
+
"judge_calls",
|
|
751
|
+
"input_tokens",
|
|
752
|
+
"output_tokens",
|
|
753
|
+
"cached_tokens",
|
|
754
|
+
"unpriced_calls",
|
|
755
|
+
"budget_refused"
|
|
756
|
+
];
|
|
757
|
+
var USD_FIELDS = ["cost_usd", "retry_cost_usd"];
|
|
758
|
+
function zeroUsage() {
|
|
759
|
+
return {
|
|
760
|
+
model_calls: 0,
|
|
761
|
+
judge_calls: 0,
|
|
762
|
+
input_tokens: 0,
|
|
763
|
+
output_tokens: 0,
|
|
764
|
+
cached_tokens: 0,
|
|
765
|
+
cost_usd: 0,
|
|
766
|
+
retry_cost_usd: 0,
|
|
767
|
+
unpriced_calls: 0,
|
|
768
|
+
budget_refused: 0
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
function addUsage(a, b) {
|
|
772
|
+
return {
|
|
773
|
+
model_calls: a.model_calls + b.model_calls,
|
|
774
|
+
judge_calls: a.judge_calls + b.judge_calls,
|
|
775
|
+
input_tokens: a.input_tokens + b.input_tokens,
|
|
776
|
+
output_tokens: a.output_tokens + b.output_tokens,
|
|
777
|
+
cached_tokens: a.cached_tokens + b.cached_tokens,
|
|
778
|
+
cost_usd: a.cost_usd + b.cost_usd,
|
|
779
|
+
retry_cost_usd: a.retry_cost_usd + b.retry_cost_usd,
|
|
780
|
+
unpriced_calls: a.unpriced_calls + b.unpriced_calls,
|
|
781
|
+
budget_refused: a.budget_refused + b.budget_refused
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function sumUsage(usages) {
|
|
785
|
+
let total = zeroUsage();
|
|
786
|
+
for (const u of usages) total = addUsage(total, u);
|
|
787
|
+
return total;
|
|
788
|
+
}
|
|
789
|
+
function parseUsage(raw) {
|
|
790
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
791
|
+
throw new TypeError(`evaluate_batch result: usage must be an object, got ${JSON.stringify(raw)}`);
|
|
792
|
+
}
|
|
793
|
+
const obj = raw;
|
|
794
|
+
const field = (name, integer) => {
|
|
795
|
+
const v = obj[name];
|
|
796
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v < 0 || integer && !Number.isInteger(v)) {
|
|
797
|
+
const kind = integer ? "a non-negative integer" : "a non-negative number";
|
|
798
|
+
throw new TypeError(`evaluate_batch result: usage.${name} must be ${kind}, got ${JSON.stringify(v)}`);
|
|
799
|
+
}
|
|
800
|
+
return v;
|
|
801
|
+
};
|
|
802
|
+
const ints = Object.fromEntries(INT_FIELDS.map((f) => [f, field(f, true)]));
|
|
803
|
+
const usd = Object.fromEntries(USD_FIELDS.map((f) => [f, field(f, false)]));
|
|
804
|
+
return { ...ints, ...usd };
|
|
805
|
+
}
|
|
806
|
+
function formatUsage(u) {
|
|
807
|
+
let line = `${u.model_calls} model calls \xB7 ${u.input_tokens + u.output_tokens} tokens (${u.cached_tokens} cached) \xB7 $${u.cost_usd.toFixed(4)} \xB7 retry cost $${u.retry_cost_usd.toFixed(4)}`;
|
|
808
|
+
if (u.budget_refused > 0) line += ` \xB7 ${u.budget_refused} calls refused by budget`;
|
|
809
|
+
if (u.unpriced_calls > 0) line += ` \xB7 ${u.unpriced_calls} unpriced calls not in $`;
|
|
810
|
+
return line;
|
|
811
|
+
}
|
|
812
|
+
function usageSummaryLine(u) {
|
|
813
|
+
if (u.model_calls === 0 && u.budget_refused === 0) return void 0;
|
|
814
|
+
return `attest usage: ${formatUsage(u)}`;
|
|
815
|
+
}
|
|
816
|
+
|
|
730
817
|
// src/client.ts
|
|
731
818
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
732
819
|
var DEFAULT_DIAGNOSTIC_BUFFER = 32;
|
|
@@ -980,14 +1067,15 @@ var AttestClient = class {
|
|
|
980
1067
|
}
|
|
981
1068
|
const params = {
|
|
982
1069
|
trace,
|
|
983
|
-
assertions: [...assertions]
|
|
1070
|
+
assertions: [...assertions],
|
|
1071
|
+
...options?.budget !== void 0 ? { budget: options.budget } : {}
|
|
984
1072
|
};
|
|
985
1073
|
const raw = await this.sendRequest(
|
|
986
1074
|
"evaluate_batch",
|
|
987
1075
|
params,
|
|
988
1076
|
options?.timeout
|
|
989
1077
|
);
|
|
990
|
-
return raw;
|
|
1078
|
+
return { ...raw, usage: parseUsage(raw["usage"]) };
|
|
991
1079
|
}
|
|
992
1080
|
async submitPluginResult(traceId2, pluginName, assertionId2, status, score, explanation, options) {
|
|
993
1081
|
const result = {
|
|
@@ -1175,11 +1263,14 @@ var AgentResult = class {
|
|
|
1175
1263
|
assertionResults;
|
|
1176
1264
|
totalCost;
|
|
1177
1265
|
totalDurationMs;
|
|
1178
|
-
|
|
1266
|
+
/** Attest model usage of the evaluation that produced this result. */
|
|
1267
|
+
usage;
|
|
1268
|
+
constructor(trace, assertionResults = [], totalCost = 0, totalDurationMs = 0, usage = zeroUsage()) {
|
|
1179
1269
|
this.trace = trace;
|
|
1180
1270
|
this.assertionResults = assertionResults.map(normalizeAssertionResult);
|
|
1181
1271
|
this.totalCost = totalCost;
|
|
1182
1272
|
this.totalDurationMs = totalDurationMs;
|
|
1273
|
+
this.usage = usage;
|
|
1183
1274
|
}
|
|
1184
1275
|
/** True if every assertion has status "pass". */
|
|
1185
1276
|
get passed() {
|
|
@@ -1358,7 +1449,8 @@ function appendJudgeMetadata(lines, meta) {
|
|
|
1358
1449
|
if (meta.rubric_version) {
|
|
1359
1450
|
rubric = `${rubric} @ ${meta.rubric_version}`;
|
|
1360
1451
|
}
|
|
1361
|
-
|
|
1452
|
+
const judge = meta.provider ? `${meta.provider}/${meta.model}` : meta.model;
|
|
1453
|
+
lines.push(` judge: ${judge} / ${rubric}`);
|
|
1362
1454
|
}
|
|
1363
1455
|
if (meta.prompt_hash) {
|
|
1364
1456
|
lines.push(` prompt: #${meta.prompt_hash}`);
|
|
@@ -1882,6 +1974,86 @@ var ExpectChain = class {
|
|
|
1882
1974
|
soft: opts?.soft ?? false
|
|
1883
1975
|
});
|
|
1884
1976
|
}
|
|
1977
|
+
// -- Layer 3: Behavior contracts (tool calls only, retries counted) --
|
|
1978
|
+
/**
|
|
1979
|
+
* Assert how many times a tool is called, per value of argument `per` when set.
|
|
1980
|
+
*
|
|
1981
|
+
* @example
|
|
1982
|
+
* ```ts
|
|
1983
|
+
* // fails with "issue_refund called 2× for order_id=O-1042 (max 1)"
|
|
1984
|
+
* expect(result).toolCardinality("issue_refund", { per: "order_id", atMost: 1 });
|
|
1985
|
+
* ```
|
|
1986
|
+
*/
|
|
1987
|
+
toolCardinality(tool, opts) {
|
|
1988
|
+
if (opts.atMost === void 0 && opts.atLeast === void 0) {
|
|
1989
|
+
throw new Error("toolCardinality needs atMost, atLeast or both");
|
|
1990
|
+
}
|
|
1991
|
+
const spec = { check: "tool_cardinality", tool };
|
|
1992
|
+
if (opts.per !== void 0) spec.per = opts.per;
|
|
1993
|
+
if (opts.atLeast !== void 0) spec.min = opts.atLeast;
|
|
1994
|
+
if (opts.atMost !== void 0) spec.max = opts.atMost;
|
|
1995
|
+
spec.soft = opts.soft ?? false;
|
|
1996
|
+
return this.add(TYPE_TRACE, spec);
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Assert the tool-call trajectory matches `tools`: `strict` (same sequence,
|
|
2000
|
+
* the default), `unordered` (same calls, any order), `subset` (no call
|
|
2001
|
+
* outside `tools`) or `superset` (every call in `tools` made). Use
|
|
2002
|
+
* {@link trajectoryPartialOrder} for ordering constraints.
|
|
2003
|
+
*/
|
|
2004
|
+
trajectory(tools, opts) {
|
|
2005
|
+
return this.add(TYPE_TRACE, {
|
|
2006
|
+
check: "trajectory",
|
|
2007
|
+
mode: opts?.mode ?? "strict",
|
|
2008
|
+
tools,
|
|
2009
|
+
soft: opts?.soft ?? false
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* Assert every tool in `tools` and `order` is called and each
|
|
2014
|
+
* `[before, after]` pair holds as in {@link toolCalledBefore}.
|
|
2015
|
+
*/
|
|
2016
|
+
trajectoryPartialOrder(order, opts) {
|
|
2017
|
+
const spec = {
|
|
2018
|
+
check: "trajectory",
|
|
2019
|
+
mode: "partial_order",
|
|
2020
|
+
order: order.map(([before, after]) => [before, after])
|
|
2021
|
+
};
|
|
2022
|
+
if (opts?.tools !== void 0) spec.tools = opts.tools;
|
|
2023
|
+
spec.soft = opts?.soft ?? false;
|
|
2024
|
+
return this.add(TYPE_TRACE, spec);
|
|
2025
|
+
}
|
|
2026
|
+
/** Assert every call to `after` has an earlier call to `before`; holds when `after` is never called. */
|
|
2027
|
+
toolCalledBefore(before, after, opts) {
|
|
2028
|
+
return this.add(TYPE_TRACE, { check: "tool_order", before, after, soft: opts?.soft ?? false });
|
|
2029
|
+
}
|
|
2030
|
+
/** Assert no block of `period` (1–4) tool calls repeats `minRepeats` (default 2) times in a row; A→B→A→B fails period 2. */
|
|
2031
|
+
noToolCycles(period, opts) {
|
|
2032
|
+
return this.add(TYPE_TRACE, {
|
|
2033
|
+
check: "cycle",
|
|
2034
|
+
period,
|
|
2035
|
+
min_repeats: opts?.minRepeats ?? 2,
|
|
2036
|
+
soft: opts?.soft ?? false
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
/** Assert at most `maxStreak` consecutive tool calls end in error (trace v2). */
|
|
2040
|
+
maxToolFailureStreak(maxStreak, opts) {
|
|
2041
|
+
return this.add(TYPE_TRACE, { check: "failure_streak", max: maxStreak, soft: opts?.soft ?? false });
|
|
2042
|
+
}
|
|
2043
|
+
/**
|
|
2044
|
+
* Assert every call to `tool` has argument `arg` (a dot path) satisfying
|
|
2045
|
+
* `op value`; holds when `tool` is never called.
|
|
2046
|
+
*/
|
|
2047
|
+
toolArgSatisfies(tool, arg, op, value, opts) {
|
|
2048
|
+
return this.add(TYPE_TRACE, {
|
|
2049
|
+
check: "arg_predicate",
|
|
2050
|
+
tool,
|
|
2051
|
+
arg,
|
|
2052
|
+
op,
|
|
2053
|
+
value,
|
|
2054
|
+
soft: opts?.soft ?? false
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
1885
2057
|
// -- Layer 4: Content --
|
|
1886
2058
|
/**
|
|
1887
2059
|
* Assert the output message contains the given string.
|
|
@@ -3052,119 +3224,113 @@ var OllamaAdapter = class {
|
|
|
3052
3224
|
};
|
|
3053
3225
|
|
|
3054
3226
|
// src/adapters/otel.ts
|
|
3227
|
+
var import_node_child_process2 = require("child_process");
|
|
3228
|
+
var CONVERT_TIMEOUT_MS = 6e4;
|
|
3229
|
+
var MAX_TRACE_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
3230
|
+
var STATUS_CODE_ERROR = 2;
|
|
3055
3231
|
var OTelAdapter = class _OTelAdapter {
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3232
|
+
/**
|
|
3233
|
+
* Build a trace from finished OpenTelemetry spans of one trace.
|
|
3234
|
+
*
|
|
3235
|
+
* @param agentId Trace `agent_id`; defaults to the first turn's `gen_ai.agent.name`.
|
|
3236
|
+
* @throws OTLPConversionError when the engine rejects the spans.
|
|
3237
|
+
*/
|
|
3238
|
+
static async fromSpans(spans, agentId2) {
|
|
3239
|
+
return _OTelAdapter.fromOtlp(spansToOtlp(spans), agentId2);
|
|
3063
3240
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3241
|
+
/**
|
|
3242
|
+
* Convert an OTLP/JSON export (`resourceSpans` → `scopeSpans` → `spans`).
|
|
3243
|
+
*
|
|
3244
|
+
* @param agentId Trace `agent_id`; defaults to the first turn's `gen_ai.agent.name`.
|
|
3245
|
+
* @throws OTLPConversionError when the engine rejects the export (malformed JSON, invalid
|
|
3246
|
+
* ids or timestamps, more than one trace, non-numeric token counts, ...).
|
|
3247
|
+
* @throws RangeError when a parsed export holds a non-finite number.
|
|
3248
|
+
* @throws OTLPConversionError when the engine times out, overflows the output buffer or
|
|
3249
|
+
* prints no trace.
|
|
3250
|
+
* @throws Error from `spawnSync` when the engine cannot start.
|
|
3251
|
+
*/
|
|
3252
|
+
static async fromOtlp(otlp, agentId2) {
|
|
3253
|
+
const payload = typeof otlp === "string" || otlp instanceof Uint8Array ? otlp : JSON.stringify(otlp, (_key, v) => {
|
|
3254
|
+
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
3255
|
+
throw new RangeError(`OTLP export holds a non-finite number: ${String(v)}`);
|
|
3256
|
+
}
|
|
3257
|
+
return v;
|
|
3069
3258
|
});
|
|
3070
|
-
const
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3259
|
+
const args = ["trace", "convert"];
|
|
3260
|
+
if (agentId2 !== void 0) args.push("--agent-id", agentId2);
|
|
3261
|
+
args.push("-");
|
|
3262
|
+
const proc = (0, import_node_child_process2.spawnSync)(await resolveEngine(), args, {
|
|
3263
|
+
input: payload,
|
|
3264
|
+
timeout: CONVERT_TIMEOUT_MS,
|
|
3265
|
+
maxBuffer: MAX_TRACE_OUTPUT_BYTES
|
|
3266
|
+
});
|
|
3267
|
+
if (proc.error) {
|
|
3268
|
+
const code = proc.error.code;
|
|
3269
|
+
if (code === "ETIMEDOUT") {
|
|
3270
|
+
throw new OTLPConversionError(
|
|
3271
|
+
`attest-engine trace convert timed out after ${CONVERT_TIMEOUT_MS / 1e3}s`
|
|
3272
|
+
);
|
|
3076
3273
|
}
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
let model;
|
|
3082
|
-
for (const span of sorted) {
|
|
3083
|
-
const attrs = span.attributes ?? {};
|
|
3084
|
-
const stepType = this.classifySpan(attrs, span.name);
|
|
3085
|
-
if (stepType === "llm_call") {
|
|
3086
|
-
const [stepArgs, stepResult] = this.extractLlmStep(attrs);
|
|
3087
|
-
builder.addLlmCall(span.name, {
|
|
3088
|
-
args: stepArgs,
|
|
3089
|
-
result: stepResult,
|
|
3090
|
-
metadata: this.spanMetadata(span)
|
|
3091
|
-
});
|
|
3092
|
-
const completion = attrs["gen_ai.completion"];
|
|
3093
|
-
if (completion) outputMessage = String(completion);
|
|
3094
|
-
const inputTokens = Number(attrs["gen_ai.usage.input_tokens"] ?? 0);
|
|
3095
|
-
const outputTokens = Number(attrs["gen_ai.usage.output_tokens"] ?? 0);
|
|
3096
|
-
const spanTokens = inputTokens + outputTokens;
|
|
3097
|
-
if (spanTokens > 0) totalTokens = (totalTokens ?? 0) + spanTokens;
|
|
3098
|
-
if (model === void 0) {
|
|
3099
|
-
const responseModel = attrs["gen_ai.response.model"];
|
|
3100
|
-
const requestModel = attrs["gen_ai.request.model"];
|
|
3101
|
-
if (responseModel) model = String(responseModel);
|
|
3102
|
-
else if (requestModel) model = String(requestModel);
|
|
3103
|
-
}
|
|
3104
|
-
} else if (stepType === "tool_call") {
|
|
3105
|
-
const [stepArgs, stepResult] = this.extractToolStep(attrs);
|
|
3106
|
-
const toolName = String(attrs["gen_ai.tool.name"] ?? span.name);
|
|
3107
|
-
builder.addToolCall(toolName, {
|
|
3108
|
-
args: stepArgs,
|
|
3109
|
-
result: stepResult,
|
|
3110
|
-
metadata: this.spanMetadata(span)
|
|
3111
|
-
});
|
|
3274
|
+
if (code === "ENOBUFS") {
|
|
3275
|
+
throw new OTLPConversionError(
|
|
3276
|
+
`attest-engine trace convert printed more than ${MAX_TRACE_OUTPUT_BYTES} bytes`
|
|
3277
|
+
);
|
|
3112
3278
|
}
|
|
3279
|
+
throw proc.error;
|
|
3113
3280
|
}
|
|
3114
|
-
if (
|
|
3115
|
-
const
|
|
3116
|
-
|
|
3117
|
-
|
|
3281
|
+
if (proc.status !== 0) {
|
|
3282
|
+
const message = proc.stderr.toString("utf8").trim();
|
|
3283
|
+
throw new OTLPConversionError(
|
|
3284
|
+
message || `attest-engine trace convert exited ${String(proc.status ?? proc.signal)}`
|
|
3285
|
+
);
|
|
3118
3286
|
}
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
if (!span.parentSpanId) return span;
|
|
3287
|
+
try {
|
|
3288
|
+
return JSON.parse(proc.stdout.toString("utf8"));
|
|
3289
|
+
} catch (err) {
|
|
3290
|
+
throw new OTLPConversionError(
|
|
3291
|
+
`attest-engine trace convert printed output that is not JSON: ${String(err)}`
|
|
3292
|
+
);
|
|
3126
3293
|
}
|
|
3127
|
-
return spans[0];
|
|
3128
3294
|
}
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
}
|
|
3134
|
-
if (op === "tool" || "gen_ai.tool.name" in attrs) {
|
|
3135
|
-
return "tool_call";
|
|
3136
|
-
}
|
|
3137
|
-
const lower = name.toLowerCase();
|
|
3138
|
-
if (lower.includes("completion") || lower.includes("chat")) return "llm_call";
|
|
3139
|
-
if (lower.includes("tool")) return "tool_call";
|
|
3140
|
-
return void 0;
|
|
3295
|
+
};
|
|
3296
|
+
function hrTimeToNanos(time, spanName) {
|
|
3297
|
+
if (!Number.isSafeInteger(time[0]) || !Number.isSafeInteger(time[1])) {
|
|
3298
|
+
throw new RangeError(`span ${JSON.stringify(spanName)} has a non-integer HrTime`);
|
|
3141
3299
|
}
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
if (
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
return
|
|
3153
|
-
}
|
|
3154
|
-
extractToolStep(attrs) {
|
|
3155
|
-
const args = {};
|
|
3156
|
-
const result = {};
|
|
3157
|
-
if ("gen_ai.tool.call.id" in attrs) args.call_id = String(attrs["gen_ai.tool.call.id"]);
|
|
3158
|
-
if ("gen_ai.tool.parameters" in attrs) args.parameters = attrs["gen_ai.tool.parameters"];
|
|
3159
|
-
if ("gen_ai.tool.output" in attrs) result.output = attrs["gen_ai.tool.output"];
|
|
3160
|
-
return [args, result];
|
|
3161
|
-
}
|
|
3162
|
-
spanMetadata(span) {
|
|
3163
|
-
const startNs = span.startTime[0] * 1e9 + span.startTime[1];
|
|
3164
|
-
const endNs = span.endTime[0] * 1e9 + span.endTime[1];
|
|
3165
|
-
return { duration_ms: Math.floor((endNs - startNs) / 1e6) };
|
|
3300
|
+
return (BigInt(time[0]) * 1000000000n + BigInt(time[1])).toString();
|
|
3301
|
+
}
|
|
3302
|
+
function anyValue(value) {
|
|
3303
|
+
if (value === null || value === void 0) return {};
|
|
3304
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
3305
|
+
if (typeof value === "string") return { stringValue: value };
|
|
3306
|
+
if (typeof value === "number") {
|
|
3307
|
+
if (!Number.isFinite(value)) {
|
|
3308
|
+
throw new RangeError(`OTel attribute value must be finite, got ${String(value)}`);
|
|
3309
|
+
}
|
|
3310
|
+
return Number.isSafeInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
3166
3311
|
}
|
|
3167
|
-
};
|
|
3312
|
+
return { arrayValue: { values: value.map((v) => anyValue(v)) } };
|
|
3313
|
+
}
|
|
3314
|
+
function spansToOtlp(spans) {
|
|
3315
|
+
const encoded = spans.map((span) => {
|
|
3316
|
+
const ctx = span.spanContext();
|
|
3317
|
+
const out = {
|
|
3318
|
+
traceId: ctx.traceId,
|
|
3319
|
+
spanId: ctx.spanId,
|
|
3320
|
+
name: span.name,
|
|
3321
|
+
startTimeUnixNano: hrTimeToNanos(span.startTime, span.name),
|
|
3322
|
+
endTimeUnixNano: hrTimeToNanos(span.endTime, span.name),
|
|
3323
|
+
attributes: Object.entries(span.attributes ?? {}).filter(([, v]) => v !== void 0).map(([key, v]) => ({ key, value: anyValue(v) }))
|
|
3324
|
+
};
|
|
3325
|
+
const parent = span.parentSpanContext?.spanId ?? span.parentSpanId;
|
|
3326
|
+
if (parent) out["parentSpanId"] = parent;
|
|
3327
|
+
if (span.status?.code === STATUS_CODE_ERROR) {
|
|
3328
|
+
out["status"] = { code: STATUS_CODE_ERROR, message: span.status.message ?? "" };
|
|
3329
|
+
}
|
|
3330
|
+
return out;
|
|
3331
|
+
});
|
|
3332
|
+
return { resourceSpans: [{ scopeSpans: [{ spans: encoded }] }] };
|
|
3333
|
+
}
|
|
3168
3334
|
|
|
3169
3335
|
// src/adapters/langchain.ts
|
|
3170
3336
|
var LangChainAdapter = class {
|
|
@@ -3288,6 +3454,7 @@ var LangChainAdapter = class {
|
|
|
3288
3454
|
GeminiAdapter,
|
|
3289
3455
|
LangChainAdapter,
|
|
3290
3456
|
ManualAdapter,
|
|
3457
|
+
OTLPConversionError,
|
|
3291
3458
|
OTelAdapter,
|
|
3292
3459
|
OUTCOME_FAIL,
|
|
3293
3460
|
OUTCOME_PASS,
|
|
@@ -3298,6 +3465,8 @@ var LangChainAdapter = class {
|
|
|
3298
3465
|
ProtocolDesyncError,
|
|
3299
3466
|
ProtocolDiagnosticBuffer,
|
|
3300
3467
|
ProtocolError,
|
|
3468
|
+
REASON_BUDGET_EXHAUSTED,
|
|
3469
|
+
REASON_JUDGE_ABSTAINED,
|
|
3301
3470
|
REASON_MISSING_EVIDENCE,
|
|
3302
3471
|
REASON_PROVIDER_NOT_CONFIGURED,
|
|
3303
3472
|
REASON_PROVIDER_UNAVAILABLE,
|
|
@@ -3327,6 +3496,7 @@ var LangChainAdapter = class {
|
|
|
3327
3496
|
TraceTree,
|
|
3328
3497
|
VERSION,
|
|
3329
3498
|
activeBuilder,
|
|
3499
|
+
addUsage,
|
|
3330
3500
|
agent,
|
|
3331
3501
|
agentId,
|
|
3332
3502
|
assertionId,
|
|
@@ -3339,11 +3509,13 @@ var LangChainAdapter = class {
|
|
|
3339
3509
|
executePluginAssertion,
|
|
3340
3510
|
extractId,
|
|
3341
3511
|
extractResult,
|
|
3512
|
+
formatUsage,
|
|
3342
3513
|
getSampleRate,
|
|
3343
3514
|
isSimulationMode,
|
|
3344
3515
|
layerForType,
|
|
3345
3516
|
loadLabelsCSV,
|
|
3346
3517
|
loadLabelsJSONL,
|
|
3518
|
+
parseUsage,
|
|
3347
3519
|
previewLine,
|
|
3348
3520
|
promptHash,
|
|
3349
3521
|
renderAssertionFailure,
|
|
@@ -3352,7 +3524,10 @@ var LangChainAdapter = class {
|
|
|
3352
3524
|
requireSimulationCapability,
|
|
3353
3525
|
resetConfig,
|
|
3354
3526
|
simulationEnvEnabled,
|
|
3527
|
+
sumUsage,
|
|
3355
3528
|
tier,
|
|
3356
|
-
traceId
|
|
3529
|
+
traceId,
|
|
3530
|
+
usageSummaryLine,
|
|
3531
|
+
zeroUsage
|
|
3357
3532
|
});
|
|
3358
3533
|
//# sourceMappingURL=index.cjs.map
|