Skip to content

fix(msteams): reset sessions on app removal lifecycle#100371

Closed
jimmypuckett wants to merge 8 commits into
openclaw:mainfrom
spinen:codex/msteams-lifecycle-session-reset-99054
Closed

fix(msteams): reset sessions on app removal lifecycle#100371
jimmypuckett wants to merge 8 commits into
openclaw:mainfrom
spinen:codex/msteams-lifecycle-session-reset-99054

Conversation

@jimmypuckett

@jimmypuckett jimmypuckett commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Closes #99054

What Problem This Solves

Fixes an issue where Microsoft Teams users who remove a personal app/bot and later add it again can continue the same OpenClaw server-side DM session, allowing the bot to use prior conversation context after an app lifecycle boundary.

This targets Teams app-management lifecycle signals that the bot can actually observe. Live capture showed Teams' local "Remove chat history" action can arrive later as an ordinary message in the same personal conversation.id, with no installationUpdate, conversationUpdate, membersAdded, or membersRemoved activity. This PR does not claim to detect that fully local clear-chat action when Teams gives the bot no lifecycle or conversation-boundary signal.

Why This Change Was Made

Teams now routes installationUpdate removal activities and bot membersRemoved conversation updates into a lifecycle handler. On a removal boundary, the handler removes the cached Teams conversation reference, rotates the matching OpenClaw session entry to a new session id with updatedAt: 0, and clears provider-owned route/delivery/origin metadata so the next inbound message cannot resume the removed chat transcript.

The handler also treats a personal installationUpdate action=add as a reinstall boundary only when an existing route-matched Teams DM session is already active. That catches tenants or flows where the re-add signal is visible but the prior remove signal was missed, without resetting first-time installs. Finally, inbound personal DMs check for a stored same-user/same-bot conversation reference with a different Teams conversation.id; when Teams exposes that boundary, OpenClaw removes the previous reference and rotates the DM session.

User Impact

After a true Teams app removal and re-add, the next inbound message starts from a fresh OpenClaw session instead of silently resuming prior DM or channel context. Operators also avoid retaining a cached proactive-send reference for the removed Teams conversation.

For Teams clear-chat/reopen flows, the patch protects the observable case where Teams gives the bot a new personal conversation id. If Teams reuses the same server-side conversation id and sends no lifecycle event, there is no bot-visible signal in the captured payloads; that remains a Teams platform limitation rather than a claim made by this PR.

Existing welcome-card behavior, normal messages, reactions, and unrelated lifecycle events are unchanged.

Evidence

  • Live corrected Dale smoke:
    • Baseline before app removal used a synthetic marker.
    • Teams app removal emitted installationUpdate action=remove.
    • Handler logged msteams lifecycle remove handled, reason=installation-remove, conversationType=personal, conversationRemoved=true, sessionsReset=1.
    • The session entry rotated to a new redacted session id with updatedAt: 0 and no Teams route/delivery/origin metadata.
    • After re-add, Teams showed the welcome card and the verification prompt used a fresh session; the bot did not recall the pre-removal marker.
  • Live Teams Remove chat history follow-up after deploying this branch:
    • Sent a synthetic pre-clear marker.
    • Used Teams Remove chat history, opened the app/chat again, and sent a verification prompt.
    • No installationUpdate add, lifecycle/remove activity, or DM conversation-boundary handler log appeared.
    • The same OpenClaw session id remained active, and the bot could recall the pre-clear marker.
    • This confirms the PR should not claim to fix Teams local clear-history behavior when Teams sends no lifecycle event and reuses the same server-side conversation id.
  • Added regression coverage for:
    • personal installationUpdate/remove
    • personal installationUpdate/remove-upgrade
    • first-install installationUpdate/add with no active session
    • personal installationUpdate/add when an existing session is active
    • ignored channel installationUpdate/add
    • channel bot membersRemoved
    • ignored non-bot membersRemoved
    • race-safe session rotation
    • personal DM conversation-id boundary rotation
    • no rotation for matching personal conversation ids
    • no rotation for different stored bot ids
  • Added monitor-level coverage proving the Teams activity shim dispatches installationUpdate and membersRemoved activities to registered lifecycle handlers.
  • Validation:
    • pnpm test extensions/msteams/src/monitor-handler/lifecycle-handler.test.ts - 11 tests passed.
    • pnpm test extensions/msteams/src/monitor-handler/message-handler.authz.test.ts - 18 tests passed.
    • pnpm test extensions/msteams - 71 files passed, 1007 tests passed.
    • pnpm run lint:extensions:bundled - passed.
    • pnpm format:check extensions/msteams/src/monitor-handler/lifecycle-handler.ts extensions/msteams/src/monitor-handler/lifecycle-handler.test.ts extensions/msteams/src/monitor-handler/message-handler.ts - passed.
    • git diff --check - passed.

