@agentvault/agentvault 0.13.1 → 0.13.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"openclaw-entry.d.ts","sourceRoot":"","sources":["../src/openclaw-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAwBH,uEAAuE;AACvE,iBAAS,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAS9C;AAED,qFAAqF;AACrF,iBAAS,yBAAyB,CAChC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAcT;AAED,sFAAsF;AACtF,iBAAS,cAAc,CACrB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,MAAM,CAiBR;AA+eD,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,cAAc,EAAE,CAAC;;;;;kBAQrD,GAAG;;AAJnB,wBAQE"}
1
+ {"version":3,"file":"openclaw-entry.d.ts","sourceRoot":"","sources":["../src/openclaw-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH,uEAAuE;AACvE,iBAAS,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAS9C;AAED,qFAAqF;AACrF,iBAAS,yBAAyB,CAChC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAcT;AAED,sFAAsF;AACtF,iBAAS,cAAc,CACrB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,MAAM,CAiBR;AA+mBD,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,cAAc,EAAE,CAAC;;;;;kBAQrD,GAAG;;AAJnB,wBAoDE"}
@@ -53,6 +53,150 @@ function resolveAccount(cfg, accountId) {
53
53
  };
54
54
  }
55
55
 
56
+ // src/fetch-interceptor.ts
57
+ import { AsyncLocalStorage } from "node:async_hooks";
58
+ import diagnosticsChannel from "node:diagnostics_channel";
59
+ var traceStore = new AsyncLocalStorage();
60
+ var DEFAULT_SKIP_PATTERNS = [
61
+ /^https?:\/\/localhost(:\d+)?/,
62
+ /^https?:\/\/127\.0\.0\.1(:\d+)?/,
63
+ /\.agentvault\.chat/,
64
+ /\.agentvault\.dev/,
65
+ /\.clerk\./
66
+ ];
67
+ var installed = false;
68
+ var originalFetch;
69
+ var inflightRequests = /* @__PURE__ */ new WeakMap();
70
+ var unsubCreate;
71
+ var unsubHeaders;
72
+ var unsubError;
73
+ function shouldSkip(url, extraPatterns) {
74
+ const allPatterns = [...DEFAULT_SKIP_PATTERNS, ...extraPatterns];
75
+ return allPatterns.some((p) => p.test(url));
76
+ }
77
+ function extractUrl(origin, path) {
78
+ return `${origin}${path}`;
79
+ }
80
+ function installFetchInterceptor(opts) {
81
+ if (installed) return;
82
+ installed = true;
83
+ const skipPatterns = [
84
+ ...DEFAULT_SKIP_PATTERNS,
85
+ ...opts.skipPatterns ?? []
86
+ ];
87
+ try {
88
+ const createChannel = diagnosticsChannel.channel("undici:request:create");
89
+ const headersChannel = diagnosticsChannel.channel("undici:request:headers");
90
+ const errorChannel = diagnosticsChannel.channel("undici:request:error");
91
+ const onRequestCreate = (message) => {
92
+ try {
93
+ const msg = message;
94
+ const req = msg.request;
95
+ if (!req) return;
96
+ const origin = String(req.origin ?? "");
97
+ const path = String(req.path ?? "/");
98
+ const url = extractUrl(origin, path);
99
+ if (shouldSkip(url, skipPatterns)) return;
100
+ inflightRequests.set(req, {
101
+ url,
102
+ method: String(req.method ?? "GET").toUpperCase(),
103
+ startTime: Date.now()
104
+ });
105
+ } catch {
106
+ }
107
+ };
108
+ const onRequestHeaders = (message) => {
109
+ try {
110
+ const msg = message;
111
+ const tracked = inflightRequests.get(msg.request);
112
+ if (!tracked) return;
113
+ inflightRequests.delete(msg.request);
114
+ const latencyMs = Date.now() - tracked.startTime;
115
+ const ctx = traceStore.getStore();
116
+ opts.onHttpCall({
117
+ method: tracked.method,
118
+ url: tracked.url,
119
+ statusCode: msg.response?.statusCode ?? 0,
120
+ latencyMs,
121
+ traceId: ctx?.traceId,
122
+ parentSpanId: ctx?.parentSpanId
123
+ });
124
+ } catch {
125
+ }
126
+ };
127
+ const onRequestError = (message) => {
128
+ try {
129
+ const msg = message;
130
+ const tracked = inflightRequests.get(msg.request);
131
+ if (!tracked) return;
132
+ inflightRequests.delete(msg.request);
133
+ const latencyMs = Date.now() - tracked.startTime;
134
+ const ctx = traceStore.getStore();
135
+ opts.onHttpCall({
136
+ method: tracked.method,
137
+ url: tracked.url,
138
+ statusCode: 0,
139
+ latencyMs,
140
+ traceId: ctx?.traceId,
141
+ parentSpanId: ctx?.parentSpanId
142
+ });
143
+ } catch {
144
+ }
145
+ };
146
+ createChannel.subscribe(onRequestCreate);
147
+ headersChannel.subscribe(onRequestHeaders);
148
+ errorChannel.subscribe(onRequestError);
149
+ unsubCreate = () => createChannel.unsubscribe(onRequestCreate);
150
+ unsubHeaders = () => headersChannel.unsubscribe(onRequestHeaders);
151
+ unsubError = () => errorChannel.unsubscribe(onRequestError);
152
+ } catch {
153
+ }
154
+ originalFetch = globalThis.fetch;
155
+ const savedOriginal = originalFetch;
156
+ globalThis.fetch = async (input, init) => {
157
+ const url = input instanceof Request ? input.url : input instanceof URL ? input.href : String(input);
158
+ if (shouldSkip(url, skipPatterns)) {
159
+ return savedOriginal(input, init);
160
+ }
161
+ const method = input instanceof Request ? input.method : init?.method ?? "GET";
162
+ const ctx = traceStore.getStore();
163
+ const start = Date.now();
164
+ try {
165
+ const response = await savedOriginal(input, init);
166
+ const latencyMs = Date.now() - start;
167
+ try {
168
+ opts.onHttpCall({
169
+ method,
170
+ url,
171
+ statusCode: response.status,
172
+ latencyMs,
173
+ traceId: ctx?.traceId,
174
+ parentSpanId: ctx?.parentSpanId
175
+ });
176
+ } catch {
177
+ }
178
+ return response;
179
+ } catch (err) {
180
+ const latencyMs = Date.now() - start;
181
+ try {
182
+ opts.onHttpCall({
183
+ method,
184
+ url,
185
+ statusCode: 0,
186
+ latencyMs,
187
+ traceId: ctx?.traceId,
188
+ parentSpanId: ctx?.parentSpanId
189
+ });
190
+ } catch {
191
+ }
192
+ throw err;
193
+ }
194
+ };
195
+ }
196
+ function runWithTraceContext(ctx, fn) {
197
+ return traceStore.run(ctx, fn);
198
+ }
199
+
56
200
  // src/openclaw-entry.ts
