Repository navigation
Conversation
There was a problem hiding this comment.
Hey - I've found 4 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="astrbot/core/db/__init__.py" line_range="971-987" />
<code_context>
...
+ @abc.abstractmethod
+ async def get_project_sessions_paginated(
+ self,
+ project_id: str,
+ page: int = 1,
+ page_size: int = 100,
+ ) -> tuple[list[PlatformSession], int]:
+ """Get a page of project sessions and its total count.
+
+ Args:
+ project_id: Project whose sessions should be listed.
+ page: One-based page number.
+ page_size: Maximum number of sessions to return.
+
+ Returns:
+ The requested sessions and total number of sessions in the project.
+ """
+ ...
+
@abc.abstractmethod
</code_context>
<issue_to_address>
**Existing adapters cannot instantiate**
When an external adapter implements the old abstract interface, `BaseDatabase` still marks the new method abstract, so the adapter remains abstract and construction raises `TypeError` before pagination can run.
Provide a concrete backward-compatible implementation or otherwise avoid making this method a required abstract method.
</issue_to_address>
### Comment 2
<location path="dashboard/src/components/chat/ProjectList.vue" line_range="257-263" />
<code_context>
if (
!container ||
container.clientHeight === 0 ||
</code_context>
<issue_to_address>
**Visible projects load prematurely**
When an expanded project list is visible but ends more than 120px above the sidebar viewport bottom, `loadMoreSessions` treats a negative `listBottom - bottom` as within the 120px threshold, so scrolling loads another page for expanded project lists that have already ended well above the viewport bottom. The pagination watcher repeats this as pages finish, causing unnecessary requests and loading sessions before users approach those lists.
Require the list bottom to be within the intended near-bottom range, such as `listBottom >= bottom - 120`, as well as no more than 120px below it.
</issue_to_address>
### Comment 3
<location path="astrbot/core/db/sqlite.py" line_range="2517" />
<code_context>
== col(SessionProjectRelation.session_id),
)
.where(col(SessionProjectRelation.project_id) == project_id)
- .order_by(desc(PlatformSession.updated_at))
+ )
</code_context>
<issue_to_address>
**Project pagination scans every relation**
When the database contains many session-project relations, `get_project_sessions_paginated` filters `session_project_relations` by `project_id` and runs both a count and a page query on each request, but the relation table has only a unique index on `session_id`. As the relation table grows, scrolling through project sessions repeatedly scans it, making pagination increasingly slow.
Add an index on `SessionProjectRelation.project_id` so the count and page queries can locate a project's relations without scanning the whole table.
</issue_to_address>
### Comment 4
<location path="dashboard/src/api/v1.ts" line_range="942" />
<code_context>
);
},
- listProjectSessions(projectId: string) {
+ listProjectSessions(projectId: string, params?: { page: number; page_size: number }) {
return typed<any>(
- openApiV1.listChatProjectSessions({ path: { project_id: projectId } }),
</code_context>
<issue_to_address>
**Valid pagination queries rejected by types**
When a typed caller wants to set only `page` or only `page_size`, `listProjectSessions` requires both `page` and `page_size` whenever `params` is supplied, so typed consumers cannot request either parameter alone even though the HTTP endpoint accepts either one; TypeScript reports a compile-time error for those valid requests.
Make both properties optional in the wrapper parameter type.
</issue_to_address>Sourcery assessment
Approval pending. 4 findings to address first.
Blocking findings: astrbot/core/db/__init__.py:987, dashboard/src/components/chat/ProjectList.vue:263, astrbot/core/db/sqlite.py:2517, dashboard/src/api/v1.ts:942
| async def get_project_sessions_paginated( | ||
| self, | ||
| project_id: str, | ||
| page: int = 1, | ||
| page_size: int = 100, | ||
| ) -> tuple[list[PlatformSession], int]: | ||
| """Get a page of project sessions and its total count. | ||
|
|
||
| Args: | ||
| project_id: Project whose sessions should be listed. | ||
| page: One-based page number. | ||
| page_size: Maximum number of sessions to return. | ||
|
|
||
| Returns: | ||
| The requested sessions and total number of sessions in the project. | ||
| """ | ||
| ... |
There was a problem hiding this comment.
🟡 Medium · Existing adapters cannot instantiate
When an external adapter implements the old abstract interface, BaseDatabase still marks the new method abstract, so the adapter remains abstract and construction raises TypeError before pagination can run.
Provide a concrete backward-compatible implementation or otherwise avoid making this method a required abstract method.
Prompt for AI agents
In `astrbot/core/db/__init__.py` at lines 971-987:
**Existing adapters cannot instantiate**
When an external adapter implements the old abstract interface, `BaseDatabase` still marks the new method abstract, so the adapter remains abstract and construction raises `TypeError` before pagination can run.
Provide a concrete backward-compatible implementation or otherwise avoid making this method a required abstract method.| if ( | ||
| !isProjectExpanded(projectId) || | ||
| !pagination?.hasMore || | ||
| pagination.loading || | ||
| pagination.error || | ||
| listBottom <= top || | ||
| listBottom - bottom > 120 |
There was a problem hiding this comment.
🟡 Medium · Visible projects load prematurely
When an expanded project list is visible but ends more than 120px above the sidebar viewport bottom, loadMoreSessions treats a negative listBottom - bottom as within the 120px threshold, so scrolling loads another page for expanded project lists that have already ended well above the viewport bottom. The pagination watcher repeats this as pages finish, causing unnecessary requests and loading sessions before users approach those lists.
Require the list bottom to be within the intended near-bottom range, such as listBottom >= bottom - 120, as well as no more than 120px below it.
Prompt for AI agents
In `dashboard/src/components/chat/ProjectList.vue` at lines 257-263:
**Visible projects load prematurely**
When an expanded project list is visible but ends more than 120px above the sidebar viewport bottom, `loadMoreSessions` treats a negative `listBottom - bottom` as within the 120px threshold, so scrolling loads another page for expanded project lists that have already ended well above the viewport bottom. The pagination watcher repeats this as pages finish, causing unnecessary requests and loading sessions before users approach those lists.
Require the list bottom to be within the intended near-bottom range, such as `listBottom >= bottom - 120`, as well as no more than 120px below it.|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="openspec/openapi-v1.yaml" line_range="1560" />
<code_context>
get:
tags: [Chat]
summary: List sessions in a ChatUI project
+ description: Without pagination parameters, returns the legacy list of up to 100 sessions. With page or page_size, returns sessions, total, page, and page_size.
operationId: listChatProjectSessions
x-astrbot-scope: chat
</code_context>
<issue_to_address>
**Generated clients cannot read page fields**
When a consumer uses the generated client to read a paginated response, the OpenAPI description promises `sessions`, `total`, `page`, and `page_size`, but the response remains the generic `SuccessEnvelope` with `data: unknown`; generated-client consumers cannot access those fields without narrowing or casting, so the new response contract is not usable as typed data.
Define and reference a response schema that describes both the legacy and paginated response shapes, or provide a typed pagination-specific response.
</issue_to_address>Sourcery assessment
Needs a human reviewer. If the pagination or counting query is wrong, users could see incomplete or misordered project sessions, but reverting restores the previous behavior. The added database index remains after a code revert and would need a separate cleanup if it proved problematic, though that is bounded and straightforward.
| get: | ||
| tags: [Chat] | ||
| summary: List sessions in a ChatUI project | ||
| description: Without pagination parameters, returns the legacy list of up to 100 sessions. With page or page_size, returns sessions, total, page, and page_size. |
There was a problem hiding this comment.
⚪ Low · Generated clients cannot read page fields
When a consumer uses the generated client to read a paginated response, the OpenAPI description promises sessions, total, page, and page_size, but the response remains the generic SuccessEnvelope with data: unknown; generated-client consumers cannot access those fields without narrowing or casting, so the new response contract is not usable as typed data.
Define and reference a response schema that describes both the legacy and paginated response shapes, or provide a typed pagination-specific response.
Prompt for AI agents
In `openspec/openapi-v1.yaml` at line 1560:
**Generated clients cannot read page fields**
When a consumer uses the generated client to read a paginated response, the OpenAPI description promises `sessions`, `total`, `page`, and `page_size`, but the response remains the generic `SuccessEnvelope` with `data: unknown`; generated-client consumers cannot access those fields without narrowing or casting, so the new response contract is not usable as typed data.
Define and reference a response schema that describes both the legacy and paginated response shapes, or provide a typed pagination-specific response.
Follow-up to #10279, applying the same pagination behavior to WebChat project sessions.
Projects currently stop at 100 sessions. This change loads 30 at a time in both the sidebar and project page, fetching older sessions within 120px of the list bottom and using the total count to determine completion.
Modifications / 改动点
Preserve the legacy API response and share pagination state between both views, independently per project.
Handle retries, stale requests, deduplication, and refreshes after mutations. Skip projects above the visible sidebar to prevent continuous offscreen loading.
Update English/Chinese WebUI instructions and regenerate API documentation/client. Navigation and layout are unchanged; existing documentation screenshots remain applicable.
This is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
verify-deps-before-run=falsefor an existing dependency metadata mismatch.Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
📚 I checked the affected WebUI instructions and screenshots in
docs/zhanddocs/enagainst the changed navigation, page structure, and labels, and updated them in this PR (or explained why no documentation update is needed). For renamed, moved, or merged entry points, I included an old entry → new entry mapping in the documentation and changelog./ 我已对照变化后的 WebUI 入口、页面结构和术语,核对并在本 PR 中更新
docs/zh和docs/en的相关操作说明与截图(或说明无需更新文档的原因)。入口改名、移动或合并时,已在文档和 changelog 中补充 旧入口 → 新入口 对照。🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。
Summary by Sourcery
Paginate WebChat project sessions consistently across the sidebar and project page while retaining backward compatibility.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests: