@smythos/sre 1.7.42 → 1.8.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.
Files changed (61) hide show
  1. package/CHANGELOG +448 -66
  2. package/dist/index.js +65 -50
  3. package/dist/index.js.map +1 -1
  4. package/dist/types/Components/Async.class.d.ts +11 -5
  5. package/dist/types/index.d.ts +2 -0
  6. package/dist/types/subsystems/AgentManager/AgentData.service/connectors/SQLiteAgentDataConnector.class.d.ts +45 -0
  7. package/dist/types/subsystems/LLMManager/LLM.helper.d.ts +32 -1
  8. package/dist/types/subsystems/LLMManager/LLM.inference.d.ts +25 -2
  9. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.d.ts +22 -2
  10. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.d.ts +2 -2
  11. package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +27 -2
  12. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Groq.class.d.ts +22 -2
  13. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Ollama.class.d.ts +22 -2
  14. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.d.ts +3 -3
  15. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.d.ts +23 -3
  16. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.d.ts +2 -2
  17. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.d.ts +2 -2
  18. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.d.ts +2 -2
  19. package/dist/types/subsystems/LLMManager/LLM.service/connectors/xAI.class.d.ts +3 -3
  20. package/dist/types/subsystems/MemoryManager/LLMContext.d.ts +10 -3
  21. package/dist/types/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.d.ts +24 -0
  22. package/dist/types/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.redaction.helper.d.ts +49 -0
  23. package/dist/types/types/LLM.types.d.ts +30 -1
  24. package/package.json +4 -3
  25. package/src/Components/APICall/OAuth.helper.ts +16 -1
  26. package/src/Components/APIEndpoint.class.ts +11 -4
  27. package/src/Components/Async.class.ts +38 -5
  28. package/src/Components/GenAILLM.class.ts +13 -7
  29. package/src/Components/ImageGenerator.class.ts +32 -13
  30. package/src/Components/LLMAssistant.class.ts +3 -1
  31. package/src/Components/LogicAND.class.ts +13 -0
  32. package/src/Components/LogicAtLeast.class.ts +18 -0
  33. package/src/Components/LogicAtMost.class.ts +19 -0
  34. package/src/Components/LogicOR.class.ts +12 -2
  35. package/src/Components/LogicXOR.class.ts +11 -0
  36. package/src/constants.ts +1 -1
  37. package/src/helpers/Conversation.helper.ts +10 -8
  38. package/src/index.ts +2 -0
  39. package/src/index.ts.bak +2 -0
  40. package/src/subsystems/AgentManager/AgentData.service/connectors/SQLiteAgentDataConnector.class.ts +190 -0
  41. package/src/subsystems/AgentManager/AgentData.service/index.ts +2 -0
  42. package/src/subsystems/LLMManager/LLM.helper.ts +117 -1
  43. package/src/subsystems/LLMManager/LLM.inference.ts +136 -67
  44. package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +22 -6
  45. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +157 -33
  46. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +9 -8
  47. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +124 -90
  48. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +125 -62
  49. package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +168 -76
  50. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +18 -8
  51. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +8 -4
  52. package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +50 -8
  53. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +30 -16
  54. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.ts +2 -2
  55. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +29 -15
  56. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +10 -8
  57. package/src/subsystems/MemoryManager/LLMContext.ts +27 -8
  58. package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.ts +313 -85
  59. package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.redaction.helper.ts +203 -0
  60. package/src/types/LLM.types.ts +31 -1
  61. package/src/types/node-sqlite.d.ts +45 -0
@@ -4,6 +4,7 @@ import { ACL } from '@sre/Security/AccessControl/ACL.class';
4
4
  import { IAccessCandidate } from '@sre/types/ACL.types';
5
5
  import { TelemetryConnector } from '../../TelemetryConnector';
6
6
  import { AgentCallLog } from '@sre/types/AgentLogger.types';
7
+ import { redactSensitiveString, redactData, redactHeaders } from './OTel.redaction.helper';
7
8
 
8
9
  import { trace, context, SpanStatusCode, Tracer, propagation } from '@opentelemetry/api';
9
10
  import { Logger as OTelLogger, logs, SeverityNumber } from '@opentelemetry/api-logs';
@@ -50,6 +51,14 @@ export type OTelLogConfig = {
50
51
  * These will be replaced with '[REDACTED]' in logs
51
52
  */
52
53
  redactFields?: string[];
54
+ /**
55
+ * Enable automatic redaction of sensitive data in logs and traces.
56
+ * When true (or omitted), sensitive data such as passwords, tokens,
57
+ * API keys, and JWT tokens are automatically replaced with '[REDACTED]'.
58
+ * Set to false to disable all automatic redaction.
59
+ * Default: true
60
+ */
61
+ enableRedaction?: boolean;
53
62
  };
54
63
  const OTEL_DEBUG_LOGS = true;
55
64
  export class OTel extends TelemetryConnector {
@@ -62,6 +71,9 @@ export class OTel extends TelemetryConnector {
62
71
 
63
72
  constructor(protected _settings: OTelLogConfig) {
64
73
  super();
74
+ // Default enableRedaction to true when not explicitly provided
75
+ _settings.enableRedaction = _settings.enableRedaction ?? true;
76
+
65
77
  if (!_settings.endpoint) {
66
78
  outputLogger.warn('OTel initialization skipped, endpoint is not set');
67
79
  return;
@@ -141,6 +153,7 @@ export class OTel extends TelemetryConnector {
141
153
  * Redact sensitive fields from an object
142
154
  */
143
155
  private redactSensitiveData(data: any, redactFields?: string[]): any {
156
+ if (!this._settings.enableRedaction) return data;
144
157
  if (!redactFields || redactFields.length === 0) return data;
145
158
  if (typeof data !== 'object' || data === null) return data;
146
159
 
@@ -157,6 +170,35 @@ export class OTel extends TelemetryConnector {
157
170
  return redacted;
158
171
  }
159
172
 
173
+ /**
174
+ * Redact sensitive patterns from a string value.
175
+ * Skips redaction when enableRedaction is explicitly set to false.
176
+ */
177
+ private redactString(value: string): string {
178
+ if (!this._settings.enableRedaction) return value;
179
+ return redactSensitiveString(value);
180
+ }
181
+
182
+ /**
183
+ * Redact sensitive data from any data type (objects, arrays, strings).
184
+ * Skips redaction when enableRedaction is explicitly set to false.
185
+ */
186
+ private redactObject<T>(data: T): T {
187
+ if (!this._settings.enableRedaction) return data;
188
+ return redactData(data);
189
+ }
190
+
191
+ /**
192
+ * Redact sensitive HTTP headers.
193
+ * Skips redaction when enableRedaction is explicitly set to false.
194
+ */
195
+ private redactRequestHeaders(
196
+ headers: Record<string, unknown> | string | undefined | null,
197
+ ): Record<string, unknown> | string | undefined | null {
198
+ if (!this._settings.enableRedaction) return headers;
199
+ return redactHeaders(headers);
200
+ }
201
+
160
202
  /**
161
203
  * Safely format output for logging with size limits and redaction
162
204
  */
@@ -170,11 +212,17 @@ export class OTel extends TelemetryConnector {
170
212
  return undefined;
171
213
  }
172
214
 
173
- // Redact sensitive fields
174
- const redacted = this.redactSensitiveData(output, config.redactFields);
215
+ // Redact sensitive fields (config-based)
216
+ let redacted = this.redactSensitiveData(output, config.redactFields);
217
+
218
+ // Apply SENSITIVE_WORDS-based redaction on the object (automatic key-based redaction)
219
+ redacted = this.redactObject(redacted);
175
220
 
176
221
  // Stringify
177
- const outputStr = JSON.stringify(redacted);
222
+ let outputStr = JSON.stringify(redacted);
223
+
224
+ // Apply string-based redaction on the stringified output to catch embedded JSON
225
+ outputStr = this.redactString(outputStr);
178
226
 
179
227
  // Check size limit
180
228
  if (outputStr && outputStr.length > maxSize) {
@@ -200,12 +248,38 @@ export class OTel extends TelemetryConnector {
200
248
  for (let key in data) {
201
249
  result[prefix ? `${prefix}.${key}` : key] = (typeof data[key] === 'object' ? JSON.stringify(data[key]) : data[key].toString()).substring(
202
250
  0,
203
- maxEntryLength
251
+ maxEntryLength,
204
252
  );
205
253
  }
206
254
 
207
255
  return result;
208
256
  }
257
+
258
+ private prepareContext(contextWindow: Array<{ role: string; content: string; [key: string]: unknown }>): string {
259
+ if (!contextWindow || !Array.isArray(contextWindow)) return '[]';
260
+
261
+ const filtered = contextWindow.filter((msg) => {
262
+ if (typeof msg !== 'object' || msg === null) return false;
263
+ const keys = Object.keys(msg);
264
+ return !keys.some((k) => k.includes('___smyth_metadata___'));
265
+ });
266
+
267
+ const lastAssistant = [...filtered].reverse().find((msg) => msg.role === 'assistant' && msg.content);
268
+ const lastUser = [...filtered].reverse().find((msg) => msg.role === 'user' && msg.content);
269
+
270
+ const messages: Array<{ role: string; content: string }> = [];
271
+ if (lastAssistant) {
272
+ const raw = typeof lastAssistant.content === 'string' ? lastAssistant.content : JSON.stringify(lastAssistant.content);
273
+ messages.push({ role: 'assistant', content: raw.substring(0, 2000) });
274
+ }
275
+ if (lastUser) {
276
+ const raw = typeof lastUser.content === 'string' ? lastUser.content : JSON.stringify(lastUser.content);
277
+ messages.push({ role: 'user', content: raw.substring(0, 2000) });
278
+ }
279
+
280
+ return JSON.stringify(messages);
281
+ }
282
+
209
283
  protected setupHooks(): Promise<void> {
210
284
  const tracer = this.tracer;
211
285
  const logger = this.logger;
@@ -219,15 +293,18 @@ export class OTel extends TelemetryConnector {
219
293
 
220
294
  const modelId = toolInfo.model;
221
295
  const contextWindow = toolInfo.contextWindow;
222
- const lastContext = contextWindow.filter((context) => context.role === 'user').slice(-2);
223
296
 
224
- const toolNames = toolInfo.map((tool) => tool.name + '(' + tool.arguments + ')');
297
+ const toolNames = toolInfo.map((tool) => {
298
+ const args = typeof tool.arguments === 'string' ? tool.arguments : JSON.stringify(tool.arguments);
299
+ return `${tool.name}(${args})`;
300
+ });
225
301
  hookContext.curLLMGenSpan.addEvent('llm.gen.tool.calls', {
226
- 'tool.calls': toolNames.join(', '),
227
- 'llm.model': modelId || 'unknown',
228
- 'context.preview': JSON.stringify(lastContext).substring(0, 200),
302
+ 'tool.calls': oTelInstance.redactString(toolNames.join(', ')),
303
+ 'llm.model': modelId || '',
304
+ 'context.preview': oTelInstance.redactString(oTelInstance.prepareContext(contextWindow).substring(0, 200)),
229
305
  });
230
306
 
307
+ const llmSpanCtx = hookContext.curLLMGenSpan.spanContext();
231
308
  const spanContext = trace.setSpan(context.active(), hookContext.curLLMGenSpan);
232
309
  context.with(spanContext, () => {
233
310
  logger.emit({
@@ -235,10 +312,15 @@ export class OTel extends TelemetryConnector {
235
312
  severityText: 'INFO',
236
313
  body: `LLM tool calls: ${toolNames.join(', ')}`,
237
314
  attributes: {
315
+ // Explicit trace correlation (some backends need these)
316
+ trace_id: llmSpanCtx.traceId,
317
+ span_id: llmSpanCtx.spanId,
318
+ trace_flags: llmSpanCtx.traceFlags,
319
+
238
320
  'agent.id': hookContext.agentId,
239
321
  'conv.id': hookContext.processId,
240
- 'llm.model': modelId || 'unknown',
241
- 'context.preview': JSON.stringify(lastContext).substring(0, 5000),
322
+ 'llm.model': modelId || '',
323
+ 'context.preview': oTelInstance.redactString(oTelInstance.prepareContext(contextWindow)),
242
324
  },
243
325
  });
244
326
  });
@@ -259,7 +341,6 @@ export class OTel extends TelemetryConnector {
259
341
  const modelId = reqInfo.model;
260
342
  const contextWindow = reqInfo.contextWindow;
261
343
 
262
- const lastContext = contextWindow.filter((context) => context.role === 'user').slice(-2);
263
344
  // End TTFB span when first data arrives
264
345
  if (hookContext?.latencySpans?.[reqInfo.requestId]) {
265
346
  const ttfbSpan = hookContext.latencySpans[reqInfo.requestId];
@@ -268,7 +349,7 @@ export class OTel extends TelemetryConnector {
268
349
  ttfbSpan.addEvent('llm.first.byte.received', {
269
350
  'request.id': reqInfo.requestId,
270
351
  'data.size': JSON.stringify(data || {}).length,
271
- 'llm.model': modelId || 'unknown',
352
+ 'llm.model': modelId || '',
272
353
  });
273
354
 
274
355
  ttfbSpan.setStatus({ code: SpanStatusCode.OK });
@@ -284,22 +365,98 @@ export class OTel extends TelemetryConnector {
284
365
  'agent.id': hookContext.agentId,
285
366
  'conv.id': hookContext.processId,
286
367
  'team.id': hookContext.teamId,
287
- 'llm.model': modelId || 'unknown',
368
+ 'llm.model': modelId || '',
288
369
  },
289
370
  },
290
- trace.setSpan(context.active(), hookContext.convSpan)
371
+ trace.setSpan(context.active(), hookContext.convSpan),
291
372
  );
292
373
  llmGenSpan.addEvent('llm.gen.started', {
293
374
  'request.id': reqInfo.requestId,
294
375
  timestamp: Date.now(),
295
- 'llm.model': modelId || 'unknown',
296
- 'context.preview': JSON.stringify(lastContext).substring(0, 200),
376
+ 'llm.model': modelId || '',
377
+ 'context.preview': oTelInstance.redactString(oTelInstance.prepareContext(contextWindow).substring(0, 200)),
378
+ });
379
+
380
+ const llmGenSpanCtx = llmGenSpan.spanContext();
381
+ const llmGenSpanContext = trace.setSpan(context.active(), llmGenSpan);
382
+ context.with(llmGenSpanContext, () => {
383
+ logger.emit({
384
+ severityNumber: SeverityNumber.INFO,
385
+ severityText: 'INFO',
386
+ body: `LLM generation started: ${hookContext.processId}`,
387
+ attributes: {
388
+ // Explicit trace correlation (some backends need these)
389
+ trace_id: llmGenSpanCtx.traceId,
390
+ span_id: llmGenSpanCtx.spanId,
391
+ trace_flags: llmGenSpanCtx.traceFlags,
392
+
393
+ 'agent.id': hookContext.agentId,
394
+ 'conv.id': hookContext.processId,
395
+ 'team.id': hookContext.teamId,
396
+ 'llm.model': modelId || '',
397
+ 'request.id': reqInfo.requestId,
398
+ 'context.preview': oTelInstance.redactString(oTelInstance.prepareContext(contextWindow)),
399
+ },
400
+ });
297
401
  });
402
+
298
403
  hookContext.curLLMGenSpan = llmGenSpan;
299
404
  if (OTEL_DEBUG_LOGS) outputLogger.debug('createDataHandler completed', reqInfo?.requestId, accessCandidate);
300
405
  };
301
406
  };
302
407
 
408
+ const createErrorHandler = function (hookContext: any) {
409
+ return function (error: Error, metadata?: { requestId?: string }) {
410
+ if (!hookContext.convSpan) return;
411
+ const accessCandidate = AccessCandidate.agent(hookContext?.agentId);
412
+ if (OTEL_DEBUG_LOGS)
413
+ outputLogger.debug('Error event received', { error: error?.message, requestId: metadata?.requestId }, accessCandidate);
414
+
415
+ // Mark that an error occurred so after hook knows not to log success
416
+ hookContext.hasError = true;
417
+ hookContext.errorDetails = error;
418
+
419
+ const convSpan = hookContext.convSpan;
420
+ const spanCtx = convSpan.spanContext();
421
+ const spanContext = trace.setSpan(context.active(), convSpan);
422
+
423
+ // Record exception on span
424
+ convSpan.recordException(error);
425
+ convSpan.setStatus({ code: SpanStatusCode.ERROR, message: error?.message || 'Unknown error' });
426
+ convSpan.addEvent('conv.error', {
427
+ 'error.message': error?.message || 'Unknown error',
428
+ 'request.id': metadata?.requestId || 'unknown',
429
+ });
430
+
431
+ context.with(spanContext, () => {
432
+ logger.emit({
433
+ severityNumber: SeverityNumber.ERROR,
434
+ severityText: 'ERROR',
435
+ body: `Conversation error: ${hookContext.processId}`,
436
+ attributes: {
437
+ // Explicit trace correlation (some backends need these)
438
+ trace_id: spanCtx.traceId,
439
+ span_id: spanCtx.spanId,
440
+ trace_flags: spanCtx.traceFlags,
441
+
442
+ 'agent.id': hookContext.agentId,
443
+ 'agent.name': hookContext.agentName,
444
+ 'conv.id': hookContext.processId,
445
+ 'error.message': error?.message || 'Unknown error',
446
+ 'error.stack': error?.stack,
447
+ 'team.id': hookContext.teamId,
448
+ 'org.slot': hookContext.orgSlot,
449
+ 'agent.debug': hookContext.isDebugSession,
450
+ 'agent.isTest': hookContext.isTestDomain,
451
+ 'request.id': metadata?.requestId || 'unknown',
452
+ },
453
+ });
454
+ });
455
+
456
+ if (OTEL_DEBUG_LOGS) outputLogger.debug('Error event handled', { error: error?.message }, accessCandidate);
457
+ };
458
+ };
459
+
303
460
  const createRequestedHandler = function (hookContext) {
304
461
  return function (reqInfo: any) {
305
462
  if (!hookContext.convSpan) return;
@@ -308,8 +465,6 @@ export class OTel extends TelemetryConnector {
308
465
  if (!hookContext.latencySpans) hookContext.latencySpans = {};
309
466
  const contextWindow = reqInfo.contextWindow;
310
467
 
311
- const lastContext = contextWindow.filter((context) => context.role === 'user').slice(-2);
312
-
313
468
  const modelId = reqInfo.model;
314
469
  const llmGenLatencySpan = tracer.startSpan(
315
470
  'Conv.GenAI.TTFB',
@@ -319,16 +474,16 @@ export class OTel extends TelemetryConnector {
319
474
  'conv.id': hookContext.processId,
320
475
  'team.id': hookContext.teamId,
321
476
  'request.id': reqInfo.requestId,
322
- 'llm.model': modelId || 'unknown',
477
+ 'llm.model': modelId || '',
323
478
  'metric.type': 'ttfb',
324
479
  },
325
480
  },
326
- trace.setSpan(context.active(), hookContext.convSpan)
481
+ trace.setSpan(context.active(), hookContext.convSpan),
327
482
  );
328
483
  llmGenLatencySpan.addEvent('llm.requested', {
329
484
  'request.id': reqInfo.requestId,
330
485
  timestamp: Date.now(),
331
- 'context.preview': JSON.stringify(lastContext).substring(0, 200),
486
+ 'context.preview': oTelInstance.redactString(oTelInstance.prepareContext(contextWindow).substring(0, 200)),
332
487
  });
333
488
  hookContext.latencySpans[reqInfo.requestId] = llmGenLatencySpan;
334
489
  if (OTEL_DEBUG_LOGS) outputLogger.debug('createRequestedHandler completed', reqInfo?.requestId, accessCandidate);
@@ -351,6 +506,7 @@ export class OTel extends TelemetryConnector {
351
506
  const sessionId = processId;
352
507
  const workflowId = agentData?.workflowReqId || agentData?.workflowID || agentData?.workflowId || undefined;
353
508
  const logTags = agentData?.sessionTag || (isDebugSession ? 'DEBUG' : undefined);
509
+ const agentName = agentData?.name || undefined;
354
510
 
355
511
  if (message == null) {
356
512
  //this is a conversation step, will be handled by createRequestedHandler
@@ -366,16 +522,17 @@ export class OTel extends TelemetryConnector {
366
522
  attributes: {
367
523
  // OTel standard attributes
368
524
  'gen_ai.operation.name': 'chat',
369
- 'gen_ai.provider.name': conversation?.llmInference?.llmProviderName || 'unknown',
525
+ 'gen_ai.provider.name': conversation?.llmInference?.llmProviderName || '',
370
526
  'gen_ai.conversation.id': processId,
371
- 'gen_ai.request.model': modelId || 'unknown',
527
+ 'gen_ai.request.model': modelId || '',
372
528
  ////////////////////////////////
373
529
  'team.id': teamId,
374
530
  'org.tier': orgTier,
375
531
  'org.slot': orgSlot,
376
532
  'agent.id': agentId,
533
+ 'agent.name': agentName,
377
534
  'conv.id': processId,
378
- 'llm.model': modelId || 'unknown',
535
+ 'llm.model': modelId || '',
379
536
  'agent.debug': isDebugSession,
380
537
  'agent.isTest': isTestDomain,
381
538
  'session.id': sessionId,
@@ -384,6 +541,7 @@ export class OTel extends TelemetryConnector {
384
541
  });
385
542
  hookContext.convSpan = convSpan;
386
543
  hookContext.agentId = agentId;
544
+ hookContext.agentName = agentData?.name || undefined;
387
545
  hookContext.processId = processId;
388
546
  hookContext.teamId = teamId;
389
547
  hookContext.orgSlot = orgSlot;
@@ -410,12 +568,15 @@ export class OTel extends TelemetryConnector {
410
568
  hookContext.toolInfoHandler = createToolInfoHandler(hookContext);
411
569
  conversation.on(TLLMEvent.ToolInfo, hookContext.toolInfoHandler);
412
570
 
571
+ hookContext.errorHandler = createErrorHandler(hookContext);
572
+ conversation.on(TLLMEvent.Error, hookContext.errorHandler);
573
+
413
574
  // Add start event
414
575
 
415
576
  convSpan.addEvent('skill.process.started', {
416
577
  'input.size': JSON.stringify(message || {}).length,
417
- 'input.preview': message.substring(0, 200),
418
- 'llm.model': modelId || 'unknown',
578
+ 'input.preview': oTelInstance.redactString(message.substring(0, 200)),
579
+ 'llm.model': modelId || '',
419
580
  });
420
581
 
421
582
  OTelContextRegistry.startProcess(agentId, processId, convSpan);
@@ -438,9 +599,10 @@ export class OTel extends TelemetryConnector {
438
599
  'org.slot': orgSlot,
439
600
 
440
601
  'agent.id': agentId,
602
+ 'agent.name': agentName,
441
603
  'conv.id': processId,
442
604
  'input.size': JSON.stringify(message || {}).length,
443
- 'input.preview': message.substring(0, 2000),
605
+ 'input.preview': oTelInstance.redactString(message.substring(0, 4000)),
444
606
  'agent.debug': isDebugSession,
445
607
  'agent.isTest': isTestDomain,
446
608
  'session.id': sessionId,
@@ -450,7 +612,7 @@ export class OTel extends TelemetryConnector {
450
612
  });
451
613
  });
452
614
  },
453
- THook.NonBlocking
615
+ THook.NonBlocking,
454
616
  );
455
617
 
456
618
  HookService.registerAfter(
@@ -471,6 +633,7 @@ export class OTel extends TelemetryConnector {
471
633
  const sessionId = processId;
472
634
  const workflowId = agentData?.workflowReqId || agentData?.workflowID || agentData?.workflowId || undefined;
473
635
  const logTags = agentData?.sessionTag || (isDebugSession ? 'DEBUG' : undefined);
636
+ const agentName = agentData?.name || undefined;
474
637
 
475
638
  if (message == null) {
476
639
  return;
@@ -489,7 +652,9 @@ export class OTel extends TelemetryConnector {
489
652
  }
490
653
  hookContext.curLLMGenSpan.addEvent('llm.gen.content', {
491
654
  'content.size': JSON.stringify(result || {}).length,
492
- 'content.preview': typeof result === 'string' ? result.substring(0, 200) : JSON.stringify(result || {}).substring(0, 200),
655
+ 'content.preview': oTelInstance.redactString(
656
+ typeof result === 'string' ? result.substring(0, 200) : JSON.stringify(result || {}).substring(0, 200),
657
+ ),
493
658
  });
494
659
  hookContext.curLLMGenSpan.end();
495
660
 
@@ -498,46 +663,52 @@ export class OTel extends TelemetryConnector {
498
663
  if (hookContext.requestedHandler) conversation.off(TLLMEvent.Requested, hookContext.requestedHandler);
499
664
  }
500
665
 
666
+ if (hookContext.errorHandler) conversation.off(TLLMEvent.Error, hookContext.errorHandler);
667
+
501
668
  const { rootSpan: convSpan } = ctx;
502
669
 
503
670
  const spanCtx = convSpan.spanContext();
504
671
  const spanContext = trace.setSpan(context.active(), convSpan);
505
672
 
506
- if (error) {
507
- // Error handling for conversation span
508
- convSpan.recordException(error);
509
- convSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
510
- convSpan.addEvent('conv.error', {
511
- 'error.message': error.message,
512
- });
673
+ // Check for errors - either thrown (error param) or emitted via event (hookContext.hasError)
674
+ const hasError = error || hookContext.hasError;
513
675
 
514
- // Emit ERROR log
515
- context.with(spanContext, () => {
516
- logger.emit({
517
- severityNumber: SeverityNumber.ERROR,
518
- severityText: 'ERROR',
519
- body: `Conversation.streamPrompt failed: ${processId}`,
520
- attributes: {
521
- // Explicit trace correlation
522
- trace_id: spanCtx.traceId,
523
- span_id: spanCtx.spanId,
524
- trace_flags: spanCtx.traceFlags,
676
+ if (hasError) {
677
+ if (error && !hookContext.hasError) {
678
+ convSpan.recordException(error);
679
+ convSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message || 'Unknown error' });
680
+ convSpan.addEvent('conv.error', {
681
+ 'error.message': error.message || 'Unknown error',
682
+ });
525
683
 
526
- 'agent.id': agentId,
527
- 'conv.id': processId,
528
- 'error.message': error.message,
529
- 'error.stack': error.stack,
530
- 'team.id': teamId,
531
- 'org.tier': orgTier,
532
- 'org.slot': orgSlot,
533
- 'agent.debug': isDebugSession,
534
- 'agent.isTest': isTestDomain,
535
- 'session.id': sessionId,
536
- 'workflow.id': workflowId,
537
- 'log.tags': logTags,
538
- },
684
+ context.with(spanContext, () => {
685
+ logger.emit({
686
+ severityNumber: SeverityNumber.ERROR,
687
+ severityText: 'ERROR',
688
+ body: `Conversation.streamPrompt failed: ${processId}`,
689
+ attributes: {
690
+ // Explicit trace correlation (some backends need these)
691
+ trace_id: spanCtx.traceId,
692
+ span_id: spanCtx.spanId,
693
+ trace_flags: spanCtx.traceFlags,
694
+
695
+ 'agent.id': agentId,
696
+ 'agent.name': agentName,
697
+ 'conv.id': processId,
698
+ 'error.message': error.message || 'Unknown error',
699
+ 'error.stack': error.stack,
700
+ 'team.id': teamId,
701
+ 'org.tier': orgTier,
702
+ 'org.slot': orgSlot,
703
+ 'agent.debug': isDebugSession,
704
+ 'agent.isTest': isTestDomain,
705
+ 'session.id': sessionId,
706
+ 'workflow.id': workflowId,
707
+ 'log.tags': logTags,
708
+ },
709
+ });
539
710
  });
540
- });
711
+ }
541
712
  } else {
542
713
  // Success handling
543
714
  convSpan.setStatus({ code: SpanStatusCode.OK });
@@ -548,11 +719,18 @@ export class OTel extends TelemetryConnector {
548
719
  severityText: 'INFO',
549
720
  body: `Conversation.streamPrompt completed: ${processId}`,
550
721
  attributes: {
722
+ // Explicit trace correlation (some backends need these)
723
+ trace_id: spanCtx.traceId,
724
+ span_id: spanCtx.spanId,
725
+ trace_flags: spanCtx.traceFlags,
726
+
551
727
  'agent.id': agentId,
728
+ 'agent.name': agentName,
552
729
  'conv.id': processId,
553
730
  'output.size': JSON.stringify(result || {}).length,
554
- 'output.preview':
555
- typeof result === 'string' ? result.substring(0, 2000) : JSON.stringify(result || {}).substring(0, 2000),
731
+ 'output.preview': oTelInstance.redactString(
732
+ (typeof result === 'string' ? result : JSON.stringify(result || {})).substring(0, 4000),
733
+ ),
556
734
  'team.id': teamId,
557
735
  'org.tier': orgTier,
558
736
  'org.slot': orgSlot,
@@ -570,7 +748,7 @@ export class OTel extends TelemetryConnector {
570
748
 
571
749
  OTelContextRegistry.endProcess(agentId, processId);
572
750
  },
573
- THook.NonBlocking
751
+ THook.NonBlocking,
574
752
  );
575
753
 
576
754
  HookService.register(
@@ -597,6 +775,7 @@ export class OTel extends TelemetryConnector {
597
775
  const logTags = agent.sessionTag || (isDebugSession ? 'DEBUG' : undefined);
598
776
  const isTestDomain = agent.usingTestDomain || false;
599
777
  const domain = agent.domain || undefined;
778
+ const agentName = agent.name || undefined;
600
779
 
601
780
  const accessCandidate = AccessCandidate.agent(agentId);
602
781
  if (OTEL_DEBUG_LOGS) outputLogger.debug('SREAgent.process started', { processId, agentProcessId, endpointPath }, accessCandidate);
@@ -608,6 +787,11 @@ export class OTel extends TelemetryConnector {
608
787
 
609
788
  const input = { body, query, headers, processInput: agentInput };
610
789
 
790
+ const logBody = oTelInstance.prepareComponentData(agentRequest.body || {}, undefined, 4000);
791
+ const logQuery = oTelInstance.prepareComponentData(agentRequest.query || {}, undefined, 4000);
792
+ const logHeaders = oTelInstance.prepareComponentData(agentRequest.headers || {}, undefined, 4000);
793
+ const logAgentInput = oTelInstance.prepareComponentData(inputData || {}, undefined, 4000);
794
+
611
795
  let convSpan;
612
796
  let parentContext = context.active();
613
797
 
@@ -640,6 +824,7 @@ export class OTel extends TelemetryConnector {
640
824
  {
641
825
  attributes: {
642
826
  'agent.id': agentId,
827
+ 'agent.name': agentName,
643
828
  'team.id': teamId,
644
829
  'conv.id': conversationId,
645
830
  'process.id': agentProcessId,
@@ -652,11 +837,11 @@ export class OTel extends TelemetryConnector {
652
837
  'agent.domain': domain,
653
838
  },
654
839
  },
655
- parentContext
840
+ parentContext,
656
841
  );
657
842
 
658
843
  // Add start event
659
- const inputPreview = JSON.stringify(input || {}).substring(0, 200);
844
+ const inputPreview = oTelInstance.redactString(JSON.stringify(input || {}).substring(0, 200));
660
845
  agentSpan.addEvent('skill.process.started', {
661
846
  endpoint: endpointPath,
662
847
  'input.size': JSON.stringify(input || {}).length,
@@ -678,12 +863,14 @@ export class OTel extends TelemetryConnector {
678
863
  trace_id: spanCtx.traceId,
679
864
  span_id: spanCtx.spanId,
680
865
  trace_flags: spanCtx.traceFlags,
866
+
681
867
  'agent.id': agentId,
868
+ 'agent.name': agentName,
682
869
  'process.id': agentProcessId,
683
- input: agentInput,
684
- body,
685
- query,
686
- headers,
870
+ input: oTelInstance.redactObject(logAgentInput),
871
+ body: oTelInstance.redactObject(logBody),
872
+ query: oTelInstance.redactObject(logQuery),
873
+ headers: oTelInstance.redactRequestHeaders(logHeaders),
687
874
  'team.id': teamId,
688
875
  'org.slot': orgSlot,
689
876
  'org.tier': orgTier,
@@ -698,7 +885,7 @@ export class OTel extends TelemetryConnector {
698
885
  } as any);
699
886
  });
700
887
  },
701
- THook.NonBlocking
888
+ THook.NonBlocking,
702
889
  );
703
890
 
704
891
  HookService.registerAfter(
@@ -720,6 +907,7 @@ export class OTel extends TelemetryConnector {
720
907
  const logTags = agent.sessionTag || (isDebugSession ? 'DEBUG' : undefined);
721
908
  const isTestDomain = agent.usingTestDomain || false;
722
909
  const domain = agent.domain || undefined;
910
+ const agentName = agent.name || undefined;
723
911
 
724
912
  const ctx = OTelContextRegistry.get(agentId, agentProcessId);
725
913
  if (!ctx) return;
@@ -774,7 +962,9 @@ export class OTel extends TelemetryConnector {
774
962
  trace_id: spanCtx.traceId,
775
963
  span_id: spanCtx.spanId,
776
964
  trace_flags: spanCtx.traceFlags,
965
+
777
966
  'agent.id': agentId,
967
+ 'agent.name': agentName,
778
968
  'process.id': agentProcessId,
779
969
  hasError: isError,
780
970
  'error.message': isError ? errorMessage : undefined,
@@ -813,7 +1003,7 @@ export class OTel extends TelemetryConnector {
813
1003
 
814
1004
  OTelContextRegistry.endProcess(agentId, agentProcessId);
815
1005
  },
816
- THook.NonBlocking
1006
+ THook.NonBlocking,
817
1007
  );
818
1008
 
819
1009
  // In setupHooks() - Enhanced Component.process hook
@@ -844,6 +1034,7 @@ export class OTel extends TelemetryConnector {
844
1034
  const isDebugSession = agent.debugSessionEnabled || agent.agentRuntime?.debug || false;
845
1035
  const logTags = agent.sessionTag || (isDebugSession ? 'DEBUG' : undefined);
846
1036
  const isTestDomain = agent.usingTestDomain || false;
1037
+ const agentName = agent.name || undefined;
847
1038
 
848
1039
  const inputAction = input?.__action || undefined;
849
1040
  const inputStatus = input?.__status || undefined;
@@ -860,6 +1051,7 @@ export class OTel extends TelemetryConnector {
860
1051
  {
861
1052
  attributes: {
862
1053
  'agent.id': agentId,
1054
+ 'agent.name': agentName,
863
1055
  'process.id': processId,
864
1056
  'event.id': eventId,
865
1057
  'cmp.id': componentId,
@@ -878,22 +1070,30 @@ export class OTel extends TelemetryConnector {
878
1070
  ...compSettingsData,
879
1071
  },
880
1072
  },
881
- parentSpan ? trace.setSpan(context.active(), parentSpan) : undefined
1073
+ parentSpan ? trace.setSpan(context.active(), parentSpan) : undefined,
882
1074
  );
883
1075
 
884
1076
  // Add event: Component started - includes input.action and input.status for workflow tracking
885
- const inputStr = JSON.stringify(input || {});
886
-
887
- const compInputData = oTelInstance.prepareComponentData(input || {});
1077
+ // Use component-specific input (from predecessor nodes), not the merged object with agent variables
1078
+ // For APIEndpoint, use HTTP request body/query as the actual user input
1079
+ const componentInput =
1080
+ componentType === 'APIEndpoint'
1081
+ ? agent.agentRequest?.method === 'GET'
1082
+ ? agent.agentRequest?.query
1083
+ : agent.agentRequest?.body
1084
+ : componentData?.runtimeData?.input || {};
1085
+
1086
+ const compInputData = oTelInstance.prepareComponentData(componentInput || {});
888
1087
  span.addEvent('cmp.call', {
889
1088
  'event.id': eventId,
890
- 'cmp.input.size': JSON.stringify(input || {}).length,
891
- 'cmp.input': JSON.stringify(compInputData),
1089
+ 'cmp.input.size': JSON.stringify(componentInput || {}).length,
1090
+ 'cmp.input': oTelInstance.redactString(JSON.stringify(compInputData)),
892
1091
  'input.action': inputAction,
893
1092
  'input.status': inputStatus,
894
1093
  });
895
1094
 
896
1095
  // Emit structured log with full details
1096
+ const cmpSpanCtx = span.spanContext();
897
1097
  const spanContext = trace.setSpan(context.active(), span);
898
1098
  context.with(spanContext, () => {
899
1099
  logger.emit({
@@ -901,13 +1101,19 @@ export class OTel extends TelemetryConnector {
901
1101
  severityText: 'INFO',
902
1102
  body: `Component ${componentType} started`,
903
1103
  attributes: {
1104
+ // Explicit trace correlation (some backends need these)
1105
+ trace_id: cmpSpanCtx.traceId,
1106
+ span_id: cmpSpanCtx.spanId,
1107
+ trace_flags: cmpSpanCtx.traceFlags,
1108
+
904
1109
  'agent.id': agentId,
1110
+ 'agent.name': agentName,
905
1111
  'process.id': processId,
906
1112
  'event.id': eventId,
907
1113
  'cmp.id': componentId,
908
1114
  'cmp.type': componentType,
909
1115
  'cmp.name': componentName,
910
- 'cmp.input': input,
1116
+ 'cmp.input': oTelInstance.redactObject(componentInput),
911
1117
  'team.id': teamId,
912
1118
  'org.slot': orgSlot,
913
1119
  'org.tier': orgTier,
@@ -926,7 +1132,7 @@ export class OTel extends TelemetryConnector {
926
1132
  // Store span in hook context (isolated per component execution, concurrency-safe)
927
1133
  this.context.otelSpan = span;
928
1134
  },
929
- THook.NonBlocking
1135
+ THook.NonBlocking,
930
1136
  );
931
1137
 
932
1138
  HookService.registerAfter(
@@ -961,6 +1167,7 @@ export class OTel extends TelemetryConnector {
961
1167
  const isDebugSession = agent.debugSessionEnabled || agent.agentRuntime?.debug || false;
962
1168
  const logTags = agent.sessionTag || (isDebugSession ? 'DEBUG' : undefined);
963
1169
  const isTestDomain = agent.usingTestDomain || false;
1170
+ const agentName = agent.name || undefined;
964
1171
 
965
1172
  const accessCandidate = AccessCandidate.agent(agentId);
966
1173
  if (OTEL_DEBUG_LOGS) outputLogger.debug('Component.process completed', { componentId }, accessCandidate);
@@ -982,6 +1189,7 @@ export class OTel extends TelemetryConnector {
982
1189
  });
983
1190
 
984
1191
  // Emit error log
1192
+ const cmpErrorSpanCtx = span.spanContext();
985
1193
  const spanContext = trace.setSpan(context.active(), span);
986
1194
  context.with(spanContext, () => {
987
1195
  logger.emit({
@@ -989,7 +1197,13 @@ export class OTel extends TelemetryConnector {
989
1197
  severityText: 'ERROR',
990
1198
  body: `Component ${componentType} (${componentId}) failed: ${error.message}`,
991
1199
  attributes: {
1200
+ // Explicit trace correlation (some backends need these)
1201
+ trace_id: cmpErrorSpanCtx.traceId,
1202
+ span_id: cmpErrorSpanCtx.spanId,
1203
+ trace_flags: cmpErrorSpanCtx.traceFlags,
1204
+
992
1205
  'agent.id': agentId,
1206
+ 'agent.name': agentName,
993
1207
  'process.id': processId,
994
1208
  'event.id': eventId,
995
1209
  'cmp.id': componentId,
@@ -1039,6 +1253,7 @@ export class OTel extends TelemetryConnector {
1039
1253
  });
1040
1254
 
1041
1255
  // Emit ERROR log for result error
1256
+ const cmpResultErrorSpanCtx = span.spanContext();
1042
1257
  const spanContext = trace.setSpan(context.active(), span);
1043
1258
  context.with(spanContext, () => {
1044
1259
  logger.emit({
@@ -1046,7 +1261,13 @@ export class OTel extends TelemetryConnector {
1046
1261
  severityText: 'ERROR',
1047
1262
  body: `Component ${componentType} (${componentId}) failed: ${errorMessage}`,
1048
1263
  attributes: {
1264
+ // Explicit trace correlation (some backends need these)
1265
+ trace_id: cmpResultErrorSpanCtx.traceId,
1266
+ span_id: cmpResultErrorSpanCtx.spanId,
1267
+ trace_flags: cmpResultErrorSpanCtx.traceFlags,
1268
+
1049
1269
  'agent.id': agentId,
1270
+ 'agent.name': agentName,
1050
1271
  'process.id': processId,
1051
1272
  'event.id': eventId,
1052
1273
  'cmp.id': componentId,
@@ -1054,7 +1275,7 @@ export class OTel extends TelemetryConnector {
1054
1275
  'cmp.type': componentType,
1055
1276
  'error.type': 'result_error',
1056
1277
  'error.message': errorMessage,
1057
- 'cmp.output': result,
1278
+ 'cmp.output': oTelInstance.redactObject(result),
1058
1279
  'team.id': teamId,
1059
1280
  'org.slot': orgSlot,
1060
1281
  'org.tier': orgTier,
@@ -1076,7 +1297,7 @@ export class OTel extends TelemetryConnector {
1076
1297
  // Add success event with output summary
1077
1298
  span.addEvent('cmp.call.result', {
1078
1299
  'output.size': resultStr.length,
1079
- 'output.preview': resultStr.substring(0, 200),
1300
+ 'output.preview': oTelInstance.redactString(resultStr.substring(0, 200)),
1080
1301
  });
1081
1302
 
1082
1303
  // Add output attributes to span
@@ -1086,14 +1307,21 @@ export class OTel extends TelemetryConnector {
1086
1307
  });
1087
1308
 
1088
1309
  // Emit success log with output (formatted safely)
1310
+ const cmpSuccessSpanCtx = span.spanContext();
1089
1311
  const logAttributes: Record<string, any> = {
1312
+ // Explicit trace correlation (some backends need these)
1313
+ trace_id: cmpSuccessSpanCtx.traceId,
1314
+ span_id: cmpSuccessSpanCtx.spanId,
1315
+ trace_flags: cmpSuccessSpanCtx.traceFlags,
1316
+
1090
1317
  'agent.id': agentId,
1318
+ 'agent.name': agentName,
1091
1319
  'cmp.id': componentId,
1092
1320
  'cmp.type': componentType,
1093
1321
  'cmp.name': componentName,
1094
1322
  'process.id': processId,
1095
1323
  'event.id': eventId,
1096
- 'cmp.output': result,
1324
+ 'cmp.output': oTelInstance.redactObject(result),
1097
1325
  'team.id': teamId,
1098
1326
  'org.slot': orgSlot,
1099
1327
  'org.tier': orgTier,
@@ -1121,7 +1349,7 @@ export class OTel extends TelemetryConnector {
1121
1349
 
1122
1350
  span.end();
1123
1351
  },
1124
- THook.NonBlocking
1352
+ THook.NonBlocking,
1125
1353
  );
1126
1354
  return Promise.resolve();
1127
1355
  }