Multi-channel ingress
The agent runtime is decoupled from the chat surface. An Ingress interface normalises inbound webhook events into a common IncomingMessage shape and lets the same agent loop service Teams, Slack, and (planned) Discord without per-channel branching at the agent level.
What an ingress owns
- Inbound. Receive the channel's webhook payload and normalise it into
{ brandId, tenantId, agentSlug, userExternalId, threadId, text }. - Outbound. Send replies via the channel's API (Bot Framework
connector.replyToActivity, Slackchat.postMessage, Discord REST). - Identity mapping. Resolve the channel's user id to a User row in the Brand's identity system, or proxy as an anonymous end-user for downstream Tenant customers who aren't first-class users on the platform.
- Threading. Map the channel's thread model onto our conversation history so a long Teams thread or a Slack channel @-mention chain stays coherent.
Channels
| Channel | Status | Surface area today |
|---|---|---|
| Microsoft Teams | Shipped | Per-Brand Azure Bot Service registration; per-agent Bot Channel + Entra app reg. Side-loaded manifest under /appPackage. |
| Slack | Shipped (Phase 5) | Per-Brand Slack App with channel-to-Tenant mapping; DM + thread + @mention. Workflows and slash commands deferred. |
| Discord | Roadmap (Sprint 4) | Same Ingress interface as Slack; mechanical addition once Slack stabilises in production. |
BYO bot registrations
Per-Brand BYO is mandatory on both Teams and Slack. Each Brand registers their own bot identity in their own Microsoft tenant and/or Slack workspace; their customer sees the Brand's bot, not a generic shared bot. The platform stores credentials encrypted under brandId scope in the secrets vault alongside the LLM provider keys and OIDC client secrets.