Skip to content

feat(channels): add native Microsoft Teams channel#783

Open
olbboy wants to merge 2 commits intonextlevelbuilder:devfrom
olbboy:feat/teams-channel
Open

feat(channels): add native Microsoft Teams channel#783
olbboy wants to merge 2 commits intonextlevelbuilder:devfrom
olbboy:feat/teams-channel

Conversation

@olbboy
Copy link
Copy Markdown

@olbboy olbboy commented Apr 9, 2026

Summary

Complete Microsoft Teams channel implementation for GoClaw via Azure Bot Framework REST API. Includes channel core, app package generator, DB instance factory, multi-bot webhook support, and 15 production bug fixes discovered during E2E testing.

56 files changed, +3938/-51 lines, 56+ tests

Features

Teams Channel Core

  • JWT auth with JWKS rotation, webhook handler, outbound messaging with retry
  • LLM markdown sanitization, message chunking (80KB limit)
  • Per-instance webhook paths for multi-bot deployments
  • DB instance factory for UI-created instances
  • serviceURL recovery from metadata (survives restart)

App Package Generator

  • CLI: `goclaw teams app-package --name "Bot" -o app.zip`
  • HTTP: `GET /v1/teams/app-package?name=Bot&bot_id=UUID`
  • Web UI: download button on Teams channel detail page
  • Teams v1.21 manifest with embedded default icons

Platform Fixes (cross-channel)

  • `CoerceStringBools` at save+load: prevents "inherit" string crash
  • Webhook path dedup: prevents mux.Handle panic
  • Permission scope auto-normalize: fixes /addwriter for non-Telegram channels
  • Bootstrap exception: new groups work immediately
  • System prompt tool retry: prevents session poisoning
  • service_url in routing metadata: enables Teams reply after restart

E2E Verified

  • 1:1 chat + group chat + multi-bot + app sideload + block reply + restart recovery

Test plan

  • `go test -race ./internal/channels/teams/...` (42 tests)
  • `go test -race ./internal/http/ -run TestTeamsApp` (14 tests)
  • `go build ./...` + `go build -tags sqliteonly ./...`
  • `go vet ./...`
  • No secrets in diff

Complete Teams channel implementation via Azure Bot Framework REST API:

Core channel (internal/channels/teams/):
- JWT auth with JWKS rotation, Bot Framework webhook handler
- Outbound messaging with retry, typing indicators, rate limiting
- LLM markdown → Teams markdown sanitization, message chunking (80KB)
- Per-instance webhook paths for multi-bot deployments
- DB instance factory for UI-created instances
- serviceURL recovery from metadata (survives restart)

App package generator:
- CLI: goclaw teams app-package --name "Bot" -o teams-app.zip
- HTTP: GET /v1/teams/app-package?name=Bot&bot_id=UUID
- Web UI: download button on Teams channel detail page
- Teams v1.21 manifest schema with embedded default icons

Platform fixes (cross-channel):
- CoerceStringBools: normalize "true"/"false"/"inherit" at save+load
- Webhook path dedup prevents mux.Handle panic
- Permission scope auto-normalize in config_permissions.grant RPC
- Bootstrap exception for file_writer in new groups
- Explicit system prompt for tool access in bootstrap mode
- service_url propagated through all outbound paths

Channel type registration:
- "teams" added to isValidChannelType (HTTP + WS handlers)
- IsDefaultChannelInstance updated with all channel types
- contacts-page CHANNEL_TYPES filter updated

Tests: 19 channel + 23 appmanifest + 14 HTTP handler tests
Docs: architecture, channels, changelog, HTTP API updated
@olbboy olbboy force-pushed the feat/teams-channel branch from 67808d3 to c3f6f29 Compare April 9, 2026 08:00
The outbound dispatcher ran Send() synchronously in a single goroutine.
When one channel's Send() was slow (Teams token refresh, Bot Framework
API timeout), ALL channels stopped receiving outbound messages.

Now each Send() runs in its own goroutine, so a slow Teams reply
doesn't block Telegram, Discord, or other channels.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants