Skip to content

Add agentic identity defaults to Teams app API#598

Open
heyitsaamir wants to merge 23 commits into
core/api-flattenfrom
heyitsaamir-agentic-api-default-identity
Open

Add agentic identity defaults to Teams app API#598
heyitsaamir wants to merge 23 commits into
core/api-flattenfrom
heyitsaamir-agentic-api-default-identity

Conversation

@heyitsaamir

@heyitsaamir heyitsaamir commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add per-turn default agentic identity propagation through Context.Api and service URL-scoped Apps API clients, while preserving explicit per-call identity overrides.
  • Add RequestOptions for service URL and agentic identity so scoped clients and activity create/update/reply/member/targeted calls can use one extensible per-call options value.
  • Add TeamsBotApplication.GetAgenticIdentity(...) with blueprint defaulting to AppId and tenant defaulting from TeamsBotApplicationOptions when configured.

Breaking change

  • Activity create/update/reply/member/targeted methods no longer expose the positional additionalHeaders parameter. This is intentional: the activity APIs now use RequestOptions for per-call service URL and identity and do not support custom additional headers on these methods.

Tenant ID note

  • Tenant ID already existed in Core BotConfig for auth/issuer/token plumbing, but TeamsBotApplicationOptions did not carry it because the Apps layer previously only needed the app ID.
  • This PR copies the configured BotConfig.TenantId into Teams options so GetAgenticIdentity(...) can populate AgenticIdentity.TenantId without requiring callers to pass the configured tenant every time.
  • This does not change BotAuthenticationHandler or add tenant-aware token acquisition; whitespace/unconfigured tenant values remain null.

Validation

  • dotnet test core/test/Microsoft.Teams.Apps.UnitTests/Microsoft.Teams.Apps.UnitTests.csproj --no-restore

Copilot AI review requested due to automatic review settings July 10, 2026 00:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces default agentic identity propagation through Context.Api and service URL-scoped ApiClient instances, and extends Teams Apps API clients (notably ActivityClient) to support default identity plus explicit per-call overrides. It also adds TeamsBotApplication.GetAgenticIdentity(...) with blueprint/tenant defaulting (blueprint defaults to AppId, tenant defaults from configured TeamsBotApplicationOptions.TenantId when available).

Changes:

  • Add TeamsBotApplicationOptions.TenantId and propagate it from hosting configuration; use it as the default tenant when building agentic identities via TeamsBotApplication.GetAgenticIdentity(...).
  • Add ApiClient.ForServiceUrl(Uri, AgenticIdentity?) and plumb default request context through service-url scoped sub-clients via ApiRequestContext.
  • Add/expand tests validating default vs explicit agentic identity behavior across Context.Api, scoped ApiClient, and ActivityClient operations.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
core/test/Microsoft.Teams.Apps.UnitTests/TeamsBotApplicationHostingExtensionsTests.cs Extends DI/hosting test coverage to assert TeamsBotApplicationOptions.TenantId is set from config.
core/test/Microsoft.Teams.Apps.UnitTests/AgenticIdentityDefaultsTests.cs New unit tests validating default/override behavior for agentic identities across scoped clients and activity operations.
core/src/Microsoft.Teams.Apps/TeamsBotApplicationOptions.cs Adds TenantId option used for defaulting agentic identity tenant in TeamsBotApplication.GetAgenticIdentity.
core/src/Microsoft.Teams.Apps/TeamsBotApplication.HostingExtensions.cs Populates TeamsBotApplicationOptions.TenantId from BotConfig.TenantId (normalizing empty/whitespace to null).
core/src/Microsoft.Teams.Apps/TeamsBotApplication.cs Caches configured tenant ID and adds GetAgenticIdentity(...); includes tenant stamping in proactive send “From” identity.
core/src/Microsoft.Teams.Apps/Context.cs Scopes Context.Api by service URL plus default agentic identity derived from the inbound activity’s Recipient.
core/src/Microsoft.Teams.Apps/Api/Clients/TeamClient.cs Threads default request context into request option creation via ApiRequestContext.
core/src/Microsoft.Teams.Apps/Api/Clients/ReactionClient.cs Uses ApiRequestContext.Resolve(...) to apply default/explicit request context.
core/src/Microsoft.Teams.Apps/Api/Clients/MemberClient.cs Uses ApiRequestContext.Resolve(...) to apply default/explicit request context.
core/src/Microsoft.Teams.Apps/Api/Clients/MeetingClient.cs Threads default request context into request option creation via ApiRequestContext.
core/src/Microsoft.Teams.Apps/Api/Clients/ConversationApiClient.cs Passes default request context through to Activities, Members, and Reactions; uses ApiRequestContext.Resolve(...) for create conversation.
core/src/Microsoft.Teams.Apps/Api/Clients/ApiRequestContext.cs New helper to merge default request context with explicit agentic identity and/or activity-derived context.
core/src/Microsoft.Teams.Apps/Api/Clients/ApiClient.cs Adds a service-url scoped client variant that carries a default agentic identity; plumbs default context into sub-clients.
core/src/Microsoft.Teams.Apps/Api/Clients/ActivityClient.cs Adds identity-aware overloads and default identity support for activity create/update/reply/delete, targeted operations, and activity member lookup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/// <summary>
/// Create a new activity in a conversation.
/// </summary>
public Task<SendActivityResponse?> CreateAsync(string conversationId, CoreActivity activity, AgenticIdentity? agenticIdentity, Dictionary<string, string>? additionalHeaders = null, CancellationToken cancellationToken = default)
/// <summary>
/// Update an existing activity in a conversation.
/// </summary>
public Task<UpdateActivityResponse> UpdateAsync(string conversationId, string id, CoreActivity activity, AgenticIdentity? agenticIdentity, Dictionary<string, string>? additionalHeaders = null, CancellationToken cancellationToken = default)
/// <summary>
/// Reply to an existing activity in a conversation.
/// </summary>
public Task<SendActivityResponse?> ReplyAsync(string conversationId, string id, CoreActivity activity, AgenticIdentity? agenticIdentity, Dictionary<string, string>? additionalHeaders = null, CancellationToken cancellationToken = default)
/// Targeted activities are only visible to the specified recipient.
/// </summary>
[Experimental("ExperimentalTeamsTargeted")]
public Task<SendActivityResponse?> CreateTargetedAsync(string conversationId, CoreActivity activity, AgenticIdentity? agenticIdentity, Dictionary<string, string>? additionalHeaders = null, CancellationToken cancellationToken = default)
/// Update an existing targeted activity in a conversation.
/// </summary>
[Experimental("ExperimentalTeamsTargeted")]
public Task<UpdateActivityResponse> UpdateTargetedAsync(string conversationId, string id, CoreActivity activity, AgenticIdentity? agenticIdentity, Dictionary<string, string>? additionalHeaders = null, CancellationToken cancellationToken = default)
heyitsaamir and others added 11 commits July 10, 2026 11:48
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@heyitsaamir heyitsaamir force-pushed the heyitsaamir-agentic-api-default-identity branch from 0b34f84 to e0ba479 Compare July 10, 2026 18:50
@heyitsaamir heyitsaamir changed the base branch from main to core/api-flatten July 10, 2026 18:50
heyitsaamir and others added 5 commits July 10, 2026 11:52
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
/// <param name="tenantId">Optional tenant ID of the agent instance for multi-tenant applications. Overrides the configured tenant ID when provided.</param>
/// <param name="agenticAppBlueprintId">Optional agentic application blueprint ID. Defaults to this application's AppId.</param>
/// <returns>An <see cref="AgenticIdentity"/> populated with application defaults.</returns>
public AgenticIdentity GetAgenticIdentity(string agenticAppId, string agenticUserId, string? tenantId = null, string? agenticAppBlueprintId = null)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this method needed anywhere ?

/// <param name="serviceUrl">The Bot Framework service URL for this scope.</param>
/// <param name="defaultAgenticIdentity">The default agentic identity for service URL-bound sub-clients.</param>
/// <returns>A new <see cref="ApiClient"/> bound to the given service URL and default identity.</returns>
public virtual ApiClient ForServiceUrl(Uri serviceUrl, AgenticIdentity? defaultAgenticIdentity)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better name ?

ArgumentNullException.ThrowIfNull(activity);
activity.ServiceUrl ??= _serviceUrl;
return _client.UpdateTargetedActivityAsync(conversationId, id, activity, requestContext: BotRequestContext.FromActivity(activity), customHeaders: additionalHeaders, cancellationToken: cancellationToken);
BotRequestContext? requestContext = BotRequestContext.Merge(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add this merge to conversation client in core instead for consistency

ArgumentNullException.ThrowIfNull(activity);
activity.ServiceUrl ??= _serviceUrl;
return _client.UpdateActivityAsync(conversationId, id, activity, requestContext: BotRequestContext.FromActivity(activity), customHeaders: additionalHeaders, cancellationToken: cancellationToken);
BotRequestContext? requestContext = BotRequestContext.Merge(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, add merge to core client

heyitsaamir and others added 7 commits July 10, 2026 14:57
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants