Skip to content

Idr msteams adaptive card tables#89944

Open
rrajp wants to merge 4 commits into
openclaw:mainfrom
rrajp:IDR-msteams-adaptive-card-tables
Open

Idr msteams adaptive card tables#89944
rrajp wants to merge 4 commits into
openclaw:mainfrom
rrajp:IDR-msteams-adaptive-card-tables

Conversation

@rrajp

@rrajp rrajp commented Jun 3, 2026

Copy link
Copy Markdown

Summary

What problem does this PR solve?

Microsoft Teams renders markdown tables as plain-text code blocks (```-wrapped ASCII tables), which are hard to read on mobile, lose column alignment in narrow viewports, and cannot be scrolled horizontally. Teams natively supports Adaptive Card Table/TableRow/TableCell elements (schema 1.5+) that render as proper visual tables with headers, grid lines, and responsive cell wrapping.

Why does this matter now?

Enterprise deployments using OpenClaw via Teams frequently produce tabular data (comparison tables, status reports, structured outputs). Users report that code-block tables are the single biggest readability issue on Teams mobile and narrow desktop panes.

What is the intended outcome?

  • Markdown tables in agent replies are automatically rendered as native Adaptive Card Table elements in Teams
  • Text before/after tables is delivered as regular markdown messages
  • The feature is the default for msteams but opt-out via config (channels.msteams.markdown.tables: "code")
  • Other channels are unaffected

What is intentionally out of scope?

  • Adaptive Card rendering for non-table content (lists, headings, etc.)
  • Nested tables or tables with merged cells
  • The EKG identity JWT signing (organization-specific, handled separately)
  • Streaming/draft table rendering (tables only render in final reply)

What does success look like?

Agent replies containing markdown tables appear as formatted, scrollable, grid-aligned tables in Teams desktop, web, and mobile clients.

What should reviewers focus on?

  • The splitTextAndTables placeholder offset logic — off-by-one errors would corrupt message ordering
  • The buildActivity early return for adaptiveCard messages — ensure it doesn't skip AI-generated entity marking
  • Whether "adaptive" mode in convertMarkdownTables (pass-through) has unintended effects on other code paths that call it

Linked context

Which issue does this close?

Closes # (first-time contribution — no existing issue yet; will file one if maintainers prefer)

Which issues, PRs, or discussions are related?

Was this requested by a maintainer or owner?

No — this is an external contributor PR addressing a pain point encountered in production Teams deployments.

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: Markdown tables in agent replies render as unreadable code blocks in Teams; now render as native Adaptive Card tables
  • Real environment tested: Docker deployment (ghcr.io/openclaw/openclaw:2026.5.12) with msteams channel connected to Azure Bot Service, tested on Teams desktop (Windows) and Teams mobile (iOS)
  • Exact steps or command run after this patch: Sent a prompt that produces a comparison table (e.g. "Compare Python vs JavaScript in a table"), observed the reply in Teams
  • Evidence after fix: Agent reply splits into text message + Adaptive Card with grid-rendered table headers/rows. Table is scrollable and wraps on mobile.
  • Observed result after fix: Tables render with bold headers, visible grid lines, proper cell text wrapping. Non-table text around the table is delivered as separate plain messages.
  • What was not tested: Tables with 10+ columns (may overflow Adaptive Card width limits on narrow screens), deeply nested markdown inside table cells (only plain text supported)
  • Proof limitations or environment constraints: Cannot share screenshots as they contain internal enterprise data. Can reproduce on request with sanitized test prompts.
  • Before evidence: Tables previously appeared as monospace code blocks, often with broken alignment on mobile due to character width variance.

Example Screen shot :
Before :
Markdown
image

After:
Adaptive Card
image

Tests and validation

Which commands did you run?

pnpm test extensions/msteams/src/adaptive-card-table.test.ts
pnpm test extensions/msteams/src/messenger.test.ts

What regression coverage was added or updated?

  • adaptive-card-table.test.ts — unit tests for buildAdaptiveCardTable (card structure, empty cells) and splitTextAndTables (no tables, single table, table at start/end, multiple tables)
  • messenger.test.ts — integration tests for renderReplyPayloadsToMessages with tableMode: "adaptive" (tables render as cards, no-table passthrough) and buildActivity adaptive card attachment handling

What failed before this fix, if known?

No failure — this is additive behavior. The previous "code" mode still works as fallback.

If no test was added, why not?

Tests were added.

Risk checklist

Did user-visible behavior change? Yes — msteams table rendering changes from code blocks to Adaptive Cards (default). Users can revert via config.

Did config, environment, or migration behavior change? Yes — new "adaptive" value in MarkdownTableMode enum; new default for msteams channel. Existing channels.msteams.markdown.tables: "code" configs continue working.

Did security, auth, secrets, network, or tool execution behavior change? No.

What is the highest-risk area?

The renderAdaptiveTablePayload function parsing tables from raw markdown at send time — if the markdown-it parser or IR layer has edge cases with malformed tables, it could produce empty/broken cards.

How is that risk mitigated?

  • Falls back to text-only rendering when markdownToIRWithMeta returns zero tables
  • The splitTextAndTables function handles all edge cases (empty text, table at boundaries)
  • Users can opt out immediately via channels.msteams.markdown.tables: "code"

Current review state

What is the next action?

Ready for maintainer review. Author can provide live proof screenshots with sanitized test data on request.

What is still waiting on author, maintainer, CI, or external proof?

Waiting on maintainer review. CI will run on push.

Which bot or reviewer comments were addressed?

N/A — first submission.

@rrajp
rrajp requested a review from a team as a code owner June 3, 2026 17:16
@github-actions github-actions Bot added the dependencies-changed PR changes dependency-related files label Jun 3, 2026
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: discord Channel integration: discord channel: imessage Channel integration: imessage channel: msteams Channel integration: msteams channel: telegram Channel integration: telegram channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo app: web-ui App: web-ui gateway Gateway runtime scripts Repository scripts commands Command implementations docker Docker and sandbox tooling agents Agent runtime and tooling channel: feishu Channel integration: feishu extensions: acpx extensions: xiaomi extensions: codex extensions: codex-supervisor Extension: codex-supervisor extensions: copilot plugin: workboard size: XL labels Jun 3, 2026
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Dependency graph guard cleared

This PR no longer has blocked dependency graph changes. A future dependency graph change requires a fresh /allow-dependencies-change comment after the guard blocks that new head SHA.

  • Current SHA: 8506c0a16516fac3b3b5a186eaf5663d922825e5

@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label Jun 3, 2026
@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed June 30, 2026, 5:00 AM ET / 09:00 UTC.

Summary
The PR adds an opt-in Microsoft Teams markdown.tables: "adaptive" mode that renders markdown tables as Adaptive Card table attachments, with shared config/schema/docs updates and Teams tests.

PR surface: Source +221, Tests +226, Docs +3. Total +450 across 16 files.

Reproducibility: yes. for the PR blockers: live CI logs reproduce the type failure, and source inspection shows the stale generated metadata, shared-mode safety gap, and rich-text split risk.

Review metrics: 2 noteworthy metrics.

  • Public Markdown Table Mode: 1 added enum/config value. The PR adds adaptive to the shared markdown.tables surface, so generated metadata and sibling channel renderers must agree before merge.
  • Generated Channel Metadata: 0 generated metadata updates. Generated config consumers still see only off, bullets, code, and block for Teams while docs and schema advertise adaptive.

Stored data model
Persistent data-model change detected: vector/embedding metadata: extensions/msteams/src/adaptive-card-table.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Resolve the shared-versus-Teams adaptive config boundary and update generated metadata/docs together.
  • Preserve rich text metadata when splitting text around adaptive tables.
  • [P2] Fix the adaptive-card table test type failure and rerun the relevant type/test lanes.

Proof path suggestion
A visual Teams proof after repairs would materially help confirm both Adaptive Card rendering and surrounding rich text preservation. Mantis is currently scoped to Telegram, Discord, and web UI chat proof, so it is not the right proof path for this surface.
Use maintainer screenshot/manual proof, browser or Playwright proof, Crabbox where appropriate, or normal local artifact proof instead.

Risk before merge

  • [P1] Merging the shared adaptive enum before generated metadata and sibling renderers agree can leave documented config rejected by generated consumers or mishandled outside Teams.
  • [P1] The adaptive split path can silently degrade Teams message formatting around tables because plain text segments bypass the existing rich text metadata renderer.
  • [P1] The branch still needs refresh and typecheck repair before maintainers can trust the merge result.

Maintainer options:

  1. Settle and Repair the Config Boundary (recommended)
    Choose whether adaptive is a shared markdown mode or Teams-only option, then align schema, generated metadata, docs, and sibling renderer tests before merge.
  2. Make Shared Adaptive Safe Everywhere
    If the shared enum remains, update markdown-core and direct IR channel renderers so unsupported channels preserve table text rather than losing or flattening content.
  3. Pause Until Teams Direction Is Sponsored
    If maintainers do not want a new public markdown table mode yet, pause or close this branch and revisit with a narrower Teams-owned design.

Next step before merge

  • [P2] Maintainers need to decide the public config boundary and require the author to repair metadata, rich rendering, and typecheck before merge.

Security
Cleared: The diff changes rendering, config/schema, docs, and tests only, with no new dependencies, workflows, package scripts, secret handling, or downloaded code execution paths.

Review findings

  • [P1] Keep adaptive table mode shared-safe — src/config/zod-schema.core.ts:655
  • [P2] Regenerate the Teams config metadata — docs/concepts/markdown-formatting.md:69
  • [P2] Preserve rich text around adaptive table splits — extensions/msteams/src/messenger.ts:239
Review details

Best possible solution:

Land a Teams-owned, opt-in Adaptive Card table mode after maintainers settle the shared-versus-Teams config boundary, regenerate metadata, preserve rich text around split sends, and clear typecheck.

Do we have a high-confidence way to reproduce the issue?

Yes for the PR blockers: live CI logs reproduce the type failure, and source inspection shows the stale generated metadata, shared-mode safety gap, and rich-text split risk.

Is this the best way to solve the issue?

No, not yet: Adaptive Card table rendering is a plausible Teams feature, but making adaptive a shared markdown table mode before metadata and sibling renderers are safe is not the best maintainable shape.

Full review comments:

  • [P1] Keep adaptive table mode shared-safe — src/config/zod-schema.core.ts:655
    Adding adaptive to the shared schema makes this value valid beyond Teams, but the markdown IR table path only knows how to emit bullets, code, and block output. Scope this to Teams or make the shared/direct-IR renderers preserve table text for adaptive before accepting the public enum value.
    Confidence: 0.89
  • [P2] Regenerate the Teams config metadata — docs/concepts/markdown-formatting.md:69
    The docs and schema now advertise markdown.tables: "adaptive", but the generated Teams channel config metadata still enumerates only off, bullets, code, and block. Generated config consumers can reject the documented option until that metadata is regenerated or updated consistently.
    Confidence: 0.92
  • [P2] Preserve rich text around adaptive table splits — extensions/msteams/src/messenger.ts:239
    This branch splits ir.text and pushes the surrounding text as plain text chunks, so links or styled text adjacent to a table no longer use the normal rich Teams rendering path. Reuse an IR-preserving slice/render path or prove that formatting metadata is preserved for text segments around adaptive tables.
    Confidence: 0.84
  • [P2] Fix the adaptive-card table test type — extensions/msteams/src/adaptive-card-table.test.ts:30
    The live type-check job fails because the test reads row.style from a type that only declares type and cells. Adjust the test narrowing or expected row type so check-test-types can pass on the PR head.
    Confidence: 0.95

Overall correctness: patch is incorrect
Overall confidence: 0.91

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 3d4b7cade9cd.

Label changes

Label justifications:

  • P2: This is a normal-priority Teams rendering feature with limited blast radius, but it affects public config and outbound message formatting before merge.
  • merge-risk: 🚨 compatibility: The PR extends a shared config enum while generated metadata and non-Teams renderers are not proven compatible with the new value.
  • merge-risk: 🚨 message-delivery: The new split-send path changes how Teams text around markdown tables is delivered and can drop rich formatting metadata.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦞 diamond lobster and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (screenshot): Before/after Teams screenshots show the changed real behavior from markdown/code-block table output to an Adaptive Card table, though they do not cover the merge blockers above.
  • proof: sufficient: Contributor real behavior proof is sufficient. Before/after Teams screenshots show the changed real behavior from markdown/code-block table output to an Adaptive Card table, though they do not cover the merge blockers above.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. Before/after Teams screenshots show the changed real behavior from markdown/code-block table output to an Adaptive Card table, though they do not cover the merge blockers above.
Evidence reviewed

PR surface:

Source +221, Tests +226, Docs +3. Total +450 across 16 files.

View PR surface stats
Area Files Added Removed Net
Source 8 235 14 +221
Tests 7 226 0 +226
Docs 1 5 2 +3
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 16 466 16 +450

Acceptance criteria:

  • [P1] gh run view 27021717825 --repo openclaw/openclaw --job 79751172427 --log-failed | rg -n "TS2339|adaptive-card-table|style".
  • [P1] node scripts/run-vitest.mjs extensions/msteams/src/adaptive-card-table.test.ts extensions/msteams/src/send.test.ts extensions/msteams/src/messenger.test.ts packages/markdown-core/src/tables.test.ts src/config/markdown-tables.test.ts src/config/zod-schema.markdown-tables.test.ts.
  • [P1] pnpm check:test-types.

What I checked:

Likely related people:

  • heyitsaamir: Authored the merged Teams SDK rebase that owns much of the current Teams messenger/send behavior affected by this PR. (role: recent area contributor; confidence: high; commits: 04c29825356f; files: extensions/msteams/src/messenger.ts, extensions/msteams/src/send.ts)
  • steipete: Merged the Teams SDK rebase and authored the markdown-core extraction that created the shared table-rendering surface involved here. (role: merger and adjacent owner; confidence: high; commits: 04c29825356f, 99ffd714ce92; files: extensions/msteams/src/messenger.ts, extensions/msteams/src/send.ts, packages/markdown-core/src/ir.ts)
  • obviyus: Recently worked on rich markdown/table rendering in the Telegram sibling renderer, which shares the table-mode invariant this PR broadens. (role: recent markdown table contributor; confidence: medium; commits: da92615816b6, 77eb0fd; files: extensions/telegram/src/format.ts, packages/markdown-core/src/ir.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@rrajp
rrajp force-pushed the IDR-msteams-adaptive-card-tables branch from fe646fb to 1272045 Compare June 3, 2026 17:24
@openclaw-barnacle openclaw-barnacle Bot removed docs Improvements or additions to documentation channel: discord Channel integration: discord channel: imessage Channel integration: imessage labels Jun 3, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 3, 2026
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 3, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
rrajp and others added 2 commits June 4, 2026 12:19
…es as Adaptive Cards

Add a new "adaptive" markdown table mode that renders tables as native
Adaptive Card Table elements (schema 1.5+) instead of plain text code
blocks. This provides proper visual table rendering in Teams desktop
and mobile clients.

- Add "adaptive" to MarkdownTableMode type union and zod schema
- Create adaptive-card-table.ts with buildAdaptiveCardTable() and
  splitTextAndTables() helpers
- Wire adaptive mode through messenger renderReplyPayloadsToMessages
  and proactive send.ts path
- Set msteams defaultMarkdownTableMode to "adaptive"
- Extend MSTeamsRenderedMessage with adaptiveCard field
- Add unit tests for card builder, text splitting, and integration

Co-authored-by: Cursor <[email protected]>
…own-core MarkdownTableMode

The markdown-core package has its own independent MarkdownTableMode
type definition that also needs the 'adaptive' variant to avoid
TS2367 in packages/markdown-core/src/tables.ts.

Co-authored-by: Cursor <[email protected]>
@rrajp
rrajp force-pushed the IDR-msteams-adaptive-card-tables branch from bb6be4f to 5b5aa11 Compare June 4, 2026 06:50
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 4, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 4, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 4, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 4, 2026
…e review findings

Keep adaptive Teams table rendering opt-in, preserve adaptive-card-only sends, and record all split-send platform IDs. Add focused regression coverage and document the new table mode.

Co-authored-by: Cursor <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 5, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 5, 2026
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams docs Improvements or additions to documentation merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: M stale Marked as stale due to inactivity status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants