@lmnr-ai/lmnr 0.8.39 → 0.8.41
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/cli.cjs +2 -2
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/{dist-oS06mAi1.cjs → dist-BNoIH9xW.cjs} +67 -6
- package/dist/dist-BNoIH9xW.cjs.map +1 -0
- package/dist/{dist-Dgq2z7AD.mjs → dist-D-1LE3Xx.mjs} +62 -7
- package/dist/dist-D-1LE3Xx.mjs.map +1 -0
- package/dist/{evaluations-BUitiaxR.d.cts → evaluations-CeDsphK5.d.cts} +99 -27
- package/dist/{evaluations-gHrXUnIp.d.mts → evaluations-pCcE5lVy.d.mts} +99 -27
- package/dist/{file-utils-Bf15ARiL.cjs → file-utils-B7VBQSna.cjs} +2 -2
- package/dist/{file-utils-Bf15ARiL.cjs.map → file-utils-B7VBQSna.cjs.map} +1 -1
- package/dist/{file-utils-D0UCmQi0.mjs → file-utils-DNyYjjV3.mjs} +2 -2
- package/dist/{file-utils-D0UCmQi0.mjs.map → file-utils-DNyYjjV3.mjs.map} +1 -1
- package/dist/index.cjs +337 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +337 -48
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/dist-Dgq2z7AD.mjs.map +0 -1
- package/dist/dist-oS06mAi1.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_rolldown_runtime = require("./rolldown-runtime-CVvi-lCc.cjs");
|
|
3
|
-
const require_dist = require("./dist-
|
|
3
|
+
const require_dist = require("./dist-BNoIH9xW.cjs");
|
|
4
4
|
const require_consts = require("./consts-DV6_Ea-8.cjs");
|
|
5
5
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
6
6
|
let _opentelemetry_context_async_hooks = require("@opentelemetry/context-async-hooks");
|
|
@@ -41,6 +41,25 @@ let _noble_hashes_blake3_js = require("@noble/hashes/blake3.js");
|
|
|
41
41
|
let _noble_hashes_utils_js = require("@noble/hashes/utils.js");
|
|
42
42
|
let node_diagnostics_channel = require("node:diagnostics_channel");
|
|
43
43
|
node_diagnostics_channel = require_rolldown_runtime.__toESM(node_diagnostics_channel);
|
|
44
|
+
//#region src/datasets/prng.ts
|
|
45
|
+
const UINT32 = 4294967296;
|
|
46
|
+
const seededPerm = (n, seed) => {
|
|
47
|
+
let state = seed >>> 0;
|
|
48
|
+
const next = () => {
|
|
49
|
+
state = state + 1831565813 >>> 0;
|
|
50
|
+
let t = state;
|
|
51
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
52
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
53
|
+
return ((t ^ t >>> 14) >>> 0) / UINT32;
|
|
54
|
+
};
|
|
55
|
+
const ix = Array.from({ length: n }, (_, i) => i);
|
|
56
|
+
for (let i = n - 1; i > 0; i--) {
|
|
57
|
+
const j = Math.floor(next() * (i + 1));
|
|
58
|
+
[ix[i], ix[j]] = [ix[j], ix[i]];
|
|
59
|
+
}
|
|
60
|
+
return ix;
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
44
63
|
//#region src/datasets.ts
|
|
45
64
|
const DEFAULT_FETCH_SIZE = 25;
|
|
46
65
|
var EvaluationDataset = class {
|
|
@@ -49,13 +68,66 @@ var EvaluationDataset = class {
|
|
|
49
68
|
for (let i = Math.max(start, 0); i < Math.min(end, await this.size()); i++) result.push(await this.get(i));
|
|
50
69
|
return result;
|
|
51
70
|
}
|
|
71
|
+
sourceDataset() {}
|
|
72
|
+
take(n) {
|
|
73
|
+
return new Transformed(this, async (base) => {
|
|
74
|
+
if (!Number.isInteger(n)) throw new Error(`take count ${n} is not an integer`);
|
|
75
|
+
const size = await base.size();
|
|
76
|
+
const count = Math.max(0, Math.min(n, size));
|
|
77
|
+
return Array.from({ length: count }, (_, i) => i);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
select(indices) {
|
|
81
|
+
const selected = [...indices];
|
|
82
|
+
return new Transformed(this, async (base) => {
|
|
83
|
+
const size = await base.size();
|
|
84
|
+
for (const index of selected) {
|
|
85
|
+
if (!Number.isInteger(index)) throw new Error(`select index ${index} is not an integer`);
|
|
86
|
+
if (index < 0 || index >= size) throw new Error(`select index ${index} is out of range for dataset of size ${size}`);
|
|
87
|
+
}
|
|
88
|
+
return selected;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
shuffle({ seed = 0 } = {}) {
|
|
92
|
+
return new Transformed(this, async (base) => seededPerm(await base.size(), seed));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var Transformed = class extends EvaluationDataset {
|
|
96
|
+
constructor(base, resolve) {
|
|
97
|
+
super();
|
|
98
|
+
this.indices = null;
|
|
99
|
+
this.resolving = null;
|
|
100
|
+
this.base = base;
|
|
101
|
+
this.resolve = resolve;
|
|
102
|
+
}
|
|
103
|
+
resolveIndices() {
|
|
104
|
+
if (this.indices !== null) return Promise.resolve(this.indices);
|
|
105
|
+
if (this.resolving === null) this.resolving = this.resolve(this.base).then((indices) => {
|
|
106
|
+
this.indices = indices;
|
|
107
|
+
return indices;
|
|
108
|
+
}).catch((err) => {
|
|
109
|
+
this.resolving = null;
|
|
110
|
+
throw err;
|
|
111
|
+
});
|
|
112
|
+
return this.resolving;
|
|
113
|
+
}
|
|
114
|
+
async size() {
|
|
115
|
+
return (await this.resolveIndices()).length;
|
|
116
|
+
}
|
|
117
|
+
async get(index) {
|
|
118
|
+
const indices = await this.resolveIndices();
|
|
119
|
+
if (index < 0 || index >= indices.length) throw new Error(`Index ${index} is out of range for dataset of size ${indices.length}`);
|
|
120
|
+
return await this.base.get(indices[index]);
|
|
121
|
+
}
|
|
122
|
+
sourceDataset() {
|
|
123
|
+
return this.base.sourceDataset();
|
|
124
|
+
}
|
|
52
125
|
};
|
|
53
126
|
var LaminarDataset = class extends EvaluationDataset {
|
|
54
127
|
constructor(name, options) {
|
|
55
128
|
super();
|
|
56
|
-
this.
|
|
129
|
+
this.pages = /* @__PURE__ */ new Map();
|
|
57
130
|
this.len = null;
|
|
58
|
-
this.offset = 0;
|
|
59
131
|
this.client = void 0;
|
|
60
132
|
if (!name && !options?.id) throw new Error("Either name or id must be provided");
|
|
61
133
|
if (name && options?.id) throw new Error("Only one of name or id must be provided");
|
|
@@ -66,25 +138,42 @@ var LaminarDataset = class extends EvaluationDataset {
|
|
|
66
138
|
setClient(client) {
|
|
67
139
|
this.client = client;
|
|
68
140
|
}
|
|
69
|
-
|
|
141
|
+
sourceDataset() {
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
fetchPage(offset) {
|
|
145
|
+
const existing = this.pages.get(offset);
|
|
146
|
+
if (existing) return existing;
|
|
147
|
+
const pending = this.doFetchPage(offset).catch((err) => {
|
|
148
|
+
this.pages.delete(offset);
|
|
149
|
+
throw err;
|
|
150
|
+
});
|
|
151
|
+
this.pages.set(offset, pending);
|
|
152
|
+
return pending;
|
|
153
|
+
}
|
|
154
|
+
async doFetchPage(offset) {
|
|
70
155
|
if (!this.client) throw new Error("Client not set");
|
|
71
156
|
const identifier = this.id ? { id: this.id } : { name: this.name };
|
|
72
157
|
const resp = await this.client.datasets.pull({
|
|
73
158
|
...identifier,
|
|
74
|
-
offset
|
|
159
|
+
offset,
|
|
75
160
|
limit: this.fetchSize
|
|
76
161
|
});
|
|
77
|
-
this.fetchedItems = this.fetchedItems.concat(resp.items);
|
|
78
|
-
this.offset = this.fetchedItems.length;
|
|
79
162
|
if (this.len === null) this.len = resp.totalCount;
|
|
163
|
+
return resp.items;
|
|
80
164
|
}
|
|
81
165
|
async size() {
|
|
82
|
-
if (this.len === null) await this.
|
|
166
|
+
if (this.len === null) await this.fetchPage(0);
|
|
83
167
|
return this.len;
|
|
84
168
|
}
|
|
85
169
|
async get(index) {
|
|
86
|
-
if (index
|
|
87
|
-
|
|
170
|
+
if (index < 0) throw new Error(`Index ${index} is out of range`);
|
|
171
|
+
if (this.len !== null && index >= this.len) throw new Error(`Index ${index} is out of range for dataset of size ${this.len}`);
|
|
172
|
+
const offset = Math.floor(index / this.fetchSize) * this.fetchSize;
|
|
173
|
+
const page = await this.fetchPage(offset);
|
|
174
|
+
const local = index - offset;
|
|
175
|
+
if (local >= page.length) throw new Error(`Index ${index} is out of range for dataset of size ${this.len ?? "unknown"}`);
|
|
176
|
+
return page[local];
|
|
88
177
|
}
|
|
89
178
|
/**
|
|
90
179
|
* Push data from files to this dataset.
|
|
@@ -94,7 +183,7 @@ var LaminarDataset = class extends EvaluationDataset {
|
|
|
94
183
|
*/
|
|
95
184
|
async push(paths, recursive = false) {
|
|
96
185
|
if (!this.client) throw new Error("Client not set");
|
|
97
|
-
const { loadFromPaths } = await Promise.resolve().then(() => require("./file-utils-
|
|
186
|
+
const { loadFromPaths } = await Promise.resolve().then(() => require("./file-utils-B7VBQSna.cjs")).then((n) => n.file_utils_exports);
|
|
98
187
|
const data = await loadFromPaths(Array.isArray(paths) ? paths : [paths], recursive);
|
|
99
188
|
if (data.length === 0) {
|
|
100
189
|
console.warn("No data to push. Skipping");
|
|
@@ -1063,11 +1152,11 @@ var LaminarSpan = class LaminarSpan {
|
|
|
1063
1152
|
}
|
|
1064
1153
|
setInput(input) {
|
|
1065
1154
|
const finalInput = typeof input === "string" ? input : JSON.stringify(input);
|
|
1066
|
-
this._span.setAttribute(require_dist.SPAN_INPUT, finalInput);
|
|
1155
|
+
this._span.setAttribute(require_dist.SPAN_INPUT, require_dist.truncateSpanPayload(finalInput, "input"));
|
|
1067
1156
|
}
|
|
1068
1157
|
setOutput(output) {
|
|
1069
1158
|
const finalOutput = typeof output === "string" ? output : JSON.stringify(output);
|
|
1070
|
-
this._span.setAttribute(require_dist.SPAN_OUTPUT, finalOutput);
|
|
1159
|
+
this._span.setAttribute(require_dist.SPAN_OUTPUT, require_dist.truncateSpanPayload(finalOutput, "output"));
|
|
1071
1160
|
}
|
|
1072
1161
|
setTags(tags) {
|
|
1073
1162
|
this._span.setAttribute(`${require_dist.ASSOCIATION_PROPERTIES}.tags`, Array.from(new Set(tags)));
|
|
@@ -1340,12 +1429,181 @@ const BEDROCK_USE_ENV = "CLAUDE_CODE_USE_BEDROCK";
|
|
|
1340
1429
|
const BEDROCK_AWS_REGION_ENV = "AWS_REGION";
|
|
1341
1430
|
const VERTEX_BASE_URL_ENV = "ANTHROPIC_VERTEX_BASE_URL";
|
|
1342
1431
|
const VERTEX_USE_ENV = "CLAUDE_CODE_USE_VERTEX";
|
|
1432
|
+
const PROXY_BASE_URL_ENV_KEYS = [
|
|
1433
|
+
"ANTHROPIC_BASE_URL",
|
|
1434
|
+
FOUNDRY_BASE_URL_ENV,
|
|
1435
|
+
BEDROCK_BASE_URL_ENV,
|
|
1436
|
+
VERTEX_BASE_URL_ENV
|
|
1437
|
+
];
|
|
1438
|
+
const PROVIDER_BASE_URL_ENV_KEYS = [
|
|
1439
|
+
[FOUNDRY_BASE_URL_ENV, FOUNDRY_USE_ENV],
|
|
1440
|
+
[BEDROCK_BASE_URL_ENV, BEDROCK_USE_ENV],
|
|
1441
|
+
[VERTEX_BASE_URL_ENV, VERTEX_USE_ENV]
|
|
1442
|
+
];
|
|
1443
|
+
const PROXY_ENV_KEYS = [
|
|
1444
|
+
"HTTP_PROXY",
|
|
1445
|
+
"HTTPS_PROXY",
|
|
1446
|
+
"http_proxy",
|
|
1447
|
+
"https_proxy"
|
|
1448
|
+
];
|
|
1449
|
+
const PROXY_NEUTRALIZED_ENV_KEYS = [...PROXY_ENV_KEYS, FOUNDRY_RESOURCE_ENV];
|
|
1450
|
+
const UPSTREAM_SETTINGS_EXCLUDED_ENV_KEYS = PROXY_ENV_KEYS;
|
|
1343
1451
|
const activeProxyServers = /* @__PURE__ */ new Set();
|
|
1344
1452
|
let globalShutdownRegistered = false;
|
|
1345
1453
|
/**
|
|
1346
|
-
* Check
|
|
1454
|
+
* Check whether an env value enables a feature.
|
|
1455
|
+
*
|
|
1456
|
+
* Claude Code accepts `1`, `true`, `yes`, and `on` (case-insensitive) — verified
|
|
1457
|
+
* against the bundled CLI. Accepting only `"1"` would miss a provider the CLI
|
|
1458
|
+
* considers enabled, so we would blank its routing keys without pinning a base
|
|
1459
|
+
* URL and break the run.
|
|
1347
1460
|
*/
|
|
1348
|
-
const isTruthyEnv = (value) =>
|
|
1461
|
+
const isTruthyEnv = (value) => {
|
|
1462
|
+
if (typeof value !== "string") return value === true;
|
|
1463
|
+
return [
|
|
1464
|
+
"1",
|
|
1465
|
+
"true",
|
|
1466
|
+
"yes",
|
|
1467
|
+
"on"
|
|
1468
|
+
].includes(value.trim().toLowerCase());
|
|
1469
|
+
};
|
|
1470
|
+
/**
|
|
1471
|
+
* Whether a provider flag is enabled in the given env, using the CLI's own
|
|
1472
|
+
* truthiness rules.
|
|
1473
|
+
*
|
|
1474
|
+
* Exported so the subprocess-env pin path shares ONE definition of "enabled"
|
|
1475
|
+
* with `getEnvVarsToRemove` / `buildProxyFlagSettings`. If they disagree, the
|
|
1476
|
+
* resource gets stripped without a base URL being pinned and the CLI hard-fails.
|
|
1477
|
+
*/
|
|
1478
|
+
const isProviderEnabledInEnv = (env, useKey) => isTruthyEnv(env[useKey]);
|
|
1479
|
+
/**
|
|
1480
|
+
* Load a Claude settings JSON file, or `null` when it could not be read.
|
|
1481
|
+
*
|
|
1482
|
+
* `null` (unreadable / malformed / not a JSON object) is deliberately distinct
|
|
1483
|
+
* from `{}` (a valid but empty settings file): callers that would otherwise
|
|
1484
|
+
* REPLACE a user's settings need to know they failed to read it.
|
|
1485
|
+
*/
|
|
1486
|
+
const loadSettingsFile = (filePath) => {
|
|
1487
|
+
try {
|
|
1488
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
1489
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
1490
|
+
} catch {}
|
|
1491
|
+
return null;
|
|
1492
|
+
};
|
|
1493
|
+
const settingsEnvBlock = (settings) => {
|
|
1494
|
+
const env = settings.env;
|
|
1495
|
+
if (!env || typeof env !== "object" || Array.isArray(env)) return {};
|
|
1496
|
+
const result = {};
|
|
1497
|
+
for (const [key, value] of Object.entries(env)) if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") result[key] = String(value);
|
|
1498
|
+
return result;
|
|
1499
|
+
};
|
|
1500
|
+
/**
|
|
1501
|
+
* Read the merged `env` block from Claude Code's on-disk settings layers.
|
|
1502
|
+
*
|
|
1503
|
+
* Claude Code applies these to the CLI session with HIGHER priority than the
|
|
1504
|
+
* subprocess environment, so a user with `ANTHROPIC_BASE_URL` in
|
|
1505
|
+
* `~/.claude/settings.json` silently bypasses our proxy. We read them to resolve
|
|
1506
|
+
* the real upstream and to detect conflicts.
|
|
1507
|
+
*
|
|
1508
|
+
* Precedence (highest first): local project, shared project, user.
|
|
1509
|
+
*
|
|
1510
|
+
* `settingSources` mirrors `options.settingSources` and gates which layers are
|
|
1511
|
+
* read: `undefined` means the CLI loads all of them, an array means only those,
|
|
1512
|
+
* and `[]` disables on-disk settings entirely. Honoring it matters because
|
|
1513
|
+
* reading a layer the CLI was told to ignore would resolve an upstream the CLI
|
|
1514
|
+
* never uses, pointing the proxy at an unintended host.
|
|
1515
|
+
*/
|
|
1516
|
+
const readClaudeSettingsEnv = (cwd, settingSources) => {
|
|
1517
|
+
const sessionCwd = cwd ?? process.cwd();
|
|
1518
|
+
const userDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
|
|
1519
|
+
const layers = [
|
|
1520
|
+
["user", path.join(userDir, "settings.json")],
|
|
1521
|
+
["project", path.join(sessionCwd, ".claude", "settings.json")],
|
|
1522
|
+
["local", path.join(sessionCwd, ".claude", "settings.local.json")]
|
|
1523
|
+
];
|
|
1524
|
+
const merged = {};
|
|
1525
|
+
for (const [source, filePath] of layers) {
|
|
1526
|
+
if (settingSources !== void 0 && !settingSources.includes(source)) continue;
|
|
1527
|
+
Object.assign(merged, settingsEnvBlock(loadSettingsFile(filePath) ?? {}));
|
|
1528
|
+
}
|
|
1529
|
+
return merged;
|
|
1530
|
+
};
|
|
1531
|
+
/**
|
|
1532
|
+
* Read the `env` block out of the caller's `options.settings` (the flag layer).
|
|
1533
|
+
*
|
|
1534
|
+
* This layer OUTRANKS every on-disk layer, so a gateway or provider config that
|
|
1535
|
+
* lives only here is what the CLI would actually use — and
|
|
1536
|
+
* `buildProxyFlagSettings` is about to overwrite those keys with the proxy URL.
|
|
1537
|
+
* Upstream resolution must therefore see it FIRST, or we forward to the wrong
|
|
1538
|
+
* host (or to the default endpoint) while the caller's gateway is silently lost.
|
|
1539
|
+
*
|
|
1540
|
+
* Returns `{}` for a value we could not read; the caller's own bail-out logic in
|
|
1541
|
+
* `buildProxyFlagSettings` handles that case.
|
|
1542
|
+
*/
|
|
1543
|
+
const flagSettingsEnv = (existing, cwd) => {
|
|
1544
|
+
if (typeof existing === "object" && existing !== null) return settingsEnvBlock(existing);
|
|
1545
|
+
if (typeof existing !== "string" || !existing.trim()) return {};
|
|
1546
|
+
const trimmed = existing.trim();
|
|
1547
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
1548
|
+
try {
|
|
1549
|
+
const parsed = JSON.parse(trimmed);
|
|
1550
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return settingsEnvBlock(parsed);
|
|
1551
|
+
} catch {}
|
|
1552
|
+
return {};
|
|
1553
|
+
}
|
|
1554
|
+
return settingsEnvBlock(loadSettingsFile(path.isAbsolute(trimmed) ? trimmed : path.join(cwd ?? process.cwd(), trimmed)) ?? {});
|
|
1555
|
+
};
|
|
1556
|
+
/**
|
|
1557
|
+
* Build the `--settings` value that forces the CLI through our proxy.
|
|
1558
|
+
*
|
|
1559
|
+
* Claude Code resolves `env` from its settings layers with higher priority than
|
|
1560
|
+
* the subprocess environment, so rewriting `options.env` alone leaves a user with
|
|
1561
|
+
* `ANTHROPIC_BASE_URL` in `~/.claude/settings.json` talking straight to their
|
|
1562
|
+
* upstream while the proxy sees zero traffic (lmnr#2167). `--settings` is the
|
|
1563
|
+
* highest user-controlled layer, so writing the proxy URL there wins without ever
|
|
1564
|
+
* touching the user's files on disk.
|
|
1565
|
+
*
|
|
1566
|
+
* Layers merge per key, so keys we simply omit keep their lower-layer value.
|
|
1567
|
+
* Redirecting keys are therefore blanked rather than dropped.
|
|
1568
|
+
*
|
|
1569
|
+
* Returns the value to assign to `options.settings`, or `null` when the caller's
|
|
1570
|
+
* existing value is a file path we could not read (in that case the path must be
|
|
1571
|
+
* left alone so the CLI can still resolve it itself).
|
|
1572
|
+
*/
|
|
1573
|
+
const buildProxyFlagSettings = (existing, proxyUrl, cwd, settingSources) => {
|
|
1574
|
+
let settingsObj = {};
|
|
1575
|
+
if (typeof existing === "object" && existing !== null) settingsObj = { ...existing };
|
|
1576
|
+
else if (typeof existing === "string" && existing.trim()) {
|
|
1577
|
+
const trimmed = existing.trim();
|
|
1578
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
1579
|
+
let parsed;
|
|
1580
|
+
try {
|
|
1581
|
+
parsed = JSON.parse(trimmed);
|
|
1582
|
+
} catch {
|
|
1583
|
+
return null;
|
|
1584
|
+
}
|
|
1585
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
1586
|
+
settingsObj = parsed;
|
|
1587
|
+
} else {
|
|
1588
|
+
const loaded = loadSettingsFile(path.isAbsolute(trimmed) ? trimmed : path.join(cwd ?? process.cwd(), trimmed));
|
|
1589
|
+
if (loaded === null) return null;
|
|
1590
|
+
settingsObj = loaded;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
const envDict = { ...settingsEnvBlock(settingsObj) };
|
|
1594
|
+
const settingsEnv = readClaudeSettingsEnv(cwd, settingSources);
|
|
1595
|
+
const inPlay = (key) => key in envDict || key in settingsEnv || process.env[key] !== void 0;
|
|
1596
|
+
envDict.ANTHROPIC_BASE_URL = proxyUrl;
|
|
1597
|
+
for (const [baseUrlKey, useKey] of PROVIDER_BASE_URL_ENV_KEYS) {
|
|
1598
|
+
if (isTruthyEnv(envDict[useKey]) || isTruthyEnv(settingsEnv[useKey]) || isTruthyEnv(process.env[useKey]) || inPlay(baseUrlKey)) envDict[baseUrlKey] = proxyUrl;
|
|
1599
|
+
if (baseUrlKey === FOUNDRY_BASE_URL_ENV && envDict[baseUrlKey] === proxyUrl) envDict[FOUNDRY_RESOURCE_ENV] = "";
|
|
1600
|
+
}
|
|
1601
|
+
for (const key of PROXY_NEUTRALIZED_ENV_KEYS) if (key in settingsEnv || key in envDict || process.env[key] !== void 0) envDict[key] = "";
|
|
1602
|
+
return {
|
|
1603
|
+
...settingsObj,
|
|
1604
|
+
env: envDict
|
|
1605
|
+
};
|
|
1606
|
+
};
|
|
1349
1607
|
/**
|
|
1350
1608
|
* Read region for a given profile from ~/.aws/config.
|
|
1351
1609
|
*/
|
|
@@ -1384,17 +1642,27 @@ const getRegionFromAwsConfig = (profile) => {
|
|
|
1384
1642
|
* 4. ANTHROPIC_BASE_URL - standard Anthropic API base URL
|
|
1385
1643
|
* 5. Fall back to default (https://api.anthropic.com)
|
|
1386
1644
|
*
|
|
1387
|
-
* For each environment variable, checks envDict first, then process.env
|
|
1645
|
+
* For each environment variable, checks envDict first, then process.env, then
|
|
1646
|
+
* Claude Code's on-disk settings `env` block. The settings layer is checked last
|
|
1647
|
+
* as a source for the *upstream* URL, but note it wins over process env inside
|
|
1648
|
+
* the CLI itself — see `buildProxyFlagSettings`.
|
|
1388
1649
|
*
|
|
1389
1650
|
* @param envDict - Dictionary of environment variables (e.g., from options.env)
|
|
1390
1651
|
* @param fallback - Fallback URL if no other source found (default: DEFAULT_ANTHROPIC_BASE_URL)
|
|
1652
|
+
* @param cwd - Session root used to locate project settings (`options.cwd`)
|
|
1391
1653
|
* @returns Resolved target URL, or null if provider is misconfigured
|
|
1392
1654
|
*/
|
|
1393
|
-
const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL) => {
|
|
1394
|
-
const
|
|
1395
|
-
const
|
|
1655
|
+
const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL, cwd, settingSources, settings) => {
|
|
1656
|
+
const flagEnv = flagSettingsEnv(settings, cwd);
|
|
1657
|
+
const settingsEnv = readClaudeSettingsEnv(cwd, settingSources);
|
|
1658
|
+
const getEnvValue = (key) => {
|
|
1659
|
+
const value = envDict[key] || process.env[key];
|
|
1660
|
+
if (value || UPSTREAM_SETTINGS_EXCLUDED_ENV_KEYS.includes(key)) return value;
|
|
1661
|
+
return flagEnv[key] || settingsEnv[key];
|
|
1662
|
+
};
|
|
1663
|
+
const httpsProxy = getEnvValue("HTTPS_PROXY") || getEnvValue("https_proxy");
|
|
1396
1664
|
if (httpsProxy) return httpsProxy.replace(/\/$/, "");
|
|
1397
|
-
const httpProxy = getEnvValue("HTTP_PROXY");
|
|
1665
|
+
const httpProxy = getEnvValue("HTTP_PROXY") || getEnvValue("http_proxy");
|
|
1398
1666
|
if (httpProxy) return httpProxy.replace(/\/$/, "");
|
|
1399
1667
|
if (isTruthyEnv(getEnvValue(FOUNDRY_USE_ENV))) {
|
|
1400
1668
|
const foundryBaseUrl = getEnvValue(FOUNDRY_BASE_URL_ENV);
|
|
@@ -1430,9 +1698,10 @@ const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL)
|
|
|
1430
1698
|
* @param envDict - Dictionary of environment variables
|
|
1431
1699
|
* @returns Array of environment variable keys to remove
|
|
1432
1700
|
*/
|
|
1433
|
-
const getEnvVarsToRemove = (envDict) => {
|
|
1434
|
-
const toRemove = [
|
|
1435
|
-
const
|
|
1701
|
+
const getEnvVarsToRemove = (envDict, cwd, settingSources) => {
|
|
1702
|
+
const toRemove = [...PROXY_ENV_KEYS];
|
|
1703
|
+
const settingsEnv = readClaudeSettingsEnv(cwd, settingSources);
|
|
1704
|
+
const getEnvValue = (key) => envDict[key] || process.env[key] || settingsEnv[key];
|
|
1436
1705
|
if (isTruthyEnv(getEnvValue(FOUNDRY_USE_ENV))) toRemove.push(FOUNDRY_RESOURCE_ENV);
|
|
1437
1706
|
return toRemove;
|
|
1438
1707
|
};
|
|
@@ -1507,14 +1776,14 @@ const registerGlobalProxyShutdown = () => {
|
|
|
1507
1776
|
* Create and start a new claude-code proxy server instance
|
|
1508
1777
|
* Each call creates an independent proxy on a unique port
|
|
1509
1778
|
*/
|
|
1510
|
-
const createProxyInstance = async ({ env }) => {
|
|
1779
|
+
const createProxyInstance = async ({ env, cwd, settingSources, settings, targetUrl: resolvedTargetUrl }) => {
|
|
1511
1780
|
try {
|
|
1512
1781
|
const port = await findAvailablePort(DEFAULT_CC_PROXY_PORT, CC_PROXY_PORT_ATTEMPTS);
|
|
1513
1782
|
if (port === null) {
|
|
1514
1783
|
logger$20.warn("Unable to allocate port for cc-proxy.");
|
|
1515
1784
|
return null;
|
|
1516
1785
|
}
|
|
1517
|
-
const targetUrl = resolveTargetUrlFromEnv(env);
|
|
1786
|
+
const targetUrl = resolvedTargetUrl ?? resolveTargetUrlFromEnv(env, void 0, cwd, settingSources, settings);
|
|
1518
1787
|
if (!targetUrl) {
|
|
1519
1788
|
logger$20.warn("Unable to resolve target URL for cc-proxy (provider misconfigured).");
|
|
1520
1789
|
return null;
|
|
@@ -1651,24 +1920,41 @@ function instrumentClaudeAgentQuery(originalQuery) {
|
|
|
1651
1920
|
...process.env,
|
|
1652
1921
|
...params.options?.env ?? {}
|
|
1653
1922
|
};
|
|
1654
|
-
const
|
|
1655
|
-
|
|
1923
|
+
const sessionCwd = typeof params.options?.cwd === "string" ? params.options.cwd : void 0;
|
|
1924
|
+
const settingSources = Array.isArray(params.options?.settingSources) ? params.options.settingSources : void 0;
|
|
1925
|
+
const callerSettings = params.options?.settings;
|
|
1926
|
+
const targetUrl = resolveTargetUrlFromEnv(mergedEnv, void 0, sessionCwd, settingSources, callerSettings);
|
|
1927
|
+
proxyInstance = await createProxyInstance({
|
|
1928
|
+
env: mergedEnv,
|
|
1929
|
+
cwd: sessionCwd,
|
|
1930
|
+
settingSources,
|
|
1931
|
+
settings: callerSettings,
|
|
1932
|
+
targetUrl
|
|
1933
|
+
});
|
|
1656
1934
|
if (proxyInstance && targetUrl) {
|
|
1657
1935
|
logger$19.debug(`Using proxy on port ${proxyInstance.port}`);
|
|
1658
1936
|
await Laminar.withSpan(span, async () => {
|
|
1659
1937
|
logger$19.debug("Setting trace to proxy instance...");
|
|
1660
1938
|
await setTraceToProxyInstance(proxyInstance);
|
|
1661
1939
|
});
|
|
1662
|
-
const varsToRemove = getEnvVarsToRemove(mergedEnv);
|
|
1940
|
+
const varsToRemove = getEnvVarsToRemove(mergedEnv, sessionCwd, settingSources);
|
|
1663
1941
|
if (!params.options) params.options = {};
|
|
1664
1942
|
if (!params.options.env) params.options.env = {};
|
|
1665
1943
|
params.options.env = { ...mergedEnv };
|
|
1666
1944
|
params.options.env.ANTHROPIC_BASE_URL = proxyInstance.baseUrl;
|
|
1667
1945
|
params.options.env.ANTHROPIC_ORIGINAL_BASE_URL = targetUrl;
|
|
1668
1946
|
for (const varName of varsToRemove) delete params.options.env[varName];
|
|
1669
|
-
|
|
1670
|
-
if (
|
|
1671
|
-
if (
|
|
1947
|
+
const subprocessEnv = params.options.env;
|
|
1948
|
+
if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_FOUNDRY")) subprocessEnv.ANTHROPIC_FOUNDRY_BASE_URL = proxyInstance.baseUrl;
|
|
1949
|
+
if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_BEDROCK")) subprocessEnv.ANTHROPIC_BEDROCK_BASE_URL = proxyInstance.baseUrl;
|
|
1950
|
+
if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_VERTEX")) subprocessEnv.ANTHROPIC_VERTEX_BASE_URL = proxyInstance.baseUrl;
|
|
1951
|
+
const flagSettings = buildProxyFlagSettings(callerSettings, proxyInstance.baseUrl, sessionCwd, settingSources);
|
|
1952
|
+
if (flagSettings === null) logger$19.warn(`Could not read options.settings ${JSON.stringify(callerSettings)}; Claude Code settings that define a base URL will bypass the Laminar proxy and produce no LLM spans.`);
|
|
1953
|
+
else {
|
|
1954
|
+
params.options.settings = flagSettings;
|
|
1955
|
+
const conflicting = Object.entries(readClaudeSettingsEnv(sessionCwd, settingSources)).filter(([key, value]) => PROXY_BASE_URL_ENV_KEYS.includes(key) && value !== "" && value !== proxyInstance.baseUrl).map(([key]) => key);
|
|
1956
|
+
if (conflicting.length > 0) logger$19.info(`Claude Code settings define ${conflicting.sort().join(", ")}, which outranks the subprocess environment. Injected settings so the Laminar proxy at ${proxyInstance.baseUrl} still intercepts API traffic; your settings files were not modified.`);
|
|
1957
|
+
}
|
|
1672
1958
|
} else logger$19.debug("No claude proxy server available. Proceeding without proxy.");
|
|
1673
1959
|
const originalGenerator = originalQuery(params);
|
|
1674
1960
|
for await (const message of originalGenerator) {
|
|
@@ -6604,9 +6890,9 @@ function observeBase({ name, contextProperties, spanAttributes, input, ignoreInp
|
|
|
6604
6890
|
return _opentelemetry_api.context.with(entityContext, () => getTracer().startActiveSpan(name, { attributes: spanAttributes }, entityContext, (span) => {
|
|
6605
6891
|
if (shouldSendTraces() && !ignoreInput) try {
|
|
6606
6892
|
const spanInput = inputParameters ?? args;
|
|
6607
|
-
if (input !== void 0) span.setAttribute(require_dist.SPAN_INPUT, typeof input === "string" ? input : serialize(input));
|
|
6608
|
-
else if (spanInput.length === 1 && typeof spanInput[0] === "object" && !(spanInput[0] instanceof Map)) span.setAttribute(require_dist.SPAN_INPUT, typeof spanInput[0] === "string" ? spanInput[0] : serialize(spanInput[0]));
|
|
6609
|
-
else span.setAttribute(require_dist.SPAN_INPUT, serialize(spanInput.length > 0 ? spanInput : {}));
|
|
6893
|
+
if (input !== void 0) span.setAttribute(require_dist.SPAN_INPUT, typeof input === "string" ? require_dist.truncateSpanPayload(input, "input") : serialize(input, "input"));
|
|
6894
|
+
else if (spanInput.length === 1 && typeof spanInput[0] === "object" && !(spanInput[0] instanceof Map)) span.setAttribute(require_dist.SPAN_INPUT, typeof spanInput[0] === "string" ? require_dist.truncateSpanPayload(spanInput[0], "input") : serialize(spanInput[0], "input"));
|
|
6895
|
+
else span.setAttribute(require_dist.SPAN_INPUT, serialize(spanInput.length > 0 ? spanInput : {}, "input"));
|
|
6610
6896
|
} catch (error) {
|
|
6611
6897
|
logger$4.warn("Failed to serialize input: " + require_dist.errorMessage(error));
|
|
6612
6898
|
}
|
|
@@ -6659,7 +6945,7 @@ function observeBase({ name, contextProperties, spanAttributes, input, ignoreInp
|
|
|
6659
6945
|
}
|
|
6660
6946
|
if (streamInfo.type !== null) return handleStreamResult(res, streamInfo, span, ignoreOutput, serialize);
|
|
6661
6947
|
try {
|
|
6662
|
-
if (shouldSendTraces() && !ignoreOutput) span.setAttribute(require_dist.SPAN_OUTPUT, typeof res === "string" ? res : serialize(res));
|
|
6948
|
+
if (shouldSendTraces() && !ignoreOutput) span.setAttribute(require_dist.SPAN_OUTPUT, typeof res === "string" ? require_dist.truncateSpanPayload(res, "output") : serialize(res));
|
|
6663
6949
|
} catch (error) {
|
|
6664
6950
|
logger$4.warn("Failed to serialize output: " + require_dist.errorMessage(error));
|
|
6665
6951
|
} finally {
|
|
@@ -6687,7 +6973,7 @@ const normalizePayload = (payload, seen) => {
|
|
|
6687
6973
|
}
|
|
6688
6974
|
return payload;
|
|
6689
6975
|
};
|
|
6690
|
-
const serialize = (payload) => JSON.stringify(normalizePayload(payload, /* @__PURE__ */ new WeakSet()));
|
|
6976
|
+
const serialize = (payload, kind = "output") => require_dist.truncateSpanPayload(JSON.stringify(normalizePayload(payload, /* @__PURE__ */ new WeakSet())), kind);
|
|
6691
6977
|
//#endregion
|
|
6692
6978
|
//#region src/decorators.ts
|
|
6693
6979
|
const logger$3 = require_dist.initializeLogger();
|
|
@@ -7064,6 +7350,7 @@ var Evaluation = class {
|
|
|
7064
7350
|
this.frontendPort = config?.frontendPort;
|
|
7065
7351
|
this.progressReporter = new EvaluationReporter(config?.baseUrl, config?.frontendPort);
|
|
7066
7352
|
this.data = data;
|
|
7353
|
+
this.datasetSource = data instanceof EvaluationDataset ? data.sourceDataset() : void 0;
|
|
7067
7354
|
this.executor = executor;
|
|
7068
7355
|
this.evaluators = evaluators;
|
|
7069
7356
|
this.groupName = groupName;
|
|
@@ -7110,22 +7397,24 @@ var Evaluation = class {
|
|
|
7110
7397
|
}
|
|
7111
7398
|
async run() {
|
|
7112
7399
|
if (this.isFinished) throw new Error("Evaluation is already finished");
|
|
7113
|
-
if (this.data instanceof
|
|
7114
|
-
this.
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7400
|
+
if (this.data instanceof EvaluationDataset) {
|
|
7401
|
+
const source = this.datasetSource;
|
|
7402
|
+
source?.setClient(this.client);
|
|
7403
|
+
if (source && !source.id) try {
|
|
7404
|
+
const datasets = await this.client.datasets.getDatasetByName(source.name);
|
|
7405
|
+
if (datasets.length > 0) source.id = datasets[0].id;
|
|
7406
|
+
else logger$2.warn(`Dataset ${source.name} not found`);
|
|
7119
7407
|
} catch (error) {
|
|
7120
|
-
logger$2.warn(`Error getting dataset ${
|
|
7408
|
+
logger$2.warn(`Error getting dataset ${source.name}: ` + require_dist.errorMessage(error));
|
|
7121
7409
|
}
|
|
7122
7410
|
}
|
|
7123
7411
|
let resultDatapoints;
|
|
7124
7412
|
try {
|
|
7413
|
+
const length = await this.getLength();
|
|
7125
7414
|
const evaluation = await this.client.evals.init(this.name, this.groupName, withSessionMetadata(this.metadata));
|
|
7126
7415
|
const url = getEvaluationUrl(evaluation.projectId, evaluation.id, this.progressReporter.baseUrl, this.frontendPort);
|
|
7127
7416
|
process.stdout.write(`\nCheck results at ${url}\n`);
|
|
7128
|
-
this.progressReporter.start({ length
|
|
7417
|
+
this.progressReporter.start({ length });
|
|
7129
7418
|
resultDatapoints = await this.evaluateInBatches(evaluation.id);
|
|
7130
7419
|
const averageScores = getAverageScores(resultDatapoints);
|
|
7131
7420
|
if (this.uploadPromises.length > 0) await Promise.all(this.uploadPromises);
|
|
@@ -7206,8 +7495,8 @@ var Evaluation = class {
|
|
|
7206
7495
|
executorSpanId,
|
|
7207
7496
|
index
|
|
7208
7497
|
};
|
|
7209
|
-
if (this.
|
|
7210
|
-
datasetId: this.
|
|
7498
|
+
if (this.datasetSource?.id && datapoint.id && datapoint.createdAt) partialDatapoint.datasetLink = {
|
|
7499
|
+
datasetId: this.datasetSource.id,
|
|
7211
7500
|
datapointId: datapoint.id,
|
|
7212
7501
|
createdAt: datapoint.createdAt
|
|
7213
7502
|
};
|
|
@@ -7261,8 +7550,8 @@ var Evaluation = class {
|
|
|
7261
7550
|
executorSpanId,
|
|
7262
7551
|
index
|
|
7263
7552
|
};
|
|
7264
|
-
if (this.
|
|
7265
|
-
datasetId: this.
|
|
7553
|
+
if (this.datasetSource?.id && datapoint.id && datapoint.createdAt) resultDatapoint.datasetLink = {
|
|
7554
|
+
datasetId: this.datasetSource.id,
|
|
7266
7555
|
datapointId: datapoint.id,
|
|
7267
7556
|
createdAt: datapoint.createdAt
|
|
7268
7557
|
};
|