Skip to content

fix(api): honour limit query param on /sessions and /replay/sessions (#1022)#1034

Open
ziishanahmad wants to merge 2 commits into
rohitg00:mainfrom
ziishanahmad:fix/1022-sessions-limit-v2
Open

fix(api): honour limit query param on /sessions and /replay/sessions (#1022)#1034
ziishanahmad wants to merge 2 commits into
rohitg00:mainfrom
ziishanahmad:fix/1022-sessions-limit-v2

Conversation

@ziishanahmad

@ziishanahmad ziishanahmad commented Jul 9, 2026

Copy link
Copy Markdown

What

The HTTP endpoints GET /agentmemory/sessions and GET /agentmemory/replay/sessions were returning the full session table on every call, ignoring any ?limit=N query parameter. The MCP tool memory_sessions already supports limit (added in #139) but the HTTP twins did not.

Why

The real-time viewer and CLI both want to page through sessions without forcing the engine to ship every record on every request. Returning the full table is wasteful for projects with thousands of sessions and the existing MCP tool already does the right thing — the HTTP path was the gap.

How

  • api::sessions (src/triggers/api.ts) now reads ?limit=N and slices the response. Negative or non-numeric values fall back to the full list so a bad query never produces an empty result.
  • api::replay::sessions (same file) gets the same treatment. The replay endpoint had the same gap.

Tests

Added test/sessions-limit.test.ts with 4 source-level assertions (matches the style of test/memories-pagination.test.ts). Full suite: 1374/1419 pass (45 pre-existing Windows HOME/USERPROPLACE failures in upstream on Win, unrelated to this change).

Notes

Diff is rebased on clean upstream main — only 2 files changed (src/triggers/api.ts + test/sessions-limit.test.ts), 75 lines. No rebrand churn.

Signed-off-by: Zeeshan Ahmad ziishanahmad@gmail.com

Summary by CodeRabbit

  • New Features

    • Added optional limit support to session listing endpoints, so clients can request only the first N sessions when a valid value is provided.
    • Implemented the same limit behavior for replay session listings to improve result manageability.
  • Bug Fixes

    • When limit is missing, invalid, or non-positive, endpoints now safely return the full filtered session list instead of applying an incorrect or partial slice.

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

@ziishanahmad 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 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds support for a limit query parameter to api::sessions and api::replay::sessions in src/triggers/api.ts, returning only the first valid positive slice when provided and the full sorted or filtered list otherwise. Adds source-level tests covering both endpoint paths.

Changes

Sessions limit query parameter

Layer / File(s) Summary
Limit query param handling in session endpoints
src/triggers/api.ts
Adds parsePositiveLimit and uses it in both api::sessions and api::replay::sessions so valid positive limit values slice the session list, while missing, invalid, or non-positive values return the full list.
Tests validating limit slicing and fallback behavior
test/sessions-limit.test.ts
Adds Vitest source-regex assertions for both endpoints, plus coverage for the helper signature and its delegation to parseOptionalInt.

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

Possibly related issues

🚥 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 The title clearly states the main change: adding limit query-param support to the sessions and replay sessions endpoints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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

🧹 Nitpick comments (4)
src/triggers/api.ts (3)

505-519: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract a shared limit-parsing helper to eliminate duplication.

The limit parsing logic (rawLimitparseIntNumber.isFinite → slice-or-full) is duplicated verbatim across both endpoints. The file already uses parseOptionalInt elsewhere (e.g., line 800 for api::commits). A small helper like parsePositiveLimit(raw: string | undefined): number | undefined would centralize the validation and keep the two endpoints consistent.

♻️ Proposed helper extraction
+// e.g. in a shared utils section:
+function parsePositiveLimit(raw: string | undefined): number | undefined {
+  if (typeof raw !== "string" || raw.length === 0) return undefined;
+  const n = parseInt(raw, 10);
+  return Number.isFinite(n) && n > 0 ? n : undefined;
+}
+
 // Then in each handler:
-const rawLimit = req.query_params?.["limit"];
-const parsedLimit =
-  typeof rawLimit === "string" && rawLimit.length > 0
-    ? parseInt(rawLimit, 10)
-    : NaN;
-const limited =
-  Number.isFinite(parsedLimit) && parsedLimit > 0
-    ? sessions.slice(0, parsedLimit)
-    : sessions;
+const limit = parsePositiveLimit(req.query_params?.["limit"]);
+const limited = limit !== undefined ? sessions.slice(0, limit) : sessions;

Also applies to: 848-861

🤖 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 505 - 519, The replay list endpoint
duplicates the same limit parsing and slicing logic used elsewhere in this
module, so extract a shared helper to keep both endpoints consistent. Add a
small helper near the existing parseOptionalInt usage, such as a positive-limit
parser, and update the replay handler and the api::commits path to use it
instead of repeating rawLimit/parsing/slice logic in each endpoint. Keep the
behavior identical for valid positive limits and fallback to the full sessions
list when no usable limit is provided.

505-509: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Trim WHAT-explaining comments per coding guidelines.

The coding guidelines for src/**/*.ts state: "avoid code comments explaining WHAT — use clear naming instead." The multi-line comments here describe what the code does ("Honour ?limit=N (>=1)...") alongside the rationale. Consider trimming to just the WHY (issue reference + motivation) and letting the code speak for itself.

Also applies to: 848-851

🤖 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 505 - 509, Trim the WHAT-explaining inline
comments around the replay list limit handling in the API trigger code and keep
only the WHY. In the area around the replay endpoint logic in
`src/triggers/api.ts` (and the matching comment block elsewhere noted in the
review), remove descriptions of what the `limit` behavior does and retain only
the motivation/reference to the related issue or fix so the code itself explains
the behavior.

Source: Coding guidelines


840-861: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Slice before summary lookups to avoid unnecessary I/O when limit is set.

api::sessions fetches summaries via Promise.all for every filtered session (lines 840–844) and only slices afterward (line 859). When ?limit=N is provided, this still performs N_total kv.get calls instead of N. Applying the slice to filtered before the summary lookup would eliminate the wasted I/O. Note that api::sessions does not sort by startedAt (unlike api::replay::sessions), so the first N sessions are in kv.list order — consider whether that ordering is intentional for paginated results.

🤖 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 840 - 861, The `api::sessions` handler is
doing summary fetches for every item in `filtered` before applying `limit`, so
`Promise.all` still triggers unnecessary `kv.get` I/O when `?limit=N` is set.
Update the `api::sessions` flow to compute `parsedLimit`/`limited` earlier and
slice `filtered` before the `Promise.all` summary lookup, using the
`withSummary`/`limited` logic in `src/triggers/api.ts` to keep only the
requested number of sessions. Also confirm the resulting pagination order is
intentional since `api::sessions` relies on `kv.list` order rather than sorting
like `api::replay::sessions`.
test/sessions-limit.test.ts (1)

1-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Source-level regex assertions are fragile — prefer behavioral tests.

These tests verify that the source code contains specific string patterns (query_params?.["limit"], slice(0, parsedLimit)) rather than testing actual endpoint behavior. A variable rename or refactor would break the tests even if behavior is correct, and a buggy implementation that happens to contain the right patterns would pass. The comment acknowledges this tradeoff, but consider adding a behavioral test that mocks sdk/kv and asserts the sliced response shape, following the patterns in test/crystallize.test.ts.

🤖 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 `@test/sessions-limit.test.ts` around lines 1 - 46, The current assertions in
sessions-limit.test.ts are source-level regex checks against
src/triggers/api.ts, which makes the test brittle and unable to verify real
behavior. Add a behavioral test like the ones in test/crystallize.test.ts by
mocking sdk/kv and exercising the api::sessions and api::replay::sessions
handlers so you can assert the returned list is sliced when limit is valid and
remains full when limit is missing or invalid. Keep the existing source checks
only if needed as a supplement, but move the main coverage to runtime behavior
around sdk.registerFunction and the sessions/replay session handlers.

Source: Coding guidelines

🤖 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 `@test/sessions-limit.test.ts`:
- Around line 38-45: The api::replay::sessions test only checks limit parsing
and slicing, but it is missing the fallback coverage that api::sessions already
verifies. In test/sessions-limit.test.ts, extend the api::replay::sessions spec
to assert the same parsedLimit > 0 fallback behavior by matching the replay
endpoint’s handling in api and confirming it returns the full sessions list when
the limit is invalid. Keep the new assertion рядом with the existing
sdk.registerFunction checks so the companion fix stays aligned with the
api::replay::sessions symbol.

---

Nitpick comments:
In `@src/triggers/api.ts`:
- Around line 505-519: The replay list endpoint duplicates the same limit
parsing and slicing logic used elsewhere in this module, so extract a shared
helper to keep both endpoints consistent. Add a small helper near the existing
parseOptionalInt usage, such as a positive-limit parser, and update the replay
handler and the api::commits path to use it instead of repeating
rawLimit/parsing/slice logic in each endpoint. Keep the behavior identical for
valid positive limits and fallback to the full sessions list when no usable
limit is provided.
- Around line 505-509: Trim the WHAT-explaining inline comments around the
replay list limit handling in the API trigger code and keep only the WHY. In the
area around the replay endpoint logic in `src/triggers/api.ts` (and the matching
comment block elsewhere noted in the review), remove descriptions of what the
`limit` behavior does and retain only the motivation/reference to the related
issue or fix so the code itself explains the behavior.
- Around line 840-861: The `api::sessions` handler is doing summary fetches for
every item in `filtered` before applying `limit`, so `Promise.all` still
triggers unnecessary `kv.get` I/O when `?limit=N` is set. Update the
`api::sessions` flow to compute `parsedLimit`/`limited` earlier and slice
`filtered` before the `Promise.all` summary lookup, using the
`withSummary`/`limited` logic in `src/triggers/api.ts` to keep only the
requested number of sessions. Also confirm the resulting pagination order is
intentional since `api::sessions` relies on `kv.list` order rather than sorting
like `api::replay::sessions`.

In `@test/sessions-limit.test.ts`:
- Around line 1-46: The current assertions in sessions-limit.test.ts are
source-level regex checks against src/triggers/api.ts, which makes the test
brittle and unable to verify real behavior. Add a behavioral test like the ones
in test/crystallize.test.ts by mocking sdk/kv and exercising the api::sessions
and api::replay::sessions handlers so you can assert the returned list is sliced
when limit is valid and remains full when limit is missing or invalid. Keep the
existing source checks only if needed as a supplement, but move the main
coverage to runtime behavior around sdk.registerFunction and the sessions/replay
session handlers.
🪄 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: 4b522fdd-34ba-4bac-93fc-36dbb534f48a

📥 Commits

Reviewing files that changed from the base of the PR and between 93ae9bc and 4e2303e.

📒 Files selected for processing (2)
  • src/triggers/api.ts
  • test/sessions-limit.test.ts

Comment thread test/sessions-limit.test.ts
…ddress review feedback (rohitg00#1022)

Signed-off-by: Zeeshan Ahmad <ziishanahmad@gmail.com>

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

🧹 Nitpick comments (1)
test/sessions-limit.test.ts (1)

1-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mirror the behavioral test pattern used in test/crystallize.test.ts.

This file asserts against src/triggers/api.ts directly; the existing suite uses runtime tests with mockSdk(), mockKV(), and sdk.trigger(...). Rewriting this to exercise the endpoint with mocked iii-sdk would make it less fragile and consistent with the rest of the tests.

🤖 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 `@test/sessions-limit.test.ts` around lines 1 - 14, The current sessions limit
test is a source-level assertion against src/triggers/api.ts, but it should
follow the runtime pattern used in crystallize.test.ts. Rework the test to
exercise the endpoint through mocked iii-sdk behavior using mockSdk(), mockKV(),
and sdk.trigger(...), so the GET /agentmemory/sessions and GET
/agentmemory/replay/sessions limit handling is validated behaviorally instead of
by reading source text.

Sources: Coding guidelines, Learnings

🤖 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.

Nitpick comments:
In `@test/sessions-limit.test.ts`:
- Around line 1-14: The current sessions limit test is a source-level assertion
against src/triggers/api.ts, but it should follow the runtime pattern used in
crystallize.test.ts. Rework the test to exercise the endpoint through mocked
iii-sdk behavior using mockSdk(), mockKV(), and sdk.trigger(...), so the GET
/agentmemory/sessions and GET /agentmemory/replay/sessions limit handling is
validated behaviorally instead of by reading source text.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a583f1f4-23f5-4140-b337-d1ed8d0b4fec

📥 Commits

Reviewing files that changed from the base of the PR and between 4e2303e and 020f897.

📒 Files selected for processing (2)
  • src/triggers/api.ts
  • test/sessions-limit.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/triggers/api.ts

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant