@saguiitay/eventhouse-ai-observability 0.1.2 → 0.2.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 (42) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +125 -18
  3. package/dist/adapters/openai.d.ts +25 -0
  4. package/dist/adapters/vercel.d.ts +25 -0
  5. package/dist/{chunk-XQFUPGYU.js → chunk-XGCHW72B.js} +11 -55
  6. package/dist/{chunk-XQFUPGYU.js.map → chunk-XGCHW72B.js.map} +1 -1
  7. package/dist/copilot.js +5 -3
  8. package/dist/copilot.js.map +1 -1
  9. package/dist/index.d.ts +1 -6
  10. package/dist/index.js +3 -11
  11. package/dist/openai.d.ts +12 -0
  12. package/dist/openai.js +408 -0
  13. package/dist/openai.js.map +1 -0
  14. package/dist/validate.d.ts +2 -0
  15. package/dist/validate.js +237 -0
  16. package/dist/validate.js.map +1 -0
  17. package/dist/validation/fabric.d.ts +29 -0
  18. package/dist/vercel.d.ts +15 -0
  19. package/dist/vercel.js +369 -0
  20. package/dist/vercel.js.map +1 -0
  21. package/docs/architecture.md +19 -3
  22. package/docs/copilot-adapter.md +1 -1
  23. package/docs/extending.md +45 -1
  24. package/docs/fabric-setup.md +24 -0
  25. package/docs/implementation-report.md +62 -18
  26. package/docs/openai-adapter.md +137 -0
  27. package/docs/quickstart.md +75 -6
  28. package/docs/research-eventstream.md +8 -6
  29. package/docs/research.md +1 -1
  30. package/docs/security.md +1 -1
  31. package/docs/telemetry-schema.md +18 -0
  32. package/docs/vercel-adapter.md +201 -0
  33. package/examples/README.md +75 -6
  34. package/examples/copilot-basic/package.json +1 -1
  35. package/examples/openai-basic/env.example +8 -0
  36. package/examples/openai-basic/index.ts +46 -0
  37. package/examples/shared.ts +3 -62
  38. package/examples/telemetry.ts +124 -0
  39. package/examples/vercel-basic/env.example +8 -0
  40. package/examples/vercel-basic/index.ts +60 -0
  41. package/fabric-setup.zip +0 -0
  42. package/package.json +39 -5
@@ -3,18 +3,21 @@
3
3
  ## Delivered
4
4
 
5
5
  A single TypeScript ESM npm package, `@saguiitay/eventhouse-ai-observability`
6
- (personal project; 0.1.1 published to GitHub Packages, 0.1.2 prepared in this
7
- checkout), with root and `/copilot` exports and ordinary internal modules in `src`.
6
+ (personal project; 0.1.1 published and registry-verified on GitHub Packages,
7
+ 0.1.2 published and registry-verified on npmjs, **0.2.0 prepared but not
8
+ published** in this checkout), with root, `/copilot`, `/openai`, and `/vercel` exports and ordinary internal modules in `src`.
8
9
  The former private workspace packages, OTLP wrapper, custom batching queue, and
9
10
  declaration-rewriting build step have been removed. OpenTelemetry's
10
- `BatchSpanProcessor`, standard `SpanExporter` interface, and official
11
- `OTLPTraceExporter` replace that plumbing.
11
+ `BatchSpanProcessor` and the standard `SpanExporter` interface replace that
12
+ plumbing. Fabric is the only built-in transport; applications can supply the
13
+ official `OTLPTraceExporter` or another standard exporter themselves.
12
14
 
13
- The implementation includes bounded asynchronous batching, parent-based sampling, explicit/ambient trace context, resource attributes, privacy filtering/redaction hooks, diagnostic counters, idempotent flush/shutdown, actual SDK event integration, three examples, Fabric schema/mapping/retention assets, analytics queries, native dashboard definitions, provisioning, local receiver tests, benchmarks, and CI.
15
+ The implementation includes bounded asynchronous batching, parent-based sampling, explicit/ambient trace context, resource attributes, privacy filtering/redaction hooks, diagnostic counters, idempotent flush/shutdown, actual SDK event integration, five runnable examples (three Copilot, one OpenAI, one Vercel), Fabric schema/mapping/retention assets, analytics queries, native dashboard definitions, provisioning, local receiver tests, benchmarks, and CI.
14
16
 
15
17
  ## Install and configure
16
18
 
17
- Build and pack from source, then use npm to install the generated tarball. The one-call entry point is:
19
+ Install the published npmjs package, or build/pack this checkout and install its
20
+ root tarball to evaluate unreleased 0.2.0. The one-call entry point is:
18
21
 
