@cuylabs/agent-a365-observability 4.5.0 → 4.6.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/README.md +192 -9
- package/dist/index.d.ts +151 -8
- package/dist/index.js +793 -189
- package/docs/README.md +7 -1
- package/docs/architecture.md +18 -6
- package/docs/lifecycle-and-limits.md +55 -4
- package/docs/microsoft-a365-observability.md +16 -7
- package/docs/microsoft-node-package-comparison.md +75 -0
- package/docs/sdk-and-auth-flow.md +125 -0
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var A365_EXPORTER_EVENT_NAMES = {
|
|
3
|
+
export: "agent365-export",
|
|
4
|
+
exportGroup: "export-group",
|
|
5
|
+
exportPartitionSpanMissingIdentity: "export-partition-span-missing-identity"
|
|
6
|
+
};
|
|
7
|
+
|
|
1
8
|
// src/errors.ts
|
|
2
9
|
var A365ObservabilityModuleLoadError = class extends Error {
|
|
3
10
|
constructor(message, options) {
|
|
@@ -5,41 +12,14 @@ var A365ObservabilityModuleLoadError = class extends Error {
|
|
|
5
12
|
this.name = "A365ObservabilityModuleLoadError";
|
|
6
13
|
}
|
|
7
14
|
};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
agentName: "gen_ai.agent.name",
|
|
14
|
-
agentDescription: "gen_ai.agent.description",
|
|
15
|
-
agentVersion: "gen_ai.agent.version",
|
|
16
|
-
agentPlatformId: "microsoft.a365.agent.platform.id",
|
|
17
|
-
agentAuid: "microsoft.agent.user.id",
|
|
18
|
-
agentEmail: "microsoft.agent.user.email",
|
|
19
|
-
agentBlueprintId: "microsoft.a365.agent.blueprint.id",
|
|
20
|
-
sessionId: "microsoft.session.id",
|
|
21
|
-
sessionDescription: "microsoft.session.description",
|
|
22
|
-
conversationId: "gen_ai.conversation.id",
|
|
23
|
-
conversationItemLink: "microsoft.conversation.item.link",
|
|
24
|
-
channelName: "microsoft.channel.name",
|
|
25
|
-
channelLink: "microsoft.channel.link",
|
|
26
|
-
userId: "user.id",
|
|
27
|
-
userName: "user.name",
|
|
28
|
-
userEmail: "user.email",
|
|
29
|
-
callerClientIp: "client.address",
|
|
30
|
-
callerAgentId: "microsoft.a365.caller.agent.id",
|
|
31
|
-
callerAgentName: "microsoft.a365.caller.agent.name",
|
|
32
|
-
callerAgentAuid: "microsoft.a365.caller.agent.user.id",
|
|
33
|
-
callerAgentEmail: "microsoft.a365.caller.agent.user.email",
|
|
34
|
-
callerAgentBlueprintId: "microsoft.a365.caller.agent.blueprint.id",
|
|
35
|
-
callerAgentPlatformId: "microsoft.a365.caller.agent.platform.id",
|
|
36
|
-
callerAgentVersion: "microsoft.a365.caller.agent.version",
|
|
37
|
-
serviceName: "service.name",
|
|
38
|
-
serverAddress: "server.address",
|
|
39
|
-
serverPort: "server.port"
|
|
15
|
+
var A365ObservabilityHostingModuleLoadError = class extends Error {
|
|
16
|
+
constructor(message, options) {
|
|
17
|
+
super(message, options);
|
|
18
|
+
this.name = "A365ObservabilityHostingModuleLoadError";
|
|
19
|
+
}
|
|
40
20
|
};
|
|
41
21
|
|
|
42
|
-
// src/internal/
|
|
22
|
+
// src/internal/values.ts
|
|
43
23
|
function setPair(target, key, value) {
|
|
44
24
|
if (value === null || value === void 0) {
|
|
45
25
|
return;
|
|
@@ -115,7 +95,480 @@ function isRecord(value) {
|
|
|
115
95
|
return typeof value === "object" && value !== null;
|
|
116
96
|
}
|
|
117
97
|
|
|
118
|
-
// src/
|
|
98
|
+
// src/auth/oauth-token-endpoint.ts
|
|
99
|
+
var CLIENT_ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
|
100
|
+
var DEFAULT_TOKEN_LIFETIME_MS = 55 * 60 * 1e3;
|
|
101
|
+
async function requestClientSecretToken(client, request, extra) {
|
|
102
|
+
const body = new URLSearchParams({
|
|
103
|
+
grant_type: "client_credentials",
|
|
104
|
+
client_id: request.clientId,
|
|
105
|
+
client_secret: request.clientSecret,
|
|
106
|
+
scope: request.scope
|
|
107
|
+
});
|
|
108
|
+
if (extra?.fmiPath) {
|
|
109
|
+
body.set("fmi_path", extra.fmiPath);
|
|
110
|
+
}
|
|
111
|
+
return await requestToken(client, body);
|
|
112
|
+
}
|
|
113
|
+
async function requestClientAssertionToken(client, request, extra) {
|
|
114
|
+
const body = new URLSearchParams({
|
|
115
|
+
grant_type: "client_credentials",
|
|
116
|
+
client_id: request.clientId,
|
|
117
|
+
client_assertion: request.clientAssertion,
|
|
118
|
+
client_assertion_type: CLIENT_ASSERTION_TYPE,
|
|
119
|
+
scope: request.scope
|
|
120
|
+
});
|
|
121
|
+
if (extra?.fmiPath) {
|
|
122
|
+
body.set("fmi_path", extra.fmiPath);
|
|
123
|
+
}
|
|
124
|
+
return await requestToken(client, body);
|
|
125
|
+
}
|
|
126
|
+
async function requestToken(client, body) {
|
|
127
|
+
const response = await client.fetch(
|
|
128
|
+
`https://login.microsoftonline.com/${encodeURIComponent(
|
|
129
|
+
client.tenantId
|
|
130
|
+
)}/oauth2/v2.0/token`,
|
|
131
|
+
{
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
134
|
+
body: body.toString()
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
const payload = parseTokenEndpointResponse(await response.text());
|
|
138
|
+
if (!response.ok || !payload.access_token) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
payload.error_description || payload.error || `token endpoint returned HTTP ${response.status}`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const expiresInMs = typeof payload.expires_in === "number" && payload.expires_in > 0 ? payload.expires_in * 1e3 : DEFAULT_TOKEN_LIFETIME_MS;
|
|
144
|
+
return {
|
|
145
|
+
accessToken: payload.access_token,
|
|
146
|
+
expiresAtMs: Date.now() + expiresInMs
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function parseTokenEndpointResponse(body) {
|
|
150
|
+
if (!body) {
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
return JSON.parse(body);
|
|
155
|
+
} catch {
|
|
156
|
+
return { error_description: body };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/auth/s2s-token-resolver.ts
|
|
161
|
+
var DEFAULT_FMI_SCOPE = "api://AzureADTokenExchange/.default";
|
|
162
|
+
var DEFAULT_OBSERVABILITY_SCOPE = "api://9b975845-388f-4429-889e-eab1ef63949c/.default";
|
|
163
|
+
var DEFAULT_REFRESH_SKEW_MS = 5 * 60 * 1e3;
|
|
164
|
+
function createA365S2STokenResolver(options) {
|
|
165
|
+
const normalized = normalizeOptions(options);
|
|
166
|
+
const cache = /* @__PURE__ */ new Map();
|
|
167
|
+
return async (agentId, tenantId) => {
|
|
168
|
+
const request = {
|
|
169
|
+
...normalized,
|
|
170
|
+
agentId: firstNonEmpty(agentId, normalized.agentId) ?? "",
|
|
171
|
+
tenantId: firstNonEmpty(tenantId, normalized.tenantId) ?? ""
|
|
172
|
+
};
|
|
173
|
+
const cacheKey = `${request.tenantId}:${request.agentId}`;
|
|
174
|
+
const cached = cache.get(cacheKey);
|
|
175
|
+
if (cached && cached.expiresAtMs - request.refreshSkewMs > Date.now()) {
|
|
176
|
+
return cached.accessToken;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const token = await acquireObservabilityToken(request);
|
|
180
|
+
cache.set(cacheKey, token);
|
|
181
|
+
return token.accessToken;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
request.logger?.warn("Failed to acquire Agent 365 S2S token", {
|
|
184
|
+
error: error instanceof Error ? error.message : String(error),
|
|
185
|
+
useManagedIdentity: request.useManagedIdentity
|
|
186
|
+
});
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function normalizeOptions(options) {
|
|
192
|
+
return {
|
|
193
|
+
tenantId: requireNonEmpty("tenantId", options.tenantId),
|
|
194
|
+
agentId: requireNonEmpty("agentId", options.agentId),
|
|
195
|
+
blueprintClientId: requireNonEmpty(
|
|
196
|
+
"blueprintClientId",
|
|
197
|
+
options.blueprintClientId
|
|
198
|
+
),
|
|
199
|
+
...options.blueprintClientSecret ? { blueprintClientSecret: options.blueprintClientSecret } : {},
|
|
200
|
+
useManagedIdentity: options.useManagedIdentity ?? false,
|
|
201
|
+
...options.managedIdentityAssertionProvider ? {
|
|
202
|
+
managedIdentityAssertionProvider: options.managedIdentityAssertionProvider
|
|
203
|
+
} : {},
|
|
204
|
+
allowManagedIdentityClientSecretFallback: options.allowManagedIdentityClientSecretFallback ?? true,
|
|
205
|
+
observabilityScope: options.observabilityScope ?? DEFAULT_OBSERVABILITY_SCOPE,
|
|
206
|
+
fmiScope: options.fmiScope ?? DEFAULT_FMI_SCOPE,
|
|
207
|
+
refreshSkewMs: options.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS,
|
|
208
|
+
...options.logger ? { logger: options.logger } : {},
|
|
209
|
+
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
async function acquireObservabilityToken(options) {
|
|
213
|
+
const t1Token = await acquireFmiToken(options);
|
|
214
|
+
return await requestClientAssertionToken(options, {
|
|
215
|
+
clientId: options.agentId,
|
|
216
|
+
clientAssertion: t1Token.accessToken,
|
|
217
|
+
scope: options.observabilityScope
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
async function acquireFmiToken(options) {
|
|
221
|
+
if (options.useManagedIdentity) {
|
|
222
|
+
try {
|
|
223
|
+
const assertion = await options.managedIdentityAssertionProvider?.();
|
|
224
|
+
if (!assertion) {
|
|
225
|
+
throw new Error(
|
|
226
|
+
"managed identity assertion provider returned no token"
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return await requestClientAssertionToken(
|
|
230
|
+
options,
|
|
231
|
+
{
|
|
232
|
+
clientId: options.blueprintClientId,
|
|
233
|
+
clientAssertion: assertion,
|
|
234
|
+
scope: options.fmiScope
|
|
235
|
+
},
|
|
236
|
+
{ fmiPath: options.agentId }
|
|
237
|
+
);
|
|
238
|
+
} catch (error) {
|
|
239
|
+
if (!options.allowManagedIdentityClientSecretFallback || !options.blueprintClientSecret) {
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
options.logger?.warn(
|
|
243
|
+
"Managed identity FMI token exchange failed; falling back to blueprint client secret",
|
|
244
|
+
{ error: error instanceof Error ? error.message : String(error) }
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return await requestClientSecretToken(
|
|
249
|
+
options,
|
|
250
|
+
{
|
|
251
|
+
clientId: options.blueprintClientId,
|
|
252
|
+
clientSecret: requireNonEmpty(
|
|
253
|
+
"blueprintClientSecret",
|
|
254
|
+
options.blueprintClientSecret
|
|
255
|
+
),
|
|
256
|
+
scope: options.fmiScope
|
|
257
|
+
},
|
|
258
|
+
{ fmiPath: options.agentId }
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
function requireNonEmpty(name, value) {
|
|
262
|
+
const normalized = value?.trim();
|
|
263
|
+
if (!normalized) {
|
|
264
|
+
throw new Error(`${name} is required`);
|
|
265
|
+
}
|
|
266
|
+
return normalized;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// src/auth/env.ts
|
|
270
|
+
var TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "y", "on"]);
|
|
271
|
+
var FALSE_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "n", "off"]);
|
|
272
|
+
function resolveA365ObservabilityEnvironment(env = process.env) {
|
|
273
|
+
const reader = createEnvReader(env);
|
|
274
|
+
return {
|
|
275
|
+
tenantId: reader(
|
|
276
|
+
"A365_OBSERVABILITY_TENANT_ID",
|
|
277
|
+
"agent365Observability__tenantId"
|
|
278
|
+
),
|
|
279
|
+
agentId: reader(
|
|
280
|
+
"A365_OBSERVABILITY_AGENT_ID",
|
|
281
|
+
"agent365Observability__agentId"
|
|
282
|
+
),
|
|
283
|
+
agentName: reader(
|
|
284
|
+
"A365_OBSERVABILITY_AGENT_NAME",
|
|
285
|
+
"agent365Observability__agentName"
|
|
286
|
+
),
|
|
287
|
+
agentDescription: reader(
|
|
288
|
+
"A365_OBSERVABILITY_AGENT_DESCRIPTION",
|
|
289
|
+
"agent365Observability__agentDescription"
|
|
290
|
+
),
|
|
291
|
+
blueprintClientId: reader(
|
|
292
|
+
"A365_OBSERVABILITY_BLUEPRINT_CLIENT_ID",
|
|
293
|
+
"A365_OBSERVABILITY_CLIENT_ID",
|
|
294
|
+
"agent365Observability__clientId",
|
|
295
|
+
"agent365Observability__agentBlueprintId"
|
|
296
|
+
),
|
|
297
|
+
blueprintClientSecret: reader(
|
|
298
|
+
"A365_OBSERVABILITY_BLUEPRINT_CLIENT_SECRET",
|
|
299
|
+
"A365_OBSERVABILITY_CLIENT_SECRET",
|
|
300
|
+
"agent365Observability__clientSecret"
|
|
301
|
+
),
|
|
302
|
+
useManagedIdentity: readBoolean(
|
|
303
|
+
reader(
|
|
304
|
+
"A365_OBSERVABILITY_USE_MANAGED_IDENTITY",
|
|
305
|
+
"agent365Observability__useManagedIdentity"
|
|
306
|
+
)
|
|
307
|
+
),
|
|
308
|
+
observabilityScope: reader(
|
|
309
|
+
"A365_OBSERVABILITY_SCOPE",
|
|
310
|
+
"A365_OBSERVABILITY_SCOPES",
|
|
311
|
+
"agent365Observability__observabilityScope"
|
|
312
|
+
),
|
|
313
|
+
fmiScope: reader(
|
|
314
|
+
"A365_OBSERVABILITY_FMI_SCOPE",
|
|
315
|
+
"A365_FMI_SCOPE",
|
|
316
|
+
"agent365Observability__fmiScope"
|
|
317
|
+
),
|
|
318
|
+
configuration: {
|
|
319
|
+
exporterEnabled: readBoolean(
|
|
320
|
+
reader(
|
|
321
|
+
"ENABLE_A365_OBSERVABILITY_EXPORTER",
|
|
322
|
+
"agent365Observability__exporterEnabled"
|
|
323
|
+
)
|
|
324
|
+
),
|
|
325
|
+
domainOverride: reader(
|
|
326
|
+
"A365_OBSERVABILITY_DOMAIN_OVERRIDE",
|
|
327
|
+
"agent365Observability__domainOverride"
|
|
328
|
+
),
|
|
329
|
+
logLevel: reader(
|
|
330
|
+
"A365_OBSERVABILITY_LOG_LEVEL",
|
|
331
|
+
"agent365Observability__logLevel"
|
|
332
|
+
),
|
|
333
|
+
authenticationScopes: splitScopes(
|
|
334
|
+
reader(
|
|
335
|
+
"A365_OBSERVABILITY_AUTHENTICATION_SCOPES",
|
|
336
|
+
"A365_OBSERVABILITY_SCOPES_OVERRIDE",
|
|
337
|
+
"agent365Observability__authenticationScopes"
|
|
338
|
+
)
|
|
339
|
+
),
|
|
340
|
+
perRequest: {
|
|
341
|
+
enabled: readBoolean(
|
|
342
|
+
reader(
|
|
343
|
+
"ENABLE_A365_OBSERVABILITY_PER_REQUEST_EXPORT",
|
|
344
|
+
"agent365Observability__perRequestExportEnabled"
|
|
345
|
+
)
|
|
346
|
+
),
|
|
347
|
+
maxTraces: readNumber(
|
|
348
|
+
reader(
|
|
349
|
+
"A365_PER_REQUEST_MAX_TRACES",
|
|
350
|
+
"agent365Observability__perRequestMaxTraces"
|
|
351
|
+
)
|
|
352
|
+
),
|
|
353
|
+
maxSpansPerTrace: readNumber(
|
|
354
|
+
reader(
|
|
355
|
+
"A365_PER_REQUEST_MAX_SPANS_PER_TRACE",
|
|
356
|
+
"agent365Observability__perRequestMaxSpansPerTrace"
|
|
357
|
+
)
|
|
358
|
+
),
|
|
359
|
+
maxConcurrentExports: readNumber(
|
|
360
|
+
reader(
|
|
361
|
+
"A365_PER_REQUEST_MAX_CONCURRENT_EXPORTS",
|
|
362
|
+
"agent365Observability__perRequestMaxConcurrentExports"
|
|
363
|
+
)
|
|
364
|
+
),
|
|
365
|
+
flushGraceMs: readNumber(
|
|
366
|
+
reader(
|
|
367
|
+
"A365_PER_REQUEST_FLUSH_GRACE_MS",
|
|
368
|
+
"agent365Observability__perRequestFlushGraceMs"
|
|
369
|
+
)
|
|
370
|
+
),
|
|
371
|
+
maxTraceAgeMs: readNumber(
|
|
372
|
+
reader(
|
|
373
|
+
"A365_PER_REQUEST_MAX_TRACE_AGE_MS",
|
|
374
|
+
"agent365Observability__perRequestMaxTraceAgeMs"
|
|
375
|
+
)
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function createA365S2STokenResolverFromEnv(options = {}) {
|
|
382
|
+
const env = resolveA365ObservabilityEnvironment(options.env);
|
|
383
|
+
return createA365S2STokenResolver({
|
|
384
|
+
...options,
|
|
385
|
+
tenantId: requireValue(
|
|
386
|
+
"tenantId",
|
|
387
|
+
firstNonEmpty(options.tenantId, env.tenantId)
|
|
388
|
+
),
|
|
389
|
+
agentId: requireValue(
|
|
390
|
+
"agentId",
|
|
391
|
+
firstNonEmpty(options.agentId, env.agentId)
|
|
392
|
+
),
|
|
393
|
+
blueprintClientId: requireValue(
|
|
394
|
+
"blueprintClientId",
|
|
395
|
+
firstNonEmpty(options.blueprintClientId, env.blueprintClientId)
|
|
396
|
+
),
|
|
397
|
+
blueprintClientSecret: firstNonEmpty(
|
|
398
|
+
options.blueprintClientSecret,
|
|
399
|
+
env.blueprintClientSecret
|
|
400
|
+
),
|
|
401
|
+
useManagedIdentity: options.useManagedIdentity ?? env.useManagedIdentity ?? Boolean(options.managedIdentityAssertionProvider),
|
|
402
|
+
observabilityScope: firstNonEmpty(
|
|
403
|
+
options.observabilityScope,
|
|
404
|
+
env.observabilityScope
|
|
405
|
+
),
|
|
406
|
+
fmiScope: firstNonEmpty(options.fmiScope, env.fmiScope)
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
function createEnvReader(env) {
|
|
410
|
+
const normalized = /* @__PURE__ */ new Map();
|
|
411
|
+
for (const [key, value] of Object.entries(env)) {
|
|
412
|
+
if (value !== void 0) {
|
|
413
|
+
normalized.set(key.toLowerCase(), value);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return (...names) => {
|
|
417
|
+
for (const name of names) {
|
|
418
|
+
const value = firstNonEmpty(
|
|
419
|
+
env[name],
|
|
420
|
+
normalized.get(name.toLowerCase())
|
|
421
|
+
);
|
|
422
|
+
if (value) {
|
|
423
|
+
return value;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return void 0;
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
function readBoolean(value) {
|
|
430
|
+
const normalized = value?.trim().toLowerCase();
|
|
431
|
+
if (!normalized) {
|
|
432
|
+
return void 0;
|
|
433
|
+
}
|
|
434
|
+
if (TRUE_VALUES.has(normalized)) {
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
if (FALSE_VALUES.has(normalized)) {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
return void 0;
|
|
441
|
+
}
|
|
442
|
+
function readNumber(value) {
|
|
443
|
+
const normalized = value?.trim();
|
|
444
|
+
if (!normalized) {
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
const parsed = Number(normalized);
|
|
448
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
449
|
+
}
|
|
450
|
+
function splitScopes(value) {
|
|
451
|
+
const scopes = value?.split(/\s+/).filter(Boolean);
|
|
452
|
+
return scopes && scopes.length > 0 ? scopes : void 0;
|
|
453
|
+
}
|
|
454
|
+
function requireValue(name, value) {
|
|
455
|
+
if (!value) {
|
|
456
|
+
throw new Error(`${name} is required`);
|
|
457
|
+
}
|
|
458
|
+
return value;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// src/runtime/module-loader.ts
|
|
462
|
+
var OBSERVABILITY_PACKAGE = "@microsoft/agents-a365-observability";
|
|
463
|
+
var OBSERVABILITY_HOSTING_PACKAGE = "@microsoft/agents-a365-observability-hosting";
|
|
464
|
+
async function loadObservabilityModule(options = {}) {
|
|
465
|
+
try {
|
|
466
|
+
if (options.getObservabilityModule) {
|
|
467
|
+
return await options.getObservabilityModule();
|
|
468
|
+
}
|
|
469
|
+
return await import(OBSERVABILITY_PACKAGE);
|
|
470
|
+
} catch (error) {
|
|
471
|
+
throw new A365ObservabilityModuleLoadError(
|
|
472
|
+
`Unable to load ${OBSERVABILITY_PACKAGE}. Install @microsoft/agents-a365-observability and @microsoft/agents-a365-runtime before using @cuylabs/agent-a365-observability.`,
|
|
473
|
+
{ cause: error }
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
async function loadObservabilityHostingModule(options = {}) {
|
|
478
|
+
try {
|
|
479
|
+
if (options.getObservabilityHostingModule) {
|
|
480
|
+
return await options.getObservabilityHostingModule();
|
|
481
|
+
}
|
|
482
|
+
return await import(OBSERVABILITY_HOSTING_PACKAGE);
|
|
483
|
+
} catch (error) {
|
|
484
|
+
throw new A365ObservabilityHostingModuleLoadError(
|
|
485
|
+
`Unable to load ${OBSERVABILITY_HOSTING_PACKAGE}. Install @microsoft/agents-a365-observability-hosting before using OBO Agent 365 observability helpers.`,
|
|
486
|
+
{ cause: error }
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// src/auth/obo-token-cache.ts
|
|
492
|
+
function createA365OboTokenResolver(options = {}) {
|
|
493
|
+
let cachePromise;
|
|
494
|
+
return async (agentId, tenantId) => {
|
|
495
|
+
cachePromise ??= getAgenticTokenCache(options);
|
|
496
|
+
const cache = await cachePromise;
|
|
497
|
+
return cache.getObservabilityToken(agentId, tenantId);
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
async function refreshA365OboObservabilityToken(options) {
|
|
501
|
+
const cache = await getAgenticTokenCache(options);
|
|
502
|
+
await cache.RefreshObservabilityToken(
|
|
503
|
+
options.agentId,
|
|
504
|
+
options.tenantId,
|
|
505
|
+
options.turnContext,
|
|
506
|
+
options.authorization,
|
|
507
|
+
options.scopes ?? [],
|
|
508
|
+
options.authHandlerName
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
async function invalidateA365OboObservabilityToken(agentId, tenantId, options = {}) {
|
|
512
|
+
const cache = await getAgenticTokenCache(options);
|
|
513
|
+
cache.invalidateToken?.(agentId, tenantId);
|
|
514
|
+
}
|
|
515
|
+
async function invalidateAllA365OboObservabilityTokens(options = {}) {
|
|
516
|
+
const cache = await getAgenticTokenCache(options);
|
|
517
|
+
cache.invalidateAll?.();
|
|
518
|
+
}
|
|
519
|
+
async function getAgenticTokenCache(options) {
|
|
520
|
+
if (options.cache) {
|
|
521
|
+
return options.cache;
|
|
522
|
+
}
|
|
523
|
+
const module = await loadObservabilityHostingModule(options);
|
|
524
|
+
return getCacheFromModule(module);
|
|
525
|
+
}
|
|
526
|
+
function getCacheFromModule(module) {
|
|
527
|
+
if (module.AgenticTokenCacheInstance) {
|
|
528
|
+
return module.AgenticTokenCacheInstance;
|
|
529
|
+
}
|
|
530
|
+
if (module.AgenticTokenCache) {
|
|
531
|
+
return new module.AgenticTokenCache();
|
|
532
|
+
}
|
|
533
|
+
throw new Error(
|
|
534
|
+
"Agent 365 observability hosting module does not export AgenticTokenCache."
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/context/baggage-keys.ts
|
|
539
|
+
var A365_BAGGAGE_KEYS = {
|
|
540
|
+
tenantId: "microsoft.tenant.id",
|
|
541
|
+
agentId: "gen_ai.agent.id",
|
|
542
|
+
agentName: "gen_ai.agent.name",
|
|
543
|
+
agentDescription: "gen_ai.agent.description",
|
|
544
|
+
agentVersion: "gen_ai.agent.version",
|
|
545
|
+
agentPlatformId: "microsoft.a365.agent.platform.id",
|
|
546
|
+
agentAuid: "microsoft.agent.user.id",
|
|
547
|
+
agentEmail: "microsoft.agent.user.email",
|
|
548
|
+
agentBlueprintId: "microsoft.a365.agent.blueprint.id",
|
|
549
|
+
sessionId: "microsoft.session.id",
|
|
550
|
+
sessionDescription: "microsoft.session.description",
|
|
551
|
+
conversationId: "gen_ai.conversation.id",
|
|
552
|
+
conversationItemLink: "microsoft.conversation.item.link",
|
|
553
|
+
channelName: "microsoft.channel.name",
|
|
554
|
+
channelLink: "microsoft.channel.link",
|
|
555
|
+
userId: "user.id",
|
|
556
|
+
userName: "user.name",
|
|
557
|
+
userEmail: "user.email",
|
|
558
|
+
callerClientIp: "client.address",
|
|
559
|
+
callerAgentId: "microsoft.a365.caller.agent.id",
|
|
560
|
+
callerAgentName: "microsoft.a365.caller.agent.name",
|
|
561
|
+
callerAgentAuid: "microsoft.a365.caller.agent.user.id",
|
|
562
|
+
callerAgentEmail: "microsoft.a365.caller.agent.user.email",
|
|
563
|
+
callerAgentBlueprintId: "microsoft.a365.caller.agent.blueprint.id",
|
|
564
|
+
callerAgentPlatformId: "microsoft.a365.caller.agent.platform.id",
|
|
565
|
+
callerAgentVersion: "microsoft.a365.caller.agent.version",
|
|
566
|
+
serviceName: "service.name",
|
|
567
|
+
serverAddress: "server.address",
|
|
568
|
+
serverPort: "server.port"
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
// src/context/baggage.ts
|
|
119
572
|
function buildA365BaggagePairs(context) {
|
|
120
573
|
const pairs = {};
|
|
121
574
|
for (const [key, value] of Object.entries(context.extraBaggage ?? {})) {
|
|
@@ -173,28 +626,7 @@ function buildA365BaggagePairs(context) {
|
|
|
173
626
|
return pairs;
|
|
174
627
|
}
|
|
175
628
|
|
|
176
|
-
// src/
|
|
177
|
-
function createA365TracingConfig(options = {}) {
|
|
178
|
-
const spanAttributes = {
|
|
179
|
-
...options.spanAttributes ?? {}
|
|
180
|
-
};
|
|
181
|
-
if (isNonEmpty(options.tenantId)) {
|
|
182
|
-
spanAttributes[A365_BAGGAGE_KEYS.tenantId] = options.tenantId.trim();
|
|
183
|
-
}
|
|
184
|
-
return {
|
|
185
|
-
...isNonEmpty(options.agentId) ? { agentId: options.agentId.trim() } : {},
|
|
186
|
-
...isNonEmpty(options.agentDescription) ? { agentDescription: options.agentDescription.trim() } : {},
|
|
187
|
-
...isNonEmpty(options.agentVersion) ? { agentVersion: options.agentVersion.trim() } : {},
|
|
188
|
-
...options.useGenAIOpenTelemetry !== void 0 ? { useGenAIOpenTelemetry: options.useGenAIOpenTelemetry } : {},
|
|
189
|
-
...options.telemetryIntegrations ? { telemetryIntegrations: options.telemetryIntegrations } : {},
|
|
190
|
-
...options.useGlobalTelemetryIntegrations !== void 0 ? {
|
|
191
|
-
useGlobalTelemetryIntegrations: options.useGlobalTelemetryIntegrations
|
|
192
|
-
} : {},
|
|
193
|
-
...Object.keys(spanAttributes).length > 0 ? { spanAttributes } : {}
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// src/turn-context.ts
|
|
629
|
+
// src/context/turn-context.ts
|
|
198
630
|
function createA365ContextFromTurnContext(turnContext, options = {}) {
|
|
199
631
|
const { serviceUrl, useRecipientIdAsAgentId, ...requestOptions } = options;
|
|
200
632
|
const activity = turnContext.activity ?? {};
|
|
@@ -215,132 +647,144 @@ function createA365ContextFromTurnContext(turnContext, options = {}) {
|
|
|
215
647
|
readPath(channelData, ["tenant", "id"]),
|
|
216
648
|
readPath(channelData, ["tenantId"])
|
|
217
649
|
);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
650
|
+
const agentName = firstNonEmpty(
|
|
651
|
+
requestOptions.agentName,
|
|
652
|
+
activity.recipient?.name
|
|
653
|
+
);
|
|
654
|
+
const agentDescription = firstNonEmpty(
|
|
655
|
+
requestOptions.agentDescription,
|
|
656
|
+
activity.recipient?.role
|
|
657
|
+
);
|
|
658
|
+
const conversationId = firstNonEmpty(
|
|
659
|
+
requestOptions.conversationId,
|
|
660
|
+
activity.conversation?.id
|
|
661
|
+
);
|
|
662
|
+
const conversationItemLink = firstNonEmpty(
|
|
663
|
+
requestOptions.conversationItemLink,
|
|
664
|
+
activity.serviceUrl
|
|
665
|
+
);
|
|
666
|
+
const sessionId = firstNonEmpty(
|
|
667
|
+
requestOptions.sessionId,
|
|
668
|
+
requestOptions.conversationId,
|
|
669
|
+
activity.conversation?.id
|
|
670
|
+
);
|
|
671
|
+
const userId = firstNonEmpty(
|
|
672
|
+
requestOptions.userId,
|
|
673
|
+
activity.from?.aadObjectId,
|
|
674
|
+
activity.from?.id,
|
|
675
|
+
readPath(turnContext.identity, ["oid"]),
|
|
676
|
+
readPath(turnContext.identity, ["sub"])
|
|
677
|
+
);
|
|
678
|
+
const userEmail = firstNonEmpty(
|
|
679
|
+
requestOptions.userEmail,
|
|
680
|
+
activity.from?.email,
|
|
681
|
+
activity.from?.userPrincipalName,
|
|
682
|
+
activity.from?.agenticUserId,
|
|
683
|
+
readPath(channelData, ["from", "userPrincipalName"]),
|
|
684
|
+
readPath(turnContext.identity, ["preferred_username"]),
|
|
685
|
+
readPath(turnContext.identity, ["upn"])
|
|
686
|
+
);
|
|
687
|
+
const context = { ...requestOptions };
|
|
688
|
+
setIfDefined(context, "tenantId", tenantId);
|
|
689
|
+
setIfDefined(context, "agentId", agentId);
|
|
690
|
+
setIfDefined(context, "agentName", agentName);
|
|
691
|
+
setIfDefined(context, "agentDescription", agentDescription);
|
|
692
|
+
setIfDefined(
|
|
693
|
+
context,
|
|
694
|
+
"agentAuid",
|
|
695
|
+
firstNonEmpty(requestOptions.agentAuid, activity.recipient?.aadObjectId)
|
|
696
|
+
);
|
|
697
|
+
setIfDefined(
|
|
698
|
+
context,
|
|
699
|
+
"agentBlueprintId",
|
|
700
|
+
firstNonEmpty(
|
|
243
701
|
requestOptions.agentBlueprintId,
|
|
244
702
|
activity.recipient?.agenticAppBlueprintId
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
requestOptions.sessionId,
|
|
272
|
-
requestOptions.conversationId,
|
|
273
|
-
activity.conversation?.id
|
|
274
|
-
)
|
|
275
|
-
} : {},
|
|
276
|
-
...firstNonEmpty(requestOptions.channelName, activity.channelId) ? {
|
|
277
|
-
channelName: firstNonEmpty(
|
|
278
|
-
requestOptions.channelName,
|
|
279
|
-
activity.channelId
|
|
280
|
-
)
|
|
281
|
-
} : {},
|
|
282
|
-
...firstNonEmpty(requestOptions.channelLink, activity.channelIdSubChannel) ? {
|
|
283
|
-
channelLink: firstNonEmpty(
|
|
284
|
-
requestOptions.channelLink,
|
|
285
|
-
activity.channelIdSubChannel
|
|
286
|
-
)
|
|
287
|
-
} : {},
|
|
288
|
-
...firstNonEmpty(
|
|
289
|
-
requestOptions.userId,
|
|
290
|
-
activity.from?.aadObjectId,
|
|
291
|
-
activity.from?.id,
|
|
292
|
-
readPath(turnContext.identity, ["oid"]),
|
|
293
|
-
readPath(turnContext.identity, ["sub"])
|
|
294
|
-
) ? {
|
|
295
|
-
userId: firstNonEmpty(
|
|
296
|
-
requestOptions.userId,
|
|
297
|
-
activity.from?.aadObjectId,
|
|
298
|
-
activity.from?.id,
|
|
299
|
-
readPath(turnContext.identity, ["oid"]),
|
|
300
|
-
readPath(turnContext.identity, ["sub"])
|
|
301
|
-
)
|
|
302
|
-
} : {},
|
|
303
|
-
...firstNonEmpty(requestOptions.userName, activity.from?.name) ? {
|
|
304
|
-
userName: firstNonEmpty(requestOptions.userName, activity.from?.name)
|
|
305
|
-
} : {},
|
|
306
|
-
// Mirrors Microsoft's A365 observability-hosting helper, which treats
|
|
307
|
-
// agenticUserId as the caller UPN/email value.
|
|
308
|
-
...firstNonEmpty(
|
|
309
|
-
requestOptions.userEmail,
|
|
310
|
-
activity.from?.email,
|
|
311
|
-
activity.from?.userPrincipalName,
|
|
312
|
-
activity.from?.agenticUserId,
|
|
313
|
-
readPath(channelData, ["from", "userPrincipalName"]),
|
|
314
|
-
readPath(turnContext.identity, ["preferred_username"]),
|
|
315
|
-
readPath(turnContext.identity, ["upn"])
|
|
316
|
-
) ? {
|
|
317
|
-
userEmail: firstNonEmpty(
|
|
318
|
-
requestOptions.userEmail,
|
|
319
|
-
activity.from?.email,
|
|
320
|
-
activity.from?.userPrincipalName,
|
|
321
|
-
activity.from?.agenticUserId,
|
|
322
|
-
readPath(channelData, ["from", "userPrincipalName"]),
|
|
323
|
-
readPath(turnContext.identity, ["preferred_username"]),
|
|
324
|
-
readPath(turnContext.identity, ["upn"])
|
|
325
|
-
)
|
|
326
|
-
} : {},
|
|
327
|
-
...firstNonEmpty(
|
|
703
|
+
)
|
|
704
|
+
);
|
|
705
|
+
setIfDefined(context, "conversationId", conversationId);
|
|
706
|
+
setIfDefined(context, "conversationItemLink", conversationItemLink);
|
|
707
|
+
setIfDefined(context, "sessionId", sessionId);
|
|
708
|
+
setIfDefined(
|
|
709
|
+
context,
|
|
710
|
+
"channelName",
|
|
711
|
+
firstNonEmpty(requestOptions.channelName, activity.channelId)
|
|
712
|
+
);
|
|
713
|
+
setIfDefined(
|
|
714
|
+
context,
|
|
715
|
+
"channelLink",
|
|
716
|
+
firstNonEmpty(requestOptions.channelLink, activity.channelIdSubChannel)
|
|
717
|
+
);
|
|
718
|
+
setIfDefined(context, "userId", userId);
|
|
719
|
+
setIfDefined(
|
|
720
|
+
context,
|
|
721
|
+
"userName",
|
|
722
|
+
firstNonEmpty(requestOptions.userName, activity.from?.name)
|
|
723
|
+
);
|
|
724
|
+
setIfDefined(context, "userEmail", userEmail);
|
|
725
|
+
setIfDefined(
|
|
726
|
+
context,
|
|
727
|
+
"callerAgentBlueprintId",
|
|
728
|
+
firstNonEmpty(
|
|
328
729
|
requestOptions.callerAgentBlueprintId,
|
|
329
730
|
activity.from?.agenticAppBlueprintId
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
731
|
+
)
|
|
732
|
+
);
|
|
733
|
+
setIfDefined(
|
|
734
|
+
context,
|
|
735
|
+
"serverAddress",
|
|
736
|
+
firstNonEmpty(requestOptions.serverAddress, endpoint?.serverAddress)
|
|
737
|
+
);
|
|
738
|
+
setIfDefined(
|
|
739
|
+
context,
|
|
740
|
+
"serverPort",
|
|
741
|
+
requestOptions.serverPort ?? endpoint?.serverPort
|
|
742
|
+
);
|
|
743
|
+
return context;
|
|
744
|
+
}
|
|
745
|
+
function setIfDefined(context, key, value) {
|
|
746
|
+
if (value !== void 0) {
|
|
747
|
+
context[key] = value;
|
|
748
|
+
}
|
|
339
749
|
}
|
|
340
750
|
|
|
341
|
-
// src/
|
|
342
|
-
var
|
|
751
|
+
// src/runtime/per-request-config.ts
|
|
752
|
+
var PER_REQUEST_ENV = {
|
|
753
|
+
enabled: "ENABLE_A365_OBSERVABILITY_PER_REQUEST_EXPORT",
|
|
754
|
+
maxTraces: "A365_PER_REQUEST_MAX_TRACES",
|
|
755
|
+
maxSpansPerTrace: "A365_PER_REQUEST_MAX_SPANS_PER_TRACE",
|
|
756
|
+
maxConcurrentExports: "A365_PER_REQUEST_MAX_CONCURRENT_EXPORTS",
|
|
757
|
+
flushGraceMs: "A365_PER_REQUEST_FLUSH_GRACE_MS",
|
|
758
|
+
maxTraceAgeMs: "A365_PER_REQUEST_MAX_TRACE_AGE_MS"
|
|
759
|
+
};
|
|
760
|
+
function applyA365PerRequestEnvironment(configuration, env = process.env) {
|
|
761
|
+
if (!configuration) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
setEnv(env, PER_REQUEST_ENV.enabled, formatBoolean(configuration.enabled));
|
|
765
|
+
setEnv(env, PER_REQUEST_ENV.maxTraces, configuration.maxTraces);
|
|
766
|
+
setEnv(env, PER_REQUEST_ENV.maxSpansPerTrace, configuration.maxSpansPerTrace);
|
|
767
|
+
setEnv(
|
|
768
|
+
env,
|
|
769
|
+
PER_REQUEST_ENV.maxConcurrentExports,
|
|
770
|
+
configuration.maxConcurrentExports
|
|
771
|
+
);
|
|
772
|
+
setEnv(env, PER_REQUEST_ENV.flushGraceMs, configuration.flushGraceMs);
|
|
773
|
+
setEnv(env, PER_REQUEST_ENV.maxTraceAgeMs, configuration.maxTraceAgeMs);
|
|
774
|
+
}
|
|
775
|
+
function setEnv(env, key, value) {
|
|
776
|
+
if (value === void 0) {
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
env[key] = String(value);
|
|
780
|
+
}
|
|
781
|
+
function formatBoolean(value) {
|
|
782
|
+
return value === void 0 ? void 0 : value ? "true" : "false";
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/runtime/lifecycle.ts
|
|
343
786
|
async function initA365Observability(options) {
|
|
787
|
+
applyA365PerRequestEnvironment(options.configuration?.perRequest);
|
|
344
788
|
const module = await loadObservabilityModule(options);
|
|
345
789
|
const configProvider = createConfigurationProvider(
|
|
346
790
|
module,
|
|
@@ -385,19 +829,6 @@ async function updateA365ExportToken(token, options = {}) {
|
|
|
385
829
|
const module = await loadObservabilityModule(options);
|
|
386
830
|
return module.updateExportToken?.(token) ?? false;
|
|
387
831
|
}
|
|
388
|
-
async function loadObservabilityModule(options = {}) {
|
|
389
|
-
try {
|
|
390
|
-
if (options.getObservabilityModule) {
|
|
391
|
-
return await options.getObservabilityModule();
|
|
392
|
-
}
|
|
393
|
-
return await import(OBSERVABILITY_PACKAGE);
|
|
394
|
-
} catch (error) {
|
|
395
|
-
throw new A365ObservabilityModuleLoadError(
|
|
396
|
-
`Unable to load ${OBSERVABILITY_PACKAGE}. Install @microsoft/agents-a365-observability and @microsoft/agents-a365-runtime before using @cuylabs/agent-a365-observability.`,
|
|
397
|
-
{ cause: error }
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
832
|
function createConfigurationProvider(module, configuration) {
|
|
402
833
|
if (!configuration) {
|
|
403
834
|
return void 0;
|
|
@@ -430,7 +861,7 @@ function normalizeCustomLogger(customLogger) {
|
|
|
430
861
|
};
|
|
431
862
|
}
|
|
432
863
|
|
|
433
|
-
// src/turn-runner.ts
|
|
864
|
+
// src/context/turn-runner.ts
|
|
434
865
|
async function runWithA365TurnContext(turnContext, optionsOrFn, maybeFnOrRuntime, maybeRuntime) {
|
|
435
866
|
const options = typeof optionsOrFn === "function" ? {} : optionsOrFn ?? {};
|
|
436
867
|
const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFnOrRuntime;
|
|
@@ -444,14 +875,187 @@ async function runWithA365TurnContext(turnContext, optionsOrFn, maybeFnOrRuntime
|
|
|
444
875
|
runtimeOptions
|
|
445
876
|
);
|
|
446
877
|
}
|
|
878
|
+
|
|
879
|
+
// src/runtime/s2s.ts
|
|
880
|
+
async function initA365S2SObservability(options) {
|
|
881
|
+
const env = resolveA365ObservabilityEnvironment(options.s2s?.env);
|
|
882
|
+
const tokenResolver = createA365S2STokenResolverFromEnv(options.s2s);
|
|
883
|
+
return await initA365Observability({
|
|
884
|
+
...options,
|
|
885
|
+
tokenResolver,
|
|
886
|
+
exporterOptions: {
|
|
887
|
+
...options.exporterOptions,
|
|
888
|
+
useS2SEndpoint: true
|
|
889
|
+
},
|
|
890
|
+
configuration: {
|
|
891
|
+
...env.configuration,
|
|
892
|
+
...options.configuration,
|
|
893
|
+
exporterEnabled: options.configuration?.exporterEnabled ?? env.configuration.exporterEnabled ?? true,
|
|
894
|
+
perRequest: {
|
|
895
|
+
...env.configuration.perRequest,
|
|
896
|
+
...options.configuration?.perRequest
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// src/tracing/tracing-config.ts
|
|
903
|
+
function createA365TracingConfig(options = {}) {
|
|
904
|
+
const spanAttributes = {
|
|
905
|
+
...options.spanAttributes ?? {}
|
|
906
|
+
};
|
|
907
|
+
if (isNonEmpty(options.tenantId)) {
|
|
908
|
+
spanAttributes[A365_BAGGAGE_KEYS.tenantId] = options.tenantId.trim();
|
|
909
|
+
}
|
|
910
|
+
return {
|
|
911
|
+
...isNonEmpty(options.agentId) ? { agentId: options.agentId.trim() } : {},
|
|
912
|
+
...isNonEmpty(options.agentDescription) ? { agentDescription: options.agentDescription.trim() } : {},
|
|
913
|
+
...isNonEmpty(options.agentVersion) ? { agentVersion: options.agentVersion.trim() } : {},
|
|
914
|
+
...options.useGenAIOpenTelemetry !== void 0 ? { useGenAIOpenTelemetry: options.useGenAIOpenTelemetry } : {},
|
|
915
|
+
...options.telemetryIntegrations ? { telemetryIntegrations: options.telemetryIntegrations } : {},
|
|
916
|
+
...options.useGlobalTelemetryIntegrations !== void 0 ? {
|
|
917
|
+
useGlobalTelemetryIntegrations: options.useGlobalTelemetryIntegrations
|
|
918
|
+
} : {},
|
|
919
|
+
...Object.keys(spanAttributes).length > 0 ? { spanAttributes } : {}
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// src/tracing/trace-context.ts
|
|
924
|
+
async function injectA365TraceContextToHeaders(headers = {}, options = {}) {
|
|
925
|
+
const module = await loadObservabilityModule(options);
|
|
926
|
+
if (!module.injectContextToHeaders) {
|
|
927
|
+
throw new Error(
|
|
928
|
+
"Agent 365 observability module does not export injectContextToHeaders."
|
|
929
|
+
);
|
|
930
|
+
}
|
|
931
|
+
return module.injectContextToHeaders(headers, options.context);
|
|
932
|
+
}
|
|
933
|
+
async function extractA365TraceContextFromHeaders(headers, options = {}) {
|
|
934
|
+
const module = await loadObservabilityModule(options);
|
|
935
|
+
if (!module.extractContextFromHeaders) {
|
|
936
|
+
throw new Error(
|
|
937
|
+
"Agent 365 observability module does not export extractContextFromHeaders."
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
return module.extractContextFromHeaders(headers, options.context);
|
|
941
|
+
}
|
|
942
|
+
async function runWithA365ExtractedTraceContext(headers, fn, options = {}) {
|
|
943
|
+
const module = await loadObservabilityModule(options);
|
|
944
|
+
if (!module.runWithExtractedTraceContext) {
|
|
945
|
+
throw new Error(
|
|
946
|
+
"Agent 365 observability module does not export runWithExtractedTraceContext."
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
return await module.runWithExtractedTraceContext(headers, fn);
|
|
950
|
+
}
|
|
951
|
+
async function runWithA365ParentSpanRef(parent, fn, options = {}) {
|
|
952
|
+
const module = await loadObservabilityModule(options);
|
|
953
|
+
if (!module.runWithParentSpanRef) {
|
|
954
|
+
throw new Error(
|
|
955
|
+
"Agent 365 observability module does not export runWithParentSpanRef."
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
return await module.runWithParentSpanRef(parent, fn);
|
|
959
|
+
}
|
|
960
|
+
async function createA365ContextWithParentSpanRef(baseContext, parent, options = {}) {
|
|
961
|
+
const module = await loadObservabilityModule(options);
|
|
962
|
+
if (!module.createContextWithParentSpanRef) {
|
|
963
|
+
throw new Error(
|
|
964
|
+
"Agent 365 observability module does not export createContextWithParentSpanRef."
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
return module.createContextWithParentSpanRef(baseContext, parent);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/tracing/output-scope.ts
|
|
971
|
+
async function runWithA365OutputMessages(output, fn, options = {}) {
|
|
972
|
+
const module = await loadObservabilityModule(options);
|
|
973
|
+
if (!module.OutputScope) {
|
|
974
|
+
throw new Error(
|
|
975
|
+
"Agent 365 observability module does not export OutputScope."
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
const outputScope = module.OutputScope.start(
|
|
979
|
+
createOutputRequest(output),
|
|
980
|
+
{ messages: output.messages },
|
|
981
|
+
createAgentDetails(output),
|
|
982
|
+
createUserDetails(output),
|
|
983
|
+
output.parentSpan ? { parentContext: output.parentSpan } : void 0
|
|
984
|
+
);
|
|
985
|
+
try {
|
|
986
|
+
return await fn();
|
|
987
|
+
} catch (error) {
|
|
988
|
+
outputScope.recordError?.(normalizeError(error));
|
|
989
|
+
throw error;
|
|
990
|
+
} finally {
|
|
991
|
+
outputScope.dispose();
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
function createOutputRequest(context) {
|
|
995
|
+
return {
|
|
996
|
+
conversationId: context.conversationId,
|
|
997
|
+
sessionId: context.sessionId,
|
|
998
|
+
channel: context.channelName || context.channelLink ? {
|
|
999
|
+
name: context.channelName,
|
|
1000
|
+
description: context.channelLink
|
|
1001
|
+
} : void 0
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
function createAgentDetails(context) {
|
|
1005
|
+
return {
|
|
1006
|
+
tenantId: context.tenantId,
|
|
1007
|
+
agentId: context.agentId,
|
|
1008
|
+
agentName: context.agentName,
|
|
1009
|
+
agentDescription: context.agentDescription,
|
|
1010
|
+
agentVersion: context.agentVersion,
|
|
1011
|
+
agentPlatformId: context.agentPlatformId,
|
|
1012
|
+
agentAUID: context.agentAuid,
|
|
1013
|
+
agentEmail: context.agentEmail,
|
|
1014
|
+
agentBlueprintId: context.agentBlueprintId
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
function createUserDetails(context) {
|
|
1018
|
+
if (!context.userId && !context.userName && !context.userEmail) {
|
|
1019
|
+
return void 0;
|
|
1020
|
+
}
|
|
1021
|
+
return {
|
|
1022
|
+
tenantId: context.tenantId,
|
|
1023
|
+
userId: context.userId,
|
|
1024
|
+
userName: context.userName,
|
|
1025
|
+
userEmail: context.userEmail
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
function normalizeError(error) {
|
|
1029
|
+
if (error instanceof Error) {
|
|
1030
|
+
return error;
|
|
1031
|
+
}
|
|
1032
|
+
return new Error(typeof error === "string" ? error : JSON.stringify(error));
|
|
1033
|
+
}
|
|
447
1034
|
export {
|
|
1035
|
+
A365ObservabilityHostingModuleLoadError,
|
|
448
1036
|
A365ObservabilityModuleLoadError,
|
|
449
1037
|
A365_BAGGAGE_KEYS,
|
|
1038
|
+
A365_EXPORTER_EVENT_NAMES,
|
|
1039
|
+
applyA365PerRequestEnvironment,
|
|
450
1040
|
buildA365BaggagePairs,
|
|
451
1041
|
createA365ContextFromTurnContext,
|
|
1042
|
+
createA365ContextWithParentSpanRef,
|
|
1043
|
+
createA365OboTokenResolver,
|
|
1044
|
+
createA365S2STokenResolver,
|
|
1045
|
+
createA365S2STokenResolverFromEnv,
|
|
452
1046
|
createA365TracingConfig,
|
|
1047
|
+
extractA365TraceContextFromHeaders,
|
|
453
1048
|
initA365Observability,
|
|
1049
|
+
initA365S2SObservability,
|
|
1050
|
+
injectA365TraceContextToHeaders,
|
|
1051
|
+
invalidateA365OboObservabilityToken,
|
|
1052
|
+
invalidateAllA365OboObservabilityTokens,
|
|
1053
|
+
refreshA365OboObservabilityToken,
|
|
1054
|
+
resolveA365ObservabilityEnvironment,
|
|
454
1055
|
runWithA365Context,
|
|
1056
|
+
runWithA365ExtractedTraceContext,
|
|
1057
|
+
runWithA365OutputMessages,
|
|
1058
|
+
runWithA365ParentSpanRef,
|
|
455
1059
|
runWithA365TurnContext,
|
|
456
1060
|
updateA365ExportToken
|
|
457
1061
|
};
|