57
201
  var _ocRuntime = null;
58
202
  var _channels = /* @__PURE__ */ new Map();
@@ -113,24 +257,124 @@ async function handleInbound(params) {
113
257
  const traceId = randomBytes(16).toString("hex");
114
258
  const rootSpanId = randomBytes(8).toString("hex");
115
259
  const inferenceSpanId = randomBytes(8).toString("hex");
260
+ const _sendActivity = (spanData) => {
261
+ try {
262
+ channel.sendActivitySpan({ ...spanData, trace_id: traceId, parent_span_id: inferenceSpanId });
263
+ } catch {
264
+ }
265
+ };
116
266
  const _instrument = {
117
267
  reportLlm: (opts) => {
118
268
  try {
119
269
  channel.telemetry?.reportLlmCall({ ...opts, traceId, parentSpanId: inferenceSpanId });
120
270
  } catch {
121
271
  }
272
+ _sendActivity({
273
+ span_id: randomBytes(8).toString("hex"),
274
+ span_type: "llm",
275
+ span_name: opts.model ?? "LLM",
276
+ status: opts.status === "error" ? "error" : "ok",
277
+ start_time: new Date(Date.now() - (opts.latencyMs ?? 0)).toISOString(),
278
+ end_time: (/* @__PURE__ */ new Date()).toISOString(),
279
+ duration_ms: opts.latencyMs ?? 0,
280
+ attributes: { "ai.agent.llm.model": opts.model ?? "" },
281
+ tokens_input: opts.tokensInput,
282
+ tokens_output: opts.tokensOutput
283
+ });
122
284
  },
123
285
  reportTool: (opts) => {
124
286
  try {
125
287
  channel.telemetry?.reportToolCall({ ...opts, traceId, parentSpanId: inferenceSpanId });
126
288
  } catch {
127
289
  }
290
+ _sendActivity({
291
+ span_id: randomBytes(8).toString("hex"),
292
+ span_type: "tool",
293
+ span_name: opts.toolName ?? "tool",
294
+ status: opts.success === false ? "error" : "ok",
295
+ start_time: new Date(Date.now() - (opts.latencyMs ?? 0)).toISOString(),
296
+ end_time: (/* @__PURE__ */ new Date()).toISOString(),
297
+ duration_ms: opts.latencyMs ?? 0,
298
+ attributes: { "ai.agent.tool.name": opts.toolName ?? "" },
299
+ tool_success: opts.success
300
+ });
128
301
  },
129
302
  reportError: (opts) => {
130
303
  try {
131
304
  channel.telemetry?.reportError({ ...opts, traceId, parentSpanId: inferenceSpanId });
132
305
  } catch {
133
306
  }
307
+ _sendActivity({
308
+ span_id: randomBytes(8).toString("hex"),
309
+ span_type: "error",
310
+ span_name: opts.errorType ?? "error",
311
+ status: "error",
312
+ start_time: (/* @__PURE__ */ new Date()).toISOString(),
313
+ end_time: (/* @__PURE__ */ new Date()).toISOString(),
314
+ duration_ms: 0,
315
+ attributes: { "ai.agent.error.type": opts.errorType ?? "" },
316
+ error_type: opts.errorType,
317
+ error_message: opts.errorMessage
318
+ });
319
+ },
320
+ reportHttp: (opts) => {
321
+ try {
322
+ channel.telemetry?.reportHttpCall({ ...opts, traceId, parentSpanId: inferenceSpanId });
323
+ } catch {
324
+ }
325
+ _sendActivity({
326
+ span_id: randomBytes(8).toString("hex"),
327
+ span_type: "http",
328
+ span_name: (() => {
329
+ try {
330
+ return new URL(opts.url).hostname;
331
+ } catch {
332
+ return opts.url?.slice(0, 40) ?? "http";
333
+ }
334
+ })(),
335
+ status: (opts.statusCode ?? 200) >= 400 ? "error" : "ok",
336
+ start_time: new Date(Date.now() - (opts.latencyMs ?? 0)).toISOString(),
337
+ end_time: (/* @__PURE__ */ new Date()).toISOString(),
338
+ duration_ms: opts.latencyMs ?? 0,
339
+ attributes: { "ai.agent.http.method": opts.method ?? "", "ai.agent.http.url": opts.url ?? "" },
340
+ http_method: opts.method,
341
+ http_status_code: opts.statusCode,
342
+ http_url: opts.url
343
+ });
344
+ },
345
+ reportAction: (opts) => {
346
+ try {
347
+ channel.telemetry?.reportActionCall({ ...opts, traceId, parentSpanId: inferenceSpanId });
348
+ } catch {
349
+ }
350
+ _sendActivity({
351
+ span_id: randomBytes(8).toString("hex"),
352
+ span_type: "action",
353
+ span_name: `${opts.actionType ?? "action"}: ${opts.target ?? ""}`,
354
+ status: opts.success === false ? "error" : "ok",
355
+ start_time: new Date(Date.now() - (opts.latencyMs ?? 0)).toISOString(),
356
+ end_time: (/* @__PURE__ */ new Date()).toISOString(),
357
+ duration_ms: opts.latencyMs ?? 0,
358
+ attributes: { "ai.agent.action.type": opts.actionType ?? "", "ai.agent.action.target": opts.target ?? "" },
359
+ action_type: opts.actionType,
360
+ action_target: opts.target
361
+ });
362
+ },
363
+ reportNav: (opts) => {
364
+ try {
365
+ channel.telemetry?.reportNavCall({ ...opts, traceId, parentSpanId: inferenceSpanId });
366
+ } catch {
367
+ }
368
+ _sendActivity({
369
+ span_id: randomBytes(8).toString("hex"),
370
+ span_type: "nav",
371
+ span_name: opts.toUrl?.slice(0, 40) ?? "navigate",
372
+ status: opts.status === "error" ? "error" : "ok",
373
+ start_time: new Date(Date.now() - (opts.latencyMs ?? 0)).toISOString(),
374
+ end_time: (/* @__PURE__ */ new Date()).toISOString(),
375
+ duration_ms: opts.latencyMs ?? 0,
376
+ attributes: { "ai.agent.nav.to_url": opts.toUrl ?? "" }
377
+ });
134
378
  },
135
379
  traceId,
136
380
  parentSpanId: inferenceSpanId
@@ -223,38 +467,41 @@ async function handleInbound(params) {
223
467
  }
224
468
  });
