@frontmcp/observability 1.9.2 → 1.9.4

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/index.js CHANGED
@@ -399,8 +399,8 @@ __export(index_exports, {
399
399
  module.exports = __toCommonJS(index_exports);
400
400
 
401
401
  // libs/observability/src/plugin/observability.plugin.ts
402
- var import_api16 = require("@opentelemetry/api");
403
- var import_sdk2 = require("@frontmcp/sdk");
402
+ var import_api17 = require("@opentelemetry/api");
403
+ var import_sdk4 = require("@frontmcp/sdk");
404
404
 
405
405
  // libs/observability/src/logging/sinks/stdout.sink.ts
406
406
  function defaultStream() {
@@ -763,6 +763,13 @@ var RequestLogCollector = class {
763
763
  this.status = status;
764
764
  this.statusCode = statusCode;
765
765
  }
766
+ /**
767
+ * Set the HTTP status the request was answered with; one of 400 or more marks it failed.
768
+ */
769
+ setStatusCode(statusCode) {
770
+ this.statusCode = statusCode;
771
+ if (statusCode >= 400) this.status = "error";
772
+ }
766
773
  /**
767
774
  * Set error details.
768
775
  */
@@ -831,8 +838,12 @@ var RequestLogCollector = class {
831
838
  }
832
839
  };
833
840
 
841
+ // libs/observability/src/request-log/request-log.hooks.ts
842
+ var import_sdk3 = require("@frontmcp/sdk");
843
+
834
844
  // libs/observability/src/plugin/observability.hooks.ts
835
- var import_api12 = require("@opentelemetry/api");
845
+ var import_api13 = require("@opentelemetry/api");
846
+ var import_sdk2 = require("@frontmcp/sdk");
836
847
  var import_utils = require("@frontmcp/utils");
837
848
 
838
849
  // libs/observability/src/otel/otel.types.ts
@@ -1027,8 +1038,35 @@ function setFetchResponseStatus(span, statusCode) {
1027
1038
  span.setAttribute(HttpAttributes.STATUS_CODE, statusCode);
1028
1039
  }
1029
1040
 
1030
- // libs/observability/src/otel/spans/http-server.span.ts
1041
+ // libs/observability/src/otel/spans/hook.span.ts
1031
1042
  var import_api4 = require("@opentelemetry/api");
1043
+ function recordHookEvent(parentSpan, stage, owner) {
1044
+ const attributes = {};
1045
+ if (owner) {
1046
+ attributes[FrontMcpAttributes.HOOK_OWNER] = owner;
1047
+ }
1048
+ parentSpan.addEvent(`hook.${stage}`, attributes);
1049
+ }
1050
+ function startHookSpan(tracer, options) {
1051
+ const attributes = {
1052
+ [FrontMcpAttributes.HOOK_STAGE]: options.stage
1053
+ };
1054
+ if (options.owner) {
1055
+ attributes[FrontMcpAttributes.HOOK_OWNER] = options.owner;
1056
+ }
1057
+ if (options.flowName) {
1058
+ attributes[FrontMcpAttributes.FLOW_NAME] = options.flowName;
1059
+ }
1060
+ return startSpan(tracer, {
1061
+ name: `hook ${options.stage}`,
1062
+ kind: import_api4.SpanKind.INTERNAL,
1063
+ attributes,
1064
+ parentContext: options.parentContext
1065
+ });
1066
+ }
1067
+
1068
+ // libs/observability/src/otel/spans/http-server.span.ts
1069
+ var import_api5 = require("@opentelemetry/api");
1032
1070
  function startHttpServerSpan(tracer, options) {
1033
1071
  const attributes = {
1034
1072
  [HttpAttributes.METHOD]: options.method.toUpperCase(),
@@ -1051,7 +1089,7 @@ function startHttpServerSpan(tracer, options) {
1051
1089
  }
1052
1090
  return startSpan(tracer, {
1053
1091
  name: `${options.method.toUpperCase()} ${options.path}`,
1054
- kind: import_api4.SpanKind.SERVER,
1092
+ kind: import_api5.SpanKind.SERVER,
1055
1093
  attributes,
1056
1094
  parentContext: options.parentContext
1057
1095
  });
@@ -1061,11 +1099,11 @@ function setHttpResponseStatus(span, statusCode) {
1061
1099
  }
1062
1100
 
1063
1101
  // libs/observability/src/otel/spans/prompt.span.ts
1064
- var import_api5 = require("@opentelemetry/api");
1102
+ var import_api6 = require("@opentelemetry/api");
1065
1103
  function startPromptSpan(tracer, options) {
1066
1104
  return startSpan(tracer, {
1067
1105
  name: `prompt ${options.name}`,
1068
- kind: import_api5.SpanKind.INTERNAL,
1106
+ kind: import_api6.SpanKind.INTERNAL,
1069
1107
  attributes: {
1070
1108
  [FrontMcpAttributes.PROMPT_NAME]: options.name,
1071
1109
  [McpAttributes.COMPONENT_TYPE]: "prompt",
@@ -1076,7 +1114,7 @@ function startPromptSpan(tracer, options) {
1076
1114
  }
1077
1115
 
1078
1116
  // libs/observability/src/otel/spans/resource.span.ts
1079
- var import_api6 = require("@opentelemetry/api");
1117
+ var import_api7 = require("@opentelemetry/api");
1080
1118
  function startResourceSpan(tracer, options) {
1081
1119
  const attributes = {
1082
1120
  [FrontMcpAttributes.RESOURCE_URI]: options.uri,
@@ -1089,14 +1127,14 @@ function startResourceSpan(tracer, options) {
1089
1127
  }
1090
1128
  return startSpan(tracer, {
1091
1129
  name: `resource ${options.uri}`,
1092
- kind: import_api6.SpanKind.INTERNAL,
1130
+ kind: import_api7.SpanKind.INTERNAL,
1093
1131
  attributes,
1094
1132
  parentContext: options.parentContext
1095
1133
  });
1096
1134
  }
1097
1135
 
1098
1136
  // libs/observability/src/otel/spans/rpc.span.ts
1099
- var import_api7 = require("@opentelemetry/api");
1137
+ var import_api8 = require("@opentelemetry/api");
1100
1138
  function startRpcSpan(tracer, options) {
1101
1139
  const attributes = {
1102
1140
  [RpcAttributes.SYSTEM]: "mcp",
@@ -1120,14 +1158,14 @@ function startRpcSpan(tracer, options) {
1120
1158
  }
1121
1159
  return startSpan(tracer, {
1122
1160
  name: options.method,
1123
- kind: import_api7.SpanKind.SERVER,
1161
+ kind: import_api8.SpanKind.SERVER,
1124
1162
  attributes,
1125
1163
  parentContext: options.parentContext
1126
1164
  });
1127
1165
  }
1128
1166
 
1129
1167
  // libs/observability/src/otel/spans/startup.span.ts
1130
- var import_api8 = require("@opentelemetry/api");
1168
+ var import_api9 = require("@opentelemetry/api");
1131
1169
  function emitStartupReport(tracer, data) {
1132
1170
  const attributes = {
1133
1171
  [FrontMcpAttributes.STARTUP_TOOLS_COUNT]: data.toolsCount,
@@ -1141,14 +1179,14 @@ function emitStartupReport(tracer, data) {
1141
1179
  }
1142
1180
  const { span } = startSpan(tracer, {
1143
1181
  name: "frontmcp.startup",
1144
- kind: import_api8.SpanKind.INTERNAL,
1182
+ kind: import_api9.SpanKind.INTERNAL,
1145
1183
  attributes
1146
1184
  });
1147
1185
  endSpanOk(span);
1148
1186
  }
1149
1187
 
1150
1188
  // libs/observability/src/otel/spans/tool.span.ts
1151
- var import_api9 = require("@opentelemetry/api");
1189
+ var import_api10 = require("@opentelemetry/api");
1152
1190
  function startToolSpan(tracer, options) {
1153
1191
  const attributes = {
1154
1192
  [FrontMcpAttributes.TOOL_NAME]: options.name,
@@ -1166,14 +1204,14 @@ function startToolSpan(tracer, options) {
1166
1204
  }
1167
1205
  return startSpan(tracer, {
1168
1206
  name: `tool ${options.name}`,
1169
- kind: import_api9.SpanKind.INTERNAL,
1207
+ kind: import_api10.SpanKind.INTERNAL,
1170
1208
  attributes,
1171
1209
  parentContext: options.parentContext
1172
1210
  });
1173
1211
  }
1174
1212
 
1175
1213
  // libs/observability/src/otel/spans/transport.span.ts
1176
- var import_api10 = require("@opentelemetry/api");
1214
+ var import_api11 = require("@opentelemetry/api");
1177
1215
  function startTransportSpan(tracer, options) {
1178
1216
  const attributes = {
1179
1217
  [FrontMcpAttributes.TRANSPORT_TYPE]: options.type
@@ -1186,7 +1224,7 @@ function startTransportSpan(tracer, options) {
1186
1224
  }
1187
1225
  return startSpan(tracer, {
1188
1226
  name: `transport ${options.type}`,
1189
- kind: import_api10.SpanKind.INTERNAL,
1227
+ kind: import_api11.SpanKind.INTERNAL,
1190
1228
  attributes,
1191
1229
  parentContext: options.parentContext
1192
1230
  });
@@ -1196,12 +1234,12 @@ function setTransportRequestType(span, requestType) {
1196
1234
  }
1197
1235
 
1198
1236
  // libs/observability/src/otel/trace-context-bridge.ts
1199
- var import_api11 = require("@opentelemetry/api");
1237
+ var import_api12 = require("@opentelemetry/api");
1200
1238
  function frontmcpToOTelSpanContext(tc) {
1201
1239
  return {
1202
1240
  traceId: tc.traceId,
1203
1241
  spanId: tc.parentId,
1204
- traceFlags: tc.traceFlags & import_api11.TraceFlags.SAMPLED ? import_api11.TraceFlags.SAMPLED : import_api11.TraceFlags.NONE,
1242
+ traceFlags: tc.traceFlags & import_api12.TraceFlags.SAMPLED ? import_api12.TraceFlags.SAMPLED : import_api12.TraceFlags.NONE,
1205
1243
  isRemote: true
1206
1244
  };
1207
1245
  }
@@ -1216,8 +1254,8 @@ function otelToFrontmcpContext(sc) {
1216
1254
  }
1217
1255
  function createOTelContextFromTrace(tc) {
1218
1256
  const spanContext = frontmcpToOTelSpanContext(tc);
1219
- const span = import_api11.trace.wrapSpanContext(spanContext);
1220
- return import_api11.trace.setSpan(import_api11.context.active(), span);
1257
+ const span = import_api12.trace.wrapSpanContext(spanContext);
1258
+ return import_api12.trace.setSpan(import_api12.context.active(), span);
1221
1259
  }
1222
1260
 
1223
1261
  // libs/observability/src/plugin/observability.hooks.ts
@@ -1227,11 +1265,13 @@ var EXEC_SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:exec-span");
1227
1265
  var ACTIVE_SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:active-span");
1228
1266
  var ACTIVE_OTEL_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:active-otel-ctx");
1229
1267
  var STAGE_TS_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:stage-ts");
1268
+ var STAGE_EVENTS_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:stage-events");
1269
+ var HTTP_SPAN_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:http-span-ctx");
1230
1270
  function sessionTracingId(sessionId) {
1231
1271
  return (0, import_utils.sha256Hex)(sessionId).slice(0, 16);
1232
1272
  }
1233
1273
  function getTracer() {
1234
- return import_api12.trace.getTracer("@frontmcp/observability");
1274
+ return import_api13.trace.getTracer("@frontmcp/observability");
1235
1275
  }
1236
1276
  function extractContext(flowCtx) {
1237
1277
  try {
@@ -1261,7 +1301,44 @@ function clearActiveSpan(flowCtx) {
1261
1301
  } catch {
1262
1302
  }
1263
1303
  }
1304
+ function beginFlowSpan(flowCtx, options, span, spanCtx) {
1305
+ flowCtx.state[SPAN_KEY] = span;
1306
+ flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1307
+ flowCtx.state[STAGE_TS_KEY] = Date.now();
1308
+ flowCtx.state[STAGE_EVENTS_KEY] = options.flowStageEvents !== false;
1309
+ }
1310
+ function parentContextOf(ctx) {
1311
+ return ctx.get?.(HTTP_SPAN_CTX_KEY) ?? createOTelContextFromTrace(ctx.traceContext);
1312
+ }
1313
+ function flowFailureOf(flowError) {
1314
+ const failed = flowError?.originalError;
1315
+ const error = flowError instanceof import_sdk2.FlowControl ? failed instanceof Error ? failed : new import_sdk2.InternalMcpError(`Flow ended with: ${flowError.type}`) : flowError instanceof Error ? flowError : new Error(String(flowError));
1316
+ const reported = (0, import_sdk2.toMcpError)(error);
1317
+ return {
1318
+ error,
1319
+ type: reported.name,
1320
+ message: reported.getPublicMessage(),
1321
+ code: reported.code,
1322
+ errorId: reported.errorId
1323
+ };
1324
+ }
1325
+ function endFailedSpan(span, flowError) {
1326
+ const failure = flowFailureOf(flowError);
1327
+ span.setStatus({ code: import_api13.SpanStatusCode.ERROR, message: failure.message });
1328
+ span.recordException({
1329
+ name: failure.type,
1330
+ message: failure.message,
1331
+ code: failure.code,
1332
+ stack: failure.error.stack
1333
+ });
1334
+ span.end();
1335
+ }
1336
+ function traceparentOf(span) {
1337
+ const { traceId, spanId, traceFlags } = span.spanContext();
1338
+ return `00-${traceId}-${spanId}-${traceFlags.toString(16).padStart(2, "0")}`;
1339
+ }
1264
1340
  function recordStageEvent(span, stageName, state) {
1341
+ if (state[STAGE_EVENTS_KEY] === false) return;
1265
1342
  const now = Date.now();
1266
1343
  const prev = state[STAGE_TS_KEY];
1267
1344
  const attributes = {};
@@ -1287,9 +1364,8 @@ function onHttpWillTrace(options, flowCtx) {
1287
1364
  });
1288
1365
  span.setAttribute(McpAttributes.SESSION_ID, sessionHash);
1289
1366
  span.setAttribute(FrontMcpAttributes.SESSION_ID_HASH, sessionHash);
1290
- flowCtx.state[SPAN_KEY] = span;
1291
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1292
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1367
+ ctx.set?.(HTTP_SPAN_CTX_KEY, spanCtx);
1368
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1293
1369
  recordStageEvent(span, "traceRequest", flowCtx.state);
1294
1370
  }
1295
1371
  function onHttpWillAcquireQuota(flowCtx) {
@@ -1333,7 +1409,7 @@ function onToolWillParse(options, flowCtx) {
1333
1409
  const ctx = extractContext(flowCtx);
1334
1410
  if (!ctx) return;
1335
1411
  const tracer = getTracer();
1336
- const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
1412
+ const parentOTelCtx = parentContextOf(ctx);
1337
1413
  const sessionHash = sessionTracingId(ctx.sessionId);
1338
1414
  const { span, context: spanCtx } = startRpcSpan(tracer, {
1339
1415
  method: "tools/call",
@@ -1341,9 +1417,7 @@ function onToolWillParse(options, flowCtx) {
1341
1417
  sessionIdHash: sessionHash,
1342
1418
  parentContext: parentOTelCtx
1343
1419
  });
1344
- flowCtx.state[SPAN_KEY] = span;
1345
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1346
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1420
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1347
1421
  recordStageEvent(span, "parseInput", flowCtx.state);
1348
1422
  }
1349
1423
  function onToolWillFindTool(flowCtx) {
@@ -1413,8 +1487,8 @@ function onToolDidFinalize(flowCtx) {
1413
1487
  const toolSpan = flowCtx.state?.[EXEC_SPAN_KEY];
1414
1488
  const error = flowCtx.state?.flowError;
1415
1489
  if (error) {
1416
- if (toolSpan) endSpanError(toolSpan, error instanceof Error ? error : String(error));
1417
- if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
1490
+ if (toolSpan) endFailedSpan(toolSpan, error);
1491
+ if (rpcSpan) endFailedSpan(rpcSpan, error);
1418
1492
  } else if (rpcSpan) {
1419
1493
  recordStageEvent(rpcSpan, "finalize", flowCtx.state);
1420
1494
  endSpanOk(rpcSpan);
@@ -1425,7 +1499,7 @@ function onResourceWillParse(options, flowCtx) {
1425
1499
  const ctx = extractContext(flowCtx);
1426
1500
  if (!ctx) return;
1427
1501
  const tracer = getTracer();
1428
- const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
1502
+ const parentOTelCtx = parentContextOf(ctx);
1429
1503
  const sessionHash = sessionTracingId(ctx.sessionId);
1430
1504
  const { span, context: spanCtx } = startRpcSpan(tracer, {
1431
1505
  method: "resources/read",
@@ -1433,9 +1507,7 @@ function onResourceWillParse(options, flowCtx) {
1433
1507
  sessionIdHash: sessionHash,
1434
1508
  parentContext: parentOTelCtx
1435
1509
  });
1436
- flowCtx.state[SPAN_KEY] = span;
1437
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1438
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1510
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1439
1511
  recordStageEvent(span, "parseInput", flowCtx.state);
1440
1512
  }
1441
1513
  function onResourceWillFind(flowCtx) {
@@ -1466,8 +1538,8 @@ function onResourceDidFinalize(flowCtx) {
1466
1538
  const resSpan = flowCtx.state?.[EXEC_SPAN_KEY];
1467
1539
  const error = flowCtx.state?.flowError;
1468
1540
  if (error) {
1469
- if (resSpan) endSpanError(resSpan, error instanceof Error ? error : String(error));
1470
- if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
1541
+ if (resSpan) endFailedSpan(resSpan, error);
1542
+ if (rpcSpan) endFailedSpan(rpcSpan, error);
1471
1543
  } else if (rpcSpan) {
1472
1544
  recordStageEvent(rpcSpan, "finalize", flowCtx.state);
1473
1545
  endSpanOk(rpcSpan);
@@ -1478,7 +1550,7 @@ function onPromptWillParse(options, flowCtx) {
1478
1550
  const ctx = extractContext(flowCtx);
1479
1551
  if (!ctx) return;
1480
1552
  const tracer = getTracer();
1481
- const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
1553
+ const parentOTelCtx = parentContextOf(ctx);
1482
1554
  const sessionHash = sessionTracingId(ctx.sessionId);
1483
1555
  const { span, context: spanCtx } = startRpcSpan(tracer, {
1484
1556
  method: "prompts/get",
@@ -1486,9 +1558,7 @@ function onPromptWillParse(options, flowCtx) {
1486
1558
  sessionIdHash: sessionHash,
1487
1559
  parentContext: parentOTelCtx
1488
1560
  });
1489
- flowCtx.state[SPAN_KEY] = span;
1490
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1491
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1561
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1492
1562
  recordStageEvent(span, "parseInput", flowCtx.state);
1493
1563
  }
1494
1564
  function onPromptWillFind(flowCtx) {
@@ -1522,8 +1592,8 @@ function onPromptDidFinalize(flowCtx) {
1522
1592
  const promptSpan = flowCtx.state?.[EXEC_SPAN_KEY];
1523
1593
  const error = flowCtx.state?.flowError;
1524
1594
  if (error) {
1525
- if (promptSpan) endSpanError(promptSpan, error instanceof Error ? error : String(error));
1526
- if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
1595
+ if (promptSpan) endFailedSpan(promptSpan, error);
1596
+ if (rpcSpan) endFailedSpan(rpcSpan, error);
1527
1597
  } else if (rpcSpan) {
1528
1598
  recordStageEvent(rpcSpan, "finalize", flowCtx.state);
1529
1599
  endSpanOk(rpcSpan);
@@ -1534,7 +1604,7 @@ function onAgentWillParse(options, flowCtx) {
1534
1604
  const ctx = extractContext(flowCtx);
1535
1605
  if (!ctx) return;
1536
1606
  const tracer = getTracer();
1537
- const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
1607
+ const parentOTelCtx = parentContextOf(ctx);
1538
1608
  const sessionHash = sessionTracingId(ctx.sessionId);
1539
1609
  const { span, context: spanCtx } = startRpcSpan(tracer, {
1540
1610
  method: "agents/call",
@@ -1542,9 +1612,7 @@ function onAgentWillParse(options, flowCtx) {
1542
1612
  sessionIdHash: sessionHash,
1543
1613
  parentContext: parentOTelCtx
1544
1614
  });
1545
- flowCtx.state[SPAN_KEY] = span;
1546
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1547
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1615
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1548
1616
  recordStageEvent(span, "parseInput", flowCtx.state);
1549
1617
  }
1550
1618
  function onAgentWillFind(flowCtx) {
@@ -1558,7 +1626,7 @@ function onAgentWillExecute(options, flowCtx) {
1558
1626
  const agentName = flowCtx.state?.input?.name ?? "unknown";
1559
1627
  const { span: agentSpan } = startSpan(tracer, {
1560
1628
  name: `agent ${agentName}`,
1561
- kind: import_api12.SpanKind.INTERNAL,
1629
+ kind: import_api13.SpanKind.INTERNAL,
1562
1630
  attributes: {
1563
1631
  [FrontMcpAttributes.FLOW_NAME]: "agents:call-agent",
1564
1632
  [McpAttributes.COMPONENT_TYPE]: "agent",
@@ -1566,7 +1634,7 @@ function onAgentWillExecute(options, flowCtx) {
1566
1634
  },
1567
1635
  parentContext: rpcCtx
1568
1636
  });
1569
- const agentOTelCtx = import_api12.trace.setSpan(rpcCtx ?? import_api12.context.active(), agentSpan);
1637
+ const agentOTelCtx = import_api13.trace.setSpan(rpcCtx ?? import_api13.context.active(), agentSpan);
1570
1638
  flowCtx.state[EXEC_SPAN_KEY] = agentSpan;
1571
1639
  flowCtx.state[STAGE_TS_KEY] = Date.now();
1572
1640
  recordStageEvent(agentSpan, "execute.start", flowCtx.state);
@@ -1585,8 +1653,8 @@ function onAgentDidFinalize(flowCtx) {
1585
1653
  const agentSpan = flowCtx.state?.[EXEC_SPAN_KEY];
1586
1654
  const error = flowCtx.state?.flowError;
1587
1655
  if (error) {
1588
- if (agentSpan) endSpanError(agentSpan, error instanceof Error ? error : String(error));
1589
- if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
1656
+ if (agentSpan) endFailedSpan(agentSpan, error);
1657
+ if (rpcSpan) endFailedSpan(rpcSpan, error);
1590
1658
  } else if (rpcSpan) {
1591
1659
  recordStageEvent(rpcSpan, "finalize", flowCtx.state);
1592
1660
  endSpanOk(rpcSpan);
@@ -1597,11 +1665,11 @@ function onGenericFlowWillStart(flowName, options, flowCtx) {
1597
1665
  const ctx = extractContext(flowCtx);
1598
1666
  if (!ctx) return;
1599
1667
  const tracer = getTracer();
1600
- const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
1668
+ const parentOTelCtx = parentContextOf(ctx);
1601
1669
  const sessionHash = sessionTracingId(ctx.sessionId);
1602
1670
  const { span, context: spanCtx } = startSpan(tracer, {
1603
1671
  name: flowName,
1604
- kind: import_api12.SpanKind.INTERNAL,
1672
+ kind: import_api13.SpanKind.INTERNAL,
1605
1673
  attributes: {
1606
1674
  [FrontMcpAttributes.FLOW_NAME]: flowName,
1607
1675
  [McpAttributes.SESSION_ID]: sessionHash,
@@ -1611,9 +1679,7 @@ function onGenericFlowWillStart(flowName, options, flowCtx) {
1611
1679
  },
1612
1680
  parentContext: parentOTelCtx
1613
1681
  });
1614
- flowCtx.state[SPAN_KEY] = span;
1615
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1616
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1682
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1617
1683
  }
1618
1684
  function onGenericFlowStage(stageName, flowCtx) {
1619
1685
  const span = flowCtx.state?.[SPAN_KEY];
@@ -1624,7 +1690,7 @@ function onGenericFlowDidFinalize(flowCtx) {
1624
1690
  if (!span) return;
1625
1691
  const error = flowCtx.state?.flowError;
1626
1692
  if (error) {
1627
- endSpanError(span, error instanceof Error ? error : String(error));
1693
+ endFailedSpan(span, error);
1628
1694
  } else {
1629
1695
  endSpanOk(span);
1630
1696
  }
@@ -1634,16 +1700,14 @@ function onTransportWillStart(transportType, options, flowCtx) {
1634
1700
  const ctx = extractContext(flowCtx);
1635
1701
  if (!ctx) return;
1636
1702
  const tracer = getTracer();
1637
- const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
1703
+ const parentOTelCtx = parentContextOf(ctx);
1638
1704
  const sessionHash = sessionTracingId(ctx.sessionId);
1639
1705
  const { span, context: spanCtx } = startTransportSpan(tracer, {
1640
1706
  type: transportType,
1641
1707
  sessionIdHash: sessionHash,
1642
1708
  parentContext: parentOTelCtx
1643
1709
  });
1644
- flowCtx.state[SPAN_KEY] = span;
1645
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1646
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1710
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1647
1711
  recordStageEvent(span, "parseInput", flowCtx.state);
1648
1712
  }
1649
1713
  function onTransportDidRoute(flowCtx) {
@@ -1663,7 +1727,7 @@ function onTransportDidFinalize(flowCtx) {
1663
1727
  recordStageEvent(span, "cleanup", flowCtx.state);
1664
1728
  const error = flowCtx.state?.flowError;
1665
1729
  if (error) {
1666
- endSpanError(span, error instanceof Error ? error : String(error));
1730
+ endFailedSpan(span, error);
1667
1731
  } else {
1668
1732
  endSpanOk(span);
1669
1733
  }
@@ -1673,14 +1737,12 @@ function onAuthWillStart(flowName, options, flowCtx) {
1673
1737
  const ctx = extractContext(flowCtx);
1674
1738
  if (!ctx) return;
1675
1739
  const tracer = getTracer();
1676
- const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
1740
+ const parentOTelCtx = parentContextOf(ctx);
1677
1741
  const { span, context: spanCtx } = startAuthSpan(tracer, {
1678
1742
  flowName,
1679
1743
  parentContext: parentOTelCtx
1680
1744
  });
1681
- flowCtx.state[SPAN_KEY] = span;
1682
- flowCtx.state[SPAN_CTX_KEY] = spanCtx;
1683
- flowCtx.state[STAGE_TS_KEY] = Date.now();
1745
+ beginFlowSpan(flowCtx, options, span, spanCtx);
1684
1746
  recordStageEvent(span, "parseInput", flowCtx.state);
1685
1747
  }
1686
1748
  function onAuthDidDetermineMode(flowCtx) {
@@ -1700,30 +1762,35 @@ function onAuthDidFinalize(flowCtx) {
1700
1762
  const error = flowCtx.state?.flowError;
1701
1763
  if (error) {
1702
1764
  setAuthResult(span, "unauthorized");
1703
- endSpanError(span, error instanceof Error ? error : String(error));
1765
+ endFailedSpan(span, error);
1704
1766
  } else {
1705
1767
  setAuthResult(span, "authorized");
1706
1768
  endSpanOk(span);
1707
1769
  }
1708
1770
  }
1709
1771
  function wrapContextFetch(options, flowCtx) {
1710
- if (options.fetchSpans === false) return;
1711
1772
  const toolCtx = flowCtx.state?.toolContext ?? flowCtx.state?.toolCallContext;
1712
1773
  if (!toolCtx || typeof toolCtx.fetch !== "function") return;
1713
1774
  const originalFetch = toolCtx.fetch.bind(toolCtx);
1714
1775
  const parentOTelCtx = flowCtx.state?.[SPAN_CTX_KEY];
1715
1776
  toolCtx.fetch = async (input, init) => {
1716
- const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
1717
- const method = init?.method ?? "GET";
1718
- const tracer = getTracer();
1719
- const { span } = startFetchSpan(tracer, { method, url, parentContext: parentOTelCtx });
1777
+ const fetchSpan = options.fetchSpans === false ? void 0 : startFetchSpan(getTracer(), {
1778
+ method: init?.method ?? (input instanceof Request ? input.method : "GET"),
1779
+ url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
1780
+ parentContext: parentOTelCtx
1781
+ }).span;
1782
+ const callingSpan = fetchSpan ?? flowCtx.state?.[EXEC_SPAN_KEY] ?? flowCtx.state?.[SPAN_KEY];
1783
+ const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
1784
+ if (callingSpan && !headers.has("traceparent")) headers.set("traceparent", traceparentOf(callingSpan));
1720
1785
  try {
1721
- const response = await originalFetch(input, init);
1722
- setFetchResponseStatus(span, response.status);
1723
- endSpanOk(span);
1786
+ const response = await originalFetch(input, { ...init, headers });
1787
+ if (fetchSpan) {
1788
+ setFetchResponseStatus(fetchSpan, response.status);
1789
+ endSpanOk(fetchSpan);
1790
+ }
1724
1791
  return response;
1725
1792
  } catch (err) {
1726
- endSpanError(span, err instanceof Error ? err : String(err));
1793
+ if (fetchSpan) endSpanError(fetchSpan, err instanceof Error ? err : String(err));
1727
1794
  throw err;
1728
1795
  }
1729
1796
  };
@@ -1741,6 +1808,26 @@ function onAgentDidExecuteEnrich(flowCtx) {
1741
1808
  }
1742
1809
  }
1743
1810
  }
1811
+ var HOOK_OBSERVER_KEY = /* @__PURE__ */ Symbol.for("frontmcp:hook-observer");
1812
+ function installHookObserver(flowCtx, observer) {
1813
+ const ctx = extractContext(flowCtx);
1814
+ if (ctx && !ctx.get?.(HOOK_OBSERVER_KEY)) ctx.set?.(HOOK_OBSERVER_KEY, observer);
1815
+ }
1816
+ async function runInHookSpan(flowCtx, hook, run) {
1817
+ const ctx = extractContext(flowCtx);
1818
+ const { span } = startHookSpan(getTracer(), {
1819
+ ...hook,
1820
+ parentContext: flowCtx.state?.[SPAN_CTX_KEY] ?? (ctx && parentContextOf(ctx))
1821
+ });
1822
+ try {
1823
+ await run();
1824
+ endSpanOk(span);
1825
+ } catch (error) {
1826
+ if (error instanceof import_sdk2.FlowControl && error.type !== "fail" && error.type !== "abort") endSpanOk(span);
1827
+ else endFailedSpan(span, error);
1828
+ throw error;
1829
+ }
1830
+ }
1744
1831
  function reportStartup(data) {
1745
1832
  const tracer = getTracer();
1746
1833
  emitStartupReport(tracer, data);
@@ -1780,28 +1867,35 @@ function startRequestLog(flowCtx, options) {
1780
1867
  if (typeof rpcMethod === "string") collector.setRpcMethod(rpcMethod);
1781
1868
  }
1782
1869
  function recordRequestLogFailure(flowCtx) {
1783
- const failure = flowCtx.state?.["flowError"];
1784
- if (!failure) return;
1785
- const error = failure instanceof Error ? failure : new Error(String(failure));
1786
- currentRequestLog(flowCtx)?.setError({
1787
- type: error.name,
1788
- message: error.message,
1789
- code: error.code
1790
- });
1870
+ const flowError = flowCtx.state?.["flowError"];
1871
+ if (!flowError) return;
1872
+ const { type, message, code, errorId } = flowFailureOf(flowError);
1873
+ currentRequestLog(flowCtx)?.setError({ type, message, code, error_id: errorId });
1874
+ }
1875
+ function recordRequestLogAuth(flowCtx) {
1876
+ const verifyResult = flowCtx.state?.["verifyResult"];
1877
+ const authorization = flowCtx.rawInput?.request?.headers?.["authorization"];
1878
+ const scheme = typeof authorization === "string" ? authorization.trim().split(/\s+/)[0].toLowerCase() : "";
1879
+ const sub = verifyResult?.authorization?.user?.sub;
1880
+ const anonymous = typeof sub !== "string" || (0, import_sdk3.isAnonymousSubject)(sub);
1881
+ currentRequestLog(flowCtx)?.setAuthInfo(
1882
+ anonymous || !scheme ? "anonymous" : scheme,
1883
+ verifyResult?.kind === "authorized" && !anonymous
1884
+ );
1791
1885
  }
1792
1886
  async function completeRequestLog(flowCtx) {
1793
1887
  const collector = currentRequestLog(flowCtx);
1794
1888
  if (!collector || collector.isFinalized()) return;
1795
1889
  const statusCode = flowCtx.state?.["statusCode"] ?? flowCtx.rawInput?.response?.statusCode;
1796
- if (typeof statusCode === "number" && statusCode >= 400) collector.setStatus("error", statusCode);
1890
+ if (typeof statusCode === "number") collector.setStatusCode(statusCode);
1797
1891
  await collector.finalize();
1798
1892
  }
1799
1893
 
1800
1894
  // libs/observability/src/telemetry/telemetry.accessor.ts
1801
- var import_api14 = require("@opentelemetry/api");
1895
+ var import_api15 = require("@opentelemetry/api");
1802
1896
 
1803
1897
  // libs/observability/src/telemetry/telemetry.counters.ts
1804
- var import_api13 = require("@opentelemetry/api");
1898
+ var import_api14 = require("@opentelemetry/api");
1805
1899
  function snapshotKey(name, attributes) {
1806
1900
  const keys = Object.keys(attributes).sort();
1807
1901
  if (keys.length === 0) return name;
@@ -1836,7 +1930,7 @@ var counterCache = /* @__PURE__ */ new Map();
1836
1930
  function createCounter(name, description) {
1837
1931
  const existing = counterCache.get(name);
1838
1932
  if (existing) return existing;
1839
- const meter = import_api13.metrics.getMeter(METER_NAME);
1933
+ const meter = import_api14.metrics.getMeter(METER_NAME);
1840
1934
  const otelCounter = meter.createCounter(name, description ? { description } : void 0);
1841
1935
  const counter = new TelemetryCounterImpl(name, otelCounter);
1842
1936
  counterCache.set(name, counter);
@@ -1915,14 +2009,14 @@ var TelemetrySpan = class {
1915
2009
  /** Record an error on this span */
1916
2010
  recordError(error) {
1917
2011
  this.span.recordException(error);
1918
- this.span.setStatus({ code: import_api14.SpanStatusCode.ERROR, message: error.message });
2012
+ this.span.setStatus({ code: import_api15.SpanStatusCode.ERROR, message: error.message });
1919
2013
  this.hasError = true;
1920
2014
  return this;
1921
2015
  }
1922
2016
  /** End the span (preserves ERROR status if already set) */
1923
2017
  end() {
1924
2018
  if (!this.hasError) {
1925
- this.span.setStatus({ code: import_api14.SpanStatusCode.OK });
2019
+ this.span.setStatus({ code: import_api15.SpanStatusCode.OK });
1926
2020
  }
1927
2021
  this.span.end();
1928
2022
  }
@@ -1930,7 +2024,7 @@ var TelemetrySpan = class {
1930
2024
  endWithError(error) {
1931
2025
  const msg = typeof error === "string" ? error : error.message;
1932
2026
  if (error instanceof Error) this.span.recordException(error);
1933
- this.span.setStatus({ code: import_api14.SpanStatusCode.ERROR, message: msg });
2027
+ this.span.setStatus({ code: import_api15.SpanStatusCode.ERROR, message: msg });
1934
2028
  this.span.end();
1935
2029
  }
1936
2030
  /** Get the underlying OTel span (escape hatch) */
@@ -1941,7 +2035,7 @@ var TelemetrySpan = class {
1941
2035
  var TelemetryAccessor = class {
1942
2036
  constructor(ctx) {
1943
2037
  this.ctx = ctx;
1944
- this.tracer = import_api14.trace.getTracer("@frontmcp/observability");
2038
+ this.tracer = import_api15.trace.getTracer("@frontmcp/observability");
1945
2039
  this.fallbackContext = createOTelContextFromTrace(ctx.traceContext);
1946
2040
  this.sessionHash = sessionTracingId(ctx.sessionId);
1947
2041
  this.baseAttributes = {
@@ -1977,7 +2071,7 @@ var TelemetryAccessor = class {
1977
2071
  const span = this.tracer.startSpan(
1978
2072
  name,
1979
2073
  {
1980
- kind: import_api14.SpanKind.INTERNAL,
2074
+ kind: import_api15.SpanKind.INTERNAL,
1981
2075
  attributes: { ...this.baseAttributes, ...attributes }
1982
2076
  },
1983
2077
  this.getActiveContext()
@@ -2026,11 +2120,11 @@ var TelemetryAccessor = class {
2026
2120
  } else {
2027
2121
  const span = this.tracer.startSpan(
2028
2122
  name,
2029
- { kind: import_api14.SpanKind.INTERNAL, attributes: this.baseAttributes },
2123
+ { kind: import_api15.SpanKind.INTERNAL, attributes: this.baseAttributes },
2030
2124
  this.fallbackContext
2031
2125
  );
2032
2126
  if (attributes) span.addEvent(name, attributes);
2033
- span.setStatus({ code: import_api14.SpanStatusCode.OK });
2127
+ span.setStatus({ code: import_api15.SpanStatusCode.OK });
2034
2128
  span.end();
2035
2129
  }
2036
2130
  }
@@ -2067,7 +2161,7 @@ var TelemetryAccessor = class {
2067
2161
  * Useful for including in external API calls or logs.
2068
2162
  */
2069
2163
  get traceId() {
2070
- return import_api14.trace.getSpan(this.fallbackContext)?.spanContext().traceId ?? "";
2164
+ return import_api15.trace.getSpan(this.fallbackContext)?.spanContext().traceId ?? "";
2071
2165
  }
2072
2166
  /**
2073
2167
  * Get the session tracing ID (privacy-safe hash).
@@ -2078,10 +2172,10 @@ var TelemetryAccessor = class {
2078
2172
  };
2079
2173
 
2080
2174
  // libs/observability/src/telemetry/telemetry.factory.ts
2081
- var import_api15 = require("@opentelemetry/api");
2175
+ var import_api16 = require("@opentelemetry/api");
2082
2176
  var TelemetryFactory = class {
2083
2177
  constructor(tracerName = "@frontmcp/observability") {
2084
- this.tracer = import_api15.trace.getTracer(tracerName);
2178
+ this.tracer = import_api16.trace.getTracer(tracerName);
2085
2179
  }
2086
2180
  /**
2087
2181
  * Create (or retrieve cached) a named counter. Increments propagate to
@@ -2128,32 +2222,32 @@ var TELEMETRY_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:observability:tele
2128
2222
  var TELEMETRY_FACTORY = /* @__PURE__ */ Symbol.for("frontmcp:observability:telemetry-factory");
2129
2223
 
2130
2224
  // libs/observability/src/plugin/observability.plugin.ts
2131
- var PromptHook = (0, import_sdk2.FlowHooksOf)("prompts:get-prompt");
2132
- var ListPromptsHook = (0, import_sdk2.FlowHooksOf)("prompts:list-prompts");
2133
- var SkillSearchHook = (0, import_sdk2.FlowHooksOf)("skills:search");
2134
- var SkillLoadHook = (0, import_sdk2.FlowHooksOf)("skills:load");
2135
- var CompletionHook = (0, import_sdk2.FlowHooksOf)("completion:complete");
2136
- var LegacySseHook = (0, import_sdk2.FlowHooksOf)("handle:legacy-sse");
2137
- var StreamableHttpHook = (0, import_sdk2.FlowHooksOf)("handle:streamable-http");
2138
- var StatelessHttpHook = (0, import_sdk2.FlowHooksOf)("handle:stateless-http");
2139
- var AuthVerifyHook = (0, import_sdk2.FlowHooksOf)("auth:verify");
2140
- var SessionVerifyHook = (0, import_sdk2.FlowHooksOf)("session:verify");
2141
- var OAuthTokenHook = (0, import_sdk2.FlowHooksOf)("oauth:token");
2142
- var OAuthAuthorizeHook = (0, import_sdk2.FlowHooksOf)("oauth:authorize");
2143
- var OAuthCallbackHook = (0, import_sdk2.FlowHooksOf)("oauth:callback");
2144
- var OAuthProviderCallbackHook = (0, import_sdk2.FlowHooksOf)("oauth:provider-callback");
2145
- var OAuthRegisterHook = (0, import_sdk2.FlowHooksOf)("oauth:register");
2146
- var ElicitRequestHook = (0, import_sdk2.FlowHooksOf)("elicitation:request");
2147
- var ElicitResultHook = (0, import_sdk2.FlowHooksOf)("elicitation:result");
2148
- var SubscribeResourceHook = (0, import_sdk2.FlowHooksOf)("resources:subscribe");
2149
- var UnsubscribeResourceHook = (0, import_sdk2.FlowHooksOf)("resources:unsubscribe");
2150
- var SkillsHttpLlmTxtHook = (0, import_sdk2.FlowHooksOf)("skills-http:llm-txt");
2151
- var SkillsHttpLlmFullTxtHook = (0, import_sdk2.FlowHooksOf)("skills-http:llm-full-txt");
2152
- var SkillsHttpApiHook = (0, import_sdk2.FlowHooksOf)("skills-http:api");
2153
- var WellKnownJwksHook = (0, import_sdk2.FlowHooksOf)("well-known.jwks");
2154
- var WellKnownOAuthServerHook = (0, import_sdk2.FlowHooksOf)("well-known.oauth-authorization-server");
2155
- var WellKnownPrmHook = (0, import_sdk2.FlowHooksOf)("well-known.prm");
2156
- var LoggingSetLevelHook = (0, import_sdk2.FlowHooksOf)("logging:set-level");
2225
+ var PromptHook = (0, import_sdk4.FlowHooksOf)("prompts:get-prompt");
2226
+ var ListPromptsHook = (0, import_sdk4.FlowHooksOf)("prompts:list-prompts");
2227
+ var SkillSearchHook = (0, import_sdk4.FlowHooksOf)("skills:search");
2228
+ var SkillLoadHook = (0, import_sdk4.FlowHooksOf)("skills:load");
2229
+ var CompletionHook = (0, import_sdk4.FlowHooksOf)("completion:complete");
2230
+ var LegacySseHook = (0, import_sdk4.FlowHooksOf)("handle:legacy-sse");
2231
+ var StreamableHttpHook = (0, import_sdk4.FlowHooksOf)("handle:streamable-http");
2232
+ var StatelessHttpHook = (0, import_sdk4.FlowHooksOf)("handle:stateless-http");
2233
+ var AuthVerifyHook = (0, import_sdk4.FlowHooksOf)("auth:verify");
2234
+ var SessionVerifyHook = (0, import_sdk4.FlowHooksOf)("session:verify");
2235
+ var OAuthTokenHook = (0, import_sdk4.FlowHooksOf)("oauth:token");
2236
+ var OAuthAuthorizeHook = (0, import_sdk4.FlowHooksOf)("oauth:authorize");
2237
+ var OAuthCallbackHook = (0, import_sdk4.FlowHooksOf)("oauth:callback");
2238
+ var OAuthProviderCallbackHook = (0, import_sdk4.FlowHooksOf)("oauth:provider-callback");
2239
+ var OAuthRegisterHook = (0, import_sdk4.FlowHooksOf)("oauth:register");
2240
+ var ElicitRequestHook = (0, import_sdk4.FlowHooksOf)("elicitation:request");
2241
+ var ElicitResultHook = (0, import_sdk4.FlowHooksOf)("elicitation:result");
2242
+ var SubscribeResourceHook = (0, import_sdk4.FlowHooksOf)("resources:subscribe");
2243
+ var UnsubscribeResourceHook = (0, import_sdk4.FlowHooksOf)("resources:unsubscribe");
2244
+ var SkillsHttpLlmTxtHook = (0, import_sdk4.FlowHooksOf)("skills-http:llm-txt");
2245
+ var SkillsHttpLlmFullTxtHook = (0, import_sdk4.FlowHooksOf)("skills-http:llm-full-txt");
2246
+ var SkillsHttpApiHook = (0, import_sdk4.FlowHooksOf)("skills-http:api");
2247
+ var WellKnownJwksHook = (0, import_sdk4.FlowHooksOf)("well-known.jwks");
2248
+ var WellKnownOAuthServerHook = (0, import_sdk4.FlowHooksOf)("well-known.oauth-authorization-server");
2249
+ var WellKnownPrmHook = (0, import_sdk4.FlowHooksOf)("well-known.prm");
2250
+ var LoggingSetLevelHook = (0, import_sdk4.FlowHooksOf)("logging:set-level");
2157
2251
  var DEFAULT_TRACING = {
2158
2252
  httpSpans: true,
2159
2253
  executionSpans: true,
@@ -2166,9 +2260,17 @@ var DEFAULT_TRACING = {
2166
2260
  elicitationSpans: true,
2167
2261
  startupReport: true
2168
2262
  };
2169
- var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2263
+ var ObservabilityPlugin = class extends import_sdk4.DynamicPlugin {
2170
2264
  constructor(options = {}) {
2171
2265
  super();
2266
+ /** Wraps each other hook the request runs: names it on the request's log, and gives it a span with `hookSpans`. */
2267
+ this.observeHook = async ({ flowName, stage, target, flowContext }, run) => {
2268
+ if (target === this) return run();
2269
+ if (this.requestLogsEnabled) currentRequestLog(flowContext)?.addHook(`${flowName}:${stage}`);
2270
+ if (!this.traces("hookSpans")) return run();
2271
+ const owner = target?.constructor?.name;
2272
+ return runInHookSpan(flowContext, { flowName, stage, owner }, run);
2273
+ };
2172
2274
  this.options = resolveOptions(options);
2173
2275
  this.tracingOpts = this.options.tracing !== false ? this.options.tracing : DEFAULT_TRACING;
2174
2276
  }
@@ -2178,6 +2280,15 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2178
2280
  get requestLogsEnabled() {
2179
2281
  return this.options.requestLogs !== false;
2180
2282
  }
2283
+ /** Whether tracing is on and its `kind` option isn't off. */
2284
+ traces(kind) {
2285
+ return this.tracingEnabled && this.tracingOpts[kind] !== false;
2286
+ }
2287
+ /** Watches the hooks of the request `ctx` serves, from the first flow of it that this plugin sees. */
2288
+ watchHooks(ctx) {
2289
+ if (this.requestLogsEnabled || this.traces("hookSpans"))
2290
+ installHookObserver(ctx, this.observeHook);
2291
+ }
2181
2292
  /** Names the entry a request serves on its request log, and records the entry flow's failure. */
2182
2293
  annotateRequestLog(ctx, set) {
2183
2294
  if (!this.requestLogsEnabled) return;
@@ -2188,6 +2299,7 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2188
2299
  _httpWillTrace(ctx) {
2189
2300
  if (this.tracingEnabled) onHttpWillTrace(this.tracingOpts, ctx);
2190
2301
  if (this.options.requestLogs !== false) startRequestLog(ctx, this.options.requestLogs);
2302
+ this.watchHooks(ctx);
2191
2303
  }
2192
2304
  _httpWillQuota(ctx) {
2193
2305
  if (this.tracingEnabled) onHttpWillAcquireQuota(ctx);
@@ -2200,6 +2312,7 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2200
2312
  }
2201
2313
  _httpDidAuth(ctx) {
2202
2314
  if (this.tracingEnabled) onHttpDidCheckAuth(ctx);
2315
+ if (this.requestLogsEnabled) recordRequestLogAuth(ctx);
2203
2316
  }
2204
2317
  _httpWillRoute(ctx) {
2205
2318
  if (this.tracingEnabled) onHttpWillRoute(ctx);
@@ -2212,6 +2325,7 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2212
2325
  if (this.requestLogsEnabled) void completeRequestLog(ctx);
2213
2326
  }
2214
2327
  _toolWillParse(ctx) {
2328
+ this.watchHooks(ctx);
2215
2329
  if (this.tracingEnabled) onToolWillParse(this.tracingOpts, ctx);
2216
2330
  }
2217
2331
  _toolWillFind(ctx) {
@@ -2250,6 +2364,7 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2250
2364
  if (this.requestLogsEnabled) recordRequestLogFailure(ctx);
2251
2365
  }
2252
2366
  _resourceWillParse(ctx) {
2367
+ this.watchHooks(ctx);
2253
2368
  if (this.tracingEnabled) onResourceWillParse(this.tracingOpts, ctx);
2254
2369
  }
2255
2370
  _resourceWillFind(ctx) {
@@ -2273,6 +2388,7 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2273
2388
  if (this.requestLogsEnabled) recordRequestLogFailure(ctx);
2274
2389
  }
2275
2390
  _promptWillParse(ctx) {
2391
+ this.watchHooks(ctx);
2276
2392
  if (this.tracingEnabled) onPromptWillParse(this.tracingOpts, ctx);
2277
2393
  }
2278
2394
  _promptWillFind(ctx) {
@@ -2296,6 +2412,7 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2296
2412
  if (this.requestLogsEnabled) recordRequestLogFailure(ctx);
2297
2413
  }
2298
2414
  _agentWillParse(ctx) {
2415
+ this.watchHooks(ctx);
2299
2416
  if (this.tracingEnabled) onAgentWillParse(this.tracingOpts, ctx);
2300
2417
  }
2301
2418
  _agentWillFind(ctx) {
@@ -2449,46 +2566,46 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2449
2566
  if (this.tracingEnabled) onAuthDidFinalize(ctx);
2450
2567
  }
2451
2568
  _oauthTokenWill(ctx) {
2452
- if (this.tracingEnabled) onGenericFlowWillStart("oauth/token", this.tracingOpts, ctx);
2569
+ if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/token", this.tracingOpts, ctx);
2453
2570
  }
2454
2571
  _oauthTokenDone(ctx) {
2455
- if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2572
+ if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
2456
2573
  }
2457
2574
  _oauthAuthzWill(ctx) {
2458
- if (this.tracingEnabled) onGenericFlowWillStart("oauth/authorize", this.tracingOpts, ctx);
2575
+ if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/authorize", this.tracingOpts, ctx);
2459
2576
  }
2460
2577
  _oauthAuthzDone(ctx) {
2461
- if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2578
+ if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
2462
2579
  }
2463
2580
  _oauthCallbackWill(ctx) {
2464
- if (this.tracingEnabled) onGenericFlowWillStart("oauth/callback", this.tracingOpts, ctx);
2581
+ if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/callback", this.tracingOpts, ctx);
2465
2582
  }
2466
2583
  _oauthCallbackDone(ctx) {
2467
- if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2584
+ if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
2468
2585
  }
2469
2586
  _oauthProviderWill(ctx) {
2470
- if (this.tracingEnabled) onGenericFlowWillStart("oauth/provider-callback", this.tracingOpts, ctx);
2587
+ if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/provider-callback", this.tracingOpts, ctx);
2471
2588
  }
2472
2589
  _oauthProviderDone(ctx) {
2473
- if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2590
+ if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
2474
2591
  }
2475
2592
  _oauthRegisterWill(ctx) {
2476
- if (this.tracingEnabled) onGenericFlowWillStart("oauth/register", this.tracingOpts, ctx);
2593
+ if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/register", this.tracingOpts, ctx);
2477
2594
  }
2478
2595
  _oauthRegisterDone(ctx) {
2479
- if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2596
+ if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
2480
2597
  }
2481
2598
  _elicitReqWill(ctx) {
2482
- if (this.tracingEnabled) onGenericFlowWillStart("elicitation/request", this.tracingOpts, ctx);
2599
+ if (this.traces("elicitationSpans")) onGenericFlowWillStart("elicitation/request", this.tracingOpts, ctx);
2483
2600
  }
2484
2601
  _elicitReqDone(ctx) {
2485
- if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2602
+ if (this.traces("elicitationSpans")) onGenericFlowDidFinalize(ctx);
2486
2603
  }
2487
2604
  _elicitResWill(ctx) {
2488
- if (this.tracingEnabled) onGenericFlowWillStart("elicitation/result", this.tracingOpts, ctx);
2605
+ if (this.traces("elicitationSpans")) onGenericFlowWillStart("elicitation/result", this.tracingOpts, ctx);
2489
2606
  }
2490
2607
  _elicitResDone(ctx) {
2491
- if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2608
+ if (this.traces("elicitationSpans")) onGenericFlowDidFinalize(ctx);
2492
2609
  }
2493
2610
  _subscribeWill(ctx) {
2494
2611
  if (this.tracingEnabled) onGenericFlowWillStart("resources/subscribe", this.tracingOpts, ctx);
@@ -2554,12 +2671,10 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
2554
2671
  // Startup Report (public method)
2555
2672
  // ═══════════════════════════════════════════════════════════════════════════
2556
2673
  /**
2557
- * Emit startup telemetry report.
2558
- * Call after scope.initialize() completes with component counts.
2674
+ * Emit the `frontmcp.startup` span (`tracing.startupReport`). The scope calls it once it is ready.
2559
2675
  */
2560
2676
  reportStartupTelemetry(data) {
2561
- if (this.options.tracing === false) return;
2562
- reportStartup(data);
2677
+ if (this.traces("startupReport")) reportStartup(data);
2563
2678
  }
2564
2679
  };
2565
2680
  ObservabilityPlugin.defaultOptions = {
@@ -2577,7 +2692,7 @@ ObservabilityPlugin.dynamicProviders = (input) => {
2577
2692
  providers.push({
2578
2693
  name: "observability:tracer",
2579
2694
  provide: OTEL_TRACER,
2580
- useValue: import_api16.trace.getTracer("@frontmcp/observability")
2695
+ useValue: import_api17.trace.getTracer("@frontmcp/observability")
2581
2696
  });
2582
2697
  providers.push({
2583
2698
  name: "observability:config",
@@ -2587,8 +2702,8 @@ ObservabilityPlugin.dynamicProviders = (input) => {
2587
2702
  providers.push({
2588
2703
  name: "observability:telemetry-accessor",
2589
2704
  provide: TELEMETRY_ACCESSOR,
2590
- scope: import_sdk2.ProviderScope.CONTEXT,
2591
- inject: () => [import_sdk2.FRONTMCP_CONTEXT],
2705
+ scope: import_sdk4.ProviderScope.CONTEXT,
2706
+ inject: () => [import_sdk4.FRONTMCP_CONTEXT],
2592
2707
  useFactory: (ctx) => new TelemetryAccessor(ctx)
2593
2708
  });
2594
2709
  providers.push({
@@ -2620,8 +2735,8 @@ ObservabilityPlugin.dynamicProviders = (input) => {
2620
2735
  providers.push({
2621
2736
  name: "observability:request-log-collector",
2622
2737
  provide: REQUEST_LOG_COLLECTOR,
2623
- scope: import_sdk2.ProviderScope.CONTEXT,
2624
- inject: () => [import_sdk2.FRONTMCP_CONTEXT],
2738
+ scope: import_sdk4.ProviderScope.CONTEXT,
2739
+ inject: () => [import_sdk4.FRONTMCP_CONTEXT],
2625
2740
  useFactory: (ctx) => {
2626
2741
  return new RequestLogCollector(
2627
2742
  {
@@ -2638,85 +2753,85 @@ ObservabilityPlugin.dynamicProviders = (input) => {
2638
2753
  return providers;
2639
2754
  };
2640
2755
  __decorateClass([
2641
- import_sdk2.HttpHook.Will("traceRequest", { priority: -1e3 })
2756
+ import_sdk4.HttpHook.Will("traceRequest", { priority: -1e3 })
2642
2757
  ], ObservabilityPlugin.prototype, "_httpWillTrace", 1);
2643
2758
  __decorateClass([
2644
- import_sdk2.HttpHook.Will("acquireQuota", { priority: -1e3 })
2759
+ import_sdk4.HttpHook.Will("acquireQuota", { priority: -1e3 })
2645
2760
  ], ObservabilityPlugin.prototype, "_httpWillQuota", 1);
2646
2761
  __decorateClass([
2647
- import_sdk2.HttpHook.Did("acquireSemaphore", { priority: 1e3 })
2762
+ import_sdk4.HttpHook.Did("acquireSemaphore", { priority: 1e3 })
2648
2763
  ], ObservabilityPlugin.prototype, "_httpDidSemaphore", 1);
2649
2764
  __decorateClass([
2650
- import_sdk2.HttpHook.Will("checkAuthorization", { priority: -1e3 })
2765
+ import_sdk4.HttpHook.Will("checkAuthorization", { priority: -1e3 })
2651
2766
  ], ObservabilityPlugin.prototype, "_httpWillAuth", 1);
2652
2767
  __decorateClass([
2653
- import_sdk2.HttpHook.Did("checkAuthorization", { priority: 1e3 })
2768
+ import_sdk4.HttpHook.Did("checkAuthorization", { priority: 1e3 })
2654
2769
  ], ObservabilityPlugin.prototype, "_httpDidAuth", 1);
2655
2770
  __decorateClass([
2656
- import_sdk2.HttpHook.Will("router", { priority: -1e3 })
2771
+ import_sdk4.HttpHook.Will("router", { priority: -1e3 })
2657
2772
  ], ObservabilityPlugin.prototype, "_httpWillRoute", 1);
2658
2773
  __decorateClass([
2659
- import_sdk2.HttpHook.Did("router", { priority: 1e3 })
2774
+ import_sdk4.HttpHook.Did("router", { priority: 1e3 })
2660
2775
  ], ObservabilityPlugin.prototype, "_httpDidRoute", 1);
2661
2776
  __decorateClass([
2662
- import_sdk2.HttpHook.Did("finalize", { priority: 1e3 })
2777
+ import_sdk4.HttpHook.Did("finalize", { priority: 1e3 })
2663
2778
  ], ObservabilityPlugin.prototype, "_httpDidFinalize", 1);
2664
2779
  __decorateClass([
2665
- import_sdk2.ToolHook.Will("parseInput", { priority: -1e3 })
2780
+ import_sdk4.ToolHook.Will("parseInput", { priority: -1e3 })
2666
2781
  ], ObservabilityPlugin.prototype, "_toolWillParse", 1);
2667
2782
  __decorateClass([
2668
- import_sdk2.ToolHook.Will("findTool", { priority: -1e3 })
2783
+ import_sdk4.ToolHook.Will("findTool", { priority: -1e3 })
2669
2784
  ], ObservabilityPlugin.prototype, "_toolWillFind", 1);
2670
2785
  __decorateClass([
2671
- import_sdk2.ToolHook.Will("checkToolAuthorization", { priority: -1e3 })
2786
+ import_sdk4.ToolHook.Will("checkToolAuthorization", { priority: -1e3 })
2672
2787
  ], ObservabilityPlugin.prototype, "_toolWillCheckAuth", 1);
2673
2788
  __decorateClass([
2674
- import_sdk2.ToolHook.Will("checkEntryAuthorities", { priority: -1e3 })
2789
+ import_sdk4.ToolHook.Will("checkEntryAuthorities", { priority: -1e3 })
2675
2790
  ], ObservabilityPlugin.prototype, "_toolWillCheckAuthorities", 1);
2676
2791
  __decorateClass([
2677
- import_sdk2.ToolHook.Did("checkEntryAuthorities", { priority: 1e3 })
2792
+ import_sdk4.ToolHook.Did("checkEntryAuthorities", { priority: 1e3 })
2678
2793
  ], ObservabilityPlugin.prototype, "_toolDidCheckAuthorities", 1);
2679
2794
  __decorateClass([
2680
- import_sdk2.ToolHook.Will("createToolCallContext", { priority: -1e3 })
2795
+ import_sdk4.ToolHook.Will("createToolCallContext", { priority: -1e3 })
2681
2796
  ], ObservabilityPlugin.prototype, "_toolWillCreateCtx", 1);
2682
2797
  __decorateClass([
2683
- import_sdk2.ToolHook.Will("validateInput", { priority: -1e3 })
2798
+ import_sdk4.ToolHook.Will("validateInput", { priority: -1e3 })
2684
2799
  ], ObservabilityPlugin.prototype, "_toolWillValidate", 1);
2685
2800
  __decorateClass([
2686
- import_sdk2.ToolHook.Will("execute", { priority: -1e3 })
2801
+ import_sdk4.ToolHook.Will("execute", { priority: -1e3 })
2687
2802
  ], ObservabilityPlugin.prototype, "_toolWillExecute", 1);
2688
2803
  __decorateClass([
2689
- import_sdk2.ToolHook.Did("execute", { priority: 1e3 })
2804
+ import_sdk4.ToolHook.Did("execute", { priority: 1e3 })
2690
2805
  ], ObservabilityPlugin.prototype, "_toolDidExecute", 1);
2691
2806
  __decorateClass([
2692
- import_sdk2.ToolHook.Will("validateOutput", { priority: -1e3 })
2807
+ import_sdk4.ToolHook.Will("validateOutput", { priority: -1e3 })
2693
2808
  ], ObservabilityPlugin.prototype, "_toolWillValidateOut", 1);
2694
2809
  __decorateClass([
2695
- import_sdk2.ToolHook.Will("applyUI", { priority: -1e3 })
2810
+ import_sdk4.ToolHook.Will("applyUI", { priority: -1e3 })
2696
2811
  ], ObservabilityPlugin.prototype, "_toolWillApplyUI", 1);
2697
2812
  __decorateClass([
2698
- import_sdk2.ToolHook.Did("finalize", { priority: 1e3 })
2813
+ import_sdk4.ToolHook.Did("finalize", { priority: 1e3 })
2699
2814
  ], ObservabilityPlugin.prototype, "_toolDidFinalize", 1);
2700
2815
  __decorateClass([
2701
- import_sdk2.ResourceHook.Will("parseInput", { priority: -1e3 })
2816
+ import_sdk4.ResourceHook.Will("parseInput", { priority: -1e3 })
2702
2817
  ], ObservabilityPlugin.prototype, "_resourceWillParse", 1);
2703
2818
  __decorateClass([
2704
- import_sdk2.ResourceHook.Will("findResource", { priority: -1e3 })
2819
+ import_sdk4.ResourceHook.Will("findResource", { priority: -1e3 })
2705
2820
  ], ObservabilityPlugin.prototype, "_resourceWillFind", 1);
2706
2821
  __decorateClass([
2707
- import_sdk2.ResourceHook.Will("checkEntryAuthorities", { priority: -1e3 })
2822
+ import_sdk4.ResourceHook.Will("checkEntryAuthorities", { priority: -1e3 })
2708
2823
  ], ObservabilityPlugin.prototype, "_resourceWillCheckAuthorities", 1);
2709
2824
  __decorateClass([
2710
- import_sdk2.ResourceHook.Did("checkEntryAuthorities", { priority: 1e3 })
2825
+ import_sdk4.ResourceHook.Did("checkEntryAuthorities", { priority: 1e3 })
2711
2826
  ], ObservabilityPlugin.prototype, "_resourceDidCheckAuthorities", 1);
2712
2827
  __decorateClass([
2713
- import_sdk2.ResourceHook.Will("execute", { priority: -1e3 })
2828
+ import_sdk4.ResourceHook.Will("execute", { priority: -1e3 })
2714
2829
  ], ObservabilityPlugin.prototype, "_resourceWillExecute", 1);
2715
2830
  __decorateClass([
2716
- import_sdk2.ResourceHook.Did("execute", { priority: 1e3 })
2831
+ import_sdk4.ResourceHook.Did("execute", { priority: 1e3 })
2717
2832
  ], ObservabilityPlugin.prototype, "_resourceDidExecute", 1);
2718
2833
  __decorateClass([
2719
- import_sdk2.ResourceHook.Did("finalize", { priority: 1e3 })
2834
+ import_sdk4.ResourceHook.Did("finalize", { priority: 1e3 })
2720
2835
  ], ObservabilityPlugin.prototype, "_resourceDidFinalize", 1);
2721
2836
  __decorateClass([
2722
2837
  PromptHook.Will("parseInput", { priority: -1e3 })
@@ -2740,55 +2855,55 @@ __decorateClass([
2740
2855
  PromptHook.Did("finalize", { priority: 1e3 })
2741
2856
  ], ObservabilityPlugin.prototype, "_promptDidFinalize", 1);
2742
2857
  __decorateClass([
2743
- import_sdk2.AgentCallHook.Will("parseInput", { priority: -1e3 })
2858
+ import_sdk4.AgentCallHook.Will("parseInput", { priority: -1e3 })
2744
2859
  ], ObservabilityPlugin.prototype, "_agentWillParse", 1);
2745
2860
  __decorateClass([
2746
- import_sdk2.AgentCallHook.Will("findAgent", { priority: -1e3 })
2861
+ import_sdk4.AgentCallHook.Will("findAgent", { priority: -1e3 })
2747
2862
  ], ObservabilityPlugin.prototype, "_agentWillFind", 1);
2748
2863
  __decorateClass([
2749
- import_sdk2.AgentCallHook.Will("checkEntryAuthorities", { priority: -1e3 })
2864
+ import_sdk4.AgentCallHook.Will("checkEntryAuthorities", { priority: -1e3 })
2750
2865
  ], ObservabilityPlugin.prototype, "_agentWillCheckAuthorities", 1);
2751
2866
  __decorateClass([
2752
- import_sdk2.AgentCallHook.Did("checkEntryAuthorities", { priority: 1e3 })
2867
+ import_sdk4.AgentCallHook.Did("checkEntryAuthorities", { priority: 1e3 })
2753
2868
  ], ObservabilityPlugin.prototype, "_agentDidCheckAuthorities", 1);
2754
2869
  __decorateClass([
2755
- import_sdk2.AgentCallHook.Will("execute", { priority: -1e3 })
2870
+ import_sdk4.AgentCallHook.Will("execute", { priority: -1e3 })
2756
2871
  ], ObservabilityPlugin.prototype, "_agentWillExecute", 1);
2757
2872
  __decorateClass([
2758
- import_sdk2.AgentCallHook.Did("execute", { priority: 1e3 })
2873
+ import_sdk4.AgentCallHook.Did("execute", { priority: 1e3 })
2759
2874
  ], ObservabilityPlugin.prototype, "_agentDidExecute", 1);
2760
2875
  __decorateClass([
2761
- import_sdk2.AgentCallHook.Did("finalize", { priority: 1e3 })
2876
+ import_sdk4.AgentCallHook.Did("finalize", { priority: 1e3 })
2762
2877
  ], ObservabilityPlugin.prototype, "_agentDidFinalize", 1);
2763
2878
  __decorateClass([
2764
- import_sdk2.ListToolsHook.Will("parseInput", { priority: -1e3 })
2879
+ import_sdk4.ListToolsHook.Will("parseInput", { priority: -1e3 })
2765
2880
  ], ObservabilityPlugin.prototype, "_listToolsWill", 1);
2766
2881
  __decorateClass([
2767
- import_sdk2.ListToolsHook.Did("findTools", { priority: 1e3 })
2882
+ import_sdk4.ListToolsHook.Did("findTools", { priority: 1e3 })
2768
2883
  ], ObservabilityPlugin.prototype, "_listToolsDidFind", 1);
2769
2884
  __decorateClass([
2770
- import_sdk2.ListToolsHook.Did("filterByAuthorities", { priority: 1e3 })
2885
+ import_sdk4.ListToolsHook.Did("filterByAuthorities", { priority: 1e3 })
2771
2886
  ], ObservabilityPlugin.prototype, "_listToolsDidFilter", 1);
2772
2887
  __decorateClass([
2773
- import_sdk2.ListToolsHook.Did("parseTools", { priority: 1e3 })
2888
+ import_sdk4.ListToolsHook.Did("parseTools", { priority: 1e3 })
2774
2889
  ], ObservabilityPlugin.prototype, "_listToolsDone", 1);
2775
2890
  __decorateClass([
2776
- import_sdk2.ListResourcesHook.Will("parseInput", { priority: -1e3 })
2891
+ import_sdk4.ListResourcesHook.Will("parseInput", { priority: -1e3 })
2777
2892
  ], ObservabilityPlugin.prototype, "_listResourcesWill", 1);
2778
2893
  __decorateClass([
2779
- import_sdk2.ListResourcesHook.Did("filterByAuthorities", { priority: 1e3 })
2894
+ import_sdk4.ListResourcesHook.Did("filterByAuthorities", { priority: 1e3 })
2780
2895
  ], ObservabilityPlugin.prototype, "_listResourcesDidFilter", 1);
2781
2896
  __decorateClass([
2782
- import_sdk2.ListResourcesHook.Did("parseResources", { priority: 1e3 })
2897
+ import_sdk4.ListResourcesHook.Did("parseResources", { priority: 1e3 })
2783
2898
  ], ObservabilityPlugin.prototype, "_listResourcesDone", 1);
2784
2899
  __decorateClass([
2785
- import_sdk2.ListResourceTemplatesHook.Will("parseInput", { priority: -1e3 })
2900
+ import_sdk4.ListResourceTemplatesHook.Will("parseInput", { priority: -1e3 })
2786
2901
  ], ObservabilityPlugin.prototype, "_listTemplatesWill", 1);
2787
2902
  __decorateClass([
2788
- import_sdk2.ListResourceTemplatesHook.Did("filterByAuthorities", { priority: 1e3 })
2903
+ import_sdk4.ListResourceTemplatesHook.Did("filterByAuthorities", { priority: 1e3 })
2789
2904
  ], ObservabilityPlugin.prototype, "_listTemplatesDidFilter", 1);
2790
2905
  __decorateClass([
2791
- import_sdk2.ListResourceTemplatesHook.Did("parseTemplates", { priority: 1e3 })
2906
+ import_sdk4.ListResourceTemplatesHook.Did("parseTemplates", { priority: 1e3 })
2792
2907
  ], ObservabilityPlugin.prototype, "_listTemplatesDone", 1);
2793
2908
  __decorateClass([
2794
2909
  ListPromptsHook.Will("parseInput", { priority: -1e3 })
@@ -2989,13 +3104,13 @@ __decorateClass([
2989
3104
  LoggingSetLevelHook.Did("finalize", { priority: 1e3 })
2990
3105
  ], ObservabilityPlugin.prototype, "_setLevelDone", 1);
2991
3106
  __decorateClass([
2992
- import_sdk2.ToolHook.Did("createToolCallContext", { priority: 999 })
3107
+ import_sdk4.ToolHook.Did("createToolCallContext", { priority: 999 })
2993
3108
  ], ObservabilityPlugin.prototype, "_toolDidCreateCtxFetch", 1);
2994
3109
  __decorateClass([
2995
- import_sdk2.AgentCallHook.Did("execute", { priority: 999 })
3110
+ import_sdk4.AgentCallHook.Did("execute", { priority: 999 })
2996
3111
  ], ObservabilityPlugin.prototype, "_agentDidExecuteMeta", 1);
2997
3112
  ObservabilityPlugin = __decorateClass([
2998
- (0, import_sdk2.Plugin)({
3113
+ (0, import_sdk4.Plugin)({
2999
3114
  name: "observability",
3000
3115
  description: "Full-system OpenTelemetry instrumentation, structured logging, and request logs",
3001
3116
  providers: [],
@@ -3032,11 +3147,11 @@ function resolveRequestLogOptions(input) {
3032
3147
  }
3033
3148
 
3034
3149
  // libs/observability/src/otel/context-propagator.ts
3035
- var import_api17 = require("@opentelemetry/api");
3150
+ var import_api18 = require("@opentelemetry/api");
3036
3151
  var TRACEPARENT_HEADER = "traceparent";
3037
3152
  var FrontMcpPropagator = class {
3038
3153
  inject(context, carrier, setter) {
3039
- const span = import_api17.trace.getSpan(context);
3154
+ const span = import_api18.trace.getSpan(context);
3040
3155
  if (!span) return;
3041
3156
  const sc = span.spanContext();
3042
3157
  if (!sc || !isValidSpanContext(sc)) return;
@@ -3056,8 +3171,8 @@ var FrontMcpPropagator = class {
3056
3171
  traceFlags: parsed.traceFlags,
3057
3172
  isRemote: true
3058
3173
  };
3059
- const span = import_api17.trace.wrapSpanContext(spanContext);
3060
- return import_api17.trace.setSpan(context, span);
3174
+ const span = import_api18.trace.wrapSpanContext(spanContext);
3175
+ return import_api18.trace.setSpan(context, span);
3061
3176
  }
3062
3177
  fields() {
3063
3178
  return [TRACEPARENT_HEADER];
@@ -3124,33 +3239,6 @@ function setupOTel(options) {
3124
3239
  }
3125
3240
  }
3126
3241
 
3127
- // libs/observability/src/otel/spans/hook.span.ts
3128
- var import_api18 = require("@opentelemetry/api");
3129
- function recordHookEvent(parentSpan, stage, owner) {
3130
- const attributes = {};
3131
- if (owner) {
3132
- attributes[FrontMcpAttributes.HOOK_OWNER] = owner;
3133
- }
3134
- parentSpan.addEvent(`hook.${stage}`, attributes);
3135
- }
3136
- function startHookSpan(tracer, options) {
3137
- const attributes = {
3138
- [FrontMcpAttributes.HOOK_STAGE]: options.stage
3139
- };
3140
- if (options.owner) {
3141
- attributes[FrontMcpAttributes.HOOK_OWNER] = options.owner;
3142
- }
3143
- if (options.flowName) {
3144
- attributes[FrontMcpAttributes.FLOW_NAME] = options.flowName;
3145
- }
3146
- return startSpan(tracer, {
3147
- name: `hook ${options.stage}`,
3148
- kind: import_api18.SpanKind.INTERNAL,
3149
- attributes,
3150
- parentContext: options.parentContext
3151
- });
3152
- }
3153
-
3154
3242
  // libs/observability/src/otel/spans/pretty-span-exporter.ts
3155
3243
  var import_api19 = require("@opentelemetry/api");
3156
3244
  var RESET = "\x1B[0m";
@@ -3393,7 +3481,7 @@ var ProcessStatsCollector = class {
3393
3481
  });
3394
3482
  }
3395
3483
  const mem = probeSafely(() => this.memoryUsage());
3396
- if (mem) {
3484
+ if (mem && mem.rss > 0) {
3397
3485
  entries.push({
3398
3486
  name: "frontmcp_process_resident_memory_bytes",
3399
3487
  value: mem.rss,
@@ -3416,7 +3504,7 @@ var ProcessStatsCollector = class {
3416
3504
  });
3417
3505
  }
3418
3506
  const uptime = probeSafely(() => this.uptime());
3419
- if (uptime !== void 0) {
3507
+ if (uptime !== void 0 && uptime > 0) {
3420
3508
  entries.push({
3421
3509
  name: "frontmcp_process_uptime_seconds",
3422
3510
  value: uptime,