mirror of
https://github.com/langbot-app/LangBot.git
synced 2025-11-25 03:15:06 +08:00
perf: Sort installed plugins: debug plugins first, then by installation time (#1798)
* Initial plan * Implement plugin list sorting: debug plugins first, then by installation time Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> * Apply ruff formatting * Add unit tests for plugin list sorting functionality Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> * Optimize database query to avoid N+1 problem and update tests Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> * Remove redundant assertion in test Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> * perf: plugin list sorting --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> Co-authored-by: Junyan Qin <rockchinq@gmail.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import typing
|
||||
import os
|
||||
import sys
|
||||
import httpx
|
||||
import sqlalchemy
|
||||
from async_lru import alru_cache
|
||||
from langbot_plugin.api.entities.builtin.pipeline.query import provider_session
|
||||
|
||||
@@ -27,6 +28,7 @@ from langbot_plugin.api.entities.builtin.command import (
|
||||
)
|
||||
from langbot_plugin.runtime.plugin.mgr import PluginInstallSource
|
||||
from ..core import taskmgr
|
||||
from ..entity.persistence import plugin as persistence_plugin
|
||||
|
||||
|
||||
class PluginRuntimeConnector:
|
||||
@@ -279,7 +281,61 @@ class PluginRuntimeConnector:
|
||||
if not self.is_enable_plugin:
|
||||
return []
|
||||
|
||||
return await self.handler.list_plugins()
|
||||
plugins = await self.handler.list_plugins()
|
||||
|
||||
# Sort plugins: debug plugins first, then by installation time (newest first)
|
||||
# Get installation timestamps from database in a single query
|
||||
plugin_timestamps = {}
|
||||
|
||||
if plugins:
|
||||
# Build list of (author, name) tuples for all plugins
|
||||
plugin_ids = []
|
||||
for plugin in plugins:
|
||||
author = plugin.get('manifest', {}).get('manifest', {}).get('metadata', {}).get('author', '')
|
||||
name = plugin.get('manifest', {}).get('manifest', {}).get('metadata', {}).get('name', '')
|
||||
if author and name:
|
||||
plugin_ids.append((author, name))
|
||||
|
||||
# Fetch all timestamps in a single query using OR conditions
|
||||
if plugin_ids:
|
||||
conditions = [
|
||||
sqlalchemy.and_(
|
||||
persistence_plugin.PluginSetting.plugin_author == author,
|
||||
persistence_plugin.PluginSetting.plugin_name == name,
|
||||
)
|
||||
for author, name in plugin_ids
|
||||
]
|
||||
|
||||
result = await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.select(
|
||||
persistence_plugin.PluginSetting.plugin_author,
|
||||
persistence_plugin.PluginSetting.plugin_name,
|
||||
persistence_plugin.PluginSetting.created_at,
|
||||
).where(sqlalchemy.or_(*conditions))
|
||||
)
|
||||
|
||||
for row in result:
|
||||
plugin_id = f'{row.plugin_author}/{row.plugin_name}'
|
||||
plugin_timestamps[plugin_id] = row.created_at
|
||||
|
||||
# Sort: debug plugins first (descending), then by created_at (descending)
|
||||
def sort_key(plugin):
|
||||
author = plugin.get('manifest', {}).get('manifest', {}).get('metadata', {}).get('author', '')
|
||||
name = plugin.get('manifest', {}).get('manifest', {}).get('metadata', {}).get('name', '')
|
||||
plugin_id = f'{author}/{name}'
|
||||
|
||||
is_debug = plugin.get('debug', False)
|
||||
created_at = plugin_timestamps.get(plugin_id)
|
||||
|
||||
# Return tuple: (not is_debug, -timestamp)
|
||||
# not is_debug: False (0) for debug plugins, True (1) for non-debug
|
||||
# -timestamp: to sort newest first (will be None for plugins without timestamp)
|
||||
timestamp_value = -created_at.timestamp() if created_at else 0
|
||||
return (not is_debug, timestamp_value)
|
||||
|
||||
plugins.sort(key=sort_key)
|
||||
|
||||
return plugins
|
||||
|
||||
async def get_plugin_info(self, author: str, plugin_name: str) -> dict[str, Any]:
|
||||
return await self.handler.get_plugin_info(author, plugin_name)
|
||||
|
||||
Reference in New Issue
Block a user