Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9461a08
Initial core bot activity library, CI, and extensibility
rido-min Dec 10, 2025
34c8eaf
lint
rido-min Dec 10, 2025
86b3ae2
Add permissions to Core-CI workflow for contents and PRs
rido-min Dec 10, 2025
5b1bc24
Merge branch 'main' into next/core
rido-min Dec 10, 2025
e645b70
Add Proactive and SourceCodeGenerators (#237)
rido-min Dec 11, 2025
f429c90
Merge branch 'main' into next/core
rido-min Dec 11, 2025
6c9d953
Update pipeline config, solution items, and null handling
rido-min Dec 11, 2025
1e75444
Add .NET 8 SDK install step to BuildTestPack job
rido-min Dec 11, 2025
56f691d
Update package icon and include assets in NuGet package
rido-min Dec 11, 2025
836843d
Add bot_icon.png image asset
rido-min Dec 11, 2025
851ab6c
Update NuGet push to run only on next/core branch
rido-min Dec 11, 2025
716e01b
Update .gitignore to exclude config and settings files
rido-min Dec 11, 2025
cca6c26
Add new test project and GitHub Actions workflow
rido-min Dec 11, 2025
daae240
Target unit tests in pipeline, fix conversation ID usage
rido-min Dec 11, 2025
6535d6a
Update echo message, logging, and exception handling
rido-min Dec 11, 2025
74934be
Update .gitignore to include runsettings files and add README for tes…
rido-min Dec 11, 2025
7a9aa23
Refactor test commands and update project references in CI configurat…
rido-min Dec 11, 2025
2073c71
Add .editorconfig, rename reply method, update tests
rido-min Dec 11, 2025
7690ea4
Refactor: use explicit types instead of var everywhere
rido-min Dec 11, 2025
1bb7229
Add copyright and MIT license headers to all files (#240)
rido-min Dec 11, 2025
8c07ca1
Add proactive messaging endpoint and update EchoBot responses
rido-min Dec 11, 2025
298973e
Merge branch 'next/core' of https://github.com/microsoft/teams.net in…
rido-min Dec 11, 2025
349f7e7
Add Azure Monitor telemetry and improve logging/configs (#241)
rido-min Dec 12, 2025
4e2a51f
Remove unused usings and improve TryGetValue typing
rido-min Dec 12, 2025
7d259a3
Merge branch 'main' into next/core
rido-min Dec 12, 2025
4d7ae86
Update pipeline triggers and add PushToADOFeed variable
rido-min Dec 12, 2025
0e90563
Fix reply activity creation method in middleware
rido-min Dec 12, 2025
b9495ec
Configure MSAL based on different configuration styles (#243)
rido-min Dec 12, 2025
154b58a
compat bot handlers
rido-min Dec 13, 2025
1dcd279
Improve message formatting and agent identity handling
rido-min Dec 13, 2025
23075bf
Add UMI support (#244)
heyitsaamir Dec 15, 2025
c5e9b41
Add AF sample, adds SendTypingActivity (#245)
rido-min Dec 16, 2025
a2ea29b
Move AgenticIdentity to Schema and make it public
rido-min Dec 16, 2025
bd7bb40
[core]: add JWT validation for bots & agents (#246)
lilyydu Dec 18, 2025
051a8ba
add packable
Dec 18, 2025
666290a
Support for Invokes, TeamsAttachmentBuilder, Complete IConversationCl…
rido-min Jan 8, 2026
1ac1a07
Return Activity Id From api/messages (#261)
rido-min Jan 12, 2026
4d640a8
Merge branch 'main' into next/core
rido-min Jan 13, 2026
73ef468
[core + compat]: Add UserTokenClient (#260)
MehakBindra Jan 13, 2026
6906413
Update Compat Layer to target Teams features (#265)
rido-min Jan 15, 2026
7ee0e41
Rename projects to use Microsoft.Teams (#267)
rido-min Jan 15, 2026
a6e8212
Set IsPackable property to false in ABSTokenServiceClient project
rido-min Jan 16, 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
9 changes: 4 additions & 5 deletions .azdo/cd-core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ pr:
branches:
include:
- next/*
# Uncomment and edit the following lines to add path filters for PRs in the future
# paths:
# include:
# - core/**
paths:
include:
- core/**

trigger:
branches:
Expand Down Expand Up @@ -55,7 +54,7 @@ stages:

- task: NuGetCommand@2
displayName: 'Push NuGet Packages'
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/next/core'))
condition: eq(variables['PushToADOFeed'], true)
inputs:
command: push
packagesToPush: '$(Build.ArtifactStagingDirectory)/*.nupkg'
Expand Down
13 changes: 12 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,18 @@
"bicepVersion": "latest"
},
"ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {
"version": "9.0"
"version": "latest"
},
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "10.0"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"moby": true,
"azureDnsAutoDetection": true,
"installDockerBuildx": true,
"installDockerComposeSwitch": true,
"version": "latest",
"dockerDashComposeVersion": "v2"
}
}

Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/core-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Core-CI
permissions:
contents: read
pull-requests: write

on:
push:
branches: [ next/core ]
pull_request:
branches: [ next/core ]

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore
working-directory: core

- name: Build Core
run: dotnet build --no-restore
working-directory: core

- name: Test
run: dotnet test --no-build
working-directory: core

- name: Build Core Tests
run: dotnet build
working-directory: core/test
41 changes: 41 additions & 0 deletions .github/workflows/core-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Core-Test
permissions:
contents: read
pull-requests: write

on:
workflow_dispatch:

jobs:
build-and-test:
runs-on: ubuntu-latest
environment: test_tenant

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore
working-directory: core

- name: Build
run: dotnet build --no-restore
working-directory: core

- name: Test
run: dotnet test --no-build test/Microsoft.Bot.Core.Tests/Microsoft.Bot.Core.Tests.csproj
working-directory: core
env:
AzureAd__Instance: 'https://login.microsoftonline.com/'
AzureAd__ClientId: 'aabdbd62-bc97-4afb-83ee-575594577de5'
AzureAd__TenantId: '56653e9d-2158-46ee-90d7-675c39642038'
AzureAd__Scope: 'https://api.botframework.com/.default'
AzureAd__ClientCredentials__0__SourceType: 'ClientSecret'
AzureAd__ClientCredentials__0__ClientSecret: ${{ secrets.CLIENT_SECRET}}
41 changes: 41 additions & 0 deletions core/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
root = true

# All files
[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true

# C# files
[*.cs]
indent_style = space
indent_size = 4
nullable = enable
#dotnet_diagnostic.CS1591.severity = none ## Suppress missing XML comment warnings
dotnet_diagnostic.CA1848.severity = warning

#### Nullable Reference Types ####
# Make nullable warnings strict
dotnet_diagnostic.CS8600.severity = error
dotnet_diagnostic.CS8602.severity = error
dotnet_diagnostic.CS8603.severity = error
dotnet_diagnostic.CS8604.severity = error
dotnet_diagnostic.CS8618.severity = error # Non-nullable field uninitialized

# Code quality rules
dotnet_code_quality_unused_parameters = all:suggestion
dotnet_diagnostic.IDE0079.severity = warning

#### Coding conventions ####
dotnet_sort_system_directives_first = true
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true

file_header_template = Copyright (c) Microsoft Corporation.\nLicensed under the MIT License.

[samples/**/*.cs]
dotnet_diagnostic.CA1848.severity = none # Suppress Logger perfomance in samples

# Test projects can be more lenient
[tests/**/*.cs]
dotnet_diagnostic.CS8602.severity = warning
3 changes: 3 additions & 0 deletions core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
launchSettings.json
appsettings.Development.json
*.runsettings
137 changes: 137 additions & 0 deletions core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Microsoft.Teams.Bot.Core

Bot Core implements the Activity Protocol, including schema, conversation client, user token client, and support for Bot and Agentic Identities.

## Design Principles

- Loose schema. `TeamsActivity` contains only the strictly required fields for Conversation Client, additional fields are captured as a Dictionary with JsonExtensionData attributes.
- Simple Serialization. `TeamsActivity` can be serialized/deserialized without any custom logic, and trying to avoid custom converters as much as possible.
- Extensible schema. Fields subject to extension, such as `ChannelData` must define their own `Properties` to allow serialization of unknown fields. Use of generics to allow additional types that are not defined in the Core Library.
- Auth based on MSAL. Token acquisition done on top of MSAL
- Respect ASP.NET DI. `TeamsBotApplication` dependencies are configured based on .NET ServiceCollection extensions, reusing the existing `HttpClient`
- Respect ILogger and IConfiguration.

## Samples

### Extensible Activity

```cs
public class MyChannelData : ChannelData
{
[JsonPropertyName("customField")]
public string? CustomField { get; set; }

[JsonPropertyName("myChannelId")]
public string? MyChannelId { get; set; }
}

public class MyCustomChannelDataActivity : TeamsActivity
{
[JsonPropertyName("channelData")]
public new MyChannelData? ChannelData { get; set; }
}

[Fact]
public void Deserialize_CustomChannelDataActivity()
{
string json = """
{
"type": "message",
"channelData": {
"customField": "customFieldValue",
"myChannelId": "12345"
}
}
""";
var deserializedActivity = TeamsActivity.FromJsonString<MyCustomChannelDataActivity>(json);
Assert.NotNull(deserializedActivity);
Assert.NotNull(deserializedActivity.ChannelData);
Assert.Equal("customFieldValue", deserializedActivity.ChannelData.CustomField);
Assert.Equal("12345", deserializedActivity.ChannelData.MyChannelId);
}
```

> Note `FromJsonString` lives in `TeamsActivity`, and there is no need to override.


### Basic Bot Application Usage

```cs
using Microsoft.Teams.Bot.Apps;
using Microsoft.Teams.Bot.Apps.Schema;

var builder = TeamsBotApplication.CreateBuilder();
var teamsApp = builder.Build();

teamsApp.OnMessage = async (messageArgs, context, cancellationToken) =>
{
await context.SendTypingActivityAsync(cancellationToken);

string replyText = $"You sent: `{messageArgs.Text}` in activity of type `{context.Activity.Type}`.";

TeamsActivity reply = TeamsActivity.CreateBuilder()
.WithText(replyText)
.Build();

await context.SendActivityAsync(reply, cancellationToken);
};

teamsApp.Run();
```

## Testing in Teams

Need to create a Teams Application, configure it in ABS and capture `TenantId`, `ClientId` and `ClientSecret`. Provide those values as

```json
{
"AzureAd" : {
"Instance" : "https://login.microsoftonline.com/",
"TenantId" : "<your-tenant-id>",
"ClientId" : "<your-client-id>",
"Scope" : "https://api.botframework.com/.default",
"ClientCredentials" : [
{
"SourceType" : "ClientSecret",
"ClientSecret" : "<your-entra-app-secret>"
}
]
}
}
```

or as env vars, using the IConfiguration Environment Configuration Provider:

```env
AzureAd__Instance=https://login.microsoftonline.com/
AzureAd__TenantId=<your-tenant-id>
AzureAd__ClientId=<your-client-id>
AzureAd__Scope=https://api.botframework.com/.default
AzureAd__ClientCredentials__0__SourceType=ClientSecret
AzureAd__ClientCredentials__0__ClientSecret=<your-entra-app-secret>
```



## Testing in localhost (anonymous)

When not providing MSAL configuration all the communication will happen as anonymous REST calls, suitable for localhost testing.

### Install Playground

Linux
```
curl -s https://raw.githubusercontent.com/OfficeDev/microsoft-365-agents-toolkit/dev/.github/scripts/install-agentsplayground-linux.sh | bash
```

Windows
```
winget install m365agentsplayground
```


### Run Scenarios

```
dotnet samples/scenarios/middleware.cs -- --urls "http://localhost:3978"
```
Binary file added core/bot_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions core/core.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<Solution>
<!-- <Folder Name="/bf/">
<Project Path="../../botbuilder-dotnet/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.Core/Microsoft.Bot.Builder.Integration.AspNet.Core.csproj" />
<Project Path="../../botbuilder-dotnet/libraries/Microsoft.Bot.Builder.Dialogs/Microsoft.Bot.Builder.Dialogs.csproj" />
<Project Path="../../botbuilder-dotnet/libraries/Microsoft.Bot.Builder/Microsoft.Bot.Builder.csproj" />
<Project Path="../../botbuilder-dotnet/libraries/Microsoft.Bot.Configuration/Microsoft.Bot.Configuration.csproj" />
<Project Path="../../botbuilder-dotnet/libraries/Microsoft.Bot.Connector.Streaming/Microsoft.Bot.Connector.Streaming.csproj" />
<Project Path="../../botbuilder-dotnet/libraries/Microsoft.Bot.Connector/Microsoft.Bot.Connector.csproj" />
<Project Path="../../botbuilder-dotnet/libraries/Microsoft.Bot.Schema/Microsoft.Bot.Schema.csproj" />
<Project Path="../../botbuilder-dotnet/libraries/Microsoft.Bot.Streaming/Microsoft.Bot.Streaming.csproj" />
</Folder> -->
<Folder Name="/Samples/">
<Project Path="samples/AFBot/AFBot.csproj" Id="ca5b4abd-3f26-457b-8197-ff9415506beb" />
<Project Path="samples/CompatBot/CompatBot.csproj" Id="39461362-c3d0-41ae-9ed7-f7e1232a8ead" />
<Project Path="samples/CoreBot/CoreBot.csproj" Id="142a67bc-68e7-4020-83cf-51423e317b53" />
<Project Path="samples/TeamsBot/TeamsBot.csproj" Id="94a35050-6826-446f-9b29-863f2bbc75b7" />
</Folder>
<Folder Name="/Solution Items/">
<File Path="../.azdo/cd-core.yaml" />
<File Path="../.github/workflows/core-ci.yaml" />
<File Path="../.github/workflows/core-test.yaml" />
<File Path=".editorconfig" />
<File Path=".gitignore" />
<File Path="README.md" />
<File Path="src/Directory.Build.props" />
<File Path="src/Directory.Build.targets" />
<File Path="version.json" />
</Folder>
<Folder Name="/Tests/">
<Project Path="samples/Proactive/Proactive.csproj" Id="69f021eb-451b-4dd3-b848-137d764ba586" />
<Project Path="test/ABSTokenServiceClient/ABSTokenServiceClient.csproj" />
<Project Path="test/Microsoft.Teams.Bot.Core.UnitTests/Microsoft.Teams.Bot.Core.UnitTests.csproj" Id="8e6790ed-0352-45f6-b3dc-0c4c3bcab038" />
<Project Path="test/Microsoft.Teams.Bot.Apps.UnitTests/Microsoft.Teams.Bot.Apps.UnitTests.csproj" Id="16f5e8eb-ccb0-40e6-9630-a9d936d6ccde" />
<Project Path="test/msal-config-api/msal-config-api.csproj" Id="54f814fa-348e-4fd3-8bc9-70cd2aedc9ae" />
</Folder>
<Project Path="src/Microsoft.Teams.Bot.Compat/Microsoft.Teams.Bot.Compat.csproj" Id="42d14898-dcc0-43a4-bb61-60e289f63c44" />
<Project Path="src/Microsoft.Teams.Bot.Core/Microsoft.Teams.Bot.Core.csproj" />
<Project Path="src/Microsoft.Teams.Bot.Apps/Microsoft.Teams.Bot.Apps.csproj" Id="0e993a63-8a1a-4cdf-8a29-cc8c59bd6c30" />
</Solution>
21 changes: 21 additions & 0 deletions core/samples/AFBot/AFBot.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
<PackageReference Include="Azure.Identity" Version="1.17.0" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.0.0-preview.251204.1" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.4.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.23.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.Teams.Bot.Core\Microsoft.Teams.Bot.Core.csproj" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions core/samples/AFBot/DropTypingMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.Teams.Bot.Core;
using Microsoft.Teams.Bot.Core.Schema;

namespace AFBot;

internal class DropTypingMiddleware : ITurnMiddleWare
{
public Task OnTurnAsync(BotApplication botApplication, CoreActivity activity, NextTurn nextTurn, CancellationToken cancellationToken = default)
{
if (activity.Type == ActivityType.Typing) return Task.CompletedTask;
return nextTurn(cancellationToken);
}
}
Loading