Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f5a6625
Add PRD for configuration provider for Agent 365 SDK
Feb 3, 2026
2fa7ab0
Change to dynamic resolution for configuration settings
Feb 3, 2026
47f109c
feat: Add configuration provider interface
Feb 4, 2026
9778fd8
Merge branch 'main' into users/johanb/ConfigurationImprovements
Feb 4, 2026
65507a0
Update lock file
Feb 4, 2026
61ea5c2
fix: add backward-compatible overloads to GetAgenticUserToken
Feb 4, 2026
d007eb9
docs: clarify multi-tenant usage patterns for DefaultConfigurationPro…
Feb 4, 2026
0a88f22
docs: clarify AgenticTokenCache singleton usage and export class
Feb 4, 2026
0a141f7
add utility methods for parsing environment variables in RuntimeConfi…
Feb 4, 2026
461bf77
add setLogger and resetLogger tests
Feb 4, 2026
5484e0f
docs: enhance JSDoc comments for RuntimeConfigurationOptions
Feb 4, 2026
2fd9b3b
docs: update deprecation notices and provide usage examples for envir…
Feb 4, 2026
ccc09c3
refactor: update McpToolRegistrationService to use ClaudeToolingConfi…
Feb 4, 2026
ae18d5a
refactor: update McpToolRegistrationService to use specific tooling c…
Feb 4, 2026
328f414
refactor: ensure undefined checks for tooling overrides in ToolingCon…
Feb 4, 2026
eb92810
refactor: enhance ObservabilityConfiguration tests for environment va…
Feb 4, 2026
bda6efd
refactor: streamline McpToolRegistrationService by removing redundant…
Feb 4, 2026
7ea4b12
Address review feedback and discrepancies between documentation and c…
Feb 5, 2026
0a9a6ec
Address additional feedback; add missing tests, improve documentation
Feb 5, 2026
62f9ea6
Merge branch 'main' into users/johanb/ConfigurationImprovements
pontemonti Feb 6, 2026
02cb9bb
Merge remote-tracking branch 'origin/main' into users/johanb/Configur…
Feb 6, 2026
e983d40
Merge branch 'users/johanb/ConfigurationImprovements' of https://gith…
Feb 6, 2026
c9d6c8f
fix: add guardrails comment for PerRequestSpanProcessor default const…
Feb 6, 2026
3efcbd4
fix: correct documentation
Feb 6, 2026
c3ee585
Refactor observability configuration to separate per-request settings
Feb 6, 2026
f4bbbde
Address PR feedback
Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ package-lock.json.bak
out/
coverage/

# We should have at some point .vscode, but for not ignore since we don't have standard
.vscode
.claude/settings.local.json
.idea/

Expand Down
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"orta.vscode-jest"
]
}
9 changes: 9 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"codeReview.agents": [
"architecture-reviewer",
"code-reviewer",
"test-coverage-reviewer"
],
"jest.jestCommandLine": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config=tests/jest.config.cjs",
"jest.rootPath": "."
}
23 changes: 20 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,18 +128,25 @@ packages/agents-a365-<name>/
3. **Builder Pattern**: `ObservabilityBuilder` and `BaggageBuilder` provide fluent APIs
4. **Strategy Pattern**: `McpToolServerConfigurationService` switches between manifest (dev) and gateway (prod) based on `NODE_ENV`
5. **Extension Methods**: `notifications` package extends `AgentApplication` via TypeScript declaration merging
6. **Configuration Provider Pattern**: Hierarchical configuration with function-based overrides for multi-tenant support. Each package has its own configuration class (`RuntimeConfiguration`, `ToolingConfiguration`, `ObservabilityConfiguration`) with default singleton providers (`defaultRuntimeConfigurationProvider`, etc.)

## Core Package Functionality

### Runtime (`@microsoft/agents-a365-runtime`)
Foundation package with no SDK dependencies. Provides:
- **`RuntimeConfiguration`**: Base configuration class with `clusterCategory`, `isDevelopmentEnvironment`, `isNodeEnvDevelopment`
- **`defaultRuntimeConfigurationProvider`**: Singleton configuration provider for runtime settings
- **`Utility`**: Token decoding (`GetAppIdFromToken`), agent identity resolution (`ResolveAgentIdentity`), User-Agent generation (`GetUserAgentHeader`)
- **`AgenticAuthenticationService`**: Token exchange for MCP platform auth
- **`PowerPlatformApiDiscovery`**: Endpoint discovery for different clouds (prod, gov, dod, mooncake, etc.)
- **Environment utilities**: `getClusterCategory()`, `isDevelopmentEnvironment()`, `getObservabilityAuthenticationScope()`, `getMcpPlatformAuthenticationScope()`
- **Environment utilities** _(deprecated)_: `getClusterCategory()`, `isDevelopmentEnvironment()`, etc. - use `RuntimeConfiguration` instead

### Observability (`@microsoft/agents-a365-observability`)
OpenTelemetry-based distributed tracing:
- **`ObservabilityConfiguration`**: Configuration with `observabilityAuthenticationScopes`, `isObservabilityExporterEnabled`, `observabilityLogLevel`, etc.
- **`PerRequestSpanProcessorConfiguration`**: Extends `ObservabilityConfiguration` with per-request processor settings (`isPerRequestExportEnabled`, `perRequestMaxTraces`, `perRequestMaxSpansPerTrace`, `perRequestMaxConcurrentExports`). Separated from `ObservabilityConfiguration` because these settings are only relevant when using `PerRequestSpanProcessor`.
- **`defaultObservabilityConfigurationProvider`**: Singleton configuration provider for observability settings
- **`defaultPerRequestSpanProcessorConfigurationProvider`**: Singleton configuration provider for per-request span processor settings
- **`ObservabilityManager`**: Main entry point (singleton)
- **`ObservabilityBuilder`**: Fluent configuration API
- **Scope classes**:
Expand All @@ -160,6 +167,8 @@ BaggageBuilder.build().run()

### Tooling (`@microsoft/agents-a365-tooling`)
MCP tool server discovery and configuration:
- **`ToolingConfiguration`**: Configuration with `mcpPlatformEndpoint`, `mcpPlatformAuthenticationScope`, `useToolingManifest`
- **`defaultToolingConfigurationProvider`**: Singleton configuration provider for tooling settings
- **`McpToolServerConfigurationService`**: Discover/configure MCP tool servers
- Dev mode (`NODE_ENV=Development`): Loads from `ToolingManifest.json`
- Prod mode (default): Discovers from Agent365 gateway endpoint
Expand Down Expand Up @@ -199,9 +208,17 @@ The keyword "Kairo" is legacy and should not appear in any code. Flag and remove
|----------|---------|--------|
| `NODE_ENV` | Dev vs prod mode | `Development`, `production` (default) |
| `CLUSTER_CATEGORY` | Environment classification | `local`, `dev`, `test`, `preprod`, `prod`, `gov`, `high`, `dod`, `mooncake`, `ex`, `rx` |
| `A365_OBSERVABILITY_SCOPES_OVERRIDE` | Override observability auth scopes | Space-separated scope strings |
| `MCP_PLATFORM_AUTHENTICATION_SCOPE` | MCP platform auth scope | Scope string |
| `MCP_PLATFORM_ENDPOINT` | MCP platform base URL | URL string |
| `MCP_PLATFORM_AUTHENTICATION_SCOPE` | MCP platform auth scope | Scope string |
| `A365_OBSERVABILITY_SCOPES_OVERRIDE` | Override observability auth scopes | Space-separated scope strings |
| `ENABLE_A365_OBSERVABILITY_EXPORTER` | Enable Agent365 exporter | `true`, `false` (default) |
| `ENABLE_A365_OBSERVABILITY_PER_REQUEST_EXPORT` | Enable per-request export mode | `true`, `false` (default) |
| `A365_OBSERVABILITY_USE_CUSTOM_DOMAIN` | Use custom domain for export | `true`, `false` (default) |
| `A365_OBSERVABILITY_DOMAIN_OVERRIDE` | Custom domain URL override | URL string |
| `A365_OBSERVABILITY_LOG_LEVEL` | Internal logging level | `none` (default), `error`, `warn`, `info`, `debug` |
| `A365_PER_REQUEST_MAX_TRACES` | Max buffered traces per request (`PerRequestSpanProcessorConfiguration`) | Number (default: 1000) |
| `A365_PER_REQUEST_MAX_SPANS_PER_TRACE` | Max spans per trace (`PerRequestSpanProcessorConfiguration`) | Number (default: 5000) |
| `A365_PER_REQUEST_MAX_CONCURRENT_EXPORTS` | Max concurrent exports (`PerRequestSpanProcessorConfiguration`) | Number (default: 20) |

## Testing

Expand Down
110 changes: 101 additions & 9 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,37 @@ Core utilities shared across the SDK.
| `AgenticAuthenticationService` | Token exchange for MCP platform authentication |
| `PowerPlatformApiDiscovery` | Endpoint discovery for different cloud environments |

**Environment Utilities:**
**Configuration:**

