UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

79 lines (52 loc) 3.76 kB
--- title: "Microsoft Teams" description: "Reach your agent from Microsoft Teams via the Bot Framework Activity protocol, with Adaptive Card human-in-the-loop prompts." type: integration --- The Teams channel runs your agent inside Microsoft Teams as a bot. It takes Bot Framework Activity POSTs, checks the Bot Connector bearer JWT on each one, and routes message activities to your agent. Human-in-the-loop (HITL) prompts come back as Adaptive Cards, and replies go out over the Bot Framework Connector REST API. See [Channels](./overview) for the contract this builds on. ## Add the channel ```ts title="agent/channels/teams.ts" import { teamsChannel } from "eve/channels/teams"; export default teamsChannel(); ``` ```bash MICROSOFT_APP_ID=... MICROSOFT_APP_PASSWORD=... MICROSOFT_TENANT_ID=... # optional, single-tenant bots ``` By default the channel mounts at `POST /eve/v1/teams`. Point your Azure Bot or Teams app messaging endpoint at that public URL. To mount somewhere else, pass `route: "/api/teams/activity"`. ## How the channel handles messages ### Dispatch The default `onMessage` handles two cases: personal-chat messages, and channel or group-chat messages that mention the bot directly. Ambient resource-specific-consent messages are dropped unless you override it. Before dispatch, eve strips the mention, adds a `<teams_context>` block, and scopes channel and group threads by root activity id (`replyToId ?? id`). For example, use the contextual `isSubscribed()` helper to continue active threads without requiring another mention: ```ts import { defaultTeamsAuth, teamsChannel } from "eve/channels/teams"; export default teamsChannel({ async onMessage(ctx, message) { if (message.from.role === "bot" || message.from.id === message.recipient.id) return null; const isDirectMessage = message.scope === "personal"; return isDirectMessage || message.isBotMentioned || (await ctx.isSubscribed()) ? { auth: defaultTeamsAuth(message) } : null; }, }); ``` `isSubscribed()` checks whether the conversation has previously involved the agent. ### Delivery Replies post as Markdown (`textFormat: "markdown"`), with oversized text split across messages and a typing indicator sent on turn start and action requests. ### Human-in-the-loop (HITL) A human-in-the-loop (HITL) `input.requested` event renders as an Adaptive Card. Approval cards show the tool input in the card and fallback text. Buttons and options map to `Action.Submit`, selects to `Input.ChoiceSet`, and freeform to `Input.Text`. Teams may return a submission as a message or invoke; eve handles both before the normal message mention gate and resumes the thread recorded in the card. By default, submissions use the Teams identity of the user who clicked the card. If you customize `onMessage` for an allowlist, configure the same policy in `onInputResponse`; eve otherwise rejects HITL submissions rather than bypassing the message gate. For invokes that aren't HITL, handle them in `onInvoke(ctx, activity)`. ### Proactive sessions Proactive sessions need an existing conversation reference, because the Bot Framework v1 surface cannot create new chats by Azure Active Directory (AAD) user id. Pass `serviceUrl`, `conversationId`, and the other reference fields to `receive(teams, { target })`. ### Attachments Inbound files are off by default. Opt in to allow personal-scope downloads and public media URLs: ```ts export default teamsChannel({ files: { enabled: true, allowedHosts: ["contoso.sharepoint.com"] }, }); ``` ## What to read next - [Channels overview](./overview): the channel contract and every built-in channel - [Auth & route protection](../guides/auth-and-route-protection): authenticating inbound traffic