feat(platform): add chat pinning to copilot sidebar#13453
Conversation
Add the ability to pin copilot chats to the top of the sidebar.
Backend:
- New ChatSession.isPinned column (+ migration), mirrors LibraryAgent.isFavorite
- PATCH /sessions/{id}/pinned route + update_session_pinned model/db helpers
- list_sessions orders pinned-first (isPinned desc, updatedAt desc) and
returns is_pinned on each summary
Frontend (behind chat-pinning flag):
- Pin/Unpin action in the chat dropdown menu
- Pin indicator on pinned chat rows
- chat-pinning feature flag + env override
Tests: route + db unit tests, sidebar integration tests, ChatSessionBlock story.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds chat session pinning across storage, API, feature flag, and sidebar UI, including a new pin/unpin endpoint, pinned session ordering, and pinned-state display in the chat sidebar. ChangesChat Session Pinning
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
autogpt_platform/backend/backend/api/features/chat/routes.py (1)
378-438: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winUpdate the
/sessionsordering docs to match the new contract.Line 387 still says this endpoint is ordered by “most recently updated”, but the backing query now sorts pinned sessions first and only uses
updatedAtas the tiebreaker. Leaving that wording in place will make the generated API docs inaccurate for clients.🤖 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 `@autogpt_platform/backend/backend/api/features/chat/routes.py` around lines 378 - 438, Update the list_sessions endpoint documentation so the ordering contract matches the current behavior: the docstring in list_sessions and any related /sessions response docs should no longer say the results are ordered by “most recently updated” alone. Describe the actual ordering used by get_user_sessions, with pinned sessions first and updatedAt only as the tiebreaker, so the generated API docs stay accurate for clients.
🧹 Nitpick comments (2)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx (1)
103-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the standard Orval error extraction in this mutation.
This toast can drop backend-provided detail text for pin/unpin failures. Please mirror the usual Copilot mutation pattern here: prefer
ApiError.response?.detail, thenerror.message, then a generic fallback.Based on learnings, Copilot Orval hook
onErrorhandlers should explicitly handleApiError, prefererror.response?.detail, then fall back toerror.messageand a generic message.🤖 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 `@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx around lines 103 - 118, The onError handler in ChatSidebar’s usePatchV2UpdateSessionPinned mutation is not using the standard Orval error extraction, so backend detail text can be lost. Update the toast logic to handle ApiError explicitly and prefer ApiError.response?.detail first, then fall back to error.message, and finally a generic message; keep the change scoped to the mutation’s onError handler and its toast call.Source: Learnings
autogpt_platform/backend/backend/api/features/chat/routes_test.py (1)
145-197: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse snapshots for these new API response tests.
These cases are validating response payloads for
/sessionsand/sessions/{id}/pinned, but they still hard-code the JSON shape inline. Converting them to snapshot assertions will keep future contract changes likeis_pinnedvisible in one reviewable diff instead of scattered across per-field checks. As per coding guidelines,autogpt_platform/backend/**/*_test.py: “Use pytest with snapshot testing for API responses”.Also applies to: 1291-1314
🤖 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 `@autogpt_platform/backend/backend/api/features/chat/routes_test.py` around lines 145 - 197, The new API response tests in test_update_pinned_success, test_update_pinned_unpin, test_update_pinned_missing_field_rejected, and test_update_pinned_not_found still assert response payloads inline instead of using snapshots. Update these /sessions/{id}/pinned tests to use snapshot assertions for the response bodies (and any validation/error payloads where applicable) so future contract changes are captured consistently in one place.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 `@autogpt_platform/backend/backend/copilot/model.py`:
- Around line 1238-1258: The outer try/except in update_chat_session_pinned is
swallowing unexpected DB/runtime errors and returning False, which the chat
route later interprets as not found or unauthorized. Keep the existing False
return only for the legitimate not-found/ownership path from
chat_db().update_chat_session_pinned, and remove or narrow the broad exception
handling so unexpected failures from update_chat_session_pinned propagate
instead of being converted into a 404. Update the logging around
_get_session_from_cache and cache_chat_session separately if needed, but do not
catch generic exceptions around the main update_chat_session_pinned call.
---
Outside diff comments:
In `@autogpt_platform/backend/backend/api/features/chat/routes.py`:
- Around line 378-438: Update the list_sessions endpoint documentation so the
ordering contract matches the current behavior: the docstring in list_sessions
and any related /sessions response docs should no longer say the results are
ordered by “most recently updated” alone. Describe the actual ordering used by
get_user_sessions, with pinned sessions first and updatedAt only as the
tiebreaker, so the generated API docs stay accurate for clients.
---
Nitpick comments:
In `@autogpt_platform/backend/backend/api/features/chat/routes_test.py`:
- Around line 145-197: The new API response tests in test_update_pinned_success,
test_update_pinned_unpin, test_update_pinned_missing_field_rejected, and
test_update_pinned_not_found still assert response payloads inline instead of
using snapshots. Update these /sessions/{id}/pinned tests to use snapshot
assertions for the response bodies (and any validation/error payloads where
applicable) so future contract changes are captured consistently in one place.
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx:
- Around line 103-118: The onError handler in ChatSidebar’s
usePatchV2UpdateSessionPinned mutation is not using the standard Orval error
extraction, so backend detail text can be lost. Update the toast logic to handle
ApiError explicitly and prefer ApiError.response?.detail first, then fall back
to error.message, and finally a generic message; keep the change scoped to the
mutation’s onError handler and its toast call.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 48526266-0b88-4134-9c70-28e788e7ddd4
📒 Files selected for processing (13)
autogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/api/features/chat/routes_test.pyautogpt_platform/backend/backend/copilot/db.pyautogpt_platform/backend/backend/copilot/db_test.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/sharing/db_test.pyautogpt_platform/backend/migrations/20260630120000_add_chat_session_is_pinned/migration.sqlautogpt_platform/backend/schema.prismaautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSessionBlock/ChatSessionBlock.stories.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSessionBlock/ChatSessionBlock.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/__tests__/ChatSidebar.test.tsxautogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
- Expose update_chat_session_pinned on DatabaseManager(Async)Client so chat_db().update_chat_session_pinned type-checks (pyright) - Regenerate committed openapi.json with the new pinned endpoint so generate:api produces usePatchV2UpdateSessionPinned (fixes FE build/e2e)
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #13453 +/- ##
==========================================
- Coverage 74.71% 74.71% -0.01%
==========================================
Files 2537 2537
Lines 192322 192437 +115
Branches 18928 18935 +7
==========================================
+ Hits 143690 143772 +82
- Misses 44500 44530 +30
- Partials 4132 4135 +3
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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 `@autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts`:
- Line 50: The rollout flag for chat pinning is currently fail-open because
`useGetFlag()` falls back to `defaultFlags[Flag.CHAT_PINNING]`, which turns the
feature on when LaunchDarkly is unavailable or returns no value. Update the flag
handling in `useGetFlag` so `Flag.CHAT_PINNING` defaults to false unless
LaunchDarkly explicitly returns true, preserving the kill switch for the sidebar
UI. Keep the change localized to the `defaultFlags`/fallback logic in
`useGetFlag` and ensure the chat pinning flag is treated as a gated rollout
rather than a safe default-on feature.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 618081de-1fdb-4cd7-811e-272f174f6278
📒 Files selected for processing (1)
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (10)
- GitHub Check: integration_test
- GitHub Check: check API types
- GitHub Check: Analyze (python)
- GitHub Check: end-to-end tests
- GitHub Check: Check PR Status
- GitHub Check: test (3.12)
- GitHub Check: type-check (3.12)
- GitHub Check: test (3.13)
- GitHub Check: test (3.11)
- GitHub Check: type-check (3.11)
⚠️ CI failures not shown inline (2)
GitHub Actions: PR Overlap Detection / 0_check-overlaps.txt: feat(platform): add chat pinning to copilot sidebar
Conclusion: failure
##[group]Run python .github/scripts/detect_overlaps.py 13453
�[36;1mpython .github/scripts/detect_overlaps.py 13453�[0m
shell: /usr/bin/bash -e {0}
env:
pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
GH_***REDACTED***
##[endgroup]
Warning: PR `#13330` has >100 files, overlap detection may be incomplete
Warning: PR `#13433` has >100 files, overlap detection may be incomplete
Warning: PR `#12653` has >100 files, overlap detection may be incomplete
Warning: PR `#13429` has >100 files, overlap detection may be incomplete
Warning: PR `#12206` has >100 files, overlap detection may be incomplete
Warning: PR `#12669` has >100 files, overlap detection may be incomplete
Error running gh pr diff 13429: could not find pull request diff: HTTP 406: Sorry, the diff exceeded the maximum number of files (300). Consider using 'List pull requests files' API or locally cloning the repository instead. (https://api.github.com/repos/Significant-Gravitas/AutoGPT/pulls/13429)
PullRequest.diff too_large
Checking PR `#13453` in Significant-Gravitas/AutoGPT
PR `#13453`: feat(platform): add chat pinning to copilot sidebar
Base branch: dev
Files changed: 15
Found 170 other open PRs targeting dev
Found 15 PRs with file overlap (excluding ignored files)
##[error]Process completed with exit code 1.
GitHub Actions: PR Overlap Detection / check-overlaps: feat(platform): add chat pinning to copilot sidebar
Conclusion: failure
##[group]Run python .github/scripts/detect_overlaps.py 13453
�[36;1mpython .github/scripts/detect_overlaps.py 13453�[0m
shell: /usr/bin/bash -e {0}
env:
pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
GH_***REDACTED***
##[endgroup]
Warning: PR `#13330` has >100 files, overlap detection may be incomplete
Warning: PR `#13433` has >100 files, overlap detection may be incomplete
Warning: PR `#12653` has >100 files, overlap detection may be incomplete
Warning: PR `#13429` has >100 files, overlap detection may be incomplete
Warning: PR `#12206` has >100 files, overlap detection may be incomplete
Warning: PR `#12669` has >100 files, overlap detection may be incomplete
Error running gh pr diff 13429: could not find pull request diff: HTTP 406: Sorry, the diff exceeded the maximum number of files (300). Consider using 'List pull requests files' API or locally cloning the repository instead. (https://api.github.com/repos/Significant-Gravitas/AutoGPT/pulls/13429)
PullRequest.diff too_large
Checking PR `#13453` in Significant-Gravitas/AutoGPT
PR `#13453`: feat(platform): add chat pinning to copilot sidebar
Base branch: dev
Files changed: 15
Found 170 other open PRs targeting dev
Found 15 PRs with file overlap (excluding ignored files)
##[error]Process completed with exit code 1.
🧰 Additional context used
📓 Path-based instructions (8)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend developmentFormat frontend code using
pnpm format
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Fully capitalize acronyms in symbols, e.g.graphID,useBackendAPI
No linter suppressors (//@ts-ignore``,// eslint-disable) — fix the actual issue
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
autogpt_platform/frontend/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/__generated__/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
autogpt_platform/frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development
autogpt_platform/frontend/**/*.{ts,tsx}: Use function declarations (not arrow functions) for components/handlers
Noanytypes unless the value genuinely can be anything
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
autogpt_platform/frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
autogpt_platform/frontend/src/**/*.{ts,tsx}: Use generated API hooks from@/app/api/__generated__/endpoints/following the patternuse{Method}{Version}{OperationName}, and regenerate withpnpm generate:api
Separate render logic from business logic using component.tsx + useComponent.ts + helpers.ts pattern, colocate state when possible and avoid creating large components, use sub-components in local/componentsfolder
Use function declarations for components and handlers, use arrow functions only for callbacks
Do not useuseCallbackoruseMemounless asked to optimise a given function
autogpt_platform/frontend/src/**/*.{ts,tsx}: Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}
Always import the-Icon-suffixed alias from@phosphor-icons/react(e.g.TrashIcon,PlusIcon,SquareIcon) — bare exports are deprecated
Do not useuseCallbackoruseMemounless asked to optimize a given function
Never usesrc/components/__legacy__/*— use design system components fromsrc/components/
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
autogpt_platform/frontend/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
No barrel files or
index.tsre-exports in the frontend
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
autogpt_platform/frontend/src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not type hook returns, let Typescript infer as much as possible
autogpt_platform/frontend/src/**/*.ts: Extract component logic into custom hooks grouped by concern, not by component, with each hook in its own.tsfile
Do not type hook returns; let TypeScript infer as much as possible
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
autogpt_platform/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never type with
any, if no types available useunknown
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
autogpt_platform/frontend/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Avoid index and barrel files
Files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
🧠 Learnings (3)
📚 Learning: 2026-04-01T18:54:16.035Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 12633
File: autogpt_platform/frontend/src/app/(platform)/library/components/AgentFilterMenu/AgentFilterMenu.tsx:3-10
Timestamp: 2026-04-01T18:54:16.035Z
Learning: In the frontend, the legacy Select component at `@/components/__legacy__/ui/select` is an intentional, codebase-wide visual-consistency pattern. During code reviews, do not flag or block PRs merely for continuing to use this legacy Select. If a migration to the newer design-system Select is desired, bundle it into a single dedicated cleanup/migration PR that updates all Select usages together (e.g., avoid piecemeal replacements).
Applied to files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
📚 Learning: 2026-04-07T09:24:16.582Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12686
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/__tests__/PainPointsStep.test.tsx:1-19
Timestamp: 2026-04-07T09:24:16.582Z
Learning: In Significant-Gravitas/AutoGPT’s `autogpt_platform/frontend` (Vite + `vitejs/plugin-react` with the automatic JSX transform), do not flag usages of React types/components (e.g., `React.ReactNode`) in `.ts`/`.tsx` files as missing `React` imports. Since the React namespace is made available by the project’s TS/Vite setup, an explicit `import React from 'react'` or `import type { ReactNode } ...` is not required; only treat it as missing if typechecking (e.g., `pnpm types`) would actually fail.
Applied to files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
📚 Learning: 2026-04-02T05:43:49.128Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12640
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/WelcomeStep.tsx:13-13
Timestamp: 2026-04-02T05:43:49.128Z
Learning: Do not flag `import { Question } from "phosphor-icons/react"` as an invalid import. `Question` is a valid named export from `phosphor-icons/react` (as reflected in the package’s generated `.d.ts` files and re-exports via `dist/index.d.ts`), so it should be treated as a supported named export during code reviews.
Applied to files:
autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts
- model.py: let unexpected DB errors in update_session_pinned propagate (only return False for real not-found/wrong-user) so the route returns 5xx instead of masking failures as 404 - routes.py: correct list_sessions docstring — pinned-first, updatedAt tiebreaker - ChatSidebar: use standard Orval ApiError.response?.detail extraction in the pin/unpin onError toast
|
@coderabbitai addressed your review in 87f3e9a:
|
|
Tip For best results, initiate chat on the files or code changes.
The 🐇✨ If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
A pin written out-of-band by update_session_pinned could be reverted in the Redis cache when an end-of-stream upsert wrote a stale in-memory session (is_pinned=False). Mirror the existing cached-title preservation in upsert_chat_session so is_pinned is taken from the cache too. Adds a regression test.
|
!deploy |
|
🚀 Deploying PR #13453 to development environment... |
|
✅ Preview Environment Deployed Successfully 📊 Deployment Summary
🔔 Please check Discord for the preview environment URLs and details. The deployment status and URLs will be posted in the AutoGPT Discord server. |
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
Why / What / How
Why: Users want to keep important copilot chats accessible instead of losing them as the recency-sorted sidebar list grows. This is the small, separable "pin chats" win flagged in the sidebar/projects discussion — low overlap with the larger agent-personas/projects work, so it can ship independently and behind a flag.
What: Adds the ability to pin/unpin a copilot chat. Pinned chats surface at the top of the sidebar regardless of recency. The UI is gated behind a new
chat-pinningLaunchDarkly flag so we can roll it out incrementally (and bundle it with the other sidebar UI updates).How:
ChatSession.isPinnedboolean column (mirrors the existingLibraryAgent.isFavoritepattern) so the list query can order pinned-first at the DB level rather than per-page in memory.list_sessionsorders by(isPinned desc, updatedAt desc)and returnsis_pinnedon each summary.PATCH /sessions/{id}/pinnedroute toggles the flag (owner-scoped, mirrors the title-update path including the Redis cache update). Pinning does not bumpupdatedAtso it doesn't reorder within its bucket.Screen.Recording.2026-06-30.at.4.29.07.PM.mov
Changes 🏗️
Backend
schema.prisma: addChatSession.isPinned Boolean @default(false)+ migration20260630120000_add_chat_session_is_pinned.copilot/model.py:ChatSessionInfo.is_pinned, populate infrom_db, newupdate_session_pinned()(DB + cache).copilot/db.py:update_chat_session_pinned();get_user_chat_sessionsnow orders pinned-first.api/features/chat/routes.py:UpdateSessionPinnedRequest,PATCH /sessions/{id}/pinned,is_pinnedonSessionSummaryResponse.Frontend (all behind
Flag.CHAT_PINNING)use-get-flag.ts: newchat-pinningflag + env override.ChatSidebar: Pin/Unpin dropdown action wired to the new mutation.ChatSessionBlock: pin indicator on pinned rows (+ Storybook story).Tests
list_sessionsreturnsis_pinned, db helper + ordering tests.Checklist 📋
For code changes:
routes_test.py96 passed,db_test.pyincl. new pin/ordering tests)pnpm generate:apithenpnpm test:unitfor the sidebar integration testschat-pinningflag, pin a chat → it jumps to the top with a pin icon; unpin → returns to recency orderFor configuration changes:
.env.defaultis updated or already compatible with my changesdocker-compose.ymlis updated or already compatible with my changes