225
469
  try {
226
- await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
227
- ctx: ctxPayload,
228
- cfg,
229
- dispatcherOptions: {
230
- deliver: async (payload) => {
231
- if (payload.kind === "thinking" || payload.kind === "reasoning") return;
232
- const text = (payload.text ?? "").trim();
233
- if (!text) return;
234
- if (/^(Reasoning|Thinking|Let me think|I need to|Let me check):/i.test(text)) return;
235
- const replyStart = Date.now();
236
- replyCount++;
237
- totalReplyChars += text.length;
238
- if (!firstReplyTime) firstReplyTime = replyStart;
239
- if (isRoomMessage) {
240
- await channel.sendToRoom(metadata.roomId, text, {
241
- metadata: { content_length: text.length }
242
- });
243
- } else {
244
- await channel.send(text, {
245
- conversationId: metadata.conversationId,
246
- topicId: metadata.topicId
247
- });
470
+ await runWithTraceContext(
471
+ { traceId, parentSpanId: inferenceSpanId },
472
+ () => core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
473
+ ctx: ctxPayload,
474
+ cfg,
475
+ dispatcherOptions: {
476
+ deliver: async (payload) => {
477
+ if (payload.kind === "thinking" || payload.kind === "reasoning") return;
478
+ const text = (payload.text ?? "").trim();
479
+ if (!text) return;
480
+ if (/^(Reasoning|Thinking|Let me think|I need to|Let me check):/i.test(text)) return;
481
+ const replyStart = Date.now();
482
+ replyCount++;
483
+ totalReplyChars += text.length;
484
+ if (!firstReplyTime) firstReplyTime = replyStart;
485
+ if (isRoomMessage) {
486
+ await channel.sendToRoom(metadata.roomId, text, {
487
+ metadata: { content_length: text.length }
488
+ });
489
+ } else {
490
+ await channel.send(text, {
491
+ conversationId: metadata.conversationId,
492
+ topicId: metadata.topicId
493
+ });
494
+ }
495
+ const replyEnd = Date.now();
496
+ replySpans.push({ startTime: replyStart, endTime: replyEnd, chars: text.length, index: replyCount });
497
+ },
498
+ onError: (err, info) => {
499
+ core.error?.(`[AgentVault] ${info?.kind ?? "reply"} error: ${String(err)}`);
248
500
  }
249
- const replyEnd = Date.now();
250
- replySpans.push({ startTime: replyStart, endTime: replyEnd, chars: text.length, index: replyCount });
251
501
  },
252
- onError: (err, info) => {
253
- core.error?.(`[AgentVault] ${info?.kind ?? "reply"} error: ${String(err)}`);
254
- }
255
- },
256
- replyOptions: {}
257
- });
502
+ replyOptions: {}
503
+ })
504
+ );
258
505
  const endTime = Date.now();
