# @copilotkit/channels-teams The **Microsoft Teams platform adapter** for [`@copilotkit/channels`](../channels). It's a concrete `PlatformAdapter` that plugs Teams into the platform-agnostic bot engine, exactly like [`@copilotkit/channels-slack`](../channels-slack) does for Slack. You write your bot once with `createBot` (handlers, JSX, tools, context) and run it on Teams by adding this adapter. It is built on the **Microsoft 365 Agents SDK** (`@microsoft/agents-hosting`), the successor to the Bot Framework SDK. ## Install ```sh pnpm add @copilotkit/channels @copilotkit/channels-ui @copilotkit/channels-teams ``` ## Quickstart ```ts import { createBot } from "@copilotkit/channels"; import { teams } from "@copilotkit/channels-teams"; const bot = createBot({ adapters: [teams({ port: 3978 })], }); bot.onMessage(({ thread, message }) => thread.post(`Echo: ${message.text}`)); await bot.start(); // POST /api/messages now listening on :3978 ``` Then point the **Microsoft 365 Agents Playground** at it. No Microsoft credentials are required for local development: ```sh npx @microsoft/m365agentsplayground # opens http://localhost:56150 ``` The Playground connects to `http://127.0.0.1:3978/api/messages` and gives you a Teams-like chat UI to test against. See [`examples/teams`](../../examples/teams) for a complete, runnable echo bot, and the [Microsoft Teams guide](../../showcase/shell-docs/src/content/docs/frontends/teams.mdx) for sideloading into real Teams via Azure Bot Service. ## How it maps onto the `PlatformAdapter` contract - **Ingress:** a `CloudAdapter` receives Teams activities at `POST /api/messages` (stood up by an Express server). Each `message` activity is normalized into `sink.onTurn(...)`. Uploaded files ride along as attachments: `buildFileContentParts` downloads them (a `file.download.info` URL, or a `data:`/https media URL) and hands the agent multimodal content parts — CSV/JSON/text as decoded text, images and PDFs as binary. That's what makes "upload a CSV → get a chart" work. Note Teams only delivers uploaded files to a bot in **1:1 (personal) chat** (requires `supportsFiles: true` in the app manifest); in a channel or group chat Teams does NOT send the file to the bot at all, so chart-from-data there means pasting the data inline. - **Egress:** structured/interactive UI is rendered to an **Adaptive Card** (1.5) and sent as an attachment; a reply that collapses to plain text is sent as a normal text activity (a bare `Echo: hi` shouldn't be a card). Both go out on the live `TurnContext` _within the originating turn_. The engine awaits the whole turn handler, so a reply (or a full `runAgent()` loop) completes before the HTTP response closes. (Out-of-turn / proactive sends fall back to `CloudAdapter.continueConversation` via the captured conversation reference.) - **Files out:** `postFile` posts a file to the conversation. An image (e.g. a rendered chart PNG) is sent as an inline attachment via a `data:` URI, so it renders directly in the thread — the bot-slack `postFile` parallel. - **Streaming:** text replies stream **by message edit** (Teams' baseline model). It posts the first content, then `updateActivity` edits the same message as the buffer grows (throttled and serialised; see `TeamsMessageStream`), after a typing indicator. Native token streaming is a later enhancement. - **Agent runs:** `createRunRenderer` bridges AG-UI events to Teams. Each text message is streamed by edit, and tool calls plus interrupts are captured for the run loop. - **History:** Teams does not hand the bot a queryable transcript, so an in-memory `TeamsConversationStore` keeps one per conversation and seeds each agent run with it. Swap in a durable `ConversationStore` for production. ## Options ```ts teams({ port: 3978, // POST /api/messages port (Playground default) clientId, // Microsoft app id; omit for anonymous local dev clientSecret, // omit for anonymous local dev tenantId, // omit for multi-tenant / anonymous interruptEventNames, // custom-event names treated as agent interrupts }); ``` Credentials also resolve from the `clientId` / `clientSecret` / `tenantId` environment variables (the names the M365 Agents SDK reads). ## Status & roadmap Implemented: message ingress; **Adaptive Card rendering** of the bot-ui vocabulary (`
`, `
`/``, ``, ``, ``, ``/`