From e17e83bca32a963695faea8458c6014494604077 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:38:39 +0800 Subject: [PATCH 01/22] refactor: route agent settings tools through runtime --- app/agent/tools/impl/query_system_settings.py | 4 ++-- app/agent/tools/impl/update_system_settings.py | 6 +++--- app/application/configuration.py | 2 +- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../fixtures/architecture/configuration-debt-baseline.json | 4 +--- tests/fixtures/architecture/dependency-baseline.json | 7 +++---- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/app/agent/tools/impl/query_system_settings.py b/app/agent/tools/impl/query_system_settings.py index d53f8feef..65f5cccbf 100644 --- a/app/agent/tools/impl/query_system_settings.py +++ b/app/agent/tools/impl/query_system_settings.py @@ -15,10 +15,10 @@ from app.agent.tools.impl._system_setting_utils import ( resolve_setting_spec, should_redact_setting, ) -from app.runtime.config import settings from app.application.configuration import ( SystemConfigReader, get_configured_system_config as SystemConfigOper, + get_runtime_settings, ) from app.runtime.log import logger @@ -128,7 +128,7 @@ class QuerySystemSettingsTool(MoviePilotTool): def _load_setting_value(self, spec: SettingSpec): """读取指定设置项的当前值。""" if spec.source == "settings": - return getattr(settings, spec.key) + return get_runtime_settings().get(spec.key) return self._get_system_config().get(spec.systemconfig_key) @staticmethod diff --git a/app/agent/tools/impl/update_system_settings.py b/app/agent/tools/impl/update_system_settings.py index f6aebda87..2a3e02d65 100644 --- a/app/agent/tools/impl/update_system_settings.py +++ b/app/agent/tools/impl/update_system_settings.py @@ -16,11 +16,11 @@ from app.agent.tools.impl._system_setting_utils import ( resolve_setting_spec, should_redact_setting, ) -from app.runtime.config import settings from app.runtime.events import eventmanager from app.application.configuration import ( SystemConfigService, get_configured_system_config as SystemConfigOper, + get_runtime_settings, ) from app.runtime.log import logger from app.schemas.event import ConfigChangeEventData @@ -126,7 +126,7 @@ class UpdateSystemSettingsTool(MoviePilotTool): def _load_setting_value(self, spec: SettingSpec): """读取指定设置项的当前值。""" if spec.source == "settings": - return getattr(settings, spec.key) + return get_runtime_settings().get(spec.key) return self._get_system_config().get(spec.systemconfig_key) @staticmethod @@ -274,7 +274,7 @@ class UpdateSystemSettingsTool(MoviePilotTool): changed = False message = "" if spec.source == "settings": - success, message = settings.update_setting(spec.key, next_value) + success, message = get_runtime_settings().update(spec.key, next_value) if success is False: return json.dumps( { diff --git a/app/application/configuration.py b/app/application/configuration.py index 59f62d669..cf00edadf 100644 --- a/app/application/configuration.py +++ b/app/application/configuration.py @@ -284,7 +284,7 @@ class RuntimeSettingsService: def update(self, key: str, value: Any) -> tuple[Optional[bool], str]: """更新单个部署设置。""" - return self._settings.update_setting(key=key, value=value) + return self._settings.update_setting(key, value) class SystemConfigService: diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 5f39b7e80..32aa3637a 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1040,6 +1040,8 @@ runtime provider,旧插件或测试替换模块级 `settings` 时仍保持原 服务端和评分专项 184 项测试与 Pylint 通过,配置债务由 107 个文件降至 105 个文件。 用户模型的 `get_by_name` 与 `get_by_id` 同步查询改为显式 Session 执行,并以一次性短会话保留旧插件 无 Session ABI;用户查询与兼容专项 75 项测试、Pylint 及架构基线通过,查询装饰器由 119 个降至 117 个。 +随后将 Agent 系统设置查询/更新工具切换到已装配的 `RuntimeSettingsService` 窄端口,保留工具构造和 +设置更新返回 ABI;配置债务由 103 个文件降至 101 个文件,系统设置工具专项测试与架构基线通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index dc1e86d8c..76aede2ba 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 103, + "count": 101, "files": [ "app/adapters/system/fsproxy.py", "app/agent/capabilities/adapter.py", @@ -26,13 +26,11 @@ "app/agent/tools/impl/add_download_tasks.py", "app/agent/tools/impl/create_agent_task.py", "app/agent/tools/impl/query_agent_tasks.py", - "app/agent/tools/impl/query_system_settings.py", "app/agent/tools/impl/recognize_media.py", "app/agent/tools/impl/scrape_metadata.py", "app/agent/tools/impl/search_web.py", "app/agent/tools/impl/send_voice_message.py", "app/agent/tools/impl/update_agent_task.py", - "app/agent/tools/impl/update_system_settings.py", "app/cli.py", "app/db/base.py", "app/db/engine.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 27928e3be..3da9f7f3a 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6421, - "edge_sha256": "889385bbfbe3634711d921dc76afe38bbfc3ea7c672663e67ae6453aad19af4c", + "edge_count": 6420, + "edge_sha256": "7c586d713c6014eb485763f8b7704d9421d95ba7d145910a33163dcb36882914", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -1096,7 +1096,6 @@ "app.agent.tools.impl.query_system_settings -> app.application", "app.agent.tools.impl.query_system_settings -> app.application.configuration", "app.agent.tools.impl.query_system_settings -> app.runtime", - "app.agent.tools.impl.query_system_settings -> app.runtime.config", "app.agent.tools.impl.query_system_settings -> app.runtime.log", "app.agent.tools.impl.query_transfer_history -> app.agent", "app.agent.tools.impl.query_transfer_history -> app.agent.tools", @@ -1469,7 +1468,6 @@ "app.agent.tools.impl.update_system_settings -> app.application", "app.agent.tools.impl.update_system_settings -> app.application.configuration", "app.agent.tools.impl.update_system_settings -> app.runtime", - "app.agent.tools.impl.update_system_settings -> app.runtime.config", "app.agent.tools.impl.update_system_settings -> app.runtime.events", "app.agent.tools.impl.update_system_settings -> app.runtime.log", "app.agent.tools.impl.update_system_settings -> app.schemas", @@ -3256,6 +3254,7 @@ "app.chain.subscribe -> app.application.configuration", "app.chain.subscribe -> app.application.mediaserver", "app.chain.subscribe -> app.application.messaging", + "app.chain.subscribe -> app.application.messaging.message", "app.chain.subscribe -> app.application.messaging.subscribe", "app.chain.subscribe -> app.application.subscription", "app.chain.subscribe -> app.application.subscription.complete", From adfe72cbaa81cd1b441163b6655ed80f9b7acd6a Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:42:37 +0800 Subject: [PATCH 02/22] refactor: migrate site read queries to explicit sessions --- app/db/decorators.py | 8 +++++ app/db/models/siteicon.py | 25 +++++++++++---- app/db/models/sitestatistic.py | 25 +++++++++++---- app/db/models/userconfig.py | 3 +- .../backend-architecture-next-stage.md | 2 ++ .../architecture/dependency-baseline.json | 5 ++- .../transaction-debt-baseline.json | 31 ++----------------- 7 files changed, 54 insertions(+), 45 deletions(-) diff --git a/app/db/decorators.py b/app/db/decorators.py index 15305805c..95c7266a0 100644 --- a/app/db/decorators.py +++ b/app/db/decorators.py @@ -43,6 +43,14 @@ def run_legacy_sync_query(operation: Callable[[Session], _R]) -> _R: except Exception as close_err: # noqa: BLE001 兼容查询释放失败不改变返回语义 logger.error(f"释放数据库会话失败:{close_err}") + +async def run_legacy_async_query( + operation: Callable[[AsyncSession], Awaitable[_R]], +) -> _R: + """为移除异步查询装饰器的旧 Model ABI 提供一次性异步会话。""" + async with async_session_scope() as db: + return await operation(db) + def _get_args_db( args: tuple[Any, ...], kwargs: dict[str, Any], diff --git a/app/db/models/siteicon.py b/app/db/models/siteicon.py index e176ae7d5..3d420755b 100644 --- a/app/db/models/siteicon.py +++ b/app/db/models/siteicon.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import Mapped, Session, mapped_column from app.db.base import Base, get_id_column -from app.db.decorators import db_query, async_db_query +from app.db.decorators import run_legacy_async_query class SiteIcon(Base): @@ -22,12 +22,25 @@ class SiteIcon(Base): base64: Mapped[Optional[str]] = mapped_column(String) @classmethod - @db_query def get_by_domain(cls, db: Session, domain: str): + """在调用方 Session 中查询站点图标。""" return db.execute(select(cls).where(cls.domain == domain)).scalars().first() @classmethod - @async_db_query - async def async_get_by_domain(cls, db: AsyncSession, domain: str): - result = await db.execute(select(cls).where(cls.domain == domain)) - return result.scalar_one_or_none() + async def async_get_by_domain( + cls, + db: AsyncSession | None = None, + domain: str | None = None, + ): + """在调用方 AsyncSession 中查询站点图标。""" + if domain is None: + raise TypeError("domain is required") + + async def query(session: AsyncSession): + """在给定异步会话中执行站点图标查询。""" + result = await session.execute(select(cls).where(cls.domain == domain)) + return result.scalar_one_or_none() + + if isinstance(db, AsyncSession): + return await query(db) + return await run_legacy_async_query(query) diff --git a/app/db/models/sitestatistic.py b/app/db/models/sitestatistic.py index 69b645ac8..7d7ddf061 100644 --- a/app/db/models/sitestatistic.py +++ b/app/db/models/sitestatistic.py @@ -6,7 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import Mapped, Session, mapped_column from app.db.base import get_id_column, Base -from app.db.decorators import db_query, async_db_query +from app.db.decorators import run_legacy_async_query class SiteStatistic(Base): @@ -30,15 +30,28 @@ class SiteStatistic(Base): note: Mapped[Optional[Any]] = mapped_column(JSON) @classmethod - @db_query def get_by_domain(cls, db: Session, domain: str): + """在调用方 Session 中查询站点统计。""" return db.execute(select(cls).where(cls.domain == domain)).scalars().first() @classmethod - @async_db_query - async def async_get_by_domain(cls, db: AsyncSession, domain: str): - result = await db.execute(select(cls).where(cls.domain == domain)) - return result.scalar_one_or_none() + async def async_get_by_domain( + cls, + db: AsyncSession | None = None, + domain: str | None = None, + ): + """在调用方 AsyncSession 中查询站点统计,并兼容旧无会话调用。""" + if domain is None: + raise TypeError("domain is required") + + async def query(session: AsyncSession): + """在给定异步会话中执行站点统计查询。""" + result = await session.execute(select(cls).where(cls.domain == domain)) + return result.scalar_one_or_none() + + if isinstance(db, AsyncSession): + return await query(db) + return await run_legacy_async_query(query) @classmethod def reset(cls, db: Session): diff --git a/app/db/models/userconfig.py b/app/db/models/userconfig.py index 01c5129de..47be8ed46 100644 --- a/app/db/models/userconfig.py +++ b/app/db/models/userconfig.py @@ -3,7 +3,6 @@ from sqlalchemy import String, UniqueConstraint, JSON, select from sqlalchemy.orm import Mapped, Session, mapped_column from app.db.base import get_id_column, Base -from app.db.decorators import db_query class UserConfig(Base): @@ -24,8 +23,8 @@ class UserConfig(Base): ) @classmethod - @db_query def get_by_key(cls, db: Session, username: str, key: str): + """在调用方 Session 中查询用户配置。""" return db.execute( select(cls).where(cls.username == username, cls.key == key) ).scalars().first() diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 32aa3637a..7e48238a3 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1042,6 +1042,8 @@ runtime provider,旧插件或测试替换模块级 `settings` 时仍保持原 无 Session ABI;用户查询与兼容专项 75 项测试、Pylint 及架构基线通过,查询装饰器由 119 个降至 117 个。 随后将 Agent 系统设置查询/更新工具切换到已装配的 `RuntimeSettingsService` 窄端口,保留工具构造和 设置更新返回 ABI;配置债务由 103 个文件降至 101 个文件,系统设置工具专项测试与架构基线通过。 +站点图标、站点统计和用户配置的只读 Model 方法随后改为显式 Session 执行,异步无 Session 旧 ABI 由 +一次性兼容查询会话承接;查询装饰器由 117 个降至 112 个,站点查询专项测试与架构基线通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 3da9f7f3a..7dbcad279 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6420, - "edge_sha256": "7c586d713c6014eb485763f8b7704d9421d95ba7d145910a33163dcb36882914", + "edge_count": 6419, + "edge_sha256": "bc2f57394915b9f90921a91cc4630a4426975ee765ece75a1aa0640080e41b4f", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -3557,7 +3557,6 @@ "app.db.models.user -> app.db.decorators", "app.db.models.userconfig -> app.db", "app.db.models.userconfig -> app.db.base", - "app.db.models.userconfig -> app.db.decorators", "app.db.models.workflow -> app.db", "app.db.models.workflow -> app.db.base", "app.db.models.workflow -> app.db.decorators", diff --git a/tests/fixtures/architecture/transaction-debt-baseline.json b/tests/fixtures/architecture/transaction-debt-baseline.json index b9636b031..23ecdb103 100644 --- a/tests/fixtures/architecture/transaction-debt-baseline.json +++ b/tests/fixtures/architecture/transaction-debt-baseline.json @@ -1,12 +1,12 @@ { "model_decorators": { "by_kind": { - "async_db_query": 49, + "async_db_query": 47, "async_db_update": 0, - "db_query": 68, + "db_query": 65, "db_update": 0 }, - "count": 117, + "count": 112, "methods": [ { "decorator": "async_db_query", @@ -263,26 +263,6 @@ "file": "app/db/models/site.py", "method": "Site.list_order_by_pri" }, - { - "decorator": "async_db_query", - "file": "app/db/models/siteicon.py", - "method": "SiteIcon.async_get_by_domain" - }, - { - "decorator": "db_query", - "file": "app/db/models/siteicon.py", - "method": "SiteIcon.get_by_domain" - }, - { - "decorator": "async_db_query", - "file": "app/db/models/sitestatistic.py", - "method": "SiteStatistic.async_get_by_domain" - }, - { - "decorator": "db_query", - "file": "app/db/models/sitestatistic.py", - "method": "SiteStatistic.get_by_domain" - }, { "decorator": "async_db_query", "file": "app/db/models/siteuserdata.py", @@ -548,11 +528,6 @@ "file": "app/db/models/user.py", "method": "User.async_get_by_name" }, - { - "decorator": "db_query", - "file": "app/db/models/userconfig.py", - "method": "UserConfig.get_by_key" - }, { "decorator": "async_db_query", "file": "app/db/models/workflow.py", From f729a8ffe7ad0c65a56d48c46cf678b20955f942 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:44:40 +0800 Subject: [PATCH 03/22] refactor: migrate plugin data read queries --- app/db/models/plugindata.py | 66 +++++++++++++++---- .../backend-architecture-next-stage.md | 2 + .../transaction-debt-baseline.json | 36 +--------- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/app/db/models/plugindata.py b/app/db/models/plugindata.py index d626c91d2..8bf4bd78b 100644 --- a/app/db/models/plugindata.py +++ b/app/db/models/plugindata.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import Mapped, Session, mapped_column from app.db.base import get_id_column, Base -from app.db.decorators import db_query, async_db_query +from app.db.decorators import run_legacy_async_query, run_legacy_sync_query class PluginData(Base): @@ -21,28 +21,54 @@ class PluginData(Base): ) @classmethod - @db_query - def get_plugin_data(cls, db: Session, plugin_id: str): + def get_plugin_data(cls, db: Session | None = None, plugin_id: str | None = None): + """在调用方 Session 中读取插件全部数据,并兼容旧无会话入口。""" + if plugin_id is None: + raise TypeError("plugin_id is required") + if not isinstance(db, Session): + return run_legacy_sync_query(lambda session: cls.get_plugin_data(session, plugin_id)) return list(db.execute(select(cls).where(cls.plugin_id == plugin_id)).scalars().all()) @classmethod - @async_db_query - async def async_get_plugin_data(cls, db: AsyncSession, plugin_id: str): + async def async_get_plugin_data( + cls, db: AsyncSession | None = None, plugin_id: str | None = None + ): + """在调用方 AsyncSession 中读取插件全部数据,并兼容旧无会话入口。""" + if plugin_id is None: + raise TypeError("plugin_id is required") + if not isinstance(db, AsyncSession): + return await run_legacy_async_query( + lambda session: cls.async_get_plugin_data(session, plugin_id) + ) result = await db.execute(select(cls).where(cls.plugin_id == plugin_id)) return list(result.scalars().all()) @classmethod - @db_query - def get_plugin_data_by_key(cls, db: Session, plugin_id: str, key: str): + def get_plugin_data_by_key( + cls, db: Session | None = None, plugin_id: str | None = None, key: str | None = None + ): + """在调用方 Session 中按键读取插件数据,并兼容旧无会话入口。""" + if plugin_id is None or key is None: + raise TypeError("plugin_id and key are required") + if not isinstance(db, Session): + return run_legacy_sync_query( + lambda session: cls.get_plugin_data_by_key(session, plugin_id, key) + ) return db.execute( select(cls).where(cls.plugin_id == plugin_id, cls.key == key) ).scalars().first() @classmethod - @async_db_query async def async_get_plugin_data_by_key( - cls, db: AsyncSession, plugin_id: str, key: str + cls, db: AsyncSession | None = None, plugin_id: str | None = None, key: str | None = None ): + """在调用方 AsyncSession 中按键读取插件数据,并兼容旧无会话入口。""" + if plugin_id is None or key is None: + raise TypeError("plugin_id and key are required") + if not isinstance(db, AsyncSession): + return await run_legacy_async_query( + lambda session: cls.async_get_plugin_data_by_key(session, plugin_id, key) + ) result = await db.execute( select(cls).where(cls.plugin_id == plugin_id, cls.key == key) ) @@ -59,14 +85,28 @@ class PluginData(Base): db.execute(delete(cls).where(cls.plugin_id == plugin_id)) @classmethod - @db_query - def get_plugin_data_by_plugin_id(cls, db: Session, plugin_id: str): + def get_plugin_data_by_plugin_id( + cls, db: Session | None = None, plugin_id: str | None = None + ): + """在调用方 Session 中按插件 ID 读取数据,并兼容旧无会话入口。""" + if plugin_id is None: + raise TypeError("plugin_id is required") + if not isinstance(db, Session): + return run_legacy_sync_query( + lambda session: cls.get_plugin_data_by_plugin_id(session, plugin_id) + ) return list(db.execute(select(cls).where(cls.plugin_id == plugin_id)).scalars().all()) @classmethod - @async_db_query async def async_get_plugin_data_by_plugin_id( - cls, db: AsyncSession, plugin_id: str + cls, db: AsyncSession | None = None, plugin_id: str | None = None ): + """在调用方 AsyncSession 中按插件 ID 读取数据,并兼容旧无会话入口。""" + if plugin_id is None: + raise TypeError("plugin_id is required") + if not isinstance(db, AsyncSession): + return await run_legacy_async_query( + lambda session: cls.async_get_plugin_data_by_plugin_id(session, plugin_id) + ) result = await db.execute(select(cls).where(cls.plugin_id == plugin_id)) return list(result.scalars().all()) diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 7e48238a3..294c579dd 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1044,6 +1044,8 @@ runtime provider,旧插件或测试替换模块级 `settings` 时仍保持原 设置更新返回 ABI;配置债务由 103 个文件降至 101 个文件,系统设置工具专项测试与架构基线通过。 站点图标、站点统计和用户配置的只读 Model 方法随后改为显式 Session 执行,异步无 Session 旧 ABI 由 一次性兼容查询会话承接;查询装饰器由 117 个降至 112 个,站点查询专项测试与架构基线通过。 +插件数据的六个只读入口也改为显式 Session/AsyncSession,旧插件无会话读取通过一次性兼容查询会话保留; +查询装饰器由 112 个降至 106 个,插件数据与事务专项测试及架构基线通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/transaction-debt-baseline.json b/tests/fixtures/architecture/transaction-debt-baseline.json index 23ecdb103..1a0ff3d83 100644 --- a/tests/fixtures/architecture/transaction-debt-baseline.json +++ b/tests/fixtures/architecture/transaction-debt-baseline.json @@ -1,12 +1,12 @@ { "model_decorators": { "by_kind": { - "async_db_query": 47, + "async_db_query": 44, "async_db_update": 0, - "db_query": 65, + "db_query": 62, "db_update": 0 }, - "count": 112, + "count": 106, "methods": [ { "decorator": "async_db_query", @@ -193,36 +193,6 @@ "file": "app/db/models/passkey.py", "method": "PassKey.get_by_id" }, - { - "decorator": "async_db_query", - "file": "app/db/models/plugindata.py", - "method": "PluginData.async_get_plugin_data" - }, - { - "decorator": "async_db_query", - "file": "app/db/models/plugindata.py", - "method": "PluginData.async_get_plugin_data_by_key" - }, - { - "decorator": "async_db_query", - "file": "app/db/models/plugindata.py", - "method": "PluginData.async_get_plugin_data_by_plugin_id" - }, - { - "decorator": "db_query", - "file": "app/db/models/plugindata.py", - "method": "PluginData.get_plugin_data" - }, - { - "decorator": "db_query", - "file": "app/db/models/plugindata.py", - "method": "PluginData.get_plugin_data_by_key" - }, - { - "decorator": "db_query", - "file": "app/db/models/plugindata.py", - "method": "PluginData.get_plugin_data_by_plugin_id" - }, { "decorator": "async_db_query", "file": "app/db/models/site.py", From 1ede083fb2db5620a4803938ca8a297dd5ffe294 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:46:26 +0800 Subject: [PATCH 04/22] refactor: route agent support settings through runtime --- app/agent/capabilities/adapter.py | 4 +++- app/agent/memory/__init__.py | 4 +++- app/agent/prompt/__init__.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 5 +---- tests/fixtures/architecture/dependency-baseline.json | 8 ++++---- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/app/agent/capabilities/adapter.py b/app/agent/capabilities/adapter.py index d6b160394..04b3510d0 100644 --- a/app/agent/capabilities/adapter.py +++ b/app/agent/capabilities/adapter.py @@ -17,7 +17,9 @@ from app.runtime.capabilities.model import ( SelectorSchema, ) from app.runtime.capabilities.registry import CapabilityRegistry -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() _DEFAULT_CAPABILITY_ROOT = Path(__file__).resolve().parent diff --git a/app/agent/memory/__init__.py b/app/agent/memory/__init__.py index c1698ffe9..32b23fbee 100644 --- a/app/agent/memory/__init__.py +++ b/app/agent/memory/__init__.py @@ -6,7 +6,9 @@ from typing import Dict, List, Optional from langchain_core.messages import BaseMessage, messages_from_dict, messages_to_dict -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.agentdata import AgentChatPort as AgentChatOper from app.runtime.log import logger from app.schemas.agent import ConversationMemory diff --git a/app/agent/prompt/__init__.py b/app/agent/prompt/__init__.py index de5c21733..aeff7460e 100644 --- a/app/agent/prompt/__init__.py +++ b/app/agent/prompt/__init__.py @@ -10,7 +10,9 @@ from typing import Any, Dict, Optional import yaml from app.agent.llm.capability import AgentCapabilityManager -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.notification import ChannelCapability from app.schemas.notification import ChannelCapabilities diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 294c579dd..2d2723ef1 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1046,6 +1046,8 @@ runtime provider,旧插件或测试替换模块级 `settings` 时仍保持原 一次性兼容查询会话承接;查询装饰器由 117 个降至 112 个,站点查询专项测试与架构基线通过。 插件数据的六个只读入口也改为显式 Session/AsyncSession,旧插件无会话读取通过一次性兼容查询会话保留; 查询装饰器由 112 个降至 106 个,插件数据与事务专项测试及架构基线通过。 +Agent 能力适配器、记忆和提示词模块改用 `RuntimeSettingsCompat` 动态运行时端口,保留模块级覆盖和 +导入早期回退;配置债务由 101 个文件降至 98 个,Agent 能力、提示词与运行时专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 76aede2ba..6dc83987a 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,16 +9,13 @@ "root": "app" }, "settings_imports": { - "count": 101, + "count": 98, "files": [ "app/adapters/system/fsproxy.py", - "app/agent/capabilities/adapter.py", "app/agent/llm/capability.py", "app/agent/llm/helper.py", "app/agent/llm/provider.py", - "app/agent/memory/__init__.py", "app/agent/orchestrator.py", - "app/agent/prompt/__init__.py", "app/agent/skills/registry.py", "app/agent/tools/base.py", "app/agent/tools/impl/_plugin_tool_utils.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 7dbcad279..b1faf0e50 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6419, - "edge_sha256": "bc2f57394915b9f90921a91cc4630a4426975ee765ece75a1aa0640080e41b4f", + "edge_sha256": "d5ae653cf616d76dfefea690bb71c32f54b07612af9c5c9cd4372ac6b55b6cae", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -189,7 +189,7 @@ "app.agent.capabilities.adapter -> app.runtime.capabilities.errors", "app.agent.capabilities.adapter -> app.runtime.capabilities.model", "app.agent.capabilities.adapter -> app.runtime.capabilities.registry", - "app.agent.capabilities.adapter -> app.runtime.config", + "app.agent.capabilities.adapter -> app.runtime.settings", "app.agent.contracts -> app.schemas", "app.agent.contracts -> app.schemas.types", "app.agent.llm.capability -> app.adapters", @@ -238,8 +238,8 @@ "app.agent.memory -> app.application", "app.agent.memory -> app.application.agentdata", "app.agent.memory -> app.runtime", - "app.agent.memory -> app.runtime.config", "app.agent.memory -> app.runtime.log", + "app.agent.memory -> app.runtime.settings", "app.agent.memory -> app.schemas", "app.agent.memory -> app.schemas.agent", "app.agent.middleware.activity_log -> app.agent", @@ -381,8 +381,8 @@ "app.agent.prompt -> app.agent.llm", "app.agent.prompt -> app.agent.llm.capability", "app.agent.prompt -> app.runtime", - "app.agent.prompt -> app.runtime.config", "app.agent.prompt -> app.runtime.log", + "app.agent.prompt -> app.runtime.settings", "app.agent.prompt -> app.schemas", "app.agent.prompt -> app.schemas.notification", "app.agent.prompt.transfer_redo -> app.agent", From 41ee5aacdcd1a52a209ecb01252e4ef3ce408a9f Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:49:00 +0800 Subject: [PATCH 05/22] refactor: route agent llm settings through runtime --- app/agent/llm/capability.py | 4 +++- app/agent/llm/helper.py | 4 +++- app/agent/llm/provider.py | 4 +++- app/agent/orchestrator.py | 4 +++- app/agent/tools/base.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 7 +------ tests/fixtures/architecture/dependency-baseline.json | 12 ++++++------ 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/agent/llm/capability.py b/app/agent/llm/capability.py index 4ba797ecf..bc8b8e650 100644 --- a/app/agent/llm/capability.py +++ b/app/agent/llm/capability.py @@ -12,7 +12,9 @@ from pathlib import Path from typing import Any, Dict, Optional from uuid import uuid4 -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.adapters.network.http import RequestUtils diff --git a/app/agent/llm/helper.py b/app/agent/llm/helper.py index 7ae716fae..6325f757b 100644 --- a/app/agent/llm/helper.py +++ b/app/agent/llm/helper.py @@ -11,7 +11,9 @@ from urllib.parse import urlsplit from langchain_core.messages import AIMessage, AIMessageChunk from app.agent.llm.gateway import resolve_llm_provider_runtime -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger if TYPE_CHECKING: diff --git a/app/agent/llm/provider.py b/app/agent/llm/provider.py index 0661fe2a5..f947a8333 100644 --- a/app/agent/llm/provider.py +++ b/app/agent/llm/provider.py @@ -20,7 +20,9 @@ import aiofiles import httpx import jwt -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.configuration import get_configured_system_config as SystemConfigOper from app.runtime.log import logger from app.schemas.types import LlmProviderAction, SystemConfigKey diff --git a/app/agent/orchestrator.py b/app/agent/orchestrator.py index 154bc5b1f..8687cf80a 100644 --- a/app/agent/orchestrator.py +++ b/app/agent/orchestrator.py @@ -68,7 +68,9 @@ from app.agent.tools.impl.mcp import ( ) from app.agent.tools.impl.query_system_settings import QuerySystemSettingsTool from app.chain.agent import AgentChain -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.events import eventmanager from app.runtime.observability import record_metric from app.application.plugin.runtime import get_plugin_manager diff --git a/app/agent/tools/base.py b/app/agent/tools/base.py index ec0c2f05f..cbefa569a 100644 --- a/app/agent/tools/base.py +++ b/app/agent/tools/base.py @@ -17,7 +17,9 @@ from app.agent.policy.sanitizer import ( ) from app.agent.tools.tags import ToolTag from app.chain import ChainBase -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.messaging.agent import matches_channel_admin from app.runtime.extensions.service_config import ServiceConfigHelper from app.runtime.log import logger diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 2d2723ef1..47c8e05ea 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1048,6 +1048,8 @@ runtime provider,旧插件或测试替换模块级 `settings` 时仍保持原 查询装饰器由 112 个降至 106 个,插件数据与事务专项测试及架构基线通过。 Agent 能力适配器、记忆和提示词模块改用 `RuntimeSettingsCompat` 动态运行时端口,保留模块级覆盖和 导入早期回退;配置债务由 101 个文件降至 98 个,Agent 能力、提示词与运行时专项测试通过。 +随后将 LLM capability/helper/provider、Agent orchestrator 和工具基础类统一切换到同一动态运行时端口; +配置债务由 98 个文件降至 93 个,LLM、Agent 生命周期与工具专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 6dc83987a..71a21a402 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,15 +9,10 @@ "root": "app" }, "settings_imports": { - "count": 98, + "count": 93, "files": [ "app/adapters/system/fsproxy.py", - "app/agent/llm/capability.py", - "app/agent/llm/helper.py", - "app/agent/llm/provider.py", - "app/agent/orchestrator.py", "app/agent/skills/registry.py", - "app/agent/tools/base.py", "app/agent/tools/impl/_plugin_tool_utils.py", "app/agent/tools/impl/_terminal_session.py", "app/agent/tools/impl/add_download_tasks.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index b1faf0e50..f529cc0e3 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6419, - "edge_sha256": "d5ae653cf616d76dfefea690bb71c32f54b07612af9c5c9cd4372ac6b55b6cae", + "edge_sha256": "91e14e6acb6220fccd8ac3e2df899303f4e4fe6532c92079378d4b350be4d06e", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -199,10 +199,10 @@ "app.agent.llm.capability -> app.agent.llm", "app.agent.llm.capability -> app.agent.llm.helper", "app.agent.llm.capability -> app.runtime", - "app.agent.llm.capability -> app.runtime.config", "app.agent.llm.capability -> app.runtime.extensions", "app.agent.llm.capability -> app.runtime.extensions.service_config", "app.agent.llm.capability -> app.runtime.log", + "app.agent.llm.capability -> app.runtime.settings", "app.agent.llm.capability -> app.schemas", "app.agent.llm.capability -> app.schemas.notification", "app.agent.llm.capability -> app.schemas.types", @@ -211,8 +211,8 @@ "app.agent.llm.helper -> app.agent.llm.gateway", "app.agent.llm.helper -> app.agent.llm.server_tools", "app.agent.llm.helper -> app.runtime", - "app.agent.llm.helper -> app.runtime.config", "app.agent.llm.helper -> app.runtime.log", + "app.agent.llm.helper -> app.runtime.settings", "app.agent.llm.provider -> app.agent", "app.agent.llm.provider -> app.agent.llm", "app.agent.llm.provider -> app.agent.llm.helper", @@ -221,8 +221,8 @@ "app.agent.llm.provider -> app.foundation", "app.agent.llm.provider -> app.foundation.singleton", "app.agent.llm.provider -> app.runtime", - "app.agent.llm.provider -> app.runtime.config", "app.agent.llm.provider -> app.runtime.log", + "app.agent.llm.provider -> app.runtime.settings", "app.agent.llm.provider -> app.schemas", "app.agent.llm.provider -> app.schemas.types", "app.agent.mcp -> app.adapters", @@ -352,10 +352,10 @@ "app.agent.orchestrator -> app.foundation", "app.agent.orchestrator -> app.foundation.identity", "app.agent.orchestrator -> app.runtime", - "app.agent.orchestrator -> app.runtime.config", "app.agent.orchestrator -> app.runtime.events", "app.agent.orchestrator -> app.runtime.log", "app.agent.orchestrator -> app.runtime.observability", + "app.agent.orchestrator -> app.runtime.settings", "app.agent.orchestrator -> app.schemas", "app.agent.orchestrator -> app.schemas.event", "app.agent.orchestrator -> app.schemas.message", @@ -422,10 +422,10 @@ "app.agent.tools.base -> app.application.messaging.agent", "app.agent.tools.base -> app.chain", "app.agent.tools.base -> app.runtime", - "app.agent.tools.base -> app.runtime.config", "app.agent.tools.base -> app.runtime.extensions", "app.agent.tools.base -> app.runtime.extensions.service_config", "app.agent.tools.base -> app.runtime.log", + "app.agent.tools.base -> app.runtime.settings", "app.agent.tools.base -> app.schemas", "app.agent.tools.base -> app.schemas.message", "app.agent.tools.base -> app.schemas.types", From 05d4ca79e712a50b9f1305d6f9d8917849046c72 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:51:25 +0800 Subject: [PATCH 06/22] refactor: route agent tool settings through runtime --- app/agent/skills/registry.py | 7 +++++-- app/agent/tools/impl/_plugin_tool_utils.py | 4 +++- app/agent/tools/impl/_terminal_session.py | 4 +++- app/agent/tools/impl/send_voice_message.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 6 +----- .../fixtures/architecture/dependency-baseline.json | 14 ++++++++------ 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/app/agent/skills/registry.py b/app/agent/skills/registry.py index 349b7d7d5..bd626d423 100644 --- a/app/agent/skills/registry.py +++ b/app/agent/skills/registry.py @@ -11,7 +11,10 @@ from urllib.parse import urlencode, urljoin, urlparse from app.agent.skills.metadata import parse_skill_metadata from app.runtime.cache import cached, fresh -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat +from app.application.configuration import get_runtime_settings + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.adapters.network.http import RequestUtils from app.foundation.singleton import WeakSingleton @@ -200,7 +203,7 @@ class SkillHelper(metaclass=WeakSingleton): 将技能源列表写回配置文件,并同步更新内存中的 settings。 """ filtered_sources = [item.strip() for item in sources if item and item.strip()] - success, message = settings.update_setting( + success, message = get_runtime_settings().update( key="SKILL_MARKET", value=",".join(filtered_sources), ) diff --git a/app/agent/tools/impl/_plugin_tool_utils.py b/app/agent/tools/impl/_plugin_tool_utils.py index f0e752cd6..cca3d5909 100644 --- a/app/agent/tools/impl/_plugin_tool_utils.py +++ b/app/agent/tools/impl/_plugin_tool_utils.py @@ -4,7 +4,9 @@ import json import shutil from typing import Any, Optional -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.plugin.runtime import get_plugin_manager from app.application.plugin.install import PluginInstallCommand from app.application.configuration import get_configured_system_config as SystemConfigOper diff --git a/app/agent/tools/impl/_terminal_session.py b/app/agent/tools/impl/_terminal_session.py index be57e2b7f..8126af25f 100644 --- a/app/agent/tools/impl/_terminal_session.py +++ b/app/agent/tools/impl/_terminal_session.py @@ -14,7 +14,9 @@ from pathlib import Path from typing import Any, Optional from app.agent.tools.impl._command_safety import validate_command_safety -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger if os.name == "posix": diff --git a/app/agent/tools/impl/send_voice_message.py b/app/agent/tools/impl/send_voice_message.py index eafecf34b..982336ac5 100644 --- a/app/agent/tools/impl/send_voice_message.py +++ b/app/agent/tools/impl/send_voice_message.py @@ -6,7 +6,9 @@ from pydantic import BaseModel, Field from app.agent.llm.capability import AgentCapabilityManager from app.agent.tools.base import MoviePilotTool from app.agent.tools.tags import ToolTag -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.message import Message from app.schemas.message import MessageType diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 47c8e05ea..e94871dad 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1050,6 +1050,8 @@ Agent 能力适配器、记忆和提示词模块改用 `RuntimeSettingsCompat` 导入早期回退;配置债务由 101 个文件降至 98 个,Agent 能力、提示词与运行时专项测试通过。 随后将 LLM capability/helper/provider、Agent orchestrator 和工具基础类统一切换到同一动态运行时端口; 配置债务由 98 个文件降至 93 个,LLM、Agent 生命周期与工具专项测试通过。 +技能注册表、插件工具辅助、终端会话和语音工具也已切换到动态运行时端口,技能市场写入改走配置服务; +配置债务由 93 个文件降至 89 个,技能、工具和安全专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 71a21a402..d9a2280af 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,19 +9,15 @@ "root": "app" }, "settings_imports": { - "count": 93, + "count": 89, "files": [ "app/adapters/system/fsproxy.py", - "app/agent/skills/registry.py", - "app/agent/tools/impl/_plugin_tool_utils.py", - "app/agent/tools/impl/_terminal_session.py", "app/agent/tools/impl/add_download_tasks.py", "app/agent/tools/impl/create_agent_task.py", "app/agent/tools/impl/query_agent_tasks.py", "app/agent/tools/impl/recognize_media.py", "app/agent/tools/impl/scrape_metadata.py", "app/agent/tools/impl/search_web.py", - "app/agent/tools/impl/send_voice_message.py", "app/agent/tools/impl/update_agent_task.py", "app/cli.py", "app/db/base.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index f529cc0e3..5fc684d7b 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6419, - "edge_sha256": "91e14e6acb6220fccd8ac3e2df899303f4e4fe6532c92079378d4b350be4d06e", + "edge_count": 6421, + "edge_sha256": "808e0a96b5cce123d86ce90ae4538258c6cc817a6204dc06346888c4f69d344b", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -404,13 +404,15 @@ "app.agent.skills.registry -> app.agent", "app.agent.skills.registry -> app.agent.skills", "app.agent.skills.registry -> app.agent.skills.metadata", + "app.agent.skills.registry -> app.application", + "app.agent.skills.registry -> app.application.configuration", "app.agent.skills.registry -> app.foundation", "app.agent.skills.registry -> app.foundation.singleton", "app.agent.skills.registry -> app.foundation.url", "app.agent.skills.registry -> app.runtime", "app.agent.skills.registry -> app.runtime.cache", - "app.agent.skills.registry -> app.runtime.config", "app.agent.skills.registry -> app.runtime.log", + "app.agent.skills.registry -> app.runtime.settings", "app.agent.tools.base -> app.agent", "app.agent.tools.base -> app.agent.callback", "app.agent.tools.base -> app.agent.policy", @@ -566,7 +568,7 @@ "app.agent.tools.impl._plugin_tool_utils -> app.application.plugin.runtime", "app.agent.tools.impl._plugin_tool_utils -> app.application.scheduling", "app.agent.tools.impl._plugin_tool_utils -> app.runtime", - "app.agent.tools.impl._plugin_tool_utils -> app.runtime.config", + "app.agent.tools.impl._plugin_tool_utils -> app.runtime.settings", "app.agent.tools.impl._plugin_tool_utils -> app.schemas", "app.agent.tools.impl._plugin_tool_utils -> app.schemas.plugin", "app.agent.tools.impl._plugin_tool_utils -> app.schemas.types", @@ -582,8 +584,8 @@ "app.agent.tools.impl._terminal_session -> app.agent.tools.impl", "app.agent.tools.impl._terminal_session -> app.agent.tools.impl._command_safety", "app.agent.tools.impl._terminal_session -> app.runtime", - "app.agent.tools.impl._terminal_session -> app.runtime.config", "app.agent.tools.impl._terminal_session -> app.runtime.log", + "app.agent.tools.impl._terminal_session -> app.runtime.settings", "app.agent.tools.impl._torrent_search_utils -> app.agent", "app.agent.tools.impl._torrent_search_utils -> app.agent.tools", "app.agent.tools.impl._torrent_search_utils -> app.agent.tools.impl", @@ -1313,8 +1315,8 @@ "app.agent.tools.impl.send_voice_message -> app.agent.tools.base", "app.agent.tools.impl.send_voice_message -> app.agent.tools.tags", "app.agent.tools.impl.send_voice_message -> app.runtime", - "app.agent.tools.impl.send_voice_message -> app.runtime.config", "app.agent.tools.impl.send_voice_message -> app.runtime.log", + "app.agent.tools.impl.send_voice_message -> app.runtime.settings", "app.agent.tools.impl.send_voice_message -> app.schemas", "app.agent.tools.impl.send_voice_message -> app.schemas.message", "app.agent.tools.impl.switch_persona -> app.agent", From d36795ec4dae50446127b2b383395c31a6579abe Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:53:48 +0800 Subject: [PATCH 07/22] refactor: route runtime extension settings through port --- app/runtime/extensions/module_manager.py | 4 +++- app/runtime/extensions/plugin/catalog.py | 4 +++- app/runtime/extensions/plugin_manager.py | 4 +++- app/runtime/state.py | 4 +++- app/runtime/thread.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 7 +------ tests/fixtures/architecture/dependency-baseline.json | 12 ++++++------ 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/runtime/extensions/module_manager.py b/app/runtime/extensions/module_manager.py index 9c57c3be2..94308cb39 100644 --- a/app/runtime/extensions/module_manager.py +++ b/app/runtime/extensions/module_manager.py @@ -12,7 +12,9 @@ from app.runtime.capabilities.model import ( CapabilitySpec, ) from app.runtime.capabilities.runtime import CapabilityRuntime -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.events import Event, EventHandlerBinding, eventmanager from app.runtime.extensions.host_module_adapter import ( HOST_MODULE_KIND, diff --git a/app/runtime/extensions/plugin/catalog.py b/app/runtime/extensions/plugin/catalog.py index b52542f29..7b6e26140 100644 --- a/app/runtime/extensions/plugin/catalog.py +++ b/app/runtime/extensions/plugin/catalog.py @@ -7,7 +7,9 @@ from collections.abc import Callable, Mapping from typing import Any, Optional from app.foundation.version import compare_version -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.extensions.plugin.contracts import supports_plugin_hook from app.runtime.extensions.plugin.storage import PluginStorage from app.runtime.extensions.plugin.system import PluginSystemServices diff --git a/app/runtime/extensions/plugin_manager.py b/app/runtime/extensions/plugin_manager.py index 93eab49ae..d593e6e71 100644 --- a/app/runtime/extensions/plugin_manager.py +++ b/app/runtime/extensions/plugin_manager.py @@ -15,7 +15,9 @@ from app.foundation.singleton import Singleton from app.foundation.version import compare_version from app.runtime.log import logger from app.runtime.observability import observe_compat_facade -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.events import EventHandlerBinding, eventmanager from app.runtime.reload import ConfigReloadMixin from app.runtime.extensions.plugin.loader import PluginLoader diff --git a/app/runtime/state.py b/app/runtime/state.py index c6e09521c..338933c31 100644 --- a/app/runtime/state.py +++ b/app/runtime/state.py @@ -11,7 +11,9 @@ from typing import Optional, Tuple import docker import psutil -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.runtime.reload import ConfigReloadMixin from app.foundation.environment import is_docker diff --git a/app/runtime/thread.py b/app/runtime/thread.py index 0209e4058..dbcac5b69 100644 --- a/app/runtime/thread.py +++ b/app/runtime/thread.py @@ -1,7 +1,9 @@ from concurrent.futures import ThreadPoolExecutor from contextvars import copy_context -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.foundation.singleton import Singleton diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index e94871dad..3ce5898e9 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1052,6 +1052,8 @@ Agent 能力适配器、记忆和提示词模块改用 `RuntimeSettingsCompat` 配置债务由 98 个文件降至 93 个,LLM、Agent 生命周期与工具专项测试通过。 技能注册表、插件工具辅助、终端会话和语音工具也已切换到动态运行时端口,技能市场写入改走配置服务; 配置债务由 93 个文件降至 89 个,技能、工具和安全专项测试通过。 +运行时状态、线程池、插件目录/管理器和模块管理器随后切换到同一动态运行时端口,保留旧模块覆盖语义; +配置债务由 89 个文件降至 84 个,插件、模块生命周期与线程安全专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index d9a2280af..e7664fa22 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 89, + "count": 84, "files": [ "app/adapters/system/fsproxy.py", "app/agent/tools/impl/add_download_tasks.py", @@ -88,11 +88,6 @@ "app/modules/wechat/wechatbot.py", "app/modules/wechatclawbot/wechatclawbot.py", "app/runtime/extensions/host_module_adapter.py", - "app/runtime/extensions/module_manager.py", - "app/runtime/extensions/plugin/catalog.py", - "app/runtime/extensions/plugin_manager.py", - "app/runtime/state.py", - "app/runtime/thread.py", "app/startup/agent_initializer.py", "app/startup/database.py", "app/startup/database_initializer.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 5fc684d7b..ee166e394 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6421, - "edge_sha256": "808e0a96b5cce123d86ce90ae4538258c6cc817a6204dc06346888c4f69d344b", + "edge_sha256": "466c1f146a2ce7403e60f32c98c7b33466b335dba3bfd2f756e7bef22a135e5e", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -5542,22 +5542,22 @@ "app.runtime.extensions.module_manager -> app.runtime.capabilities", "app.runtime.extensions.module_manager -> app.runtime.capabilities.model", "app.runtime.extensions.module_manager -> app.runtime.capabilities.runtime", - "app.runtime.extensions.module_manager -> app.runtime.config", "app.runtime.extensions.module_manager -> app.runtime.events", "app.runtime.extensions.module_manager -> app.runtime.extensions", "app.runtime.extensions.module_manager -> app.runtime.extensions.host_module_adapter", "app.runtime.extensions.module_manager -> app.runtime.log", + "app.runtime.extensions.module_manager -> app.runtime.settings", "app.runtime.extensions.module_manager -> app.schemas", "app.runtime.extensions.module_manager -> app.schemas.types", "app.runtime.extensions.plugin.catalog -> app.foundation", "app.runtime.extensions.plugin.catalog -> app.foundation.version", "app.runtime.extensions.plugin.catalog -> app.runtime", - "app.runtime.extensions.plugin.catalog -> app.runtime.config", "app.runtime.extensions.plugin.catalog -> app.runtime.extensions", "app.runtime.extensions.plugin.catalog -> app.runtime.extensions.plugin", "app.runtime.extensions.plugin.catalog -> app.runtime.extensions.plugin.contracts", "app.runtime.extensions.plugin.catalog -> app.runtime.extensions.plugin.storage", "app.runtime.extensions.plugin.catalog -> app.runtime.extensions.plugin.system", + "app.runtime.extensions.plugin.catalog -> app.runtime.settings", "app.runtime.extensions.plugin.catalog -> app.schemas", "app.runtime.extensions.plugin.catalog -> app.schemas.plugin", "app.runtime.extensions.plugin.catalog -> app.schemas.types", @@ -5610,7 +5610,6 @@ "app.runtime.extensions.plugin_manager -> app.foundation.singleton", "app.runtime.extensions.plugin_manager -> app.foundation.version", "app.runtime.extensions.plugin_manager -> app.runtime", - "app.runtime.extensions.plugin_manager -> app.runtime.config", "app.runtime.extensions.plugin_manager -> app.runtime.events", "app.runtime.extensions.plugin_manager -> app.runtime.extensions", "app.runtime.extensions.plugin_manager -> app.runtime.extensions.plugin", @@ -5632,6 +5631,7 @@ "app.runtime.extensions.plugin_manager -> app.runtime.log", "app.runtime.extensions.plugin_manager -> app.runtime.observability", "app.runtime.extensions.plugin_manager -> app.runtime.reload", + "app.runtime.extensions.plugin_manager -> app.runtime.settings", "app.runtime.extensions.plugin_manager -> app.schemas", "app.runtime.extensions.plugin_manager -> app.schemas.plugin", "app.runtime.extensions.plugin_manager -> app.schemas.types", @@ -5657,13 +5657,13 @@ "app.runtime.state -> app.foundation", "app.runtime.state -> app.foundation.environment", "app.runtime.state -> app.runtime", - "app.runtime.state -> app.runtime.config", "app.runtime.state -> app.runtime.log", "app.runtime.state -> app.runtime.reload", + "app.runtime.state -> app.runtime.settings", "app.runtime.thread -> app.foundation", "app.runtime.thread -> app.foundation.singleton", "app.runtime.thread -> app.runtime", - "app.runtime.thread -> app.runtime.config", + "app.runtime.thread -> app.runtime.settings", "app.scheduler -> app.adapters", "app.scheduler -> app.adapters.external", "app.scheduler -> app.adapters.external.server", From c5f0bd4fb72863d169ae24f5c0ddfaf4b7fb843a Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:57:19 +0800 Subject: [PATCH 08/22] refactor: route agent task settings through runtime --- app/agent/tools/impl/add_download_tasks.py | 4 +++- app/agent/tools/impl/create_agent_task.py | 4 +++- app/agent/tools/impl/query_agent_tasks.py | 4 +++- app/agent/tools/impl/recognize_media.py | 4 +++- app/agent/tools/impl/scrape_metadata.py | 4 +++- app/agent/tools/impl/search_web.py | 4 +++- app/agent/tools/impl/update_agent_task.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../configuration-debt-baseline.json | 9 +-------- .../architecture/dependency-baseline.json | 16 ++++++++-------- tests/test_architecture_contract_baseline.py | 4 ++-- 11 files changed, 34 insertions(+), 25 deletions(-) diff --git a/app/agent/tools/impl/add_download_tasks.py b/app/agent/tools/impl/add_download_tasks.py index 7b8e34f1c..c877e9c22 100644 --- a/app/agent/tools/impl/add_download_tasks.py +++ b/app/agent/tools/impl/add_download_tasks.py @@ -12,7 +12,9 @@ from app.agent.tools.tags import ToolTag from app.chain.download import DownloadChain from app.chain.media import MediaChain from app.chain.search import SearchChain -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import Context from app.domain.metainfo import MetaInfo from app.application.agentdata import SitePort as SiteOper diff --git a/app/agent/tools/impl/create_agent_task.py b/app/agent/tools/impl/create_agent_task.py index ebce7d3e1..ed2dafefa 100644 --- a/app/agent/tools/impl/create_agent_task.py +++ b/app/agent/tools/impl/create_agent_task.py @@ -7,7 +7,9 @@ from pydantic import BaseModel, Field, model_validator from app.agent.tools.base import MoviePilotTool from app.agent.tools.tags import ToolTag -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.agentdata import AgentChatPort as AgentChatOper from app.application.agentdata import AgentTaskPort as AgentTaskOper from app.runtime.scheduling import TimerUtils diff --git a/app/agent/tools/impl/query_agent_tasks.py b/app/agent/tools/impl/query_agent_tasks.py index f159c1c43..99a4a1269 100644 --- a/app/agent/tools/impl/query_agent_tasks.py +++ b/app/agent/tools/impl/query_agent_tasks.py @@ -5,7 +5,9 @@ from pydantic import BaseModel, Field from app.agent.tools.base import MoviePilotTool from app.agent.tools.tags import ToolTag -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.agentdata import AgentTaskPort as AgentTaskOper diff --git a/app/agent/tools/impl/recognize_media.py b/app/agent/tools/impl/recognize_media.py index a20591428..d37a2c7ae 100644 --- a/app/agent/tools/impl/recognize_media.py +++ b/app/agent/tools/impl/recognize_media.py @@ -9,7 +9,9 @@ from pydantic import BaseModel, Field from app.agent.tools.base import MoviePilotTool from app.agent.tools.tags import ToolTag from app.chain.media import MediaChain -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import Context from app.domain.meta.metamusic import MetaMusic from app.domain.metainfo import MetaInfo diff --git a/app/agent/tools/impl/scrape_metadata.py b/app/agent/tools/impl/scrape_metadata.py index 70340cb9e..d3a2a249d 100644 --- a/app/agent/tools/impl/scrape_metadata.py +++ b/app/agent/tools/impl/scrape_metadata.py @@ -10,7 +10,9 @@ from app.agent.tools.base import MoviePilotTool from app.agent.tools.tags import ToolTag from app.chain.media import MediaChain from app.chain.scraping import ScrapingChain -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.workflow import FileItem from app.schemas.types import ( diff --git a/app/agent/tools/impl/search_web.py b/app/agent/tools/impl/search_web.py index 9d6b270ec..2a30813fa 100644 --- a/app/agent/tools/impl/search_web.py +++ b/app/agent/tools/impl/search_web.py @@ -9,7 +9,9 @@ from pydantic import BaseModel, Field from app.agent.tools.base import MoviePilotTool from app.agent.tools.tags import ToolTag -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger # 搜索超时时间(秒) diff --git a/app/agent/tools/impl/update_agent_task.py b/app/agent/tools/impl/update_agent_task.py index 92898ab53..d0f931f2d 100644 --- a/app/agent/tools/impl/update_agent_task.py +++ b/app/agent/tools/impl/update_agent_task.py @@ -7,7 +7,9 @@ from pydantic import BaseModel, Field, model_validator from app.agent.tools.base import MoviePilotTool from app.agent.tools.tags import ToolTag -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.agentdata import AgentTaskPort as AgentTaskOper from app.runtime.scheduling import TimerUtils diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 3ce5898e9..aa5a09a21 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1054,6 +1054,8 @@ Agent 能力适配器、记忆和提示词模块改用 `RuntimeSettingsCompat` 配置债务由 93 个文件降至 89 个,技能、工具和安全专项测试通过。 运行时状态、线程池、插件目录/管理器和模块管理器随后切换到同一动态运行时端口,保留旧模块覆盖语义; 配置债务由 89 个文件降至 84 个,插件、模块生命周期与线程安全专项测试通过。 +Agent 下载、任务、媒体识别、刮削和 Web 搜索工具也切换到动态运行时端口,保留原工具输入与输出 ABI; +配置债务由 84 个文件降至 77 个,Agent 任务、搜索与识别专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index e7664fa22..acdbdd55b 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,16 +9,9 @@ "root": "app" }, "settings_imports": { - "count": 84, + "count": 77, "files": [ "app/adapters/system/fsproxy.py", - "app/agent/tools/impl/add_download_tasks.py", - "app/agent/tools/impl/create_agent_task.py", - "app/agent/tools/impl/query_agent_tasks.py", - "app/agent/tools/impl/recognize_media.py", - "app/agent/tools/impl/scrape_metadata.py", - "app/agent/tools/impl/search_web.py", - "app/agent/tools/impl/update_agent_task.py", "app/cli.py", "app/db/base.py", "app/db/engine.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index ee166e394..18b50e627 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6421, - "edge_sha256": "466c1f146a2ce7403e60f32c98c7b33466b335dba3bfd2f756e7bef22a135e5e", + "edge_sha256": "18448b750688670f90d17bc46bc5425dc481a12266b01d3e126f0da13fe12fb7", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -624,8 +624,8 @@ "app.agent.tools.impl.add_download_tasks -> app.foundation", "app.agent.tools.impl.add_download_tasks -> app.foundation.crypto", "app.agent.tools.impl.add_download_tasks -> app.runtime", - "app.agent.tools.impl.add_download_tasks -> app.runtime.config", "app.agent.tools.impl.add_download_tasks -> app.runtime.log", + "app.agent.tools.impl.add_download_tasks -> app.runtime.settings", "app.agent.tools.impl.add_download_tasks -> app.schemas", "app.agent.tools.impl.add_download_tasks -> app.schemas.file", "app.agent.tools.impl.add_rule_group -> app.agent", @@ -690,8 +690,8 @@ "app.agent.tools.impl.create_agent_task -> app.application.agentdata", "app.agent.tools.impl.create_agent_task -> app.application.scheduling", "app.agent.tools.impl.create_agent_task -> app.runtime", - "app.agent.tools.impl.create_agent_task -> app.runtime.config", "app.agent.tools.impl.create_agent_task -> app.runtime.scheduling", + "app.agent.tools.impl.create_agent_task -> app.runtime.settings", "app.agent.tools.impl.delete_agent_task -> app.agent", "app.agent.tools.impl.delete_agent_task -> app.agent.tools", "app.agent.tools.impl.delete_agent_task -> app.agent.tools.base", @@ -841,7 +841,7 @@ "app.agent.tools.impl.query_agent_tasks -> app.application.agentdata", "app.agent.tools.impl.query_agent_tasks -> app.application.scheduling", "app.agent.tools.impl.query_agent_tasks -> app.runtime", - "app.agent.tools.impl.query_agent_tasks -> app.runtime.config", + "app.agent.tools.impl.query_agent_tasks -> app.runtime.settings", "app.agent.tools.impl.query_builtin_filter_rules -> app.agent", "app.agent.tools.impl.query_builtin_filter_rules -> app.agent.tools", "app.agent.tools.impl.query_builtin_filter_rules -> app.agent.tools.base", @@ -1150,8 +1150,8 @@ "app.agent.tools.impl.recognize_media -> app.domain.meta.metamusic", "app.agent.tools.impl.recognize_media -> app.domain.metainfo", "app.agent.tools.impl.recognize_media -> app.runtime", - "app.agent.tools.impl.recognize_media -> app.runtime.config", "app.agent.tools.impl.recognize_media -> app.runtime.log", + "app.agent.tools.impl.recognize_media -> app.runtime.settings", "app.agent.tools.impl.recognize_media -> app.schemas", "app.agent.tools.impl.recognize_media -> app.schemas.types", "app.agent.tools.impl.reload_plugin -> app.agent", @@ -1212,8 +1212,8 @@ "app.agent.tools.impl.scrape_metadata -> app.domain", "app.agent.tools.impl.scrape_metadata -> app.domain.media", "app.agent.tools.impl.scrape_metadata -> app.runtime", - "app.agent.tools.impl.scrape_metadata -> app.runtime.config", "app.agent.tools.impl.scrape_metadata -> app.runtime.log", + "app.agent.tools.impl.scrape_metadata -> app.runtime.settings", "app.agent.tools.impl.scrape_metadata -> app.schemas", "app.agent.tools.impl.scrape_metadata -> app.schemas.media", "app.agent.tools.impl.scrape_metadata -> app.schemas.types", @@ -1287,8 +1287,8 @@ "app.agent.tools.impl.search_web -> app.agent.tools.base", "app.agent.tools.impl.search_web -> app.agent.tools.tags", "app.agent.tools.impl.search_web -> app.runtime", - "app.agent.tools.impl.search_web -> app.runtime.config", "app.agent.tools.impl.search_web -> app.runtime.log", + "app.agent.tools.impl.search_web -> app.runtime.settings", "app.agent.tools.impl.send_local_file -> app.agent", "app.agent.tools.impl.send_local_file -> app.agent.tools", "app.agent.tools.impl.send_local_file -> app.agent.tools.base", @@ -1365,8 +1365,8 @@ "app.agent.tools.impl.update_agent_task -> app.application.agentdata", "app.agent.tools.impl.update_agent_task -> app.application.scheduling", "app.agent.tools.impl.update_agent_task -> app.runtime", - "app.agent.tools.impl.update_agent_task -> app.runtime.config", "app.agent.tools.impl.update_agent_task -> app.runtime.scheduling", + "app.agent.tools.impl.update_agent_task -> app.runtime.settings", "app.agent.tools.impl.update_custom_filter_rule -> app.agent", "app.agent.tools.impl.update_custom_filter_rule -> app.agent.tools", "app.agent.tools.impl.update_custom_filter_rule -> app.agent.tools.base", diff --git a/tests/test_architecture_contract_baseline.py b/tests/test_architecture_contract_baseline.py index 5ac76c595..7f97abb5d 100644 --- a/tests/test_architecture_contract_baseline.py +++ b/tests/test_architecture_contract_baseline.py @@ -126,8 +126,8 @@ def test_transaction_debt_baseline_is_a_model_and_oper_ratchet() -> None: baseline = json.loads(baseline_path.read_text(encoding="utf-8")) assert baseline["schema_version"] == 1 - assert baseline["model_decorators"]["count"] == 117 - assert sum(baseline["model_decorators"]["by_kind"].values()) == 117 + assert baseline["model_decorators"]["count"] == 106 + assert sum(baseline["model_decorators"]["by_kind"].values()) == 106 assert baseline["model_decorators"]["by_kind"]["db_update"] == 0 assert baseline["model_decorators"]["by_kind"]["async_db_update"] == 0 assert baseline["model_transaction_calls"] == {"count": 0, "calls": []} From 4641db7f5ba1a22638c9aa41dc7b7c8660de012d Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:01:29 +0800 Subject: [PATCH 09/22] refactor: route metadata module settings through runtime --- app/modules/acoustid/__init__.py | 4 +++- app/modules/anilist/__init__.py | 4 +++- app/modules/anilist/anilist.py | 4 +++- app/modules/bangumi/__init__.py | 4 +++- app/modules/bangumi/bangumi.py | 4 +++- app/modules/douban/__init__.py | 4 +++- app/modules/douban/apiv2.py | 4 +++- app/modules/fanart/__init__.py | 4 +++- app/modules/imdb/__init__.py | 4 +++- app/modules/imdb/api.py | 4 +++- .../backend-architecture-next-stage.md | 2 ++ .../configuration-debt-baseline.json | 12 +--------- .../architecture/dependency-baseline.json | 22 +++++++++---------- 13 files changed, 44 insertions(+), 32 deletions(-) diff --git a/app/modules/acoustid/__init__.py b/app/modules/acoustid/__init__.py index c4862682b..44689c37e 100644 --- a/app/modules/acoustid/__init__.py +++ b/app/modules/acoustid/__init__.py @@ -9,7 +9,9 @@ from pathlib import Path from typing import Any, Optional, Tuple, Union from uuid import UUID -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules import _ModuleBase from app.schemas.types import ModuleType, OtherModulesType diff --git a/app/modules/anilist/__init__.py b/app/modules/anilist/__init__.py index 0cf9e419d..c74062667 100644 --- a/app/modules/anilist/__init__.py +++ b/app/modules/anilist/__init__.py @@ -1,7 +1,9 @@ from typing import List, Optional, Tuple, Union from app.schemas.context import MediaPerson as _SchemaMediaPerson -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo from app.domain.meta.metabase import MetaBase from app.domain.scraper import MediaScraperHelper diff --git a/app/modules/anilist/anilist.py b/app/modules/anilist/anilist.py index 7399343ad..f4d2195c8 100644 --- a/app/modules/anilist/anilist.py +++ b/app/modules/anilist/anilist.py @@ -2,7 +2,9 @@ from datetime import date from typing import Optional from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.adapters.network.http import AsyncRequestUtils, RequestUtils diff --git a/app/modules/bangumi/__init__.py b/app/modules/bangumi/__init__.py index 5a1348b9b..efe61921b 100644 --- a/app/modules/bangumi/__init__.py +++ b/app/modules/bangumi/__init__.py @@ -2,7 +2,9 @@ from dataclasses import dataclass from typing import Any, List, Optional, Tuple, Union from app.schemas.context import MediaPerson as _SchemaMediaPerson -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo from app.domain.meta.metabase import MetaBase from app.domain.scraper import MediaScraperHelper diff --git a/app/modules/bangumi/bangumi.py b/app/modules/bangumi/bangumi.py index 7862bc23f..8e2511f9a 100644 --- a/app/modules/bangumi/bangumi.py +++ b/app/modules/bangumi/bangumi.py @@ -4,7 +4,9 @@ from typing import Optional import requests from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.adapters.network.http import RequestUtils, AsyncRequestUtils diff --git a/app/modules/douban/__init__.py b/app/modules/douban/__init__.py index cdb8854f0..2f92d9661 100644 --- a/app/modules/douban/__init__.py +++ b/app/modules/douban/__init__.py @@ -4,7 +4,9 @@ from typing import Any, List, Optional, Tuple, Union import cn2an from app.schemas.context import MediaPerson as _SchemaMediaPerson -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import ( MediaInfo, MusicAlbumInfo, diff --git a/app/modules/douban/apiv2.py b/app/modules/douban/apiv2.py index 49ddeb46d..36c8a64c8 100644 --- a/app/modules/douban/apiv2.py +++ b/app/modules/douban/apiv2.py @@ -13,7 +13,9 @@ import requests from bs4 import BeautifulSoup from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.adapters.network.http import RequestUtils, AsyncRequestUtils from app.foundation.singleton import WeakSingleton diff --git a/app/modules/fanart/__init__.py b/app/modules/fanart/__init__.py index c1fe73ceb..73ff28b50 100644 --- a/app/modules/fanart/__init__.py +++ b/app/modules/fanart/__init__.py @@ -4,7 +4,9 @@ from typing import Optional, Tuple, Union from app.runtime.cache import cached from app.domain.context import MediaInfo -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules import _ModuleBase from app.schemas.types import MediaType, ModuleType, OtherModulesType diff --git a/app/modules/imdb/__init__.py b/app/modules/imdb/__init__.py index ec196f7fd..7a4077823 100644 --- a/app/modules/imdb/__init__.py +++ b/app/modules/imdb/__init__.py @@ -11,7 +11,9 @@ from app.domain.meta.metabase import MetaBase from app.domain.scraper import MediaScraperHelper from app.foundation.text import convert as zhconv_convert from app.modules import _ModuleBase -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.context import MediaCredit, MediaImageSet from app.schemas.media import normalize_media_source diff --git a/app/modules/imdb/api.py b/app/modules/imdb/api.py index a500cb929..912a31fc7 100644 --- a/app/modules/imdb/api.py +++ b/app/modules/imdb/api.py @@ -9,7 +9,9 @@ from pydantic import BaseModel, ConfigDict, Field, ValidationError from app.adapters.network.http import AsyncRequestUtils, RequestUtils from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger TModel = TypeVar("TModel", bound=BaseModel) diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index aa5a09a21..0361e406a 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1056,6 +1056,8 @@ Agent 能力适配器、记忆和提示词模块改用 `RuntimeSettingsCompat` 配置债务由 89 个文件降至 84 个,插件、模块生命周期与线程安全专项测试通过。 Agent 下载、任务、媒体识别、刮削和 Web 搜索工具也切换到动态运行时端口,保留原工具输入与输出 ABI; 配置债务由 84 个文件降至 77 个,Agent 任务、搜索与识别专项测试通过。 +AcoustID、AniList、Bangumi、Douban、Fanart 和 IMDb 模块族改用动态运行时端口,模块公开类与配置热读保持; +配置债务由 77 个文件降至 67 个,相关识别、浏览与刮削专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index acdbdd55b..b28d56165 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 77, + "count": 67, "files": [ "app/adapters/system/fsproxy.py", "app/cli.py", @@ -20,16 +20,8 @@ "app/doctor/runner.py", "app/factory.py", "app/main.py", - "app/modules/acoustid/__init__.py", - "app/modules/anilist/__init__.py", - "app/modules/anilist/anilist.py", - "app/modules/bangumi/__init__.py", - "app/modules/bangumi/bangumi.py", "app/modules/discord/discord.py", - "app/modules/douban/__init__.py", - "app/modules/douban/apiv2.py", "app/modules/emby/emby.py", - "app/modules/fanart/__init__.py", "app/modules/feishu/feishu.py", "app/modules/filemanager/module.py", "app/modules/filemanager/storages/alipan.py", @@ -39,8 +31,6 @@ "app/modules/filemanager/storages/smb.py", "app/modules/filemanager/storages/u115.py", "app/modules/filemanager/transhandler.py", - "app/modules/imdb/__init__.py", - "app/modules/imdb/api.py", "app/modules/indexer/parser/__init__.py", "app/modules/indexer/parser/rousi.py", "app/modules/indexer/spider/__init__.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 18b50e627..616efc46f 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6421, - "edge_sha256": "18448b750688670f90d17bc46bc5425dc481a12266b01d3e126f0da13fe12fb7", + "edge_sha256": "a5ef71ffebe71367bde1689ab0889db037c83cea53b85ee12ad0a79aa006f231", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -3881,8 +3881,8 @@ "app.modules.acoustid -> app.adapters.network.http", "app.modules.acoustid -> app.modules", "app.modules.acoustid -> app.runtime", - "app.modules.acoustid -> app.runtime.config", "app.modules.acoustid -> app.runtime.log", + "app.modules.acoustid -> app.runtime.settings", "app.modules.acoustid -> app.schemas", "app.modules.acoustid -> app.schemas.types", "app.modules.anilist -> app.domain", @@ -3894,8 +3894,8 @@ "app.modules.anilist -> app.modules", "app.modules.anilist -> app.modules.anilist.anilist", "app.modules.anilist -> app.runtime", - "app.modules.anilist -> app.runtime.config", "app.modules.anilist -> app.runtime.log", + "app.modules.anilist -> app.runtime.settings", "app.modules.anilist -> app.schemas", "app.modules.anilist -> app.schemas.context", "app.modules.anilist -> app.schemas.types", @@ -3904,8 +3904,8 @@ "app.modules.anilist.anilist -> app.adapters.network.http", "app.modules.anilist.anilist -> app.runtime", "app.modules.anilist.anilist -> app.runtime.cache", - "app.modules.anilist.anilist -> app.runtime.config", "app.modules.anilist.anilist -> app.runtime.log", + "app.modules.anilist.anilist -> app.runtime.settings", "app.modules.bangumi -> app.adapters", "app.modules.bangumi -> app.adapters.network", "app.modules.bangumi -> app.adapters.network.http", @@ -3918,8 +3918,8 @@ "app.modules.bangumi -> app.modules", "app.modules.bangumi -> app.modules.bangumi.bangumi", "app.modules.bangumi -> app.runtime", - "app.modules.bangumi -> app.runtime.config", "app.modules.bangumi -> app.runtime.log", + "app.modules.bangumi -> app.runtime.settings", "app.modules.bangumi -> app.schemas", "app.modules.bangumi -> app.schemas.context", "app.modules.bangumi -> app.schemas.types", @@ -3928,7 +3928,7 @@ "app.modules.bangumi.bangumi -> app.adapters.network.http", "app.modules.bangumi.bangumi -> app.runtime", "app.modules.bangumi.bangumi -> app.runtime.cache", - "app.modules.bangumi.bangumi -> app.runtime.config", + "app.modules.bangumi.bangumi -> app.runtime.settings", "app.modules.dingtalk -> app.domain", "app.modules.dingtalk -> app.domain.context", "app.modules.dingtalk -> app.modules", @@ -3986,10 +3986,10 @@ "app.modules.douban -> app.modules.douban.apiv2", "app.modules.douban -> app.modules.douban.scraper", "app.modules.douban -> app.runtime", - "app.modules.douban -> app.runtime.config", "app.modules.douban -> app.runtime.execution", "app.modules.douban -> app.runtime.log", "app.modules.douban -> app.runtime.rate", + "app.modules.douban -> app.runtime.settings", "app.modules.douban -> app.schemas", "app.modules.douban -> app.schemas.context", "app.modules.douban -> app.schemas.exception", @@ -4001,7 +4001,7 @@ "app.modules.douban.apiv2 -> app.foundation.singleton", "app.modules.douban.apiv2 -> app.runtime", "app.modules.douban.apiv2 -> app.runtime.cache", - "app.modules.douban.apiv2 -> app.runtime.config", + "app.modules.douban.apiv2 -> app.runtime.settings", "app.modules.douban.scraper -> app.domain", "app.modules.douban.scraper -> app.domain.context", "app.modules.douban.scraper -> app.foundation", @@ -4039,8 +4039,8 @@ "app.modules.fanart -> app.modules", "app.modules.fanart -> app.runtime", "app.modules.fanart -> app.runtime.cache", - "app.modules.fanart -> app.runtime.config", "app.modules.fanart -> app.runtime.log", + "app.modules.fanart -> app.runtime.settings", "app.modules.fanart -> app.schemas", "app.modules.fanart -> app.schemas.types", "app.modules.feishu -> app.application", @@ -4273,8 +4273,8 @@ "app.modules.imdb -> app.modules", "app.modules.imdb -> app.modules.imdb.api", "app.modules.imdb -> app.runtime", - "app.modules.imdb -> app.runtime.config", "app.modules.imdb -> app.runtime.log", + "app.modules.imdb -> app.runtime.settings", "app.modules.imdb -> app.schemas", "app.modules.imdb -> app.schemas.context", "app.modules.imdb -> app.schemas.media", @@ -4284,8 +4284,8 @@ "app.modules.imdb.api -> app.adapters.network.http", "app.modules.imdb.api -> app.runtime", "app.modules.imdb.api -> app.runtime.cache", - "app.modules.imdb.api -> app.runtime.config", "app.modules.imdb.api -> app.runtime.log", + "app.modules.imdb.api -> app.runtime.settings", "app.modules.indexer -> app.application", "app.modules.indexer -> app.application.site", "app.modules.indexer -> app.application.site.health", From 4098cc1eecf9ab790f3e14f9c8503ec739293da2 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:03:26 +0800 Subject: [PATCH 10/22] refactor: route music module settings through runtime --- app/modules/listenbrainz/__init__.py | 4 +++- app/modules/lrclib/__init__.py | 4 +++- app/modules/musicbrainz/__init__.py | 4 +++- app/modules/musicbrainz/music_cache.py | 4 +++- app/modules/theaudiodb/__init__.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 7 +------ tests/fixtures/architecture/dependency-baseline.json | 12 ++++++------ 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/modules/listenbrainz/__init__.py b/app/modules/listenbrainz/__init__.py index eaa8851e1..30f282265 100644 --- a/app/modules/listenbrainz/__init__.py +++ b/app/modules/listenbrainz/__init__.py @@ -1,7 +1,9 @@ from typing import Any, Optional, Tuple, Union from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MusicInfo from app.runtime.log import logger from app.modules import _ModuleBase diff --git a/app/modules/lrclib/__init__.py b/app/modules/lrclib/__init__.py index 2a8073d9e..44dc6c7f7 100644 --- a/app/modules/lrclib/__init__.py +++ b/app/modules/lrclib/__init__.py @@ -4,7 +4,9 @@ import time from typing import Any, Optional, Tuple, Union from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MusicInfo, MusicLyrics from app.domain.meta.metamusic import MetaMusic from app.runtime.log import logger diff --git a/app/modules/musicbrainz/__init__.py b/app/modules/musicbrainz/__init__.py index e9e74c3c8..324068f4a 100644 --- a/app/modules/musicbrainz/__init__.py +++ b/app/modules/musicbrainz/__init__.py @@ -8,7 +8,9 @@ from typing import Any, Iterable, Optional, Tuple, Union from requests import Session from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import ( MusicAlbumInfo, MusicArtistInfo, diff --git a/app/modules/musicbrainz/music_cache.py b/app/modules/musicbrainz/music_cache.py index 14f244be6..8b771df13 100644 --- a/app/modules/musicbrainz/music_cache.py +++ b/app/modules/musicbrainz/music_cache.py @@ -6,7 +6,9 @@ from time import time from typing import Optional from app.runtime.cache import FileCache, TTLCache -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MusicInfo from app.domain.meta.metamusic import MetaMusic from app.runtime.log import logger diff --git a/app/modules/theaudiodb/__init__.py b/app/modules/theaudiodb/__init__.py index 96f7d3809..6757363f9 100644 --- a/app/modules/theaudiodb/__init__.py +++ b/app/modules/theaudiodb/__init__.py @@ -1,7 +1,9 @@ from typing import Any, Optional, Tuple, Union from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import ( MusicAlbumInfo, MusicArtistInfo, diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 0361e406a..3c15923b6 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1058,6 +1058,8 @@ Agent 下载、任务、媒体识别、刮削和 Web 搜索工具也切换到动 配置债务由 84 个文件降至 77 个,Agent 任务、搜索与识别专项测试通过。 AcoustID、AniList、Bangumi、Douban、Fanart 和 IMDb 模块族改用动态运行时端口,模块公开类与配置热读保持; 配置债务由 77 个文件降至 67 个,相关识别、浏览与刮削专项测试通过。 +MusicBrainz、ListenBrainz、LrcLib 与 TheAudioDB 模块族也完成同样迁移,配置债务由 67 个文件降至 62 个, +音乐元数据专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index b28d56165..376a7cbab 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 67, + "count": 62, "files": [ "app/adapters/system/fsproxy.py", "app/cli.py", @@ -43,10 +43,6 @@ "app/modules/indexer/spider/torrentleech.py", "app/modules/indexer/spider/yema.py", "app/modules/jellyfin/jellyfin.py", - "app/modules/listenbrainz/__init__.py", - "app/modules/lrclib/__init__.py", - "app/modules/musicbrainz/__init__.py", - "app/modules/musicbrainz/music_cache.py", "app/modules/postgresql/__init__.py", "app/modules/qbittorrent/__init__.py", "app/modules/qqbot/qqbot.py", @@ -55,7 +51,6 @@ "app/modules/slack/slack.py", "app/modules/subtitle/__init__.py", "app/modules/telegram/telegram.py", - "app/modules/theaudiodb/__init__.py", "app/modules/themoviedb/__init__.py", "app/modules/themoviedb/category.py", "app/modules/themoviedb/scraper.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 616efc46f..2df6ab039 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6421, - "edge_sha256": "a5ef71ffebe71367bde1689ab0889db037c83cea53b85ee12ad0a79aa006f231", + "edge_sha256": "6b9946cab961b8c499aad349218832c54c0b581f86ba8dbd992d538534a0322f", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -4622,8 +4622,8 @@ "app.modules.listenbrainz -> app.modules", "app.modules.listenbrainz -> app.runtime", "app.modules.listenbrainz -> app.runtime.cache", - "app.modules.listenbrainz -> app.runtime.config", "app.modules.listenbrainz -> app.runtime.log", + "app.modules.listenbrainz -> app.runtime.settings", "app.modules.listenbrainz -> app.schemas", "app.modules.listenbrainz -> app.schemas.types", "app.modules.lrclib -> app.adapters", @@ -4636,8 +4636,8 @@ "app.modules.lrclib -> app.modules", "app.modules.lrclib -> app.runtime", "app.modules.lrclib -> app.runtime.cache", - "app.modules.lrclib -> app.runtime.config", "app.modules.lrclib -> app.runtime.log", + "app.modules.lrclib -> app.runtime.settings", "app.modules.lrclib -> app.schemas", "app.modules.lrclib -> app.schemas.types", "app.modules.musicbrainz -> app.adapters", @@ -4655,8 +4655,8 @@ "app.modules.musicbrainz -> app.modules.musicbrainz.music_cache", "app.modules.musicbrainz -> app.runtime", "app.modules.musicbrainz -> app.runtime.cache", - "app.modules.musicbrainz -> app.runtime.config", "app.modules.musicbrainz -> app.runtime.log", + "app.modules.musicbrainz -> app.runtime.settings", "app.modules.musicbrainz -> app.schemas", "app.modules.musicbrainz -> app.schemas.types", "app.modules.musicbrainz.music_cache -> app.domain", @@ -4667,8 +4667,8 @@ "app.modules.musicbrainz.music_cache -> app.foundation.singleton", "app.modules.musicbrainz.music_cache -> app.runtime", "app.modules.musicbrainz.music_cache -> app.runtime.cache", - "app.modules.musicbrainz.music_cache -> app.runtime.config", "app.modules.musicbrainz.music_cache -> app.runtime.log", + "app.modules.musicbrainz.music_cache -> app.runtime.settings", "app.modules.musicbrainz.music_cache -> app.schemas", "app.modules.musicbrainz.music_cache -> app.schemas.types", "app.modules.navidrome -> app.application", @@ -4935,8 +4935,8 @@ "app.modules.theaudiodb -> app.modules", "app.modules.theaudiodb -> app.runtime", "app.modules.theaudiodb -> app.runtime.cache", - "app.modules.theaudiodb -> app.runtime.config", "app.modules.theaudiodb -> app.runtime.log", + "app.modules.theaudiodb -> app.runtime.settings", "app.modules.theaudiodb -> app.schemas", "app.modules.theaudiodb -> app.schemas.types", "app.modules.themoviedb -> app.adapters", From ac32adc7b65bebe0d20d087948ee9e17dfb63432 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:09:59 +0800 Subject: [PATCH 11/22] refactor: route media and chat module settings through runtime --- app/modules/discord/discord.py | 4 +++- app/modules/emby/emby.py | 4 +++- app/modules/feishu/feishu.py | 4 +++- app/modules/jellyfin/jellyfin.py | 4 +++- app/modules/slack/slack.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 7 +------ tests/fixtures/architecture/dependency-baseline.json | 12 ++++++------ 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/modules/discord/discord.py b/app/modules/discord/discord.py index cb0fbb20c..13eaff162 100644 --- a/app/modules/discord/discord.py +++ b/app/modules/discord/discord.py @@ -9,7 +9,9 @@ import discord from discord import app_commands import httpx -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo, Context from app.domain.metainfo import MetaInfo from app.runtime.log import logger diff --git a/app/modules/emby/emby.py b/app/modules/emby/emby.py index e2041687c..a055ad0ca 100644 --- a/app/modules/emby/emby.py +++ b/app/modules/emby/emby.py @@ -14,7 +14,9 @@ from app.schemas.mediaserver import MediaServerLibrary as _SchemaMediaServerLibr from app.schemas.mediaserver import MediaServerPlayItem as _SchemaMediaServerPlayItem from app.schemas.mediaserver import RefreshMediaItem as _SchemaRefreshMediaItem from app.schemas.mediaserver import WebhookEventInfo as _SchemaWebhookEventInfo -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.mediaserver import MediaServerIdentityHelper, MusicMediaServerHelper from app.runtime.log import logger from app.schemas.mediaserver import MediaServerItem diff --git a/app/modules/feishu/feishu.py b/app/modules/feishu/feishu.py index f20b0380d..c3651d831 100644 --- a/app/modules/feishu/feishu.py +++ b/app/modules/feishu/feishu.py @@ -50,7 +50,9 @@ from lark_oapi.event.callback.model.p2_card_action_trigger import ( P2CardActionTriggerResponse, ) -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import Context, MediaInfo from app.application.security.user import get_configured_user_channel_lookup from app.application.messaging.agent import matches_channel_admin diff --git a/app/modules/jellyfin/jellyfin.py b/app/modules/jellyfin/jellyfin.py index 3ef28ee5f..037feae72 100644 --- a/app/modules/jellyfin/jellyfin.py +++ b/app/modules/jellyfin/jellyfin.py @@ -11,7 +11,9 @@ from app.schemas.mediaserver import MediaServerItemUserState as _SchemaMediaServ from app.schemas.mediaserver import MediaServerLibrary as _SchemaMediaServerLibrary from app.schemas.mediaserver import MediaServerPlayItem as _SchemaMediaServerPlayItem from app.schemas.mediaserver import WebhookEventInfo as _SchemaWebhookEventInfo -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.mediaserver import MediaServerIdentityHelper, MusicMediaServerHelper from app.runtime.log import logger from app.schemas.types import MediaType diff --git a/app/modules/slack/slack.py b/app/modules/slack/slack.py index e537a1bb4..2f88c32f9 100644 --- a/app/modules/slack/slack.py +++ b/app/modules/slack/slack.py @@ -10,7 +10,9 @@ from slack_bolt import App from slack_bolt.adapter.socket_mode import SocketModeHandler from slack_sdk import WebClient -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo, Context from app.domain.metainfo import MetaInfo from app.runtime.log import logger diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 3c15923b6..e78e115a1 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1060,6 +1060,8 @@ AcoustID、AniList、Bangumi、Douban、Fanart 和 IMDb 模块族改用动态运 配置债务由 77 个文件降至 67 个,相关识别、浏览与刮削专项测试通过。 MusicBrainz、ListenBrainz、LrcLib 与 TheAudioDB 模块族也完成同样迁移,配置债务由 67 个文件降至 62 个, 音乐元数据专项测试通过。 +Emby、Jellyfin、Feishu、Discord 与 Slack 模块切换到动态运行时配置,模块测试与消息生命周期 ABI 保持; +配置债务由 62 个文件降至 57 个,媒体服务器和消息模块专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 376a7cbab..d335a7a31 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 62, + "count": 57, "files": [ "app/adapters/system/fsproxy.py", "app/cli.py", @@ -20,9 +20,6 @@ "app/doctor/runner.py", "app/factory.py", "app/main.py", - "app/modules/discord/discord.py", - "app/modules/emby/emby.py", - "app/modules/feishu/feishu.py", "app/modules/filemanager/module.py", "app/modules/filemanager/storages/alipan.py", "app/modules/filemanager/storages/alist.py", @@ -42,13 +39,11 @@ "app/modules/indexer/spider/tnode.py", "app/modules/indexer/spider/torrentleech.py", "app/modules/indexer/spider/yema.py", - "app/modules/jellyfin/jellyfin.py", "app/modules/postgresql/__init__.py", "app/modules/qbittorrent/__init__.py", "app/modules/qqbot/qqbot.py", "app/modules/redis/__init__.py", "app/modules/rtorrent/__init__.py", - "app/modules/slack/slack.py", "app/modules/subtitle/__init__.py", "app/modules/telegram/telegram.py", "app/modules/themoviedb/__init__.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 2df6ab039..441805822 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6421, - "edge_sha256": "6b9946cab961b8c499aad349218832c54c0b581f86ba8dbd992d538534a0322f", + "edge_sha256": "2282230a3d14a429841f4f5a98da557808eb44c54e0b8bc2653a429fbd5f47de", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -3966,8 +3966,8 @@ "app.modules.discord.discord -> app.foundation", "app.modules.discord.discord -> app.foundation.size", "app.modules.discord.discord -> app.runtime", - "app.modules.discord.discord -> app.runtime.config", "app.modules.discord.discord -> app.runtime.log", + "app.modules.discord.discord -> app.runtime.settings", "app.modules.discord.discord -> app.schemas", "app.modules.discord.discord -> app.schemas.types", "app.modules.douban -> app.adapters", @@ -4025,8 +4025,8 @@ "app.modules.emby.emby -> app.foundation", "app.modules.emby.emby -> app.foundation.url", "app.modules.emby.emby -> app.runtime", - "app.modules.emby.emby -> app.runtime.config", "app.modules.emby.emby -> app.runtime.log", + "app.modules.emby.emby -> app.runtime.settings", "app.modules.emby.emby -> app.schemas", "app.modules.emby.emby -> app.schemas.dashboard", "app.modules.emby.emby -> app.schemas.mediaserver", @@ -4068,8 +4068,8 @@ "app.modules.feishu.feishu -> app.domain", "app.modules.feishu.feishu -> app.domain.context", "app.modules.feishu.feishu -> app.runtime", - "app.modules.feishu.feishu -> app.runtime.config", "app.modules.feishu.feishu -> app.runtime.log", + "app.modules.feishu.feishu -> app.runtime.settings", "app.modules.feishu.feishu -> app.schemas", "app.modules.feishu.feishu -> app.schemas.message", "app.modules.feishu.feishu -> app.schemas.types", @@ -4608,8 +4608,8 @@ "app.modules.jellyfin.jellyfin -> app.foundation", "app.modules.jellyfin.jellyfin -> app.foundation.url", "app.modules.jellyfin.jellyfin -> app.runtime", - "app.modules.jellyfin.jellyfin -> app.runtime.config", "app.modules.jellyfin.jellyfin -> app.runtime.log", + "app.modules.jellyfin.jellyfin -> app.runtime.settings", "app.modules.jellyfin.jellyfin -> app.schemas", "app.modules.jellyfin.jellyfin -> app.schemas.dashboard", "app.modules.jellyfin.jellyfin -> app.schemas.mediaserver", @@ -4845,8 +4845,8 @@ "app.modules.slack.slack -> app.foundation", "app.modules.slack.slack -> app.foundation.size", "app.modules.slack.slack -> app.runtime", - "app.modules.slack.slack -> app.runtime.config", "app.modules.slack.slack -> app.runtime.log", + "app.modules.slack.slack -> app.runtime.settings", "app.modules.subtitle -> app.adapters", "app.modules.subtitle -> app.adapters.network", "app.modules.subtitle -> app.adapters.network.http", From dd6405389cff71c671046f05dac5d423900391d2 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:12:51 +0800 Subject: [PATCH 12/22] refactor: route storage module settings through runtime --- app/modules/filemanager/module.py | 4 +++- app/modules/filemanager/storages/alipan.py | 5 ++++- app/modules/filemanager/storages/alist.py | 5 ++++- app/modules/filemanager/storages/rclone.py | 4 +++- app/modules/filemanager/storages/smb.py | 5 ++++- app/modules/filemanager/storages/u115.py | 5 ++++- app/modules/filemanager/transhandler.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 9 +-------- .../fixtures/architecture/dependency-baseline.json | 14 +++++++++----- 10 files changed, 37 insertions(+), 20 deletions(-) diff --git a/app/modules/filemanager/module.py b/app/modules/filemanager/module.py index 13c7d4cad..6d6113216 100644 --- a/app/modules/filemanager/module.py +++ b/app/modules/filemanager/module.py @@ -1,7 +1,9 @@ from pathlib import Path from typing import Any, Optional, List, Tuple, Union, Dict, Callable -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo, MusicInfo from app.domain.meta.metabase import MetaBase from app.domain.meta.metamusic import MetaMusic diff --git a/app/modules/filemanager/storages/alipan.py b/app/modules/filemanager/storages/alipan.py index 206b79fb1..c8afbb6d8 100644 --- a/app/modules/filemanager/storages/alipan.py +++ b/app/modules/filemanager/storages/alipan.py @@ -10,7 +10,10 @@ import requests from app.schemas.file import StorageUsage as _SchemaStorageUsage from app.schemas.workflow import FileItem as _SchemaFileItem -from app.runtime.config import settings, global_vars +from app.runtime.settings import RuntimeSettingsCompat +from app.runtime.config import global_vars + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules.filemanager import StorageBase from app.modules.filemanager.storages import transfer_process diff --git a/app/modules/filemanager/storages/alist.py b/app/modules/filemanager/storages/alist.py index 4b936abf6..c5177ce2c 100644 --- a/app/modules/filemanager/storages/alist.py +++ b/app/modules/filemanager/storages/alist.py @@ -8,7 +8,10 @@ from typing import Optional, List from app.schemas.file import StorageUsage as _SchemaStorageUsage from app.schemas.workflow import FileItem as _SchemaFileItem from app.runtime.cache import cached -from app.runtime.config import settings, global_vars +from app.runtime.settings import RuntimeSettingsCompat +from app.runtime.config import global_vars + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules.filemanager.storages import StorageBase, transfer_process from app.schemas.exception import OperationInterrupted, StorageQueryError diff --git a/app/modules/filemanager/storages/rclone.py b/app/modules/filemanager/storages/rclone.py index 19036c949..0a2995578 100644 --- a/app/modules/filemanager/storages/rclone.py +++ b/app/modules/filemanager/storages/rclone.py @@ -8,7 +8,9 @@ from typing import Optional, List, Union from app.schemas.file import StorageUsage as _SchemaStorageUsage from app.schemas.workflow import FileItem as _SchemaFileItem -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules.filemanager.storages import StorageBase, transfer_process from app.schemas.exception import StorageQueryError diff --git a/app/modules/filemanager/storages/smb.py b/app/modules/filemanager/storages/smb.py index a33e6b917..5f08d911b 100644 --- a/app/modules/filemanager/storages/smb.py +++ b/app/modules/filemanager/storages/smb.py @@ -14,7 +14,10 @@ from smbprotocol.exceptions import ( from app.schemas.file import StorageUsage as _SchemaStorageUsage from app.schemas.workflow import FileItem as _SchemaFileItem -from app.runtime.config import settings, global_vars +from app.runtime.settings import RuntimeSettingsCompat +from app.runtime.config import global_vars + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules.filemanager import StorageBase from app.modules.filemanager.storages import transfer_process diff --git a/app/modules/filemanager/storages/u115.py b/app/modules/filemanager/storages/u115.py index ea8003411..db90db3f5 100644 --- a/app/modules/filemanager/storages/u115.py +++ b/app/modules/filemanager/storages/u115.py @@ -14,7 +14,10 @@ from cryptography.hazmat.primitives import hashes from app.schemas.file import StorageUsage as _SchemaStorageUsage from app.schemas.workflow import FileItem as _SchemaFileItem -from app.runtime.config import settings, global_vars +from app.runtime.settings import RuntimeSettingsCompat +from app.runtime.config import global_vars + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules.filemanager import StorageBase from app.modules.filemanager.storages import transfer_process diff --git a/app/modules/filemanager/transhandler.py b/app/modules/filemanager/transhandler.py index 57042ddfd..2f7f5ff8d 100644 --- a/app/modules/filemanager/transhandler.py +++ b/app/modules/filemanager/transhandler.py @@ -4,7 +4,9 @@ from typing import Optional, List, Tuple from jinja2 import Template -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo, MusicInfo from app.runtime.events import eventmanager from app.domain.meta.metabase import MetaBase diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index e78e115a1..ec1a05cf3 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1062,6 +1062,8 @@ MusicBrainz、ListenBrainz、LrcLib 与 TheAudioDB 模块族也完成同样迁 音乐元数据专项测试通过。 Emby、Jellyfin、Feishu、Discord 与 Slack 模块切换到动态运行时配置,模块测试与消息生命周期 ABI 保持; 配置债务由 62 个文件降至 57 个,媒体服务器和消息模块专项测试通过。 +文件管理器及 Alist、Rclone、U115、SMB、Alipan 存储实现切换到动态运行时配置,保留模块级 global_vars 与 +存储公开方法;配置债务由 57 个文件降至 50 个,文件管理与存储专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index d335a7a31..f8a9eddbe 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 57, + "count": 50, "files": [ "app/adapters/system/fsproxy.py", "app/cli.py", @@ -20,14 +20,7 @@ "app/doctor/runner.py", "app/factory.py", "app/main.py", - "app/modules/filemanager/module.py", - "app/modules/filemanager/storages/alipan.py", - "app/modules/filemanager/storages/alist.py", "app/modules/filemanager/storages/local.py", - "app/modules/filemanager/storages/rclone.py", - "app/modules/filemanager/storages/smb.py", - "app/modules/filemanager/storages/u115.py", - "app/modules/filemanager/transhandler.py", "app/modules/indexer/parser/__init__.py", "app/modules/indexer/parser/rousi.py", "app/modules/indexer/spider/__init__.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 441805822..f4c5d91e0 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6421, - "edge_sha256": "2282230a3d14a429841f4f5a98da557808eb44c54e0b8bc2653a429fbd5f47de", + "edge_count": 6425, + "edge_sha256": "6cd4675c9165f8837860621c2f6c66574dc17e57d6b0b0421145e14b880e2257", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -4094,8 +4094,8 @@ "app.modules.filemanager.module -> app.modules.filemanager.storages", "app.modules.filemanager.module -> app.modules.filemanager.transhandler", "app.modules.filemanager.module -> app.runtime", - "app.modules.filemanager.module -> app.runtime.config", "app.modules.filemanager.module -> app.runtime.log", + "app.modules.filemanager.module -> app.runtime.settings", "app.modules.filemanager.module -> app.schemas", "app.modules.filemanager.module -> app.schemas.file", "app.modules.filemanager.module -> app.schemas.mediaserver", @@ -4128,6 +4128,7 @@ "app.modules.filemanager.storages.alipan -> app.runtime", "app.modules.filemanager.storages.alipan -> app.runtime.config", "app.modules.filemanager.storages.alipan -> app.runtime.log", + "app.modules.filemanager.storages.alipan -> app.runtime.settings", "app.modules.filemanager.storages.alipan -> app.schemas", "app.modules.filemanager.storages.alipan -> app.schemas.exception", "app.modules.filemanager.storages.alipan -> app.schemas.file", @@ -4146,6 +4147,7 @@ "app.modules.filemanager.storages.alist -> app.runtime.cache", "app.modules.filemanager.storages.alist -> app.runtime.config", "app.modules.filemanager.storages.alist -> app.runtime.log", + "app.modules.filemanager.storages.alist -> app.runtime.settings", "app.modules.filemanager.storages.alist -> app.schemas", "app.modules.filemanager.storages.alist -> app.schemas.exception", "app.modules.filemanager.storages.alist -> app.schemas.file", @@ -4183,8 +4185,8 @@ "app.modules.filemanager.storages.rclone -> app.modules.filemanager", "app.modules.filemanager.storages.rclone -> app.modules.filemanager.storages", "app.modules.filemanager.storages.rclone -> app.runtime", - "app.modules.filemanager.storages.rclone -> app.runtime.config", "app.modules.filemanager.storages.rclone -> app.runtime.log", + "app.modules.filemanager.storages.rclone -> app.runtime.settings", "app.modules.filemanager.storages.rclone -> app.schemas", "app.modules.filemanager.storages.rclone -> app.schemas.exception", "app.modules.filemanager.storages.rclone -> app.schemas.file", @@ -4198,6 +4200,7 @@ "app.modules.filemanager.storages.smb -> app.runtime", "app.modules.filemanager.storages.smb -> app.runtime.config", "app.modules.filemanager.storages.smb -> app.runtime.log", + "app.modules.filemanager.storages.smb -> app.runtime.settings", "app.modules.filemanager.storages.smb -> app.schemas", "app.modules.filemanager.storages.smb -> app.schemas.exception", "app.modules.filemanager.storages.smb -> app.schemas.file", @@ -4213,6 +4216,7 @@ "app.modules.filemanager.storages.u115 -> app.runtime.config", "app.modules.filemanager.storages.u115 -> app.runtime.log", "app.modules.filemanager.storages.u115 -> app.runtime.rate", + "app.modules.filemanager.storages.u115 -> app.runtime.settings", "app.modules.filemanager.storages.u115 -> app.schemas", "app.modules.filemanager.storages.u115 -> app.schemas.exception", "app.modules.filemanager.storages.u115 -> app.schemas.file", @@ -4236,9 +4240,9 @@ "app.modules.filemanager.transhandler -> app.modules.filemanager", "app.modules.filemanager.transhandler -> app.modules.filemanager.storages", "app.modules.filemanager.transhandler -> app.runtime", - "app.modules.filemanager.transhandler -> app.runtime.config", "app.modules.filemanager.transhandler -> app.runtime.events", "app.modules.filemanager.transhandler -> app.runtime.log", + "app.modules.filemanager.transhandler -> app.runtime.settings", "app.modules.filemanager.transhandler -> app.schemas", "app.modules.filemanager.transhandler -> app.schemas.event", "app.modules.filemanager.transhandler -> app.schemas.exception", From 55c80c87da26d5432fc1481ad76c79da3ec0ee89 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:15:21 +0800 Subject: [PATCH 13/22] refactor: route indexer module settings through runtime --- app/modules/indexer/parser/__init__.py | 4 +++- app/modules/indexer/parser/rousi.py | 6 +++-- app/modules/indexer/spider/__init__.py | 4 +++- app/modules/indexer/spider/haidan.py | 4 +++- app/modules/indexer/spider/hddolby.py | 4 +++- app/modules/indexer/spider/mtorrent.py | 4 +++- app/modules/indexer/spider/rousi.py | 4 +++- app/modules/indexer/spider/sunnypt.py | 4 +++- app/modules/indexer/spider/tnode.py | 4 +++- app/modules/indexer/spider/torrentleech.py | 4 +++- app/modules/indexer/spider/yema.py | 4 +++- .../backend-architecture-next-stage.md | 2 ++ .../configuration-debt-baseline.json | 13 +--------- .../architecture/dependency-baseline.json | 24 +++++++++---------- 14 files changed, 49 insertions(+), 36 deletions(-) diff --git a/app/modules/indexer/parser/__init__.py b/app/modules/indexer/parser/__init__.py index 2dad3d202..8247160aa 100644 --- a/app/modules/indexer/parser/__init__.py +++ b/app/modules/indexer/parser/__init__.py @@ -8,7 +8,9 @@ from urllib.parse import urljoin, urlsplit from requests import Session -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.adapters.network.cloudflare import under_challenge from app.runtime.log import logger from app.adapters.network.http import RequestUtils diff --git a/app/modules/indexer/parser/rousi.py b/app/modules/indexer/parser/rousi.py index 26d079ae7..28978b186 100644 --- a/app/modules/indexer/parser/rousi.py +++ b/app/modules/indexer/parser/rousi.py @@ -4,7 +4,9 @@ from urllib.parse import urljoin from typing import Optional, Tuple from app.runtime.log import logger -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.adapters.network.http import RequestUtils from app.domain import site as site_rules from app.foundation import temporal as time_tools @@ -232,4 +234,4 @@ class RousiSiteUserInfo(SiteParserBase): proxies=settings.PROXY if self._proxy else None ).post_res( url=urljoin(self._base_url, "api/messages/read-all") - ) \ No newline at end of file + ) diff --git a/app/modules/indexer/spider/__init__.py b/app/modules/indexer/spider/__init__.py index 24f768812..5f8e4f38b 100644 --- a/app/modules/indexer/spider/__init__.py +++ b/app/modules/indexer/spider/__init__.py @@ -9,7 +9,9 @@ from fastapi.concurrency import run_in_threadpool from jinja2 import Template from pyquery import PyQuery -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.types import MediaType from app.adapters.system import rust as rust_accel diff --git a/app/modules/indexer/spider/haidan.py b/app/modules/indexer/spider/haidan.py index 5ebba3885..bad502493 100644 --- a/app/modules/indexer/spider/haidan.py +++ b/app/modules/indexer/spider/haidan.py @@ -1,7 +1,9 @@ import urllib.parse from typing import Tuple, List -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.configuration import get_configured_system_config as SystemConfigOper from app.runtime.log import logger from app.schemas.types import MediaType diff --git a/app/modules/indexer/spider/hddolby.py b/app/modules/indexer/spider/hddolby.py index 1b60c3488..76367095b 100644 --- a/app/modules/indexer/spider/hddolby.py +++ b/app/modules/indexer/spider/hddolby.py @@ -1,6 +1,8 @@ from typing import Tuple, List, Optional -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.configuration import get_configured_system_config as SystemConfigOper from app.runtime.log import logger from app.schemas.types import MediaType diff --git a/app/modules/indexer/spider/mtorrent.py b/app/modules/indexer/spider/mtorrent.py index 4e4b8023c..cd5313604 100644 --- a/app/modules/indexer/spider/mtorrent.py +++ b/app/modules/indexer/spider/mtorrent.py @@ -4,7 +4,9 @@ import re from typing import Tuple, List, Optional from urllib.parse import urlparse -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.configuration import get_configured_system_config as SystemConfigOper from app.runtime.log import logger from app.schemas.types import MediaType diff --git a/app/modules/indexer/spider/rousi.py b/app/modules/indexer/spider/rousi.py index 342734ced..4040f585d 100644 --- a/app/modules/indexer/spider/rousi.py +++ b/app/modules/indexer/spider/rousi.py @@ -2,7 +2,9 @@ import base64 import json from typing import List, Optional, Tuple -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.configuration import get_configured_system_config as SystemConfigOper from app.runtime.log import logger from app.schemas.types import MediaType diff --git a/app/modules/indexer/spider/sunnypt.py b/app/modules/indexer/spider/sunnypt.py index b8aaac039..ea4d702a0 100644 --- a/app/modules/indexer/spider/sunnypt.py +++ b/app/modules/indexer/spider/sunnypt.py @@ -3,7 +3,9 @@ import json import time from typing import List, Optional, Tuple -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.types import MediaType from app.adapters.network.http import AsyncRequestUtils, RequestUtils diff --git a/app/modules/indexer/spider/tnode.py b/app/modules/indexer/spider/tnode.py index 19bbcd6c0..0773c5cd4 100644 --- a/app/modules/indexer/spider/tnode.py +++ b/app/modules/indexer/spider/tnode.py @@ -2,7 +2,9 @@ import re from typing import Tuple, List, Optional from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.adapters.network.http import RequestUtils, AsyncRequestUtils from app.foundation.singleton import SingletonClass diff --git a/app/modules/indexer/spider/torrentleech.py b/app/modules/indexer/spider/torrentleech.py index b50d8f1e2..54f98e772 100644 --- a/app/modules/indexer/spider/torrentleech.py +++ b/app/modules/indexer/spider/torrentleech.py @@ -1,7 +1,9 @@ from typing import List, Tuple, Optional from urllib.parse import quote -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.types import MediaType from app.adapters.network.http import RequestUtils, AsyncRequestUtils diff --git a/app/modules/indexer/spider/yema.py b/app/modules/indexer/spider/yema.py index 60a013cb7..4814cba36 100644 --- a/app/modules/indexer/spider/yema.py +++ b/app/modules/indexer/spider/yema.py @@ -2,7 +2,9 @@ import base64 import json from typing import List, Optional, Tuple -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.types import MediaType from app.adapters.network.http import AsyncRequestUtils, RequestUtils diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index ec1a05cf3..66a731b97 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1064,6 +1064,8 @@ Emby、Jellyfin、Feishu、Discord 与 Slack 模块切换到动态运行时配 配置债务由 62 个文件降至 57 个,媒体服务器和消息模块专项测试通过。 文件管理器及 Alist、Rclone、U115、SMB、Alipan 存储实现切换到动态运行时配置,保留模块级 global_vars 与 存储公开方法;配置债务由 57 个文件降至 50 个,文件管理与存储专项测试通过。 +Indexer parser/spider 模块族切换到动态运行时配置,站点搜索 URL、解析与分类行为保持;配置债务由 50 个文件 +降至 39 个,Indexer 专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index f8a9eddbe..9ce86e501 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 50, + "count": 39, "files": [ "app/adapters/system/fsproxy.py", "app/cli.py", @@ -21,17 +21,6 @@ "app/factory.py", "app/main.py", "app/modules/filemanager/storages/local.py", - "app/modules/indexer/parser/__init__.py", - "app/modules/indexer/parser/rousi.py", - "app/modules/indexer/spider/__init__.py", - "app/modules/indexer/spider/haidan.py", - "app/modules/indexer/spider/hddolby.py", - "app/modules/indexer/spider/mtorrent.py", - "app/modules/indexer/spider/rousi.py", - "app/modules/indexer/spider/sunnypt.py", - "app/modules/indexer/spider/tnode.py", - "app/modules/indexer/spider/torrentleech.py", - "app/modules/indexer/spider/yema.py", "app/modules/postgresql/__init__.py", "app/modules/qbittorrent/__init__.py", "app/modules/qqbot/qqbot.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index f4c5d91e0..c21f76dae 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6425, - "edge_sha256": "6cd4675c9165f8837860621c2f6c66574dc17e57d6b0b0421145e14b880e2257", + "edge_sha256": "06fb9c478770d0a27b22f8bcde92644fc5a2b14775446953716b4ed492b32042", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -4326,8 +4326,8 @@ "app.modules.indexer.parser -> app.foundation", "app.modules.indexer.parser -> app.foundation.size", "app.modules.indexer.parser -> app.runtime", - "app.modules.indexer.parser -> app.runtime.config", "app.modules.indexer.parser -> app.runtime.log", + "app.modules.indexer.parser -> app.runtime.settings", "app.modules.indexer.parser.bitpt -> app.foundation", "app.modules.indexer.parser.bitpt -> app.foundation.size", "app.modules.indexer.parser.bitpt -> app.foundation.temporal", @@ -4434,8 +4434,8 @@ "app.modules.indexer.parser.rousi -> app.modules.indexer", "app.modules.indexer.parser.rousi -> app.modules.indexer.parser", "app.modules.indexer.parser.rousi -> app.runtime", - "app.modules.indexer.parser.rousi -> app.runtime.config", "app.modules.indexer.parser.rousi -> app.runtime.log", + "app.modules.indexer.parser.rousi -> app.runtime.settings", "app.modules.indexer.parser.small_horse -> app.foundation", "app.modules.indexer.parser.small_horse -> app.foundation.dom", "app.modules.indexer.parser.small_horse -> app.foundation.size", @@ -4496,8 +4496,8 @@ "app.modules.indexer.spider -> app.foundation.temporal", "app.modules.indexer.spider -> app.foundation.url", "app.modules.indexer.spider -> app.runtime", - "app.modules.indexer.spider -> app.runtime.config", "app.modules.indexer.spider -> app.runtime.log", + "app.modules.indexer.spider -> app.runtime.settings", "app.modules.indexer.spider -> app.schemas", "app.modules.indexer.spider -> app.schemas.types", "app.modules.indexer.spider.haidan -> app.adapters", @@ -4510,8 +4510,8 @@ "app.modules.indexer.spider.haidan -> app.foundation", "app.modules.indexer.spider.haidan -> app.foundation.temporal", "app.modules.indexer.spider.haidan -> app.runtime", - "app.modules.indexer.spider.haidan -> app.runtime.config", "app.modules.indexer.spider.haidan -> app.runtime.log", + "app.modules.indexer.spider.haidan -> app.runtime.settings", "app.modules.indexer.spider.haidan -> app.schemas", "app.modules.indexer.spider.haidan -> app.schemas.types", "app.modules.indexer.spider.hddolby -> app.adapters", @@ -4522,8 +4522,8 @@ "app.modules.indexer.spider.hddolby -> app.domain", "app.modules.indexer.spider.hddolby -> app.domain.site", "app.modules.indexer.spider.hddolby -> app.runtime", - "app.modules.indexer.spider.hddolby -> app.runtime.config", "app.modules.indexer.spider.hddolby -> app.runtime.log", + "app.modules.indexer.spider.hddolby -> app.runtime.settings", "app.modules.indexer.spider.hddolby -> app.schemas", "app.modules.indexer.spider.hddolby -> app.schemas.types", "app.modules.indexer.spider.mtorrent -> app.adapters", @@ -4536,8 +4536,8 @@ "app.modules.indexer.spider.mtorrent -> app.foundation", "app.modules.indexer.spider.mtorrent -> app.foundation.temporal", "app.modules.indexer.spider.mtorrent -> app.runtime", - "app.modules.indexer.spider.mtorrent -> app.runtime.config", "app.modules.indexer.spider.mtorrent -> app.runtime.log", + "app.modules.indexer.spider.mtorrent -> app.runtime.settings", "app.modules.indexer.spider.mtorrent -> app.schemas", "app.modules.indexer.spider.mtorrent -> app.schemas.types", "app.modules.indexer.spider.rousi -> app.adapters", @@ -4550,8 +4550,8 @@ "app.modules.indexer.spider.rousi -> app.foundation", "app.modules.indexer.spider.rousi -> app.foundation.temporal", "app.modules.indexer.spider.rousi -> app.runtime", - "app.modules.indexer.spider.rousi -> app.runtime.config", "app.modules.indexer.spider.rousi -> app.runtime.log", + "app.modules.indexer.spider.rousi -> app.runtime.settings", "app.modules.indexer.spider.rousi -> app.schemas", "app.modules.indexer.spider.rousi -> app.schemas.types", "app.modules.indexer.spider.sunnypt -> app.adapters", @@ -4560,8 +4560,8 @@ "app.modules.indexer.spider.sunnypt -> app.foundation", "app.modules.indexer.spider.sunnypt -> app.foundation.temporal", "app.modules.indexer.spider.sunnypt -> app.runtime", - "app.modules.indexer.spider.sunnypt -> app.runtime.config", "app.modules.indexer.spider.sunnypt -> app.runtime.log", + "app.modules.indexer.spider.sunnypt -> app.runtime.settings", "app.modules.indexer.spider.sunnypt -> app.schemas", "app.modules.indexer.spider.sunnypt -> app.schemas.types", "app.modules.indexer.spider.tnode -> app.adapters", @@ -4572,8 +4572,8 @@ "app.modules.indexer.spider.tnode -> app.foundation.temporal", "app.modules.indexer.spider.tnode -> app.runtime", "app.modules.indexer.spider.tnode -> app.runtime.cache", - "app.modules.indexer.spider.tnode -> app.runtime.config", "app.modules.indexer.spider.tnode -> app.runtime.log", + "app.modules.indexer.spider.tnode -> app.runtime.settings", "app.modules.indexer.spider.torrentleech -> app.adapters", "app.modules.indexer.spider.torrentleech -> app.adapters.network", "app.modules.indexer.spider.torrentleech -> app.adapters.network.http", @@ -4581,8 +4581,8 @@ "app.modules.indexer.spider.torrentleech -> app.foundation.temporal", "app.modules.indexer.spider.torrentleech -> app.foundation.text", "app.modules.indexer.spider.torrentleech -> app.runtime", - "app.modules.indexer.spider.torrentleech -> app.runtime.config", "app.modules.indexer.spider.torrentleech -> app.runtime.log", + "app.modules.indexer.spider.torrentleech -> app.runtime.settings", "app.modules.indexer.spider.torrentleech -> app.schemas", "app.modules.indexer.spider.torrentleech -> app.schemas.types", "app.modules.indexer.spider.yema -> app.adapters", @@ -4591,8 +4591,8 @@ "app.modules.indexer.spider.yema -> app.foundation", "app.modules.indexer.spider.yema -> app.foundation.temporal", "app.modules.indexer.spider.yema -> app.runtime", - "app.modules.indexer.spider.yema -> app.runtime.config", "app.modules.indexer.spider.yema -> app.runtime.log", + "app.modules.indexer.spider.yema -> app.runtime.settings", "app.modules.indexer.spider.yema -> app.schemas", "app.modules.indexer.spider.yema -> app.schemas.types", "app.modules.jellyfin -> app.modules", From 061a92eab08725f151152ecc99b82dd9a78cd50a Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:17:40 +0800 Subject: [PATCH 14/22] refactor: route chat and subtitle settings through runtime --- app/modules/qqbot/qqbot.py | 4 +++- app/modules/subtitle/__init__.py | 4 +++- app/modules/telegram/telegram.py | 4 +++- app/modules/wechat/wechatbot.py | 4 +++- app/modules/wechatclawbot/wechatclawbot.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 7 +------ tests/fixtures/architecture/dependency-baseline.json | 12 ++++++------ 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/modules/qqbot/qqbot.py b/app/modules/qqbot/qqbot.py index 63b3c4727..5c4b84ffa 100644 --- a/app/modules/qqbot/qqbot.py +++ b/app/modules/qqbot/qqbot.py @@ -12,7 +12,9 @@ from typing import Optional, List, Tuple from PIL import Image from app.runtime.cache import FileCache -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo, Context from app.domain.metainfo import MetaInfo from app.runtime.log import logger diff --git a/app/modules/subtitle/__init__.py b/app/modules/subtitle/__init__.py index 59f1bb953..d0ddfc65b 100644 --- a/app/modules/subtitle/__init__.py +++ b/app/modules/subtitle/__init__.py @@ -4,7 +4,9 @@ from urllib.parse import urljoin, urlparse from lxml import etree -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import Context from app.application.site.query import get_configured_site_query_service from app.application.site.sites import SitesHelper # pylint: disable=import-error,no-name-in-module diff --git a/app/modules/telegram/telegram.py b/app/modules/telegram/telegram.py index 181d4cc29..96ab59713 100644 --- a/app/modules/telegram/telegram.py +++ b/app/modules/telegram/telegram.py @@ -36,7 +36,9 @@ try: except ImportError: from telegramify_markdown.type import ContentTypes, File, Photo, Text # noqa: E402 -from app.runtime.config import settings # noqa: E402 +from app.runtime.settings import RuntimeSettingsCompat # noqa: E402 + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo, Context # noqa: E402 from app.domain.metainfo import MetaInfo # noqa: E402 from app.application.image import ImageHelper # noqa: E402 diff --git a/app/modules/wechat/wechatbot.py b/app/modules/wechat/wechatbot.py index 1b48648cf..a970c221c 100644 --- a/app/modules/wechat/wechatbot.py +++ b/app/modules/wechat/wechatbot.py @@ -12,7 +12,9 @@ import websocket from Crypto.Cipher import AES from app.runtime.cache import FileCache -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo, Context from app.domain.metainfo import MetaInfo from app.application.messaging.agent import matches_channel_admin diff --git a/app/modules/wechatclawbot/wechatclawbot.py b/app/modules/wechatclawbot/wechatclawbot.py index efafe34a3..01ffbf232 100644 --- a/app/modules/wechatclawbot/wechatclawbot.py +++ b/app/modules/wechatclawbot/wechatclawbot.py @@ -17,7 +17,9 @@ from Crypto.Cipher import AES from Crypto.Util.Padding import pad from app.runtime.cache import FileCache -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import Context, MediaInfo from app.domain.metainfo import MetaInfo from app.runtime.log import logger diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 66a731b97..bfdac7bcd 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1066,6 +1066,8 @@ Emby、Jellyfin、Feishu、Discord 与 Slack 模块切换到动态运行时配 存储公开方法;配置债务由 57 个文件降至 50 个,文件管理与存储专项测试通过。 Indexer parser/spider 模块族切换到动态运行时配置,站点搜索 URL、解析与分类行为保持;配置债务由 50 个文件 降至 39 个,Indexer 专项测试通过。 +QQ、Telegram、WeChat、WeChatClawBot 与字幕模块切换到动态运行时配置,消息回调、代理和字幕下载行为保持; +配置债务由 39 个文件降至 34 个,消息与字幕专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 9ce86e501..7e0d3da22 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 39, + "count": 34, "files": [ "app/adapters/system/fsproxy.py", "app/cli.py", @@ -23,11 +23,8 @@ "app/modules/filemanager/storages/local.py", "app/modules/postgresql/__init__.py", "app/modules/qbittorrent/__init__.py", - "app/modules/qqbot/qqbot.py", "app/modules/redis/__init__.py", "app/modules/rtorrent/__init__.py", - "app/modules/subtitle/__init__.py", - "app/modules/telegram/telegram.py", "app/modules/themoviedb/__init__.py", "app/modules/themoviedb/category.py", "app/modules/themoviedb/scraper.py", @@ -40,8 +37,6 @@ "app/modules/transmission/__init__.py", "app/modules/trimemedia/api.py", "app/modules/webpush/__init__.py", - "app/modules/wechat/wechatbot.py", - "app/modules/wechatclawbot/wechatclawbot.py", "app/runtime/extensions/host_module_adapter.py", "app/startup/agent_initializer.py", "app/startup/database.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index c21f76dae..e1252b0bd 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6425, - "edge_sha256": "06fb9c478770d0a27b22f8bcde92644fc5a2b14775446953716b4ed492b32042", + "edge_sha256": "41afc9f5275b7f406e8ab4dd240d9af5bd01dd2e7537431e221558db2b9e593e", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -4797,8 +4797,8 @@ "app.modules.qqbot.qqbot -> app.modules.qqbot.gateway", "app.modules.qqbot.qqbot -> app.runtime", "app.modules.qqbot.qqbot -> app.runtime.cache", - "app.modules.qqbot.qqbot -> app.runtime.config", "app.modules.qqbot.qqbot -> app.runtime.log", + "app.modules.qqbot.qqbot -> app.runtime.settings", "app.modules.redis -> app.adapters", "app.modules.redis -> app.adapters.cache", "app.modules.redis -> app.adapters.cache.redis", @@ -4861,8 +4861,8 @@ "app.modules.subtitle -> app.domain.context", "app.modules.subtitle -> app.modules", "app.modules.subtitle -> app.runtime", - "app.modules.subtitle -> app.runtime.config", "app.modules.subtitle -> app.runtime.log", + "app.modules.subtitle -> app.runtime.settings", "app.modules.subtitle -> app.schemas", "app.modules.subtitle -> app.schemas.types", "app.modules.synologychat -> app.adapters", @@ -4923,9 +4923,9 @@ "app.modules.telegram.telegram -> app.modules.telegram", "app.modules.telegram.telegram -> app.modules.telegram.compat", "app.modules.telegram.telegram -> app.runtime", - "app.modules.telegram.telegram -> app.runtime.config", "app.modules.telegram.telegram -> app.runtime.execution", "app.modules.telegram.telegram -> app.runtime.log", + "app.modules.telegram.telegram -> app.runtime.settings", "app.modules.telegram.telegram -> app.runtime.thread", "app.modules.theaudiodb -> app.adapters", "app.modules.theaudiodb -> app.adapters.network", @@ -5322,8 +5322,8 @@ "app.modules.wechat.wechatbot -> app.foundation.size", "app.modules.wechat.wechatbot -> app.runtime", "app.modules.wechat.wechatbot -> app.runtime.cache", - "app.modules.wechat.wechatbot -> app.runtime.config", "app.modules.wechat.wechatbot -> app.runtime.log", + "app.modules.wechat.wechatbot -> app.runtime.settings", "app.modules.wechat.wechatbot -> app.schemas", "app.modules.wechat.wechatbot -> app.schemas.message", "app.modules.wechat.wechatbot -> app.schemas.types", @@ -5351,8 +5351,8 @@ "app.modules.wechatclawbot.wechatclawbot -> app.foundation.size", "app.modules.wechatclawbot.wechatclawbot -> app.runtime", "app.modules.wechatclawbot.wechatclawbot -> app.runtime.cache", - "app.modules.wechatclawbot.wechatclawbot -> app.runtime.config", "app.modules.wechatclawbot.wechatclawbot -> app.runtime.log", + "app.modules.wechatclawbot.wechatclawbot -> app.runtime.settings", "app.modules.zspace -> app.modules", "app.modules.zspace -> app.modules._base", "app.modules.zspace -> app.modules.zspace.zspace", From c89066d96fdcbbfbc5a5d745cdb2a92a15477af7 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:20:03 +0800 Subject: [PATCH 15/22] refactor: route media source settings through runtime --- app/modules/themoviedb/__init__.py | 4 +++- app/modules/themoviedb/category.py | 4 +++- app/modules/themoviedb/scraper.py | 4 +++- app/modules/themoviedb/tmdb_cache.py | 4 +++- app/modules/themoviedb/tmdbapi.py | 4 +++- .../themoviedb/tmdbv3api/objs/discover.py | 4 +++- app/modules/themoviedb/tmdbv3api/tmdb.py | 4 +++- app/modules/thetvdb/__init__.py | 4 +++- app/modules/thetvdb/tvdb_v4_official.py | 4 +++- app/modules/trimemedia/api.py | 4 +++- .../backend-architecture-next-stage.md | 2 ++ .../configuration-debt-baseline.json | 12 +--------- .../architecture/dependency-baseline.json | 22 +++++++++---------- 13 files changed, 44 insertions(+), 32 deletions(-) diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index 224410119..6ba124ede 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -6,7 +6,9 @@ import cn2an from app.schemas.context import MediaPerson as _SchemaMediaPerson from app.schemas.tmdb import TmdbSeason as _SchemaTmdbSeason from app.schemas.tmdb import TmdbEpisode as _SchemaTmdbEpisode -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo from app.domain.meta.metabase import MetaBase from app.runtime.log import logger diff --git a/app/modules/themoviedb/category.py b/app/modules/themoviedb/category.py index b252375e5..a22fdf92c 100644 --- a/app/modules/themoviedb/category.py +++ b/app/modules/themoviedb/category.py @@ -5,7 +5,9 @@ from typing import Union import ruamel.yaml from ruamel.yaml import CommentedMap -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.category import CategoryConfig from app.foundation.singleton import WeakSingleton diff --git a/app/modules/themoviedb/scraper.py b/app/modules/themoviedb/scraper.py index f58059b98..eb57265bd 100644 --- a/app/modules/themoviedb/scraper.py +++ b/app/modules/themoviedb/scraper.py @@ -2,7 +2,9 @@ from pathlib import Path from typing import Optional, Tuple from xml.dom import minidom -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.context import MediaInfo from app.domain.meta.metabase import MetaBase from app.schemas.types import MediaType diff --git a/app/modules/themoviedb/tmdb_cache.py b/app/modules/themoviedb/tmdb_cache.py index 0c23515bd..8b354f9a3 100644 --- a/app/modules/themoviedb/tmdb_cache.py +++ b/app/modules/themoviedb/tmdb_cache.py @@ -6,7 +6,9 @@ from time import time from typing import Any, Optional from app.runtime.cache import FileCache, TTLCache -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.domain.meta.metabase import MetaBase from app.runtime.log import logger from app.schemas.types import MediaSource, MediaType diff --git a/app/modules/themoviedb/tmdbapi.py b/app/modules/themoviedb/tmdbapi.py index 859fda704..badb5aeb8 100644 --- a/app/modules/themoviedb/tmdbapi.py +++ b/app/modules/themoviedb/tmdbapi.py @@ -2,7 +2,9 @@ import re import traceback from typing import Optional, List -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.schemas.types import MediaType from app.foundation import text as text_tools diff --git a/app/modules/themoviedb/tmdbv3api/objs/discover.py b/app/modules/themoviedb/tmdbv3api/objs/discover.py index f9d59da01..42eaaa2d7 100644 --- a/app/modules/themoviedb/tmdbv3api/objs/discover.py +++ b/app/modules/themoviedb/tmdbv3api/objs/discover.py @@ -1,5 +1,7 @@ from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from ..tmdb import TMDb try: diff --git a/app/modules/themoviedb/tmdbv3api/tmdb.py b/app/modules/themoviedb/tmdbv3api/tmdb.py index 1b7b39ed3..f72f1bf60 100644 --- a/app/modules/themoviedb/tmdbv3api/tmdb.py +++ b/app/modules/themoviedb/tmdbv3api/tmdb.py @@ -10,7 +10,9 @@ import requests import requests.exceptions from app.runtime.cache import cached, fresh, async_fresh -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.adapters.network.http import RequestUtils, AsyncRequestUtils from .exceptions import TMDbException, TMDbConnectionError diff --git a/app/modules/thetvdb/__init__.py b/app/modules/thetvdb/__init__.py index 06b68f534..065be8b02 100644 --- a/app/modules/thetvdb/__init__.py +++ b/app/modules/thetvdb/__init__.py @@ -1,7 +1,9 @@ from threading import Lock from typing import Optional, Tuple, Union -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules import _ModuleBase from app.modules.thetvdb import tvdb_v4_official diff --git a/app/modules/thetvdb/tvdb_v4_official.py b/app/modules/thetvdb/tvdb_v4_official.py index 13dcbbb90..a862a794a 100644 --- a/app/modules/thetvdb/tvdb_v4_official.py +++ b/app/modules/thetvdb/tvdb_v4_official.py @@ -8,7 +8,9 @@ import urllib.parse from http import HTTPStatus from app.runtime.cache import cached -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.adapters.network.http import RequestUtils diff --git a/app/modules/trimemedia/api.py b/app/modules/trimemedia/api.py index 5218cfb79..4a6372eb8 100644 --- a/app/modules/trimemedia/api.py +++ b/app/modules/trimemedia/api.py @@ -7,7 +7,9 @@ from enum import Enum from typing import List, Optional, Union from urllib.parse import quote -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.adapters.network.http import RequestUtils, requests diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index bfdac7bcd..fb7d0a83f 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1068,6 +1068,8 @@ Indexer parser/spider 模块族切换到动态运行时配置,站点搜索 URL 降至 39 个,Indexer 专项测试通过。 QQ、Telegram、WeChat、WeChatClawBot 与字幕模块切换到动态运行时配置,消息回调、代理和字幕下载行为保持; 配置债务由 39 个文件降至 34 个,消息与字幕专项测试通过。 +TMDB、TVDB 与 TriMedia 模块切换到动态运行时配置,缓存、重试、媒体源和登录兼容行为保持;配置债务由 34 个 +文件降至 24 个,TMDB、媒体源与 TriMedia 专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 7e0d3da22..74df363a5 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 34, + "count": 24, "files": [ "app/adapters/system/fsproxy.py", "app/cli.py", @@ -25,17 +25,7 @@ "app/modules/qbittorrent/__init__.py", "app/modules/redis/__init__.py", "app/modules/rtorrent/__init__.py", - "app/modules/themoviedb/__init__.py", - "app/modules/themoviedb/category.py", - "app/modules/themoviedb/scraper.py", - "app/modules/themoviedb/tmdb_cache.py", - "app/modules/themoviedb/tmdbapi.py", - "app/modules/themoviedb/tmdbv3api/objs/discover.py", - "app/modules/themoviedb/tmdbv3api/tmdb.py", - "app/modules/thetvdb/__init__.py", - "app/modules/thetvdb/tvdb_v4_official.py", "app/modules/transmission/__init__.py", - "app/modules/trimemedia/api.py", "app/modules/webpush/__init__.py", "app/runtime/extensions/host_module_adapter.py", "app/startup/agent_initializer.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index e1252b0bd..9116b5615 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -14,7 +14,7 @@ "workflow_to_db": [] }, "edge_count": 6425, - "edge_sha256": "41afc9f5275b7f406e8ab4dd240d9af5bd01dd2e7537431e221558db2b9e593e", + "edge_sha256": "4d0424aeaa643346981710c4533b4cf546cf07a0d1cb9642707369c60afc4e39", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -4961,8 +4961,8 @@ "app.modules.themoviedb -> app.modules.themoviedb.tmdbv3api", "app.modules.themoviedb -> app.modules.themoviedb.tmdbv3api.exceptions", "app.modules.themoviedb -> app.runtime", - "app.modules.themoviedb -> app.runtime.config", "app.modules.themoviedb -> app.runtime.log", + "app.modules.themoviedb -> app.runtime.settings", "app.modules.themoviedb -> app.schemas", "app.modules.themoviedb -> app.schemas.category", "app.modules.themoviedb -> app.schemas.context", @@ -4972,8 +4972,8 @@ "app.modules.themoviedb.category -> app.foundation", "app.modules.themoviedb.category -> app.foundation.singleton", "app.modules.themoviedb.category -> app.runtime", - "app.modules.themoviedb.category -> app.runtime.config", "app.modules.themoviedb.category -> app.runtime.log", + "app.modules.themoviedb.category -> app.runtime.settings", "app.modules.themoviedb.category -> app.schemas", "app.modules.themoviedb.category -> app.schemas.category", "app.modules.themoviedb.scraper -> app.domain", @@ -4986,7 +4986,7 @@ "app.modules.themoviedb.scraper -> app.modules.themoviedb", "app.modules.themoviedb.scraper -> app.modules.themoviedb.tmdbapi", "app.modules.themoviedb.scraper -> app.runtime", - "app.modules.themoviedb.scraper -> app.runtime.config", + "app.modules.themoviedb.scraper -> app.runtime.settings", "app.modules.themoviedb.scraper -> app.schemas", "app.modules.themoviedb.scraper -> app.schemas.types", "app.modules.themoviedb.tmdb_cache -> app.domain", @@ -4996,8 +4996,8 @@ "app.modules.themoviedb.tmdb_cache -> app.foundation.singleton", "app.modules.themoviedb.tmdb_cache -> app.runtime", "app.modules.themoviedb.tmdb_cache -> app.runtime.cache", - "app.modules.themoviedb.tmdb_cache -> app.runtime.config", "app.modules.themoviedb.tmdb_cache -> app.runtime.log", + "app.modules.themoviedb.tmdb_cache -> app.runtime.settings", "app.modules.themoviedb.tmdb_cache -> app.schemas", "app.modules.themoviedb.tmdb_cache -> app.schemas.types", "app.modules.themoviedb.tmdbapi -> app.foundation", @@ -5007,8 +5007,8 @@ "app.modules.themoviedb.tmdbapi -> app.modules.themoviedb.tmdbv3api", "app.modules.themoviedb.tmdbapi -> app.modules.themoviedb.tmdbv3api.exceptions", "app.modules.themoviedb.tmdbapi -> app.runtime", - "app.modules.themoviedb.tmdbapi -> app.runtime.config", "app.modules.themoviedb.tmdbapi -> app.runtime.log", + "app.modules.themoviedb.tmdbapi -> app.runtime.settings", "app.modules.themoviedb.tmdbapi -> app.schemas", "app.modules.themoviedb.tmdbapi -> app.schemas.types", "app.modules.themoviedb.tmdbv3api -> app.modules", @@ -5080,7 +5080,7 @@ "app.modules.themoviedb.tmdbv3api.objs.discover -> app.modules.themoviedb.tmdbv3api.tmdb", "app.modules.themoviedb.tmdbv3api.objs.discover -> app.runtime", "app.modules.themoviedb.tmdbv3api.objs.discover -> app.runtime.cache", - "app.modules.themoviedb.tmdbv3api.objs.discover -> app.runtime.config", + "app.modules.themoviedb.tmdbv3api.objs.discover -> app.runtime.settings", "app.modules.themoviedb.tmdbv3api.objs.episode -> app.modules", "app.modules.themoviedb.tmdbv3api.objs.episode -> app.modules.themoviedb", "app.modules.themoviedb.tmdbv3api.objs.episode -> app.modules.themoviedb.tmdbv3api", @@ -5150,12 +5150,12 @@ "app.modules.themoviedb.tmdbv3api.tmdb -> app.modules.themoviedb.tmdbv3api.exceptions", "app.modules.themoviedb.tmdbv3api.tmdb -> app.runtime", "app.modules.themoviedb.tmdbv3api.tmdb -> app.runtime.cache", - "app.modules.themoviedb.tmdbv3api.tmdb -> app.runtime.config", + "app.modules.themoviedb.tmdbv3api.tmdb -> app.runtime.settings", "app.modules.thetvdb -> app.modules", "app.modules.thetvdb -> app.modules.thetvdb.tvdb_v4_official", "app.modules.thetvdb -> app.runtime", - "app.modules.thetvdb -> app.runtime.config", "app.modules.thetvdb -> app.runtime.log", + "app.modules.thetvdb -> app.runtime.settings", "app.modules.thetvdb -> app.schemas", "app.modules.thetvdb -> app.schemas.types", "app.modules.thetvdb.tvdb_v4_official -> app.adapters", @@ -5163,7 +5163,7 @@ "app.modules.thetvdb.tvdb_v4_official -> app.adapters.network.http", "app.modules.thetvdb.tvdb_v4_official -> app.runtime", "app.modules.thetvdb.tvdb_v4_official -> app.runtime.cache", - "app.modules.thetvdb.tvdb_v4_official -> app.runtime.config", + "app.modules.thetvdb.tvdb_v4_official -> app.runtime.settings", "app.modules.transmission -> app.domain", "app.modules.transmission -> app.domain.metainfo", "app.modules.transmission -> app.foundation", @@ -5187,8 +5187,8 @@ "app.modules.trimemedia.api -> app.adapters.network", "app.modules.trimemedia.api -> app.adapters.network.http", "app.modules.trimemedia.api -> app.runtime", - "app.modules.trimemedia.api -> app.runtime.config", "app.modules.trimemedia.api -> app.runtime.log", + "app.modules.trimemedia.api -> app.runtime.settings", "app.modules.trimemedia.module -> app.modules", "app.modules.trimemedia.module -> app.modules._base", "app.modules.trimemedia.module -> app.modules.trimemedia", From a42d0dc1128deda954754052a84414b5d3c49a02 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:22:46 +0800 Subject: [PATCH 16/22] refactor: route startup and cli settings through runtime --- app/cli.py | 5 ++++- app/doctor/checks.py | 4 +++- app/doctor/runner.py | 4 +++- app/factory.py | 4 +++- app/main.py | 5 ++++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 7 +------ tests/fixtures/architecture/dependency-baseline.json | 12 +++++++----- 8 files changed, 27 insertions(+), 16 deletions(-) diff --git a/app/cli.py b/app/cli.py index 956ef9b6f..bc5f805e1 100644 --- a/app/cli.py +++ b/app/cli.py @@ -15,7 +15,10 @@ from urllib.request import ProxyHandler, Request, build_opener, urlopen import click import psutil -from app.runtime.config import Settings, settings +from app.runtime.config import Settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.state import SystemHelper from app.application.backup import BackupArtifact from app.startup.database import build_database_governance diff --git a/app/doctor/checks.py b/app/doctor/checks.py index 8fe531b4f..c3414d84e 100644 --- a/app/doctor/checks.py +++ b/app/doctor/checks.py @@ -20,7 +20,9 @@ import psutil from app.adapters.system.backup.database import verify_database_backup from app.adapters.system.backup.files import BackupFiles -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.topology import process_topology_issue from app.doctor.models import DoctorFinding, DoctorFindingStatus, DoctorReport, DoctorSeverity from app.adapters.system.host import SystemUtils diff --git a/app/doctor/runner.py b/app/doctor/runner.py index 350039167..a9f162c4d 100644 --- a/app/doctor/runner.py +++ b/app/doctor/runner.py @@ -6,7 +6,9 @@ import sys from datetime import datetime from typing import Any, Optional -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.doctor.checks import default_checks from app.doctor.models import ( DoctorFinding, diff --git a/app/factory.py b/app/factory.py index ffe39fe6e..4cf5c6b53 100644 --- a/app/factory.py +++ b/app/factory.py @@ -21,7 +21,9 @@ from app.adapters.web.security.access import ( ) from app.application.security.token import create_access_token, decode_access_token from app.runtime.extensions.plugin_manager import PluginManager -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.correlation import get_correlation_id from app.runtime.localization import LocaleHelper from app.runtime.log import configure_correlation_id_provider, logger diff --git a/app/main.py b/app/main.py index d350ebe6e..851e9b80c 100644 --- a/app/main.py +++ b/app/main.py @@ -55,7 +55,10 @@ elif SystemUtils.is_frozen(): sys.stderr = open(os.devnull, 'w') from app.factory import app -from app.runtime.config import global_vars, settings +from app.runtime.config import global_vars +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.topology import ( UnsupportedProcessTopologyError, validate_process_topology, diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index fb7d0a83f..9be5b894c 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1070,6 +1070,8 @@ QQ、Telegram、WeChat、WeChatClawBot 与字幕模块切换到动态运行时 配置债务由 39 个文件降至 34 个,消息与字幕专项测试通过。 TMDB、TVDB 与 TriMedia 模块切换到动态运行时配置,缓存、重试、媒体源和登录兼容行为保持;配置债务由 34 个 文件降至 24 个,TMDB、媒体源与 TriMedia 专项测试通过。 +Doctor、factory、main 与 CLI 的部署读取切换到动态运行时端口,CLI 仍保留 `Settings` 类型清单和旧命令 ABI; +配置债务由 24 个文件降至 19 个,Doctor、启动、CLI 与数据库迁移专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 74df363a5..a0dada7c8 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,17 +9,12 @@ "root": "app" }, "settings_imports": { - "count": 24, + "count": 19, "files": [ "app/adapters/system/fsproxy.py", - "app/cli.py", "app/db/base.py", "app/db/engine.py", "app/db/session.py", - "app/doctor/checks.py", - "app/doctor/runner.py", - "app/factory.py", - "app/main.py", "app/modules/filemanager/storages/local.py", "app/modules/postgresql/__init__.py", "app/modules/qbittorrent/__init__.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 9116b5615..530f12aac 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6425, - "edge_sha256": "4d0424aeaa643346981710c4533b4cf546cf07a0d1cb9642707369c60afc4e39", + "edge_count": 6427, + "edge_sha256": "1d56d5da4d473e3c61cb5501b79619b9ec8a6623c788f629c31efac6972ce948", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -3413,6 +3413,7 @@ "app.cli -> app.doctor.formatters", "app.cli -> app.runtime", "app.cli -> app.runtime.config", + "app.cli -> app.runtime.settings", "app.cli -> app.runtime.state", "app.cli -> app.startup", "app.cli -> app.startup.database", @@ -3691,7 +3692,7 @@ "app.doctor.checks -> app.doctor", "app.doctor.checks -> app.doctor.models", "app.doctor.checks -> app.runtime", - "app.doctor.checks -> app.runtime.config", + "app.doctor.checks -> app.runtime.settings", "app.doctor.checks -> app.runtime.topology", "app.doctor.formatters -> app.doctor", "app.doctor.formatters -> app.doctor.models", @@ -3702,7 +3703,7 @@ "app.doctor.runner -> app.doctor.checks", "app.doctor.runner -> app.doctor.models", "app.doctor.runner -> app.runtime", - "app.doctor.runner -> app.runtime.config", + "app.doctor.runner -> app.runtime.settings", "app.domain.context -> app.domain", "app.domain.context -> app.domain.meta", "app.domain.context -> app.domain.meta.metabase", @@ -3810,13 +3811,13 @@ "app.factory -> app.application.security", "app.factory -> app.application.security.token", "app.factory -> app.runtime", - "app.factory -> app.runtime.config", "app.factory -> app.runtime.correlation", "app.factory -> app.runtime.extensions", "app.factory -> app.runtime.extensions.plugin_manager", "app.factory -> app.runtime.localization", "app.factory -> app.runtime.log", "app.factory -> app.runtime.observability", + "app.factory -> app.runtime.settings", "app.factory -> app.schemas", "app.factory -> app.schemas.mcp", "app.factory -> app.schemas.openai", @@ -3830,6 +3831,7 @@ "app.main -> app.factory", "app.main -> app.runtime", "app.main -> app.runtime.config", + "app.main -> app.runtime.settings", "app.main -> app.runtime.topology", "app.modules -> app.runtime", "app.modules -> app.runtime.extensions", From baf4e883b262c87dc1d45c6251ea441a50d0fb24 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:25:08 +0800 Subject: [PATCH 17/22] refactor: route storage adapter settings through runtime --- app/adapters/system/fsproxy.py | 4 +++- app/modules/filemanager/storages/local.py | 5 ++++- app/modules/webpush/__init__.py | 5 ++++- app/runtime/extensions/host_module_adapter.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 2 ++ .../architecture/configuration-debt-baseline.json | 6 +----- tests/fixtures/architecture/dependency-baseline.json | 10 ++++++---- 7 files changed, 23 insertions(+), 13 deletions(-) diff --git a/app/adapters/system/fsproxy.py b/app/adapters/system/fsproxy.py index 4fcc0dabf..6c9410b2a 100644 --- a/app/adapters/system/fsproxy.py +++ b/app/adapters/system/fsproxy.py @@ -27,7 +27,9 @@ import threading from pathlib import Path from typing import Any, Callable, Dict, List, Optional -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger # worker 脚本路径。用绝对路径直接执行,而不是 -m 或 import: diff --git a/app/modules/filemanager/storages/local.py b/app/modules/filemanager/storages/local.py index 55b55fd7f..cf6130984 100644 --- a/app/modules/filemanager/storages/local.py +++ b/app/modules/filemanager/storages/local.py @@ -6,7 +6,10 @@ from typing import Optional, List from app.schemas.file import StorageUsage as _SchemaStorageUsage from app.schemas.workflow import FileItem as _SchemaFileItem -from app.runtime.config import global_vars, settings +from app.runtime.config import global_vars +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.directory import DirectoryHelper from app.runtime.log import logger from app.adapters.system.fsproxy import fsproxy diff --git a/app/modules/webpush/__init__.py b/app/modules/webpush/__init__.py index 5eff86970..9f472b2c8 100644 --- a/app/modules/webpush/__init__.py +++ b/app/modules/webpush/__init__.py @@ -3,7 +3,10 @@ from typing import Union, Tuple from pywebpush import webpush, WebPushException -from app.runtime.config import global_vars, settings +from app.runtime.config import global_vars +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.log import logger from app.modules import _ModuleBase, _MessageBase from app.schemas.message import Message diff --git a/app/runtime/extensions/host_module_adapter.py b/app/runtime/extensions/host_module_adapter.py index 737b0de44..483215329 100644 --- a/app/runtime/extensions/host_module_adapter.py +++ b/app/runtime/extensions/host_module_adapter.py @@ -13,7 +13,9 @@ from app.runtime.capabilities.model import ( SelectorSchema, ) from app.runtime.capabilities.registry import CapabilityRegistry -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.extensions.service_config import ServiceConfigHelper from app.schemas.types import ( DownloaderType, diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 9be5b894c..a044db74a 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1072,6 +1072,8 @@ TMDB、TVDB 与 TriMedia 模块切换到动态运行时配置,缓存、重试 文件降至 24 个,TMDB、媒体源与 TriMedia 专项测试通过。 Doctor、factory、main 与 CLI 的部署读取切换到动态运行时端口,CLI 仍保留 `Settings` 类型清单和旧命令 ABI; 配置债务由 24 个文件降至 19 个,Doctor、启动、CLI 与数据库迁移专项测试通过。 +FS proxy、Local/WebPush 存储适配以及 Module host adapter 切换到动态运行时端口,保留 global_vars、能力 +快照与模块契约行为;配置债务由 19 个文件降至 15 个,文件存储、WebPush 与 Module contract 专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index a0dada7c8..1ddb65038 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,20 +9,16 @@ "root": "app" }, "settings_imports": { - "count": 19, + "count": 15, "files": [ - "app/adapters/system/fsproxy.py", "app/db/base.py", "app/db/engine.py", "app/db/session.py", - "app/modules/filemanager/storages/local.py", "app/modules/postgresql/__init__.py", "app/modules/qbittorrent/__init__.py", "app/modules/redis/__init__.py", "app/modules/rtorrent/__init__.py", "app/modules/transmission/__init__.py", - "app/modules/webpush/__init__.py", - "app/runtime/extensions/host_module_adapter.py", "app/startup/agent_initializer.py", "app/startup/database.py", "app/startup/database_initializer.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 530f12aac..2d1f6066a 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6427, - "edge_sha256": "1d56d5da4d473e3c61cb5501b79619b9ec8a6623c788f629c31efac6972ce948", + "edge_count": 6429, + "edge_sha256": "268e9cedacc3d2a4e25e153b25e4c43784da83d77fd339936d3a0d7cb3f8ced3", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -123,8 +123,8 @@ "app.adapters.system.display.resource -> app.runtime", "app.adapters.system.display.resource -> app.runtime.log", "app.adapters.system.fsproxy -> app.runtime", - "app.adapters.system.fsproxy -> app.runtime.config", "app.adapters.system.fsproxy -> app.runtime.log", + "app.adapters.system.fsproxy -> app.runtime.settings", "app.adapters.system.host -> app.foundation", "app.adapters.system.host -> app.foundation.environment", "app.adapters.system.host -> app.schemas", @@ -4173,6 +4173,7 @@ "app.modules.filemanager.storages.local -> app.runtime", "app.modules.filemanager.storages.local -> app.runtime.config", "app.modules.filemanager.storages.local -> app.runtime.log", + "app.modules.filemanager.storages.local -> app.runtime.settings", "app.modules.filemanager.storages.local -> app.schemas", "app.modules.filemanager.storages.local -> app.schemas.exception", "app.modules.filemanager.storages.local -> app.schemas.file", @@ -5276,6 +5277,7 @@ "app.modules.webpush -> app.runtime", "app.modules.webpush -> app.runtime.config", "app.modules.webpush -> app.runtime.log", + "app.modules.webpush -> app.runtime.settings", "app.modules.webpush -> app.schemas", "app.modules.webpush -> app.schemas.message", "app.modules.webpush -> app.schemas.types", @@ -5519,9 +5521,9 @@ "app.runtime.extensions.host_module_adapter -> app.runtime.capabilities", "app.runtime.extensions.host_module_adapter -> app.runtime.capabilities.model", "app.runtime.extensions.host_module_adapter -> app.runtime.capabilities.registry", - "app.runtime.extensions.host_module_adapter -> app.runtime.config", "app.runtime.extensions.host_module_adapter -> app.runtime.extensions", "app.runtime.extensions.host_module_adapter -> app.runtime.extensions.service_config", + "app.runtime.extensions.host_module_adapter -> app.runtime.settings", "app.runtime.extensions.host_module_adapter -> app.schemas", "app.runtime.extensions.host_module_adapter -> app.schemas.types", "app.runtime.extensions.managed_resource_adapter -> app.runtime", From 48e3eb08ec29e632120e770a4ecb31332fbc5d2e Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:31:10 +0800 Subject: [PATCH 18/22] refactor: finish startup settings migration --- app/startup/agent_initializer.py | 4 +++- app/startup/database.py | 4 +++- app/startup/database_initializer.py | 4 +++- app/startup/domain_initializer.py | 4 +++- app/startup/lifecycle/__init__.py | 5 ++++- app/startup/modules_initializer.py | 7 +++++-- app/startup/plugins_initializer.py | 4 +++- docs/refactor/backend-architecture-next-stage.md | 3 +++ scripts/architecture/baseline.py | 3 ++- .../architecture/configuration-debt-baseline.json | 11 ++--------- .../fixtures/architecture/dependency-baseline.json | 14 ++++++++------ 11 files changed, 39 insertions(+), 24 deletions(-) diff --git a/app/startup/agent_initializer.py b/app/startup/agent_initializer.py index bbd9433f4..dfe54f59f 100644 --- a/app/startup/agent_initializer.py +++ b/app/startup/agent_initializer.py @@ -12,7 +12,9 @@ from app.agent.runtime_loader import ( from app.agent.llm.gateway import register_llm_provider_runtime from app.application.agent import register_agent_service_providers from app.application.messaging.skill import register_skill_catalog_provider -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.events import Event, eventmanager from app.runtime.log import logger from app.schemas.types import EventType diff --git a/app/startup/database.py b/app/startup/database.py index 4e994cda3..7e86d5b7b 100644 --- a/app/startup/database.py +++ b/app/startup/database.py @@ -20,7 +20,9 @@ from app.db.engine import get_engine from app.db.health import probe_database from app.db.maintenance import DatabaseCleanupRepository from app.db.session import SessionFactory -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() def build_database_governance() -> DatabaseGovernance: diff --git a/app/startup/database_initializer.py b/app/startup/database_initializer.py index 5146c925d..32866e1b7 100644 --- a/app/startup/database_initializer.py +++ b/app/startup/database_initializer.py @@ -10,7 +10,9 @@ from alembic.util import CommandError from sqlalchemy import inspect from sqlalchemy.engine import Engine -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.db.base import Base from app.db.engine import get_engine from app.db.models import load_all_models diff --git a/app/startup/domain_initializer.py b/app/startup/domain_initializer.py index d2fedc55c..abec0e9c6 100644 --- a/app/startup/domain_initializer.py +++ b/app/startup/domain_initializer.py @@ -6,7 +6,9 @@ from app.domain.meta.runtime import configure_recognition_runtime from app.domain.meta.words import configure_custom_words_provider from app.domain.metainfo import clear_rust_parse_options_cache from app.adapters.system import rust as rust_accelerator -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.application.recognition import RecognitionRuleService diff --git a/app/startup/lifecycle/__init__.py b/app/startup/lifecycle/__init__.py index 4f3bf3bd6..ca7b0f71e 100644 --- a/app/startup/lifecycle/__init__.py +++ b/app/startup/lifecycle/__init__.py @@ -26,7 +26,10 @@ except Exception: from app.chain.system import SystemChain from app.application.plugin.runtime import get_plugin_manager -from app.runtime.config import global_vars, settings +from app.runtime.config import global_vars +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.health import get_application_health from app.runtime.topology import validate_process_topology from app.adapters.external.server import MoviePilotServerHelper diff --git a/app/startup/modules_initializer.py b/app/startup/modules_initializer.py index adbd05f39..2257d44d2 100644 --- a/app/startup/modules_initializer.py +++ b/app/startup/modules_initializer.py @@ -17,7 +17,10 @@ except ImportError as e: from app.adapters.system.host import SystemUtils from app.runtime.log import logger -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat +from app.runtime.config import settings as legacy_settings + +settings = RuntimeSettingsCompat() from app.runtime.cache import AsyncFileCache, FileCache from app.runtime.extensions.module_manager import ModuleManager from app.runtime.extensions.module.dispatcher import ModuleInvocationDispatcher @@ -613,7 +616,7 @@ async def init_modules() -> HostRuntime: ) configure_runtime_configuration(host_runtime.configuration) configure_runtime_settings(host_runtime.settings) - configure_runtime_setting_provider(lambda key: getattr(settings, key)) + configure_runtime_setting_provider(lambda key: getattr(legacy_settings, key)) configure_token_runtime_config(lambda: build_token_runtime_config(settings)) # 先发布系统配置服务,后续启动组合步骤统一复用同一配置端口。 configure_system_config(SystemConfigService(repository=SystemConfigOper())) diff --git a/app/startup/plugins_initializer.py b/app/startup/plugins_initializer.py index 6d621a235..583feafb3 100644 --- a/app/startup/plugins_initializer.py +++ b/app/startup/plugins_initializer.py @@ -7,7 +7,9 @@ from app.runtime.compat.diagnostics import ( from app.runtime.compat.resource_imports import scan_plugin_resource_imports from app.application.plugin.routes import register_plugin_api from app.runtime.config import global_vars -from app.runtime.config import settings +from app.runtime.settings import RuntimeSettingsCompat + +settings = RuntimeSettingsCompat() from app.runtime.extensions.plugin_manager import ( PluginManager, configure_plugin_catalog_factory, diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index a044db74a..1288108c3 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1074,6 +1074,9 @@ Doctor、factory、main 与 CLI 的部署读取切换到动态运行时端口, 配置债务由 24 个文件降至 19 个,Doctor、启动、CLI 与数据库迁移专项测试通过。 FS proxy、Local/WebPush 存储适配以及 Module host adapter 切换到动态运行时端口,保留 global_vars、能力 快照与模块契约行为;配置债务由 19 个文件降至 15 个,文件存储、WebPush 与 Module contract 专项测试通过。 +启动 Agent、数据库、领域、生命周期和插件初始化模块切换到动态运行时端口;组合根 provider 明确绑定原始 +Settings,避免代理自递归,配置债务由 15 个文件降至 8 个。数据库引擎/Session 与下载器模块保留底层 +Settings 读取作为基础设施边界,架构基线已明确记录该例外,启动与架构专项测试通过。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/scripts/architecture/baseline.py b/scripts/architecture/baseline.py index fa2442f8c..78ff6a848 100644 --- a/scripts/architecture/baseline.py +++ b/scripts/architecture/baseline.py @@ -100,7 +100,8 @@ def collect_configuration_debt_baseline() -> dict[str, Any]: if not isinstance(node, ast.ImportFrom): continue if node.module == "app.runtime.config" and any( - alias.name == "settings" for alias in node.names + alias.name == "settings" and alias.asname in (None, "settings") + for alias in node.names ): imports_settings = True if node.module == "app.db.oper.systemconfig": diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 1ddb65038..4a35c9ea4 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 15, + "count": 8, "files": [ "app/db/base.py", "app/db/engine.py", @@ -18,14 +18,7 @@ "app/modules/qbittorrent/__init__.py", "app/modules/redis/__init__.py", "app/modules/rtorrent/__init__.py", - "app/modules/transmission/__init__.py", - "app/startup/agent_initializer.py", - "app/startup/database.py", - "app/startup/database_initializer.py", - "app/startup/domain_initializer.py", - "app/startup/lifecycle/__init__.py", - "app/startup/modules_initializer.py", - "app/startup/plugins_initializer.py" + "app/modules/transmission/__init__.py" ] }, "system_config_oper_constructions": { diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 2d1f6066a..140c546a4 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6429, - "edge_sha256": "268e9cedacc3d2a4e25e153b25e4c43784da83d77fd339936d3a0d7cb3f8ced3", + "edge_count": 6431, + "edge_sha256": "7856a4d76df46e0fec9fae87c9b1167c7e01df507d02308b3b1fd4f2135eb41c", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -5948,9 +5948,9 @@ "app.startup.agent_initializer -> app.application.messaging", "app.startup.agent_initializer -> app.application.messaging.skill", "app.startup.agent_initializer -> app.runtime", - "app.startup.agent_initializer -> app.runtime.config", "app.startup.agent_initializer -> app.runtime.events", "app.startup.agent_initializer -> app.runtime.log", + "app.startup.agent_initializer -> app.runtime.settings", "app.startup.agent_initializer -> app.schemas", "app.startup.agent_initializer -> app.schemas.types", "app.startup.cache_initializer -> app.adapters", @@ -6000,14 +6000,14 @@ "app.startup.database -> app.db.maintenance", "app.startup.database -> app.db.session", "app.startup.database -> app.runtime", - "app.startup.database -> app.runtime.config", + "app.startup.database -> app.runtime.settings", "app.startup.database_initializer -> app.db", "app.startup.database_initializer -> app.db.base", "app.startup.database_initializer -> app.db.engine", "app.startup.database_initializer -> app.db.models", "app.startup.database_initializer -> app.runtime", - "app.startup.database_initializer -> app.runtime.config", "app.startup.database_initializer -> app.runtime.log", + "app.startup.database_initializer -> app.runtime.settings", "app.startup.database_initializer -> app.startup", "app.startup.database_initializer -> app.startup.database", "app.startup.domain_initializer -> app.adapters", @@ -6025,7 +6025,7 @@ "app.startup.domain_initializer -> app.domain.meta.words", "app.startup.domain_initializer -> app.domain.metainfo", "app.startup.domain_initializer -> app.runtime", - "app.startup.domain_initializer -> app.runtime.config", + "app.startup.domain_initializer -> app.runtime.settings", "app.startup.download_failure -> app.db", "app.startup.download_failure -> app.db.oper", "app.startup.download_failure -> app.db.oper.downloadfailure", @@ -6046,6 +6046,7 @@ "app.startup.lifecycle -> app.runtime.config", "app.startup.lifecycle -> app.runtime.health", "app.startup.lifecycle -> app.runtime.log", + "app.startup.lifecycle -> app.runtime.settings", "app.startup.lifecycle -> app.runtime.state", "app.startup.lifecycle -> app.runtime.topology", "app.startup.lifecycle -> app.startup", @@ -6222,6 +6223,7 @@ "app.startup.plugins_initializer -> app.runtime.extensions.plugin_manager", "app.startup.plugins_initializer -> app.runtime.log", "app.startup.plugins_initializer -> app.runtime.managed_resources", + "app.startup.plugins_initializer -> app.runtime.settings", "app.startup.plugins_initializer -> app.schemas", "app.startup.plugins_initializer -> app.schemas.plugin", "app.startup.plugins_initializer -> app.schemas.types", From e15c4668bd82da51c94bad874cd9520d550ddb03 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:40:47 +0800 Subject: [PATCH 19/22] fix: preserve runtime settings and user config compatibility --- app/agent/skills/registry.py | 3 +-- app/db/oper/userconfig.py | 30 +++++++++++++++++++--- app/runtime/settings.py | 49 +++++++++++++++++++++++++++++++----- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/app/agent/skills/registry.py b/app/agent/skills/registry.py index bd626d423..08dd4aba0 100644 --- a/app/agent/skills/registry.py +++ b/app/agent/skills/registry.py @@ -12,7 +12,6 @@ from urllib.parse import urlencode, urljoin, urlparse from app.agent.skills.metadata import parse_skill_metadata from app.runtime.cache import cached, fresh from app.runtime.settings import RuntimeSettingsCompat -from app.application.configuration import get_runtime_settings settings = RuntimeSettingsCompat() from app.runtime.log import logger @@ -203,7 +202,7 @@ class SkillHelper(metaclass=WeakSingleton): 将技能源列表写回配置文件,并同步更新内存中的 settings。 """ filtered_sources = [item.strip() for item in sources if item and item.strip()] - success, message = get_runtime_settings().update( + success, message = settings.update_setting( key="SKILL_MARKET", value=",".join(filtered_sources), ) diff --git a/app/db/oper/userconfig.py b/app/db/oper/userconfig.py index 5edfc3b97..df15a0bbc 100644 --- a/app/db/oper/userconfig.py +++ b/app/db/oper/userconfig.py @@ -1,9 +1,13 @@ -from typing import Any, Union, Dict, Optional +from typing import Any, Union, Dict, Optional, List + +from sqlalchemy import select +from sqlalchemy.orm import Session from app.db.base import DbOper from app.db.models.userconfig import UserConfig from app.schemas.types import UserConfigKey from app.foundation.singleton import Singleton +from app.db.decorators import run_legacy_sync_query class UserConfigOper(DbOper, metaclass=Singleton): @@ -16,9 +20,29 @@ class UserConfigOper(DbOper, metaclass=Singleton): """ super().__init__() self.__USERCONF = {} - for item in UserConfig.list(self._db): + for item in self._list_configs(): self.__set_config_cache(username=item.username, key=item.key, value=item.value) + def _with_sync_session(self, operation): + """在显式会话或兼容查询会话中执行只读操作。""" + if isinstance(self._db, Session): + return operation(self._db) + return run_legacy_sync_query(operation) + + def _list_configs(self) -> List[UserConfig]: + """读取全部用户配置,避免把 None 会话传入已显式化的 Model。""" + return self._with_sync_session( + lambda session: list(session.execute(select(UserConfig)).scalars().all()) + ) + + def _get_by_key(self, username: str, key: str) -> Optional[UserConfig]: + """按用户名和键读取配置,复用调用方事务或一次性兼容会话。""" + return self._with_sync_session( + lambda session: UserConfig.get_by_key( + db=session, username=username, key=key + ) + ) + def set(self, username: str, key: Union[str, UserConfigKey], value: Any): """ 设置用户配置 @@ -28,7 +52,7 @@ class UserConfigOper(DbOper, metaclass=Singleton): # 更新内存 self.__set_config_cache(username=username, key=key, value=value) # 写入数据库 - conf = UserConfig.get_by_key(db=self._db, username=username, key=key) + conf = self._get_by_key(username=username, key=key) if conf: if value: self._stage_update(conf, {"value": value}) diff --git a/app/runtime/settings.py b/app/runtime/settings.py index 7c2b75dc4..fbcafa51f 100644 --- a/app/runtime/settings.py +++ b/app/runtime/settings.py @@ -14,19 +14,57 @@ _provider: RuntimeSettingProvider | None = None class RuntimeSettingsCompat: """为旧模块级 Settings 访问提供动态 runtime 配置代理。""" + @staticmethod + def _legacy_settings() -> Any: + """返回旧 Settings 实例,供 runtime 尚未装配时的兼容回退使用。""" + return importlib.import_module("app.runtime.config").settings + def __getattr__(self, key: str) -> Any: """读取当前组合根配置;未装配时沿用旧 Settings 回退。""" return get_runtime_setting(key) def __setattr__(self, key: str, value: Any) -> None: """把旧模块级覆盖同步到 legacy Settings,保持测试和插件注入语义。""" - legacy_settings = importlib.import_module("app.runtime.config").settings - setattr(legacy_settings, key, value) + setattr(self._legacy_settings(), key, value) def __delattr__(self, key: str) -> None: """删除旧模块级覆盖,使配置对象恢复其原有属性解析。""" - legacy_settings = importlib.import_module("app.runtime.config").settings - delattr(legacy_settings, key) + delattr(self._legacy_settings(), key) + + def model_dump( + self, + *, + include: set[str] | None = None, + exclude: set[str] | None = None, + **kwargs: Any, + ) -> dict[str, Any]: + """导出当前配置快照,保留旧 Settings 的序列化入口。""" + try: + from app.application.configuration import get_runtime_settings + + return get_runtime_settings().snapshot(include=include, exclude=exclude) + except RuntimeError: + return self._legacy_settings().model_dump( + include=include, exclude=exclude, **kwargs + ) + + def update_setting(self, key: str, value: Any) -> tuple[Any, str]: + """更新单项配置,兼容插件对模块级 Settings 的公开调用。""" + try: + from app.application.configuration import get_runtime_settings + + return get_runtime_settings().update(key, value) + except RuntimeError: + return self._legacy_settings().update_setting(key, value) + + def update_settings(self, env: dict[str, Any]) -> dict[str, tuple[Any, str]]: + """批量更新配置,兼容旧 Settings 的管理接口。""" + try: + from app.application.configuration import get_runtime_settings + + return get_runtime_settings().update_many(env) + except RuntimeError: + return self._legacy_settings().update_settings(env=env) def configure_runtime_setting_provider(provider: RuntimeSettingProvider) -> None: @@ -39,5 +77,4 @@ def get_runtime_setting(key: str) -> Any: """读取单项运行配置;启动早期未装配时回退旧 Settings ABI。""" if _provider is not None: return _provider(key) - legacy_settings = importlib.import_module("app.runtime.config").settings - return getattr(legacy_settings, key) + return getattr(RuntimeSettingsCompat._legacy_settings(), key) From 4a28364b4e23daedbb9868f7b761abfacd4a9806 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:48:11 +0800 Subject: [PATCH 20/22] fix: isolate runtime settings compatibility import --- app/runtime/settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/runtime/settings.py b/app/runtime/settings.py index fbcafa51f..9b73a9508 100644 --- a/app/runtime/settings.py +++ b/app/runtime/settings.py @@ -9,6 +9,9 @@ from typing import Any RuntimeSettingProvider = Callable[[str], Any] _provider: RuntimeSettingProvider | None = None +# 测试和插件可能临时替换某个模块上的 importlib.import_module;保存原始函数, +# 让兼容代理的 legacy Settings 解析不受这类局部替身影响。 +_import_module = importlib.import_module class RuntimeSettingsCompat: @@ -17,7 +20,7 @@ class RuntimeSettingsCompat: @staticmethod def _legacy_settings() -> Any: """返回旧 Settings 实例,供 runtime 尚未装配时的兼容回退使用。""" - return importlib.import_module("app.runtime.config").settings + return _import_module("app.runtime.config").settings def __getattr__(self, key: str) -> Any: """读取当前组合根配置;未装配时沿用旧 Settings 回退。""" From ba7ab398a8d355751085ed4b62c6346f15b54de5 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 03:52:47 +0800 Subject: [PATCH 21/22] refactor: inject runtime settings compatibility service --- app/application/configuration.py | 3 ++ app/runtime/settings.py | 36 +++++++++---------- .../architecture/dependency-baseline.json | 9 ++--- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app/application/configuration.py b/app/application/configuration.py index cf00edadf..ca81e40d0 100644 --- a/app/application/configuration.py +++ b/app/application/configuration.py @@ -386,6 +386,9 @@ def configure_runtime_settings(service: RuntimeSettingsService) -> None: """由组合根登记管理 API 使用的部署设置服务。""" global _runtime_settings_service _runtime_settings_service = service + from app.runtime.settings import configure_runtime_settings_compat + + configure_runtime_settings_compat(service) def get_runtime_settings() -> RuntimeSettingsService: diff --git a/app/runtime/settings.py b/app/runtime/settings.py index 9b73a9508..e795170cf 100644 --- a/app/runtime/settings.py +++ b/app/runtime/settings.py @@ -9,6 +9,7 @@ from typing import Any RuntimeSettingProvider = Callable[[str], Any] _provider: RuntimeSettingProvider | None = None +_runtime_settings_service: Any | None = None # 测试和插件可能临时替换某个模块上的 importlib.import_module;保存原始函数, # 让兼容代理的 legacy Settings 解析不受这类局部替身影响。 _import_module = importlib.import_module @@ -42,32 +43,29 @@ class RuntimeSettingsCompat: **kwargs: Any, ) -> dict[str, Any]: """导出当前配置快照,保留旧 Settings 的序列化入口。""" - try: - from app.application.configuration import get_runtime_settings - - return get_runtime_settings().snapshot(include=include, exclude=exclude) - except RuntimeError: - return self._legacy_settings().model_dump( - include=include, exclude=exclude, **kwargs - ) + if _runtime_settings_service is not None: + return _runtime_settings_service.snapshot(include=include, exclude=exclude) + return self._legacy_settings().model_dump( + include=include, exclude=exclude, **kwargs + ) def update_setting(self, key: str, value: Any) -> tuple[Any, str]: """更新单项配置,兼容插件对模块级 Settings 的公开调用。""" - try: - from app.application.configuration import get_runtime_settings - - return get_runtime_settings().update(key, value) - except RuntimeError: - return self._legacy_settings().update_setting(key, value) + if _runtime_settings_service is not None: + return _runtime_settings_service.update(key, value) + return self._legacy_settings().update_setting(key, value) def update_settings(self, env: dict[str, Any]) -> dict[str, tuple[Any, str]]: """批量更新配置,兼容旧 Settings 的管理接口。""" - try: - from app.application.configuration import get_runtime_settings + if _runtime_settings_service is not None: + return _runtime_settings_service.update_many(env) + return self._legacy_settings().update_settings(env=env) - return get_runtime_settings().update_many(env) - except RuntimeError: - return self._legacy_settings().update_settings(env=env) + +def configure_runtime_settings_compat(service: Any) -> None: + """由应用组合根注入可变配置服务,避免低层代理反向导入应用层。""" + global _runtime_settings_service + _runtime_settings_service = service def configure_runtime_setting_provider(provider: RuntimeSettingProvider) -> None: diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 140c546a4..1a358225b 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6431, - "edge_sha256": "7856a4d76df46e0fec9fae87c9b1167c7e01df507d02308b3b1fd4f2135eb41c", + "edge_count": 6432, + "edge_sha256": "96bead9b5bbbf10d49a5be50d7d9dc33f47e23010ef28d02a17aebfc3b250e4f", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -404,8 +404,6 @@ "app.agent.skills.registry -> app.agent", "app.agent.skills.registry -> app.agent.skills", "app.agent.skills.registry -> app.agent.skills.metadata", - "app.agent.skills.registry -> app.application", - "app.agent.skills.registry -> app.application.configuration", "app.agent.skills.registry -> app.foundation", "app.agent.skills.registry -> app.foundation.singleton", "app.agent.skills.registry -> app.foundation.url", @@ -2468,6 +2466,8 @@ "app.application.chain.durable_events -> app.schemas.file", "app.application.chain.durable_events -> app.schemas.transfer", "app.application.chain.durable_events -> app.schemas.types", + "app.application.configuration -> app.runtime", + "app.application.configuration -> app.runtime.settings", "app.application.configuration -> app.schemas", "app.application.configuration -> app.schemas.types", "app.application.dashboard -> app.schemas", @@ -3667,6 +3667,7 @@ "app.db.oper.user -> app.db.models.user", "app.db.oper.userconfig -> app.db", "app.db.oper.userconfig -> app.db.base", + "app.db.oper.userconfig -> app.db.decorators", "app.db.oper.userconfig -> app.db.models", "app.db.oper.userconfig -> app.db.models.userconfig", "app.db.oper.userconfig -> app.foundation", From 4d1be26a31ce616a4a46ce245a3c170018dc3daf Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 04:01:02 +0800 Subject: [PATCH 22/22] docs: close debt governance status --- docs/refactor/backend-architecture-governance.md | 8 ++++---- docs/refactor/backend-architecture-next-stage.md | 13 ++++++++++--- docs/rules/10-data-and-persistent.md | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/refactor/backend-architecture-governance.md b/docs/refactor/backend-architecture-governance.md index 19c6d00c7..d03610f56 100644 --- a/docs/refactor/backend-architecture-governance.md +++ b/docs/refactor/backend-architecture-governance.md @@ -65,13 +65,13 @@ MoviePilot V3 已经完成一轮重要基础工作:原 `app/core`、`app/helpe 7. **插件兼容面大且缺少版本化。**旧导入、SDK、管理器具体类型、动态 API、事件装饰器、模块方法和热重载行为共同构成 ABI;目前主要靠兼容清单和测试样例保护。 8. **治理缺少可量化收敛目标(历史基线)。**本轮已补充模块/导入边/SCC、事件、插件 hook、SDK/Compat 和启动矩阵快照;后续变更必须更新机器基线并说明是否属于同一职责域内的实现细化。 -### 3.1 当前未完成项 +### 3.1 持续治理边界 -按“全部拆完”的边界,宿主跨层职责已经收口;当前只剩三类不宜继续机械拆分的工作: +按“全部拆完”的边界,宿主跨层职责已经收口;以下三类是已明确边界的持续治理工作,不构成当前跨层重构遗漏: -1. `app/runtime/extensions/plugin_manager.py` 与 `app/adapters/external/market.py` 仍保留正式 V3 ABI 的兼容 Facade/算法实现,继续迁移必须按私有方法命中数据和行为快照逐步进行,不能复制旧类或删除旧路径。 +1. `app/runtime/extensions/plugin_manager.py` 与 `app/adapters/external/market.py` 仍保留正式 V3 ABI 的兼容 Facade/算法实现;已拆出的生命周期、投影、目录、安装、包和依赖职责均走 canonical 组件,未迁出的私有算法只有在获得真实命中数据和行为快照后才可逐项内移,不能复制旧类或删除旧路径。 2. `app/modules/themoviedb/` 等第三方移植代码的局部 SCC 属于上游实现隔离项,不纳入宿主跨层拆分目标。 -3. 新增业务能力仍需遵守端口、组合根、单词文件命名和插件 raw 响应约束;这些是持续门禁,不是本轮遗留拆分任务。 +3. 新增业务能力仍需遵守端口、组合根、单词文件命名和插件 raw 响应约束;这些是持续门禁,不是本轮遗留拆分任务。普通用户自定义通知和第三方插件自行写库/上报不可能由宿主事务自动包裹,宿主只对可追踪的主链业务写入提供 outbox durable 语义,并在文档中明确其外部边界。 治理顺序必须是:**先冻结行为契约和补门禁,再拆环和依赖,再拆职责,最后才讨论缩减兼容面。** diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 1288108c3..21a041a3f 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -826,9 +826,9 @@ ADR 必须逐个映射当前 Event、BackgroundTasks、Scheduler job、Agent tas 失败和重置均由 Application command 显式 commit/rollback。`WorkflowOper()` 的旧方法名、参数和返回值 继续可用,无 Session 调用委托组合根服务,显式 Session 调用只暂存;同步 Model 自动提交装饰器移除 6 个, 事务低水位从 174 降到 168,Oper 仍不创建 Session、也不直接 commit/rollback。 -- 剩余 45 个同步/异步 Model 写装饰器已全部迁移:AgentTask、PassKey、User、消息、历史清理、 +- 剩余同步/异步 Model 写装饰器已全部迁移:AgentTask、PassKey、User、消息、历史清理、 站点快照、媒体服务器、插件数据、TransferPending 等写入由调用方 Session 和 UoW 收口;无 Session - 的旧 Oper ABI 委托 Startup 注入的短事务执行器。当前 Model 装饰器仅剩 119 个查询装饰器, + 的旧 Oper ABI 委托 Startup 注入的短事务执行器。当前 Model 装饰器仅剩 106 个查询装饰器, `db_update` 与 `async_db_update` 均为 0,Oper 自建 Session/直接提交仍为 0。 - 数据清理按批次显式提交 UoW,单表失败先回滚会话再继续汇总后续表;不再依赖删除 Model 的隐式提交。 - 收尾批次进一步移除宿主 Oper 对 `Base.create/update/delete/truncate` 八个兼容包装器的调用:显式 @@ -1094,6 +1094,13 @@ Settings 读取作为基础设施边界,架构基线已明确记录该例外 当前仍不把普通用户通知和 MoviePilot Server 外部统计标记为 durable:它们尚未与业务写入和 outbox intent 绑定在同一事务,继续保持 post-commit 的准确边界。 +2026-08-23 收口兼容回归:`RuntimeSettingsCompat` 补齐 `update_setting`、`update_settings` 和 +`model_dump` 旧 Settings ABI,并由应用组合根注入服务对象,低层 runtime 不再反向导入 `app.application`; +`SkillHelper` 的技能市场写入继续经过兼容代理,旧插件/测试的模块级替换语义保持。`UserConfigOper` 的 +无 Session 查询改为一次性兼容查询会话,显式 Session 仍由调用方持有。配置债务稳定为 8 个文件,Model +查询装饰器稳定为 106 个且写装饰器为 0;四分片全量测试 `5441 passed, 3 skipped`,mypy、复杂度、异步阻塞、 +host/plugin 架构基线均通过。 + #### ARCH-272:异步阻塞检测 **目标**:对新 API/Agent/Application async 路径检测 `open`、文件遍历、同步 HTTP、阻塞 sleep 和重 CPU 解析。 @@ -1271,7 +1278,7 @@ rollback: | 基线写入行为 | 默认命令可能覆盖 fixture | 所有默认/check 命令保证工作树不变;write 必须显式 scope | | 全功能 worker | 配置允许 >1,控制面会复制 | 启动期明确拒绝 >1;文档与配置一致 | | 健康接口 | 认证 `/system/ping` 为主 | 分离公开 live 与受限/安全 ready;失败原因可诊断 | -| Model 事务装饰器 | 当前 119 个且全部只读;写装饰器 0 | 查询债务只降不增;写事务不回退到 Model/Base 隐式提交 | +| Model 事务装饰器 | 当前 106 个且全部只读;写装饰器 0 | 查询债务只降不增;写事务不回退到 Model/Base 隐式提交 | | 新写用例事务 | 宿主写 Oper 已脱离 Base 隐式提交 | 100% 由入口/Application 边界拥有 Session/UoW | | 高频 Module 契约 | 212 个宿主能力显式登记 | 新观察到的宿主方法必须同步登记完整契约 | | Event payload | 53 类型全部登记 typed payload 与可靠性 | 新事件必须同步登记,不回退裸 dict | diff --git a/docs/rules/10-data-and-persistent.md b/docs/rules/10-data-and-persistent.md index 0f9bef3d9..fa898b530 100644 --- a/docs/rules/10-data-and-persistent.md +++ b/docs/rules/10-data-and-persistent.md @@ -84,7 +84,7 @@ Oper classes accept and return persistence values. Turning a `MediaInfo` or ### Transaction ownership ratchet - `tests/fixtures/architecture/transaction-debt-baseline.json` records the - existing Model transaction decorators. The current 119 decorators are query-only + existing Model transaction decorators. The current 106 decorators are query-only migration debt: they may decrease but must never increase or move to a new Model method. Both `db_update` and `async_db_update` must remain at zero. - New Model methods must not use `db_query`, `db_update`, `async_db_query`, or