fix(agent-sdk): add session timeout to ActionWizard to prevent memory leaks#1767
fix(agent-sdk): add session timeout to ActionWizard to prevent memory leaks#1767
Conversation
… leaks Sessions in ActionWizard are stored in a Map and only removed on explicit cancel or completion. If a user abandons a wizard mid-flow (closes the app, loses network, or stops responding), the session entry persists in memory indefinitely. For long-running agents with many users, this causes unbounded memory growth proportional to the abandonment rate. This adds lazy session expiration: when a message arrives for a session older than sessionTimeoutMs (default: 30 minutes), the session is expired and the cancel handler is called. This avoids background timers while still preventing accumulation of orphaned sessions.
🦋 Changeset detectedLatest commit: 7166864 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@mvanhorn is attempting to deploy a commit to the XMTP Labs Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
🟡 Medium
The sessionTimeoutMs option is documented as an idle timeout, but createdAt is set only at session start and never updated. Sessions that take longer than the timeout to complete are expired even when the user is actively responding. To match the documented behavior, update createdAt (or add lastActivityAt) in #advance() whenever the user provides input.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file sdks/agent-sdk/src/middleware/ActionWizard.ts around line 197:
The `sessionTimeoutMs` option is documented as an idle timeout, but `createdAt` is set only at session start and never updated. Sessions that take longer than the timeout to complete are expired even when the user is actively responding. To match the documented behavior, update `createdAt` (or add `lastActivityAt`) in `#advance()` whenever the user provides input.
Evidence trail:
sdks/agent-sdk/src/middleware/ActionWizard.ts:
- Line 62: Documentation says `sessionTimeoutMs` is for 'idle' timeout
- Lines 137-143: `createdAt` set only in `start()` method
- Lines 185-199: `#advance()` method does not update `createdAt` or any activity timestamp
- Lines 215-219: Timeout check uses `session.createdAt` to determine expiration
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. While this is a straightforward bug fix adding session timeout to prevent memory leaks, the author does not own any of the modified files. Both files are owned by other teams (@xmtp/documentation and @xmtp/protocol-sdk), so designated code owners should review these changes. You can customize Macroscope's approvability policy. Learn more. |
Track lastActivityAt on each user response so the session timeout measures idle time, not total elapsed time. Sessions with active users no longer expire prematurely.
|
Fixed in 7166864: timeout now tracks |
Summary
Adds lazy session expiration to
ActionWizardso abandoned sessions don't accumulate in memory indefinitely.Why this matters
ActionWizardstores user sessions in aMap(#sessions,ActionWizard.ts:83). Sessions are created instart()(L149-156) and only deleted via explicit cancel (#handleCancel, L193) or wizard completion (#advance, L209). If a user abandons a wizard mid-flow - closes the app, loses network, or stops responding - the session entry persists forever.For a long-running agent serving 100 users/day with a 10% abandonment rate, that's ~10 orphaned sessions/day, ~300/month, growing without bound.
Changes
createdAttimestamp toActionWizardSession(set instart())sessionTimeoutMsoption toActionWizardOptions(default: 30 minutes)middleware(): when a message arrives for a session older than the timeout, the session is expired via the existing#handleCancelpath, then control passes tonext()The lazy approach avoids adding a background
setInterval, which would complicate agent lifecycle management and require explicit cleanup on shutdown. Sessions are checked and cleaned only when a message arrives for that conversation+sender pair.Testing
yarn format:checkpassesyarn typecheckpassesThis contribution was developed with AI assistance (Claude Code). I have reviewed all changes and can discuss implementation decisions.
Related: PR #1743 - original ActionWizard middleware by @bennycode
Note
Add session timeout to
ActionWizardto prevent memory leaks from abandoned sessionssessionTimeoutMsoption toActionWizardOptions, defaulting to 30 minutes, controlling the maximum idle time before a session is auto-expired.createdAtandlastActivityAttimestamps;lastActivityAtis refreshed on each wizard step advance.#handleCancelon sessions that have exceeded the timeout.Macroscope summarized 7166864.