langwatch 1.12.1 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/agent/index.d.mts +5 -1
  2. package/dist/agent/index.d.ts +5 -1
  3. package/dist/agent/index.js +239 -14
  4. package/dist/agent/index.js.map +1 -1
  5. package/dist/agent/index.mjs +239 -14
  6. package/dist/agent/index.mjs.map +1 -1
  7. package/dist/{chunk-OSVJ65OO.js → chunk-7R54TMZZ.js} +2 -2
  8. package/dist/{chunk-OSVJ65OO.js.map → chunk-7R54TMZZ.js.map} +1 -1
  9. package/dist/{chunk-H2DJGGYQ.js → chunk-G64XZMIU.js} +12 -12
  10. package/dist/{chunk-H2DJGGYQ.js.map → chunk-G64XZMIU.js.map} +1 -1
  11. package/dist/{chunk-53NOLJEX.mjs → chunk-N3755EHD.mjs} +2 -2
  12. package/dist/{chunk-2HA4SJSD.mjs → chunk-NPEK4RSD.mjs} +5 -2
  13. package/dist/{chunk-2HA4SJSD.mjs.map → chunk-NPEK4RSD.mjs.map} +1 -1
  14. package/dist/{chunk-4ERRCKOH.js → chunk-O4J3ZPZY.js} +5 -2
  15. package/dist/chunk-O4J3ZPZY.js.map +1 -0
  16. package/dist/{chunk-IVRETMQH.mjs → chunk-UHRSTPZ5.mjs} +2 -2
  17. package/dist/{chunk-IVRETMQH.mjs.map → chunk-UHRSTPZ5.mjs.map} +1 -1
  18. package/dist/cli/bundle.js +362 -358
  19. package/dist/{implementation-BNaydX6f.d.ts → implementation-BDK4X-CS.d.ts} +1 -1
  20. package/dist/{implementation-DLMEZQgA.d.mts → implementation-BOP-3GoX.d.mts} +1 -1
  21. package/dist/index.d.mts +75 -5
  22. package/dist/index.d.ts +75 -5
  23. package/dist/index.js +324 -99
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +242 -17
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/observability-sdk/index.d.mts +3 -3
  28. package/dist/observability-sdk/index.d.ts +3 -3
  29. package/dist/observability-sdk/index.js +3 -3
  30. package/dist/observability-sdk/index.mjs +2 -2
  31. package/dist/observability-sdk/instrumentation/langchain/index.d.mts +1 -1
  32. package/dist/observability-sdk/instrumentation/langchain/index.d.ts +1 -1
  33. package/dist/observability-sdk/instrumentation/langchain/index.js +3 -3
  34. package/dist/observability-sdk/instrumentation/langchain/index.mjs +1 -1
  35. package/dist/observability-sdk/setup/node/index.js +3 -3
  36. package/dist/observability-sdk/setup/node/index.mjs +2 -2
  37. package/dist/{types-CLDQMYpV.d.ts → types-C3SDhizh.d.ts} +1138 -111
  38. package/dist/{types-DWNdXOWw.d.mts → types-C9abONOS.d.mts} +1138 -111
  39. package/package.json +1 -1
  40. package/dist/chunk-4ERRCKOH.js.map +0 -1
  41. /package/dist/{chunk-53NOLJEX.mjs.map → chunk-N3755EHD.mjs.map} +0 -0
@@ -44,7 +44,7 @@ import * as os from "os";
44
44
  import { randomUUID } from "crypto";
45
45
 
46
46
  // package.json
47
- var version = "1.12.1";
47
+ var version = "1.13.0";
48
48
 
49
49
  // src/internal/constants.ts
50
50
  var LANGWATCH_SDK_VERSION = version;
