@frugalco/frugal-sdk-node 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/LICENSE +201 -0
- package/README.md +227 -0
- package/dist/block-hash-lru.d.ts +18 -0
- package/dist/block-hash-lru.d.ts.map +1 -0
- package/dist/block-hash-lru.js +48 -0
- package/dist/block-hash-lru.js.map +1 -0
- package/dist/caller.d.ts +23 -0
- package/dist/caller.d.ts.map +1 -0
- package/dist/caller.js +204 -0
- package/dist/caller.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +165 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/instrument.d.ts +49 -0
- package/dist/instrument.d.ts.map +1 -0
- package/dist/instrument.js +194 -0
- package/dist/instrument.js.map +1 -0
- package/dist/otel.d.ts +27 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +211 -0
- package/dist/otel.js.map +1 -0
- package/dist/prompt-analyzer.d.ts +26 -0
- package/dist/prompt-analyzer.d.ts.map +1 -0
- package/dist/prompt-analyzer.js +210 -0
- package/dist/prompt-analyzer.js.map +1 -0
- package/dist/semconv.d.ts +52 -0
- package/dist/semconv.d.ts.map +1 -0
- package/dist/semconv.js +53 -0
- package/dist/semconv.js.map +1 -0
- package/dist/streams.d.ts +21 -0
- package/dist/streams.d.ts.map +1 -0
- package/dist/streams.js +85 -0
- package/dist/streams.js.map +1 -0
- package/dist/track.d.ts +44 -0
- package/dist/track.d.ts.map +1 -0
- package/dist/track.js +170 -0
- package/dist/track.js.map +1 -0
- package/dist/wrappers/anthropic.d.ts +2 -0
- package/dist/wrappers/anthropic.d.ts.map +1 -0
- package/dist/wrappers/anthropic.js +229 -0
- package/dist/wrappers/anthropic.js.map +1 -0
- package/dist/wrappers/bedrock-models.d.ts +26 -0
- package/dist/wrappers/bedrock-models.d.ts.map +1 -0
- package/dist/wrappers/bedrock-models.js +320 -0
- package/dist/wrappers/bedrock-models.js.map +1 -0
- package/dist/wrappers/bedrock.d.ts +2 -0
- package/dist/wrappers/bedrock.d.ts.map +1 -0
- package/dist/wrappers/bedrock.js +284 -0
- package/dist/wrappers/bedrock.js.map +1 -0
- package/dist/wrappers/openai.d.ts +2 -0
- package/dist/wrappers/openai.d.ts.map +1 -0
- package/dist/wrappers/openai.js +347 -0
- package/dist/wrappers/openai.js.map +1 -0
- package/package.json +60 -0
package/dist/caller.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// Stack walking to resolve the call site of a wrapped AI call.
|
|
2
|
+
//
|
|
3
|
+
// Uses V8's Error.prepareStackTrace to get structured CallSite objects rather
|
|
4
|
+
// than regex-parsing stack strings. Walks upward from the wrapper frame until
|
|
5
|
+
// we find a frame whose source file is not (a) inside our own package, (b)
|
|
6
|
+
// inside the wrapped SDK package, or (c) under any FRUGAL_PATH_BLOCK_LIST
|
|
7
|
+
// prefix. Returns the file relative to FRUGAL_REPO_ROOT plus the function
|
|
8
|
+
// name.
|
|
9
|
+
//
|
|
10
|
+
// Performance: realpath results and full caller resolutions are cached so the
|
|
11
|
+
// stack walk and path resolution only happen once per unique call site.
|
|
12
|
+
// Subsequent calls from the same site are a Map.get() lookup.
|
|
13
|
+
import { realpathSync } from "node:fs";
|
|
14
|
+
import { sep } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { CALLER_FILE_EXTERNAL, CALLER_FILE_UNKNOWN, CALLER_OVERFLOW, } from "./semconv.js";
|
|
17
|
+
const CACHE_MAX_SIZE = 10_000;
|
|
18
|
+
// filename → realpath
|
|
19
|
+
const realpathCache = new Map();
|
|
20
|
+
// "filename\0functionName" → CallerInfo | null (null = skip this frame)
|
|
21
|
+
const callerCache = new Map();
|
|
22
|
+
// Cardinality cap state — first-come-first-served. Once `seenCallSites` hits
|
|
23
|
+
// the configured max, subsequent unseen pairs overflow (partial if the file
|
|
24
|
+
// is already known, full otherwise).
|
|
25
|
+
const seenCallSites = new Set();
|
|
26
|
+
const seenFiles = new Set();
|
|
27
|
+
let capHitNotified = false;
|
|
28
|
+
let capHitPending = false;
|
|
29
|
+
export function resolveCaller(args) {
|
|
30
|
+
const frames = captureCallSites(args.skipFrames ?? 1);
|
|
31
|
+
for (const frame of frames) {
|
|
32
|
+
const raw = frame.getFileName();
|
|
33
|
+
if (!raw)
|
|
34
|
+
continue;
|
|
35
|
+
const fnName = frame.getFunctionName() ?? frame.getMethodName() ?? "<anonymous>";
|
|
36
|
+
// Fast path: check caller cache before any path work.
|
|
37
|
+
const cacheKey = raw + "\0" + fnName;
|
|
38
|
+
const cached = callerCache.get(cacheKey);
|
|
39
|
+
if (cached !== undefined) {
|
|
40
|
+
if (cached === null)
|
|
41
|
+
continue; // known skip frame
|
|
42
|
+
return cached;
|
|
43
|
+
}
|
|
44
|
+
const filename = cachedNormalize(raw);
|
|
45
|
+
if (isInAny(filename, args.skipPackageDirs)) {
|
|
46
|
+
cachePut(cacheKey, null);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const rel = repoRelative(filename, args.repoRoot);
|
|
50
|
+
if (rel !== null && isBlocked(rel, args.blockList)) {
|
|
51
|
+
cachePut(cacheKey, null);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const resolvedFile = rel === null ? CALLER_FILE_EXTERNAL : rel;
|
|
55
|
+
const result = applyCap(resolvedFile, fnName, args.maxCallSites);
|
|
56
|
+
cachePut(cacheKey, result);
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
return { file: CALLER_FILE_UNKNOWN, function: "<unknown>" };
|
|
60
|
+
}
|
|
61
|
+
function applyCap(file, fn, maxCallSites) {
|
|
62
|
+
if (maxCallSites <= 0) {
|
|
63
|
+
return { file, function: fn };
|
|
64
|
+
}
|
|
65
|
+
const key = file + "\0" + fn;
|
|
66
|
+
if (seenCallSites.has(key)) {
|
|
67
|
+
return { file, function: fn };
|
|
68
|
+
}
|
|
69
|
+
if (seenCallSites.size < maxCallSites) {
|
|
70
|
+
seenCallSites.add(key);
|
|
71
|
+
seenFiles.add(file);
|
|
72
|
+
return { file, function: fn };
|
|
73
|
+
}
|
|
74
|
+
// At cap — soft overflow: keep file if we've seen it, else collapse both.
|
|
75
|
+
if (!capHitNotified) {
|
|
76
|
+
capHitNotified = true;
|
|
77
|
+
capHitPending = true;
|
|
78
|
+
}
|
|
79
|
+
if (seenFiles.has(file)) {
|
|
80
|
+
return { file, function: CALLER_OVERFLOW };
|
|
81
|
+
}
|
|
82
|
+
return { file: CALLER_OVERFLOW, function: CALLER_OVERFLOW };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Returns true iff a cardinality cap was crossed since the last call.
|
|
86
|
+
* Designed to be called once per `startCall` so the instrument layer can
|
|
87
|
+
* emit a single `frugal.gen_ai.internal_errors{stage=cardinality_cap_hit}`.
|
|
88
|
+
*/
|
|
89
|
+
export function consumeCapHitEvent() {
|
|
90
|
+
if (capHitPending) {
|
|
91
|
+
capHitPending = false;
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function captureCallSites(skipFrames) {
|
|
97
|
+
const originalPrepare = Error.prepareStackTrace;
|
|
98
|
+
const originalLimit = Error.stackTraceLimit;
|
|
99
|
+
try {
|
|
100
|
+
Error.stackTraceLimit = 20;
|
|
101
|
+
Error.prepareStackTrace = (_err, sites) => sites;
|
|
102
|
+
const holder = {};
|
|
103
|
+
Error.captureStackTrace(holder, captureCallSites);
|
|
104
|
+
const sites = holder.stack ?? [];
|
|
105
|
+
return sites.slice(skipFrames);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
Error.prepareStackTrace = originalPrepare;
|
|
109
|
+
Error.stackTraceLimit = originalLimit;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function cachedNormalize(filename) {
|
|
113
|
+
const hit = realpathCache.get(filename);
|
|
114
|
+
if (hit !== undefined)
|
|
115
|
+
return hit;
|
|
116
|
+
const resolved = normalize(filename);
|
|
117
|
+
if (realpathCache.size < CACHE_MAX_SIZE) {
|
|
118
|
+
realpathCache.set(filename, resolved);
|
|
119
|
+
}
|
|
120
|
+
return resolved;
|
|
121
|
+
}
|
|
122
|
+
function normalize(filename) {
|
|
123
|
+
let f = filename;
|
|
124
|
+
if (f.startsWith("file://")) {
|
|
125
|
+
try {
|
|
126
|
+
f = fileURLToPath(f);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// leave as-is
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
return realpathSync(f);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return f;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function cachePut(key, value) {
|
|
140
|
+
if (callerCache.size < CACHE_MAX_SIZE) {
|
|
141
|
+
callerCache.set(key, value);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function isInAny(filename, dirs) {
|
|
145
|
+
for (const d of dirs) {
|
|
146
|
+
if (!d)
|
|
147
|
+
continue;
|
|
148
|
+
const withSep = d.endsWith(sep) ? d : d + sep;
|
|
149
|
+
if (filename === d || filename.startsWith(withSep))
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
function repoRelative(filename, repoRoot) {
|
|
155
|
+
if (!filename)
|
|
156
|
+
return null;
|
|
157
|
+
const root = repoRoot.endsWith(sep) ? repoRoot.slice(0, -1) : repoRoot;
|
|
158
|
+
if (filename === root)
|
|
159
|
+
return "";
|
|
160
|
+
const prefix = root + sep;
|
|
161
|
+
if (filename.startsWith(prefix))
|
|
162
|
+
return filename.slice(prefix.length);
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
function isBlocked(relPath, blockList) {
|
|
166
|
+
for (const entry of blockList) {
|
|
167
|
+
if (!entry)
|
|
168
|
+
continue;
|
|
169
|
+
const trimmed = entry.replace(/\/+$/g, "");
|
|
170
|
+
if (relPath === trimmed || relPath.startsWith(trimmed + "/"))
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
export function packageDirFor(anyPathInPackage) {
|
|
176
|
+
let file = anyPathInPackage;
|
|
177
|
+
if (file.startsWith("file://")) {
|
|
178
|
+
try {
|
|
179
|
+
file = fileURLToPath(file);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// leave as-is
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
const real = realpathSync(file);
|
|
187
|
+
const idx = real.lastIndexOf(sep);
|
|
188
|
+
return idx >= 0 ? real.slice(0, idx) : real;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
const idx = file.lastIndexOf(sep);
|
|
192
|
+
return idx >= 0 ? file.slice(0, idx) : file;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/** Test-only hook — clear all caches. */
|
|
196
|
+
export function resetCachesForTests() {
|
|
197
|
+
realpathCache.clear();
|
|
198
|
+
callerCache.clear();
|
|
199
|
+
seenCallSites.clear();
|
|
200
|
+
seenFiles.clear();
|
|
201
|
+
capHitNotified = false;
|
|
202
|
+
capHitPending = false;
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=caller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caller.js","sourceRoot":"","sources":["../src/caller.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
/** Optional now — when null the tenant label (auto-injected by VMAuth) identifies the customer. */
|
|
3
|
+
customerId: string | null;
|
|
4
|
+
/** Frugal project this deployment belongs to — the primary attribution key. */
|
|
5
|
+
projectId: string;
|
|
6
|
+
/** Optional logical components this deployment serves; metrics fan out one extra series per entry. */
|
|
7
|
+
components: readonly string[];
|
|
8
|
+
repoRoot: string;
|
|
9
|
+
pathBlockList: readonly string[];
|
|
10
|
+
otlpEndpoint: string;
|
|
11
|
+
otlpHeaders: string;
|
|
12
|
+
exportIntervalMs: number;
|
|
13
|
+
/** Max distinct (file, function) combinations to attribute before overflow. 0 = unlimited. */
|
|
14
|
+
maxCallSites: number;
|
|
15
|
+
/** Fraction of analyzed calls to emit prompt-analysis metrics for, 0..1. */
|
|
16
|
+
promptAnalysisSampleRate: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function loadConfig(): Config | null;
|
|
19
|
+
/** Test-only hook to re-arm the one-shot warning. */
|
|
20
|
+
export declare function resetWarningStateForTests(): void;
|
|
21
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,MAAM;IACrB,mGAAmG;IACnG,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,sGAAsG;IACtG,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,8FAA8F;IAC9F,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,wBAAwB,EAAE,MAAM,CAAC;CAClC;AA2CD,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAmG1C;AAED,qDAAqD;AACrD,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// Environment-variable configuration loading.
|
|
2
|
+
//
|
|
3
|
+
// All configuration comes from env vars — no init() API. If any required
|
|
4
|
+
// variable is missing, loadConfig() returns null and the wrappers no-op. A
|
|
5
|
+
// single warning is logged on the first no-op.
|
|
6
|
+
//
|
|
7
|
+
// Minimum required production config (two env vars):
|
|
8
|
+
// FRUGAL_API_KEY — per-customer bearer token (Frugal mints these per tenant)
|
|
9
|
+
// FRUGAL_PROJECT_ID — the Frugal project this deployment belongs to. Stats are
|
|
10
|
+
// attributed per project (file/function is unique within a
|
|
11
|
+
// project), so the same repo deployed across microservices
|
|
12
|
+
// no longer collides. Frugal shows this value in the UI.
|
|
13
|
+
//
|
|
14
|
+
// Everything else has sensible defaults:
|
|
15
|
+
// - Endpoint defaults to https://metrics.frugal.co/opentelemetry/v1/metrics
|
|
16
|
+
// - REPO_ROOT defaults to process.cwd() (the strip prefix for caller_file)
|
|
17
|
+
// - CUSTOMER_ID is optional; when unset, the tenant label (auto-injected
|
|
18
|
+
// server-side by VMAuth from the bearer token) is the canonical customer
|
|
19
|
+
// identifier and the frugal.customer_id label is omitted.
|
|
20
|
+
// - COMPONENTS is optional; a comma-separated list (e.g. "ai-handler,reco").
|
|
21
|
+
// When set, every metric is ALSO emitted once per component (tagged with
|
|
22
|
+
// frugal.component) on top of the base project-level series, so usage can be
|
|
23
|
+
// viewed for the whole project (component absent) or split by component.
|
|
24
|
+
//
|
|
25
|
+
// The older env vars (FRUGAL_OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
26
|
+
// FRUGAL_OTEL_EXPORTER_OTLP_HEADERS, FRUGAL_REPO_ROOT, FRUGAL_CUSTOMER_ID,
|
|
27
|
+
// plus the standard OTel ones) all still work — explicit values override
|
|
28
|
+
// the defaults so existing customers don't need to change anything.
|
|
29
|
+
import { realpathSync } from "node:fs";
|
|
30
|
+
import { resolve } from "node:path";
|
|
31
|
+
const ENV = {
|
|
32
|
+
CUSTOMER_ID: "FRUGAL_CUSTOMER_ID",
|
|
33
|
+
PROJECT_ID: "FRUGAL_PROJECT_ID",
|
|
34
|
+
// Namespaced overrides that take precedence over the bare FRUGAL_* names.
|
|
35
|
+
// Use these when embedding the SDK in an app that already owns FRUGAL_PROJECT_ID
|
|
36
|
+
// / FRUGAL_API_KEY for its own configuration (e.g. a Frugal-product service).
|
|
37
|
+
METRICS_PROJECT_ID: "FRUGAL_METRICS_PROJECT_ID",
|
|
38
|
+
METRICS_API_KEY: "FRUGAL_METRICS_API_KEY",
|
|
39
|
+
COMPONENTS: "FRUGAL_COMPONENTS",
|
|
40
|
+
REPO_ROOT: "FRUGAL_REPO_ROOT",
|
|
41
|
+
PATH_BLOCK_LIST: "FRUGAL_PATH_BLOCK_LIST",
|
|
42
|
+
DISABLED: "FRUGAL_DISABLED",
|
|
43
|
+
API_KEY: "FRUGAL_API_KEY",
|
|
44
|
+
FRUGAL_OTLP_ENDPOINT: "FRUGAL_OTEL_EXPORTER_OTLP_ENDPOINT",
|
|
45
|
+
FRUGAL_OTLP_HEADERS: "FRUGAL_OTEL_EXPORTER_OTLP_HEADERS",
|
|
46
|
+
OTLP_ENDPOINT: "OTEL_EXPORTER_OTLP_ENDPOINT",
|
|
47
|
+
OTLP_HEADERS: "OTEL_EXPORTER_OTLP_HEADERS",
|
|
48
|
+
EXPORT_INTERVAL_MS: "FRUGAL_METRIC_EXPORT_INTERVAL_MS",
|
|
49
|
+
MAX_CALL_SITES: "FRUGAL_MAX_CALL_SITES",
|
|
50
|
+
PROMPT_ANALYSIS_SAMPLE_RATE: "FRUGAL_PROMPT_ANALYSIS_SAMPLE_RATE",
|
|
51
|
+
};
|
|
52
|
+
const DEFAULT_OTLP_ENDPOINT = "https://metrics.frugal.co/opentelemetry/v1/metrics";
|
|
53
|
+
const DEFAULT_MAX_CALL_SITES = 500;
|
|
54
|
+
const DEFAULT_PROMPT_ANALYSIS_SAMPLE_RATE = 0.1;
|
|
55
|
+
let warnedOnce = false;
|
|
56
|
+
function truthy(value) {
|
|
57
|
+
if (!value)
|
|
58
|
+
return false;
|
|
59
|
+
const v = value.trim().toLowerCase();
|
|
60
|
+
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
61
|
+
}
|
|
62
|
+
function warnOnce(message) {
|
|
63
|
+
if (warnedOnce)
|
|
64
|
+
return;
|
|
65
|
+
warnedOnce = true;
|
|
66
|
+
// eslint-disable-next-line no-console
|
|
67
|
+
console.warn(`[frugal-metrics] disabled: ${message}`);
|
|
68
|
+
}
|
|
69
|
+
export function loadConfig() {
|
|
70
|
+
if (truthy(process.env[ENV.DISABLED]))
|
|
71
|
+
return null;
|
|
72
|
+
const customerId = process.env[ENV.CUSTOMER_ID] || null;
|
|
73
|
+
// Prefer the namespaced override so the SDK can coexist with a host app that
|
|
74
|
+
// uses FRUGAL_PROJECT_ID / FRUGAL_API_KEY for its own config. `||` so an empty
|
|
75
|
+
// override falls through to the bare name rather than blanking the value.
|
|
76
|
+
const projectId = process.env[ENV.METRICS_PROJECT_ID] || process.env[ENV.PROJECT_ID];
|
|
77
|
+
const repoRootEnv = process.env[ENV.REPO_ROOT];
|
|
78
|
+
const apiKey = process.env[ENV.METRICS_API_KEY] || process.env[ENV.API_KEY];
|
|
79
|
+
// Explicit headers override anything we'd build from the API key — keeps
|
|
80
|
+
// existing deployments that set FRUGAL_OTEL_EXPORTER_OTLP_HEADERS directly
|
|
81
|
+
// working unchanged.
|
|
82
|
+
const explicitHeaders = process.env[ENV.FRUGAL_OTLP_HEADERS] ?? process.env[ENV.OTLP_HEADERS];
|
|
83
|
+
const otlpHeaders = explicitHeaders
|
|
84
|
+
? explicitHeaders
|
|
85
|
+
: apiKey
|
|
86
|
+
? `Authorization=Bearer ${apiKey}`
|
|
87
|
+
: null;
|
|
88
|
+
// Required for any useful run: PROJECT_ID (the attribution key) and SOME auth
|
|
89
|
+
// (either FRUGAL_API_KEY or an explicit OTLP_HEADERS containing the bearer).
|
|
90
|
+
const missing = [];
|
|
91
|
+
if (!projectId)
|
|
92
|
+
missing.push(ENV.PROJECT_ID);
|
|
93
|
+
if (!otlpHeaders)
|
|
94
|
+
missing.push(`${ENV.API_KEY} or ${ENV.FRUGAL_OTLP_HEADERS}`);
|
|
95
|
+
if (missing.length > 0) {
|
|
96
|
+
warnOnce(`missing required env vars: ${missing.join(", ")}`);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
// Resolve through symlinks so caller-file relativization is consistent with
|
|
100
|
+
// what Node reports in stack traces (esp. macOS /var -> /private/var).
|
|
101
|
+
// Default to process.cwd() — works for the standard container pattern
|
|
102
|
+
// where WORKDIR is set to the source-code root.
|
|
103
|
+
const repoRootRaw = repoRootEnv || process.cwd();
|
|
104
|
+
let repoRootAbs;
|
|
105
|
+
try {
|
|
106
|
+
repoRootAbs = realpathSync(resolve(repoRootRaw));
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
repoRootAbs = resolve(repoRootRaw);
|
|
110
|
+
}
|
|
111
|
+
const blockListRaw = process.env[ENV.PATH_BLOCK_LIST] ?? "";
|
|
112
|
+
const pathBlockList = blockListRaw
|
|
113
|
+
.split(",")
|
|
114
|
+
.map((e) => e.trim().replace(/^\/+|\/+$/g, ""))
|
|
115
|
+
.filter((e) => e.length > 0);
|
|
116
|
+
// Optional comma-separated logical components (e.g. "ai-handler,reco"). Each
|
|
117
|
+
// becomes an extra per-component series on top of the base project series.
|
|
118
|
+
const componentsRaw = process.env[ENV.COMPONENTS] ?? "";
|
|
119
|
+
const components = componentsRaw
|
|
120
|
+
.split(",")
|
|
121
|
+
.map((e) => e.trim())
|
|
122
|
+
.filter((e) => e.length > 0);
|
|
123
|
+
const otlpEndpoint = process.env[ENV.FRUGAL_OTLP_ENDPOINT] ??
|
|
124
|
+
process.env[ENV.OTLP_ENDPOINT] ??
|
|
125
|
+
DEFAULT_OTLP_ENDPOINT;
|
|
126
|
+
const intervalRaw = process.env[ENV.EXPORT_INTERVAL_MS];
|
|
127
|
+
let exportIntervalMs = 60_000;
|
|
128
|
+
if (intervalRaw && intervalRaw.trim()) {
|
|
129
|
+
const parsed = Number.parseInt(intervalRaw, 10);
|
|
130
|
+
if (Number.isFinite(parsed))
|
|
131
|
+
exportIntervalMs = parsed;
|
|
132
|
+
}
|
|
133
|
+
const maxCallSitesRaw = process.env[ENV.MAX_CALL_SITES];
|
|
134
|
+
let maxCallSites = DEFAULT_MAX_CALL_SITES;
|
|
135
|
+
if (maxCallSitesRaw && maxCallSitesRaw.trim()) {
|
|
136
|
+
const parsed = Number.parseInt(maxCallSitesRaw, 10);
|
|
137
|
+
if (Number.isFinite(parsed) && parsed >= 0)
|
|
138
|
+
maxCallSites = parsed;
|
|
139
|
+
}
|
|
140
|
+
const sampleRateRaw = process.env[ENV.PROMPT_ANALYSIS_SAMPLE_RATE];
|
|
141
|
+
let promptAnalysisSampleRate = DEFAULT_PROMPT_ANALYSIS_SAMPLE_RATE;
|
|
142
|
+
if (sampleRateRaw && sampleRateRaw.trim()) {
|
|
143
|
+
const parsed = Number.parseFloat(sampleRateRaw);
|
|
144
|
+
if (Number.isFinite(parsed) && parsed >= 0 && parsed <= 1) {
|
|
145
|
+
promptAnalysisSampleRate = parsed;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
customerId,
|
|
150
|
+
projectId: projectId,
|
|
151
|
+
components,
|
|
152
|
+
repoRoot: repoRootAbs,
|
|
153
|
+
pathBlockList,
|
|
154
|
+
otlpEndpoint,
|
|
155
|
+
otlpHeaders: otlpHeaders,
|
|
156
|
+
exportIntervalMs,
|
|
157
|
+
maxCallSites,
|
|
158
|
+
promptAnalysisSampleRate,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/** Test-only hook to re-arm the one-shot warning. */
|
|
162
|
+
export function resetWarningStateForTests() {
|
|
163
|
+
warnedOnce = false;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { wrapOpenAI } from "./wrappers/openai.js";
|
|
2
|
+
export { wrapAnthropic } from "./wrappers/anthropic.js";
|
|
3
|
+
export { wrapBedrock } from "./wrappers/bedrock.js";
|
|
4
|
+
export { startAICall, trackAICall } from "./track.js";
|
|
5
|
+
export type { AICallInfo, AIUsage, AICallHandle } from "./track.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,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,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type CallerInfo } from "./caller.js";
|
|
2
|
+
import type { Config } from "./config.js";
|
|
3
|
+
import { type Instruments } from "./otel.js";
|
|
4
|
+
import { type RequestPayload } from "./prompt-analyzer.js";
|
|
5
|
+
export interface CallContext {
|
|
6
|
+
system: string;
|
|
7
|
+
operation: string;
|
|
8
|
+
requestModel: string;
|
|
9
|
+
skipPackageDirs: readonly string[];
|
|
10
|
+
/** True when this call is a batch-API submission, false for normal sync/streaming. */
|
|
11
|
+
batched?: boolean;
|
|
12
|
+
/** Captured request kwargs for prompt analysis + cap utilization. */
|
|
13
|
+
requestPayload?: RequestPayload;
|
|
14
|
+
}
|
|
15
|
+
export interface UsageReport {
|
|
16
|
+
responseModel?: string | null;
|
|
17
|
+
inputTokens?: number | null;
|
|
18
|
+
outputTokens?: number | null;
|
|
19
|
+
cacheReadTokens?: number | null;
|
|
20
|
+
cacheWriteTokens?: number | null;
|
|
21
|
+
reasoningTokens?: number | null;
|
|
22
|
+
}
|
|
23
|
+
export interface StartCallOptions {
|
|
24
|
+
/**
|
|
25
|
+
* How many frames at the top of the stack to skip past when resolving the
|
|
26
|
+
* caller. Default 2 drops resolveCaller + startCall, leaving the wrapper
|
|
27
|
+
* frame — resolveCaller then skips our wrapper frame via skipPackageDirs to
|
|
28
|
+
* land on the customer's code.
|
|
29
|
+
*/
|
|
30
|
+
skipFrames?: number;
|
|
31
|
+
caller?: CallerInfo;
|
|
32
|
+
}
|
|
33
|
+
export declare function startCall(config: Config, ctx: CallContext, opts?: StartCallOptions): CallEmitter;
|
|
34
|
+
export declare class CallEmitter {
|
|
35
|
+
private readonly config;
|
|
36
|
+
private readonly ctx;
|
|
37
|
+
readonly caller: CallerInfo;
|
|
38
|
+
private readonly instruments;
|
|
39
|
+
private readonly startSec;
|
|
40
|
+
private finalized;
|
|
41
|
+
constructor(config: Config, ctx: CallContext, caller: CallerInfo, instruments: Instruments, startSec: number);
|
|
42
|
+
success(usage: UsageReport): void;
|
|
43
|
+
private recordCapUtilization;
|
|
44
|
+
private maybeAnalyze;
|
|
45
|
+
private recordStable;
|
|
46
|
+
error(err: unknown): void;
|
|
47
|
+
private baseAttrs;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=instrument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../src/instrument.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAwB9B,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qEAAqE;IACrE,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,WAAW,EAChB,IAAI,GAAE,gBAAqB,GAC1B,WAAW,CAuBb;AAOD,qBAAa,WAAW;IAIpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,QAAQ,CAAC,MAAM,EAAE,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,OAAO,CAAC,SAAS,CAAS;gBAGP,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,WAAW,EACxB,MAAM,EAAE,UAAU,EACV,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM;IAGnC,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAqCjC,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,YAAY;IAyCpB,OAAO,CAAC,YAAY;IAgBpB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAWzB,OAAO,CAAC,SAAS;CAelB"}
|