Skip to content

fix(api): join session summaries via kv.list instead of per-session kv.get fan-out#1101

Open
Codejune wants to merge 1 commit into
rohitg00:mainfrom
Codejune:fix/api-sessions-summaries-fanout
Open

fix(api): join session summaries via kv.list instead of per-session kv.get fan-out#1101
Codejune wants to merge 1 commit into
rohitg00:mainfrom
Codejune:fix/api-sessions-summaries-fanout

Conversation

@Codejune

@Codejune Codejune commented Jul 22, 2026

Copy link
Copy Markdown

Fixes #1100

Problem

api::sessions fires one kv.get(KV.summaries, id) per session inside a single Promise.all. Once the session count grows into the hundreds (615 in my store), the burst of concurrent kv calls is never serviced: the promises neither resolve nor reject (no timeout on kv.get, and .catch only handles rejections), so GET /agentmemory/sessions hangs permanently (HTTP 000 after 180s+) and every attempt parks its in-flight kv invocations on the worker — active_invocations climbs without bound (327 → 1,403 while a dashboard was polling), heap hits ~94%, health goes degraded. Dashboard and agentmemory status then show 0 sessions / 0% token savings.

Full bisection evidence is in #1100 (zero-fanout filter responds in 0.17s, list-only endpoints respond in ~50ms, only the unbounded fan-out deadlocks).

Fix

Fetch summaries with a single kv.list(KV.summaries) and join in memory by sessionId — the same pattern mem::diagnose already uses. One engine roundtrip instead of N.

Verification

  • Patched the identical logic into the bundled dist of a live v0.9.28 install with 615 sessions / 9,525 observations / 114 summaries:
    • /agentmemory/sessions: 0.02–0.08s, HTTP 200, all 114 summaries attached (previously: permanent hang)
    • agentmemory status: Sessions: 615, Observations: 9,526 (previously Sessions: 0)
    • active_invocations stable in single digits while polling the dashboard (previously leaking ~600 per request)
  • npx tsc --noEmit: no new diagnostics in src/triggers/api.ts (the 4 pre-existing ones there are at lines 252/288/2454, untouched)
  • npm test: 1,402 passed / 13 failed — the same 13 environment-dependent tests (embedding-provider key detection, auto-compress env gate, hook-project cwd basename, fs-watcher timing) fail identically on unmodified main in my environment; test/mcp-standalone-proxy.test.ts, the only suite touching /agentmemory/sessions, passes

Summary by CodeRabbit

  • Performance Improvements
    • Improved session summary loading efficiency.
    • Session lists continue to include optional summaries while preserving existing filtering behavior.

…v.get fan-out

api::sessions fired one kv.get(KV.summaries, id) per session inside a
single Promise.all. Once the session count grows into the hundreds the
burst of concurrent kv calls is never serviced, the promises neither
resolve nor reject, and GET /agentmemory/sessions hangs permanently
while each attempt parks its in-flight kv invocations on the worker
(active_invocations climbs without bound, heap exhaustion, degraded
status). The viewer dashboard and CLI status then render 0 sessions
and 0% token savings.

Replace the fan-out with a single kv.list(KV.summaries) and an
in-memory join keyed by sessionId, the same pattern mem::diagnose
already uses.

Fixes rohitg00#1100
Copilot AI review requested due to automatic review settings July 22, 2026 18:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

@Codejune is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

api::sessions now retrieves all session summaries with one kv.list, indexes them by sessionId, and joins matching summaries onto agent-filtered sessions before returning the response.

Changes

Session summary lookup

Layer / File(s) Summary
Bulk summary retrieval and response join
src/triggers/api.ts
The sessions API replaces per-session kv.get calls with one kv.list(KV.summaries) and an in-memory sessionId map. Missing summaries remain omitted from individual session responses.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: copilot, rohitg00, tanmay-008

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed It clearly names the core change: replacing per-session kv.get fan-out with a kv.list-based join.
Linked Issues check ✅ Passed The change replaces the unbounded per-session kv.get fan-out with kv.list plus an in-memory sessionId join, addressing the deadlock.
Out of Scope Changes check ✅ Passed The edit stays within the sessions summary lookup path and doesn't introduce unrelated behavior changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/triggers/api.ts`:
- Around line 858-860: Remove the catch(() => []) fallback from the KV.summaries
read in the summary mapping, so failures from kv.list<SessionSummary> propagate
or are converted into the API’s explicit 5xx error response. Preserve the
existing mapping of successful results to [summary.sessionId, summary] entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71994376-f9a2-4621-af7c-21f9f696b111

📥 Commits

Reviewing files that changed from the base of the PR and between a8e7d19 and e9fb374.

📒 Files selected for processing (1)
  • src/triggers/api.ts

Comment thread src/triggers/api.ts
Comment on lines +858 to 860
(await kv.list<SessionSummary>(KV.summaries).catch(() => [])).map(
(summary): [string, SessionSummary] => [summary.sessionId, summary],
),

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not silently replace summary-store failures with an empty result.

catch(() => []) converts any KV.summaries read failure into a successful response where every session lacks its summary. This silently produces incomplete data and can make dashboards/CLI report incorrect token-savings information. Let the failure propagate or return an explicit 5xx response.

Proposed fix
       const summariesById = new Map(
-        (await kv.list<SessionSummary>(KV.summaries).catch(() => [])).map(
+        (await kv.list<SessionSummary>(KV.summaries)).map(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(await kv.list<SessionSummary>(KV.summaries).catch(() => [])).map(
(summary): [string, SessionSummary] => [summary.sessionId, summary],
),
(await kv.list<SessionSummary>(KV.summaries)).map(
(summary): [string, SessionSummary] => [summary.sessionId, summary],
),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/triggers/api.ts` around lines 858 - 860, Remove the catch(() => [])
fallback from the KV.summaries read in the summary mapping, so failures from
kv.list<SessionSummary> propagate or are converted into the API’s explicit 5xx
error response. Preserve the existing mapping of successful results to
[summary.sessionId, summary] entries.

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

Labels

None yet

Projects

None yet

2 participants