Skip to content

Commit adecb7f

Browse files
CopilotnikhilNava
andauthored
Default a365 exporter endpoint to agent365.svc.cloud.microsoft (#212)
* Initial plan * Default exporter to custom domain endpoint, update URL paths to include tenantId - Remove PowerPlatformApiDiscovery from exporter, always use custom domain - Endpoint resolution: domain override > resolveAgent365Endpoint() - Update URL paths: /observability/tenants/{tenantId}/agents/{agentId}/traces - S2S paths: /observabilityService/tenants/{tenantId}/agents/{agentId}/traces - Always include x-ms-tenant-id header - Update tests to reflect new default behavior Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
1 parent 1d68ffa commit adecb7f

13 files changed

Lines changed: 29 additions & 205 deletions

File tree

CLAUDE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ The keyword "Kairo" is legacy and should not appear in any code. Flag and remove
213213
| `A365_OBSERVABILITY_SCOPES_OVERRIDE` | Override observability auth scopes | Space-separated scope strings |
214214
| `ENABLE_A365_OBSERVABILITY_EXPORTER` | Enable Agent365 exporter | `true`, `false` (default) |
215215
| `ENABLE_A365_OBSERVABILITY_PER_REQUEST_EXPORT` | Enable per-request export mode | `true`, `false` (default) |
216-
| `A365_OBSERVABILITY_USE_CUSTOM_DOMAIN` | Use custom domain for export | `true`, `false` (default) |
217216
| `A365_OBSERVABILITY_DOMAIN_OVERRIDE` | Custom domain URL override | URL string |
218217
| `A365_OBSERVABILITY_LOG_LEVEL` | Internal logging level | `none` (default), `error`, `warn`, `info`, `debug` |
219218
| `A365_PER_REQUEST_MAX_TRACES` | Max buffered traces per request (`PerRequestSpanProcessorConfiguration`) | Number (default: 1000) |

docs/prd-configuration-provider.md

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ The Agent365 SDK currently relies on environment variables for all configuration
6666
|---------|--------------|---------|------|---------|
6767
| `observabilityAuthenticationScopes` | `A365_OBSERVABILITY_SCOPES_OVERRIDE` | `['https://api.powerplatform.com/.default']` | `string[]` | ObservabilityConfiguration |
6868
| `isObservabilityExporterEnabled` | `ENABLE_A365_OBSERVABILITY_EXPORTER` | `false` | `boolean` | ObservabilityConfiguration |
69-
| `useCustomDomainForObservability` | `A365_OBSERVABILITY_USE_CUSTOM_DOMAIN` | `false` | `boolean` | ObservabilityConfiguration |
7069
| `observabilityDomainOverride` | `A365_OBSERVABILITY_DOMAIN_OVERRIDE` | `null` | `string \| null` | ObservabilityConfiguration |
7170
| `observabilityLogLevel` | `A365_OBSERVABILITY_LOG_LEVEL` | `'none'` | `string` | ObservabilityConfiguration |
7271

@@ -392,7 +391,6 @@ export type ObservabilityConfigurationOptions = RuntimeConfigurationOptions & {
392391
*/
393392
observabilityAuthenticationScopes?: () => string[];
394393
isObservabilityExporterEnabled?: () => boolean;
395-
useCustomDomainForObservability?: () => boolean;
396394
observabilityDomainOverride?: () => string | null;
397395
observabilityLogLevel?: () => string;
398396
};
@@ -449,15 +447,6 @@ export class ObservabilityConfiguration extends RuntimeConfiguration {
449447
return ['true', '1', 'yes', 'on'].includes(value);
450448
}
451449

452-
get useCustomDomainForObservability(): boolean {
453-
const result = this.observabilityOverrides.useCustomDomainForObservability?.();
454-
if (result !== undefined) {
455-
return result;
456-
}
457-
const value = process.env.A365_OBSERVABILITY_USE_CUSTOM_DOMAIN?.toLowerCase() ?? '';
458-
return ['true', '1', 'yes', 'on'].includes(value);
459-
}
460-
461450
get observabilityDomainOverride(): string | null {
462451
const result = this.observabilityOverrides.observabilityDomainOverride?.();
463452
if (result !== undefined) {
@@ -666,7 +655,6 @@ packages/agents-a365-observability-extensions-openai/src/
666655
2. **`tests/observability/tracing/exporter-utils.test.ts`** (NEW)
667656
- `isAgent365ExporterEnabled()` with all boolean variants
668657
- `isPerRequestExportEnabled()` with all boolean variants
669-
- `useCustomDomainForObservability()` edge cases
670658
- `getAgent365ObservabilityDomainOverride()` edge cases
671659
- `resolveAgent365Endpoint()` for all cluster categories
672660

@@ -1173,7 +1161,6 @@ These methods remain available for backward compatibility but should not be used
11731161
| `A365_OBSERVABILITY_SCOPES_OVERRIDE` | string (space-sep) | prod scope | observability |
11741162
| `ENABLE_A365_OBSERVABILITY_EXPORTER` | boolean | `false` | observability |
11751163
| `ENABLE_A365_OBSERVABILITY_PER_REQUEST_EXPORT` | boolean | `false` | observability (PerRequestSpanProcessorConfiguration) |
1176-
| `A365_OBSERVABILITY_USE_CUSTOM_DOMAIN` | boolean | `false` | observability |
11771164
| `A365_OBSERVABILITY_DOMAIN_OVERRIDE` | string | `null` | observability |
11781165
| `A365_OBSERVABILITY_LOG_LEVEL` | string | `'none'` | observability |
11791166
| `A365_PER_REQUEST_MAX_TRACES` | number | `1000` | observability (PerRequestSpanProcessorConfiguration) |

packages/agents-a365-observability-extensions-openai/src/configuration/OpenAIObservabilityConfiguration.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,5 @@ export class OpenAIObservabilityConfiguration extends ObservabilityConfiguration
5757
}
5858

5959
// Inherited: clusterCategory, isDevelopmentEnvironment, observabilityAuthenticationScopes,
60-
// isObservabilityExporterEnabled, useCustomDomainForObservability,
61-
// observabilityDomainOverride, observabilityLogLevel
60+
// isObservabilityExporterEnabled, observabilityDomainOverride, observabilityLogLevel
6261
}

packages/agents-a365-observability/docs/design.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,6 @@ const customConfig = new ObservabilityConfiguration({
444444
|----------|--------------|---------|-------------|
445445
| `observabilityAuthenticationScopes` | `A365_OBSERVABILITY_SCOPES_OVERRIDE` | `['https://api.powerplatform.com/.default']` | OAuth scopes for observability auth |
446446
| `isObservabilityExporterEnabled` | `ENABLE_A365_OBSERVABILITY_EXPORTER` | `false` | Enable Agent365 exporter |
447-
| `useCustomDomainForObservability` | `A365_OBSERVABILITY_USE_CUSTOM_DOMAIN` | `false` | Use custom domain for export |
448447
| `observabilityDomainOverride` | `A365_OBSERVABILITY_DOMAIN_OVERRIDE` | `null` | Custom domain URL override |
449448
| `observabilityLogLevel` | `A365_OBSERVABILITY_LOG_LEVEL` | `none` | Internal logging level |
450449
| `clusterCategory` | `CLUSTER_CATEGORY` | `prod` | (Inherited) Environment cluster |
@@ -482,7 +481,6 @@ console.log(config.perRequestMaxTraces); // Max buffered traces (default: 1000)
482481
| `ENABLE_A365_OBSERVABILITY_EXPORTER` | Enable/disable Agent365 exporter | `false` |
483482
| `A365_OBSERVABILITY_SCOPES_OVERRIDE` | Override auth scopes (space-separated) | Production scope |
484483
| `ENABLE_A365_OBSERVABILITY_PER_REQUEST_EXPORT` | Enable per-request export mode | `false` |
485-
| `A365_OBSERVABILITY_USE_CUSTOM_DOMAIN` | Use custom domain for export | `false` |
486484
| `A365_OBSERVABILITY_DOMAIN_OVERRIDE` | Custom domain URL | - |
487485
| `A365_OBSERVABILITY_LOG_LEVEL` | Internal log level | `none` |
488486
| `A365_PER_REQUEST_MAX_TRACES` | Max buffered traces (`PerRequestSpanProcessorConfiguration`) | `1000` |

packages/agents-a365-observability/src/configuration/ObservabilityConfiguration.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,6 @@ export class ObservabilityConfiguration extends RuntimeConfiguration {
4444
return RuntimeConfiguration.parseEnvBoolean(process.env.ENABLE_A365_OBSERVABILITY_EXPORTER);
4545
}
4646

47-
get useCustomDomainForObservability(): boolean {
48-
const result = this.observabilityOverrides.useCustomDomainForObservability?.();
49-
if (result !== undefined) return result;
50-
return RuntimeConfiguration.parseEnvBoolean(process.env.A365_OBSERVABILITY_USE_CUSTOM_DOMAIN);
51-
}
52-
5347
get observabilityDomainOverride(): string | null {
5448
const result = this.observabilityOverrides.observabilityDomainOverride?.();
5549
if (result !== undefined) {

packages/agents-a365-observability/src/configuration/ObservabilityConfigurationOptions.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,8 @@ export type ObservabilityConfigurationOptions = RuntimeConfigurationOptions & {
3535
*/
3636
isObservabilityExporterEnabled?: () => boolean;
3737

38-
/**
39-
* Override to enable/disable custom domain for observability endpoints.
40-
* When enabled, uses `observabilityDomainOverride` instead of the default endpoint.
41-
*
42-
* @returns `true` to use custom domain, `false` to use default.
43-
* @envvar A365_OBSERVABILITY_USE_CUSTOM_DOMAIN - 'true', '1', 'yes', 'on' to enable.
44-
* @default false
45-
*/
46-
useCustomDomainForObservability?: () => boolean;
47-
4838
/**
4939
* Override for the custom observability domain/endpoint.
50-
* Only used when `useCustomDomainForObservability` is true.
5140
* Trailing slashes are automatically removed.
5241
*
5342
* @returns Custom domain URL string, or `null` for no override.

packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { ExportResult, ExportResultCode } from '@opentelemetry/core';
77
import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';
88

9-
import { PowerPlatformApiDiscovery, ClusterCategory, IConfigurationProvider } from '@microsoft/agents-a365-runtime';
9+
import { ClusterCategory, IConfigurationProvider } from '@microsoft/agents-a365-runtime';
1010
import type { ObservabilityConfiguration } from '../../configuration';
1111
import {
1212
partitionByIdentity,
@@ -15,7 +15,6 @@ import {
1515
hexSpanId,
1616
kindName,
1717
statusName,
18-
useCustomDomainForObservability,
1918
resolveAgent365Endpoint,
2019
getAgent365ObservabilityDomainOverride,
2120
isPerRequestExportEnabled
@@ -82,8 +81,8 @@ interface OTLPStatus {
8281
* Observability span exporter for Agent365:
8382
* - Partitions spans by (tenantId, agentId)
8483
* - Builds OTLP-like JSON: resourceSpans -> scopeSpans -> spans
85-
* - POSTs per group to https://{endpoint}/maven/agent365/agents/{agentId}/traces?api-version=1
86-
* or, when useS2SEndpoint is true, https://{endpoint}/maven/agent365/service/agents/{agentId}/traces?api-version=1
84+
* - POSTs per group to https://{endpoint}/observability/tenants/{tenantId}/agents/{agentId}/traces?api-version=1
85+
* or, when useS2SEndpoint is true, https://{endpoint}/observabilityService/tenants/{tenantId}/agents/{agentId}/traces?api-version=1
8786
* - Adds Bearer token via token_resolver(agentId, tenantId)
8887
*/
8988
export class Agent365Exporter implements SpanExporter {
@@ -170,27 +169,20 @@ export class Agent365Exporter implements SpanExporter {
170169

171170
const payload = this.buildExportRequest(spans);
172171
const body = JSON.stringify(payload);
173-
const usingCustomServiceEndpoint = useCustomDomainForObservability(this.configProvider);
174-
// Select endpoint path based on S2S flag
172+
// Select endpoint path based on S2S flag (includes tenantId in path)
175173
const endpointRelativePath =
176174
this.options.useS2SEndpoint
177-
? `/maven/agent365/service/agents/${agentId}/traces`
178-
: `/maven/agent365/agents/${agentId}/traces`;
175+
? `/observabilityService/tenants/${tenantId}/agents/${agentId}/traces`
176+
: `/observability/tenants/${tenantId}/agents/${agentId}/traces`;
179177

180178
let url: string;
181179
const domainOverride = getAgent365ObservabilityDomainOverride(this.configProvider);
182180
if (domainOverride) {
183181
url = `${domainOverride}${endpointRelativePath}?api-version=1`;
184-
} else if (usingCustomServiceEndpoint) {
182+
} else {
185183
const base = resolveAgent365Endpoint(this.options.clusterCategory as ClusterCategory);
186184
url = `${base}${endpointRelativePath}?api-version=1`;
187-
logger.info(`[Agent365Exporter] Using custom domain endpoint: ${url}`);
188-
} else {
189-
// Default behavior: discover PPAPI gateway endpoint per-tenant
190-
const discovery = new PowerPlatformApiDiscovery(this.options.clusterCategory as ClusterCategory);
191-
const endpoint = discovery.getTenantIslandClusterEndpoint(tenantId);
192-
url = `https://${endpoint}${endpointRelativePath}?api-version=1`;
193-
logger.info(`[Agent365Exporter] Resolved endpoint: ${url}`);
185+
logger.info(`[Agent365Exporter] Using default endpoint: ${url}`);
194186
}
195187

196188
const headers: Record<string, string> = {
@@ -229,10 +221,8 @@ export class Agent365Exporter implements SpanExporter {
229221
return;
230222
}
231223

232-
// Add tenant id to headers when using custom domain
233-
if (usingCustomServiceEndpoint) {
234-
headers['x-ms-tenant-id'] = tenantId;
235-
}
224+
// Always include tenant id header
225+
headers['x-ms-tenant-id'] = tenantId;
236226

237227
// Basic retry loop
238228
const { ok, correlationId } = await this.postWithRetries(url, body, headers);

packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export type TokenResolver = (agentId: string, tenantId: string) => string | null
2121
* @property {ClusterCategory | string} clusterCategory Environment / cluster category (e.g. ClusterCategory.preprod, ClusterCategory.prod, default to ClusterCategory.prod).
2222
* @property {TokenResolver} [tokenResolver] Optional delegate to obtain an auth token. If omitted the exporter will
2323
* fall back to reading the cached token (AgenticTokenCacheInstance.getObservabilityToken).
24-
* @property {boolean} [useS2SEndpoint] When true, exporter will POST to the S2S path (/maven/agent365/service/agents/{agentId}/traces).
24+
* @property {boolean} [useS2SEndpoint] When true, exporter will POST to the S2S path (/observabilityService/tenants/{tenantId}/agents/{agentId}/traces).
2525
* @property {number} maxQueueSize Maximum span queue size before drops occur (passed to BatchSpanProcessor).
2626
* @property {number} scheduledDelayMilliseconds Delay between automatic batch flush attempts.
2727
* @property {number} exporterTimeoutMilliseconds Per-export timeout (abort if exceeded).

packages/agents-a365-observability/src/tracing/exporter/utils.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,6 @@ export function isPerRequestExportEnabled(
156156
return enabled;
157157
}
158158

159-
/**
160-
* Single toggle to use custom domain for observability export.
161-
* When true exporter will send traces to custom Agent365 service endpoint
162-
* and include x-ms-tenant-id in headers.
163-
* @param configProvider Optional configuration provider. Defaults to defaultObservabilityConfigurationProvider if not specified.
164-
*/
165-
export function useCustomDomainForObservability(
166-
configProvider?: IConfigurationProvider<ObservabilityConfiguration>
167-
): boolean {
168-
const provider = configProvider ?? defaultObservabilityConfigurationProvider;
169-
const enabled = provider.getConfiguration().useCustomDomainForObservability;
170-
logger.info(`[Agent365Exporter] Use custom domain for observability: ${enabled}`);
171-
return enabled;
172-
}
173-
174159
/**
175160
* Resolve the Agent365 service endpoint base URI for a given cluster category.
176161
* When an explicit override is not configured, this determines the default base URI.

tests/observability-extensions-openai/configuration/OpenAIObservabilityConfiguration.test.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,6 @@ describe('OpenAIObservabilityConfiguration', () => {
7171
expect(config.observabilityAuthenticationScopes).toEqual(['custom-scope/.default']);
7272
});
7373

74-
it('should inherit useCustomDomainForObservability from override', () => {
75-
const config = new OpenAIObservabilityConfiguration({
76-
useCustomDomainForObservability: () => true
77-
});
78-
expect(config.useCustomDomainForObservability).toBe(true);
79-
});
80-
8174
it('should inherit observabilityDomainOverride from override', () => {
8275
const config = new OpenAIObservabilityConfiguration({
8376
observabilityDomainOverride: () => 'https://custom.domain'

0 commit comments

Comments
 (0)