@cuylabs/agent-microsoft-opentelemetry 4.8.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.
package/dist/index.js ADDED
@@ -0,0 +1,363 @@
1
+ import {
2
+ MICROSOFT_A365_ATTRIBUTES,
3
+ MICROSOFT_A365_FMI_SCOPE,
4
+ MICROSOFT_A365_OBSERVABILITY_SCOPE,
5
+ MicrosoftOpenTelemetryModuleLoadError,
6
+ MicrosoftOpenTelemetryResourceModuleLoadError,
7
+ buildMicrosoftA365BaggagePairs,
8
+ callOptionalBooleanMethod,
9
+ callOptionalStringMethod,
10
+ createEnvReader,
11
+ createMicrosoftA365S2STokenResolver,
12
+ createMicrosoftA365S2STokenResolverFromEnv,
13
+ createMicrosoftOpenTelemetryInstrumentationOptions,
14
+ createMicrosoftOpenTelemetryTracingConfig,
15
+ firstNonEmpty,
16
+ initMicrosoftOpenTelemetry,
17
+ initMicrosoftOpenTelemetryFromEnv,
18
+ loadMicrosoftOpenTelemetryModule,
19
+ loadOpenTelemetryResourceModule,
20
+ mergeInstrumentationOptions,
21
+ normalizeInstrumentationProfile,
22
+ parseServiceEndpoint,
23
+ readPath,
24
+ resolveMicrosoftOpenTelemetryBooleanEnv,
25
+ resolveMicrosoftOpenTelemetryEnvironment,
26
+ resolveMicrosoftOpenTelemetryNumberEnv,
27
+ runWithMicrosoftA365Context,
28
+ updateMicrosoftA365ExportToken
29
+ } from "./chunk-S7XVXBY3.js";
30
+
31
+ // src/a365/hosting.ts
32
+ async function configureMicrosoftA365Hosting(adapter, options = {}) {
33
+ const module = await loadMicrosoftOpenTelemetryModule(options.runtime);
34
+ const hostingOptions = resolveHostingOptions(options);
35
+ if (module.configureA365Hosting) {
36
+ return module.configureA365Hosting(adapter, hostingOptions);
37
+ }
38
+ if (module.ObservabilityHostingManager) {
39
+ const manager = new module.ObservabilityHostingManager();
40
+ manager.configure(adapter, hostingOptions);
41
+ return manager;
42
+ }
43
+ throw new MicrosoftOpenTelemetryModuleLoadError(
44
+ "The installed @microsoft/opentelemetry package does not expose A365 hosting middleware helpers."
45
+ );
46
+ }
47
+ function resolveHostingOptions(options) {
48
+ return {
49
+ enableBaggage: options.enableBaggage ?? true,
50
+ enableOutputLogging: options.enableOutputLogging ?? true
51
+ };
52
+ }
53
+
54
+ // src/a365/turn-context.ts
55
+ function createMicrosoftA365ContextFromTurnContext(turnContext, options = {}) {
56
+ const { serviceUrl, useRecipientIdAsAgentId, ...requestOptions } = options;
57
+ const activity = turnContext.activity ?? {};
58
+ const channelData = activity.channelData;
59
+ const endpoint = parseServiceEndpoint(serviceUrl ?? activity.serviceUrl);
60
+ const isAgenticRequest = callOptionalBooleanMethod(activity.isAgenticRequest);
61
+ const agentId = firstNonEmpty(
62
+ requestOptions.agentId,
63
+ isAgenticRequest ? callOptionalStringMethod(activity.getAgenticInstanceId) : void 0,
64
+ activity.recipient?.agenticAppId,
65
+ useRecipientIdAsAgentId ? activity.recipient?.id : void 0
66
+ );
67
+ const tenantId = firstNonEmpty(
68
+ requestOptions.tenantId,
69
+ callOptionalStringMethod(activity.getAgenticTenantId),
70
+ activity.recipient?.tenantId,
71
+ activity.conversation?.tenantId,
72
+ readPath(channelData, ["tenant", "id"]),
73
+ readPath(channelData, ["tenantId"])
74
+ );
75
+ const context = { ...requestOptions };
76
+ setIfDefined(context, "tenantId", tenantId);
77
+ setIfDefined(context, "agentId", agentId);
78
+ setIfDefined(
79
+ context,
80
+ "agentName",
81
+ firstNonEmpty(requestOptions.agentName, activity.recipient?.name)
82
+ );
83
+ setIfDefined(
84
+ context,
85
+ "agentDescription",
86
+ firstNonEmpty(requestOptions.agentDescription, activity.recipient?.role)
87
+ );
88
+ setIfDefined(
89
+ context,
90
+ "agentAuid",
91
+ firstNonEmpty(requestOptions.agentAuid, activity.recipient?.aadObjectId)
92
+ );
93
+ setIfDefined(
94
+ context,
95
+ "agentBlueprintId",
96
+ firstNonEmpty(
97
+ requestOptions.agentBlueprintId,
98
+ activity.recipient?.agenticAppBlueprintId
99
+ )
100
+ );
101
+ setIfDefined(
102
+ context,
103
+ "conversationId",
104
+ firstNonEmpty(requestOptions.conversationId, activity.conversation?.id)
105
+ );
106
+ setIfDefined(
107
+ context,
108
+ "conversationItemLink",
109
+ firstNonEmpty(requestOptions.conversationItemLink, activity.serviceUrl)
110
+ );
111
+ setIfDefined(
112
+ context,
113
+ "sessionId",
114
+ firstNonEmpty(
115
+ requestOptions.sessionId,
116
+ requestOptions.conversationId,
117
+ activity.conversation?.id
118
+ )
119
+ );
120
+ setIfDefined(
121
+ context,
122
+ "channelName",
123
+ firstNonEmpty(requestOptions.channelName, activity.channelId)
124
+ );
125
+ setIfDefined(
126
+ context,
127
+ "channelLink",
128
+ firstNonEmpty(requestOptions.channelLink, activity.channelIdSubChannel)
129
+ );
130
+ setIfDefined(
131
+ context,
132
+ "userId",
133
+ firstNonEmpty(
134
+ requestOptions.userId,
135
+ activity.from?.aadObjectId,
136
+ activity.from?.id,
137
+ readPath(turnContext.identity, ["oid"]),
138
+ readPath(turnContext.identity, ["sub"])
139
+ )
140
+ );
141
+ setIfDefined(
142
+ context,
143
+ "userName",
144
+ firstNonEmpty(requestOptions.userName, activity.from?.name)
145
+ );
146
+ setIfDefined(
147
+ context,
148
+ "userEmail",
149
+ firstNonEmpty(
150
+ requestOptions.userEmail,
151
+ activity.from?.email,
152
+ activity.from?.userPrincipalName,
153
+ activity.from?.agenticUserId,
154
+ readPath(channelData, ["from", "userPrincipalName"]),
155
+ readPath(turnContext.identity, ["preferred_username"]),
156
+ readPath(turnContext.identity, ["upn"])
157
+ )
158
+ );
159
+ setIfDefined(
160
+ context,
161
+ "callerAgentBlueprintId",
162
+ firstNonEmpty(
163
+ requestOptions.callerAgentBlueprintId,
164
+ activity.from?.agenticAppBlueprintId
165
+ )
166
+ );
167
+ setIfDefined(
168
+ context,
169
+ "serverAddress",
170
+ firstNonEmpty(requestOptions.serverAddress, endpoint?.serverAddress)
171
+ );
172
+ setIfDefined(
173
+ context,
174
+ "serverPort",
175
+ requestOptions.serverPort ?? endpoint?.serverPort
176
+ );
177
+ return context;
178
+ }
179
+ function setIfDefined(context, key, value) {
180
+ if (value !== void 0) {
181
+ context[key] = value;
182
+ }
183
+ }
184
+
185
+ // src/internal/async-queue.ts
186
+ var AsyncQueue = class {
187
+ values = [];
188
+ waiters = [];
189
+ closed = false;
190
+ push(value) {
191
+ if (this.closed) {
192
+ return;
193
+ }
194
+ const waiter = this.waiters.shift();
195
+ if (waiter) {
196
+ waiter({ value, done: false });
197
+ return;
198
+ }
199
+ this.values.push(value);
200
+ }
201
+ close() {
202
+ if (this.closed) {
203
+ return;
204
+ }
205
+ this.closed = true;
206
+ for (const waiter of this.waiters.splice(0)) {
207
+ waiter({ value: void 0, done: true });
208
+ }
209
+ }
210
+ [Symbol.asyncIterator]() {
211
+ return {
212
+ next: () => {
213
+ const value = this.values.shift();
214
+ if (value !== void 0) {
215
+ return Promise.resolve({ value, done: false });
216
+ }
217
+ if (this.closed) {
218
+ return Promise.resolve({ value: void 0, done: true });
219
+ }
220
+ return new Promise((resolve) => {
221
+ this.waiters.push(resolve);
222
+ });
223
+ }
224
+ };
225
+ }
226
+ };
227
+
228
+ // src/a365/turn-source.ts
229
+ function createMicrosoftA365ObservedTurnSource({
230
+ context,
231
+ runtimeOptions,
232
+ source
233
+ }) {
234
+ const resolveContext = typeof context === "function" ? context : () => context;
235
+ return {
236
+ async *chat(sessionId, message, options) {
237
+ const requestContext = await resolveContext({
238
+ sessionId,
239
+ message,
240
+ options
241
+ });
242
+ const queue = new AsyncQueue();
243
+ let failure;
244
+ void runWithMicrosoftA365Context(
245
+ requestContext,
246
+ async () => {
247
+ try {
248
+ for await (const event of source.chat(
249
+ sessionId,
250
+ message,
251
+ options
252
+ )) {
253
+ queue.push(event);
254
+ }
255
+ } catch (error) {
256
+ failure = error;
257
+ } finally {
258
+ queue.close();
259
+ }
260
+ },
261
+ runtimeOptions
262
+ ).catch((error) => {
263
+ failure = error;
264
+ queue.close();
265
+ });
266
+ for await (const event of queue) {
267
+ yield event;
268
+ }
269
+ if (failure) {
270
+ throw failure;
271
+ }
272
+ }
273
+ };
274
+ }
275
+
276
+ // src/runtime/destinations.ts
277
+ var TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
278
+ function isMicrosoftOtlpEnvironmentEnabled(env = process.env) {
279
+ return Boolean(
280
+ readFirst(
281
+ env,
282
+ "OTEL_EXPORTER_OTLP_ENDPOINT",
283
+ "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
284
+ "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
285
+ "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"
286
+ )
287
+ );
288
+ }
289
+ function isAzureMonitorEnvironmentEnabled(env = process.env) {
290
+ if (isTruthy(readFirst(env, "MICROSOFT_OTEL_AZURE_MONITOR_ENABLED"))) {
291
+ return true;
292
+ }
293
+ return Boolean(readFirst(env, "APPLICATIONINSIGHTS_CONNECTION_STRING"));
294
+ }
295
+ function createAzureMonitorOptionsFromEnv(env = process.env) {
296
+ const enabled = isAzureMonitorEnvironmentEnabled(env);
297
+ const connectionString = readFirst(
298
+ env,
299
+ "APPLICATIONINSIGHTS_CONNECTION_STRING"
300
+ );
301
+ if (!enabled && !connectionString) {
302
+ return void 0;
303
+ }
304
+ return {
305
+ enabled,
306
+ ...connectionString ? { azureMonitorExporterOptions: { connectionString } } : {}
307
+ };
308
+ }
309
+ function summarizeMicrosoftOpenTelemetryDestinations(options = {}) {
310
+ const env = options.env ?? process.env;
311
+ const azureMonitor = options.azureMonitor === false ? false : options.azureMonitor?.enabled ?? isAzureMonitorEnvironmentEnabled(env);
312
+ const agent365 = options.a365?.enabled === true && options.a365.enableObservabilityExporter === true;
313
+ const otlp = isMicrosoftOtlpEnvironmentEnabled(env);
314
+ return {
315
+ agent365,
316
+ azureMonitor,
317
+ otlp,
318
+ console: options.enableConsoleExporters ?? (!agent365 && !azureMonitor && !otlp)
319
+ };
320
+ }
321
+ function readFirst(env, ...names) {
322
+ for (const name of names) {
323
+ const value = env[name]?.trim();
324
+ if (value) {
325
+ return value;
326
+ }
327
+ }
328
+ return void 0;
329
+ }
330
+ function isTruthy(value) {
331
+ return TRUE_VALUES.has((value ?? "").trim().toLowerCase());
332
+ }
333
+ export {
334
+ MICROSOFT_A365_ATTRIBUTES,
335
+ MICROSOFT_A365_FMI_SCOPE,
336
+ MICROSOFT_A365_OBSERVABILITY_SCOPE,
337
+ MicrosoftOpenTelemetryModuleLoadError,
338
+ MicrosoftOpenTelemetryResourceModuleLoadError,
339
+ buildMicrosoftA365BaggagePairs,
340
+ configureMicrosoftA365Hosting,
341
+ createAzureMonitorOptionsFromEnv,
342
+ createEnvReader,
343
+ createMicrosoftA365ContextFromTurnContext,
344
+ createMicrosoftA365ObservedTurnSource,
345
+ createMicrosoftA365S2STokenResolver,
346
+ createMicrosoftA365S2STokenResolverFromEnv,
347
+ createMicrosoftOpenTelemetryInstrumentationOptions,
348
+ createMicrosoftOpenTelemetryTracingConfig,
349
+ initMicrosoftOpenTelemetry,
350
+ initMicrosoftOpenTelemetryFromEnv,
351
+ isAzureMonitorEnvironmentEnabled,
352
+ isMicrosoftOtlpEnvironmentEnabled,
353
+ loadMicrosoftOpenTelemetryModule,
354
+ loadOpenTelemetryResourceModule,
355
+ mergeInstrumentationOptions,
356
+ normalizeInstrumentationProfile,
357
+ resolveMicrosoftOpenTelemetryBooleanEnv,
358
+ resolveMicrosoftOpenTelemetryEnvironment,
359
+ resolveMicrosoftOpenTelemetryNumberEnv,
360
+ runWithMicrosoftA365Context,
361
+ summarizeMicrosoftOpenTelemetryDestinations,
362
+ updateMicrosoftA365ExportToken
363
+ };
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/loader.js ADDED
@@ -0,0 +1,3 @@
1
+ // src/loader.ts
2
+ import "@microsoft/opentelemetry/loader";
3
+ await import("./register.js");
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,17 @@
1
+ import {
2
+ initMicrosoftOpenTelemetryFromEnv
3
+ } from "./chunk-S7XVXBY3.js";
4
+
5
+ // src/register.ts
6
+ var DISABLED_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
7
+ var GLOBAL_HANDLE_KEY = /* @__PURE__ */ Symbol.for(
8
+ "@cuylabs/agent-microsoft-opentelemetry/register"
9
+ );
10
+ var disabled = DISABLED_VALUES.has(
11
+ (process.env.CUYLABS_MICROSOFT_OPENTELEMETRY_DISABLED ?? "").toLowerCase()
12
+ );
13
+ if (!disabled) {
14
+ const globalState = globalThis;
15
+ globalState[GLOBAL_HANDLE_KEY] ??= initMicrosoftOpenTelemetryFromEnv();
16
+ await globalState[GLOBAL_HANDLE_KEY];
17
+ }
@@ -0,0 +1,110 @@
1
+ # Architecture
2
+
3
+ `@cuylabs/agent-microsoft-opentelemetry` is the Microsoft OpenTelemetry distro
4
+ adapter for `agents-ts`.
5
+
6
+ ## Layers
7
+
8
+ The package keeps three boundaries separate.
9
+
10
+ First, `@cuylabs/agent-core` remains the owner of agent execution telemetry. It
11
+ configures AI SDK v7 GenAI telemetry for model calls and tool execution and
12
+ provides `createAgent({ tracing })` as the app-facing integration point.
13
+
14
+ Second, `@microsoft/opentelemetry` owns the Microsoft OpenTelemetry provider,
15
+ span processors, exporters, Azure Monitor integration, Agent 365 exporter, OTLP
16
+ export, and Microsoft-supported framework instrumentation.
17
+
18
+ Third, this package bridges the two. It starts the Microsoft distro, creates
19
+ Agent 365 S2S token resolvers, applies Agent 365 baggage around turns, and
20
+ returns `agent-core` tracing defaults that align with Microsoft Agent 365
21
+ schemas.
22
+
23
+ The adapter default instrumentation profile is `agent-core`. It disables
24
+ Microsoft's optional framework auto-instrumentations for OpenAI Agents SDK and
25
+ LangChain because those are not part of the normal `agents-ts` execution path.
26
+ Applications can opt into those official Microsoft framework integrations with
27
+ `microsoft-genai` or explicit `instrumentationOptions`.
28
+
29
+ ## Source Layout
30
+
31
+ The Microsoft distro source is organized by owned implementation subsystems:
32
+ A365 processors/exporters/scopes, Azure Monitor, OTLP, GenAI instrumentation,
33
+ and shared distro setup. This package does not copy those internals. It keeps
34
+ only the adapter responsibilities:
35
+
36
+ | Folder | Responsibility |
37
+ | --- | --- |
38
+ | `src/a365` | Normalize channel/runtime data into Microsoft A365 baggage. |
39
+ | `src/auth` | Resolve Agent 365 S2S tokens from CLI-generated configuration or host-provided managed identity assertions. |
40
+ | `src/runtime` | Call `useMicrosoftOpenTelemetry()`, map adapter options to distro options, expose destination helpers, expose instrumentation profiles, and load Microsoft modules lazily. |
41
+ | `src/tracing` | Produce `agent-core` tracing config that avoids duplicate tool spans and carries Microsoft attributes. |
42
+ | `src/common` | Public cross-cutting type aliases. |
43
+ | `src/internal` | Small helpers that are not part of the package API. |
44
+
45
+ ## Agent 365 Flow
46
+
47
+ An application starts the Microsoft distro with `initMicrosoftOpenTelemetry()`.
48
+ For ESM services that rely on automatic instrumentation, start the process with
49
+ `--import @cuylabs/agent-microsoft-opentelemetry/loader`. That loader imports
50
+ Microsoft's OpenTelemetry hook first and then runs this package's env-driven
51
+ registration. This follows the distro's requirement that instrumentation hooks
52
+ are registered before app modules load.
53
+
54
+ When `a365.enabled` is true, the distro registers the Agent 365 span processor.
55
+ When `a365.enableObservabilityExporter` is true, it also registers the Agent
56
+ 365 HTTP exporter. The adapter still accepts `exporterEnabled` as a
57
+ compatibility alias, but new code should use Microsoft's option name.
58
+
59
+ Each channel turn should run inside `runWithMicrosoftA365Context()` or an
60
+ observed turn source. That scope creates Microsoft baggage values such as
61
+ `microsoft.tenant.id`, `gen_ai.agent.id`, `user.email`,
62
+ `microsoft.channel.name`, and `gen_ai.conversation.id`. The Microsoft distro
63
+ copies those baggage values onto spans before export.
64
+
65
+ For Microsoft Agent Hosting compatible adapters, the package can also delegate
66
+ to the official distro's hosting middleware with
67
+ `configureMicrosoftA365Hosting()`. This keeps Microsoft TurnContext middleware
68
+ on Microsoft's implementation while still exposing one `agents-ts` integration
69
+ surface.
70
+
71
+ The Agent 365 exporter groups spans by tenant and agent identity, then calls the
72
+ token resolver. For S2S agents, `createMicrosoftA365S2STokenResolver()` performs
73
+ the Agent 365 FMI flow and caches the resulting Observability API token.
74
+
75
+ ## Tool Spans
76
+
77
+ The default tracing helper returns `emitToolSpans: false`. This is intentional.
78
+ AI SDK v7 GenAI telemetry already emits standard tool spans for normal
79
+ `streamText()` tool execution. Enabling both AI SDK tool spans and agent-core
80
+ custom tool spans creates duplicate `execute_tool` telemetry for one tool call.
81
+
82
+ If an application has a custom execution path that does not emit AI SDK tool
83
+ spans, it can opt in with:
84
+
85
+ ```ts
86
+ createMicrosoftOpenTelemetryTracingConfig({
87
+ emitToolSpans: true,
88
+ });
89
+ ```
90
+
91
+ ## Content Capture
92
+
93
+ The package does not force a privacy policy. `recordInputs` and `recordOutputs`
94
+ are explicit `agent-core` tracing settings. Set them to `true` when Agent 365
95
+ validation or audit scenarios require prompt, response, tool argument, and tool
96
+ result attributes. Set them to `false` when an application needs metadata-only
97
+ telemetry.
98
+
99
+ ## Distro Migration
100
+
101
+ The older `@cuylabs/agent-a365-observability` package wraps
102
+ `@microsoft/agents-a365-observability`. This package wraps the newer
103
+ `@microsoft/opentelemetry` distro. New Microsoft integrations should prefer this
104
+ package unless they need to remain on the older Microsoft package family for
105
+ compatibility.
106
+
107
+ For an option-by-option mapping to the Microsoft distro, see
108
+ [distro-alignment.md](./distro-alignment.md).
109
+ For destination and instrumentation strategy, see
110
+ [destinations-and-instrumentation.md](./destinations-and-instrumentation.md).
@@ -0,0 +1,116 @@
1
+ # Destinations and Instrumentation
2
+
3
+ The Microsoft OpenTelemetry distro separates where telemetry is sent from how
4
+ telemetry is created.
5
+
6
+ ## Destinations
7
+
8
+ Destinations are exporters attached to the same OpenTelemetry pipeline.
9
+
10
+ | Destination | Purpose | How to enable |
11
+ | --- | --- | --- |
12
+ | Agent 365 | Microsoft 365 admin, Defender, and Purview agent activity. | `a365.enabled: true` plus `a365.enableObservabilityExporter: true`. |
13
+ | Azure Monitor | Application operations, traces, dependencies, logs, metrics, dashboards, and alerts. | `azureMonitor: { enabled: true }` or `APPLICATIONINSIGHTS_CONNECTION_STRING`. |
14
+ | OTLP | Vendor-neutral export to collectors or backends such as Grafana, Datadog, or New Relic. | Standard `OTEL_EXPORTER_OTLP_*` environment variables. |
15
+ | Console | Local validation when no remote exporter is active, or explicit debugging. | `enableConsoleExporters: true`. |
16
+
17
+ The same spans can flow to multiple destinations. Agent 365 enrichment still
18
+ helps Azure Monitor and OTLP when `a365.enabled` is true because the Microsoft
19
+ distro's `A365SpanProcessor` copies baggage onto spans before export.
20
+
21
+ ## Instrumentation
22
+
23
+ Instrumentation controls which libraries create spans.
24
+
25
+ | Instrumentation | Purpose |
26
+ | --- | --- |
27
+ | `http`, `azureSdk`, databases, Redis, Bunyan, Winston | Infrastructure and application telemetry. |
28
+ | `openaiAgents` | Optional Microsoft auto-instrumentation for the OpenAI Agents SDK when `@openai/agents` is installed. |
29
+ | `langchain` | Optional Microsoft auto-instrumentation for LangChain when `@langchain/core` is installed. |
30
+ | `agent-core` tracing | Emits `agents-ts` agent invocation spans and passes AI SDK v7 GenAI telemetry into `streamText()`. |
31
+
32
+ `@cuylabs/agent-core` does not use OpenAI Agents SDK or LangChain internally.
33
+ Those Microsoft framework instrumentations are useful only when an application
34
+ also runs those frameworks in the same process.
35
+
36
+ ## Profiles
37
+
38
+ Use `instrumentationProfile` to make the intent explicit.
39
+
40
+ ```ts
41
+ await initMicrosoftOpenTelemetry({
42
+ instrumentationProfile: "agent-core",
43
+ });
44
+ ```
45
+
46
+ | Profile | Behavior |
47
+ | --- | --- |
48
+ | `agent-core` | Disables Microsoft infra and framework auto-instrumentation. Best default for `agents-ts`, where `agent-core` emits the agent/model/tool telemetry. |
49
+ | `microsoft-genai` | Disables infrastructure auto-instrumentation and enables Microsoft's OpenAI Agents SDK and LangChain auto-instrumentations. |
50
+ | `full-stack` | Enables infrastructure and Microsoft framework auto-instrumentation. Best when sending to Azure Monitor or a general OTLP backend too. |
51
+ | `manual` | Disables built-in auto-instrumentation. Best when the app supplies its own processors/instrumentation. |
52
+ | `microsoft-default` | Leaves `instrumentationOptions` unset so the official distro applies its native defaults. |
53
+
54
+ Explicit `instrumentationOptions` always override the selected profile.
55
+ The old pre-release name `agent365-genai` is still accepted as an alias for
56
+ `microsoft-genai`, but new code should not use it.
57
+
58
+ ## Content Recording
59
+
60
+ There are two content-recording surfaces only if the application uses both
61
+ `agent-core` and Microsoft's optional framework auto-instrumentations.
62
+
63
+ `agent-core` uses `agent.recordInputs` and `agent.recordOutputs` in this
64
+ adapter's tracing config. Those settings control AI SDK v7 GenAI telemetry
65
+ created by `@cuylabs/agent-core`.
66
+
67
+ Microsoft's optional OpenAI Agents and LangChain auto-instrumentations use their
68
+ own official flags:
69
+
70
+ ```ts
71
+ await initMicrosoftOpenTelemetry({
72
+ instrumentationOptions: {
73
+ openaiAgents: {
74
+ enabled: true,
75
+ isContentRecordingEnabled: true,
76
+ },
77
+ langchain: {
78
+ enabled: true,
79
+ isContentRecordingEnabled: true,
80
+ },
81
+ },
82
+ });
83
+ ```
84
+
85
+ Set these only when the process actually uses those frameworks. They do not
86
+ control `agent-core`'s AI SDK spans.
87
+
88
+ ## Example: Agent 365 and Azure Monitor
89
+
90
+ ```ts
91
+ const observability = await initMicrosoftOpenTelemetry({
92
+ resource: {
93
+ serviceName: "cdo-ai-companion",
94
+ serviceVersion: "1.0.0",
95
+ },
96
+ a365: {
97
+ enabled: true,
98
+ enableObservabilityExporter: true,
99
+ useS2SEndpoint: true,
100
+ tokenResolver: createMicrosoftA365S2STokenResolverFromEnv(),
101
+ },
102
+ azureMonitor: {
103
+ enabled: Boolean(process.env.APPLICATIONINSIGHTS_CONNECTION_STRING),
104
+ },
105
+ instrumentationProfile: "full-stack",
106
+ });
107
+ ```
108
+
109
+ This sends the same enriched spans to Agent 365 and Azure Monitor. Set standard
110
+ `OTEL_EXPORTER_OTLP_ENDPOINT` variables to add OTLP export without changing code.
111
+
112
+ Azure Monitor options are passed through to the Microsoft distro. Use official
113
+ properties such as `enableLiveMetrics`, `enableStandardMetrics`,
114
+ `enableTraceBasedSamplingForLogs`, `enablePerformanceCounters`, and
115
+ `browserSdkLoaderOptions` when the application needs those Azure Monitor
116
+ features.