@farzanhossans/agentlens 0.2.0 → 0.2.1

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.mjs CHANGED
@@ -1,13 +1,10 @@
1
1
  import { randomUUID } from 'crypto';
2
2
  import { getCurrentTraceId, runWithTrace, getCurrentSpanId } from '@farzanhossans/agentlens-core';
3
3
  export { getCurrentSpanId, getCurrentTrace, getCurrentTraceId, runWithTrace } from '@farzanhossans/agentlens-core';
4
+ import http from 'http';
5
+ import https from 'https';
4
6
 
5
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
- }) : x)(function(x) {
8
- if (typeof require !== "undefined") return require.apply(this, arguments);
9
- throw Error('Dynamic require of "' + x + '" is not supported');
10
- });
7
+ // src/index.ts
11
8
 
12
9
  // src/registry.ts
13
10
  var LLM_REGISTRY = {
@@ -344,25 +341,40 @@ function patchFetch(transport2) {
344
341
  patched.__agentlens_patched = true;
345
342
  globalThis.fetch = patched;
346
343
  }
347
-
348
- // src/interceptors/https.ts
344
+ var responseChunkRegistry = /* @__PURE__ */ new WeakMap();
345
+ var incomingMessagePatched = false;
349
346
  function patchHttps(transport2) {
350
- if (typeof process === "undefined" || typeof __require === "undefined") {
351
- return;
352
- }
353
- try {
354
- patchModule("https", transport2);
355
- patchModule("http", transport2);
356
- } catch {
357
- }
347
+ patchIncomingMessage();
348
+ patchModule(http, "http", transport2);
349
+ patchModule(https, "https", transport2);
358
350
  }
359
- function patchModule(name, transport2) {
360
- let mod;
361
- try {
362
- mod = __require(name);
363
- } catch {
364
- return;
365
- }
351
+ function patchIncomingMessage() {
352
+ if (incomingMessagePatched) return;
353
+ const IncomingMessage = http.IncomingMessage;
354
+ if (!IncomingMessage?.prototype) return;
355
+ const proto = IncomingMessage.prototype;
356
+ const originalPush = proto.push;
357
+ proto.push = function patchedPush(chunk, encoding) {
358
+ if (chunk !== null) {
359
+ const chunks = responseChunkRegistry.get(this);
360
+ if (chunks) {
361
+ try {
362
+ if (Buffer.isBuffer(chunk)) {
363
+ chunks.push(chunk);
364
+ } else if (typeof chunk === "string") {
365
+ chunks.push(Buffer.from(chunk, encoding ?? "utf8"));
366
+ } else if (chunk && typeof chunk === "object") {
367
+ chunks.push(Buffer.from(chunk));
368
+ }
369
+ } catch {
370
+ }
371
+ }
372
+ }
373
+ return originalPush.call(this, chunk, encoding);
374
+ };
375
+ incomingMessagePatched = true;
376
+ }
377
+ function patchModule(mod, name, transport2) {
366
378
  if (mod.__agentlens_patched) return;
367
379
  const original = mod.request.bind(mod);
368
380
  mod.request = function patchedRequest(...args) {
@@ -370,7 +382,6 @@ function patchModule(name, transport2) {
370
382
  if (!ctx) return original(...args);
371
383
  const start = Date.now();
372
384
  const requestChunks = [];
373
- const responseChunks = [];
374
385
  const req = original(...args);
375
386
  const originalWrite = req.write.bind(req);
376
387
  req.write = function(chunk, ...rest) {
@@ -382,16 +393,12 @@ function patchModule(name, transport2) {
382
393
  };
383
394
  req.on("response", (...resArgs) => {
384
395
  const res = resArgs[0];
385
- res.on("data", (chunk) => {
386
- try {
387
- responseChunks.push(toBuffer(chunk));
388
- } catch {
389
- }
390
- });
396
+ const chunks = [];
397
+ responseChunkRegistry.set(res, chunks);
391
398
  res.on("end", () => {
392
399
  const latency = Date.now() - start;
393
400
  const requestText = Buffer.concat(requestChunks).toString("utf8");
394
- const responseText = Buffer.concat(responseChunks).toString("utf8");
401
+ const responseText = Buffer.concat(chunks).toString("utf8");
395
402
  const requestBody = safeParse(requestText);
396
403
  const responseBody = safeParse(responseText);
397
404
  if (responseBody) {
@@ -405,6 +412,7 @@ function patchModule(name, transport2) {
405
412
  isStream: requestBody?.stream === true
406
413
  });
407
414
  }
415
+ responseChunkRegistry.delete(res);
408
416
  });
409
417
  });
410
418
  req.on("error", (...errArgs) => {
@@ -838,6 +846,7 @@ var Transport = class {
838
846
  constructor(config) {
839
847
  this.config = {
840
848
  apiKey: config.apiKey,
849
+ projectId: config.projectId,
841
850
  endpoint: config.endpoint,
842
851
  flushIntervalMs: config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS,
843
852
  maxBatchSize: config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE,
@@ -848,6 +857,8 @@ var Transport = class {
848
857
  this.registerExitHandler();
849
858
  }
850
859
  push(payload) {
860
+ const startedAt = new Date(Date.now() - payload.latency).toISOString();
861
+ const endedAt = (/* @__PURE__ */ new Date()).toISOString();
851
862
  let parsed;
852
863
  try {
853
864
  parsed = parseSpan({
@@ -862,28 +873,34 @@ var Transport = class {
862
873
  }
863
874
  return;
864
875
  }
865
- const outbound = this.toOutbound(parsed, payload.latency, payload.status);
876
+ const outbound = this.toOutbound(parsed, payload, startedAt, endedAt);
866
877
  this.enqueue(outbound);
867
878
  }
868
879
  pushError(payload) {
869
880
  const ids = this.resolveIds();
881
+ const startedAt = new Date(Date.now() - payload.latency).toISOString();
882
+ const endedAt = (/* @__PURE__ */ new Date()).toISOString();
870
883
  const span = {
871
884
  spanId: ids.spanId,
872
885
  traceId: ids.traceId,
873
886
  parentSpanId: ids.parentSpanId,
887
+ projectId: this.config.projectId,
888
+ name: `${payload.provider}.error`,
874
889
  model: "unknown",
875
890
  provider: payload.provider,
891
+ input: this.scrub(this.stringifyRequest(payload.request)),
892
+ output: "",
876
893
  inputTokens: 0,
877
894
  outputTokens: 0,
878
895
  totalTokens: 0,
879
896
  costUsd: 0,
880
- inputText: this.scrub(this.stringifyRequest(payload.request)),
881
- outputText: "",
882
- isStream: false,
883
- error: payload.error,
884
- latency: payload.latency,
885
- status: 0,
886
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
897
+ latencyMs: payload.latency,
898
+ status: "error",
899
+ errorMessage: payload.error,
900
+ metadata: { httpStatus: 0 },
901
+ startedAt,
902
+ endedAt,
903
+ isStream: false
887
904
  };
888
905
  this.enqueue(span);
889
906
  }
@@ -905,18 +922,30 @@ var Transport = class {
905
922
  this.timer = null;
906
923
  }
907
924
  }
908
- toOutbound(parsed, latency, status) {
925
+ toOutbound(parsed, payload, startedAt, endedAt) {
909
926
  const ids = this.resolveIds();
927
+ const status = payload.status >= 200 && payload.status < 400 ? "success" : "error";
910
928
  return {
911
- ...parsed,
912
929
  spanId: ids.spanId,
913
930
  traceId: ids.traceId,
914
931
  parentSpanId: ids.parentSpanId,
915
- inputText: this.scrub(parsed.inputText),
916
- outputText: this.scrub(parsed.outputText),
917
- latency,
932
+ projectId: this.config.projectId,
933
+ name: spanNameFor(payload),
934
+ model: parsed.model,
935
+ provider: parsed.provider,
936
+ input: this.scrub(parsed.inputText),
937
+ output: this.scrub(parsed.outputText),
938
+ inputTokens: parsed.inputTokens,
939
+ outputTokens: parsed.outputTokens,
940
+ totalTokens: parsed.totalTokens,
941
+ costUsd: parsed.costUsd,
942
+ latencyMs: payload.latency,
918
943
  status,
919
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
944
+ errorMessage: parsed.error,
945
+ metadata: { httpStatus: payload.status },
946
+ startedAt,
947
+ endedAt,
948
+ isStream: parsed.isStream
920
949
  };
921
950
  }
922
951
  /**
@@ -955,12 +984,13 @@ var Transport = class {
955
984
  enqueue(span) {
956
985
  if (this.config.debug) {
957
986
  console.log("[agentlens] span", {
987
+ name: span.name,
958
988
  model: span.model,
959
989
  provider: span.provider,
960
990
  inputTokens: span.inputTokens,
961
991
  outputTokens: span.outputTokens,
962
992
  costUsd: span.costUsd,
963
- latency: span.latency,
993
+ latencyMs: span.latencyMs,
964
994
  isStream: span.isStream
965
995
  });
966
996
  }
@@ -1021,6 +1051,9 @@ var Transport = class {
1021
1051
  method: "POST",
1022
1052
  headers: {
1023
1053
  "content-type": "application/json",
1054
+ // Hosted ingest expects X-API-Key. Send Authorization too for any
1055
+ // gateways that may sit in front (some Cloudflare workers want it).
1056
+ "x-api-key": this.config.apiKey,
1024
1057
  authorization: `Bearer ${this.config.apiKey}`
1025
1058
  },
1026
1059
  body
@@ -1028,6 +1061,17 @@ var Transport = class {
1028
1061
  return { ok: res.ok, status: res.status };
1029
1062
  }
1030
1063
  };
1064
+ function spanNameFor(payload) {
1065
+ const req = payload.request;
1066
+ if (req && Array.isArray(req.messages)) return `${payload.provider}.chat`;
1067
+ if (req && (typeof req.prompt === "string" || typeof req.input === "string")) {
1068
+ return `${payload.provider}.completion`;
1069
+ }
1070
+ if (req && (req.input !== void 0 || req.contents !== void 0)) {
1071
+ return `${payload.provider}.embedding`;
1072
+ }
1073
+ return `${payload.provider}.call`;
1074
+ }
1031
1075
  function sleep(ms) {
1032
1076
  return new Promise((resolve) => setTimeout(resolve, ms));
1033
1077
  }
@@ -1040,9 +1084,13 @@ var AgentLens = {
1040
1084
  if (!config?.apiKey) {
1041
1085
  throw new Error("AgentLens.init requires an apiKey");
1042
1086
  }
1087
+ if (!config?.projectId) {
1088
+ throw new Error("AgentLens.init requires a projectId");
1089
+ }
1043
1090
  initialized = true;
1044
1091
  transport = new Transport({
1045
1092
  apiKey: config.apiKey,
1093
+ projectId: config.projectId,
1046
1094
  endpoint: config.endpoint ?? DEFAULT_ENDPOINT,
1047
1095
  debug: config.debug ?? false,
1048
1096
  pii: config.pii ?? true,