19
22
  ```typescript
20
23
  const observer = observeCopilot(existingSession, {
@@ -24,20 +27,33 @@ const observer = observeCopilot(existingSession, {
24
27
 
25
28
  Only supply `entityName` if the Fabric source's connection string omits `EntityPath`. Metadata-only capture is the default. Shutdown the observer explicitly without transferring ownership of the session/client. See the [quickstart](quickstart.md) for all options.
26
29
 
27
- The repository routes `@saguiitay` packages to GitHub Packages. The basic
28
- example's `.npmrc` uses the organization-approved Microsoft npm proxy for its
29
- other dependencies. Tokens belong in user-level configuration or CI secrets.
30
+ The repository routes `@saguiitay` packages to GitHub Packages. Consumer
31
+ dependency registries remain organization-controlled; private registry
32
+ configuration must not be copied into tracked files or distributed assets.
33
+ Tokens belong in user-level configuration or CI secrets.
30
34
  The earlier Azure Artifacts authentication blocker is historical: frozen installs
31
35
  and package smoke checks subsequently passed on Node 22/24 and Windows/Linux CI,
32
36
  and the operator successfully installed the published package from GitHub Packages
33
37
  into the basic example. Packed-artifact smoke tests still reuse project runtime
34
38
  dependencies and are not themselves a clean registry install.
35
39
 
40
+ The prepared 0.2.0 npm tarball includes exactly one generated
41
+ `fabric-setup.zip`, not raw tenant-bound Fabric source files. Install first,
42
+ resolve it beneath `npm root`, and extract its `README.md`, `manifest.json`,
43
+ and `fabric\` tree using the [README commands](../README.md#fabric-setup-bundle-and-ingestion-check).
44
+ Its manifest matches the npm version and records schema/version/hash metadata.
45
+ Public setup distribution uses npm because the source repository stays private;
46
+ GitHub Release ZIPs and Actions artifacts remain collaborator-only alternatives.
47
+ This policy permits only this project's authored generic public-API templates
48
+ and synthetic samples, not Microsoft-private code/docs/configuration, tenant
49
+ content, credentials, real telemetry, or copied external-repository files.
50
+ Fresh neutral generation is required but does not replace provenance review.
51
+
36
52
  ## Protocol and framework evidence
37
53
 
38
54
  Fabric ingestion uses the **Custom endpoint source's Event Hub producer interface**, through the official Azure Event Hubs client over AMQP/TLS. This is the documented direct-ingestion path and requires neither a separate Event Hubs resource nor a Collector. It is not Eventstream accepting OTLP, nor an outbound custom endpoint destination.
39
55
 
40
- The transport emits versioned framework-neutral JSON derived from standard OpenTelemetry spans. The optional OTLP transport uses the official HTTP exporter for an existing endpoint. See the [producer research](research-eventstream.md), [Copilot event research](research-copilot.md), and [Fabric provisioning/dashboard research](research-fabric.md) for source references.
56
+ The transport emits versioned framework-neutral JSON derived from standard OpenTelemetry spans. OTLP support is provided by a caller-supplied official HTTP exporter, not built into this package. See the [producer research](research-eventstream.md), [Copilot event research](research-copilot.md), and [Fabric provisioning/dashboard research](research-fabric.md) for source references.
41
57
 
42
58
  Supported Copilot events are `session.start`/`session.resume`, `assistant.turn_start`/`assistant.turn_end`, `tool.execution_start`/`tool.execution_complete`, `subagent.started`/`subagent.completed`/`subagent.failed`, `assistant.usage`, `model.call_failure`, `user.message`/`assistant.message` (opt-in content), and `abort`/`session.error`/`session.idle`/`session.shutdown`. Request usage remains request-scoped; separate subagent aggregate usage is not added to request totals. Correlation is explicit-only and bounded; unsupported or missing metadata is not invented.
43
59
 
@@ -47,12 +63,28 @@ Fabric assets include a schema-validated native **version-75 KQLDashboard** defi
47
63
 
48
64
  SDK, adapter, exporter, and Fabric asset tests run in Vitest. The Fabric checks preserve the original fixture analytics, all twenty query contracts, complete native dashboard schema validation, and source/destination routing checks using Ajv. PowerShell handles provisioning/updates and twenty mocked REST scenarios (twelve provisioning, eight updates). See [actual benchmark results](performance.md) for event handling, serialization, memory, throughput, burst pressure, and sustained queue behavior.
49
65
 
50
- After the dependency and example updates, **96 Vitest tests across 8 files passed**,
51
- including the Fabric asset regression suites. The installed development
66
+ The completed local validation passed **194 Vitest tests across 15 files**,
67
+ including SDK adapters and Fabric asset regression suites. The installed development
52
68
  dependencies are AJV 8.18.0 and fast-uri 3.1.9, resolving the reported dependency
53
- advisories. Formatting checks, root package build, declaration/ESM smoke checks
54
- against the rebuilt tarball, strict typechecking, and twenty mocked REST scenarios
55
- are release checks. The original silent-export-failure reproduction rejects
69
+ advisories. Strict typechecking, Prettier, eight Fabric contract tests, and twenty
70
+ mocked REST scenarios (twelve provisioning, eight updates) passed. npm and pnpm
71
+ root build/pack checks, ESM/declaration/CLI smoke checks, optional-peer isolation,
72
+ privacy smoke checks, and neutral versioned standalone ZIP generation also
73
+ passed locally. Repeated real root pnpm and npm packs regenerated identical
74
+ setup ZIP bytes; packed inventory, bindings, synthetic samples, version, and
75
+ per-file SHA-256 checks passed on both tarballs. The standalone ZIP matched the
76
+ package archive byte-for-byte. These completed checks are offline evidence, not a fresh online
77
+ consumer install, public/latest CI, real provider requests, or latest live Fabric.
78
+ The npm-embedded ZIP change additionally passed fifteen focused bundle tests,
79
+ including three repeated isolated fixture npm packs, stale ZIP exclusion,
80
+ neutral bindings, per-file hashes, safe paths, manual no-overwrite behavior,
81
+ and fail-closed content/source checks. The complete generator, three provisioning
82
+ scripts, and bundle README were reviewed: project-authored source, public Fabric
83
+ API/schema references, placeholder endpoints, and synthetic samples only; no
84
+ foreign source was imported. The fixture checks supplement, rather than replace,
85
+ the completed real root npm/pnpm pack and package-smoke validation. Content
86
+ checks cannot independently certify source provenance.
87
+ The original silent-export-failure reproduction rejects
56
88
  after full cleanup, reports a sanitized authentication category and failed-export
57
89
  counts, and exposes no raw input. The earlier in-memory benchmark completed;
58
90
  its deliberate overload cases retain bounded queues and report drops, not
@@ -64,6 +96,13 @@ guaranteed network throughput.
64
96
  - Fabric offline checks validate schemas, fixture contracts, query assets, and mocked REST provisioning, including polling and orchestration. These are **not KQL engine execution or dashboard service rendering**.
65
97
  - The package builds with tsup plus ordinary TypeScript 7 CLI declaration emission. There are no workspace imports or custom declaration-rewriting steps.
66
98
 
99
+ Latest observed CI run **43727442386** failed on 287 registry-specific lockfile
100
+ tarball URLs. Those routes were removed without changing versions or integrity
101
+ hashes. A registry-agnostic pnpm hook prevents their regeneration while preserving
102
+ explicit URL dependencies, custom archives, and signed routes. Frozen offline
103
+ installation and three hook regression tests passed. This report does not claim
104
+ that the failing run or subsequent CI has passed.
105
+
67
106
  **Live Fabric compatibility: verified for the operator's 0.1.0 deployment on
68
107
  2026-11-12.** The operator installed the published package, ran the basic Copilot
69
108
  example with Eventstream transport, and reported three generated/acknowledged
@@ -73,8 +112,9 @@ operator-reported, not a live run performed by the offline suite.
73
112
 
74
113
  `tools/live-fabric.ts` remains an explicit opt-in test of producer acceptance,
75
114
  ingestion, KQL lookup, and parent-child preservation; its execution has not been
76
- reported. Automated provisioning, update APIs, all three examples, parent-child
77
- assertions, performance at scale, and a live run of 0.1.1 remain unverified.
115
+ reported. Automated provisioning, update APIs, all five examples as a complete
116
+ set, parent-child assertions, performance at scale, and live runs of 0.1.1,
117
+ 0.1.2, and the prepared 0.2.0 remain unverified.
78
118
 
79
119
  ## Reliability and limitations
80
120
 
@@ -94,8 +134,12 @@ Pattern redaction is defense in depth, not a general PII/secret detector. Conten
94
134
 
95
135
  ## Required external validation
96
136
 
97
- Run CI on Node 22.15+ and 24 for each release. After publishing 0.1.2, reinstall
137
+ Run CI on Node 22.15+ and 24 for each release. After publishing 0.2.0, reinstall
98
138
  the basic example's pinned dependency and repeat live ingestion/dashboard checks.
139
+ Before publication, observe a passing CI run after lockfile remediation and
140
+ complete a fresh consumer installation through an approved registry.
141
+ Publication, uploads, and source-repository visibility changes are outside this
142
+ documentation update.
99
143
  Run the opt-in parent-child validation and the remaining examples, and validate
100
144
  automated provisioning/updates and interactive KQL performance before claiming
101
145
  those additional capabilities as service-verified.
@@ -0,0 +1,137 @@
1
+ # OpenAI Node SDK adapter
2
+
3
+ The `/openai` entry point observes the official `openai` Node SDK's direct
4
+ `client.chat.completions.create()` and `client.responses.create()` calls.
5
+ The compatibility target is **OpenAI SDK 7.53.0**, Node.js 22.15 or later.
6
+ It uses public SDK APIs, not provider-wide request hooks or application-global
7
+ OpenTelemetry configuration.
8
+
9
+ ```ts
10
+ import OpenAI from "openai";
11
+ import { observeOpenAI } from "@saguiitay/eventhouse-ai-observability/openai";
12
+
13
+ const sdk = new OpenAI(); // Configure authentication in the application.
14
+ const observer = observeOpenAI(sdk, {
15
+ connectionString: process.env.FABRIC_EVENTSTREAM_CONNECTION_STRING!,
16
+ });
17
+
18
+ try {
19
+ const response = await observer.client.responses.create({
20
+ model: "gpt-4.1-mini",
21
+ input: "Hello",
22
+ });
23
+ console.log(response.output_text);
24
+ } finally {
25
+ await observer.shutdown();
26
+ }
27
+ ```
28
+
29
+ Use the returned `client`. The original client remains uninstrumented and
30
+ unmodified. Endpoint overloads and the client type are preserved; SDK results and
31
+ raw SDK exceptions reach the caller. `then`, `catch`, `finally`, `withResponse`
32
+ and `asResponse` remain available. SDK retries, authentication, request options
33
+ and abort signals are unchanged. Observation never retries requests.
34
+
35
+ ## Scope and telemetry
36
+
37
+ Each supported call produces one client span, with `gen_ai.operation.name:
38
+ "chat"` for both APIs, `gen_ai.provider.name: "openai"`, requested/returned model,
39
+ response ID, finite nonnegative input/output token usage when available, finish
40
+ reasons for Chat Completions, and SDK-call-to-completion duration.
41
+ `openai.api` distinguishes `chat.completions` from `responses`.
42
+
43
+ Errors use fixed `error.type` categories and a numeric HTTP status when available.
44
+ Raw exception messages, headers, credentials and endpoint URLs are not captured.
45
+ Failed/incomplete Responses results are returned unchanged and marked as errors.
46
+ Completed request/response failures are failed spans, not incomplete observations.
47
+ `observability.incomplete` is reserved for unfinished work, cancellation/abort,
48
+ incomplete responses/streams, unsupported results, and observer shutdown.
49
+ Background responses that are still queued/in progress are marked incomplete;
50
+ the adapter does not poll them.
51
+
52
+ Other endpoints and SDK helpers (`parse`, `stream`, `runTools`, retrieval,
53
+ pagination, realtime, embeddings, audio, batches, files, and helpers on `beta`)
54
+ are **not intercepted**. A client produced by `withOptions()` must be observed
55
+ separately. Tool execution is not traced. Only direct calls through the returned
56
+ client's two supported `create` methods are observed.
57
+
58
+ ## Streaming and promise consumption
59
+
60
+ Supported `create({ stream: true })` calls remain lazy: no background consumer or
61
+ extra tee is created. The public SDK Stream constructor decorates iteration
62
+ without changing the original stream. Async iteration, `controller.abort()`,
63
+ `tee()` and `toReadableStream()` retain SDK behavior. Chunks and SDK errors are
64
+ returned unchanged. The SDK's own `_request_id` property descriptor is preserved
65
+ on decorated streams. Usage is taken from observed chunks/terminal Responses
66
+ events, never estimated. For Chat Completions, request
67
+ `stream_options: { include_usage: true }` if token reporting is needed; the
68
+ adapter does not change request parameters.
69
+
70
+ Stream spans finish once on exhaustion, error, early return, abort or observer
71
+ shutdown. Missing terminal events/finish reasons are marked incomplete.
72
+ Chat streams require every requested choice index to finish, not just the first
73
+ choice. Tracking is bounded to `n` values from 1 to 32; higher/invalid counts
74
+ remain usable but cannot be certified complete and are marked incomplete.
75
+ Duplicate, invalid and out-of-range choice indices do not satisfy completion.
76
+ `flush()` exports ended spans, without consuming or ending live streams.
77
+ `tee()` uses the SDK's own buffers; callers must consume/cancel both branches
78
+ responsibly. The adapter adds no chunk queue.
79
+
80
+ Promises are not eagerly parsed: that would consume bodies intended for
81
+ `asResponse()`. Await or consume a supported promise to observe its result.
82
+ `asResponse()` finishes an HTTP-only observation without reading/cloning its
83
+ body, so token/content telemetry is unavailable on that path. If mixed with
84
+ parsed consumption, the first terminal observation wins. Unconsumed promises
85
+ and streams stay tracked until observer shutdown; they are then marked
86
+ `observability.incomplete` and `openai.lifecycle: "observer_shutdown"`.
87
+ Shutdown does **not** abort application requests/streams, and late results
88
+ continue to reach the caller without reopening spans.
89
+
90
+ ## Privacy and bounds
91
+
92
+ Metadata-only is the default. With an engine configured for `captureContent:
93
+ true`, the adapter captures text-only input/output using `gen_ai.input.messages`
94
+ and `gen_ai.output.messages`. The engine sanitizer/redactor applies before any
95
+ exporter sees content. Images, audio, tool arguments/results and arbitrary object
96
+ serialization are excluded. Chat output capture is limited to the first choice.
97
+ Structured text traversal is bounded to 32 entries per array and three levels.
98
+
99
+ `maxContentChars` defaults to 4096 (range 1–4096), independently bounding input and
100
+ output text, including streaming text accumulation. This is truncated text, not
101
+ a complete conversation transcript. `maxTrackedRequests` defaults to 1024 (range
102
+ 1–65536) and is capped by the engine's active-span limit. At capacity, new calls
103
+ pass through unchanged/unobserved; `requestsSkipped` reports adapter admissions
104
+ skipped. `trackedRequests` includes unconsumed SDK promises/streams.
105
+
106
+ ## Shared engines and lifecycle
107
+
108
+ ```ts
109
+ import { createObservability } from "@saguiitay/eventhouse-ai-observability";
110
+ import { attachOpenAI } from "@saguiitay/eventhouse-ai-observability/openai";
111
+
112
+ const engine = createObservability({ exporter: myExporter });
113
+ const observer = attachOpenAI(sdk, engine); // External ownership by default.
114
+ // Equivalent: observeOpenAI(sdk, { engine })
115
+ try {
116
+ await observer.client.chat.completions.create({
117
+ model: "gpt-4.1-mini",
118
+ messages: [{ role: "user", content: "Hello" }],
119
+ });
120
+ } finally {
121
+ await observer.shutdown(); // End adapter work and flush, keep engine alive.
122
+ await engine.shutdown(); // Once, after every shared adapter shuts down.
123
+ }
124
+ ```
125
+
126
+ `observeOpenAI` owns engines it creates and shuts them down by default.
127
+ Supplied engines are externally owned by default. `shutdownEngine: true` explicitly
128
+ takes ownership of a supplied engine; do not set it to true on independently shutting-down adapters
129
+ that share an engine. Shutdown is awaited and idempotent. The SDK client is never
130
+ closed. `shutdownEngine: false` requires an external engine so newly constructed
131
+ engines cannot be left without an owner. Engine diagnostics are returned alongside
132
+ the two adapter counters.
133
+
134
+ Public SDK references:
135
+ [7.53.0 README](https://github.com/openai/openai-node/blob/v7.53.0/README.md),
136
+ [APIPromise](https://github.com/openai/openai-node/blob/v7.53.0/src/core/api-promise.ts),
137
+ [Stream](https://github.com/openai/openai-node/blob/v7.53.0/src/core/streaming.ts).
@@ -1,6 +1,22 @@
1
1
  # Quickstart
2
2
 
3
- Use the [Fabric setup](fabric-setup.md) first. There is no Collector or Azure Event Hubs resource to deploy.
3
+ Install the package first, then follow [Fabric setup](fabric-setup.md).
4
+ There is no Collector or Azure Event Hubs resource to deploy.
5
+
6
+ ## Install a published version
7
+
8
+ ```sh
9
+ npm install @saguiitay/eventhouse-ai-observability
10
+ ```
11
+
12
+ npmjs **0.1.2** and GitHub Packages **0.1.1** are published and registry-verified.
13
+ This checkout's **0.2.0 is prepared, not published**. Its generated
14
+ `fabric-setup.zip` will be available from the installed package root, without
15
+ access to this private source repository; see the
16
+ [PowerShell extraction instructions](../README.md#fabric-setup-bundle-and-ingestion-check).
17
+ The earlier published versions do not include it; use manual Fabric setup for
18
+ those versions. GitHub Packages additionally requires
19
+ [registry authentication](../README.md#installation-from-github-packages).
4
20
 
5
21
  ## Build and install locally
6
22
 
@@ -10,9 +26,13 @@ pnpm build
10
26
  pnpm pack
11
27
  ```
