@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/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-oS06mAi1.cjs");
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.fetchedItems = [];
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
- async fetchBatch() {
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: this.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.fetchBatch();
166
+ if (this.len === null) await this.fetchPage(0);
83
167
  return this.len;
84
168
  }
85
169
  async get(index) {
86
- if (index >= this.fetchedItems.length) await this.fetchBatch();
87
- return this.fetchedItems[index];
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-Bf15ARiL.cjs")).then((n) => n.file_utils_exports);
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 if environment variable value is truthy (equals '1')
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) => value === "1";
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 as fallback.
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 getEnvValue = (key) => envDict[key] || process.env[key];
1395
- const httpsProxy = getEnvValue("HTTPS_PROXY");
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 = ["HTTPS_PROXY", "HTTP_PROXY"];
1435
- const getEnvValue = (key) => envDict[key] || process.env[key];
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 targetUrl = resolveTargetUrlFromEnv(mergedEnv);
1655
- proxyInstance = await createProxyInstance({ env: mergedEnv });
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
- if (params.options.env.CLAUDE_CODE_USE_FOUNDRY === "1") params.options.env.ANTHROPIC_FOUNDRY_BASE_URL = proxyInstance.baseUrl;
1670
- if (params.options.env.CLAUDE_CODE_USE_BEDROCK === "1") params.options.env.ANTHROPIC_BEDROCK_BASE_URL = proxyInstance.baseUrl;
1671
- if (params.options.env.CLAUDE_CODE_USE_VERTEX === "1") params.options.env.ANTHROPIC_VERTEX_BASE_URL = proxyInstance.baseUrl;
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 LaminarDataset) {
7114
- this.data.setClient(this.client);
7115
- if (!this.data.id) try {
7116
- const datasets = await this.client.datasets.getDatasetByName(this.data.name);
7117
- if (datasets.length > 0) this.data.id = datasets[0].id;
7118
- else logger$2.warn(`Dataset ${this.data.name} not found`);
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 ${this.data.name}: ` + require_dist.errorMessage(error));
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: await this.getLength() });
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.data instanceof LaminarDataset && this.data.id && datapoint.id && datapoint.createdAt) partialDatapoint.datasetLink = {
7210
- datasetId: this.data.id,
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.data instanceof LaminarDataset && this.data.id && datapoint.id && datapoint.createdAt) resultDatapoint.datasetLink = {
7265
- datasetId: this.data.id,
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
  };