Skip to content

feat(teams): add budget-aware long messages - #1501

Draft
NeoHsu wants to merge 15 commits into
openabdev:mainfrom
NeoHsu:stack/teams-09-formatting-long-messages
Draft

feat(teams): add budget-aware long messages#1501
NeoHsu wants to merge 15 commits into
openabdev:mainfrom
NeoHsu:stack/teams-09-formatting-long-messages

Conversation

@NeoHsu

@NeoHsu NeoHsu commented Aug 20, 2026

Copy link
Copy Markdown

Important

Stacked draft: logical base stack/teams-08-attachment-ingress is PR #1500. GitHub requires an upstream PR base to exist in openabdev/openab, so this draft temporarily targets main and may show preceding stack layers. Do not merge it until #1500 is merged and this branch is rebased onto current main; then review only its single incremental commit.

What problem does this solve?

Replace Teams' temporary 4,096-character split with an exact conservative
UTF-16-byte budget, preserve Markdown/code-fence/table fallback behavior, and
make every required-ACK chunk sequence ordered, stop-on-failure, and explicitly
partial when only a prefix was delivered.

Discord Discussion URL: https://discord.com/channels/1491295327620169908/1491365158868619404/1531339032527765655
Microsoft Teams roadmap discussion.

Review Contract

This is the proposed PR-body contract. The PR description becomes canonical
only if a maintainer opens the PR and freezes this text under the repository's
review process.

Goal

Replace Teams' temporary 4,096-character split with an exact conservative
UTF-16-byte budget, preserve Markdown/code-fence/table fallback behavior, and
make every required-ACK chunk sequence ordered, stop-on-failure, and explicitly
partial when only a prefix was delivered.

Non-goals

Adaptive Cards, outbound authenticated mentions, Graph/RSC files, proactive
messaging, configurable Teams size limits, changing other platforms' advertised
limits, automatic POST retry, or rollback of delivered chunks are not part of PR 9.

Accepted Residual Risks

Microsoft's 100 KB limit is approximate, so the documented 80,000-byte target
may still receive an explicit 413 as the platform evolves. Teams Markdown
presentation differs across desktop, iOS, and Android. An operator can still
choose tables = "off" and receive raw pipes. A rejected later chunk can leave
a visible delivered prefix; rollback is intentionally avoided because it would
add ambiguous writes and could destroy successfully delivered content.

Acceptance Criteria

The PR's automated checks pass; Standalone and Unified advertise the
same Teams budget; every generated chunk fits the negotiated unit; required-ACK
sequences stop at the first non-delivered outcome; unknown POST outcomes produce
no retry, cleanup, fresh send, or warning activity; partial-delivery counts are
sanitized and accurate; the 4,096 legacy fallback remains intact; and existing
Teams progressive and non-Teams character-splitting regressions pass.

Follow-ups

Revisit headroom only on direct 413 evidence; add budget accounting if future
activities carry mention
entities or cards; evaluate richer cross-client Markdown normalization; and
implement Adaptive Cards only after text-command semantics are stable.

At a Glance

Authenticated Teams activity / operator target
                    │
                    ▼
            [this PR’s bounded layer]
                    │
                    ▼
          explicit outcome or fail-closed stop

Prior Art & Industry Research

OpenClaw: its Microsoft Teams extension separates access checks, Bot Framework route context, and outbound operations. For this slice the relevant comparison is Teams formatting, message limits, and ordered multi-part output.

Hermes Agent: its Teams platform adapter keeps Teams-specific transport and message shaping behind a platform adapter. It does not provide OpenAB’s negotiated Core/Gateway outcome contract, so this PR keeps the useful adapter boundary but adds explicit fail-closed semantics.

Proposed Solution

  • Replace the temporary Teams character cap with an 80,000 UTF-16-byte budget.
  • Preserve table fallback, Markdown fences, grapheme boundaries, and legacy limits.
  • Stop ordered required-ACK chunks at the first non-Delivered outcome.

Why this approach?

A conservative UTF-16-byte budget matches the documented platform unit while ordered stop-on-failure delivery avoids duplicate suffixes.

Alternatives Considered

Use a character count (rejected: wrong unit for supplementary Unicode) or roll back a delivered prefix (rejected: destructive ambiguous writes).

Validation

  • cargo check -p openab-core
  • cargo check -p openab-gateway --features teams
  • python3 scripts/test-teams-ack-drop-proxy.py (14 tests)

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.

1 participant