12
28
 
13
- Install the resulting tarball into an existing Node ESM application using `npm install <tarball>`. For published versions, follow the [GitHub Packages installation instructions](../README.md#installation-from-github-packages). Keep your existing Copilot session creation, permissions, model configuration, and execution unchanged; attach `observeCopilot` immediately after creating the session and before sending the first prompt.
29
+ Install the resulting tarball into an existing Node ESM application using `npm install <tarball>`.
30
+ The prepared package includes the generated setup ZIP; extract it after installing.
31
+ Keep your existing Copilot session creation, permissions, model configuration, and execution unchanged; attach `observeCopilot` immediately after creating the session and before sending the first prompt.
14
32
 
15
- `pnpm test:package` checks the packed root and `/copilot` exports, disposal, parent-child IDs, and public TypeScript declarations. It reuses already-installed project runtime dependencies and does not claim a fresh online install.
33
+ `pnpm test:package` checks all packed SDK exports, the validator CLI, disposal,
34
+ parent-child IDs, and public TypeScript declarations. It reuses already-installed
35
+ project runtime dependencies and does not claim a fresh online install.
16
36
 
17
37
  ```typescript
18
38
  import { observeCopilot } from "@saguiitay/eventhouse-ai-observability/copilot";
@@ -38,6 +58,7 @@ Shutdown closes the observer, **not your application-owned Copilot session/clien
38
58
  | ---------------------- | ------------------------------------------------------------------------- |
39
59
  | `connectionString` | `FABRIC_EVENTSTREAM_CONNECTION_STRING` |
40
60
  | `entityName` | Needed only if `EntityPath` is absent; `FABRIC_EVENTSTREAM_ENTITY_NAME` |
61
+ | `exporter` | Optional standard `SpanExporter`; replaces built-in Fabric export |
41
62
  | `serviceName` | `OTEL_SERVICE_NAME`, then `ai-application` |
42
63
  | `serviceVersion` | `OTEL_SERVICE_VERSION` |
43
64
  | `environment` | `DEPLOYMENT_ENVIRONMENT` |
@@ -79,14 +100,62 @@ into the application. Unknown third-party error codes remain `unknown`.
79
100
 
80
101
  Native OTel batches wait for a concurrency slot within the existing queue admission budget and callback deadline, so healthy flush backlogs drain without saturation drops. There is no second span queue. New admissions beyond `maxQueueSize` and batches exceeding their deadline are dropped. Third-party exporters remain standard OTel `SpanExporter`s; a callback deadline cannot forcibly stop their I/O, so a hung call keeps its slot until actual completion. Engine shutdown still releases local context within its deadline even if exporter cleanup hangs. Eventstream cancels Azure operations with abort signals and separately bounds pending transport calls. Known acknowledged spans count as exported; oversized, unsent, or uncertain spans count as dropped. See [transport failure semantics](eventstream-transport.md#failure-semantics).
81
102
 
82
- For an **existing** OTLP service, explicitly set `transport: "otlp"` and `endpoint`, or use `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`. `OTEL_EXPORTER_OTLP_ENDPOINT` is a base URL to which `/v1/traces` is appended. Headers support the corresponding standard traces/general environment variables. Without a Fabric connection string or an explicit OTLP endpoint, configuration fails early instead of silently sending to localhost.
103
+ Fabric is the only built-in transport. Without a Fabric connection string or
104
+ an explicit `exporter`, configuration fails early. The root package does not
105
+ read OTLP environment variables.
106
+
107
+ For an existing OTLP service, install
108
+ `@opentelemetry/exporter-trace-otlp-http` separately:
109
+
110
+ ```typescript
111
+ import { createObservability } from "@saguiitay/eventhouse-ai-observability";
112
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
113
+
114
+ const observer = createObservability({
115
+ exporter: new OTLPTraceExporter({
116
+ url: "https://your-collector.example/v1/traces",
117
+ headers: { authorization: `Bearer ${process.env.COLLECTOR_TOKEN}` },
118
+ }),
119
+ });
120
+ ```
121
+
122
+ Endpoint, header, and standard OTLP environment handling belong to that exporter.
123
+ Use HTTPS outside local development. The engine still sanitizes spans and owns
124
+ the supplied exporter's flush/shutdown lifecycle.
125
+
126
+ In 0.2.0, remove `transport`, `endpoint`, and `headers` from observability options
127
+ and stop importing `OTLPTraceExporter` from this package. Use `exporter` as above.
83
128
 
84
129
  ## Live Fabric validation
85
130
 
86
131
  Set `FABRIC_EVENTSTREAM_CONNECTION_STRING`, optionally `FABRIC_EVENTSTREAM_ENTITY_NAME`, `FABRIC_KQL_QUERY_ENDPOINT` (database query URI, HTTPS), `FABRIC_KQL_DATABASE`, and `FABRIC_KQL_ACCESS_TOKEN` (a short-lived, authorized Kusto query token for that URI).
87
132
 
133
+ Run the CLI from the application where this SDK is installed; no source checkout
134
+ or separate CLI package is needed:
135
+
88
136
  ```sh
89
- pnpm exec tsx tools/live-fabric.ts
137
+ npx --no-install eventhouse-ai-observability-validate
90
138
  ```
91
139
 
92
- The opt-in test sends two spans, waits up to three minutes for ingestion, queries `AIObservabilityTraces`, and checks their trace and parent IDs. It writes real telemetry to your database. It neither provisions resources nor generates tokens. A producer send acknowledgement alone is not a successful live validation.
140
+ From a checkout, run `pnpm build` then `pnpm validate:ingestion`.
141
+ `pnpm exec tsx tools/live-fabric.ts` remains a compatible source command.
142
+ `--help` performs no network I/O. No other arguments are accepted; keep
143
+ credentials out of command-line arguments, shell history, and committed files.
144
+
145
+ The producer needs Eventstream source Send credentials. The separate query token
146
+ needs Kusto database read permission and the correct Kusto audience; the
147
+ `FABRIC_ACCESS_TOKEN` used by provisioning is not a substitute.
148
+
149
+ The opt-in check reports producer acknowledgement, Eventhouse ingestion, and
150
+ trace/parent-child correlation separately. It sends two metadata-only spans and
151
+ queries `AIObservabilityTraces` until both appear. The polling timeout defaults
152
+ to three minutes after producer cleanup; set `FABRIC_VALIDATION_TIMEOUT_MS` to
153
+ a positive integer up to `900000` to change it. Export and query requests have
154
+ bounded deadlines. Query authorization failures, producer failures, ingestion
155
+ timeouts, and mapping/correlation failures use distinct safe error messages and
156
+ exit code 1; successful verification exits 0. No endpoint, token, query response
157
+ body, or raw SDK error is printed.
158
+
159
+ This writes real telemetry and can incur Fabric ingestion/query charges. It
160
+ neither provisions resources, acquires tokens, nor calls an AI provider. A
161
+ producer acknowledgement alone is not a successful validation.
@@ -162,15 +162,17 @@ or schema-registry headers.
162
162
 
163
163
  [Official OTel exporter documentation][otel] identifies
164
164
  `@opentelemetry/exporter-trace-otlp-http` as **HTTP/JSON**, not HTTP/protobuf
165
- (`exporter-trace-otlp-proto`). The OTLP path uses the official
166
- `OTLPTraceExporter` directly through its standard `export(spans, callback)`
167
- interface, without a separate transport wrapper or private package.
165
+ (`exporter-trace-otlp-proto`). Applications can supply the official
166
+ `OTLPTraceExporter` directly through the standard `exporter` option, without
167
+ a separate transport wrapper or private package. It is not a runtime
168
+ dependency or public export of this package.
168
169
  The [official implementation][otlp-source] supplies the serializer, HTTP sender,
169
170
  and exporter lifecycle.
170
171
 
171
- `endpoint`, if supplied, is the full traces URL, normally ending in `/v1/traces`.
172
- If omitted, the SDK owns environment/default resolution. Headers are copied and
173
- validated against invalid names/newlines, and exporter errors are sanitized.
172
+ The exporter's `url`, if supplied, is the full traces URL, normally ending in
173
+ `/v1/traces`. The official exporter owns environment/default resolution and
174
+ header configuration. The observability engine sanitizes exported spans and
175
+ diagnostic errors, not arbitrary transport configuration.
174
176
  Use HTTPS outside trusted local development. This is an optional external OTLP
175
177
  destination, **not an assertion that Fabric Eventstream accepts OTLP**.
176
178
 
package/docs/research.md CHANGED
@@ -31,6 +31,6 @@ on 2026-11-12.** The published package was installed and the basic Copilot examp
31
31
  ran successfully, with three acknowledged spans and no drops/failures. The
32
32
  operator confirmed rows in `AIObservabilityTraces` and dashboard visibility.
33
33
  This is not automated validation of all tenants, provisioning APIs, all examples,
34
- or 0.1.1. The opt-in live validation script's execution and parent-child assertions
34
+ or 0.1.1, 0.1.2, or the prepared unpublished 0.2.0. The opt-in live validation script's execution and parent-child assertions
35
35
  have not been reported; it requires a real Custom endpoint source, Eventhouse
36
36
  destination, KQL query URI/database, and a user-supplied query access token.
package/docs/security.md CHANGED
@@ -19,7 +19,7 @@ Use the Fabric Custom endpoint source's producer credential with **Send** capabi
19
19
 
20
20
  Rotate using Fabric's supported source key regeneration/credential controls: update the application secret, replace the observer/transport, verify ingestion, then revoke the old key. Existing clients retain their original credential; changing an environment variable does not rotate a running producer. No credential is embedded in the provisioned dashboard or sample data.
21
21
 
22
- AMQP uses TLS through the official Azure SDK. OTLP requires HTTPS except localhost/loopback for local tests. The SDK does not register global logging or print raw exporter errors. Diagnostics contain aggregate counts and an optional latest failure with an allowlisted category and fixed troubleshooting hint, never the original exception. `onDiagnostic` and opt-in `debug` logging expose only those safe fields.
22
+ AMQP uses TLS through the official Azure SDK. For a caller-supplied OTLP exporter, configure HTTPS except localhost/loopback for local tests; endpoint/header security belongs to the application and its exporter. The SDK does not register global logging or print raw exporter errors. Diagnostics contain aggregate counts and an optional latest failure with an allowlisted category and fixed troubleshooting hint, never the original exception. `onDiagnostic` and opt-in `debug` logging expose only those safe fields.
23
23
 
24
24
  ## Access and retention
25
25
 
@@ -26,6 +26,24 @@ Copilot correlation uses the `copilot.*` namespace, including `copilot.session.i
26
26
 
27
27
  `copilot.span.type` distinguishes `session`, `turn`, `tool`, `subagent`, and `model_request`. Execution metrics count turns, not the enclosing session observation or the separate subagent lifecycle span. Generic `invoke_agent` spans without Copilot-specific types remain supported. Agent identity is preserved as `copilot.agent.id`; names are added only when explicitly correlated metadata is available.
28
28
 
29
+ ## Request token details
30
+
31
+ SDK adapters normalize explicitly reported request usage into:
32
+
33
+ | Attribute | Meaning |
34
+ | ------------------------------------------ | --------------------------------------------------- |
35
+ | `gen_ai.usage.cache_read.input_tokens` | Input tokens read from the provider's prompt cache |
36
+ | `gen_ai.usage.cache_creation.input_tokens` | Input tokens written to the provider's prompt cache |
37
+ | `gen_ai.usage.reasoning.output_tokens` | Reasoning tokens within the reported output total |
38
+
39
+ These are breakdowns, not additional totals: do not add reasoning tokens to `gen_ai.usage.output_tokens` or cached tokens to `gen_ai.usage.input_tokens`. Missing details remain absent; explicitly reported zero remains zero. Counts must be nonnegative safe integers. Adapters do not estimate, split totals, infer cache writes from reads, or copy aggregate turn/session usage onto requests.
40
+
41
+ OpenAI Chat Completions uses `prompt_tokens_details.cached_tokens`, `prompt_tokens_details.cache_write_tokens`, and `completion_tokens_details.reasoning_tokens`. Responses uses `input_tokens_details.cached_tokens`, `input_tokens_details.cache_write_tokens`, and `output_tokens_details.reasoning_tokens`. Normal and terminal streaming usage follow the same mapping; cache creation is recorded only if the provider reports it.
42
+
43
+ Vercel AI SDK 7 uses each `onLanguageModelCallEnd` event's `usage.inputTokenDetails.cacheReadTokens`, `cacheWriteTokens`, and `usage.outputTokenDetails.reasoningTokens` on its native model-request span. Native cache attributes and optional supplemental reasoning attributes normalize to the same keys. This also works when native supplemental usage recording is disabled; step/root aggregate usage is not duplicated.
44
+
45
+ Copilot `assistant.usage` uses `cacheReadTokens`, `cacheWriteTokens`, and `reasoningTokens`. The compatibility attribute `copilot.usage.reasoning_tokens` remains alongside the standard reasoning key. Session shutdown metrics and subagent aggregates are not converted into request token details.
46
+
29
47
  ## Privacy and evolution
30
48
 
31
49
  Content is disabled by default. Sanitized resources, span attributes, events, and links are bounded before export. A custom transport receives the same privacy-filtered model. Error status remains available without exposing raw error text.