@opengeni/observability 1.4.4 → 1.4.5-canary.37458084490001

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.
@@ -0,0 +1,25 @@
1
+ import type { Observability } from "./index.js";
2
+ /**
3
+ * Closed, low-cardinality families for agent tool calls. A tool's exact name,
4
+ * MCP server, connector domain, arguments, and output never become labels;
5
+ * unknown future tools collapse to `other` until reviewed here.
6
+ */
7
+ export declare const AGENT_TOOL_METRIC_FAMILIES: readonly ["shell", "apply_patch", "browser", "computer", "human_handoff", "human_input", "image", "video", "web", "memory", "goal", "session", "machine", "skill", "tool_router", "files", "connector", "integration", "custom_mcp", "codemode", "other"];
8
+ export type AgentToolMetricFamily = (typeof AGENT_TOOL_METRIC_FAMILIES)[number];
9
+ export declare const AGENT_TOOL_CALL_OUTCOMES: readonly ["ok", "error", "rejected", "cancelled"];
10
+ export type AgentToolCallOutcome = (typeof AGENT_TOOL_CALL_OUTCOMES)[number];
11
+ /**
12
+ * Map the content-free analytics family computed for a tool call
13
+ * (`toolCallFamily`: a first-party tool name, `integration:<domain>`, or
14
+ * `custom`) — or, when absent, the model-facing tool name — onto the closed
15
+ * metric family set.
16
+ */
17
+ export declare function agentToolMetricFamily(toolFamily: string | null | undefined, name?: string | null): AgentToolMetricFamily;
18
+ /** Structural outcome of a normalized `agent.toolCall.output` payload. */
19
+ export declare function agentToolCallOutcome(payload: unknown): AgentToolCallOutcome;
20
+ /** Count one completed agent tool call. Telemetry failures never reach the turn. */
21
+ export declare function recordAgentToolCall(observability: Observability | null | undefined, input: {
22
+ family: AgentToolMetricFamily;
23
+ outcome: AgentToolCallOutcome;
24
+ durationMs?: number;
25
+ }): void;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type TraceContext } from "./trace-context.js";
2
2
  import { type FailureDiagnosticInput } from "./failure-diagnostic.js";
3
3
  export type { FailureDiagnosticInput } from "./failure-diagnostic.js";
4
+ export { AGENT_TOOL_CALL_OUTCOMES, AGENT_TOOL_METRIC_FAMILIES, agentToolCallOutcome, agentToolMetricFamily, recordAgentToolCall, type AgentToolCallOutcome, type AgentToolMetricFamily, } from "./agent-tool-metrics.js";
4
5
  export { failureDiagnostic } from "./failure-diagnostic.js";
5
6
  export { createLogThrottle, type LogThrottle } from "./log-throttle.js";
6
7
  export { withMcpTelemetry, withMcpCallIdentity, bindMcpTelemetry, beginMcpPhase, measureMcpPhase, recordToolApproval, MCP_EXECUTION_PHASES, } from "./mcp-timing.js";
@@ -150,6 +151,19 @@ export declare class Observability {
150
151
  status: number;
151
152
  durationSeconds: number;
152
153
  }): void;
154
+ /**
155
+ * Count a rejected API request by route, status, public error code, and a
156
+ * bounded reason (`permission:<name>`, a typed detail code, or
157
+ * `unclassified`). Values outside the closed grammars collapse to `other` so
158
+ * a malformed caller can never mint a free-form series.
159
+ */
160
+ recordHttpRejection(input: {
161
+ method: string;
162
+ route: string;
163
+ status: number;
164
+ code: string;
165
+ reason: string;
166
+ }): void;
153
167
  recordWorkerActivity(input: {
154
168
  activity: string;
155
169
  status: string;
@@ -220,6 +234,8 @@ export type InteractionOperationMetricObservation = {
220
234
  operation: string;
221
235
  outcome: string;
222
236
  mode: string;
237
+ /** Bounded failure reason; `none` for successful or non-failed outcomes. */
238
+ reason?: string | undefined;
223
239
  durationMs: number;
224
240
  replayed?: boolean | undefined;
225
241
  };
package/dist/index.js CHANGED
@@ -291,6 +291,157 @@ function failureDiagnostic(input, revision) {
291
291
  };
292
292
  }
293
293
 
294
+ // src/agent-tool-metrics.ts
295
+ var AGENT_TOOL_METRIC_FAMILIES = [
296
+ "shell",
297
+ "apply_patch",
298
+ "browser",
299
+ "computer",
300
+ "human_handoff",
301
+ "human_input",
302
+ "image",
303
+ "video",
304
+ "web",
305
+ "memory",
306
+ "goal",
307
+ "session",
308
+ "machine",
309
+ "skill",
310
+ "tool_router",
311
+ "files",
312
+ "connector",
313
+ "integration",
314
+ "custom_mcp",
315
+ "codemode",
316
+ "other"
317
+ ];
318
+ var AGENT_TOOL_CALL_OUTCOMES = ["ok", "error", "rejected", "cancelled"];
319
+ var EXACT = {
320
+ exec_command: "shell",
321
+ write_stdin: "shell",
322
+ local_shell_call: "shell",
323
+ shell_call: "shell",
324
+ shell: "shell",
325
+ command_wait: "shell",
326
+ command_read: "shell",
327
+ interaction_discover: "browser",
328
+ interaction_request_human: "human_handoff",
329
+ request_human_input: "human_input",
330
+ wait_for_input: "human_input",
331
+ session_human_input_respond: "human_input",
332
+ generate_image: "image",
333
+ view_image: "image",
334
+ image_generation_call: "image",
335
+ generate_video: "video",
336
+ get_video_generation_capabilities: "video",
337
+ web_fetch: "web",
338
+ set_session_title: "session",
339
+ notify_user: "session",
340
+ set_other_session_title: "session",
341
+ sessions_list: "session",
342
+ sandboxes_list: "machine",
343
+ sandbox_attach: "machine",
344
+ sandbox_swap: "machine",
345
+ sandbox_provision: "machine",
346
+ run_on: "machine",
347
+ load_skill: "skill",
348
+ repository_skill_read: "skill",
349
+ tool_search: "tool_router",
350
+ tool_list: "tool_router",
351
+ tool_invoke: "tool_router",
352
+ sandbox_file_publish: "files",
353
+ google_drive_publish_file: "files",
354
+ custom_mcp_setup_request: "connector",
355
+ list_models: "other"
356
+ };
357
+ var PREFIXES = [
358
+ ["apply_patch", "apply_patch"],
359
+ ["browser_", "browser"],
360
+ ["computer_", "computer"],
361
+ ["web_search", "web"],
362
+ ["knowledge_", "memory"],
363
+ ["memory_", "memory"],
364
+ ["instruction_policy_", "memory"],
365
+ ["preference_", "memory"],
366
+ ["task_note", "memory"],
367
+ ["remember", "memory"],
368
+ ["company_profile_", "memory"],
369
+ ["work_claim_", "memory"],
370
+ ["goal_", "goal"],
371
+ ["session_", "session"],
372
+ ["project_", "session"],
373
+ ["rig_", "session"],
374
+ ["scheduled_task", "session"],
375
+ ["connected_machine_", "machine"],
376
+ ["skill_", "skill"],
377
+ ["artifacts_", "files"],
378
+ ["editable_artifact_", "files"],
379
+ ["files_", "files"],
380
+ ["slack_", "connector"],
381
+ ["fiken_", "connector"],
382
+ ["x_", "connector"],
383
+ ["reddit_", "connector"],
384
+ ["social_", "connector"],
385
+ ["github_", "connector"],
386
+ ["atlassian_", "connector"],
387
+ ["gmail_", "connector"],
388
+ ["variable_set_", "connector"],
389
+ ["environment_", "connector"],
390
+ ["capability_", "connector"]
391
+ ];
392
+ function agentToolMetricFamily(toolFamily, name) {
393
+ if (toolFamily === "custom") return "custom_mcp";
394
+ if (toolFamily?.startsWith("integration:")) return "integration";
395
+ const candidate = (toolFamily ?? name ?? "").replace(/^(?:opengeni|interaction)__/, "").toLowerCase();
396
+ if (!candidate) return "other";
397
+ const exact = EXACT[candidate];
398
+ if (exact) return exact;
399
+ for (const [prefix, family] of PREFIXES) {
400
+ if (candidate.startsWith(prefix)) return family;
401
+ }
402
+ return "other";
403
+ }
404
+ var SDK_NOT_APPROVED = "Tool execution was not approved.";
405
+ var SDK_TOOL_ERROR_PREFIX = "An error occurred while running the tool";
406
+ function agentToolCallOutcome(payload) {
407
+ if (!payload || typeof payload !== "object") return "ok";
408
+ const record = payload;
409
+ if (record.error === true || record.failed === true) return "error";
410
+ const output = record.output;
411
+ if (output && typeof output === "object" && output.isError === true) {
412
+ return "error";
413
+ }
414
+ const text = typeof output === "string" ? output : output && typeof output === "object" && typeof output.text === "string" ? output.text : null;
415
+ if (text !== null) {
416
+ const trimmed = text.trim();
417
+ if (trimmed === SDK_NOT_APPROVED) return "rejected";
418
+ if (trimmed === "aborted") return "cancelled";
419
+ if (trimmed.startsWith(SDK_TOOL_ERROR_PREFIX)) return "error";
420
+ }
421
+ return "ok";
422
+ }
423
+ function recordAgentToolCall(observability, input) {
424
+ if (!observability) return;
425
+ const family = AGENT_TOOL_METRIC_FAMILIES.includes(input.family) ? input.family : "other";
426
+ const outcome = AGENT_TOOL_CALL_OUTCOMES.includes(input.outcome) ? input.outcome : "ok";
427
+ try {
428
+ observability.incrementCounter({
429
+ name: "opengeni_agent_tool_calls_total",
430
+ help: "Completed agent tool calls by closed tool family and structural outcome.",
431
+ labels: { family, outcome }
432
+ });
433
+ if (input.durationMs !== void 0 && Number.isFinite(input.durationMs)) {
434
+ observability.observeHistogram({
435
+ name: "opengeni_agent_tool_call_duration_seconds",
436
+ help: "Agent tool-call duration in seconds by closed tool family.",
437
+ labels: { family },
438
+ value: Math.max(0, input.durationMs) / 1e3
439
+ });
440
+ }
441
+ } catch {
442
+ }
443
+ }
444
+
294
445
  // src/log-throttle.ts
295
446
  function createLogThrottle(options) {
296
447
  const intervalMs = Math.max(0, options.intervalMs);
@@ -553,10 +704,57 @@ var INTERACTION_OUTCOMES = /* @__PURE__ */ new Set([
553
704
  "dispatched",
554
705
  "completed",
555
706
  "failed",
707
+ "denied",
556
708
  "outcome_unknown",
557
709
  "stale",
558
710
  "cancelled"
559
711
  ]);
712
+ var INTERACTION_OPERATION_REASONS = /* @__PURE__ */ new Set([
713
+ "none",
714
+ "resource_not_found",
715
+ "resource_unavailable",
716
+ "controller_stale",
717
+ "target_not_found",
718
+ "target_stale",
719
+ "observation_stale",
720
+ "document_stale",
721
+ "frame_stale",
722
+ "locator_not_found",
723
+ "locator_ambiguous",
724
+ "unsupported",
725
+ "permission_denied",
726
+ "machine_locked",
727
+ "attempt_stale",
728
+ "operation_conflict",
729
+ "outcome_unknown",
730
+ "invalid_action",
731
+ "timeout",
732
+ "controller_lost",
733
+ "driver_failed",
734
+ "action_failed",
735
+ "stale",
736
+ "unauthenticated",
737
+ "access_denied",
738
+ "not_found",
739
+ "conflict",
740
+ "invalid_request",
741
+ "rate_limited",
742
+ "unavailable",
743
+ "internal",
744
+ "rejected",
745
+ "control_unsupported",
746
+ "control_os",
747
+ "control_not_found",
748
+ "control_consent_required",
749
+ "control_timeout",
750
+ "control_draining",
751
+ "control_protocol",
752
+ "control_stream",
753
+ "control_agent_offline",
754
+ "control_fenced",
755
+ "control_payload_too_large",
756
+ "control_unknown"
757
+ ]);
560
758
  var INTERACTION_MODES = /* @__PURE__ */ new Set([
561
759
  "semantic",
562
760
  "coordinate",
@@ -649,10 +847,18 @@ var PUBLIC_TELEMETRY_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
649
847
  "retainedOutputKind",
650
848
  "suppressedCount"
651
849
  ]);
850
+ var HTTP_REJECTION_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
851
+ var HTTP_REJECTION_REASON_PATTERN = /^(?:permission:[a-z][a-z0-9-]*:[a-z][a-z0-9-]*|control:[a-z][a-z0-9_]{0,31}|[A-Za-z][A-Za-z0-9_.-]{0,63})$/;
652
852
  var PUBLIC_TELEMETRY_OPAQUE_ATTRIBUTE_PATTERNS = /* @__PURE__ */ new Map([
653
853
  ["mcpCallKey", /^mcp_[0-9a-f]{32}$/],
654
854
  ["sandboxLeaseKey", /^slk_[0-9a-f]{32}$/],
655
855
  ["correlationId", /^[A-Za-z0-9._:-]{1,128}$/],
856
+ // Rejected-request classification (apps/api/src/http/rejection-telemetry.ts):
857
+ // the public ErrorEnvelope code enum, a catalog permission or typed detail
858
+ // code, and a one-way message hash. Never message text or identifiers.
859
+ ["rejectionCode", HTTP_REJECTION_CODE_PATTERN],
860
+ ["rejectionReason", HTTP_REJECTION_REASON_PATTERN],
861
+ ["rejectionFingerprint", /^m_[0-9a-f]{10}$/],
656
862
  // Web error beacon: a route PATTERN of lowercase literal and `$param`
657
863
  // segments (never a concrete path or id) and the bundle revision token, in
658
864
  // the exact wire grammar the API route admits.
@@ -1073,6 +1279,26 @@ var Observability = class {
1073
1279
  }
1074
1280
  });
1075
1281
  }
1282
+ /**
1283
+ * Count a rejected API request by route, status, public error code, and a
1284
+ * bounded reason (`permission:<name>`, a typed detail code, or
1285
+ * `unclassified`). Values outside the closed grammars collapse to `other` so
1286
+ * a malformed caller can never mint a free-form series.
1287
+ */
1288
+ recordHttpRejection(input) {
1289
+ this.incrementCounter({
1290
+ name: "opengeni_http_request_rejections_total",
1291
+ help: "Rejected HTTP requests (status >= 400) by route, status, public error code, and bounded reason.",
1292
+ labels: {
1293
+ method: input.method,
1294
+ route: input.route,
1295
+ status: String(input.status),
1296
+ code: HTTP_REJECTION_CODE_PATTERN.test(input.code) ? input.code : "other",
1297
+ reason: HTTP_REJECTION_REASON_PATTERN.test(input.reason) ? input.reason : "other",
1298
+ component: this.options.component
1299
+ }
1300
+ });
1301
+ }
1076
1302
  recordWorkerActivity(input) {
1077
1303
  this.incrementCounter({
1078
1304
  name: "opengeni_worker_activity_runs_total",
@@ -1381,11 +1607,12 @@ function interactionOperationMetricObserver(observability) {
1381
1607
  const operation = boundedMetricEnum(INTERACTION_OPERATIONS, observation.operation);
1382
1608
  const outcome = boundedMetricEnum(INTERACTION_OUTCOMES, observation.outcome);
1383
1609
  const mode = boundedMetricEnum(INTERACTION_MODES, observation.mode);
1610
+ const reason = boundedMetricEnum(INTERACTION_OPERATION_REASONS, observation.reason ?? "none");
1384
1611
  try {
1385
1612
  observability.incrementCounter({
1386
1613
  name: "opengeni_interaction_operations_total",
1387
- help: "Browser and Computer operations by bounded resource, operation, mode, and outcome.",
1388
- labels: { resource, operation, mode, outcome }
1614
+ help: "Browser and Computer operations by bounded resource, operation, mode, outcome, and failure reason.",
1615
+ labels: { resource, operation, mode, outcome, reason }
1389
1616
  });
1390
1617
  observability.observeHistogram({
1391
1618
  name: "opengeni_interaction_operation_duration_seconds",
@@ -1810,11 +2037,15 @@ async function defaultExporter(url, body, headers) {
1810
2037
  }
1811
2038
  }
1812
2039
  export {
2040
+ AGENT_TOOL_CALL_OUTCOMES,
2041
+ AGENT_TOOL_METRIC_FAMILIES,
1813
2042
  MCP_EXECUTION_PHASES,
1814
2043
  OPENGENI_OBSERVABILITY_DISTRIBUTION,
1815
2044
  Observability,
1816
2045
  TENANCY_COMPATIBILITY_LANES,
1817
2046
  admissionTraceContext,
2047
+ agentToolCallOutcome,
2048
+ agentToolMetricFamily,
1818
2049
  beginMcpPhase,
1819
2050
  bindMcpTelemetry,
1820
2051
  createLogThrottle,
@@ -1829,6 +2060,7 @@ export {
1829
2060
  measureMcpPhase,
1830
2061
  parseHeaders,
1831
2062
  parseTraceparent,
2063
+ recordAgentToolCall,
1832
2064
  recordTenancyCompatibilityLaneUse,
1833
2065
  recordToolApproval,
1834
2066
  recordWorkflowWakeReconciliation,