| Function | Purpose |
| Property | Purpose |
|----------|---------|
| `getObservabilityAuthenticationScope()` | Get auth scopes for observability service |
| `getClusterCategory()` | Get environment classification (prod, dev, local) |
| `isDevelopmentEnvironment()` | Check if running in development mode |
| `getMcpPlatformAuthenticationScope()` | Get MCP platform authentication scope |
| `clusterCategory` | Environment classification (prod, dev, local) |
| `isDevelopmentEnvironment` | Check if running in development mode |
| `mcpPlatformAuthenticationScope` | MCP platform authentication scope |
| `observabilityAuthenticationScopes` | Auth scopes for observability service |

**Usage Example:**

```typescript
import {
Utility,
PowerPlatformApiDiscovery,
getClusterCategory,
defaultRuntimeConfigurationProvider,
} from '@microsoft/agents-a365-runtime';

// Access configuration via the default provider
const config = defaultRuntimeConfigurationProvider.getConfiguration();
console.log(`Cluster: ${config.clusterCategory}`);
console.log(`Is dev: ${config.isDevelopmentEnvironment}`);

// Decode agent identity from JWT token
const appId = Utility.GetAppIdFromToken(jwtToken);

// Resolve agent identity from context
const agentId = Utility.ResolveAgentIdentity(turnContext, authToken);

// Discover Power Platform endpoints
const discovery = new PowerPlatformApiDiscovery('prod');
const discovery = new PowerPlatformApiDiscovery(config.clusterCategory);
const endpoint = discovery.getTenantIslandClusterEndpoint(tenantId);

// Generate User-Agent header
Expand Down Expand Up @@ -340,7 +345,94 @@ async listToolServers(agenticAppId: string, authToken: string): Promise<MCPServe
}
```

### 5. Extension Methods Pattern
### 5. Configuration Provider Pattern

The SDK uses a hierarchical configuration system with function-based overrides for multi-tenant support:

```typescript
import {
RuntimeConfiguration,
RuntimeConfigurationOptions,
DefaultConfigurationProvider,
defaultRuntimeConfigurationProvider,
} from '@microsoft/agents-a365-runtime';

// Simple usage: default configuration with environment variables
const config = defaultRuntimeConfigurationProvider.getConfiguration();

// Multi-tenant: per-request configuration with dynamic overrides
const options: RuntimeConfigurationOptions = {
clusterCategory: () => getTenantCluster(currentTenantId),
};
const tenantProvider = new DefaultConfigurationProvider(
() => new RuntimeConfiguration(options)
);
const tenantConfig = tenantProvider.getConfiguration();
```

**Configuration Resolution Order:**

Each configuration property follows a consistent resolution chain. The first non-undefined value wins:

```
┌─────────────────────────────────────────────────────────────────────────┐
│ Configuration Resolution Order │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ │
│ │ Override Function │ ← Called on EVERY property access │
│ │ (if provided) │ Enables per-request/per-tenant values │
│ └──────────┬───────────┘ │
│ │ │
│ ▼ returns undefined? │
│ │ │
│ ┌──────────────────────┐ │
│ │ Environment Variable│ ← Process-level configuration │
│ │ (if set and valid) │ Standard 12-factor app approach │
│ └──────────┬───────────┘ │
│ │ │
│ ▼ not set or invalid? │
│ │ │
│ ┌──────────────────────┐ │
│ │ Default Value │ ← Built-in production defaults │
│ │ (always defined) │ Safe fallback for all properties │
│ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```

**Example Resolution:**

```typescript
// Configuration class getter implementation pattern:
get clusterCategory(): ClusterCategory {
// 1. Check override function
const override = this.overrides.clusterCategory?.();
if (override !== undefined) return override; // ← Override wins

// 2. Check environment variable
const envValue = process.env.CLUSTER_CATEGORY;
if (isValidClusterCategory(envValue)) return envValue; // ← Env var wins

// 3. Return default
return ClusterCategory.prod; // ← Default fallback
}
```

**Key Characteristics:**

| Aspect | Behavior |
|--------|----------|
| **Dynamic resolution** | Override functions called on each access, not cached |
| **Undefined vs false** | `undefined` falls through; explicit `false` is used |
| **Validation** | Invalid env var values fall through to defaults |
| **Thread safety** | Safe for concurrent access (no shared mutable state) |

**Inheritance Hierarchy:**
- `RuntimeConfiguration` → `ToolingConfiguration`, `ObservabilityConfiguration`
- Each child package extends the base with additional settings

### 6. Extension Methods Pattern

The notifications package uses TypeScript declaration merging to extend `AgentApplication`:

Expand Down
Loading