@clawsweeper

clawsweeper Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 10, 2026, 2:55 PM ET / 18:55 UTC.

Summary
The PR dispatches Microsoft Teams removal lifecycle events, removes matching cached conversation references, rotates routed sessions, and detects observable personal-DM conversation-id changes.

PR surface: Source +423, Tests +575. Total +998 across 8 files.

Reproducibility: yes. Create a matching Teams session entry with updatedAt: 0 and provider-owned binding metadata, trigger the removal handler, and observe that the PR skips it even though current session resolution still treats it as fresh.

Review metrics: 1 noteworthy metric.

  • Stored session reset paths: 1 added. The new replacement path clears provider routing metadata but currently excludes matching entries already timestamped stale.

Stored data model
Persistent data-model change detected: migration/backfill/repair: extensions/msteams/src/monitor-handler/lifecycle-handler.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #99054
Summary: This PR is the stronger candidate fix for the canonical Teams lifecycle issue but needs one correctness repair; the competing stale-only PR is not a safe co-landing path.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦞 diamond lobster
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

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

Rank-up moves:

  • [P2] Rotate zero-timestamp provider-bound entries and add focused regression coverage.

Risk before merge

  • [P1] A matching Teams entry already marked updatedAt: 0 can retain its old session identifier and provider binding after app removal, allowing prior context to resume.
  • [P1] The PR intentionally preserves transcript files while severing active session and proactive-send linkage; maintainers still need to approve that retention boundary.
  • [P1] The overlapping fix(msteams): handle bot removal and uninstallation to mark sessions stale #100350 handles the same events with a weaker stale-only path and must not land alongside this implementation.

Maintainer options:

  1. Repair stale provider-bound entries (recommended)
    Rotate matching entries even when updatedAt is already zero and add focused provider-binding regression coverage.
  2. Accept incomplete lifecycle isolation
    Merge knowing a previously stale provider-bound Teams session can still resume old context after removal.
  3. Pause for retention policy
    Hold the PR if maintainers are not ready to define what transcript data survives an observable Teams uninstall.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Ensure Teams lifecycle rotation replaces matching entries whose updatedAt is already 0 when provider-owned metadata remains, and add focused regression coverage.

Next step before merge

  • [P2] One narrow mechanical P1 repair is suitable for automation before maintainers make the separate transcript-retention decision.

Maintainer decision needed

  • Question: After the stale-entry bypass is repaired, should observable Microsoft Teams app removal preserve transcript artifacts while severing active session context and cached proactive-send linkage?
  • Rationale: The mechanical defect has a clear repair, but code correctness alone cannot choose OpenClaw's post-uninstall transcript-retention policy.
  • Likely owner: steipete — The shared Teams conversation-store refactor and adjacent session-routing work provide the strongest available ownership signal for this retention decision.
  • Options:
    • Retain transcripts, reset linkage (recommended): Rotate every matching session and remove cached Teams conversation references while preserving transcript artifacts.
    • Define deletion semantics first: Pause landing until app removal also specifies transcript deletion, archival, or another explicit retention policy.

Security
Needs attention: The stale provider-bound bypass leaves a concrete privacy-boundary gap in the proposed uninstall reset.

Review findings

  • [P1] Rotate matching sessions even when updatedAt is already zero — extensions/msteams/src/monitor-handler/lifecycle-handler.ts:124-125
Review details

Best possible solution:

Rotate every matching session regardless of its existing timestamp, retain the compare-and-swap protection, add provider-bound zero-timestamp regression coverage, and explicitly approve the non-destructive transcript-retention boundary.

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

Yes. Create a matching Teams session entry with updatedAt: 0 and provider-owned binding metadata, trigger the removal handler, and observe that the PR skips it even though current session resolution still treats it as fresh.

Is this the best way to solve the issue?

No, not yet. Route-derived atomic replacement is the right solution shape and is stronger than the competing stale-only implementation, but it must also rotate zero-timestamp provider-bound entries.

Full review comments:

  • [P1] Rotate matching sessions even when updatedAt is already zero — extensions/msteams/src/monitor-handler/lifecycle-handler.ts:124-125
    Remove this skip or explicitly clear provider-owned bindings for these entries. Current session resolution treats provider-bound entries as fresh without consulting updatedAt, so an entry previously marked stale can retain its old session and context across Teams removal. This was equally visible on the earlier reviewed head and is a late discovery.
    Confidence: 0.98
    Late finding: first raised on code an earlier review cycle already covered.

Overall correctness: patch is incorrect
Overall confidence: 0.97

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 7af7e41eedf4.

Label changes

Label changes:

  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (logs): The supplied live after-fix logs convincingly demonstrate the normal active-session removal path, although they do not cover the stale provider-bound state found in review.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.
  • remove status: 👀 ready for maintainer look: Current PR status label is status: ⏳ waiting on author.

Label justifications:

  • P1: The PR addresses a privacy-sensitive Teams regression, but the same context-retention failure remains reachable for provider-bound sessions already marked stale.
  • merge-risk: 🚨 session-state: Merging as written can leave an old matching Teams session identifier and provider binding reusable after app removal.
  • merge-risk: 🚨 security-boundary: The patch defines whether prior personal-chat context and proactive-send reachability survive a user removing the Teams app.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (logs): The supplied live after-fix logs convincingly demonstrate the normal active-session removal path, although they do not cover the stale provider-bound state found in review.
  • proof: sufficient: Contributor real behavior proof is sufficient. The supplied live after-fix logs convincingly demonstrate the normal active-session removal path, although they do not cover the stale provider-bound state found in review.
Evidence reviewed

PR surface:

Source +423, Tests +575. Total +998 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 5 455 32 +423
Tests 3 575 0 +575
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 8 1030 32 +998

Security concerns:

  • [medium] Provider-bound stale sessions survive removal reset — extensions/msteams/src/monitor-handler/lifecycle-handler.ts:124
    The handler skips matching zero-timestamp entries even though provider-owned metadata can keep those sessions fresh and reusable, allowing pre-removal context to survive.
    Confidence: 0.98

Acceptance criteria:

  • [P1] pnpm test extensions/msteams/src/monitor-handler/lifecycle-handler.test.ts.
  • [P1] pnpm test extensions/msteams/src/monitor-handler/message-handler.authz.test.ts.
  • [P1] pnpm test extensions/msteams.
  • [P1] pnpm run lint:extensions:bundled.
  • [P1] pnpm format:check extensions/msteams/src/monitor-handler/lifecycle-handler.ts extensions/msteams/src/monitor-handler/lifecycle-handler.test.ts.

What I checked:

