perf:优化识图,缓解重复回复,使用原始插件manifest_id避免不一致情况

This commit is contained in:
SengokuCola
2026-05-09 02:32:59 +08:00
parent 05052ba02b
commit 0f124e845c
6 changed files with 87 additions and 12 deletions

View File

@@ -18,7 +18,7 @@ const PLUGIN_DETAILS_FILE = 'plugin_details.json'
* 插件列表 API 响应类型(只包含我们需要的字段) * 插件列表 API 响应类型(只包含我们需要的字段)
*/ */
interface PluginApiResponse { interface PluginApiResponse {
id: string id?: string
manifest: { manifest: {
manifest_version: number manifest_version: number
id?: string id?: string
@@ -110,7 +110,7 @@ export async function fetchPluginList(): Promise<ApiResponse<PluginInfo[]>> {
console.warn('跳过无效插件数据:', item) console.warn('跳过无效插件数据:', item)
return false return false
} }
const pluginId = item.manifest.id || item.id const pluginId = item.manifest.id
if (!pluginId) { if (!pluginId) {
console.warn('跳过缺少 ID 的插件:', item) console.warn('跳过缺少 ID 的插件:', item)
return false return false
@@ -122,7 +122,7 @@ export async function fetchPluginList(): Promise<ApiResponse<PluginInfo[]>> {
return true return true
}) })
.map((item) => ({ .map((item) => ({
id: item.manifest.id || item.id, id: item.manifest.id!,
manifest: normalizePluginManifest(item.manifest), manifest: normalizePluginManifest(item.manifest),
downloads: 0, downloads: 0,
rating: 0, rating: 0,

View File

@@ -1 +1 @@
请用中文描述这张图片的内容。如果有文字,请把文字描述概括出来,请留意其主题、直观感受,输出为一段平文本,最多30字请注意不要分点就输出一段文本 请用中文详细描述这张图片的内容。如果有文字,请把文字描述概括出来,请留意其主题、直观感受,输出为一段平文本,最多100字请注意不要分点就输出一段文本

View File

@@ -61,3 +61,76 @@ def test_resolve_installed_plugin_path_accepts_manifest_id_case_mismatch(client:
assert plugin_path is not None assert plugin_path is not None
assert plugin_path.name == "demo_plugin" assert plugin_path.name == "demo_plugin"
def test_install_plugin_preserves_manifest_declared_id(client: TestClient, monkeypatch):
class FakeGitMirrorService:
async def clone_repository(self, **kwargs):
target_path = kwargs["target_path"]
target_path.mkdir(parents=True, exist_ok=True)
(target_path / "_manifest.json").write_text(
json.dumps(
{
"manifest_version": 2,
"id": "author.declared",
"name": "Declared Plugin",
"version": "1.0.0",
"author": {"name": "author"},
}
),
encoding="utf-8",
)
return {"success": True}
monkeypatch.setattr(management_module, "get_git_mirror_service", lambda: FakeGitMirrorService())
response = client.post(
"/api/webui/plugins/install",
json={
"plugin_id": "market.plugin",
"repository_url": "https://github.com/author/declared",
"branch": "main",
},
)
assert response.status_code == 200
plugin_path = support_module.resolve_installed_plugin_path("author.declared")
assert plugin_path is not None
manifest = json.loads((plugin_path / "_manifest.json").read_text(encoding="utf-8"))
assert manifest["id"] == "author.declared"
def test_install_plugin_backfills_missing_manifest_id(client: TestClient, monkeypatch):
class FakeGitMirrorService:
async def clone_repository(self, **kwargs):
target_path = kwargs["target_path"]
target_path.mkdir(parents=True, exist_ok=True)
(target_path / "_manifest.json").write_text(
json.dumps(
{
"manifest_version": 2,
"name": "Legacy Plugin",
"version": "1.0.0",
"author": {"name": "author"},
}
),
encoding="utf-8",
)
return {"success": True}
monkeypatch.setattr(management_module, "get_git_mirror_service", lambda: FakeGitMirrorService())
response = client.post(
"/api/webui/plugins/install",
json={
"plugin_id": "market.legacy",
"repository_url": "https://github.com/author/legacy",
"branch": "main",
},
)
assert response.status_code == 200
plugin_path = support_module.resolve_installed_plugin_path("market.legacy")
assert plugin_path is not None
manifest = json.loads((plugin_path / "_manifest.json").read_text(encoding="utf-8"))
assert manifest["id"] == "market.legacy"

View File

@@ -263,6 +263,7 @@ async def handle_tool(
target_user_info = target_message.message_info.user_info target_user_info = target_message.message_info.user_info
target_user_name = target_user_info.user_cardname or target_user_info.user_nickname or target_user_info.user_id target_user_name = target_user_info.user_cardname or target_user_info.user_nickname or target_user_info.user_id
bot_name = config_module.global_config.bot.nickname.strip() or "MaiSaka"
if tool_ctx.runtime.chat_stream.platform == CLI_PLATFORM_NAME: if tool_ctx.runtime.chat_stream.platform == CLI_PLATFORM_NAME:
tool_ctx.append_guided_reply_to_chat_history(combined_reply_text) tool_ctx.append_guided_reply_to_chat_history(combined_reply_text)
@@ -291,7 +292,7 @@ async def handle_tool(
) )
return tool_ctx.build_success_result( return tool_ctx.build_success_result(
invocation.tool_name, invocation.tool_name,
f'已生成并发送回复"{combined_reply_text}"\n发送对象:{target_user_name}', f'"{bot_name}"已生成并向"{target_user_name}"发送了回复"{combined_reply_text}"',
structured_content={ structured_content={
"msg_id": target_message_id, "msg_id": target_message_id,
"set_quote": set_quote, "set_quote": set_quote,

View File

@@ -187,9 +187,10 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional
for field in ["manifest_version", "name", "version", "author"]: for field in ["manifest_version", "name", "version", "author"]:
if field not in manifest: if field not in manifest:
raise ValueError(f"缺少必需字段: {field}") raise ValueError(f"缺少必需字段: {field}")
manifest["id"] = plugin_id if not str(manifest.get("id", "")).strip():
with open(manifest_path, "w", encoding="utf-8") as file_obj: manifest["id"] = plugin_id
json.dump(manifest, file_obj, ensure_ascii=False, indent=2) with open(manifest_path, "w", encoding="utf-8") as file_obj:
json.dump(manifest, file_obj, ensure_ascii=False, indent=2)
except Exception as e: except Exception as e:
remove_tree(target_path) remove_tree(target_path)
await update_progress( await update_progress(

8
uv.lock generated
View File

@@ -1511,7 +1511,7 @@ requires-dist = [
{ name = "httpx", extras = ["socks"] }, { name = "httpx", extras = ["socks"] },
{ name = "jieba", specifier = ">=0.42.1" }, { name = "jieba", specifier = ">=0.42.1" },
{ name = "json-repair", specifier = ">=0.47.6" }, { name = "json-repair", specifier = ">=0.47.6" },
{ name = "maibot-dashboard", specifier = ">=1.0.9" }, { name = "maibot-dashboard", specifier = ">=1.0.10" },
{ name = "maibot-plugin-sdk", specifier = ">=2.4.0" }, { name = "maibot-plugin-sdk", specifier = ">=2.4.0" },
{ name = "maim-message", specifier = ">=0.6.2" }, { name = "maim-message", specifier = ">=0.6.2" },
{ name = "matplotlib", specifier = ">=3.10.5" }, { name = "matplotlib", specifier = ">=3.10.5" },
@@ -1549,11 +1549,11 @@ dev = [
[[package]] [[package]]
name = "maibot-dashboard" name = "maibot-dashboard"
version = "1.0.9" version = "1.0.10"
source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" }
sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ac/5b/e90896cbdddc89ec5586873de07a3d70c0107e4dc76db8666a0c0fde6ae8/maibot_dashboard-1.0.9.tar.gz", hash = "sha256:0e5c00be021419686105238cded501024f0383a3815bd85f9a1e747f3f04d0cd", size = 2496957, upload-time = "2026-05-07T18:37:51.291Z" } sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/9a/b7/3301c49d96bbfde0c61405b7e5afe1c75d625420fdd83d1f4814b9f09eec/maibot_dashboard-1.0.10.tar.gz", hash = "sha256:38be2833f6a17c1f347262eccf5967813327948ad29900b955bb91631844a27c", size = 2496436, upload-time = "2026-05-08T13:15:48.204Z" }
wheels = [ wheels = [
{ url = "https://pypi.tuna.tsinghua.edu.cn/packages/8c/27/ab227a84e55356039004a375e78031e5e8aaf4192e11908a568498816d5e/maibot_dashboard-1.0.9-py3-none-any.whl", hash = "sha256:197b26c5c3d0e6ba1238b91d12c88e57db71c65303cc602fcccdca84ce4db582", size = 2563281, upload-time = "2026-05-07T18:37:49.648Z" }, { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ab/1e/c86f8a98c9de4eef831f855994744ec0512ccfb9322aaef385ca0919f950/maibot_dashboard-1.0.10-py3-none-any.whl", hash = "sha256:749390d6e4c340598e048d72f4c733558163153c0ad4443ff81b5a1c28799629", size = 2563613, upload-time = "2026-05-08T13:15:46.562Z" },
] ]
[[package]] [[package]]