259
506
  _emitHierarchicalSpans(channel, {
260
507
  traceId,
@@ -303,13 +550,38 @@ async function handleInbound(params) {
303
550
  throw err;
304
551
  }
305
552
  }
553
+ function _inferSpanType(name) {
554
+ if (name === "error" || name.includes("error")) return "error";
555
+ if (name.startsWith("llm.") || name.includes("inference")) return "llm";
556
+ if (name.startsWith("tool.") || name.includes("tool")) return "tool";
557
+ if (name.startsWith("http.") || name.includes("http")) return "http";
558
+ if (name.startsWith("nav.") || name.includes("nav")) return "nav";
559
+ if (name.startsWith("action.") || name.includes("action")) return "action";
560
+ return "action";
561
+ }
562
+ function _extractSpanName(name, attrs) {
563
+ if (attrs["ai.agent.llm.model"]) return String(attrs["ai.agent.llm.model"]);
564
+ if (attrs["ai.agent.tool.name"]) return String(attrs["ai.agent.tool.name"]);
565
+ if (attrs["ai.agent.http.url"]) {
566
+ try {
567
+ return new URL(String(attrs["ai.agent.http.url"])).hostname;
568
+ } catch {
569
+ }
570
+ return String(attrs["ai.agent.http.url"]).slice(0, 40);
571
+ }
572
+ if (attrs["ai.agent.action.type"]) return `${attrs["ai.agent.action.type"]}: ${attrs["ai.agent.action.target"] ?? ""}`;
573
+ if (attrs["ai.agent.nav.to_url"]) return String(attrs["ai.agent.nav.to_url"]).slice(0, 40);
574
+ if (attrs["ai.agent.error.type"]) return String(attrs["ai.agent.error.type"]);
575
+ return name;
576
+ }
306
577
  function _emitChildSpan(channel, opts) {
307
578
  try {
308
579
  const reporter = channel.telemetry;
309
580
  if (!reporter) return;
581
+ const spanId = opts.spanId ?? randomBytes(8).toString("hex");
310
582
  reporter.reportCustomSpan({
311
583
  traceId: opts.traceId,
312
- spanId: opts.spanId ?? randomBytes(8).toString("hex"),
584
+ spanId,
313
585
  parentSpanId: opts.parentSpanId,
314
586
  name: opts.name,
315
587
  kind: "internal",
@@ -321,6 +593,40 @@ function _emitChildSpan(channel, opts) {
321
593
  message: opts.statusMessage
322
594
  }
323
595
  });
596
+ try {
597
+ const spanType = _inferSpanType(opts.name);
598
+ const spanName = _extractSpanName(opts.name, opts.attributes);
599
+ const durationMs = opts.endTime - opts.startTime;
600
+ channel.sendActivitySpan({
601
+ trace_id: opts.traceId,
602
+ span_id: spanId,
603
+ parent_span_id: opts.parentSpanId,
604
+ span_type: spanType,
605
+ span_name: spanName,
606
+ status: opts.status,
607
+ start_time: new Date(opts.startTime).toISOString(),
608
+ end_time: new Date(opts.endTime).toISOString(),
609
+ duration_ms: durationMs,
610
+ attributes: opts.attributes,
611
+ ...spanType === "llm" ? {
612
+ tokens_input: opts.attributes["ai.agent.llm.tokens_input"],
613
+ tokens_output: opts.attributes["ai.agent.llm.tokens_output"]
614
+ } : {},
615
+ ...spanType === "http" ? {
616
+ http_method: opts.attributes["ai.agent.http.method"],
617
+ http_status_code: opts.attributes["ai.agent.http.status_code"],
618
+ http_url: opts.attributes["ai.agent.http.url"]
619
+ } : {},
620
+ ...spanType === "tool" ? {
621
+ tool_success: opts.attributes["ai.agent.tool.success"]
622
+ } : {},
623
+ ...spanType === "error" ? {
624
+ error_type: opts.attributes["ai.agent.error.type"],
625
+ error_message: opts.attributes["ai.agent.error.message"]
626
+ } : {}
627
+ });
628
+ } catch {
629
+ }
324
630
  } catch {
325
631
  }
326
632
  }
@@ -502,6 +808,51 @@ var openclaw_entry_default = {
502
808
  description: "End-to-end encrypted, zero-knowledge messaging between AI agent owners and their agents.",
503
809
  register(api) {
504
810
  _setRuntime(api.runtime);
811
+ installFetchInterceptor({
812
+ onHttpCall: (report) => {
813
+ const ch = _channels.values().next().value;
814
+ if (!ch?.telemetry) return;
815
+ try {
816
+ ch.telemetry.reportHttpCall({
817
+ method: report.method,
818
+ url: report.url,
819
+ statusCode: report.statusCode,
820
+ latencyMs: report.latencyMs,
821
+ ...report.traceId ? { traceId: report.traceId } : {},
822
+ ...report.parentSpanId ? { parentSpanId: report.parentSpanId } : {}
823
+ });
824
+ } catch {
825
+ }
826
+ try {
827
+ const hostname = (() => {
828
+ try {
829
+ return new URL(report.url).hostname;
830
+ } catch {
831
+ return report.url.slice(0, 40);
832
+ }
833
+ })();
834
+ ch.sendActivitySpan({
835
+ trace_id: report.traceId ?? "",
836
+ parent_span_id: report.parentSpanId ?? "",
837
+ span_id: randomBytes(8).toString("hex"),
838
+ span_type: "http",
839
+ span_name: hostname,
840
+ status: report.statusCode >= 400 || report.statusCode === 0 ? "error" : "ok",
841
+ start_time: new Date(Date.now() - report.latencyMs).toISOString(),
842
+ end_time: (/* @__PURE__ */ new Date()).toISOString(),
843
+ duration_ms: report.latencyMs,
844
+ attributes: {
845
+ "ai.agent.http.method": report.method,
846
+ "ai.agent.http.url": report.url
847
+ },
848
+ http_method: report.method,
849
+ http_status_code: report.statusCode,
850
+ http_url: report.url
851
+ });
852
+ } catch {
853
+ }
854
+ }
855
+ });
505
856
  api.registerChannel({ plugin: agentVaultPlugin });
506
857
  }
507
858
  };