Likely related people:

  • steipete: Introduced the shared Microsoft Teams conversation-store helper structure and has adjacent current session-routing history relevant to the reset and retention boundary. (role: recent area contributor; confidence: high; commits: 1bf8d69d950d; files: extensions/msteams/src/conversation-store-helpers.ts, extensions/msteams/src/conversation-store.ts, src/agents/command/session.ts)
  • vincentkoc: Recently maintained Microsoft Teams handler tests and conversation-store-adjacent behavior, making them relevant to the focused regression coverage. (role: recent area contributor; confidence: medium; commits: 8c88fb68b772, b53ab34d0478; files: extensions/msteams/src/monitor-handler.adaptive-card.test.ts, extensions/msteams/src/monitor-handler/message-handler.authz.test.ts, extensions/msteams/src/graph-messages.test.ts)
  • sudie-codes: Implemented recent Teams DM/channel target-isolation work and conversation-store helper changes involving a closely related cross-conversation privacy boundary. (role: introduced adjacent behavior; confidence: medium; commits: 1fed7bc3796e; files: extensions/msteams/src/conversation-store-helpers.ts, extensions/msteams/src/send-context.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 (6 earlier review cycles)
  • reviewed 2026-07-05T16:02:27.770Z sha fd1acc9 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-05T16:10:15.978Z sha fd1acc9 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-05T18:12:42.187Z sha 158e595 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-05T18:26:57.044Z sha 158e595 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-06T22:09:12.540Z sha d45522d :: needs maintainer review before merge. :: none
  • reviewed 2026-07-06T23:17:13.958Z sha 78f31a2 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 5, 2026
@jimmypuckett

Copy link
Copy Markdown
Contributor Author

I pushed a follow-up that tightens the implementation and updates the proof packet.

What changed since the first draft:

  • Teams app removal still handles installationUpdate action=remove|remove-upgrade and bot membersRemoved.
  • The reset now rotates the stored session id, sets updatedAt: 0, and clears Teams route/delivery/origin metadata instead of only marking the existing entry stale.
  • Personal installationUpdate action=add now acts as a reinstall boundary only if an active route-matched Teams DM session already exists. First-time installs remain effectively ignored because there is no prior session to rotate.
  • Inbound personal DMs now check for a stored same-user/same-bot conversation reference with a different Teams conversation.id; if Teams exposes that boundary, OpenClaw removes the previous reference and rotates the DM session.

Live app-management removal proof:

baseline:
  synthetic marker sent before Teams app-management removal

remove lifecycle:
  type=installationUpdate action=remove conversationType=personal
  msteams lifecycle remove handled
  reason=installation-remove conversationRemoved=true sessionsReset=1

session state:
  previous active Teams DM session rotated to a new redacted session id
  updatedAt=0
  Teams route/delivery/origin metadata cleared

after re-add:
  Teams welcome card appeared
  verification prompt used a fresh session
  response did not recall the pre-removal marker

Live Remove chat history follow-up:

pre-clear:
  synthetic marker sent and acknowledged

user action:
  Teams Remove chat history
  then user opened the app/chat again and sent a verification prompt

observed:
  no installationUpdate add/remove
  no membersAdded/membersRemoved lifecycle boundary
  no msteams dm conversation boundary handled log
  same OpenClaw session id remained active
  response could recall the pre-clear marker

So this PR intentionally fixes the observable Teams app lifecycle boundaries and changed-conversation-id boundary. It does not claim to fix Teams local Remove chat history when Teams sends only a normal message in the same server-side conversation.

Validation:

pnpm test extensions/msteams/src/monitor-handler/lifecycle-handler.test.ts
  PASS 11 tests

pnpm test extensions/msteams/src/monitor-handler/message-handler.authz.test.ts
  PASS 18 tests

pnpm test extensions/msteams
  PASS 71 files, 1007 tests

pnpm run lint:extensions:bundled
  PASS

pnpm format:check extensions/msteams/src/monitor-handler/lifecycle-handler.ts extensions/msteams/src/monitor-handler/lifecycle-handler.test.ts extensions/msteams/src/monitor-handler/message-handler.ts
  PASS

git diff --check
  PASS

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 5, 2026
@jimmypuckett
jimmypuckett marked this pull request as ready for review July 5, 2026 18:19
@AmirF194

AmirF194 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Reviewed at 158e595. This looks correct and is the stronger of the two lifecycle fixes.

Confirmed the gap on main: extensions/msteams/src/monitor-handler.ts registers no onInstallationUpdate/onMembersRemoved, so a removed-then-re-added app resumes the prior session. Notably, just marking the entry stale (updatedAt: 0) is not enough on its own — src/agents/command/session.ts:389 sets skipImplicitExpiry when hasProviderOwnedSession is true (src/config/sessions/entry-freshness.ts:48), which keeps a provider-owned session "fresh" regardless of updatedAt. This PR's full replaceEntry down to { sessionId, updatedAt: 0 } in rotateMSTeamsSessions (extensions/msteams/src/monitor-handler/lifecycle-handler.ts:731) drops the provider binding and route/origin metadata, so freshness actually fails and the next message starts clean. Deriving the key from the same resolveAgentRoute used to write sessions keeps the reset keyed correctly by construction, and the compare-and-swap in the patchSessionEntry update (lifecycle-handler.ts:739) makes the rotation race-safe. Coverage of personal remove/remove-upgrade, reinstall-add gated on an existing session, channel/group bot removal plus :thread: sessions, and the DM conversation-id boundary all read well and are backed by tests.

Two non-blocking notes:

  1. findStoredPersonalDmConversation (extensions/msteams/src/monitor-handler/lifecycle-handler.ts:791) largely re-implements findPreferredDmConversationByUserId (extensions/msteams/src/conversation-store-helpers.ts:56), already surfaced by the store as findPreferredDmByUserId (extensions/msteams/src/conversation-store-state.ts:190). Reusing that and layering the bot-id check would drop the duplicated personal/user filter + lastSeen sort.
  2. handleMSTeamsDmConversationBoundary runs on every inbound DM and does a full conversationStore.list(), now ahead of the poll-vote/empty-body early returns. Fine for typical volumes, but worth confirming that's acceptable as a per-DM cost, or routing it through the existing preferred-DM lookup.

One process point for maintainers: #100350 targets the same two lifecycle events with a mark-stale-only, personal-DM-only approach and a hardcoded agent:<accountId>:msteams:direct:<userId> key. Merging both would double-register the handlers, and the mark-stale path is defeated by the provider-owned-session case above — so these should not both land.

@jimmypuckett

jimmypuckett commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Maintainer note: these existing PRs were opened from the Spinen organization fork, and I learned that GitHub's normal "allow edits from maintainers" flow may not work reliably for org-owned forks.

For future OpenClaw PRs, I'll open from my personal fork so maintainer edits work normally.

For this existing batch, I want to make collaboration as easy as possible. I've invited @steipete as a temporary Write collaborator on spinen/openclaw in case direct branch edits are useful. I'm also happy to grant temporary access to another specific maintainer, quickly apply/cherry-pick requested changes myself, or support a maintainer takeover PR if that is the fastest path.

My goal is to make these branches easy to finish, not to create extra process.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 10, 2026
@jimmypuckett

Copy link
Copy Markdown
Contributor Author

Superseded by #104690 from my personal fork, using the same published head commit. This move preserves my authorship while enabling maintainer edits and repository automation. Please continue review on #104690; this PR remains available for prior discussion, proof, and CI history.

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

Labels

channel: msteams Channel integration: msteams merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: XL 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.

[Bug]: Teams app removal/re-add retains prior DM session history

2 participants