@@ -449,6 +449,213 @@ function createParameterReader({
449
449
 
450
450
  // src/agent/transport.ts
451
451
  import { createRequire } from "module";
452
+
453
+ // src/internal/http/langwatchFetch.ts
454
+ var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
455
+ var FOLLOWING_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
456
+ var MAX_FOLLOW_HOPS = 5;
457
+ var CREDENTIAL_HEADERS = [
458
+ "authorization",
459
+ "cookie",
460
+ "proxy-authorization",
461
+ "x-api-key",
462
+ "x-auth-token",
463
+ "x-project-id"
464
+ ];
465
+ var LangWatchRedirectError = class extends Error {
466
+ constructor({
467
+ url,
468
+ location,
469
+ status
470
+ }) {
471
+ super(
472
+ `LangWatch refused to follow a redirect from ${url} to ${location ?? "an unknown location"} (HTTP ${status}). Set the endpoint to the final URL.`
473
+ );
474
+ this.name = "LangWatchRedirectError";
475
+ this.url = url;
476
+ this.location = location;
477
+ this.status = status;
478
+ }
479
+ };
480
+ var warnedOrigins = /* @__PURE__ */ new Set();
481
+ var isRedirect = (response) => response.type === "opaqueredirect" || REDIRECT_STATUSES.has(response.status);
482
+ var isStream = (body) => typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
483
+ var abortError = (signal) => {
484
+ const reason = signal.reason;
485
+ if (reason instanceof Error) return reason;
486
+ if (typeof DOMException !== "undefined") {
487
+ return new DOMException("This operation was aborted", "AbortError");
488
+ }
489
+ return Object.assign(new Error("This operation was aborted"), { name: "AbortError" });
490
+ };
491
+ var discard = (spare) => {
492
+ void spare?.body?.cancel().catch(() => void 0);
493
+ };
494
+ var replayBody = async ({
495
+ spare,
496
+ signal
497
+ }) => {
498
+ if (!signal) return spare.arrayBuffer();
499
+ if (signal.aborted) throw abortError(signal);
500
+ const aborted = new Promise((_, reject) => {
501
+ signal.addEventListener("abort", () => reject(abortError(signal)), { once: true });
502
+ });
503
+ void aborted.catch(() => void 0);
504
+ try {
505
+ return await Promise.race([spare.arrayBuffer(), aborted]);
506
+ } catch (error) {
507
+ discard(spare);
508
+ throw error;
509
+ }
510
+ };
511
+ var requestUrl = (input) => {
512
+ if (typeof input === "string") return input;
513
+ if (input instanceof URL) return input.href;
514
+ return input.url;
515
+ };
516
+ var parseHop = ({
517
+ url,
518
+ location
519
+ }) => {
520
+ try {
521
+ const from = new URL(url);
522
+ return { from, to: new URL(location, from) };
523
+ } catch {
524
+ return null;
525
+ }
526
+ };
527
+ var isSchemeUpgrade = ({ from, to }) => from.protocol === "http:" && to.protocol === "https:" && from.hostname === to.hostname && from.port === to.port;
528
+ var schemeUpgradeTarget = ({
529
+ url,
530
+ location
531
+ }) => {
532
+ const hop = parseHop({ url, location });
533
+ if (hop === null || !isSchemeUpgrade(hop)) return null;
534
+ const { from, to } = hop;
535
+ if (from.pathname !== to.pathname) return null;
536
+ if (from.search !== to.search) return null;
537
+ to.hash = "";
538
+ return to.href;
539
+ };
540
+ var followTarget = ({
541
+ url,
542
+ location
543
+ }) => {
544
+ const hop = parseHop({ url, location });
545
+ if (hop === null) return null;
546
+ const { from, to } = hop;
547
+ if (to.protocol !== "http:" && to.protocol !== "https:") return null;
548
+ if (from.protocol === "https:" && to.protocol === "http:") return null;
549
+ to.hash = "";
550
+ return to.href;
551
+ };
552
+ var keepsCredentials = ({ from, to }) => from.origin === to.origin || isSchemeUpgrade({ from, to });
553
+ var withoutCredentials = (headers) => {
554
+ const stripped = new Headers(headers);
555
+ for (const name of CREDENTIAL_HEADERS) stripped.delete(name);
556
+ return stripped;
557
+ };
558
+ var warnOnce = ({ url, logger }) => {
559
+ const { origin, host } = new URL(url);
560
+ if (warnedOrigins.has(origin)) return;
561
+ warnedOrigins.add(origin);
562
+ logger.warn(
563
+ `LangWatch endpoint ${origin} redirected to https. Set the endpoint to https://${host} to skip the extra round trip.`
564
+ );
565
+ };
566
+ var refusalOf = ({
567
+ url,
568
+ response
569
+ }) => new LangWatchRedirectError({
570
+ url,
571
+ location: response.headers.get("location"),
572
+ status: response.status
573
+ });
574
+ var effectiveRequest = ({
575
+ input,
576
+ init
577
+ }) => typeof Request !== "undefined" && input instanceof Request ? new Request(input, { ...init, redirect: "manual" }) : null;
578
+ var follow = async ({
579
+ send,
580
+ log,
581
+ effective,
582
+ init,
583
+ url,
584
+ method,
585
+ first
586
+ }) => {
587
+ let headers = new Headers(effective?.headers ?? init?.headers);
588
+ const signal = effective?.signal ?? init?.signal;
589
+ let current = url;
590
+ let response = first;
591
+ for (let hop = 0; hop < MAX_FOLLOW_HOPS; hop++) {
592
+ const location = response.headers.get("location");
593
+ const target = location === null ? null : followTarget({ url: current, location });
594
+ if (target === null) throw refusalOf({ url: current, response });
595
+ const from = new URL(current);
596
+ const to = new URL(target);
597
+ if (!keepsCredentials({ from, to })) headers = withoutCredentials(headers);
598
+ if (isSchemeUpgrade({ from, to })) warnOnce({ url: current, logger: log });
599
+ current = target;
600
+ response = effective ? await send(new Request(target, { method, headers, signal, redirect: "manual" })) : await send(target, { ...init, method, headers, body: void 0, redirect: "manual" });
601
+ if (!isRedirect(response)) return response;
602
+ }
603
+ throw refusalOf({ url: current, response });
604
+ };
605
+ var upgrade = async ({
606
+ send,
607
+ log,
608
+ effective,
609
+ init,
610
+ url,
611
+ first,
612
+ spare
613
+ }) => {
614
+ const location = first.headers.get("location");
615
+ const refused = refusalOf({ url, response: first });
616
+ const target = location === null ? null : schemeUpgradeTarget({ url, location });
617
+ if (location === null || first.status === 303 || target === null || isStream(init?.body)) {
618
+ discard(spare);
619
+ throw refused;
620
+ }
621
+ warnOnce({ url, logger: log });
622
+ const second = effective ? await send(
623
+ new Request(target, {
624
+ method: effective.method,
625
+ headers: effective.headers,
626
+ body: spare ? await replayBody({ spare, signal: effective.signal }) : null,
627
+ signal: effective.signal,
628
+ redirect: "manual"
629
+ })
630
+ ) : await send(target, { ...init, redirect: "manual" });
631
+ if (!isRedirect(second)) return second;
632
+ throw refusalOf({ url: target, response: second });
633
+ };
634
+ var createLangWatchFetch = ({
635
+ fetch: fetchImpl,
636
+ logger
637
+ } = {}) => {
638
+ const send = fetchImpl ?? ((input, init) => globalThis.fetch(input, init));
639
+ const log = logger ?? new ConsoleLogger({ level: "warn", prefix: "LangWatch" });
640
+ return async (input, init) => {
641
+ const url = requestUrl(input);
642
+ const effective = effectiveRequest({ input, init });
643
+ const method = (effective?.method ?? init?.method ?? "GET").toUpperCase();
644
+ const spare = effective !== null && effective.body !== null ? effective.clone() : null;
645
+ const first = effective ? await send(effective) : await send(input, { ...init, redirect: "manual" });
646
+ if (!isRedirect(first)) {
647
+ discard(spare);
648
+ return first;
649
+ }
650
+ const hop = { send, log, effective, init, url, first };
651
+ if (!FOLLOWING_METHODS.has(method)) return upgrade({ ...hop, spare });
652
+ discard(spare);
653
+ return follow({ ...hop, method });
654
+ };
655
+ };
656
+ var langwatchFetch = createLangWatchFetch();
657
+
658
+ // src/agent/transport.ts
452
659
  var AGENT_TRANSPORTS = ["websocket", "http"];
453
660
  var INSTANCE_TOKEN_HEADER = "X-Agent-Instance-Token";
454
661
  var isSet3 = (value) => typeof value === "string" && value.trim() !== "";
@@ -533,7 +740,7 @@ var HttpLongPollSocket = class {
533
740
  this.settleRegistered = () => void 0;
534
741
  this.url = options.url;
535
742
  this.headers = options.headers;
536
- const fetchImpl = options.fetch ?? globalThis.fetch;
743
+ const fetchImpl = options.fetch ?? (typeof globalThis.fetch === "function" ? langwatchFetch : void 0);
537
744
  if (typeof fetchImpl !== "function") {
538
745
  throw new Error("the HTTP transport needs a global fetch; run on Node 20 or later");
539
746
  }
@@ -734,10 +941,9 @@ var HttpLongPollSocket = class {
734
941
  }
735
942
  };
736
943
 
737
- // src/agent/client.ts
944
+ // src/agent/reconnect.ts
738
945
  var RECONNECT_BASE_MS = 1e3;
739
946
  var RECONNECT_MAX_MS = 3e4;
740
- var FAILURE_NOTICE_INTERVAL_MS = 5 * 6e4;
741
947
  function reconnectDelayMs({
742
948
  attempt,
743
949
  baseMs = RECONNECT_BASE_MS,
@@ -748,6 +954,22 @@ function reconnectDelayMs({
748
954
  const jittered = exponential * (0.75 + random() * 0.5);
749
955
  return Math.round(Math.min(maxMs, Math.max(baseMs, jittered)));
750
956
  }
957
+ function watchdogDelayMs(heartbeatIntervalMs) {
958
+ return Math.max(15e3, heartbeatIntervalMs * 3);
959
+ }
960
+ var describeError = (error) => error instanceof Error ? error.message : String(error);
961
+ function openTransportSocket({
962
+ transport,
963
+ websocketUrl,
964
+ httpUrl,
965
+ headers,
966
+ socketFactory = defaultSocketFactory
967
+ }) {
968
+ return transport === "http" ? new HttpLongPollSocket({ url: httpUrl, headers }) : socketFactory({ url: websocketUrl, headers });
969
+ }
970
+
971
+ // src/agent/client.ts
972
+ var FAILURE_NOTICE_INTERVAL_MS = 5 * 6e4;
751
973
  var NOT_CONNECTED = "not connected to LangWatch";
752
974
  function refusalAdvice(frame) {
753
975
  switch (frame.code) {
@@ -780,7 +1002,6 @@ function refusalAdvice(frame) {
780
1002
  }
781
1003
  var SHUTDOWN_SIGNALS = ["SIGINT", "SIGTERM"];
782
1004
  var CLOSE_GRACE_MS = 500;
783
- var describeError = (error) => error instanceof Error ? error.message : String(error);
784
1005
  var AgentClient = class {
785
1006
  constructor(config) {
786
1007
  this.agents = [];
@@ -941,7 +1162,13 @@ var AgentClient = class {
941
1162
  if (this.stopped || this.socket) return;
942
1163
  let socket;
943
1164
  try {
944
- socket = this.activeTransport === "http" ? new HttpLongPollSocket({ url: this.httpUrl, headers: this.headers }) : this.openSocket({ url: this.url, headers: this.headers });
1165
+ socket = openTransportSocket({
1166
+ transport: this.activeTransport,
1167
+ websocketUrl: this.url,
1168
+ httpUrl: this.httpUrl,
1169
+ headers: this.headers,
1170
+ socketFactory: this.openSocket
1171
+ });
945
1172
  } catch (error) {
946
1173
  if (error instanceof NoWebSocketError) {
947
1174
  this.giveUp(
@@ -1029,7 +1256,7 @@ var AgentClient = class {
1029
1256
  socket.terminate();
1030
1257
  } catch {
1031
1258
  }
1032
- }, Math.max(15e3, this.heartbeatIntervalMs * 3));
1259
+ }, watchdogDelayMs(this.heartbeatIntervalMs));
1033
1260
  }
1034
1261
  registerFrame() {
1035
1262
  return {
@@ -1292,7 +1519,7 @@ var installShutdownHooks = () => {
1292
1519
  }
1293
1520
  process.on("beforeExit", onBeforeExit);
1294
1521
  };
1295
- function warnOnce({ logger, key, message }) {
1522
+ function warnOnce2({ logger, key, message }) {
1296
1523
  if (noticesGiven.has(key)) {
1297
1524
  logger.debug(message);
1298
1525
  return;
@@ -1304,7 +1531,7 @@ function getSharedClient(config) {
1304
1531
  const key = `${config.endpoint ?? ""}|${config.projectId ?? ""}|${config.apiKey}`;
1305
1532
  if (shared) {
1306
1533
  if (sharedKey !== key) {
1307
- warnOnce({
1534
+ warnOnce2({
1308
1535
  logger: config.logger,
1309
1536
  key: "credentials-differ",
1310
1537
  message: "connectAgent: this process already has an agent connection with other credentials or endpoint; the first ones are used"
@@ -1321,6 +1548,7 @@ function getSharedClient(config) {
1321
1548
  // src/agent/define.ts
1322
1549
  var DEFAULT_TIMEOUT_MS = 12e4;
1323
1550
  var MAX_TIMEOUT_MS = 3e5;
1551
+ var DEFAULT_CONCURRENCY = 10;
1324
1552
  var isMessage = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.role === "string";
1325
1553
  function normalizeReply(reply) {
1326
1554
  if (typeof reply === "string") return { output: reply };
@@ -1360,10 +1588,7 @@ function connectAgent(options, handler) {
1360
1588
  const parameters = toParameterSchema(options.parameters);
1361
1589
  const specs = parameterSpecsFromSchema(parameters);
1362
1590
  const timeoutMs = clampTimeout({ timeoutMs: options.timeoutMs, logger, name });
1363
- const concurrency = Math.max(
1364
- 1,
1365
- Math.floor(options.concurrency ?? (environment === DEFAULT_ENVIRONMENT ? 1 : 4))
1366
- );
1591
+ const concurrency = Math.max(1, Math.floor(options.concurrency ?? DEFAULT_CONCURRENCY));
1367
1592
  const runHandler = async (call) => normalizeReply(await handler(call));
1368
1593
  const readParams2 = createParameterReader({ input: options.parameters, specs });
1369
1594
  const invoke = async (call) => {
@@ -1399,7 +1624,7 @@ function connectAgent(options, handler) {
1399
1624
  } else {
1400
1625
  const apiKey = readApiKey(options.apiKey);
1401
1626
  if (!apiKey) {
1402
- warnOnce({
1627
+ warnOnce2({
1403
1628
  logger,
1404
1629
  key: "no-api-key",
1405
1630
  message: `agent "${name}" not connected to LangWatch: no API key. Set LANGWATCH_API_KEY to run simulations against it.`