Skip to content

feat(msteams): add native plugin interactivity parity#55828

Open
Evizero wants to merge 5 commits into
mainfrom
teams-parity-minimal
Open

feat(msteams): add native plugin interactivity parity#55828
Evizero wants to merge 5 commits into
mainfrom
teams-parity-minimal

Conversation

@Evizero

@Evizero Evizero commented Mar 27, 2026

Copy link
Copy Markdown
Member

Summary

DO NOT MERGE YET -- for review

  • Problem: OpenClaw's Teams channel could send messages/cards, but the native plugin interactivity path still stopped short of Teams. The Codex app-server Teams work therefore had to rely on a command bridge instead of the same core plugin/runtime flow used by first-class channels.
  • Why it matters: I am working on this so Teams support for the Codex app-server path is grounded in real OpenClaw channel support, not a partial workaround. Without these core changes, Teams actions, binding flows, message edits, and channel-scoped Graph operations do not have the same native foundation as Discord/Telegram-style plugin integrations.
  • What changed: this PR adds native Teams plugin interactive dispatch in src/plugins/interactive.ts and src/plugins/interactive-dispatch-adapters.ts, adds the Teams runtime surface in src/plugins/runtime/runtime-msteams.ts, src/plugins/runtime/runtime-msteams-typing.ts, and src/plugins/runtime/runtime-msteams-ops.runtime.ts, wires Teams invoke handling through extensions/msteams/src/plugin-interactions.ts and extensions/msteams/src/monitor-handler.ts, extends command/target normalization in src/plugins/commands.ts and src/channels/plugins/target-parsing.ts, and fixes Teams Graph/edit/allowlist correctness in extensions/msteams/src/send.ts, extensions/msteams/src/graph.ts, extensions/msteams/src/graph-messages.ts, extensions/msteams/src/graph-thread.ts, extensions/msteams/src/resolve-allowlist.ts, and extensions/msteams/src/policy.ts.
  • What did NOT change (scope boundary): this does not try to fix unrelated latest-main agent/skills TypeScript failures, and it does not claim live-tenant validation for every Teams topology (for example shared-channel behavior still needs real-environment confirmation outside this PR).

Change Type

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes: N/A
  • Related: cross-repo Teams parity work in openclaw-codex-app-server
  • This PR fixes a bug or regression

Root Cause / Regression History

  • Root cause: Teams support in core had been built around message/card sending and text-command handling, but not the native plugin interactive dispatch/runtime path. That left Codex app-server Teams support depending on a hidden command bridge instead of the same first-class interactive surface exposed to other channels.
  • Missing detection / guardrail: there was no Teams-native seam/integration coverage for plugin invoke handling, source-message edits/clears, Graph channel id translation, or fail-closed allowlist resolution.
  • Prior context (git blame, prior PR, issue, or refactor if known): the current code shape reflected the earlier minimal Teams MVP, where src/plugins/interactive.ts and runtime channel exposure were intentionally limited and Teams only had the smaller send-oriented surface.
  • Why this regressed now: the cross-repo Codex Teams work pushed beyond that MVP and exposed the remaining OpenClaw core gaps.
  • If unknown, what was ruled out: N/A

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file:
    • extensions/msteams/src/monitor-handler.plugin-interactions.test.ts
    • extensions/msteams/src/graph-messages.test.ts
    • extensions/msteams/src/send.test.ts
    • extensions/msteams/src/resolve-allowlist.test.ts
    • extensions/msteams/src/policy.test.ts
    • src/plugins/interactive.test.ts
    • src/plugins/runtime/index.test.ts
    • src/plugins/commands.test.ts
  • Scenario the test should lock in: Teams invoke payloads dispatch through the native plugin interactive handler, reply/follow-up/edit/clear flows update the expected Teams message/card surface, command/binding targets normalize consistently, Graph channel operations resolve the correct team/channel ids, and allowlist failures fail closed instead of widening access.
  • Why this is the smallest reliable guardrail: the failures crossed the Teams adapter, plugin interactive core, and Graph-backed Teams operations; narrower unit tests would miss the integration seams that were actually broken.
  • Existing test that already covers this (if any): the files above now cover the main Teams seams.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Teams plugin actions now go through native OpenClaw plugin interactivity instead of relying on a command-only bridge.
  • Teams plugin replies/follow-ups/edit-source/clear-actions now preserve better source-message behavior for Adaptive Card flows.
  • Teams plugin command binding and explicit target parsing now normalize teams: / msteams: conversation targets consistently.
  • Teams channel-scoped Graph operations use the resolved Graph team id path more safely.
  • Teams allowlist resolution now fails closed when primary-channel lookup cannot safely resolve a usable runtime key.

