@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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as __exportAll, S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-BUitiaxR.cjs";
1
+ import { C as __exportAll, S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-CeDsphK5.cjs";
2
2
  import { ServerResponse } from "node:http";
3
3
  import { ReadableSpan, SpanExporter, SpanProcessor, TimedEvent } from "@opentelemetry/sdk-trace-base";
4
4
  import { AttributeValue, Attributes, Context, Exception, HrTime, Link, Span, Span as Span$1, SpanContext, SpanKind, SpanStatus, TimeInput, Tracer, TracerProvider } from "@opentelemetry/api";
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-gHrXUnIp.mjs";
1
+ import { S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-pCcE5lVy.mjs";
2
2
  import { AttributeValue, Attributes, Context, Exception, HrTime, Link, Span, Span as Span$1, SpanContext, SpanKind, SpanStatus, TimeInput, Tracer, TracerProvider } from "@opentelemetry/api";
3
3
  import { Instrumentation, InstrumentationBase } from "@opentelemetry/instrumentation";
4
4
  import { ReadableSpan, SpanExporter, SpanProcessor, TimedEvent } from "@opentelemetry/sdk-trace-base";
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { r as __require } from "./rolldown-runtime-2rV9d50f.mjs";
2
- import { A as SPAN_INSTRUMENTATION_SOURCE, B as DEBUG_SESSION_DIR, C as PARENT_SPAN_IDS_PATH, D as SPAN_INPUT, E as SPAN_IDS_PATH, F as SPAN_TYPE, H as TracingLevel, I as TRACE_HAS_BROWSER_SESSION, L as TRACE_TYPE, M as SPAN_OUTPUT, N as SPAN_PATH, O as SPAN_INSTRUMENTATION_SCOPE_NAME, P as SPAN_SDK_VERSION, R as USER_ID, S as LaminarAttributes, T as SESSION_ID, U as errorMessage, V as DEBUG_SESSION_FILE, _ as tryToOtelSpanContext, b as ASSOCIATION_PROPERTIES_OVERRIDES, c as initializeLogger, d as newUUID, f as normalizeOtelSpanId, g as parseOtelHeaders, h as otelTraceIdToUUID, i as deserializeLaminarSpanContext, j as SPAN_LANGUAGE_VERSION, k as SPAN_INSTRUMENTATION_SCOPE_VERSION, l as loadEnv, m as otelSpanIdToUUID, n as NIL_UUID, o as getFrontendUrl, p as normalizeOtelTraceId, r as Semaphore, s as getOtelEnvVar, t as LaminarClient, u as metadataToAttributes, v as validateTracingConfig, w as PARENT_SPAN_PATH, x as HUMAN_EVALUATOR_OPTIONS, y as ASSOCIATION_PROPERTIES, z as version } from "./dist-Dgq2z7AD.mjs";
2
+ import { A as SPAN_INSTRUMENTATION_SCOPE_VERSION, B as version, C as LaminarAttributes, D as SPAN_IDS_PATH, E as SESSION_ID, F as SPAN_SDK_VERSION, H as DEBUG_SESSION_FILE, I as SPAN_TYPE, L as TRACE_HAS_BROWSER_SESSION, M as SPAN_LANGUAGE_VERSION, N as SPAN_OUTPUT, O as SPAN_INPUT, P as SPAN_PATH, R as TRACE_TYPE, S as HUMAN_EVALUATOR_OPTIONS, T as PARENT_SPAN_PATH, U as TracingLevel, V as DEBUG_SESSION_DIR, W as errorMessage, _ as truncateSpanPayload, b as ASSOCIATION_PROPERTIES, c as initializeLogger, d as newUUID, f as normalizeOtelSpanId, g as parseOtelHeaders, h as otelTraceIdToUUID, i as deserializeLaminarSpanContext, j as SPAN_INSTRUMENTATION_SOURCE, k as SPAN_INSTRUMENTATION_SCOPE_NAME, l as loadEnv, m as otelSpanIdToUUID, n as NIL_UUID, o as getFrontendUrl, p as normalizeOtelTraceId, r as Semaphore, s as getOtelEnvVar, t as LaminarClient, u as metadataToAttributes, v as tryToOtelSpanContext, w as PARENT_SPAN_IDS_PATH, x as ASSOCIATION_PROPERTIES_OVERRIDES, y as validateTracingConfig, z as USER_ID } from "./dist-D-1LE3Xx.mjs";
3
3
  import { n as TRACEPARENT_HEADER, t as LAMINAR_SPAN_CONTEXT_HEADER } from "./consts-3AfXaMBI.mjs";
4
4
  import { DiagConsoleLogger, DiagLogLevel, ROOT_CONTEXT, SpanKind, SpanStatusCode, TraceFlags, context, createContextKey, diag, isSpanContextValid, trace } from "@opentelemetry/api";
5
5
  import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
@@ -34,6 +34,25 @@ import * as cliProgress from "cli-progress";
34
34
  import { blake3 } from "@noble/hashes/blake3.js";
35
35
  import { bytesToHex } from "@noble/hashes/utils.js";
36
36
  import * as diagnosticsChannel from "node:diagnostics_channel";
37
+ //#region src/datasets/prng.ts
38
+ const UINT32 = 4294967296;
39
+ const seededPerm = (n, seed) => {
40
+ let state = seed >>> 0;
41
+ const next = () => {
42
+ state = state + 1831565813 >>> 0;
43
+ let t = state;
44
+ t = Math.imul(t ^ t >>> 15, t | 1);
45
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
46
+ return ((t ^ t >>> 14) >>> 0) / UINT32;
47
+ };
48
+ const ix = Array.from({ length: n }, (_, i) => i);
49
+ for (let i = n - 1; i > 0; i--) {
50
+ const j = Math.floor(next() * (i + 1));
51
+ [ix[i], ix[j]] = [ix[j], ix[i]];
52
+ }
53
+ return ix;
54
+ };
55
+ //#endregion
37
56
  //#region src/datasets.ts
38
57
  const DEFAULT_FETCH_SIZE = 25;
39
58
  var EvaluationDataset = class {
@@ -42,13 +61,66 @@ var EvaluationDataset = class {
42
61
  for (let i = Math.max(start, 0); i < Math.min(end, await this.size()); i++) result.push(await this.get(i));
43
62
  return result;
44
63
  }
64
+ sourceDataset() {}
65
+ take(n) {
66
+ return new Transformed(this, async (base) => {
67
+ if (!Number.isInteger(n)) throw new Error(`take count ${n} is not an integer`);
68
+ const size = await base.size();
69
+ const count = Math.max(0, Math.min(n, size));
70
+ return Array.from({ length: count }, (_, i) => i);
71
+ });
72
+ }
73
+ select(indices) {
74
+ const selected = [...indices];
75
+ return new Transformed(this, async (base) => {
76
+ const size = await base.size();
77
+ for (const index of selected) {
78
+ if (!Number.isInteger(index)) throw new Error(`select index ${index} is not an integer`);
79
+ if (index < 0 || index >= size) throw new Error(`select index ${index} is out of range for dataset of size ${size}`);
80
+ }
81
+ return selected;
82
+ });
83
+ }
84
+ shuffle({ seed = 0 } = {}) {
85
+ return new Transformed(this, async (base) => seededPerm(await base.size(), seed));
86
+ }
87
+ };
88
+ var Transformed = class extends EvaluationDataset {
89
+ constructor(base, resolve) {
90
+ super();
91
+ this.indices = null;
92
+ this.resolving = null;
93
+ this.base = base;
94
+ this.resolve = resolve;
95
+ }
96
+ resolveIndices() {
97
+ if (this.indices !== null) return Promise.resolve(this.indices);
98
+ if (this.resolving === null) this.resolving = this.resolve(this.base).then((indices) => {
99
+ this.indices = indices;
100
+ return indices;
101
+ }).catch((err) => {
102
+ this.resolving = null;
103
+ throw err;
104
+ });
105
+ return this.resolving;
106
+ }
107
+ async size() {
108
+ return (await this.resolveIndices()).length;
109
+ }
110
+ async get(index) {
111
+ const indices = await this.resolveIndices();
112
+ if (index < 0 || index >= indices.length) throw new Error(`Index ${index} is out of range for dataset of size ${indices.length}`);
113
+ return await this.base.get(indices[index]);
114
+ }
115
+ sourceDataset() {
116
+ return this.base.sourceDataset();
117
+ }
45
118
  };
46
119
  var LaminarDataset = class extends EvaluationDataset {
47
120
  constructor(name, options) {
48
121
  super();
49
- this.fetchedItems = [];
122
+ this.pages = /* @__PURE__ */ new Map();
50
123
  this.len = null;
51
- this.offset = 0;
52
124
  this.client = void 0;
53
125
  if (!name && !options?.id) throw new Error("Either name or id must be provided");
54
126
  if (name && options?.id) throw new Error("Only one of name or id must be provided");
@@ -59,25 +131,42 @@ var LaminarDataset = class extends EvaluationDataset {
59
131
  setClient(client) {
60
132
  this.client = client;
61
133
  }
62
- async fetchBatch() {
134
+ sourceDataset() {
135
+ return this;
136
+ }
137
+ fetchPage(offset) {
138
+ const existing = this.pages.get(offset);
139
+ if (existing) return existing;
140
+ const pending = this.doFetchPage(offset).catch((err) => {
141
+ this.pages.delete(offset);
142
+ throw err;
143
+ });
144
+ this.pages.set(offset, pending);
145
+ return pending;
146
+ }
147
+ async doFetchPage(offset) {
63
148
  if (!this.client) throw new Error("Client not set");
64
149
  const identifier = this.id ? { id: this.id } : { name: this.name };
65
150
  const resp = await this.client.datasets.pull({
66
151
  ...identifier,
67
- offset: this.offset,
152
+ offset,
68
153
  limit: this.fetchSize
69
154
  });
70
- this.fetchedItems = this.fetchedItems.concat(resp.items);
71
- this.offset = this.fetchedItems.length;
72
155
  if (this.len === null) this.len = resp.totalCount;
156
+ return resp.items;
73
157
  }
74
158
  async size() {
75
- if (this.len === null) await this.fetchBatch();
159
+ if (this.len === null) await this.fetchPage(0);
76
160
  return this.len;
77
161
  }
78
162
  async get(index) {
79
- if (index >= this.fetchedItems.length) await this.fetchBatch();
80
- return this.fetchedItems[index];
163
+ if (index < 0) throw new Error(`Index ${index} is out of range`);
164
+ if (this.len !== null && index >= this.len) throw new Error(`Index ${index} is out of range for dataset of size ${this.len}`);
165
+ const offset = Math.floor(index / this.fetchSize) * this.fetchSize;
166
+ const page = await this.fetchPage(offset);
167
+ const local = index - offset;
168
+ if (local >= page.length) throw new Error(`Index ${index} is out of range for dataset of size ${this.len ?? "unknown"}`);
169
+ return page[local];
81
170
  }
82
171
  /**
83
172
  * Push data from files to this dataset.
@@ -87,7 +176,7 @@ var LaminarDataset = class extends EvaluationDataset {
87
176
  */
88
177
  async push(paths, recursive = false) {
89
178
  if (!this.client) throw new Error("Client not set");
90
- const { loadFromPaths } = await import("./file-utils-D0UCmQi0.mjs").then((n) => n.t);
179
+ const { loadFromPaths } = await import("./file-utils-DNyYjjV3.mjs").then((n) => n.t);
91
180
  const data = await loadFromPaths(Array.isArray(paths) ? paths : [paths], recursive);
92
181
  if (data.length === 0) {
93
182
  console.warn("No data to push. Skipping");
@@ -1056,11 +1145,11 @@ var LaminarSpan = class LaminarSpan {
1056
1145
  }
1057
1146
  setInput(input) {
1058
1147
  const finalInput = typeof input === "string" ? input : JSON.stringify(input);
1059
- this._span.setAttribute(SPAN_INPUT, finalInput);
1148
+ this._span.setAttribute(SPAN_INPUT, truncateSpanPayload(finalInput, "input"));
1060
1149
  }
1061
1150
  setOutput(output) {
1062
1151
  const finalOutput = typeof output === "string" ? output : JSON.stringify(output);
1063
- this._span.setAttribute(SPAN_OUTPUT, finalOutput);
1152
+ this._span.setAttribute(SPAN_OUTPUT, truncateSpanPayload(finalOutput, "output"));
1064
1153
  }
1065
1154
  setTags(tags) {
1066
1155
  this._span.setAttribute(`${ASSOCIATION_PROPERTIES}.tags`, Array.from(new Set(tags)));
@@ -1333,12 +1422,181 @@ const BEDROCK_USE_ENV = "CLAUDE_CODE_USE_BEDROCK";
1333
1422
  const BEDROCK_AWS_REGION_ENV = "AWS_REGION";
1334
1423
  const VERTEX_BASE_URL_ENV = "ANTHROPIC_VERTEX_BASE_URL";
1335
1424
  const VERTEX_USE_ENV = "CLAUDE_CODE_USE_VERTEX";
1425
+ const PROXY_BASE_URL_ENV_KEYS = [
1426
+ "ANTHROPIC_BASE_URL",
1427
+ FOUNDRY_BASE_URL_ENV,
1428
+ BEDROCK_BASE_URL_ENV,
1429
+ VERTEX_BASE_URL_ENV
1430
+ ];
1431
+ const PROVIDER_BASE_URL_ENV_KEYS = [
1432
+ [FOUNDRY_BASE_URL_ENV, FOUNDRY_USE_ENV],
1433
+ [BEDROCK_BASE_URL_ENV, BEDROCK_USE_ENV],
1434
+ [VERTEX_BASE_URL_ENV, VERTEX_USE_ENV]
1435
+ ];
1436
+ const PROXY_ENV_KEYS = [
1437
+ "HTTP_PROXY",
1438
+ "HTTPS_PROXY",
1439
+ "http_proxy",
1440
+ "https_proxy"
1441
+ ];
1442
+ const PROXY_NEUTRALIZED_ENV_KEYS = [...PROXY_ENV_KEYS, FOUNDRY_RESOURCE_ENV];
1443
+ const UPSTREAM_SETTINGS_EXCLUDED_ENV_KEYS = PROXY_ENV_KEYS;
1336
1444
  const activeProxyServers = /* @__PURE__ */ new Set();
1337
1445
  let globalShutdownRegistered = false;
1338
1446
  /**
1339
- * Check if environment variable value is truthy (equals '1')
1447
+ * Check whether an env value enables a feature.
1448
+ *
1449
+ * Claude Code accepts `1`, `true`, `yes`, and `on` (case-insensitive) — verified
1450
+ * against the bundled CLI. Accepting only `"1"` would miss a provider the CLI
1451
+ * considers enabled, so we would blank its routing keys without pinning a base
1452
+ * URL and break the run.
1340
1453
  */
1341
- const isTruthyEnv = (value) => value === "1";
1454
+ const isTruthyEnv = (value) => {
1455
+ if (typeof value !== "string") return value === true;
1456
+ return [
1457
+ "1",
1458
+ "true",
1459
+ "yes",
1460
+ "on"
1461
+ ].includes(value.trim().toLowerCase());
1462
+ };
1463
+ /**
1464
+ * Whether a provider flag is enabled in the given env, using the CLI's own
1465
+ * truthiness rules.
1466
+ *
1467
+ * Exported so the subprocess-env pin path shares ONE definition of "enabled"
1468
+ * with `getEnvVarsToRemove` / `buildProxyFlagSettings`. If they disagree, the
1469
+ * resource gets stripped without a base URL being pinned and the CLI hard-fails.
1470
+ */
1471
+ const isProviderEnabledInEnv = (env, useKey) => isTruthyEnv(env[useKey]);
1472
+ /**
1473
+ * Load a Claude settings JSON file, or `null` when it could not be read.
1474
+ *
1475
+ * `null` (unreadable / malformed / not a JSON object) is deliberately distinct
1476
+ * from `{}` (a valid but empty settings file): callers that would otherwise
1477
+ * REPLACE a user's settings need to know they failed to read it.
1478
+ */
1479
+ const loadSettingsFile = (filePath) => {
1480
+ try {
1481
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"));
1482
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
1483
+ } catch {}
1484
+ return null;
1485
+ };
1486
+ const settingsEnvBlock = (settings) => {
1487
+ const env = settings.env;
1488
+ if (!env || typeof env !== "object" || Array.isArray(env)) return {};
1489
+ const result = {};
1490
+ for (const [key, value] of Object.entries(env)) if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") result[key] = String(value);
1491
+ return result;
1492
+ };
1493
+ /**
1494
+ * Read the merged `env` block from Claude Code's on-disk settings layers.
1495
+ *
1496
+ * Claude Code applies these to the CLI session with HIGHER priority than the
1497
+ * subprocess environment, so a user with `ANTHROPIC_BASE_URL` in
1498
+ * `~/.claude/settings.json` silently bypasses our proxy. We read them to resolve
1499
+ * the real upstream and to detect conflicts.
1500
+ *
1501
+ * Precedence (highest first): local project, shared project, user.
1502
+ *
1503
+ * `settingSources` mirrors `options.settingSources` and gates which layers are
1504
+ * read: `undefined` means the CLI loads all of them, an array means only those,
1505
+ * and `[]` disables on-disk settings entirely. Honoring it matters because
1506
+ * reading a layer the CLI was told to ignore would resolve an upstream the CLI
1507
+ * never uses, pointing the proxy at an unintended host.
1508
+ */
1509
+ const readClaudeSettingsEnv = (cwd, settingSources) => {
1510
+ const sessionCwd = cwd ?? process.cwd();
1511
+ const userDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
1512
+ const layers = [
1513
+ ["user", path.join(userDir, "settings.json")],
1514
+ ["project", path.join(sessionCwd, ".claude", "settings.json")],
1515
+ ["local", path.join(sessionCwd, ".claude", "settings.local.json")]
1516
+ ];
1517
+ const merged = {};
1518
+ for (const [source, filePath] of layers) {
1519
+ if (settingSources !== void 0 && !settingSources.includes(source)) continue;
1520
+ Object.assign(merged, settingsEnvBlock(loadSettingsFile(filePath) ?? {}));
1521
+ }
1522
+ return merged;
1523
+ };
1524
+ /**
1525
+ * Read the `env` block out of the caller's `options.settings` (the flag layer).
1526
+ *
1527
+ * This layer OUTRANKS every on-disk layer, so a gateway or provider config that
1528
+ * lives only here is what the CLI would actually use — and
1529
+ * `buildProxyFlagSettings` is about to overwrite those keys with the proxy URL.
1530
+ * Upstream resolution must therefore see it FIRST, or we forward to the wrong
1531
+ * host (or to the default endpoint) while the caller's gateway is silently lost.
1532
+ *
1533
+ * Returns `{}` for a value we could not read; the caller's own bail-out logic in
1534
+ * `buildProxyFlagSettings` handles that case.
1535
+ */
1536
+ const flagSettingsEnv = (existing, cwd) => {
1537
+ if (typeof existing === "object" && existing !== null) return settingsEnvBlock(existing);
1538
+ if (typeof existing !== "string" || !existing.trim()) return {};
1539
+ const trimmed = existing.trim();
1540
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
1541
+ try {
1542
+ const parsed = JSON.parse(trimmed);
1543
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return settingsEnvBlock(parsed);
1544
+ } catch {}
1545
+ return {};
1546
+ }
1547
+ return settingsEnvBlock(loadSettingsFile(path.isAbsolute(trimmed) ? trimmed : path.join(cwd ?? process.cwd(), trimmed)) ?? {});
1548
+ };
1549
+ /**
1550
+ * Build the `--settings` value that forces the CLI through our proxy.
1551
+ *
1552
+ * Claude Code resolves `env` from its settings layers with higher priority than
1553
+ * the subprocess environment, so rewriting `options.env` alone leaves a user with
1554
+ * `ANTHROPIC_BASE_URL` in `~/.claude/settings.json` talking straight to their
1555
+ * upstream while the proxy sees zero traffic (lmnr#2167). `--settings` is the
1556
+ * highest user-controlled layer, so writing the proxy URL there wins without ever
1557
+ * touching the user's files on disk.
1558
+ *
1559
+ * Layers merge per key, so keys we simply omit keep their lower-layer value.
1560
+ * Redirecting keys are therefore blanked rather than dropped.
1561
+ *
1562
+ * Returns the value to assign to `options.settings`, or `null` when the caller's
1563
+ * existing value is a file path we could not read (in that case the path must be
1564
+ * left alone so the CLI can still resolve it itself).
1565
+ */
1566
+ const buildProxyFlagSettings = (existing, proxyUrl, cwd, settingSources) => {
1567
+ let settingsObj = {};
1568
+ if (typeof existing === "object" && existing !== null) settingsObj = { ...existing };
1569
+ else if (typeof existing === "string" && existing.trim()) {
1570
+ const trimmed = existing.trim();
1571
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
1572
+ let parsed;
1573
+ try {
1574
+ parsed = JSON.parse(trimmed);
1575
+ } catch {
1576
+ return null;
1577
+ }
1578
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
1579
+ settingsObj = parsed;
1580
+ } else {
1581
+ const loaded = loadSettingsFile(path.isAbsolute(trimmed) ? trimmed : path.join(cwd ?? process.cwd(), trimmed));
1582
+ if (loaded === null) return null;
1583
+ settingsObj = loaded;
1584
+ }
1585
+ }
1586
+ const envDict = { ...settingsEnvBlock(settingsObj) };
1587
+ const settingsEnv = readClaudeSettingsEnv(cwd, settingSources);
1588
+ const inPlay = (key) => key in envDict || key in settingsEnv || process.env[key] !== void 0;
1589
+ envDict.ANTHROPIC_BASE_URL = proxyUrl;
1590
+ for (const [baseUrlKey, useKey] of PROVIDER_BASE_URL_ENV_KEYS) {
1591
+ if (isTruthyEnv(envDict[useKey]) || isTruthyEnv(settingsEnv[useKey]) || isTruthyEnv(process.env[useKey]) || inPlay(baseUrlKey)) envDict[baseUrlKey] = proxyUrl;
1592
+ if (baseUrlKey === FOUNDRY_BASE_URL_ENV && envDict[baseUrlKey] === proxyUrl) envDict[FOUNDRY_RESOURCE_ENV] = "";
1593
+ }
1594
+ for (const key of PROXY_NEUTRALIZED_ENV_KEYS) if (key in settingsEnv || key in envDict || process.env[key] !== void 0) envDict[key] = "";
1595
+ return {
1596
+ ...settingsObj,
1597
+ env: envDict
1598
+ };
1599
+ };
1342
1600
  /**
1343
1601
  * Read region for a given profile from ~/.aws/config.
1344
1602
  */
@@ -1377,17 +1635,27 @@ const getRegionFromAwsConfig = (profile) => {
1377
1635
  * 4. ANTHROPIC_BASE_URL - standard Anthropic API base URL
1378
1636
  * 5. Fall back to default (https://api.anthropic.com)
1379
1637
  *
1380
- * For each environment variable, checks envDict first, then process.env as fallback.
1638
+ * For each environment variable, checks envDict first, then process.env, then
1639
+ * Claude Code's on-disk settings `env` block. The settings layer is checked last
1640
+ * as a source for the *upstream* URL, but note it wins over process env inside
1641
+ * the CLI itself — see `buildProxyFlagSettings`.
1381
1642
  *
1382
1643
  * @param envDict - Dictionary of environment variables (e.g., from options.env)
1383
1644
  * @param fallback - Fallback URL if no other source found (default: DEFAULT_ANTHROPIC_BASE_URL)
1645
+ * @param cwd - Session root used to locate project settings (`options.cwd`)
1384
1646
  * @returns Resolved target URL, or null if provider is misconfigured
1385
1647
  */
1386
- const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL) => {
1387
- const getEnvValue = (key) => envDict[key] || process.env[key];
1388
- const httpsProxy = getEnvValue("HTTPS_PROXY");
1648
+ const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL, cwd, settingSources, settings) => {
1649
+ const flagEnv = flagSettingsEnv(settings, cwd);
1650
+ const settingsEnv = readClaudeSettingsEnv(cwd, settingSources);
1651
+ const getEnvValue = (key) => {
1652
+ const value = envDict[key] || process.env[key];
1653
+ if (value || UPSTREAM_SETTINGS_EXCLUDED_ENV_KEYS.includes(key)) return value;
1654
+ return flagEnv[key] || settingsEnv[key];
1655
+ };
1656
+ const httpsProxy = getEnvValue("HTTPS_PROXY") || getEnvValue("https_proxy");
1389
1657
  if (httpsProxy) return httpsProxy.replace(/\/$/, "");
1390
- const httpProxy = getEnvValue("HTTP_PROXY");
1658
+ const httpProxy = getEnvValue("HTTP_PROXY") || getEnvValue("http_proxy");
1391
1659
  if (httpProxy) return httpProxy.replace(/\/$/, "");
1392
1660
  if (isTruthyEnv(getEnvValue(FOUNDRY_USE_ENV))) {
1393
1661
  const foundryBaseUrl = getEnvValue(FOUNDRY_BASE_URL_ENV);
@@ -1423,9 +1691,10 @@ const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL)
1423
1691
  * @param envDict - Dictionary of environment variables
1424
1692
  * @returns Array of environment variable keys to remove
1425
1693
  */
1426
- const getEnvVarsToRemove = (envDict) => {
1427
- const toRemove = ["HTTPS_PROXY", "HTTP_PROXY"];
1428
- const getEnvValue = (key) => envDict[key] || process.env[key];
1694
+ const getEnvVarsToRemove = (envDict, cwd, settingSources) => {
1695
+ const toRemove = [...PROXY_ENV_KEYS];
1696
+ const settingsEnv = readClaudeSettingsEnv(cwd, settingSources);
1697
+ const getEnvValue = (key) => envDict[key] || process.env[key] || settingsEnv[key];
1429
1698
  if (isTruthyEnv(getEnvValue(FOUNDRY_USE_ENV))) toRemove.push(FOUNDRY_RESOURCE_ENV);
1430
1699
  return toRemove;
1431
1700
  };
@@ -1500,14 +1769,14 @@ const registerGlobalProxyShutdown = () => {
1500
1769
  * Create and start a new claude-code proxy server instance
1501
1770
  * Each call creates an independent proxy on a unique port
1502
1771
  */
1503
- const createProxyInstance = async ({ env }) => {
1772
+ const createProxyInstance = async ({ env, cwd, settingSources, settings, targetUrl: resolvedTargetUrl }) => {
1504
1773
  try {
1505
1774
  const port = await findAvailablePort(DEFAULT_CC_PROXY_PORT, CC_PROXY_PORT_ATTEMPTS);
1506
1775
  if (port === null) {
1507
1776
  logger$20.warn("Unable to allocate port for cc-proxy.");
1508
1777
  return null;
1509
1778
  }
1510
- const targetUrl = resolveTargetUrlFromEnv(env);
1779
+ const targetUrl = resolvedTargetUrl ?? resolveTargetUrlFromEnv(env, void 0, cwd, settingSources, settings);
1511
1780
  if (!targetUrl) {
1512
1781
  logger$20.warn("Unable to resolve target URL for cc-proxy (provider misconfigured).");
1513
1782
  return null;
@@ -1644,24 +1913,41 @@ function instrumentClaudeAgentQuery(originalQuery) {
1644
1913
  ...process.env,
1645
1914
  ...params.options?.env ?? {}
1646
1915
  };
1647
- const targetUrl = resolveTargetUrlFromEnv(mergedEnv);
1648
- proxyInstance = await createProxyInstance({ env: mergedEnv });
1916
+ const sessionCwd = typeof params.options?.cwd === "string" ? params.options.cwd : void 0;
1917
+ const settingSources = Array.isArray(params.options?.settingSources) ? params.options.settingSources : void 0;
1918
+ const callerSettings = params.options?.settings;
1919
+ const targetUrl = resolveTargetUrlFromEnv(mergedEnv, void 0, sessionCwd, settingSources, callerSettings);
1920
+ proxyInstance = await createProxyInstance({
1921
+ env: mergedEnv,
1922
+ cwd: sessionCwd,
1923
+ settingSources,
1924
+ settings: callerSettings,
1925
+ targetUrl
1926
+ });
1649
1927
  if (proxyInstance && targetUrl) {
1650
1928
  logger$19.debug(`Using proxy on port ${proxyInstance.port}`);
1651
1929
  await Laminar.withSpan(span, async () => {
1652
1930
  logger$19.debug("Setting trace to proxy instance...");
1653
1931
  await setTraceToProxyInstance(proxyInstance);
1654
1932
  });
1655
- const varsToRemove = getEnvVarsToRemove(mergedEnv);
1933
+ const varsToRemove = getEnvVarsToRemove(mergedEnv, sessionCwd, settingSources);
1656
1934
  if (!params.options) params.options = {};
1657
1935
  if (!params.options.env) params.options.env = {};
1658
1936
  params.options.env = { ...mergedEnv };
1659
1937
  params.options.env.ANTHROPIC_BASE_URL = proxyInstance.baseUrl;
1660
1938
  params.options.env.ANTHROPIC_ORIGINAL_BASE_URL = targetUrl;
1661
1939
  for (const varName of varsToRemove) delete params.options.env[varName];
1662
- if (params.options.env.CLAUDE_CODE_USE_FOUNDRY === "1") params.options.env.ANTHROPIC_FOUNDRY_BASE_URL = proxyInstance.baseUrl;
1663
- if (params.options.env.CLAUDE_CODE_USE_BEDROCK === "1") params.options.env.ANTHROPIC_BEDROCK_BASE_URL = proxyInstance.baseUrl;
1664
- if (params.options.env.CLAUDE_CODE_USE_VERTEX === "1") params.options.env.ANTHROPIC_VERTEX_BASE_URL = proxyInstance.baseUrl;
1940
+ const subprocessEnv = params.options.env;
1941
+ if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_FOUNDRY")) subprocessEnv.ANTHROPIC_FOUNDRY_BASE_URL = proxyInstance.baseUrl;
1942
+ if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_BEDROCK")) subprocessEnv.ANTHROPIC_BEDROCK_BASE_URL = proxyInstance.baseUrl;
1943
+ if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_VERTEX")) subprocessEnv.ANTHROPIC_VERTEX_BASE_URL = proxyInstance.baseUrl;
1944
+ const flagSettings = buildProxyFlagSettings(callerSettings, proxyInstance.baseUrl, sessionCwd, settingSources);
1945
+ 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.`);
1946
+ else {
1947
+ params.options.settings = flagSettings;
1948
+ const conflicting = Object.entries(readClaudeSettingsEnv(sessionCwd, settingSources)).filter(([key, value]) => PROXY_BASE_URL_ENV_KEYS.includes(key) && value !== "" && value !== proxyInstance.baseUrl).map(([key]) => key);
1949
+ 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.`);
1950
+ }
1665
1951
  } else logger$19.debug("No claude proxy server available. Proceeding without proxy.");
1666
1952
  const originalGenerator = originalQuery(params);
1667
1953
  for await (const message of originalGenerator) {
@@ -6597,9 +6883,9 @@ function observeBase({ name, contextProperties, spanAttributes, input, ignoreInp
6597
6883
  return context.with(entityContext, () => getTracer().startActiveSpan(name, { attributes: spanAttributes }, entityContext, (span) => {
6598
6884
  if (shouldSendTraces() && !ignoreInput) try {
6599
6885
  const spanInput = inputParameters ?? args;
6600
- if (input !== void 0) span.setAttribute(SPAN_INPUT, typeof input === "string" ? input : serialize(input));
6601
- else if (spanInput.length === 1 && typeof spanInput[0] === "object" && !(spanInput[0] instanceof Map)) span.setAttribute(SPAN_INPUT, typeof spanInput[0] === "string" ? spanInput[0] : serialize(spanInput[0]));
6602
- else span.setAttribute(SPAN_INPUT, serialize(spanInput.length > 0 ? spanInput : {}));
6886
+ if (input !== void 0) span.setAttribute(SPAN_INPUT, typeof input === "string" ? truncateSpanPayload(input, "input") : serialize(input, "input"));
6887
+ else if (spanInput.length === 1 && typeof spanInput[0] === "object" && !(spanInput[0] instanceof Map)) span.setAttribute(SPAN_INPUT, typeof spanInput[0] === "string" ? truncateSpanPayload(spanInput[0], "input") : serialize(spanInput[0], "input"));
6888
+ else span.setAttribute(SPAN_INPUT, serialize(spanInput.length > 0 ? spanInput : {}, "input"));
6603
6889
  } catch (error) {
6604
6890
  logger$4.warn("Failed to serialize input: " + errorMessage(error));
6605
6891
  }
@@ -6652,7 +6938,7 @@ function observeBase({ name, contextProperties, spanAttributes, input, ignoreInp
6652
6938
  }
6653
6939
  if (streamInfo.type !== null) return handleStreamResult(res, streamInfo, span, ignoreOutput, serialize);
6654
6940
  try {
6655
- if (shouldSendTraces() && !ignoreOutput) span.setAttribute(SPAN_OUTPUT, typeof res === "string" ? res : serialize(res));
6941
+ if (shouldSendTraces() && !ignoreOutput) span.setAttribute(SPAN_OUTPUT, typeof res === "string" ? truncateSpanPayload(res, "output") : serialize(res));
6656
6942
  } catch (error) {
6657
6943
  logger$4.warn("Failed to serialize output: " + errorMessage(error));
6658
6944
  } finally {
@@ -6680,7 +6966,7 @@ const normalizePayload = (payload, seen) => {
6680
6966
  }
6681
6967
  return payload;
6682
6968
  };
6683
- const serialize = (payload) => JSON.stringify(normalizePayload(payload, /* @__PURE__ */ new WeakSet()));
6969
+ const serialize = (payload, kind = "output") => truncateSpanPayload(JSON.stringify(normalizePayload(payload, /* @__PURE__ */ new WeakSet())), kind);
6684
6970
  //#endregion
6685
6971
  //#region src/decorators.ts
6686
6972
  const logger$3 = initializeLogger();
@@ -7057,6 +7343,7 @@ var Evaluation = class {
7057
7343
  this.frontendPort = config?.frontendPort;
7058
7344
  this.progressReporter = new EvaluationReporter(config?.baseUrl, config?.frontendPort);
7059
7345
  this.data = data;
7346
+ this.datasetSource = data instanceof EvaluationDataset ? data.sourceDataset() : void 0;
7060
7347
  this.executor = executor;
7061
7348
  this.evaluators = evaluators;
7062
7349
  this.groupName = groupName;
@@ -7103,22 +7390,24 @@ var Evaluation = class {
7103
7390
  }
7104
7391
  async run() {
7105
7392
  if (this.isFinished) throw new Error("Evaluation is already finished");
7106
- if (this.data instanceof LaminarDataset) {
7107
- this.data.setClient(this.client);
7108
- if (!this.data.id) try {
7109
- const datasets = await this.client.datasets.getDatasetByName(this.data.name);
7110
- if (datasets.length > 0) this.data.id = datasets[0].id;
7111
- else logger$2.warn(`Dataset ${this.data.name} not found`);
7393
+ if (this.data instanceof EvaluationDataset) {
7394
+ const source = this.datasetSource;
7395
+ source?.setClient(this.client);
7396
+ if (source && !source.id) try {
7397
+ const datasets = await this.client.datasets.getDatasetByName(source.name);
7398
+ if (datasets.length > 0) source.id = datasets[0].id;
7399
+ else logger$2.warn(`Dataset ${source.name} not found`);
7112
7400
  } catch (error) {
7113
- logger$2.warn(`Error getting dataset ${this.data.name}: ` + errorMessage(error));
7401
+ logger$2.warn(`Error getting dataset ${source.name}: ` + errorMessage(error));
7114
7402
  }
7115
7403
  }
7116
7404
  let resultDatapoints;
7117
7405
  try {
7406
+ const length = await this.getLength();
7118
7407
  const evaluation = await this.client.evals.init(this.name, this.groupName, withSessionMetadata(this.metadata));
7119
7408
  const url = getEvaluationUrl(evaluation.projectId, evaluation.id, this.progressReporter.baseUrl, this.frontendPort);
7120
7409
  process.stdout.write(`\nCheck results at ${url}\n`);
7121
- this.progressReporter.start({ length: await this.getLength() });
7410
+ this.progressReporter.start({ length });
7122
7411
  resultDatapoints = await this.evaluateInBatches(evaluation.id);
7123
7412
  const averageScores = getAverageScores(resultDatapoints);
7124
7413
  if (this.uploadPromises.length > 0) await Promise.all(this.uploadPromises);
@@ -7199,8 +7488,8 @@ var Evaluation = class {
7199
7488
  executorSpanId,
7200
7489
  index
7201
7490
  };
7202
- if (this.data instanceof LaminarDataset && this.data.id && datapoint.id && datapoint.createdAt) partialDatapoint.datasetLink = {
7203
- datasetId: this.data.id,
7491
+ if (this.datasetSource?.id && datapoint.id && datapoint.createdAt) partialDatapoint.datasetLink = {
7492
+ datasetId: this.datasetSource.id,
7204
7493
  datapointId: datapoint.id,
7205
7494
  createdAt: datapoint.createdAt
7206
7495
  };
@@ -7254,8 +7543,8 @@ var Evaluation = class {
7254
7543
  executorSpanId,
7255
7544
  index
7256
7545
  };
7257
- if (this.data instanceof LaminarDataset && this.data.id && datapoint.id && datapoint.createdAt) resultDatapoint.datasetLink = {
7258
- datasetId: this.data.id,
7546
+ if (this.datasetSource?.id && datapoint.id && datapoint.createdAt) resultDatapoint.datasetLink = {
7547
+ datasetId: this.datasetSource.id,
7259
7548
  datapointId: datapoint.id,
7260
7549
  createdAt: datapoint.createdAt
7261
7550
  };