langwatch 1.12.0 → 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.
- package/dist/agent/index.d.mts +5 -1
- package/dist/agent/index.d.ts +5 -1
- package/dist/agent/index.js +239 -14
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +239 -14
- package/dist/agent/index.mjs.map +1 -1
- package/dist/{chunk-3WIN2UXZ.js → chunk-7R54TMZZ.js} +2 -2
- package/dist/{chunk-3WIN2UXZ.js.map → chunk-7R54TMZZ.js.map} +1 -1
- package/dist/{chunk-QLYKPPAW.js → chunk-G64XZMIU.js} +12 -12
- package/dist/{chunk-QLYKPPAW.js.map → chunk-G64XZMIU.js.map} +1 -1
- package/dist/{chunk-BAE4KYKJ.mjs → chunk-N3755EHD.mjs} +2 -2
- package/dist/{chunk-2HA4SJSD.mjs → chunk-NPEK4RSD.mjs} +5 -2
- package/dist/{chunk-2HA4SJSD.mjs.map → chunk-NPEK4RSD.mjs.map} +1 -1
- package/dist/{chunk-4ERRCKOH.js → chunk-O4J3ZPZY.js} +5 -2
- package/dist/chunk-O4J3ZPZY.js.map +1 -0
- package/dist/{chunk-F5UYCQT3.mjs → chunk-UHRSTPZ5.mjs} +2 -2
- package/dist/{chunk-F5UYCQT3.mjs.map → chunk-UHRSTPZ5.mjs.map} +1 -1
- package/dist/cli/bundle.js +362 -357
- package/dist/{implementation-rpImK8WS.d.ts → implementation-BDK4X-CS.d.ts} +1 -1
- package/dist/{implementation-BA3xa5UR.d.mts → implementation-BOP-3GoX.d.mts} +1 -1
- package/dist/index.d.mts +75 -5
- package/dist/index.d.ts +75 -5
- package/dist/index.js +328 -103
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +246 -21
- package/dist/index.mjs.map +1 -1
- package/dist/observability-sdk/index.d.mts +3 -3
- package/dist/observability-sdk/index.d.ts +3 -3
- package/dist/observability-sdk/index.js +3 -3
- package/dist/observability-sdk/index.mjs +2 -2
- package/dist/observability-sdk/instrumentation/langchain/index.d.mts +1 -1
- package/dist/observability-sdk/instrumentation/langchain/index.d.ts +1 -1
- package/dist/observability-sdk/instrumentation/langchain/index.js +3 -3
- package/dist/observability-sdk/instrumentation/langchain/index.mjs +1 -1
- package/dist/observability-sdk/setup/node/index.js +3 -3
- package/dist/observability-sdk/setup/node/index.mjs +2 -2
- package/dist/{types-Cr25FO-i.d.ts → types-C3SDhizh.d.ts} +1151 -117
- package/dist/{types-DJyJypkv.d.mts → types-C9abONOS.d.mts} +1151 -117
- package/package.json +1 -1
- package/dist/chunk-4ERRCKOH.js.map +0 -1
- /package/dist/{chunk-BAE4KYKJ.mjs.map → chunk-N3755EHD.mjs.map} +0 -0
package/dist/agent/index.mjs
CHANGED
|
@@ -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.
|
|
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/
|
|
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 =
|
|
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
|
-
},
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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.`
|