Diagram

Before:
Teams Action.Submit -> Teams-specific command bridge -> plugin workaround -> partial updates

After:
Teams Action.Submit -> extensions/msteams/src/plugin-interactions.ts
                  -> src/plugins/interactive.ts
                  -> plugin handler/runtime.channel.msteams
                  -> native reply/edit/typing/channel actions

Security Impact

  • New permissions/capabilities? (Yes/No) Yes
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) Yes
  • Command/tool execution surface changed? (Yes/No) Yes
  • Data access scope changed? (Yes/No) Yes
  • If any Yes, explain risk + mitigation:
    • This PR gives plugins a new trusted runtime.channel.msteams surface for Teams-native operations and adds Teams-native interactive dispatch. The risk is widening what a plugin can do in Teams or routing to the wrong target. Mitigations in this PR are explicit runtime typing in src/plugins/runtime/types-channel.ts, targeted runtime wiring instead of broad generic exposure, conversation-scoped interactive handling in extensions/msteams/src/plugin-interactions.ts, Graph team-id resolution fixes in extensions/msteams/src/graph-thread.ts / extensions/msteams/src/graph.ts, and fail-closed allowlist behavior in extensions/msteams/src/resolve-allowlist.ts / extensions/msteams/src/policy.ts.

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local pnpm workspace checkout
  • Model/provider: N/A
  • Integration/channel (if any): Microsoft Teams (extensions/msteams)
  • Relevant config (redacted): local dev config only; no secrets included in this PR

Steps

  1. Enable the Teams channel and a plugin that uses OpenClaw interactive handlers/runtime operations.
  2. Trigger a Teams plugin interaction that needs source-message edits, follow-ups, binding, or Teams-native runtime actions.
  3. Exercise channel-scoped Teams paths that resolve Graph ids and allowlist-target normalization.

Expected

  • Teams interactive actions route through the native plugin handler path.
  • Teams runtime operations are available through runtime.channel.msteams.
  • Teams message/card edit flows keep the intended source-card behavior.
  • Teams channel Graph operations resolve the correct team/channel path.
  • Unsafe Teams allowlist fallbacks do not widen access.

