Skip to content

fix: paginate thread history when forking and loading sessions - #481

Merged
nikita-ashihmin merged 4 commits into
mainfrom
nikita.ashikhmin/fix-fork-history-pagination
Sep 6, 2026
Merged

fix: paginate thread history when forking and loading sessions#481
nikita-ashihmin merged 4 commits into
mainfrom
nikita.ashikhmin/fix-fork-history-pagination

Conversation

@nikita-ashihmin

@nikita-ashihmin nikita-ashihmin commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Forking and loading paginated threads emitted repeated “Full-history hydration is deprecated” warnings because the adapter requested complete history through thread/read, thread/fork, and thread/resume.

Load history through descending thread/turns/list pages with itemsView: "full", then reverse the turns for chronological replay. Paginated session loads use the resume response's turnsBackwardsCursor as the upper boundary; a null resume cursor means empty durable history. Standalone reads and AIR fork-point resolution start at the newest page so newly appended turns do not enter subsequent pages. Legacy histories use thread/read(includeTurns: true) instead of pagination, avoiding repeated rollout reconstruction and dependence on the paging API. Repeated or cyclic cursors fail explicitly.

Use excludeTurns: true for session resume, session fork, and temporary audit forks. Preserve complete items, their order within each turn, and AIR fork-point matching across pages.

Validation:

  • npm run typecheck and npm run build passed.
  • npm test: 552 passed, 26 skipped.
  • Regression coverage includes multi-page ordering, full items, empty history, later-page failures, repeated/cyclic cursors including the initial boundary, duplicate fingerprints, legacy loading without a pagination API, null resume boundaries, and turns appended during history loading.
  • Real app-server read, fork, and load passed: paginated load used a non-null resume cursor with descending requests, preserved saved items, and emitted no hydration warnings. The check used a saved failed turn because the configured model requires a newer Codex version for generation.

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.

🟡 Changes recommended

Cursor-cycle detection is required to prevent malformed pagination responses from causing an infinite loop.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds cursor-based thread-history pagination while preserving replay and fork-point matching.

Changes:

  • Loads full turns chronologically via paginated thread/turns/list.
  • Excludes turns from resume, fork, and audit-fork responses.
  • Adds pagination, failure, and fingerprint-matching tests.
File summaries
File Description
src/SessionFork.ts Resolves fork points from paginated history.
src/CodexAppServerClient.ts Implements pagination, but repeated or cyclic cursors can cause an infinite request loop.
src/CodexAcpClient.ts Uses metadata-only resume and fork responses.
src/__tests__/CodexACPAgent/thread-history.test.ts Tests pagination and failure handling.
src/__tests__/CodexACPAgent/load-session.test.ts Updates session-loading mocks and assertions.
src/__tests__/CodexACPAgent/data/paginated-thread-history.json Provides expected paginated-history data.
src/__tests__/CodexACPAgent/CodexAcpClient.test.ts Tests resume, fork, and fingerprint behavior.
src/__tests__/CodexACPAgent/agent-file-change-report.test.ts Verifies metadata-only audit forks.
Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +587 to +599
const turns: ThreadReadResponse["thread"]["turns"] = [];
let cursor: string | null = null;
do {
const page = await this.threadTurnsList({
threadId,
cursor,
limit: 50,
sortDirection: "asc",
itemsView: "full",
});
turns.push(...page.data);
cursor = page.nextCursor;
} while (cursor !== null);

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.

🟡 Changes recommended

Two moderate issues prevent history pagination from providing a consistent snapshot.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread src/CodexAcpClient.ts Outdated
threadId: response.thread.id,
includeTurns: true,
});
const historyResponse = await this.codexClient.threadReadWithHistory(response.thread.id);
Comment thread src/CodexAppServerClient.ts Outdated
threadId,
cursor,
limit: 50,
sortDirection: "asc",

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.

🟡 Changes recommended

Legacy session history must retain its required full-read path before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment on lines +585 to +589
async threadReadWithHistory(threadId: string): Promise<ThreadReadResponse> {
const response = await this.threadRead({threadId});
const turns = await this.threadReadHistory(threadId);
return {...response, thread: {...response.thread, turns}};
}

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.

🟢 Approval recommended

The reviewed changes have comprehensive regression coverage and no unresolved issues.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@nikita-ashihmin
nikita-ashihmin merged commit 1a3c01e into main Sep 6, 2026
7 checks passed
@nikita-ashihmin
nikita-ashihmin deleted the nikita.ashikhmin/fix-fork-history-pagination branch September 6, 2026 09:17
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.

2 participants