@graphorin/observability 0.5.0

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 (138) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +115 -0
  4. package/dist/cost/cost-tracker.d.ts +28 -0
  5. package/dist/cost/cost-tracker.d.ts.map +1 -0
  6. package/dist/cost/cost-tracker.js +169 -0
  7. package/dist/cost/cost-tracker.js.map +1 -0
  8. package/dist/cost/index.d.ts +3 -0
  9. package/dist/cost/index.js +3 -0
  10. package/dist/cost/types.d.ts +104 -0
  11. package/dist/cost/types.d.ts.map +1 -0
  12. package/dist/eval/index.d.ts +3 -0
  13. package/dist/eval/index.js +3 -0
  14. package/dist/eval/runner.d.ts +11 -0
  15. package/dist/eval/runner.d.ts.map +1 -0
  16. package/dist/eval/runner.js +113 -0
  17. package/dist/eval/runner.js.map +1 -0
  18. package/dist/eval/types.d.ts +108 -0
  19. package/dist/eval/types.d.ts.map +1 -0
  20. package/dist/exporters/console.d.ts +27 -0
  21. package/dist/exporters/console.d.ts.map +1 -0
  22. package/dist/exporters/console.js +47 -0
  23. package/dist/exporters/console.js.map +1 -0
  24. package/dist/exporters/index.d.ts +6 -0
  25. package/dist/exporters/index.js +7 -0
  26. package/dist/exporters/jsonl.d.ts +57 -0
  27. package/dist/exporters/jsonl.d.ts.map +1 -0
  28. package/dist/exporters/jsonl.js +95 -0
  29. package/dist/exporters/jsonl.js.map +1 -0
  30. package/dist/exporters/otlp-http.d.ts +38 -0
  31. package/dist/exporters/otlp-http.d.ts.map +1 -0
  32. package/dist/exporters/otlp-http.js +115 -0
  33. package/dist/exporters/otlp-http.js.map +1 -0
  34. package/dist/exporters/types.d.ts +72 -0
  35. package/dist/exporters/types.d.ts.map +1 -0
  36. package/dist/exporters/types.js +13 -0
  37. package/dist/exporters/types.js.map +1 -0
  38. package/dist/exporters/with-validation.d.ts +45 -0
  39. package/dist/exporters/with-validation.d.ts.map +1 -0
  40. package/dist/exporters/with-validation.js +99 -0
  41. package/dist/exporters/with-validation.js.map +1 -0
  42. package/dist/gen-ai/emit.d.ts +27 -0
  43. package/dist/gen-ai/emit.d.ts.map +1 -0
  44. package/dist/gen-ai/emit.js +88 -0
  45. package/dist/gen-ai/emit.js.map +1 -0
  46. package/dist/gen-ai/index.d.ts +5 -0
  47. package/dist/gen-ai/index.js +5 -0
  48. package/dist/gen-ai/operation-mapping.d.ts +24 -0
  49. package/dist/gen-ai/operation-mapping.d.ts.map +1 -0
  50. package/dist/gen-ai/operation-mapping.js +67 -0
  51. package/dist/gen-ai/operation-mapping.js.map +1 -0
  52. package/dist/gen-ai/system-derivation.d.ts +41 -0
  53. package/dist/gen-ai/system-derivation.d.ts.map +1 -0
  54. package/dist/gen-ai/system-derivation.js +67 -0
  55. package/dist/gen-ai/system-derivation.js.map +1 -0
  56. package/dist/gen-ai/types.d.ts +87 -0
  57. package/dist/gen-ai/types.d.ts.map +1 -0
  58. package/dist/index.d.ts +58 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +60 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/logger/index.d.ts +2 -0
  63. package/dist/logger/index.js +3 -0
  64. package/dist/logger/logger.d.ts +53 -0
  65. package/dist/logger/logger.d.ts.map +1 -0
  66. package/dist/logger/logger.js +145 -0
  67. package/dist/logger/logger.js.map +1 -0
  68. package/dist/openinference/index.d.ts +45 -0
  69. package/dist/openinference/index.d.ts.map +1 -0
  70. package/dist/openinference/index.js +92 -0
  71. package/dist/openinference/index.js.map +1 -0
  72. package/dist/redaction/config.d.ts +39 -0
  73. package/dist/redaction/config.d.ts.map +1 -0
  74. package/dist/redaction/config.js +15 -0
  75. package/dist/redaction/config.js.map +1 -0
  76. package/dist/redaction/errors.d.ts +36 -0
  77. package/dist/redaction/errors.d.ts.map +1 -0
  78. package/dist/redaction/errors.js +42 -0
  79. package/dist/redaction/errors.js.map +1 -0
  80. package/dist/redaction/imperative-patterns.d.ts +108 -0
  81. package/dist/redaction/imperative-patterns.d.ts.map +1 -0
  82. package/dist/redaction/imperative-patterns.js +187 -0
  83. package/dist/redaction/imperative-patterns.js.map +1 -0
  84. package/dist/redaction/index.d.ts +7 -0
  85. package/dist/redaction/index.js +7 -0
  86. package/dist/redaction/patterns.d.ts +85 -0
  87. package/dist/redaction/patterns.d.ts.map +1 -0
  88. package/dist/redaction/patterns.js +172 -0
  89. package/dist/redaction/patterns.js.map +1 -0
  90. package/dist/redaction/types.d.ts +103 -0
  91. package/dist/redaction/types.d.ts.map +1 -0
  92. package/dist/redaction/validator.d.ts +26 -0
  93. package/dist/redaction/validator.d.ts.map +1 -0
  94. package/dist/redaction/validator.js +195 -0
  95. package/dist/redaction/validator.js.map +1 -0
  96. package/dist/replay/config.d.ts +56 -0
  97. package/dist/replay/config.d.ts.map +1 -0
  98. package/dist/replay/config.js +18 -0
  99. package/dist/replay/config.js.map +1 -0
  100. package/dist/replay/index.d.ts +5 -0
  101. package/dist/replay/index.js +5 -0
  102. package/dist/replay/log.d.ts +39 -0
  103. package/dist/replay/log.d.ts.map +1 -0
  104. package/dist/replay/log.js +59 -0
  105. package/dist/replay/log.js.map +1 -0
  106. package/dist/replay/replay.d.ts +25 -0
  107. package/dist/replay/replay.d.ts.map +1 -0
  108. package/dist/replay/replay.js +173 -0
  109. package/dist/replay/replay.js.map +1 -0
  110. package/dist/replay/types.d.ts +110 -0
  111. package/dist/replay/types.d.ts.map +1 -0
  112. package/dist/telemetry/index.d.ts +63 -0
  113. package/dist/telemetry/index.d.ts.map +1 -0
  114. package/dist/telemetry/index.js +49 -0
  115. package/dist/telemetry/index.js.map +1 -0
  116. package/dist/tracer/ids.d.ts +23 -0
  117. package/dist/tracer/ids.d.ts.map +1 -0
  118. package/dist/tracer/ids.js +30 -0
  119. package/dist/tracer/ids.js.map +1 -0
  120. package/dist/tracer/index.d.ts +6 -0
  121. package/dist/tracer/index.js +6 -0
  122. package/dist/tracer/sampling.d.ts +77 -0
  123. package/dist/tracer/sampling.d.ts.map +1 -0
  124. package/dist/tracer/sampling.js +67 -0
  125. package/dist/tracer/sampling.js.map +1 -0
  126. package/dist/tracer/span-names.d.ts +11 -0
  127. package/dist/tracer/span-names.d.ts.map +1 -0
  128. package/dist/tracer/span-names.js +11 -0
  129. package/dist/tracer/span-names.js.map +1 -0
  130. package/dist/tracer/span.d.ts +27 -0
  131. package/dist/tracer/span.d.ts.map +1 -0
  132. package/dist/tracer/span.js +80 -0
  133. package/dist/tracer/span.js.map +1 -0
  134. package/dist/tracer/tracer.d.ts +101 -0
  135. package/dist/tracer/tracer.d.ts.map +1 -0
  136. package/dist/tracer/tracer.js +150 -0
  137. package/dist/tracer/tracer.js.map +1 -0
  138. package/package.json +138 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":["VALIDATED_EXPORTER_BRAND: unique symbol"],"sources":["../../src/exporters/types.ts"],"sourcesContent":["/**\n * Shared types for the exporter surface.\n *\n * @packageDocumentation\n */\n\nimport type { SpanAttributes, SpanAttributeValue, SpanStatus, SpanType } from '@graphorin/core';\n\n/**\n * Discriminator marker — every exporter that has been wrapped via\n * `withValidation(...)` is branded with this symbol so the tracer can\n * fail-fast at startup when a raw exporter is registered.\n *\n * @stable\n */\nexport const VALIDATED_EXPORTER_BRAND: unique symbol = Symbol.for(\n 'graphorin.observability.exporter.validated',\n);\n\n/**\n * Sanitized, JSON-serialisable representation of a finished span. The\n * exporters never see the live OTel span; the tracer materialises this\n * record once the span ends and runs it through the validator.\n *\n * @stable\n */\nexport interface SpanRecord<T extends SpanType = SpanType> {\n readonly type: T;\n readonly id: string;\n readonly traceId: string;\n readonly parentId?: string;\n readonly name: string;\n readonly startUnixNano: number;\n readonly endUnixNano: number;\n readonly status: SpanStatus;\n readonly statusMessage?: string;\n readonly attributes: SpanAttributes;\n readonly events: ReadonlyArray<SpanRecordEvent>;\n /** Optional per-attribute sensitivity map — see `setAttribute({ sensitivity })`. */\n readonly sensitivityByAttribute?: Readonly<Record<string, SpanAttributeValue>>;\n /** Set when the validator dropped the span entirely (replay marker). */\n readonly droppedReason?: string;\n}\n\n/**\n * Single span event carried alongside the span record.\n *\n * @stable\n */\nexport interface SpanRecordEvent {\n readonly name: string;\n readonly timeUnixNano: number;\n readonly attributes: SpanAttributes;\n}\n\n/**\n * A trace exporter contract. Exporters consume a stream of finished\n * spans and forward them to a sink (console, file, OTLP wire, …).\n *\n * @stable\n */\nexport interface TraceExporter {\n readonly id: string;\n /** Forward a finished span record. Implementations should be cheap. */\n export(record: SpanRecord): Promise<void>;\n /** Flush any buffered spans. Called on `tracer.shutdown()`. */\n flush(): Promise<void>;\n /** Close any underlying resources. Idempotent. */\n shutdown(): Promise<void>;\n /**\n * Branded-marker stub. Set by `withValidation(...)` to signal that the\n * exporter has been wrapped. Direct exporters omit the brand and the\n * tracer fails fast at startup.\n *\n * @internal\n */\n readonly [VALIDATED_EXPORTER_BRAND]?: true;\n}\n"],"mappings":";;;;;;;;AAeA,MAAaA,2BAA0C,OAAO,IAC5D,6CACD"}
@@ -0,0 +1,45 @@
1
+ import { TraceExporter } from "./types.js";
2
+ import { RedactionCounters, RedactionValidatorInstance, RedactionValidatorOptions } from "../redaction/types.js";
3
+ import { SpanAttributeValue, SpanAttributes } from "@graphorin/core";
4
+
5
+ //#region src/exporters/with-validation.d.ts
6
+
7
+ /**
8
+ * Options for {@link withValidation}.
9
+ *
10
+ * @stable
11
+ */
12
+ interface WithValidationOptions extends RedactionValidatorOptions {
13
+ /**
14
+ * Optional pre-built validator. When supplied, the rest of the
15
+ * options on this object are ignored and the supplied validator is
16
+ * reused — useful for sharing one validator across multiple exporters.
17
+ */
18
+ readonly validator?: RedactionValidatorInstance;
19
+ }
20
+ /**
21
+ * Wrap an exporter so every span flows through a {@link RedactionValidator}
22
+ * before reaching the sink. Exporters that are not wrapped are rejected
23
+ * by the tracer at startup.
24
+ *
25
+ * @stable
26
+ */
27
+ declare function withValidation<E extends TraceExporter>(exporter: E, opts?: WithValidationOptions): TraceExporter;
28
+ /**
29
+ * Quickly check whether an exporter is the result of a previous
30
+ * {@link withValidation} call. The tracer uses this to fail fast at
31
+ * startup.
32
+ *
33
+ * @stable
34
+ */
35
+ declare function isValidatedExporter(exporter: TraceExporter): boolean;
36
+ /**
37
+ * Pull the counters out of any exporter wrapped by {@link withValidation}.
38
+ * Returns `null` for exporters that were never wrapped.
39
+ *
40
+ * @stable
41
+ */
42
+ declare function tryGetValidatorCounters(validator: RedactionValidatorInstance): RedactionCounters;
43
+ //#endregion
44
+ export { WithValidationOptions, isValidatedExporter, tryGetValidatorCounters, withValidation };
45
+ //# sourceMappingURL=with-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-validation.d.ts","names":[],"sources":["../../src/exporters/with-validation.ts"],"sourcesContent":[],"mappings":";;;;;;;AAgJA;AAUA;;;UAhIiB,qBAAA,SAA8B;;;;;;uBAMxB;;;;;;;;;iBAUP,yBAAyB,yBAC7B,UACJ,wBACL;;;;;;;;iBAmGa,mBAAA,WAA8B;;;;;;;iBAU9B,uBAAA,YAAmC,6BAA6B"}
@@ -0,0 +1,99 @@
1
+ import { VALIDATED_EXPORTER_BRAND } from "./types.js";
2
+ import { createRedactionValidator } from "../redaction/validator.js";
3
+
4
+ //#region src/exporters/with-validation.ts
5
+ const DEFAULT_ATTR_SENSITIVITY = "internal";
6
+ /**
7
+ * Wrap an exporter so every span flows through a {@link RedactionValidator}
8
+ * before reaching the sink. Exporters that are not wrapped are rejected
9
+ * by the tracer at startup.
10
+ *
11
+ * @stable
12
+ */
13
+ function withValidation(exporter, opts = {}) {
14
+ const validator = opts.validator ?? createRedactionValidator(opts);
15
+ return {
16
+ id: `${exporter.id}+validated`,
17
+ [VALIDATED_EXPORTER_BRAND]: true,
18
+ async export(record) {
19
+ await exporter.export(sanitizeRecord(record, validator));
20
+ },
21
+ flush: () => exporter.flush(),
22
+ shutdown: () => exporter.shutdown()
23
+ };
24
+ }
25
+ /**
26
+ * @internal
27
+ */
28
+ function sanitizeRecord(record, validator) {
29
+ const sensitivities = record.sensitivityByAttribute ?? {};
30
+ const sanitizedAttrs = sanitizeAttributes(record.attributes, sensitivities, validator, record.type);
31
+ const sanitizedEvents = sanitizeEvents(record.events, validator, record.type);
32
+ return {
33
+ ...record,
34
+ attributes: sanitizedAttrs,
35
+ events: sanitizedEvents
36
+ };
37
+ }
38
+ /**
39
+ * @internal
40
+ */
41
+ function sanitizeAttributes(attrs, sensitivities, validator, spanType) {
42
+ const out = {};
43
+ for (const [key, value] of Object.entries(attrs)) {
44
+ const tier = readTier(sensitivities[key]);
45
+ const result = validator.validate({
46
+ value,
47
+ tier,
48
+ context: spanType === void 0 ? { attribute: key } : {
49
+ attribute: key,
50
+ spanType
51
+ }
52
+ });
53
+ if (result === null) continue;
54
+ out[key] = result.value;
55
+ }
56
+ return Object.freeze(out);
57
+ }
58
+ /**
59
+ * @internal
60
+ */
61
+ function sanitizeEvents(events, validator, spanType) {
62
+ const out = [];
63
+ for (const event of events) {
64
+ const sanitizedAttrs = sanitizeAttributes(event.attributes, {}, validator, spanType);
65
+ out.push({
66
+ name: event.name,
67
+ timeUnixNano: event.timeUnixNano,
68
+ attributes: sanitizedAttrs
69
+ });
70
+ }
71
+ return out;
72
+ }
73
+ function readTier(value) {
74
+ if (value === "public" || value === "internal" || value === "secret") return value;
75
+ return DEFAULT_ATTR_SENSITIVITY;
76
+ }
77
+ /**
78
+ * Quickly check whether an exporter is the result of a previous
79
+ * {@link withValidation} call. The tracer uses this to fail fast at
80
+ * startup.
81
+ *
82
+ * @stable
83
+ */
84
+ function isValidatedExporter(exporter) {
85
+ return exporter[VALIDATED_EXPORTER_BRAND] === true;
86
+ }
87
+ /**
88
+ * Pull the counters out of any exporter wrapped by {@link withValidation}.
89
+ * Returns `null` for exporters that were never wrapped.
90
+ *
91
+ * @stable
92
+ */
93
+ function tryGetValidatorCounters(validator) {
94
+ return validator.counters();
95
+ }
96
+
97
+ //#endregion
98
+ export { isValidatedExporter, sanitizeRecord, tryGetValidatorCounters, withValidation };
99
+ //# sourceMappingURL=with-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-validation.js","names":["DEFAULT_ATTR_SENSITIVITY: Sensitivity","out: Record<string, SpanAttributeValue>","out: SpanRecord['events'][number][]"],"sources":["../../src/exporters/with-validation.ts"],"sourcesContent":["/**\n * `withValidation(exporter, opts)` — the **mandatory wrapper** applied\n * to every exporter. Forwards each span record through a\n * `RedactionValidator` first; drops + counts when a value exceeds the\n * configured tier floor or matches a secret / PII pattern.\n *\n * @packageDocumentation\n */\n\nimport type { Sensitivity, SpanAttributes, SpanAttributeValue } from '@graphorin/core';\nimport type {\n RedactionCounters,\n RedactionValidatorInstance,\n RedactionValidatorOptions,\n} from '../redaction/types.js';\nimport { createRedactionValidator } from '../redaction/validator.js';\n\nimport { type SpanRecord, type TraceExporter, VALIDATED_EXPORTER_BRAND } from './types.js';\n\nconst DEFAULT_ATTR_SENSITIVITY: Sensitivity = 'internal';\n\n/**\n * Options for {@link withValidation}.\n *\n * @stable\n */\nexport interface WithValidationOptions extends RedactionValidatorOptions {\n /**\n * Optional pre-built validator. When supplied, the rest of the\n * options on this object are ignored and the supplied validator is\n * reused — useful for sharing one validator across multiple exporters.\n */\n readonly validator?: RedactionValidatorInstance;\n}\n\n/**\n * Wrap an exporter so every span flows through a {@link RedactionValidator}\n * before reaching the sink. Exporters that are not wrapped are rejected\n * by the tracer at startup.\n *\n * @stable\n */\nexport function withValidation<E extends TraceExporter>(\n exporter: E,\n opts: WithValidationOptions = {},\n): TraceExporter {\n const validator = opts.validator ?? createRedactionValidator(opts);\n const wrapped: TraceExporter = {\n id: `${exporter.id}+validated`,\n [VALIDATED_EXPORTER_BRAND]: true,\n async export(record: SpanRecord): Promise<void> {\n // RP-18: the validator strips offending attributes (counting each drop)\n // and always returns an exportable record — a single untagged or\n // over-tier attribute no longer makes the whole span vanish from every\n // exporter.\n await exporter.export(sanitizeRecord(record, validator));\n },\n flush: () => exporter.flush(),\n shutdown: () => exporter.shutdown(),\n };\n return wrapped;\n}\n\n/**\n * @internal\n */\nexport function sanitizeRecord(\n record: SpanRecord,\n validator: RedactionValidatorInstance,\n): SpanRecord {\n const sensitivities = record.sensitivityByAttribute ?? {};\n // RP-18: attribute-granular sanitization. Offending attributes are stripped\n // (and counted by the validator); the span itself always survives so\n // framework spans carrying untagged attributes still reach every exporter.\n const sanitizedAttrs = sanitizeAttributes(\n record.attributes,\n sensitivities,\n validator,\n record.type,\n );\n const sanitizedEvents = sanitizeEvents(record.events, validator, record.type);\n return {\n ...record,\n attributes: sanitizedAttrs,\n events: sanitizedEvents,\n };\n}\n\n/**\n * @internal\n */\nexport function sanitizeAttributes(\n attrs: SpanAttributes,\n sensitivities: Readonly<Record<string, SpanAttributeValue>>,\n validator: RedactionValidatorInstance,\n spanType?: string,\n): SpanAttributes {\n const out: Record<string, SpanAttributeValue> = {};\n for (const [key, value] of Object.entries(attrs)) {\n const tier = readTier(sensitivities[key]);\n const result = validator.validate({\n value,\n tier,\n context: spanType === undefined ? { attribute: key } : { attribute: key, spanType },\n });\n if (result === null) {\n // RP-18: this single attribute exceeded the floor (or matched a secret\n // pattern). Strip it — the validator has already counted the drop — and\n // keep the rest of the span rather than discarding the whole record.\n continue;\n }\n out[key] = result.value as SpanAttributeValue;\n }\n return Object.freeze(out) as SpanAttributes;\n}\n\n/**\n * @internal\n */\nexport function sanitizeEvents(\n events: SpanRecord['events'],\n validator: RedactionValidatorInstance,\n spanType?: string,\n): SpanRecord['events'] {\n const out: SpanRecord['events'][number][] = [];\n for (const event of events) {\n const sanitizedAttrs = sanitizeAttributes(event.attributes, {}, validator, spanType);\n out.push({ name: event.name, timeUnixNano: event.timeUnixNano, attributes: sanitizedAttrs });\n }\n return out;\n}\n\nfunction readTier(value: SpanAttributeValue | undefined): Sensitivity {\n if (value === 'public' || value === 'internal' || value === 'secret') return value;\n return DEFAULT_ATTR_SENSITIVITY;\n}\n\n/**\n * Quickly check whether an exporter is the result of a previous\n * {@link withValidation} call. The tracer uses this to fail fast at\n * startup.\n *\n * @stable\n */\nexport function isValidatedExporter(exporter: TraceExporter): boolean {\n return exporter[VALIDATED_EXPORTER_BRAND] === true;\n}\n\n/**\n * Pull the counters out of any exporter wrapped by {@link withValidation}.\n * Returns `null` for exporters that were never wrapped.\n *\n * @stable\n */\nexport function tryGetValidatorCounters(validator: RedactionValidatorInstance): RedactionCounters {\n return validator.counters();\n}\n"],"mappings":";;;;AAmBA,MAAMA,2BAAwC;;;;;;;;AAuB9C,SAAgB,eACd,UACA,OAA8B,EAAE,EACjB;CACf,MAAM,YAAY,KAAK,aAAa,yBAAyB,KAAK;AAclE,QAb+B;EAC7B,IAAI,GAAG,SAAS,GAAG;GAClB,2BAA2B;EAC5B,MAAM,OAAO,QAAmC;AAK9C,SAAM,SAAS,OAAO,eAAe,QAAQ,UAAU,CAAC;;EAE1D,aAAa,SAAS,OAAO;EAC7B,gBAAgB,SAAS,UAAU;EACpC;;;;;AAOH,SAAgB,eACd,QACA,WACY;CACZ,MAAM,gBAAgB,OAAO,0BAA0B,EAAE;CAIzD,MAAM,iBAAiB,mBACrB,OAAO,YACP,eACA,WACA,OAAO,KACR;CACD,MAAM,kBAAkB,eAAe,OAAO,QAAQ,WAAW,OAAO,KAAK;AAC7E,QAAO;EACL,GAAG;EACH,YAAY;EACZ,QAAQ;EACT;;;;;AAMH,SAAgB,mBACd,OACA,eACA,WACA,UACgB;CAChB,MAAMC,MAA0C,EAAE;AAClD,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;EAChD,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,MAAM,SAAS,UAAU,SAAS;GAChC;GACA;GACA,SAAS,aAAa,SAAY,EAAE,WAAW,KAAK,GAAG;IAAE,WAAW;IAAK;IAAU;GACpF,CAAC;AACF,MAAI,WAAW,KAIb;AAEF,MAAI,OAAO,OAAO;;AAEpB,QAAO,OAAO,OAAO,IAAI;;;;;AAM3B,SAAgB,eACd,QACA,WACA,UACsB;CACtB,MAAMC,MAAsC,EAAE;AAC9C,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,iBAAiB,mBAAmB,MAAM,YAAY,EAAE,EAAE,WAAW,SAAS;AACpF,MAAI,KAAK;GAAE,MAAM,MAAM;GAAM,cAAc,MAAM;GAAc,YAAY;GAAgB,CAAC;;AAE9F,QAAO;;AAGT,SAAS,SAAS,OAAoD;AACpE,KAAI,UAAU,YAAY,UAAU,cAAc,UAAU,SAAU,QAAO;AAC7E,QAAO;;;;;;;;;AAUT,SAAgB,oBAAoB,UAAkC;AACpE,QAAO,SAAS,8BAA8B;;;;;;;;AAShD,SAAgB,wBAAwB,WAA0D;AAChG,QAAO,UAAU,UAAU"}
@@ -0,0 +1,27 @@
1
+ import { GenAIAttributes, GenAIMessage } from "./types.js";
2
+ import { AISpan, SpanType } from "@graphorin/core";
3
+
4
+ //#region src/gen-ai/emit.d.ts
5
+
6
+ /**
7
+ * Attach the canonical `gen_ai.*` attribute set to a span. The helper
8
+ * is additive on the existing Graphorin-prefixed attributes and applies
9
+ * the per-attribute sensitivity defaults catalogue.
10
+ *
11
+ * @stable
12
+ */
13
+ declare function emitGenAIAttributes<T extends SpanType>(span: AISpan<T>, attrs: GenAIAttributes): void;
14
+ /**
15
+ * Emit per-message OpenTelemetry GenAI span events. The helper records
16
+ * one event per message — the per-message-event emission shape per the
17
+ * OTel semconv discipline (size-bounded individually; safer than the
18
+ * aggregate-attribute shape on large prompts).
19
+ *
20
+ * @stable
21
+ */
22
+ declare function emitGenAIMessageEvents<T extends SpanType>(span: AISpan<T>, messages: ReadonlyArray<GenAIMessage>, opts?: {
23
+ readonly system?: string;
24
+ }): void;
25
+ //#endregion
26
+ export { emitGenAIAttributes, emitGenAIMessageEvents };
27
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","names":[],"sources":["../../src/gen-ai/emit.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;iBAsDgB,8BAA8B,gBACtC,OAAO,WACN;;;;;;;;;iBAoCO,iCAAiC,gBACzC,OAAO,cACH,cAAc"}
@@ -0,0 +1,88 @@
1
+ import { asGraphorinSpan } from "../tracer/tracer.js";
2
+ import { operationNameFor } from "./operation-mapping.js";
3
+
4
+ //#region src/gen-ai/emit.ts
5
+ const PUBLIC_KEY_PREFIXES = [
6
+ "gen_ai.system",
7
+ "gen_ai.request.model",
8
+ "gen_ai.response.model",
9
+ "gen_ai.response.id",
10
+ "gen_ai.response.finish_reasons",
11
+ "gen_ai.usage.input_tokens",
12
+ "gen_ai.usage.output_tokens",
13
+ "gen_ai.tool.name",
14
+ "gen_ai.tool.type",
15
+ "gen_ai.tool.call.id",
16
+ "gen_ai.tool.description",
17
+ "gen_ai.agent.id",
18
+ "gen_ai.agent.name",
19
+ "gen_ai.session.id",
20
+ "gen_ai.operation.name"
21
+ ];
22
+ /**
23
+ * Attach the canonical `gen_ai.*` attribute set to a span. The helper
24
+ * is additive on the existing Graphorin-prefixed attributes and applies
25
+ * the per-attribute sensitivity defaults catalogue.
26
+ *
27
+ * @stable
28
+ */
29
+ function emitGenAIAttributes(span, attrs) {
30
+ const gs = asGraphorinSpan(span);
31
+ const operation = attrs.operation ?? operationNameFor(span.type);
32
+ if (operation !== void 0) setPublic(gs, span, "gen_ai.operation.name", operation);
33
+ if (attrs.system !== void 0) setPublic(gs, span, "gen_ai.system", attrs.system);
34
+ if (attrs.requestModel !== void 0) setPublic(gs, span, "gen_ai.request.model", attrs.requestModel);
35
+ if (attrs.responseModel !== void 0) setPublic(gs, span, "gen_ai.response.model", attrs.responseModel);
36
+ if (attrs.responseId !== void 0) setPublic(gs, span, "gen_ai.response.id", attrs.responseId);
37
+ if (attrs.inputTokens !== void 0) setPublic(gs, span, "gen_ai.usage.input_tokens", attrs.inputTokens);
38
+ if (attrs.outputTokens !== void 0) setPublic(gs, span, "gen_ai.usage.output_tokens", attrs.outputTokens);
39
+ if (attrs.finishReasons !== void 0) setPublic(gs, span, "gen_ai.response.finish_reasons", [...attrs.finishReasons]);
40
+ if (attrs.agentId !== void 0) setPublic(gs, span, "gen_ai.agent.id", attrs.agentId);
41
+ if (attrs.agentName !== void 0) setPublic(gs, span, "gen_ai.agent.name", attrs.agentName);
42
+ if (attrs.sessionId !== void 0) setPublic(gs, span, "gen_ai.session.id", attrs.sessionId);
43
+ if (attrs.toolName !== void 0) setPublic(gs, span, "gen_ai.tool.name", attrs.toolName);
44
+ if (attrs.toolType !== void 0) setPublic(gs, span, "gen_ai.tool.type", attrs.toolType);
45
+ if (attrs.toolCallId !== void 0) setPublic(gs, span, "gen_ai.tool.call.id", attrs.toolCallId);
46
+ if (attrs.toolDescription !== void 0) setPublic(gs, span, "gen_ai.tool.description", attrs.toolDescription);
47
+ }
48
+ /**
49
+ * Emit per-message OpenTelemetry GenAI span events. The helper records
50
+ * one event per message — the per-message-event emission shape per the
51
+ * OTel semconv discipline (size-bounded individually; safer than the
52
+ * aggregate-attribute shape on large prompts).
53
+ *
54
+ * @stable
55
+ */
56
+ function emitGenAIMessageEvents(span, messages, opts = {}) {
57
+ for (const message of messages) span.addEvent(eventNameFor(message.role), buildEventAttrs(message, opts.system));
58
+ }
59
+ function eventNameFor(role) {
60
+ switch (role) {
61
+ case "system": return "gen_ai.system.message";
62
+ case "user": return "gen_ai.user.message";
63
+ case "assistant": return "gen_ai.assistant.message";
64
+ case "tool": return "gen_ai.tool.message";
65
+ }
66
+ }
67
+ function buildEventAttrs(message, system) {
68
+ const out = {
69
+ "gen_ai.message.role": message.role,
70
+ content: message.content
71
+ };
72
+ if (system !== void 0) out["gen_ai.system"] = system;
73
+ if (message.name !== void 0) out["gen_ai.message.name"] = message.name;
74
+ if (message.toolCallId !== void 0) out["gen_ai.tool.call.id"] = message.toolCallId;
75
+ if (message.toolCalls !== void 0 && message.toolCalls.length > 0) out["gen_ai.tool.calls"] = JSON.stringify(message.toolCalls);
76
+ return Object.freeze(out);
77
+ }
78
+ function setPublic(gs, span, key, value) {
79
+ if (gs !== null && PUBLIC_KEY_PREFIXES.some((prefix) => key === prefix || key.startsWith(`${prefix}.`))) {
80
+ gs.setAttribute(key, value, { sensitivity: "public" });
81
+ return;
82
+ }
83
+ span.setAttributes({ [key]: value });
84
+ }
85
+
86
+ //#endregion
87
+ export { emitGenAIAttributes, emitGenAIMessageEvents };
88
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","names":["out: Record<string, SpanAttributeValue>"],"sources":["../../src/gen-ai/emit.ts"],"sourcesContent":["/**\n * Emission helpers that attach OpenTelemetry GenAI semantic-convention\n * attributes / events to an existing span.\n *\n * The helpers are deliberately additive — they NEVER remove or rename\n * existing attributes. The new `gen_ai.*` family sits on top of the\n * Graphorin-prefixed family. Sensitivity defaults follow the catalogue\n * documented alongside the canonical mapping table:\n *\n * - `gen_ai.system` / `gen_ai.request.model` / `gen_ai.response.model` /\n * `gen_ai.response.id` / `gen_ai.usage.{input,output}_tokens` /\n * `gen_ai.response.finish_reasons` / `gen_ai.tool.{name,type,call.id,description}` /\n * `gen_ai.agent.{id,name}` / `gen_ai.session.id` /\n * `gen_ai.operation.name` → `'public'`\n * - `gen_ai.request.messages` / per-message events / `gen_ai.response.content`\n * → `'internal'` (default-deny non-public per DEC-141)\n * - `gen_ai.tool.output` → inherits per-tool `Tool.sensitivity`\n *\n * @packageDocumentation\n */\n\nimport type { AISpan, SpanAttributes, SpanAttributeValue, SpanType } from '@graphorin/core';\n\nimport type { GraphorinSpan } from '../tracer/span.js';\nimport { asGraphorinSpan } from '../tracer/tracer.js';\n\nimport { operationNameFor } from './operation-mapping.js';\nimport type { GenAIAttributes, GenAIMessage, GenAIMessageRole } from './types.js';\n\nconst PUBLIC_KEY_PREFIXES = [\n 'gen_ai.system',\n 'gen_ai.request.model',\n 'gen_ai.response.model',\n 'gen_ai.response.id',\n 'gen_ai.response.finish_reasons',\n 'gen_ai.usage.input_tokens',\n 'gen_ai.usage.output_tokens',\n 'gen_ai.tool.name',\n 'gen_ai.tool.type',\n 'gen_ai.tool.call.id',\n 'gen_ai.tool.description',\n 'gen_ai.agent.id',\n 'gen_ai.agent.name',\n 'gen_ai.session.id',\n 'gen_ai.operation.name',\n] as const;\n\n/**\n * Attach the canonical `gen_ai.*` attribute set to a span. The helper\n * is additive on the existing Graphorin-prefixed attributes and applies\n * the per-attribute sensitivity defaults catalogue.\n *\n * @stable\n */\nexport function emitGenAIAttributes<T extends SpanType>(\n span: AISpan<T>,\n attrs: GenAIAttributes,\n): void {\n const gs = asGraphorinSpan(span);\n const operation = attrs.operation ?? operationNameFor(span.type);\n if (operation !== undefined) setPublic(gs, span, 'gen_ai.operation.name', operation);\n\n if (attrs.system !== undefined) setPublic(gs, span, 'gen_ai.system', attrs.system);\n if (attrs.requestModel !== undefined)\n setPublic(gs, span, 'gen_ai.request.model', attrs.requestModel);\n if (attrs.responseModel !== undefined)\n setPublic(gs, span, 'gen_ai.response.model', attrs.responseModel);\n if (attrs.responseId !== undefined) setPublic(gs, span, 'gen_ai.response.id', attrs.responseId);\n if (attrs.inputTokens !== undefined)\n setPublic(gs, span, 'gen_ai.usage.input_tokens', attrs.inputTokens);\n if (attrs.outputTokens !== undefined)\n setPublic(gs, span, 'gen_ai.usage.output_tokens', attrs.outputTokens);\n if (attrs.finishReasons !== undefined)\n setPublic(gs, span, 'gen_ai.response.finish_reasons', [...attrs.finishReasons]);\n if (attrs.agentId !== undefined) setPublic(gs, span, 'gen_ai.agent.id', attrs.agentId);\n if (attrs.agentName !== undefined) setPublic(gs, span, 'gen_ai.agent.name', attrs.agentName);\n if (attrs.sessionId !== undefined) setPublic(gs, span, 'gen_ai.session.id', attrs.sessionId);\n if (attrs.toolName !== undefined) setPublic(gs, span, 'gen_ai.tool.name', attrs.toolName);\n if (attrs.toolType !== undefined) setPublic(gs, span, 'gen_ai.tool.type', attrs.toolType);\n if (attrs.toolCallId !== undefined) setPublic(gs, span, 'gen_ai.tool.call.id', attrs.toolCallId);\n if (attrs.toolDescription !== undefined)\n setPublic(gs, span, 'gen_ai.tool.description', attrs.toolDescription);\n}\n\n/**\n * Emit per-message OpenTelemetry GenAI span events. The helper records\n * one event per message — the per-message-event emission shape per the\n * OTel semconv discipline (size-bounded individually; safer than the\n * aggregate-attribute shape on large prompts).\n *\n * @stable\n */\nexport function emitGenAIMessageEvents<T extends SpanType>(\n span: AISpan<T>,\n messages: ReadonlyArray<GenAIMessage>,\n opts: { readonly system?: string } = {},\n): void {\n for (const message of messages) {\n span.addEvent(eventNameFor(message.role), buildEventAttrs(message, opts.system));\n }\n}\n\nfunction eventNameFor(role: GenAIMessageRole): string {\n switch (role) {\n case 'system':\n return 'gen_ai.system.message';\n case 'user':\n return 'gen_ai.user.message';\n case 'assistant':\n return 'gen_ai.assistant.message';\n case 'tool':\n return 'gen_ai.tool.message';\n }\n}\n\nfunction buildEventAttrs(message: GenAIMessage, system?: string): SpanAttributes {\n const out: Record<string, SpanAttributeValue> = {\n 'gen_ai.message.role': message.role,\n content: message.content,\n };\n if (system !== undefined) out['gen_ai.system'] = system;\n if (message.name !== undefined) out['gen_ai.message.name'] = message.name;\n if (message.toolCallId !== undefined) out['gen_ai.tool.call.id'] = message.toolCallId;\n if (message.toolCalls !== undefined && message.toolCalls.length > 0) {\n out['gen_ai.tool.calls'] = JSON.stringify(message.toolCalls);\n }\n return Object.freeze(out) as SpanAttributes;\n}\n\nfunction setPublic(\n gs: GraphorinSpan | null,\n span: AISpan,\n key: string,\n value: SpanAttributeValue,\n): void {\n if (\n gs !== null &&\n PUBLIC_KEY_PREFIXES.some((prefix) => key === prefix || key.startsWith(`${prefix}.`))\n ) {\n gs.setAttribute(key, value, { sensitivity: 'public' });\n return;\n }\n span.setAttributes({ [key]: value });\n}\n"],"mappings":";;;;AA6BA,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;AASD,SAAgB,oBACd,MACA,OACM;CACN,MAAM,KAAK,gBAAgB,KAAK;CAChC,MAAM,YAAY,MAAM,aAAa,iBAAiB,KAAK,KAAK;AAChE,KAAI,cAAc,OAAW,WAAU,IAAI,MAAM,yBAAyB,UAAU;AAEpF,KAAI,MAAM,WAAW,OAAW,WAAU,IAAI,MAAM,iBAAiB,MAAM,OAAO;AAClF,KAAI,MAAM,iBAAiB,OACzB,WAAU,IAAI,MAAM,wBAAwB,MAAM,aAAa;AACjE,KAAI,MAAM,kBAAkB,OAC1B,WAAU,IAAI,MAAM,yBAAyB,MAAM,cAAc;AACnE,KAAI,MAAM,eAAe,OAAW,WAAU,IAAI,MAAM,sBAAsB,MAAM,WAAW;AAC/F,KAAI,MAAM,gBAAgB,OACxB,WAAU,IAAI,MAAM,6BAA6B,MAAM,YAAY;AACrE,KAAI,MAAM,iBAAiB,OACzB,WAAU,IAAI,MAAM,8BAA8B,MAAM,aAAa;AACvE,KAAI,MAAM,kBAAkB,OAC1B,WAAU,IAAI,MAAM,kCAAkC,CAAC,GAAG,MAAM,cAAc,CAAC;AACjF,KAAI,MAAM,YAAY,OAAW,WAAU,IAAI,MAAM,mBAAmB,MAAM,QAAQ;AACtF,KAAI,MAAM,cAAc,OAAW,WAAU,IAAI,MAAM,qBAAqB,MAAM,UAAU;AAC5F,KAAI,MAAM,cAAc,OAAW,WAAU,IAAI,MAAM,qBAAqB,MAAM,UAAU;AAC5F,KAAI,MAAM,aAAa,OAAW,WAAU,IAAI,MAAM,oBAAoB,MAAM,SAAS;AACzF,KAAI,MAAM,aAAa,OAAW,WAAU,IAAI,MAAM,oBAAoB,MAAM,SAAS;AACzF,KAAI,MAAM,eAAe,OAAW,WAAU,IAAI,MAAM,uBAAuB,MAAM,WAAW;AAChG,KAAI,MAAM,oBAAoB,OAC5B,WAAU,IAAI,MAAM,2BAA2B,MAAM,gBAAgB;;;;;;;;;;AAWzE,SAAgB,uBACd,MACA,UACA,OAAqC,EAAE,EACjC;AACN,MAAK,MAAM,WAAW,SACpB,MAAK,SAAS,aAAa,QAAQ,KAAK,EAAE,gBAAgB,SAAS,KAAK,OAAO,CAAC;;AAIpF,SAAS,aAAa,MAAgC;AACpD,SAAQ,MAAR;EACE,KAAK,SACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,KAAK,OACH,QAAO;;;AAIb,SAAS,gBAAgB,SAAuB,QAAiC;CAC/E,MAAMA,MAA0C;EAC9C,uBAAuB,QAAQ;EAC/B,SAAS,QAAQ;EAClB;AACD,KAAI,WAAW,OAAW,KAAI,mBAAmB;AACjD,KAAI,QAAQ,SAAS,OAAW,KAAI,yBAAyB,QAAQ;AACrE,KAAI,QAAQ,eAAe,OAAW,KAAI,yBAAyB,QAAQ;AAC3E,KAAI,QAAQ,cAAc,UAAa,QAAQ,UAAU,SAAS,EAChE,KAAI,uBAAuB,KAAK,UAAU,QAAQ,UAAU;AAE9D,QAAO,OAAO,OAAO,IAAI;;AAG3B,SAAS,UACP,IACA,MACA,KACA,OACM;AACN,KACE,OAAO,QACP,oBAAoB,MAAM,WAAW,QAAQ,UAAU,IAAI,WAAW,GAAG,OAAO,GAAG,CAAC,EACpF;AACA,KAAG,aAAa,KAAK,OAAO,EAAE,aAAa,UAAU,CAAC;AACtD;;AAEF,MAAK,cAAc,GAAG,MAAM,OAAO,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { GenAIAttributes, GenAIMessage, GenAIMessageRole, GenAIOperationName, GenAISystem, GenAIToolType, SpanTypeToOperationName } from "./types.js";
2
+ import { emitGenAIAttributes, emitGenAIMessageEvents } from "./emit.js";
3
+ import { OPERATION_NAME_TABLE, operationNameFor } from "./operation-mapping.js";
4
+ import { PROVIDER_CLASS_TO_GEN_AI_SYSTEM, _resetGenAISystemWarningsForTesting, deriveGenAISystem, setGenAISystemWarnSink } from "./system-derivation.js";
5
+ export { type GenAIAttributes, type GenAIMessage, type GenAIMessageRole, type GenAIOperationName, type GenAISystem, type GenAIToolType, OPERATION_NAME_TABLE, PROVIDER_CLASS_TO_GEN_AI_SYSTEM, type SpanTypeToOperationName, _resetGenAISystemWarningsForTesting, deriveGenAISystem, emitGenAIAttributes, emitGenAIMessageEvents, operationNameFor, setGenAISystemWarnSink };
@@ -0,0 +1,5 @@
1
+ import { OPERATION_NAME_TABLE, operationNameFor } from "./operation-mapping.js";
2
+ import { emitGenAIAttributes, emitGenAIMessageEvents } from "./emit.js";
3
+ import { PROVIDER_CLASS_TO_GEN_AI_SYSTEM, _resetGenAISystemWarningsForTesting, deriveGenAISystem, setGenAISystemWarnSink } from "./system-derivation.js";
4
+
5
+ export { OPERATION_NAME_TABLE, PROVIDER_CLASS_TO_GEN_AI_SYSTEM, _resetGenAISystemWarningsForTesting, deriveGenAISystem, emitGenAIAttributes, emitGenAIMessageEvents, operationNameFor, setGenAISystemWarnSink };
@@ -0,0 +1,24 @@
1
+ import { GenAIOperationName } from "./types.js";
2
+ import { SpanType } from "@graphorin/core";
3
+
4
+ //#region src/gen-ai/operation-mapping.d.ts
5
+
6
+ /**
7
+ * Resolve the canonical `gen_ai.operation.name` value for a Graphorin
8
+ * span type. Returns `undefined` if no mapping exists (e.g. for
9
+ * `replay.*` markers, which are emitted via a separate code path).
10
+ *
11
+ * @stable
12
+ */
13
+ declare function operationNameFor(type: SpanType): GenAIOperationName | undefined;
14
+ /**
15
+ * Full canonical span-to-operation table — exposed for tooling
16
+ * (documentation generators, fixture tests) that need to introspect
17
+ * the mapping.
18
+ *
19
+ * @stable
20
+ */
21
+ declare const OPERATION_NAME_TABLE: ReadonlyArray<readonly [SpanType, GenAIOperationName]>;
22
+ //#endregion
23
+ export { OPERATION_NAME_TABLE, operationNameFor };
24
+ //# sourceMappingURL=operation-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-mapping.d.ts","names":[],"sources":["../../src/gen-ai/operation-mapping.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;iBA0EgB,gBAAA,OAAuB,WAAW;;;;;;;;cAWrC,sBAAsB,wBAAwB,UAAU"}
@@ -0,0 +1,67 @@
1
+ //#region src/gen-ai/operation-mapping.ts
2
+ const TABLE = Object.freeze([
3
+ ["agent.run", "agent.run"],
4
+ ["agent.step", "agent.step"],
5
+ ["agent.handoff", "agent.handoff"],
6
+ ["agent.suspend", "agent.suspend"],
7
+ ["agent.resume", "agent.resume"],
8
+ ["provider.generate", "chat"],
9
+ ["provider.stream", "chat"],
10
+ ["tool.execute", "execute_tool"],
11
+ ["tool.approval", "execute_tool"],
12
+ ["memory.read.working", "memory.read"],
13
+ ["memory.read.session", "memory.read"],
14
+ ["memory.read.episodic", "memory.read"],
15
+ ["memory.read.semantic", "memory.read"],
16
+ ["memory.read.procedural", "memory.read"],
17
+ ["memory.read.shared", "memory.read"],
18
+ ["memory.write.working", "memory.write"],
19
+ ["memory.write.session", "memory.write"],
20
+ ["memory.write.episodic", "memory.write"],
21
+ ["memory.write.semantic", "memory.write"],
22
+ ["memory.write.procedural", "memory.write"],
23
+ ["memory.write.shared", "memory.write"],
24
+ ["memory.search.working", "memory.search"],
25
+ ["memory.search.session", "memory.search"],
26
+ ["memory.search.episodic", "memory.search"],
27
+ ["memory.search.semantic", "memory.search"],
28
+ ["memory.search.procedural", "memory.search"],
29
+ ["memory.search.shared", "memory.search"],
30
+ ["memory.consolidate.light", "memory.consolidate"],
31
+ ["memory.consolidate.standard", "memory.consolidate"],
32
+ ["memory.consolidate.deep", "memory.consolidate"],
33
+ ["memory.conflict", "memory.conflict"],
34
+ ["memory.embed", "embedding"],
35
+ ["workflow.run", "workflow.run"],
36
+ ["workflow.step", "workflow.step"],
37
+ ["workflow.task", "workflow.task"],
38
+ ["workflow.checkpoint", "workflow.checkpoint"],
39
+ ["skill.activate", "skill.activate"],
40
+ ["skill.load", "skill.load"],
41
+ ["mcp.connect", "mcp.connect"],
42
+ ["mcp.call", "mcp.call"],
43
+ ["mcp.list-tools", "mcp.list-tools"]
44
+ ]);
45
+ const LOOKUP = new Map(TABLE);
46
+ /**
47
+ * Resolve the canonical `gen_ai.operation.name` value for a Graphorin
48
+ * span type. Returns `undefined` if no mapping exists (e.g. for
49
+ * `replay.*` markers, which are emitted via a separate code path).
50
+ *
51
+ * @stable
52
+ */
53
+ function operationNameFor(type) {
54
+ return LOOKUP.get(type);
55
+ }
56
+ /**
57
+ * Full canonical span-to-operation table — exposed for tooling
58
+ * (documentation generators, fixture tests) that need to introspect
59
+ * the mapping.
60
+ *
61
+ * @stable
62
+ */
63
+ const OPERATION_NAME_TABLE = TABLE;
64
+
65
+ //#endregion
66
+ export { OPERATION_NAME_TABLE, operationNameFor };
67
+ //# sourceMappingURL=operation-mapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-mapping.js","names":["TABLE: ReadonlyArray<readonly [SpanType, GenAIOperationName]>","OPERATION_NAME_TABLE: ReadonlyArray<readonly [SpanType, GenAIOperationName]>"],"sources":["../../src/gen-ai/operation-mapping.ts"],"sourcesContent":["/**\n * Mapping table from Graphorin `SpanType` values to canonical\n * `gen_ai.operation.name` enum values.\n *\n * The table mirrors the canonical-mapping reference table published\n * in the architecture documentation and is the authoritative source\n * for the `emitGenAIAttributes` helper.\n *\n * @packageDocumentation\n */\n\nimport type { SpanType } from '@graphorin/core';\n\nimport type { GenAIOperationName } from './types.js';\n\nconst TABLE: ReadonlyArray<readonly [SpanType, GenAIOperationName]> = Object.freeze([\n ['agent.run', 'agent.run'],\n ['agent.step', 'agent.step'],\n ['agent.handoff', 'agent.handoff'],\n ['agent.suspend', 'agent.suspend'],\n ['agent.resume', 'agent.resume'],\n\n ['provider.generate', 'chat'],\n ['provider.stream', 'chat'],\n\n ['tool.execute', 'execute_tool'],\n ['tool.approval', 'execute_tool'],\n\n ['memory.read.working', 'memory.read'],\n ['memory.read.session', 'memory.read'],\n ['memory.read.episodic', 'memory.read'],\n ['memory.read.semantic', 'memory.read'],\n ['memory.read.procedural', 'memory.read'],\n ['memory.read.shared', 'memory.read'],\n ['memory.write.working', 'memory.write'],\n ['memory.write.session', 'memory.write'],\n ['memory.write.episodic', 'memory.write'],\n ['memory.write.semantic', 'memory.write'],\n ['memory.write.procedural', 'memory.write'],\n ['memory.write.shared', 'memory.write'],\n ['memory.search.working', 'memory.search'],\n ['memory.search.session', 'memory.search'],\n ['memory.search.episodic', 'memory.search'],\n ['memory.search.semantic', 'memory.search'],\n ['memory.search.procedural', 'memory.search'],\n ['memory.search.shared', 'memory.search'],\n ['memory.consolidate.light', 'memory.consolidate'],\n ['memory.consolidate.standard', 'memory.consolidate'],\n ['memory.consolidate.deep', 'memory.consolidate'],\n ['memory.conflict', 'memory.conflict'],\n ['memory.embed', 'embedding'],\n\n ['workflow.run', 'workflow.run'],\n ['workflow.step', 'workflow.step'],\n ['workflow.task', 'workflow.task'],\n ['workflow.checkpoint', 'workflow.checkpoint'],\n\n ['skill.activate', 'skill.activate'],\n ['skill.load', 'skill.load'],\n\n ['mcp.connect', 'mcp.connect'],\n ['mcp.call', 'mcp.call'],\n ['mcp.list-tools', 'mcp.list-tools'],\n] as const);\n\nconst LOOKUP = new Map<SpanType, GenAIOperationName>(TABLE);\n\n/**\n * Resolve the canonical `gen_ai.operation.name` value for a Graphorin\n * span type. Returns `undefined` if no mapping exists (e.g. for\n * `replay.*` markers, which are emitted via a separate code path).\n *\n * @stable\n */\nexport function operationNameFor(type: SpanType): GenAIOperationName | undefined {\n return LOOKUP.get(type);\n}\n\n/**\n * Full canonical span-to-operation table — exposed for tooling\n * (documentation generators, fixture tests) that need to introspect\n * the mapping.\n *\n * @stable\n */\nexport const OPERATION_NAME_TABLE: ReadonlyArray<readonly [SpanType, GenAIOperationName]> = TABLE;\n"],"mappings":";AAeA,MAAMA,QAAgE,OAAO,OAAO;CAClF,CAAC,aAAa,YAAY;CAC1B,CAAC,cAAc,aAAa;CAC5B,CAAC,iBAAiB,gBAAgB;CAClC,CAAC,iBAAiB,gBAAgB;CAClC,CAAC,gBAAgB,eAAe;CAEhC,CAAC,qBAAqB,OAAO;CAC7B,CAAC,mBAAmB,OAAO;CAE3B,CAAC,gBAAgB,eAAe;CAChC,CAAC,iBAAiB,eAAe;CAEjC,CAAC,uBAAuB,cAAc;CACtC,CAAC,uBAAuB,cAAc;CACtC,CAAC,wBAAwB,cAAc;CACvC,CAAC,wBAAwB,cAAc;CACvC,CAAC,0BAA0B,cAAc;CACzC,CAAC,sBAAsB,cAAc;CACrC,CAAC,wBAAwB,eAAe;CACxC,CAAC,wBAAwB,eAAe;CACxC,CAAC,yBAAyB,eAAe;CACzC,CAAC,yBAAyB,eAAe;CACzC,CAAC,2BAA2B,eAAe;CAC3C,CAAC,uBAAuB,eAAe;CACvC,CAAC,yBAAyB,gBAAgB;CAC1C,CAAC,yBAAyB,gBAAgB;CAC1C,CAAC,0BAA0B,gBAAgB;CAC3C,CAAC,0BAA0B,gBAAgB;CAC3C,CAAC,4BAA4B,gBAAgB;CAC7C,CAAC,wBAAwB,gBAAgB;CACzC,CAAC,4BAA4B,qBAAqB;CAClD,CAAC,+BAA+B,qBAAqB;CACrD,CAAC,2BAA2B,qBAAqB;CACjD,CAAC,mBAAmB,kBAAkB;CACtC,CAAC,gBAAgB,YAAY;CAE7B,CAAC,gBAAgB,eAAe;CAChC,CAAC,iBAAiB,gBAAgB;CAClC,CAAC,iBAAiB,gBAAgB;CAClC,CAAC,uBAAuB,sBAAsB;CAE9C,CAAC,kBAAkB,iBAAiB;CACpC,CAAC,cAAc,aAAa;CAE5B,CAAC,eAAe,cAAc;CAC9B,CAAC,YAAY,WAAW;CACxB,CAAC,kBAAkB,iBAAiB;CACrC,CAAU;AAEX,MAAM,SAAS,IAAI,IAAkC,MAAM;;;;;;;;AAS3D,SAAgB,iBAAiB,MAAgD;AAC/E,QAAO,OAAO,IAAI,KAAK;;;;;;;;;AAUzB,MAAaC,uBAA+E"}
@@ -0,0 +1,41 @@
1
+ import { GenAISystem } from "./types.js";
2
+
3
+ //#region src/gen-ai/system-derivation.d.ts
4
+
5
+ /**
6
+ * Canonical mapping from a provider class name (or substring) to the
7
+ * `gen_ai.system` enum value. The table is an export so consumers
8
+ * (e.g. provider adapters in Phase 06) can introspect or extend it.
9
+ *
10
+ * @stable
11
+ */
12
+ declare const PROVIDER_CLASS_TO_GEN_AI_SYSTEM: ReadonlyArray<readonly [RegExp, GenAISystem]>;
13
+ /**
14
+ * Override the WARN-once sink used for unrecognised provider class
15
+ * names. Useful in tests so the suite does not pollute stderr.
16
+ *
17
+ * @internal
18
+ */
19
+ declare function setGenAISystemWarnSink(sink: (line: string) => void): void;
20
+ /**
21
+ * Reset the WARN-once cache. Test-only.
22
+ *
23
+ * @internal
24
+ */
25
+ declare function _resetGenAISystemWarningsForTesting(): void;
26
+ /**
27
+ * Derive the canonical `gen_ai.system` value from a provider class
28
+ * name. Returns `null` when the name does not match any known
29
+ * pattern; callers should declare `Provider.genAiSystem` explicitly
30
+ * in that case.
31
+ *
32
+ * The first time an unknown class name is seen, the function emits
33
+ * one structured WARN line to the configured sink so operators
34
+ * notice the gap. Subsequent lookups for the same class are silent.
35
+ *
36
+ * @stable
37
+ */
38
+ declare function deriveGenAISystem(providerClassName: string): GenAISystem | null;
39
+ //#endregion
40
+ export { PROVIDER_CLASS_TO_GEN_AI_SYSTEM, _resetGenAISystemWarningsForTesting, deriveGenAISystem, setGenAISystemWarnSink };
41
+ //# sourceMappingURL=system-derivation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-derivation.d.ts","names":[],"sources":["../../src/gen-ai/system-derivation.ts"],"sourcesContent":[],"mappings":";;;;;;AAwCA;AASA;AAgBA;;;cAlDa,iCAAiC,wBAAwB,QAAQ;;;;;;;iBAyB9D,sBAAA;;;;;;iBASA,mCAAA,CAAA;;;;;;;;;;;;;iBAgBA,iBAAA,6BAA8C"}
@@ -0,0 +1,67 @@
1
+ //#region src/gen-ai/system-derivation.ts
2
+ /**
3
+ * Canonical mapping from a provider class name (or substring) to the
4
+ * `gen_ai.system` enum value. The table is an export so consumers
5
+ * (e.g. provider adapters in Phase 06) can introspect or extend it.
6
+ *
7
+ * @stable
8
+ */
9
+ const PROVIDER_CLASS_TO_GEN_AI_SYSTEM = Object.freeze([
10
+ [/anthropic/i, "anthropic"],
11
+ [/openai(?!compat)/i, "openai"],
12
+ [/google|gemini/i, "google"],
13
+ [/mistral/i, "mistral"],
14
+ [/ollama/i, "ollama"],
15
+ [/openrouter/i, "openrouter"],
16
+ [/azure/i, "azure_ai_inference"],
17
+ [/bedrock|aws/i, "aws.bedrock"],
18
+ [/cohere/i, "cohere"],
19
+ [/vertex/i, "vertex_ai"],
20
+ [/llamacpp|llama-cpp|llama_cpp/i, "graphorin-llamacpp"],
21
+ [/openaicompatible|openai-compatible/i, "graphorin-openai-compatible"]
22
+ ]);
23
+ const WARNED_CLASSES = /* @__PURE__ */ new Set();
24
+ let WARN_SINK = (line) => console.warn(line);
25
+ /**
26
+ * Override the WARN-once sink used for unrecognised provider class
27
+ * names. Useful in tests so the suite does not pollute stderr.
28
+ *
29
+ * @internal
30
+ */
31
+ function setGenAISystemWarnSink(sink) {
32
+ WARN_SINK = sink;
33
+ }
34
+ /**
35
+ * Reset the WARN-once cache. Test-only.
36
+ *
37
+ * @internal
38
+ */
39
+ function _resetGenAISystemWarningsForTesting() {
40
+ WARNED_CLASSES.clear();
41
+ }
42
+ /**
43
+ * Derive the canonical `gen_ai.system` value from a provider class
44
+ * name. Returns `null` when the name does not match any known
45
+ * pattern; callers should declare `Provider.genAiSystem` explicitly
46
+ * in that case.
47
+ *
48
+ * The first time an unknown class name is seen, the function emits
49
+ * one structured WARN line to the configured sink so operators
50
+ * notice the gap. Subsequent lookups for the same class are silent.
51
+ *
52
+ * @stable
53
+ */
54
+ function deriveGenAISystem(providerClassName) {
55
+ for (const [regex, system] of PROVIDER_CLASS_TO_GEN_AI_SYSTEM) if (regex.test(providerClassName)) return system;
56
+ warnOnce(providerClassName);
57
+ return null;
58
+ }
59
+ function warnOnce(providerClassName) {
60
+ if (WARNED_CLASSES.has(providerClassName)) return;
61
+ WARNED_CLASSES.add(providerClassName);
62
+ WARN_SINK(`[graphorin/observability] WARN: provider class "${providerClassName}" is not in the auto-derivation table for \`gen_ai.system\`. Declare \`Provider.genAiSystem\` explicitly on the adapter so OpenTelemetry GenAI dashboards attribute the spans correctly. See \`@graphorin/observability/gen-ai\` and the OpenTelemetry GenAI semantic conventions for the canonical vendor enum.`);
63
+ }
64
+
65
+ //#endregion
66
+ export { PROVIDER_CLASS_TO_GEN_AI_SYSTEM, _resetGenAISystemWarningsForTesting, deriveGenAISystem, setGenAISystemWarnSink };
67
+ //# sourceMappingURL=system-derivation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-derivation.js","names":["PROVIDER_CLASS_TO_GEN_AI_SYSTEM: ReadonlyArray<readonly [RegExp, GenAISystem]>","WARN_SINK: (line: string) => void"],"sources":["../../src/gen-ai/system-derivation.ts"],"sourcesContent":["/**\n * Auto-derivation lookup table for the `gen_ai.system` attribute.\n *\n * @packageDocumentation\n */\n\nimport type { GenAISystem } from './types.js';\n\n/**\n * Canonical mapping from a provider class name (or substring) to the\n * `gen_ai.system` enum value. The table is an export so consumers\n * (e.g. provider adapters in Phase 06) can introspect or extend it.\n *\n * @stable\n */\nexport const PROVIDER_CLASS_TO_GEN_AI_SYSTEM: ReadonlyArray<readonly [RegExp, GenAISystem]> =\n Object.freeze([\n [/anthropic/i, 'anthropic'],\n [/openai(?!compat)/i, 'openai'],\n [/google|gemini/i, 'google'],\n [/mistral/i, 'mistral'],\n [/ollama/i, 'ollama'],\n [/openrouter/i, 'openrouter'],\n [/azure/i, 'azure_ai_inference'],\n [/bedrock|aws/i, 'aws.bedrock'],\n [/cohere/i, 'cohere'],\n [/vertex/i, 'vertex_ai'],\n [/llamacpp|llama-cpp|llama_cpp/i, 'graphorin-llamacpp'],\n [/openaicompatible|openai-compatible/i, 'graphorin-openai-compatible'],\n ] as const);\n\nconst WARNED_CLASSES = new Set<string>();\nlet WARN_SINK: (line: string) => void = (line) => console.warn(line);\n\n/**\n * Override the WARN-once sink used for unrecognised provider class\n * names. Useful in tests so the suite does not pollute stderr.\n *\n * @internal\n */\nexport function setGenAISystemWarnSink(sink: (line: string) => void): void {\n WARN_SINK = sink;\n}\n\n/**\n * Reset the WARN-once cache. Test-only.\n *\n * @internal\n */\nexport function _resetGenAISystemWarningsForTesting(): void {\n WARNED_CLASSES.clear();\n}\n\n/**\n * Derive the canonical `gen_ai.system` value from a provider class\n * name. Returns `null` when the name does not match any known\n * pattern; callers should declare `Provider.genAiSystem` explicitly\n * in that case.\n *\n * The first time an unknown class name is seen, the function emits\n * one structured WARN line to the configured sink so operators\n * notice the gap. Subsequent lookups for the same class are silent.\n *\n * @stable\n */\nexport function deriveGenAISystem(providerClassName: string): GenAISystem | null {\n for (const [regex, system] of PROVIDER_CLASS_TO_GEN_AI_SYSTEM) {\n if (regex.test(providerClassName)) return system;\n }\n warnOnce(providerClassName);\n return null;\n}\n\nfunction warnOnce(providerClassName: string): void {\n if (WARNED_CLASSES.has(providerClassName)) return;\n WARNED_CLASSES.add(providerClassName);\n WARN_SINK(\n `[graphorin/observability] WARN: provider class \"${providerClassName}\" is not in ` +\n 'the auto-derivation table for `gen_ai.system`. Declare `Provider.genAiSystem` ' +\n 'explicitly on the adapter so OpenTelemetry GenAI dashboards attribute the spans ' +\n 'correctly. See `@graphorin/observability/gen-ai` and the OpenTelemetry GenAI ' +\n 'semantic conventions for the canonical vendor enum.',\n );\n}\n"],"mappings":";;;;;;;;AAeA,MAAaA,kCACX,OAAO,OAAO;CACZ,CAAC,cAAc,YAAY;CAC3B,CAAC,qBAAqB,SAAS;CAC/B,CAAC,kBAAkB,SAAS;CAC5B,CAAC,YAAY,UAAU;CACvB,CAAC,WAAW,SAAS;CACrB,CAAC,eAAe,aAAa;CAC7B,CAAC,UAAU,qBAAqB;CAChC,CAAC,gBAAgB,cAAc;CAC/B,CAAC,WAAW,SAAS;CACrB,CAAC,WAAW,YAAY;CACxB,CAAC,iCAAiC,qBAAqB;CACvD,CAAC,uCAAuC,8BAA8B;CACvE,CAAU;AAEb,MAAM,iCAAiB,IAAI,KAAa;AACxC,IAAIC,aAAqC,SAAS,QAAQ,KAAK,KAAK;;;;;;;AAQpE,SAAgB,uBAAuB,MAAoC;AACzE,aAAY;;;;;;;AAQd,SAAgB,sCAA4C;AAC1D,gBAAe,OAAO;;;;;;;;;;;;;;AAexB,SAAgB,kBAAkB,mBAA+C;AAC/E,MAAK,MAAM,CAAC,OAAO,WAAW,gCAC5B,KAAI,MAAM,KAAK,kBAAkB,CAAE,QAAO;AAE5C,UAAS,kBAAkB;AAC3B,QAAO;;AAGT,SAAS,SAAS,mBAAiC;AACjD,KAAI,eAAe,IAAI,kBAAkB,CAAE;AAC3C,gBAAe,IAAI,kBAAkB;AACrC,WACE,mDAAmD,kBAAkB,kTAKtE"}
@@ -0,0 +1,87 @@
1
+ import { SpanType } from "@graphorin/core";
2
+
3
+ //#region src/gen-ai/types.d.ts
4
+
5
+ /**
6
+ * Canonical OpenTelemetry semantic-conventions vendor enum used as the
7
+ * value of the `gen_ai.system` attribute.
8
+ *
9
+ * @stable
10
+ */
11
+ type GenAISystem = 'anthropic' | 'openai' | 'google' | 'mistral' | 'ollama' | 'openrouter' | 'azure_ai_inference' | 'aws.bedrock' | 'cohere' | 'vertex_ai' | 'graphorin-llamacpp' | 'graphorin-openai-compatible' | (string & {
12
+ readonly __genAiSystem?: never;
13
+ });
14
+ /**
15
+ * `gen_ai.tool.type` enum value. Defaults to `'function'` for
16
+ * user-defined and MCP-derived tools without explicit declaration.
17
+ *
18
+ * @stable
19
+ */
20
+ type GenAIToolType = 'function' | 'web_search' | 'database' | 'code_interpreter' | 'image_generation' | 'file_search';
21
+ /**
22
+ * Canonical `gen_ai.operation.name` enum used per the OpenTelemetry
23
+ * GenAI semantic conventions for AI agent + framework spans.
24
+ *
25
+ * @stable
26
+ */
27
+ type GenAIOperationName = 'agent.run' | 'agent.step' | 'agent.handoff' | 'agent.suspend' | 'agent.resume' | 'agent.fanout.spawned' | 'agent.fanout.merged' | 'agent.evaluator.iteration' | 'chat' | 'embedding' | 'execute_tool' | 'memory.read' | 'memory.write' | 'memory.search' | 'memory.consolidate' | 'memory.conflict' | 'workflow.run' | 'workflow.step' | 'workflow.task' | 'workflow.checkpoint' | 'mcp.connect' | 'mcp.call' | 'mcp.list-tools' | 'skill.activate' | 'skill.load' | 'replay.run' | 'replay.skipped';
28
+ /**
29
+ * Per-message event type used by {@link emitGenAIMessageEvents}.
30
+ *
31
+ * @stable
32
+ */
33
+ type GenAIMessageRole = 'system' | 'user' | 'assistant' | 'tool';
34
+ /**
35
+ * Single per-message record passed to {@link emitGenAIMessageEvents}.
36
+ *
37
+ * @stable
38
+ */
39
+ interface GenAIMessage {
40
+ readonly role: GenAIMessageRole;
41
+ readonly content: string;
42
+ /** Optional model-specific metadata (tool calls, names, …). */
43
+ readonly toolCalls?: ReadonlyArray<{
44
+ readonly id: string;
45
+ readonly name: string;
46
+ readonly arguments: string;
47
+ }>;
48
+ readonly toolCallId?: string;
49
+ readonly name?: string;
50
+ }
51
+ /**
52
+ * Per-span attribute payload expected by {@link emitGenAIAttributes}.
53
+ * The fields mirror the OpenTelemetry GenAI semantic conventions and
54
+ * are merged with the existing Graphorin-prefixed attributes — the
55
+ * `gen_ai.*` family is additive, never replacing.
56
+ *
57
+ * @stable
58
+ */
59
+ interface GenAIAttributes {
60
+ readonly system?: GenAISystem;
61
+ readonly requestModel?: string;
62
+ readonly responseModel?: string;
63
+ readonly responseId?: string;
64
+ readonly inputTokens?: number;
65
+ readonly outputTokens?: number;
66
+ readonly finishReasons?: ReadonlyArray<string>;
67
+ readonly operation?: GenAIOperationName;
68
+ readonly agentId?: string;
69
+ readonly agentName?: string;
70
+ readonly sessionId?: string;
71
+ readonly toolName?: string;
72
+ readonly toolType?: GenAIToolType;
73
+ readonly toolCallId?: string;
74
+ readonly toolDescription?: string;
75
+ }
76
+ /**
77
+ * Mapping from a Graphorin `SpanType` to the canonical
78
+ * `gen_ai.operation.name` value. Returns `undefined` for span types
79
+ * that do not have a canonical operation enum (`replay.*` is recorded
80
+ * as `'replay.run'` / `'replay.skipped'` per the doc table).
81
+ *
82
+ * @stable
83
+ */
84
+ type SpanTypeToOperationName = (type: SpanType) => GenAIOperationName | undefined;
85
+ //#endregion
86
+ export { GenAIAttributes, GenAIMessage, GenAIMessageRole, GenAIOperationName, GenAISystem, GenAIToolType, SpanTypeToOperationName };
87
+ //# sourceMappingURL=types.d.ts.map