Actual

  • This branch implements those paths in code and verifies them with the Teams-focused tests listed below.
  • After rebasing onto latest main, repo-wide pnpm check is blocked by unrelated src/agents/** TypeScript failures already present on top of main; those are out of scope for this PR.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Concrete issues fixed in this branch and covered by passing tests/review loops:

  • Teams plugin interactions could not run through the native OpenClaw interactive dispatch path.
  • Teams source-message update paths could clear or duplicate replies incorrectly.
  • Teams channel Graph operations could use the wrong team identifier for channel-scoped requests.
  • Teams allowlist resolution briefly risked widening access when primary-channel lookup failed; this branch keeps that path fail-closed.

Evidence run locally during this work:

  • pnpm test -- extensions/msteams/src/graph-messages.test.ts extensions/msteams/src/monitor-handler.plugin-interactions.test.ts extensions/msteams/src/resolve-allowlist.test.ts extensions/msteams/src/policy.test.ts
  • Earlier Teams-scoped validation on this branch also included:
    • extensions/msteams/src/send.test.ts
    • src/plugins/interactive.test.ts
    • src/plugins/runtime/index.test.ts
    • src/plugins/commands.test.ts
  • Before the rebase to latest main, this branch also passed:
    • pnpm check
    • pnpm build
    • pnpm plugin-sdk:api:check

Human Verification

NOT YET!

  • Verified scenarios:
    • reviewed the Teams interactive dispatch flow from extensions/msteams/src/plugin-interactions.ts into src/plugins/interactive.ts
    • verified the new Teams runtime surface and SDK baseline updates
    • verified Teams target parsing / command binding normalization
    • verified Teams Graph id resolution and allowlist behavior through targeted tests and review-fix loops
    • rebased the branch onto latest origin/main and resolved the resulting conflicts
  • Edge cases checked:
    • Teams source-message edit vs clear-card behavior
    • Teams interaction fallthrough when a handler declines handling
    • Graph team-id recovery / paging behavior
    • fail-closed allowlist resolution when primary-channel lookup is unavailable
  • What you did not verify:
    • no live Microsoft Teams tenant verification in this PR
    • no shared/private-channel live validation beyond code/test coverage
    • no attempt to fix unrelated latest-main src/agents/** failures

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Teams interactive/message-edit behavior can differ from Telegram/Discord because Adaptive Cards and Teams invoke semantics are different.
    • Mitigation: keep Teams-specific behavior isolated under extensions/msteams/**, cover the adapter seams with tests, and preserve explanatory comments in the non-obvious parsing/Graph-resolution paths.
  • Risk: Graph team/channel id translation could still behave differently in real tenants than in mocked tests.
    • Mitigation: the code now handles Graph-usable ids directly, pages through group lookup fallback, and fails closed when it cannot safely resolve a usable target.
  • Risk: exposing Teams runtime actions to plugins could widen the trusted plugin surface.
    • Mitigation: the surface is explicit and typed in the runtime channel layer rather than being an unbounded Teams SDK export.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: msteams Channel integration: msteams size: XL maintainer Maintainer-authored PR labels Mar 27, 2026
@greptile-apps

greptile-apps Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds native Microsoft Teams plugin interactivity to OpenClaw, bringing Teams to parity with Discord, Telegram, and Slack for the core plugin interactive dispatch path. The changes wire invoke/message.submitAction payloads from the Teams Bot Framework adapter through the new handleMSTeamsPluginInteraction entry point into dispatchPluginInteractiveHandler, expose a typed runtime.channel.msteams surface to plugins (send, adaptive-card, typing lease, edit/delete/edit-channel), fix Graph team-id resolution so it correctly maps Bot Framework runtime team keys to Graph group GUIDs, and tighten allowlist resolution to fail closed instead of widening access on API failure.

Key points:

  • extensions/msteams/src/plugin-interactions.ts — new entry point for Teams invoke handling; authorization, conversation-ID normalization, and respond-callback construction look correct.
  • extensions/msteams/src/graph-thread.ts — adds a paged group-scan fallback for Bot Framework team-key → Graph group-id resolution. Contains a URL-construction bug: graphPathFromNextLink returns url.pathname + url.search, but Microsoft Graph @odata.nextLink paths include the API version segment (e.g. /v1.0/groups?...). When fetchGraphJson prepends GRAPH_ROOT, the URL doubles to .../v1.0/v1.0/groups, causing a 404 on every paginated request. This silently breaks team-id resolution for any tenant with more than 999 provisioned teams.
  • extensions/msteams/src/resolve-allowlist.ts — intentional behavioral change: primary-channel lookup failure now returns resolved: false instead of falling back to the Graph GUID; this is the described fail-closed fix.
  • src/plugins/interactive.ts — adds msteams as a first-class channel alongside telegram, discord, slack; dispatch routing and overload signatures are correct.
  • looksLikeGraphTeamId is defined identically in three separate files (graph-thread.ts, graph.ts, graph-messages.ts); worth consolidating.

Confidence Score: 4/5

Safe to merge for the common case; one P1 pagination bug in the team-id fallback path affects large tenants (more than 999 teams) where the Bot Framework team key is not directly usable as a Graph GUID.

The bulk of the PR (interactive dispatch wiring, runtime surface, allowlist hardening, Graph message operations, send/edit/typing primitives) is well-structured and backed by targeted tests. The single P1 finding — graphPathFromNextLink doubling the /v1.0 version prefix on paginated @odata.nextLink URLs — only affects the deep fallback path in resolveTeamGroupId, which is only reached when the direct /teams/{id} call fails and the raw ID does not look like a GUID. Most tenants will never reach this code; large enterprises could. The fix is a one-line regex in graphPathFromNextLink. All other findings are P2.

extensions/msteams/src/graph-thread.ts — graphPathFromNextLink pagination URL construction.

Important Files Changed

Filename Overview
extensions/msteams/src/graph-thread.ts Adds paged group-scan fallback for Bot Framework team-key → Graph group-id resolution; contains a URL-construction bug that doubles the API version prefix on pagination, and a per-team primaryChannel fan-out that can be expensive in large tenants.
extensions/msteams/src/plugin-interactions.ts New file wiring Teams invoke payloads through native OpenClaw plugin interactive dispatch; authorization, conversation-ID extraction, and respond-callback wiring look correct.
extensions/msteams/src/resolve-allowlist.ts Switches from find-General-channel to primaryChannel API for team-key resolution and adds fail-closed behavior when the lookup fails; behavioral change is intentional and covered by tests.
extensions/msteams/src/graph-messages.ts Rewrites conversation-target resolution to a typed discriminated union, adding proper team-group-id resolution for channel paths; logic is sound and test coverage updated.
extensions/msteams/src/graph.ts Adds PATCH support, getPrimaryChannelForTeam, and editChannelMSTeams; channel rename correctly resolves the Graph team id before issuing the PATCH.
extensions/msteams/src/send.ts Makes edit-message text optional and adds card support; adds sendTypingMSTeams with correct channel-type guard.
src/plugins/interactive.ts Adds msteams as a first-class interactive channel alongside telegram/discord/slack; dispatch routing and overload signatures look correct.
src/plugins/runtime/runtime-msteams.ts New file exposing the Teams runtime surface to plugins via lazy-loaded operations; typing.start correctly validates cfg presence before creating a lease.
extensions/msteams/src/sdk.ts Uses string-concatenated module IDs to prevent bundler static analysis from eagerly resolving optional Teams SDK deps; intentional lazy-load pattern.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/msteams/src/graph-thread.ts
Line: 27-33

Comment:
**Pagination URL doubles the API version prefix**

`graphPathFromNextLink` returns `url.pathname + url.search`. Microsoft Graph `@odata.nextLink` values embed the API version in the path (the pathname is `/v1.0/groups`, not `/groups`). When `fetchGraphJson` prepends `GRAPH_ROOT` (`https://graph.microsoft.com/v1.0`), the resulting URL becomes `https://graph.microsoft.com/v1.0/v1.0/groups?...` — a 404. Team-ID resolution silently fails to paginate in any tenant with more than 999 teams.

Strip the API-version segment from the pathname before returning it:
```typescript
function graphPathFromNextLink(nextLink: string): string | null {
  try {
    const url = new URL(nextLink);
    // nextLink includes the API version (e.g. /v1.0/groups).
    // Strip it so the caller can prepend GRAPH_ROOT without doubling the prefix.
    const pathWithoutVersion = url.pathname.replace(/^\/(?:v\d+(?:\.\d+)*|beta)\b/, "");
    return pathWithoutVersion + url.search;
  } catch {
    return null;
  }
}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/msteams/src/graph-thread.ts
Line: 86-120

Comment:
**O(N) per-team primary-channel fan-out in the fallback path**

The new fallback enumerates all provisioned teams with `$top=999`, then calls `/teams/{id}/primaryChannel` individually for each candidate until one matches. In a large tenant this can be hundreds of sequential Graph calls and will hit rate limits before succeeding. Consider batching with `$expand=primaryChannel` on the groups query so the primary channel id is returned alongside the group id in a single response per page, reducing the fan-out to one call per page instead of one call per team.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/msteams/src/graph-thread.ts
Line: 19-21

Comment:
**`looksLikeGraphTeamId` is duplicated across three files**

The same helper (`/^[0-9a-fA-F-]{16,}$/.test(value.trim())`) is now defined identically in `graph-thread.ts` (line 19), `graph.ts`, and `graph-messages.ts`. Extracting it to a shared internal utility (e.g., `graph-id-utils.ts`) would remove the drift risk and make the regex easier to update or tighten in one place.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Teams: add native plugin interactivity p..." | Re-trigger Greptile

Comment thread extensions/msteams/src/graph-thread.ts
Comment thread extensions/msteams/src/graph-thread.ts
Comment thread extensions/msteams/src/graph-thread.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: df84e99e95

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/msteams/src/graph-thread.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08c6cb5eb6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/channels/plugins/target-parsing.ts Outdated
@Evizero
Evizero force-pushed the teams-parity-minimal branch from 08c6cb5 to 25463ab Compare March 28, 2026 11:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25463ab775

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/channels/plugins/target-parsing.ts Outdated
@Evizero
Evizero force-pushed the teams-parity-minimal branch from 25463ab to e0ca60c Compare March 28, 2026 11:40
@Evizero
Evizero requested a review from a team as a code owner March 28, 2026 11:40
@openclaw-barnacle openclaw-barnacle Bot added the agents Agent runtime and tooling label Mar 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0ca60cfae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/msteams/src/plugin-interactions.ts
@Evizero
Evizero force-pushed the teams-parity-minimal branch from e0ca60c to d94e1ee Compare March 28, 2026 11:49
@openclaw-barnacle openclaw-barnacle Bot removed the agents Agent runtime and tooling label Mar 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0e0d02cc10

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +140 to +143
if (!teamId || !channelId) {
throw new Error(
`Conversation ${cleaned} is a Teams channel but missing teamId or graphChannelId in the conversation store.`,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add fallback for channel records missing graphChannelId

This branch makes channel Graph operations hard-fail when a stored channel conversation lacks graphChannelId, but that field is newly introduced here and older msteams-conversations.json entries will not have it. After upgrade, existing bound channel conversations can throw missing teamId or graphChannelId for getMessage/pin/react/search until a new inbound message refreshes the store, which is a regression for already-persisted state. Please add a compatibility fallback (or migration/backfill) instead of immediately throwing.

Useful? React with 👍 / 👎.

Comment on lines 287 to 289
teamId,
graphChannelId: activity.channelData?.channel?.id,
channelId: activity.channelId,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve graphChannelId when channel metadata is absent

The upsert payload always includes graphChannelId: activity.channelData?.channel?.id, so activities without channelData.channel write undefined for this field. Because the store merge path spreads incoming fields and does not preserve graphChannelId, this can erase previously known channel metadata for that conversation, and later channel Graph calls will fail on the new required-metadata check. Only write graphChannelId when it is present.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added the rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. label May 21, 2026
@clawsweeper

clawsweeper Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed July 5, 2026, 12:25 PM ET / 16:25 UTC.

Summary
Adds native Microsoft Teams plugin interactive dispatch, a plugin-facing Teams runtime surface, Teams Graph/edit/allowlist changes, target normalization updates, focused tests, SDK baseline updates, and a draft parity spec.

PR surface: Source +1031, Tests +390, Docs +1200, Generated 0. Total +2621 across 39 files.

Reproducibility: no. high-confidence live Teams reproduction/proof is present; the PR body explicitly says live tenant verification is not done. The target-parsing and graphChannelId upgrade blockers are source-reproducible from the PR head.

Review metrics: 3 noteworthy metrics.

  • Plugin API surface: 1 interactive channel plus 7 Teams runtime helpers added. The PR expands plugin-facing Teams authority, so compatibility and security review cannot be delegated to green tests alone.
  • Stored metadata requirement: 1 persisted conversation field added. graphChannelId affects upgrades from existing Teams conversation records and needs migration, backfill, or safe fallback proof.
  • Live merge state: CONFLICTING / DIRTY at 0e0d02c. Maintainers need a rebase before validating the actual current-main merge result.

Stored data model
Persistent data-model change detected: serialized state: extensions/msteams/src/graph.test.ts, vector/embedding metadata: OPENCLAW_CODEX_APP.md, vector/embedding metadata: src/plugins/commands.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Result: blocked until real behavior proof is added.

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

Rank-up moves:

  • Rebase onto current main and resolve the dirty merge state.
  • [P1] Fix the target-parsing contract and graphChannelId upgrade/preservation blockers with focused tests.
  • [P1] Add redacted live Microsoft Teams tenant proof for invoke dispatch, card update flows, Graph routing, and allowlist behavior.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body explicitly says live Microsoft Teams tenant verification is not done; targeted tests are useful but do not prove the real Teams tenant, Graph routing, or allowlist paths after the change. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Proof path suggestion
A real Teams interaction recording with diagnostics would materially help verify the visible Action.Submit flow, target scoping, and allowlist behavior. Mantis is proof-only, so it must not be asked to change code or mutate GitHub state.
Use ClawSweeper's repair, apply, or automerge lanes for code changes, branch updates, labels, comments, PR repair, closes, or merges.

Risk before merge

  • [P1] The PR is currently CONFLICTING / DIRTY, so maintainers need a rebase before reviewing the actual current-main merge result.
  • [P1] The new runtime.channel.msteams surface grants plugins broader Teams send, card, typing, edit, delete, channel-edit, and Graph-backed authority without final maintainer API/security direction.
  • [P1] Existing Teams conversation-store records can lack graphChannelId, and the PR-head sparse upsert path can clear that field, so Graph-backed channel operations can break after upgrade.
  • [P1] Live Microsoft Teams tenant behavior is still unproven for invoke dispatch, Adaptive Card reply/follow-up/edit/clear flows, Graph channel routing, and allowlist fail-closed behavior.

Maintainer options:

  1. Rebase and repair compatibility blockers (recommended)
    Bring the branch onto current main, remove private extension parser imports from core, and make stored Teams channel metadata upgrade-safe with focused tests before another merge review.
  2. Require live Teams tenant proof
    Capture redacted real Teams proof for invoke dispatch, card reply/follow-up/edit/clear behavior, Graph channel routing, and allowlist fail-closed behavior before accepting the expanded surface.
  3. Pause or split the API expansion
    If maintainers want the broader lane-oriented channel interface to own this shape, pause this PR or split out only narrow Teams fixes that do not expand the permanent plugin API.

Next step before merge

  • [P2] Protected maintainer PR needs rebase, API/security direction, live Teams proof, and compatibility repairs rather than an autonomous repair lane.

Maintainer decision needed

  • Question: Should OpenClaw accept this new plugin-facing runtime.channel.msteams authority now, and if so what target-scoping, upgrade, and live-proof conditions are required before merge?
  • Rationale: The PR expands plugin API and Teams Graph authority in a maintainer-labeled PR; deciding the permanent API/security boundary and whether to split or wait for the broader lane-interface direction is not a safe automation-only choice.
  • Likely owner: steipete — steipete is the strongest history signal for the current route/plugin boundary and Teams store refactor seams that govern the API/security decision.
  • Options:
    • Repair and prove this Teams surface (recommended): Rebase the branch, fix the target-parsing and graphChannelId upgrade blockers, then require redacted live Teams tenant proof before merge.
    • Narrow or split behind the lane interface: Move only the minimum Teams fixes forward and defer broad runtime/API expansion to the lane-oriented channel interface work at refactor(plugins): add lane-oriented channel interface #59986.
    • Pause this branch: Keep the PR open but paused until maintainers settle the Teams plugin authority model and live validation plan.

Security
Needs attention: The diff expands trusted Teams plugin authority and Graph-backed operations without live target-scoping proof, and the metadata upgrade blockers can affect authorization-sensitive routing.

Review findings

  • [P1] Keep target parsing behind channel contracts — src/channels/plugins/target-parsing.ts:5-7
  • [P1] Handle stored channel records without graphChannelId — extensions/msteams/src/graph-messages.ts:139-143
  • [P2] Preserve graphChannelId during sparse upserts — extensions/msteams/src/monitor-handler/message-handler.ts:288
Review details

Best possible solution:

Rebase onto current main, route Teams target parsing through current channel route contracts, make graphChannelId upgrade-safe, and require maintainer API/security signoff plus redacted live Teams proof before merge.

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

No high-confidence live Teams reproduction/proof is present; the PR body explicitly says live tenant verification is not done. The target-parsing and graphChannelId upgrade blockers are source-reproducible from the PR head.

Is this the best way to solve the issue?

No, not as submitted. The direction is plausible, but the best fix needs current-main route-contract alignment, upgrade-safe Teams metadata handling, maintainer API/security approval, and live tenant proof before merge.

Full review comments:

  • [P1] Keep target parsing behind channel contracts — src/channels/plugins/target-parsing.ts:5-7
    These imports make core target parsing depend directly on private bundled extension source modules. Current main keeps this surface behind loaded channel/plugin contracts and route helpers, so this can eagerly load optional channel code and drift from external plugin behavior; route through the registered channel contract or a narrow lightweight public artifact instead.
    Confidence: 0.87
  • [P1] Handle stored channel records without graphChannelId — extensions/msteams/src/graph-messages.ts:139-143
    graphChannelId is new in this PR, but existing stored Teams channel conversations will not have it. After upgrade, Graph-backed channel operations for those bound conversations can throw here until a new inbound activity refreshes the store, so this needs a migration/backfill or safe lookup fallback before the field is required.
    Confidence: 0.9
  • [P2] Preserve graphChannelId during sparse upserts — extensions/msteams/src/monitor-handler/message-handler.ts:288
    This writes graphChannelId even when activity.channelData?.channel?.id is absent. The PR branch's store merge preserves only timezone before spreading incoming fields, so a sparse Teams activity can erase a previously captured Graph channel id and break later channel Graph operations; only include this field when present or preserve the existing value in the merge helper.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 70f2bef6b4cf.

Label changes

Label justifications:

  • P2: This is a substantial Teams feature/API improvement with compatibility blockers, but the blast radius is limited to the Teams integration and plugin runtime surface.
  • merge-risk: 🚨 compatibility: The PR changes plugin-facing API surface and requires new stored Teams channel metadata without an upgrade-safe path.
  • merge-risk: 🚨 message-delivery: Missing or erased Teams target metadata can make Graph-backed replies, edits, pins, reactions, searches, or interactive responses fail or use the wrong conversation path.
  • merge-risk: 🚨 security-boundary: The new runtime.channel.msteams surface grants plugins broader Teams message and channel operations that need target-scoping proof and maintainer approval.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body explicitly says live Microsoft Teams tenant verification is not done; targeted tests are useful but do not prove the real Teams tenant, Graph routing, or allowlist paths after the change. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +1031, Tests +390, Docs +1200, Generated 0. Total +2621 across 39 files.

View PR surface stats
Area Files Added Removed Net
Source 24 1159 128 +1031
Tests 12 913 523 +390
Docs 1 1200 0 +1200
Config 0 0 0 0
Generated 2 68 68 0
Other 0 0 0 0
Total 39 3340 719 +2621

Security concerns:

  • [medium] Expanded Teams runtime authority needs scoped proof — src/plugins/runtime/types-channel.ts:149
    runtime.channel.msteams exposes Teams send/card/typing/message-edit/delete/channel-edit operations to plugins. Because target resolution depends on newly stored Teams metadata and no live tenant proof is included, maintainers need security/API review before accepting this surface.
    Confidence: 0.82

What I checked:

  • Repository policy read: Root and scoped AGENTS.md files were read; plugin/channel/SDK boundary and compatibility rules apply because the PR changes Teams channel code, plugin runtime APIs, target parsing, persisted Teams metadata, and SDK surfaces. (AGENTS.md:18, 70f2bef6b4cf)
  • Scoped docs contract: Current docs say not to add new uses of parser-backed loaded-route helpers and to prefer channel targetResolver/resolveOutboundSessionRoute for provider-native target identity. Public docs: docs/plugins/sdk-migration.md. (docs/plugins/sdk-migration.md:352, 70f2bef6b4cf)
  • Live PR state: Live GitHub metadata shows the PR is open, non-draft, author association MEMBER, labeled maintainer, head 0e0d02c, and mergeStateStatus DIRTY / mergeable CONFLICTING. (0e0d02cc1076)
  • Current main does not already implement the central feature: Current main has no source matches for PluginInteractiveMSTeams, runtime.channel.msteams, createRuntimeMSTeams, handleMSTeamsPluginInteraction, sendTypingMSTeams, or graphChannelId, so this PR is not implemented on main. (70f2bef6b4cf)
  • PR head deep-imports extension internals from core target parsing: The PR-head target parser imports Discord, Teams, and Telegram private extension source modules directly from src/channels, bypassing the loaded channel/plugin contract path used on current main. (src/channels/plugins/target-parsing.ts:5, 0e0d02cc1076)
  • Current main keeps loaded target parsing behind channel contracts: Current main's loaded target parser resolves through getLoadedChannelPluginForRead or getChannelPlugin messaging.parseExplicitTarget rather than directly importing private extension source modules. (src/channels/plugins/target-parsing-loaded.ts:54, 70f2bef6b4cf)

Likely related people:

  • Evizero: The PR branch is authored by Evizero, and GitHub commit search shows prior merged Teams Graph authentication fixes by the same author. (role: feature branch owner and prior Teams contributor; confidence: medium; commits: 0e0d02cc1076, 2b8b3c4b10e9, ef777d6bb64b; files: extensions/msteams/src/graph.ts, extensions/msteams/src/graph-thread.ts, src/plugins/runtime/types-channel.ts)
  • steipete: Current-main history shows steipete on channel route helper migrations, plugin SDK/runtime adjacent work, Teams conversation-store refactors, and CODEOWNERS for ownership rules. (role: recent route/plugin runtime and Teams store contributor; confidence: high; commits: c4f0da00a9fe, e27c32b9b0d9, 1bf8d69d950d; files: src/channels/plugins/target-parsing-loaded.ts, src/plugins/interactive.ts, extensions/msteams/src/conversation-store-helpers.ts)
  • sudie-codes: Teams Graph message, reaction, group-management, and thread-history commits touch the same Graph/message routing area this PR expands. (role: Teams Graph feature contributor; confidence: high; commits: 8c852d86f759, 355794c24a39, 0f192710924f; files: extensions/msteams/src/graph-thread.ts, extensions/msteams/src/graph-messages.ts, extensions/msteams/src/graph.ts)
  • vincentkoc: History shows vincentkoc on loaded target parsing isolation and interactive callback dedupe/registry work adjacent to this PR's core parsing and interactive dispatch changes. (role: target parsing and plugin interactive seam contributor; confidence: medium; commits: eed595bba9ac, d1e3ed374398, 2e1ec9653c37; files: src/channels/plugins/target-parsing-loaded.ts, src/plugins/interactive.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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-03T04:34:06.608Z sha 0e0d02c :: found issues before merge. :: [P1] Keep target parsing behind channel contracts | [P1] Handle stored channel records without graphChannelId | [P2] Preserve graphChannelId during sparse upserts

@clawsweeper

clawsweeper Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🔥 Warming up: real-behavior proof passed; findings, security review, or rank-up moves are still in progress.

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.
What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@clawsweeper clawsweeper Bot added 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. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels May 22, 2026
@clawsweeper clawsweeper Bot added status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 25, 2026
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 maintainer Maintainer-authored PR 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. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XL status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant