Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions python/packages/hosting-teams/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
113 changes: 113 additions & 0 deletions python/packages/hosting-teams/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# agent-framework-hosting-teams

Microsoft Teams channel for [agent-framework-hosting](../hosting), built on
the official [`microsoft-teams-apps`](https://pypi.org/project/microsoft-teams-apps/)
SDK (microsoft/teams.py). Teams is reached **through Azure Bot Service**;
this channel does not change that — there is currently no way to receive
Teams traffic without a Bot Service registration. What it changes is the
*programming model*: typed activity models, native streaming, Adaptive
Cards, citations, and a typed feedback callback all in one place.

> Looking for the channel-neutral Activity Protocol shape (text in / text
> out for Slack, Webex, Telegram-via-Bot-Service, …)? Use
> [`agent-framework-hosting-activity-protocol`](../hosting-activity-protocol)
> instead.

## When to choose which

| If you need … | Use this channel |
| ------------------------------------------------------------------------ | ------------------------------------------------- |
| One bot reachable from many Bot Service connectors with the same code | `agent-framework-hosting-activity-protocol` |
| Microsoft Teams with Adaptive Cards, streaming, citations, feedback | `agent-framework-hosting-teams` (this package) |
| Slack / Webex / Telegram-via-Bot-Service only | `agent-framework-hosting-activity-protocol` |

## Usage

```python
from agent_framework_hosting import AgentFrameworkHost
from agent_framework_hosting_teams import (
TeamsChannel,
TeamsCitation,
TeamsOutboundContext,
TeamsOutboundPayload,
)

# Plain text reply
host = AgentFrameworkHost(
target=my_agent,
channels=[
TeamsChannel(
client_id="<entra app id>",
client_secret="<entra client secret>",
tenant_id="<tenant id>",
)
],
)
host.serve()
```

### Streaming

```python
TeamsChannel(
client_id=..., client_secret=..., tenant_id=...,
streaming=True, # use the SDK's HttpStream for live mid-message edits
)
```

### Adaptive Cards via outbound transform

```python
from microsoft_teams.cards.core import AdaptiveCard

async def to_card(ctx: TeamsOutboundContext) -> TeamsOutboundPayload:
card = AdaptiveCard(
body=[{"type": "TextBlock", "text": ctx.result.text, "wrap": True}],
)
return TeamsOutboundPayload(card=card)

TeamsChannel(..., outbound_transform=to_card)
```

### Citations

```python
async def with_citations(ctx: TeamsOutboundContext) -> TeamsOutboundPayload:
return TeamsOutboundPayload(
text=ctx.result.text,
citations=[
TeamsCitation(
name="Microsoft Agent Framework",
url="https://aka.ms/agent-framework",
abstract="Build, orchestrate, and deploy AI agents.",
),
],
)
```

### Feedback callback

```python
from agent_framework_hosting_teams import TeamsFeedbackContext

async def on_feedback(ctx: TeamsFeedbackContext) -> None:
log.info(
"rating=%s reply_to=%s feedback=%s user=%s",
ctx.rating, ctx.reply_to_id, ctx.feedback, ctx.identity.native_id,
)

TeamsChannel(..., feedback_handler=on_feedback)
```

## Authentication

Pass `client_id` / `client_secret` (and optionally `tenant_id`) the same
way you would to the SDK directly. For managed identity or custom token
acquisition flows, supply the SDK-shaped `token=` callable instead. For
local development against the Bot Framework Emulator, set
`skip_auth=True` to disable JWT validation on inbound activities.

## Custom mount path

The default messaging endpoint is `/teams/messages` (matching the Bot
Framework convention). Override via the `path=` constructor argument.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (c) Microsoft. All rights reserved.

"""Microsoft Teams channel for :mod:`agent_framework_hosting`.

Built on the official ``microsoft-teams-apps`` SDK (microsoft/teams.py).
Surfaces Teams-native affordances on top of Azure Bot Service: streaming
via :class:`~microsoft_teams.apps.HttpStream`, Adaptive Cards (via an
outbound transform hook), citations, and message-feedback callbacks.
"""

from ._channel import (
TeamsChannel,
TeamsCitation,
TeamsFeedbackContext,
TeamsFeedbackHandler,
TeamsOutboundContext,
TeamsOutboundPayload,
TeamsOutboundTransform,
teams_isolation_key,
)

__all__ = [
"TeamsChannel",
"TeamsCitation",
"TeamsFeedbackContext",
"TeamsFeedbackHandler",
"TeamsOutboundContext",
"TeamsOutboundPayload",
"TeamsOutboundTransform",
"teams_isolation_key",
]
Loading