refactor backend module architecture

This commit is contained in:
jxxghp
2026-08-14 15:45:38 +08:00
parent 557cc0e2e3
commit 7b3444c366
716 changed files with 10378 additions and 7709 deletions
+1 -4
View File
@@ -10,10 +10,7 @@ rust/**/target/
nginx/ nginx/
test.py test.py
safety_report.txt safety_report.txt
app/helper/sites.py app/infrastructure/*.bin
app/helper/*.so
app/helper/*.pyd
app/helper/*.bin
app/plugins/** app/plugins/**
!app/plugins/__init__.py !app/plugins/__init__.py
config/cookies/ config/cookies/
+2 -2
View File
@@ -73,5 +73,5 @@ ignore-imports=yes
[TYPECHECK] [TYPECHECK]
# 生成缺失成员提示的类列表 # 生成缺失成员提示的类列表
generated-members=requests.packages.urllib3 generated-members=requests.packages.urllib3
# app.helper.sites 会主动隐藏模块属性枚举,避免误报 no-name-in-module # app.infrastructure.sites 会主动隐藏模块属性枚举,接口由同目录 sites.pyi 声明
ignored-modules=app.helper.sites ignored-modules=app.infrastructure.sites
+57 -1
View File
@@ -50,6 +50,61 @@ For work that changes or reviews repository behavior, identify the domains actua
--- ---
## Canonical Package Ownership
The historical `app/core`, `app/helper`, and `app/utils` directories are compatibility-only virtual import roots. Never add physical Python source there and never use those imports from host code. Choose an owner by responsibility, not by whether a function is "shared" or has historically been called a helper.
| Package | Owns | Must Not Own | Representative Files |
|---|---|---|---|
| `app/foundation/` | Generic mechanisms that work without MoviePilot business state: HTTP transport, reflection/module loading, crypto, URL/object primitives, and structures | `settings`, DB/SystemConfig, MoviePilot business rules, concrete products, legacy import paths | `http.py`, `module.py`, `url.py`, `structures.py` |
| `app/domain/` | Pure MoviePilot business semantics and models for media, recognition, sites, and torrents | Persistence, global settings reads, network/filesystem clients, Rust imports, service discovery, process lifecycle | `context.py`, `media.py`, `metainfo.py`, `scraper.py`, `meta/` |
| `app/platform/` | Process-wide runtime contracts and policy: configuration, events, complete logging runtime, cache contracts/in-memory behavior, concurrency, scheduling, rate limiting, localization, GC, restart state | Named third-party integrations, DB-backed business services, Redis/file cache adapter implementations | `config.py`, `events.py`, `log.py`, `cache.py`, `thread.py`, `gc.py`, `runtime.py` |
| `app/infrastructure/` | Configured technical adapters to Redis, files and standard streams, OS/process facilities, browser/display, DNS, RSS transport, package/resource installation, Rust, generated site resources | Media/site/torrent business decisions, plugin lifecycle, named ecosystem workflows, process restart policy after an adapter action | `cache.py`, `stdio.py`, `redis.py`, `resource.py`, `rss.py`, `rust.py`, `system.py` |
| `app/integrations/` | Concrete external products and ecosystems, including plugin markets, MoviePilot remote service, CookieCloud, OCR, and IP-location providers | Generic HTTP/DNS/filesystem primitives or reusable domain semantics | `market.py`, `server.py`, `cookiecloud.py`, `ocr.py`, `location.py` |
| `app/extensions/` | Discovery, loading, registration, and lifecycle of runtime modules, plugins, and configured service implementations | Generic module import mechanics, plugin-facing compatibility APIs, unrelated business workflows | `module_manager.py`, `plugin_manager.py`, `service_registry.py` |
| `app/messaging/` | Message rendering/routing, interactions, and Agent-to-message bridging | Authentication policy, generic HTTP clients, configured service discovery, endpoint-only Web Push behavior | `message.py`, `interaction.py`, `agent.py` |
| `app/security/` | Authentication, authorization, cookies, passkeys, OTP/two-factor, path/URL safety, SSRF and signing policy | Generic URL parsing, process runtime policy, ordinary business validation | `access.py`, `auth.py`, `cookie.py`, `passkey.py`, `otp.py`, `twofactor.py`, `url.py` |
| `app/services/` | Focused application services and service-bound rules, including persisted configuration, configured capability discovery, notification selection, and media-server normalization/matching | Multi-domain use-case orchestration, generic primitives, concrete product protocols | `recognition.py`, `filter.py`, `notification.py`, `mediaserver.py`, `history.py`, `image.py`, `torrent.py` |
| `app/chain/` | Reusable use-case orchestration across modules, services, Oper classes, events, and caches | Transport schemas, backend-specific protocol details, generic primitives | `media.py`, `download.py`, `subscribe.py`, `transfer.py` |
| `app/startup/` | Composition root: inject providers/adapters, order initialization and shutdown, decide restart/lifecycle policy | Reusable business rules or adapter implementation details | `lifecycle.py`, `domain_initializer.py`, `cache_initializer.py`, `modules_initializer.py` |
| `app/sdk/` | Deliberately curated stable imports for new plugins | Canonical implementation logic or host-internal dependencies | `cache.py`, `logging.py`, `media.py`, `network.py`, `services.py` |
| `app/compat/` | Standard-library-only exact legacy import routing and DEBUG diagnostics | Business implementation, wildcard alias guessing, eager canonical imports | `manifest.py`, `imports.py`, `diagnostics.py` |
### Placement Decision Order
Use these questions in order before creating or moving a module:
1. Is it generic and independent of MoviePilot state? Put it in `foundation`.
2. Is it a pure core MoviePilot rule/model that is independent of a configured service boundary? Put it in `domain`.
3. Is it process-wide runtime policy or a contract used by adapters? Put it in `platform`.
4. Does it perform configured technical I/O against Redis, files, OS, browser, RSS, or Rust? Put it in `infrastructure`.
5. Does it implement a named external product/ecosystem workflow? Put it in `integrations`.
6. Does it discover or manage modules/plugins/service implementations? Put it in `extensions`.
7. Does it own authentication, authorization, signing, SSRF, URL/path safety, OTP, passkeys, or two-factor behavior? Put it in `security`.
8. Does it read persisted user configuration, coordinate one bounded capability, or normalize/match one service family? Put it in `services`.
9. Does it coordinate several modules/services/Oper classes for one use case? Put it in `chain`.
10. Is it public to plugins or only preserving an old path? Curate it in `sdk` or map it in `compat`; do not move implementation there.
### Enforced Split Examples
These decisions are architectural constraints, not naming suggestions:
* Cache contracts, memory backends, decorators, and proxies stay in `app/platform/cache.py`; Redis and filesystem implementations stay in `app/infrastructure/cache.py`. Startup registers concrete factories before decorated business modules are imported. Legacy `app.core.cache` resolves to the complete `app.sdk.cache` facade.
* The complete logging runtime stays in `app/platform/log.py`: policy, console/plugin routing, async rotating file output, and shutdown. `app.platform.config` supplies the resolved settings and log path. `platform/log.py` remains a dependency leaf with no `app.*` imports. Plugins use `app.sdk.logging`; legacy `app.log` resolves to that SDK facade.
* Recognition parsing stays pure in `app/domain/meta/` and `app/domain/metainfo.py`. `app/services/recognition.py` reads `SystemConfigOper`; `app/startup/domain_initializer.py` injects rules, extension policy, source defaults, TMDB image construction, and the optional Rust accelerator.
* Kodi-style NFO reading and metadata document generation are one domain capability and stay together in `app/domain/scraper.py`; a separate `domain/nfo.py` must not be recreated.
* `app/services/mediaserver.py` is the single media-server service capability module. It owns configured service discovery together with Provider ID normalization and music-library matching, while reusing generic identity rules from `app/domain/media.py`.
* Configured notification-service discovery belongs in `app/services/notification.py`. Web Push subscription and manual-send HTTP behavior stays in `app/api/endpoints/message.py`; it is not a reusable messaging capability module.
* `app/infrastructure/resource.py` detects/downloads/installs resources and returns whether installation occurred. Only `app/startup/modules_initializer.py` may decide to restart the process afterward.
* Process memory/GC policy belongs in `app/platform/gc.py`; external IP-location APIs belong in `app/integrations/location.py`.
* Security implementation filenames use package-context nouns: `app/security/url.py` and `app/security/twofactor.py`. Historical `app.utils.security` and `app.helper.twofa` remain compatibility mappings only.
Foundation modules do not emit runtime logs. They return documented fallback values or raise according to their public contract; application callers decide whether a failure is operationally relevant and log it from the owning upper layer.
Any ownership move must update canonical host imports, `app/compat/manifest.py`, curated SDK exports when applicable, `docs/rules/05-architecture.md`, and `tests/test_architecture_dependencies.py`. Run that architecture test before broader tests; it rejects physical legacy sources, forbidden upward dependencies, retired canonical filenames, and import cycles.
---
## Agent Execution Rules ## Agent Execution Rules
### Pre-Flight Check ### Pre-Flight Check
@@ -85,6 +140,7 @@ When modifying the following, you must also update the listed artifacts:
| Database model schema | New Alembic migration under `database/versions/` | | Database model schema | New Alembic migration under `database/versions/` |
| User-visible config or init flow | Related docs, help text, setup/init flows, tests | | User-visible config or init flow | Related docs, help text, setup/init flows, tests |
| New skill | Follow `skills/<name>/SKILL.md` structure, keep YAML front matter | | New skill | Follow `skills/<name>/SKILL.md` structure, keep YAML front matter |
| Canonical module ownership or import path | `docs/rules/05-architecture.md`, `app/compat/manifest.py`, SDK exports when public, architecture/compatibility tests |
--- ---
@@ -94,4 +150,4 @@ For the full documentation map and cross-references, refer to:
**[Documentation Hub Index](./docs/rules/README.md)** **[Documentation Hub Index](./docs/rules/README.md)**
*Last Updated: 2026-05-25* *Last Updated: 2026-08-14*
+3
View File
@@ -1,5 +1,7 @@
import warnings import warnings
from app.compat.imports import install_legacy_import_hook
def _filter_third_party_startup_warnings() -> None: def _filter_third_party_startup_warnings() -> None:
""" """
@@ -13,3 +15,4 @@ def _filter_third_party_startup_warnings() -> None:
_filter_third_party_startup_warnings() _filter_third_party_startup_warnings()
install_legacy_import_hook()
+14 -3077
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@ from fastapi.concurrency import run_in_threadpool
from app.agent.policy import sanitize_for_host from app.agent.policy import sanitize_for_host
from app.chain import ChainBase from app.chain import ChainBase
from app.log import logger from app.platform.log import logger
from app.schemas import Notification from app.schemas import Notification
from app.schemas.message import ( from app.schemas.message import (
MessageResponse, MessageResponse,
+4 -4
View File
@@ -12,9 +12,9 @@ from pathlib import Path
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from uuid import uuid4 from uuid import uuid4
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
from app.utils.http import RequestUtils from app.foundation.http import RequestUtils
class AgentCapabilityProvider(ABC): class AgentCapabilityProvider(ABC):
@@ -799,7 +799,7 @@ class AgentCapabilityManager:
if not source: if not source:
return False return False
from app.helper.service import ServiceConfigHelper from app.extensions.service_registry import ServiceConfigHelper
for config in ServiceConfigHelper.get_notification_configs(): for config in ServiceConfigHelper.get_notification_configs():
if config.name != source: if config.name != source:
+2 -2
View File
@@ -10,8 +10,8 @@ from urllib.parse import urlsplit
from langchain_core.messages import AIMessage, AIMessageChunk from langchain_core.messages import AIMessage, AIMessageChunk
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
if TYPE_CHECKING: if TYPE_CHECKING:
from app.agent.llm.server_tools import ServerToolResolution from app.agent.llm.server_tools import ServerToolResolution
+3 -3
View File
@@ -20,11 +20,11 @@ import aiofiles
import httpx import httpx
import jwt import jwt
from app.core.config import settings from app.platform.config import settings
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger from app.platform.log import logger
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
from app.utils.singleton import Singleton from app.foundation.singleton import Singleton
class LLMProviderError(RuntimeError): class LLMProviderError(RuntimeError):
+2 -2
View File
@@ -13,14 +13,14 @@ from typing import Any, Optional
from urllib.parse import urljoin from urllib.parse import urljoin
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger from app.platform.log import logger
from app.schemas.agent import ( from app.schemas.agent import (
AgentMcpServerConfig, AgentMcpServerConfig,
AgentMcpServerTestResult, AgentMcpServerTestResult,
AgentMcpServerToolInfo, AgentMcpServerToolInfo,
) )
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
from app.utils.http import AsyncRequestUtils from app.foundation.http import AsyncRequestUtils
MCP_PROTOCOL_VERSION = "2025-11-25" MCP_PROTOCOL_VERSION = "2025-11-25"
MCP_CLIENT_NAME = "MoviePilot Agent" MCP_CLIENT_NAME = "MoviePilot Agent"
+2 -2
View File
@@ -6,9 +6,9 @@ from typing import Dict, List, Optional
from langchain_core.messages import BaseMessage, messages_from_dict, messages_to_dict from langchain_core.messages import BaseMessage, messages_from_dict, messages_to_dict
from app.core.config import settings from app.platform.config import settings
from app.db.agentchat_oper import AgentChatOper from app.db.agentchat_oper import AgentChatOper
from app.log import logger from app.platform.log import logger
from app.schemas.agent import ConversationMemory from app.schemas.agent import ConversationMemory
+1 -1
View File
@@ -35,7 +35,7 @@ from pydantic import BaseModel, Field
from app.agent.middleware.utils import append_to_system_message from app.agent.middleware.utils import append_to_system_message
from app.agent.policy import sanitize_for_host, summarize_error, summarize_result from app.agent.policy import sanitize_for_host, summarize_error, summarize_result
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
# 活动日志保留天数 # 活动日志保留天数
DEFAULT_RETENTION_DAYS = 7 DEFAULT_RETENTION_DAYS = 7
+1 -1
View File
@@ -17,7 +17,7 @@ from langchain_core.runnables import RunnableConfig
from langgraph.runtime import Runtime from langgraph.runtime import Runtime
from app.agent.middleware.utils import append_to_system_message from app.agent.middleware.utils import append_to_system_message
from app.log import logger from app.platform.log import logger
# JOB.md 文件最大限制为 1MB # JOB.md 文件最大限制为 1MB
MAX_JOB_FILE_SIZE = 1 * 1024 * 1024 MAX_JOB_FILE_SIZE = 1 * 1024 * 1024
+1 -1
View File
@@ -15,7 +15,7 @@ from langchain_core.runnables import RunnableConfig
from langgraph.runtime import Runtime from langgraph.runtime import Runtime
from app.agent.middleware.utils import append_to_system_message from app.agent.middleware.utils import append_to_system_message
from app.log import logger from app.platform.log import logger
# 记忆文件最大限制为 100KB,防止单文件过大导致上下文溢出 # 记忆文件最大限制为 100KB,防止单文件过大导致上下文溢出
MAX_MEMORY_FILE_SIZE = 100 * 1024 MAX_MEMORY_FILE_SIZE = 100 * 1024
+9 -166
View File
@@ -26,57 +26,17 @@ from pydantic import BaseModel, Field
from app.agent.middleware.utils import append_to_system_message from app.agent.middleware.utils import append_to_system_message
from app.agent.policy import sanitize_for_host, summarize_error from app.agent.policy import sanitize_for_host, summarize_error
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.agent.skills.metadata import (
MAX_SKILL_FILE_SIZE,
SkillMetadata,
parse_skill_metadata,
)
from app.platform.log import logger
# 磁盘读取上限与模型返回上限分离,避免异常大的 Skill 文件撑爆内存或上下文。 # 模型返回上限独立于领域层的磁盘读取上限,避免异常内容撑爆上下文。
MAX_SKILL_FILE_SIZE = 1 * 1024 * 1024
MAX_SKILL_RESULT_CHARS = 64 * 1024 MAX_SKILL_RESULT_CHARS = 64 * 1024
SKILL_CONTENT_TRUNCATION_SUFFIX = "\n...(Skill 内容已截断)" SKILL_CONTENT_TRUNCATION_SUFFIX = "\n...(Skill 内容已截断)"
# Agent Skills 规范约束 (https://agentskills.io/specification)
MAX_SKILL_NAME_LENGTH = 64
MAX_SKILL_DESCRIPTION_LENGTH = 1024
MAX_SKILL_COMPATIBILITY_LENGTH = 500
class SkillMetadata(TypedDict):
"""Skill 元数据,符合 Agent Skills 规范。"""
path: str
"""SKILL.md 文件路径。"""
id: str
"""Skill 标识符。
约束: 1-64 字符仅限小写字母/数字/连字符不能以连字符开头或结尾无连续连字符需与父目录名一致
"""
name: str
"""Skill 名称。
约束: Skill中文描述
"""
version: int
"""Skill 版本号。
用于内置技能的版本管理同步时比较版本号决定是否覆盖用户目录中的旧版本
"""
description: str
"""Skill 功能描述。
约束: 1-1024 字符应说明功能及适用场景
"""
license: str | None
"""许可证信息。"""
compatibility: str | None
"""环境依赖或兼容性要求 (最多 500 字符)。"""
metadata: dict[str, str]
"""附加元数据。"""
allowed_tools: list[str]
"""(实验性) Skill 建议使用的工具列表。"""
class SkillsState(AgentState): class SkillsState(AgentState):
"""skills 中间件状态。""" """skills 中间件状态。"""
@@ -101,123 +61,6 @@ class SkillToolInput(BaseModel):
) )
def _parse_skill_metadata( # noqa: C901
content: str,
skill_path: str,
skill_id: str,
) -> SkillMetadata | None:
"""从 SKILL.md 内容中解析 YAML 前言并验证元数据。"""
if len(content) > MAX_SKILL_FILE_SIZE:
logger.warning(
"Skipping %s: content too large (%d bytes)", skill_path, len(content)
)
return None
# 匹配 --- 分隔的 YAML 前言
frontmatter_pattern = r"^---\s*\n(.*?)\n---\s*\n"
match = re.match(frontmatter_pattern, content, re.DOTALL)
if not match:
logger.warning("Skipping %s: no valid YAML frontmatter found", skill_path)
return None
frontmatter_str = match.group(1)
# 解析 YAML
try:
frontmatter_data = yaml.safe_load(frontmatter_str)
except yaml.YAMLError as e:
logger.warning("Invalid YAML in %s: %s", skill_path, summarize_error(e))
return None
if not isinstance(frontmatter_data, dict):
logger.warning("Skipping %s: frontmatter is not a mapping", skill_path)
return None
# SKill名称和描述
name = str(frontmatter_data.get("name", "")).strip()
description = str(frontmatter_data.get("description", "")).strip()
if not name or not description:
logger.warning(
"Skipping %s: missing required 'name' or 'description'", skill_path
)
return None
description_str = description
if len(description_str) > MAX_SKILL_DESCRIPTION_LENGTH:
logger.warning(
"Description exceeds %d characters in %s, truncating",
MAX_SKILL_DESCRIPTION_LENGTH,
skill_path,
)
description_str = description_str[:MAX_SKILL_DESCRIPTION_LENGTH]
# 可选的工具列表,支持空格或逗号分隔
raw_tools = frontmatter_data.get("allowed-tools")
if isinstance(raw_tools, str):
allowed_tools = [
t.strip(",") # 兼容 Claude Code 风格的逗号分隔
for t in raw_tools.split()
if t.strip(",")
]
else:
if raw_tools is not None:
logger.warning(
"Ignoring non-string 'allowed-tools' in %s (got %s)",
skill_path,
type(raw_tools).__name__,
)
allowed_tools = []
# 能力或环境兼容性说明,最多 500 字符
compatibility_str = str(frontmatter_data.get("compatibility", "")).strip() or None
if compatibility_str and len(compatibility_str) > MAX_SKILL_COMPATIBILITY_LENGTH:
logger.warning(
"Compatibility exceeds %d characters in %s, truncating",
MAX_SKILL_COMPATIBILITY_LENGTH,
skill_path,
)
compatibility_str = str(compatibility_str)[:MAX_SKILL_COMPATIBILITY_LENGTH]
# 版本号,默认为 0(表示未设置版本)
raw_version = frontmatter_data.get("version")
version = 0
if raw_version is not None:
try:
version = int(raw_version)
except (ValueError, TypeError):
logger.warning(
"Invalid 'version' in %s (got %r), defaulting to 0",
skill_path,
raw_version,
)
return SkillMetadata(
id=skill_id,
name=name,
version=version,
description=description_str,
path=skill_path,
metadata=_validate_metadata(frontmatter_data.get("metadata", {}), skill_path),
license=str(frontmatter_data.get("license", "")).strip() or None,
compatibility=compatibility_str,
allowed_tools=allowed_tools,
)
def _validate_metadata(
raw: object,
skill_path: str,
) -> dict[str, str]:
"""验证并规范化 YAML 前言中的元数据字段,确保为 dict[str, str] 类型。"""
if not isinstance(raw, dict):
if raw:
logger.warning(
"Ignoring non-dict metadata in %s (got %s)",
skill_path,
type(raw).__name__,
)
return {}
return {str(k): str(v) for k, v in raw.items()}
def _format_skill_annotations(skill: SkillMetadata) -> str: def _format_skill_annotations(skill: SkillMetadata) -> str:
"""构建许可证和兼容性说明字符串。""" """构建许可证和兼容性说明字符串。"""
parts: list[str] = [] parts: list[str] = []
@@ -264,7 +107,7 @@ async def _alist_skills(source_path: AsyncPath) -> list[SkillMetadata]:
) )
# 解析元数据 # 解析元数据
skill_metadata = _parse_skill_metadata( skill_metadata = parse_skill_metadata(
content=skill_content, content=skill_content,
skill_path=str(skill_md_path), skill_path=str(skill_md_path),
skill_id=skill_path.name, skill_id=skill_path.name,
@@ -303,7 +146,7 @@ def _list_skills(source_path: Path) -> list[SkillMetadata]:
skill_content = skill_md_path.read_bytes().decode( skill_content = skill_md_path.read_bytes().decode(
"utf-8", errors="replace" "utf-8", errors="replace"
) )
skill_metadata = _parse_skill_metadata( skill_metadata = parse_skill_metadata(
content=skill_content, content=skill_content,
skill_path=str(skill_md_path), skill_path=str(skill_md_path),
skill_id=skill_path.name, skill_id=skill_path.name,
+1 -1
View File
@@ -37,7 +37,7 @@ from app.agent.policy import (
from app.agent.runtime import SubAgentDefinition, agent_runtime_manager from app.agent.runtime import SubAgentDefinition, agent_runtime_manager
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.agent.tools.catalog import ToolCatalogSnapshot from app.agent.tools.catalog import ToolCatalogSnapshot
from app.log import logger from app.platform.log import logger
SUBAGENT_TASK_TOOL_NAME = "task" SUBAGENT_TASK_TOOL_NAME = "task"
+1 -1
View File
@@ -17,7 +17,7 @@ from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.types import Command from langgraph.types import Command
from app.agent.middleware.usage import UsageMiddleware from app.agent.middleware.usage import UsageMiddleware
from app.log import logger from app.platform.log import logger
try: try:
_internal_call_metadata = import_module( _internal_call_metadata = import_module(
+1 -1
View File
@@ -28,7 +28,7 @@ from typing_extensions import TypedDict # noqa
from app.agent.llm import LLMHelper from app.agent.llm import LLMHelper
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
MIN_SELECTED_TOOL_COUNT = 4 MIN_SELECTED_TOOL_COUNT = 4
RECENT_SELECTION_CONTEXT_MESSAGE_LIMIT = 6 RECENT_SELECTION_CONTEXT_MESSAGE_LIMIT = 6
+1 -1
View File
@@ -11,7 +11,7 @@ from langchain.agents.middleware.types import (
from langchain_core.messages import AIMessage from langchain_core.messages import AIMessage
from langchain_core.messages.utils import count_tokens_approximately from langchain_core.messages.utils import count_tokens_approximately
from app.log import logger from app.platform.log import logger
class UsageMiddleware(AgentMiddleware): class UsageMiddleware(AgentMiddleware):
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -25,7 +25,7 @@ from app.agent.policy.sanitizer import (
summarize_input, summarize_input,
summarize_result, summarize_result,
) )
from app.log import logger from app.platform.log import logger
_HookResult = TypeVar("_HookResult") _HookResult = TypeVar("_HookResult")
+3 -3
View File
@@ -10,15 +10,15 @@ from typing import Any, Dict, Optional
import yaml import yaml
from app.agent.llm.capability import AgentCapabilityManager from app.agent.llm.capability import AgentCapabilityManager
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
from app.schemas import ( from app.schemas import (
ChannelCapability, ChannelCapability,
ChannelCapabilities, ChannelCapabilities,
MessageChannel, MessageChannel,
ChannelCapabilityManager, ChannelCapabilityManager,
) )
from app.utils.system import SystemUtils from app.infrastructure.system import SystemUtils
SYSTEM_TASKS_FILE = "System Tasks.yaml" SYSTEM_TASKS_FILE = "System Tasks.yaml"
SYSTEM_TASKS_SCHEMA_VERSION = 2 SYSTEM_TASKS_SCHEMA_VERSION = 2
+2 -2
View File
@@ -12,8 +12,8 @@ from typing import Any, Iterable, Optional
import yaml import yaml
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
CURRENT_PERSONA_FILE = "CURRENT_PERSONA.md" CURRENT_PERSONA_FILE = "CURRENT_PERSONA.md"
SYSTEM_RUNTIME_DIR = "runtime" SYSTEM_RUNTIME_DIR = "runtime"
+1
View File
@@ -0,0 +1 @@
"""Agent Skill 元数据、市场和本地生命周期能力。"""
+132
View File
@@ -0,0 +1,132 @@
import logging
import re
from typing import TypedDict
import yaml
logger = logging.getLogger(__name__)
# 磁盘读取上限属于 Skill 文档格式约束,市场扫描和 Agent 加载必须共用。
MAX_SKILL_FILE_SIZE = 1 * 1024 * 1024
MAX_SKILL_NAME_LENGTH = 64
MAX_SKILL_DESCRIPTION_LENGTH = 1024
MAX_SKILL_COMPATIBILITY_LENGTH = 500
class SkillMetadata(TypedDict):
"""描述符合 Agent Skills 规范的已校验元数据。"""
path: str
id: str
name: str
version: int
description: str
license: str | None
compatibility: str | None
metadata: dict[str, str]
allowed_tools: list[str]
def _validate_metadata(raw: object, skill_path: str) -> dict[str, str]:
"""将 YAML metadata 字段规范化为字符串键值映射。"""
if not isinstance(raw, dict):
if raw:
logger.warning(
"Ignoring non-dict metadata in %s (got %s)",
skill_path,
type(raw).__name__,
)
return {}
return {str(key): str(value) for key, value in raw.items()}
def parse_skill_metadata( # noqa: C901
content: str,
skill_path: str,
skill_id: str,
) -> SkillMetadata | None:
"""解析并校验一个 SKILL.md 的 YAML 前言。"""
if len(content) > MAX_SKILL_FILE_SIZE:
logger.warning(
"Skipping %s: content too large (%d bytes)", skill_path, len(content)
)
return None
match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL)
if not match:
logger.warning("Skipping %s: no valid YAML frontmatter found", skill_path)
return None
try:
frontmatter_data = yaml.safe_load(match.group(1))
except yaml.YAMLError as err:
logger.warning("Invalid YAML in %s: %s", skill_path, err)
return None
if not isinstance(frontmatter_data, dict):
logger.warning("Skipping %s: frontmatter is not a mapping", skill_path)
return None
name = str(frontmatter_data.get("name", "")).strip()
description = str(frontmatter_data.get("description", "")).strip()
if not name or not description:
logger.warning(
"Skipping %s: missing required 'name' or 'description'", skill_path
)
return None
if len(description) > MAX_SKILL_DESCRIPTION_LENGTH:
logger.warning(
"Description exceeds %d characters in %s, truncating",
MAX_SKILL_DESCRIPTION_LENGTH,
skill_path,
)
description = description[:MAX_SKILL_DESCRIPTION_LENGTH]
raw_tools = frontmatter_data.get("allowed-tools")
if isinstance(raw_tools, str):
allowed_tools = [
tool.strip(",")
for tool in raw_tools.split()
if tool.strip(",")
]
else:
if raw_tools is not None:
logger.warning(
"Ignoring non-string 'allowed-tools' in %s (got %s)",
skill_path,
type(raw_tools).__name__,
)
allowed_tools = []
compatibility = str(frontmatter_data.get("compatibility", "")).strip() or None
if compatibility and len(compatibility) > MAX_SKILL_COMPATIBILITY_LENGTH:
logger.warning(
"Compatibility exceeds %d characters in %s, truncating",
MAX_SKILL_COMPATIBILITY_LENGTH,
skill_path,
)
compatibility = compatibility[:MAX_SKILL_COMPATIBILITY_LENGTH]
raw_version = frontmatter_data.get("version")
version = 0
if raw_version is not None:
try:
version = int(raw_version)
except (ValueError, TypeError):
logger.warning(
"Invalid 'version' in %s (got %r), defaulting to 0",
skill_path,
raw_version,
)
return SkillMetadata(
id=skill_id,
name=name,
version=version,
description=description,
path=skill_path,
metadata=_validate_metadata(frontmatter_data.get("metadata", {}), skill_path),
license=str(frontmatter_data.get("license", "")).strip() or None,
compatibility=compatibility,
allowed_tools=allowed_tools,
)
@@ -9,13 +9,13 @@ from pathlib import Path
from typing import Dict, List, Optional, Tuple from typing import Dict, List, Optional, Tuple
from urllib.parse import urlencode, urljoin, urlparse from urllib.parse import urlencode, urljoin, urlparse
from app.agent.middleware.skills import _parse_skill_metadata from app.agent.skills.metadata import parse_skill_metadata
from app.core.cache import cached, fresh from app.platform.cache import cached, fresh
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
from app.utils.http import RequestUtils from app.foundation.http import RequestUtils
from app.utils.singleton import WeakSingleton from app.foundation.singleton import WeakSingleton
from app.utils.url import UrlUtils from app.foundation.url import UrlUtils
_SOURCE_META_FILENAME = ".moviepilot-skill-source.json" _SOURCE_META_FILENAME = ".moviepilot-skill-source.json"
_DEFAULT_BRANCHES = ("main", "master") _DEFAULT_BRANCHES = ("main", "master")
@@ -35,6 +35,8 @@ _OFFICIAL_SKILL_REPOS = {
@dataclass @dataclass
class SkillInfo: class SkillInfo:
"""描述本地或市场中的一个 Skill。"""
id: str id: str
name: str name: str
description: str description: str
@@ -55,6 +57,8 @@ class SkillInfo:
@dataclass @dataclass
class SkillMarketSource: class SkillMarketSource:
"""描述一个 Skill 市场来源及其可移除状态。"""
source: str source: str
label: str label: str
builtin: bool = True builtin: bool = True
@@ -386,7 +390,7 @@ class SkillHelper(metaclass=WeakSingleton):
logger.warning("读取技能文件失败:%s - %s", skill_md, e) logger.warning("读取技能文件失败:%s - %s", skill_md, e)
continue continue
metadata = _parse_skill_metadata(content, str(skill_md), path.name) metadata = parse_skill_metadata(content, str(skill_md), path.name)
if not metadata: if not metadata:
continue continue
@@ -551,7 +555,7 @@ class SkillHelper(metaclass=WeakSingleton):
logger.warning("读取市场技能失败:%s - %s", archive_name, e) logger.warning("读取市场技能失败:%s - %s", archive_name, e)
continue continue
metadata = _parse_skill_metadata( metadata = parse_skill_metadata(
content, content,
f"{repo['repo_url']}:{rel_path}", f"{repo['repo_url']}:{rel_path}",
skill_id, skill_id,
+5 -5
View File
@@ -10,7 +10,7 @@ from typing import Any, Callable, ClassVar, Optional
from langchain_core.tools import BaseTool from langchain_core.tools import BaseTool
from pydantic import PrivateAttr from pydantic import PrivateAttr
from app.agent import StreamingHandler from app.agent.callback import StreamingHandler
from app.agent.policy.sanitizer import ( from app.agent.policy.sanitizer import (
summarize_error, summarize_error,
summarize_input, summarize_input,
@@ -18,10 +18,10 @@ from app.agent.policy.sanitizer import (
) )
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain import ChainBase from app.chain import ChainBase
from app.core.config import settings from app.platform.config import settings
from app.helper.agent import matches_channel_admin from app.messaging.agent import matches_channel_admin
from app.helper.service import ServiceConfigHelper from app.extensions.service_registry import ServiceConfigHelper
from app.log import logger from app.platform.log import logger
from app.schemas import Notification from app.schemas import Notification
from app.schemas.types import MessageChannel, NotificationType from app.schemas.types import MessageChannel, NotificationType
+2 -2
View File
@@ -87,8 +87,8 @@ from app.agent.tools.impl.update_custom_identifiers import UpdateCustomIdentifie
from app.agent.tools.impl.query_system_settings import QuerySystemSettingsTool from app.agent.tools.impl.query_system_settings import QuerySystemSettingsTool
from app.agent.tools.impl.update_system_settings import UpdateSystemSettingsTool from app.agent.tools.impl.update_system_settings import UpdateSystemSettingsTool
from app.agent.llm.capability import AgentCapabilityManager from app.agent.llm.capability import AgentCapabilityManager
from app.core.plugin import PluginManager from app.extensions.plugin_manager import PluginManager
from app.log import logger from app.platform.log import logger
from app.schemas.message import ChannelCapabilityManager from app.schemas.message import ChannelCapabilityManager
from app.schemas.types import MessageChannel from app.schemas.types import MessageChannel
from .base import MoviePilotTool from .base import MoviePilotTool
+2 -2
View File
@@ -4,10 +4,10 @@ import copy
import re import re
from typing import Any, Dict, Iterable, Optional from typing import Any, Dict, Iterable, Optional
from app.core.event import eventmanager from app.platform.events import eventmanager
from app.db.subscribe_oper import SubscribeOper from app.db.subscribe_oper import SubscribeOper
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.helper.rule import RuleHelper from app.services.filter import RuleHelper
from app.modules.filter.RuleParser import RuleParser from app.modules.filter.RuleParser import RuleParser
from app.modules.filter.builtin_rules import BUILTIN_RULE_SET from app.modules.filter.builtin_rules import BUILTIN_RULE_SET
from app.schemas import CustomRule, FilterRuleGroup from app.schemas import CustomRule, FilterRuleGroup
+2 -2
View File
@@ -2,7 +2,7 @@
from typing import Any, Optional from typing import Any, Optional
from app.core.context import ( from app.domain.context import (
MusicAlbumInfo, MusicAlbumInfo,
MusicArtistInfo, MusicArtistInfo,
MusicInfo, MusicInfo,
@@ -12,7 +12,7 @@ from app.schemas.types import (
MUSIC_SUBSCRIBABLE_TYPES, MUSIC_SUBSCRIBABLE_TYPES,
media_type_to_agent, media_type_to_agent,
) )
from app.utils.media import normalize_music_type from app.domain.media import normalize_music_type
MUSIC_TRACK_PREVIEW_LIMIT = 100 MUSIC_TRACK_PREVIEW_LIMIT = 100
+4 -4
View File
@@ -4,11 +4,11 @@ import json
import shutil import shutil
from typing import Any, Optional from typing import Any, Optional
from app.core.config import settings from app.platform.config import settings
from app.core.plugin import PluginManager from app.extensions.plugin_manager import PluginManager
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.helper.server import MoviePilotServerHelper from app.integrations.server import MoviePilotServerHelper
from app.helper.plugin import PluginHelper from app.integrations.market import PluginHelper
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
# 默认只向智能体返回一个可读预览,避免超大插件数据挤爆上下文窗口。 # 默认只向智能体返回一个可读预览,避免超大插件数据挤爆上下文窗口。
@@ -4,7 +4,7 @@ from dataclasses import dataclass
from typing import Any, Optional from typing import Any, Optional
from app.agent.policy.secret_fields import is_secret_setting_key from app.agent.policy.secret_fields import is_secret_setting_key
from app.core.config import Settings from app.platform.config import Settings
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
+2 -2
View File
@@ -14,8 +14,8 @@ from pathlib import Path
from typing import Any, Optional from typing import Any, Optional
from app.agent.tools.impl._command_safety import validate_command_safety from app.agent.tools.impl._command_safety import validate_command_safety
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
if os.name == "posix": if os.name == "posix":
import fcntl as _fcntl import fcntl as _fcntl
@@ -3,10 +3,10 @@
import re import re
from typing import List, Optional from typing import List, Optional
from app.core.context import Context from app.domain.context import Context
from app.schemas.types import MediaType, media_type_to_agent from app.schemas.types import MediaType, media_type_to_agent
from app.utils.crypto import HashUtils from app.foundation.crypto import HashUtils
from app.utils.string import StringUtils from app.domain.string import StringUtils
from ._music_utils import simplify_music_info from ._music_utils import simplify_music_info
SEARCH_RESULT_CACHE_FILE = "__search_result__" SEARCH_RESULT_CACHE_FILE = "__search_result__"
@@ -13,7 +13,7 @@ from app.agent.tools.impl._filter_rule_utils import (
save_system_config, save_system_config,
serialize_custom_rule, serialize_custom_rule,
) )
from app.log import logger from app.platform.log import logger
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
+6 -6
View File
@@ -12,14 +12,14 @@ from app.agent.tools.tags import ToolTag
from app.chain.download import DownloadChain from app.chain.download import DownloadChain
from app.chain.media import MediaChain from app.chain.media import MediaChain
from app.chain.search import SearchChain from app.chain.search import SearchChain
from app.core.config import settings from app.platform.config import settings
from app.core.context import Context from app.domain.context import Context
from app.core.metainfo import MetaInfo from app.domain.metainfo import MetaInfo
from app.db.site_oper import SiteOper from app.db.site_oper import SiteOper
from app.helper.directory import DirectoryHelper, validate_download_save_path from app.services.directory import DirectoryHelper, validate_download_save_path
from app.log import logger from app.platform.log import logger
from app.schemas import FileURI from app.schemas import FileURI
from app.utils.crypto import HashUtils from app.foundation.crypto import HashUtils
class AddDownloadTasksInput(BaseModel): class AddDownloadTasksInput(BaseModel):
+1 -1
View File
@@ -17,7 +17,7 @@ from app.agent.tools.impl._filter_rule_utils import (
save_system_config, save_system_config,
serialize_rule_group, serialize_rule_group,
) )
from app.log import logger from app.platform.log import logger
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
+1 -1
View File
@@ -8,7 +8,7 @@ from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.subscribe import SubscribeChain from app.chain.subscribe import SubscribeChain
from app.db.user_oper import UserOper from app.db.user_oper import UserOper
from app.log import logger from app.platform.log import logger
from app.schemas.types import MUSIC_ENTITY_ALBUM, MediaSource, MediaType, MessageChannel from app.schemas.types import MUSIC_ENTITY_ALBUM, MediaSource, MediaType, MessageChannel
from ._music_utils import normalize_music_type from ._music_utils import normalize_music_type
+2 -2
View File
@@ -6,11 +6,11 @@ from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.helper.interaction import ( from app.messaging.interaction import (
AgentInteractionOption, AgentInteractionOption,
agent_interaction_manager, agent_interaction_manager,
) )
from app.log import logger from app.platform.log import logger
from app.schemas import Notification, NotificationType from app.schemas import Notification, NotificationType
from app.schemas.message import ChannelCapabilityManager from app.schemas.message import ChannelCapabilityManager
from app.schemas.types import MessageChannel from app.schemas.types import MessageChannel
+2 -2
View File
@@ -9,8 +9,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.helper.browser import BrowserSessionHelper from app.infrastructure.browser import BrowserSessionHelper
from app.log import logger from app.platform.log import logger
# 页面内容最大长度;保留在全局工具结果兜底上限以内。 # 页面内容最大长度;保留在全局工具结果兜底上限以内。
MAX_CONTENT_LENGTH = 12_000 MAX_CONTENT_LENGTH = 12_000
+2 -2
View File
@@ -7,10 +7,10 @@ from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.config import settings from app.platform.config import settings
from app.db.agentchat_oper import AgentChatOper from app.db.agentchat_oper import AgentChatOper
from app.db.agenttask_oper import AgentTaskOper from app.db.agenttask_oper import AgentTaskOper
from app.utils.timer import TimerUtils from app.platform.scheduling import TimerUtils
class CreateAgentTaskInput(BaseModel): class CreateAgentTaskInput(BaseModel):
@@ -13,7 +13,7 @@ from app.agent.tools.impl._filter_rule_utils import (
get_rule_groups, get_rule_groups,
save_system_config, save_system_config,
) )
from app.log import logger from app.platform.log import logger
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.downloadhistory_oper import DownloadHistoryOper from app.db.downloadhistory_oper import DownloadHistoryOper
from app.log import logger from app.platform.log import logger
class DeleteDownloadHistoryInput(BaseModel): class DeleteDownloadHistoryInput(BaseModel):
@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.download import DownloadChain from app.chain.download import DownloadChain
from app.log import logger from app.platform.log import logger
class DeleteDownloadTasksInput(BaseModel): class DeleteDownloadTasksInput(BaseModel):
+1 -1
View File
@@ -12,7 +12,7 @@ from app.agent.tools.impl._filter_rule_utils import (
remove_rule_group_references, remove_rule_group_references,
save_system_config, save_system_config,
) )
from app.log import logger from app.platform.log import logger
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
+3 -3
View File
@@ -6,10 +6,10 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.event import eventmanager from app.platform.events import eventmanager
from app.db.subscribe_oper import SubscribeOper from app.db.subscribe_oper import SubscribeOper
from app.helper.server import MoviePilotServerHelper from app.integrations.server import MoviePilotServerHelper
from app.log import logger from app.platform.log import logger
from app.schemas.types import EventType from app.schemas.types import EventType
@@ -8,7 +8,7 @@ from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.storage import StorageChain from app.chain.storage import StorageChain
from app.db.transferhistory_oper import TransferHistoryOper from app.db.transferhistory_oper import TransferHistoryOper
from app.log import logger from app.platform.log import logger
from app.schemas import FileItem from app.schemas import FileItem
+1 -1
View File
@@ -13,7 +13,7 @@ from app.agent.tools.impl._file_write_utils import (
calculate_file_sha256, calculate_file_sha256,
) )
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
class EditFileInput(BaseModel): class EditFileInput(BaseModel):
+1 -1
View File
@@ -23,7 +23,7 @@ from app.agent.tools.impl._terminal_session import (
TERMINAL_WAIT_DEFAULT_MS, TERMINAL_WAIT_DEFAULT_MS,
terminal_session_manager, terminal_session_manager,
) )
from app.log import logger from app.platform.log import logger
DEFAULT_TIMEOUT_SECONDS = 60 DEFAULT_TIMEOUT_SECONDS = 60
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.recommend import RecommendChain from app.chain.recommend import RecommendChain
from app.log import logger from app.platform.log import logger
from app.modules.listenbrainz import ( from app.modules.listenbrainz import (
LISTENBRAINZ_CHART_RANGES, LISTENBRAINZ_CHART_RANGES,
LISTENBRAINZ_FRESH_MAX_DAYS, LISTENBRAINZ_FRESH_MAX_DAYS,
+1 -1
View File
@@ -9,7 +9,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.search import SearchChain from app.chain.search import SearchChain
from app.log import logger from app.platform.log import logger
from ._torrent_search_utils import ( from ._torrent_search_utils import (
TORRENT_RESULT_LIMIT, TORRENT_RESULT_LIMIT,
build_filter_options, build_filter_options,
+1 -1
View File
@@ -13,7 +13,7 @@ from app.agent.tools.impl._plugin_tool_utils import (
load_market_plugins, load_market_plugins,
summarize_plugin, summarize_plugin,
) )
from app.log import logger from app.platform.log import logger
class InstallPluginInput(BaseModel): class InstallPluginInput(BaseModel):
+2 -2
View File
@@ -10,9 +10,9 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.storage import StorageChain from app.chain.storage import StorageChain
from app.log import logger from app.platform.log import logger
from app.schemas.file import FileItem from app.schemas.file import FileItem
from app.utils.string import StringUtils from app.domain.string import StringUtils
DEFAULT_DIRECTORY_PAGE_SIZE = 50 DEFAULT_DIRECTORY_PAGE_SIZE = 50
+1 -1
View File
@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
class ListSlashCommandsInput(BaseModel): class ListSlashCommandsInput(BaseModel):
+1 -1
View File
@@ -5,7 +5,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.config import settings from app.platform.config import settings
from app.db.agenttask_oper import AgentTaskOper from app.db.agenttask_oper import AgentTaskOper
@@ -12,7 +12,7 @@ from app.agent.tools.impl._filter_rule_utils import (
serialize_builtin_rule, serialize_builtin_rule,
RULE_STRING_SYNTAX, RULE_STRING_SYNTAX,
) )
from app.log import logger from app.platform.log import logger
class QueryBuiltinFilterRulesInput(BaseModel): class QueryBuiltinFilterRulesInput(BaseModel):
@@ -13,7 +13,7 @@ from app.agent.tools.impl._filter_rule_utils import (
get_rule_groups, get_rule_groups,
serialize_custom_rule, serialize_custom_rule,
) )
from app.log import logger from app.platform.log import logger
class QueryCustomFilterRulesInput(BaseModel): class QueryCustomFilterRulesInput(BaseModel):
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger from app.platform.log import logger
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
@@ -7,8 +7,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.helper.directory import DirectoryHelper from app.services.directory import DirectoryHelper
from app.log import logger from app.platform.log import logger
class QueryDirectorySettingsInput(BaseModel): class QueryDirectorySettingsInput(BaseModel):
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.doctor import run_doctor from app.doctor import run_doctor
from app.log import logger from app.platform.log import logger
class QueryDoctorReportInput(BaseModel): class QueryDoctorReportInput(BaseModel):
+1 -1
View File
@@ -9,7 +9,7 @@ from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.download import DownloadChain from app.chain.download import DownloadChain
from app.db.downloadhistory_oper import DownloadHistoryOper from app.db.downloadhistory_oper import DownloadHistoryOper
from app.log import logger from app.platform.log import logger
from app.schemas import DownloaderTorrent from app.schemas import DownloaderTorrent
from app.schemas.types import MUSIC_ENTITY_RECORDING, TorrentQueryStatus, media_type_to_agent from app.schemas.types import MUSIC_ENTITY_RECORDING, TorrentQueryStatus, media_type_to_agent
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger from app.platform.log import logger
from app.schemas.types import SystemConfigKey from app.schemas.types import SystemConfigKey
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.tmdb import TmdbChain from app.chain.tmdb import TmdbChain
from app.log import logger from app.platform.log import logger
class QueryEpisodeScheduleInput(BaseModel): class QueryEpisodeScheduleInput(BaseModel):
@@ -16,7 +16,7 @@ from app.agent.tools.impl._plugin_tool_utils import (
summarize_candidates, summarize_candidates,
summarize_plugin, summarize_plugin,
) )
from app.log import logger from app.platform.log import logger
class QueryInstalledPluginsInput(BaseModel): class QueryInstalledPluginsInput(BaseModel):
+2 -2
View File
@@ -10,8 +10,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.mediaserver import MediaServerChain from app.chain.mediaserver import MediaServerChain
from app.helper.mediaserver import MediaServerHelper from app.services.mediaserver import MediaServerHelper
from app.log import logger from app.platform.log import logger
from app.schemas.types import ( from app.schemas.types import (
MUSIC_ENTITY_ALBUM, MUSIC_ENTITY_ALBUM,
MediaSource, MediaSource,
+2 -2
View File
@@ -9,8 +9,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.mediaserver import MediaServerChain from app.chain.mediaserver import MediaServerChain
from app.helper.service import ServiceConfigHelper from app.extensions.service_registry import ServiceConfigHelper
from app.log import logger from app.platform.log import logger
PAGE_SIZE = 20 PAGE_SIZE = 20
+1 -1
View File
@@ -15,7 +15,7 @@ from app.agent.tools.impl._plugin_tool_utils import (
summarize_candidates, summarize_candidates,
summarize_plugin, summarize_plugin,
) )
from app.log import logger from app.platform.log import logger
class QueryMarketPluginsInput(BaseModel): class QueryMarketPluginsInput(BaseModel):
+1 -1
View File
@@ -9,7 +9,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.media import MediaChain from app.chain.media import MediaChain
from app.log import logger from app.platform.log import logger
from app.schemas.types import ( from app.schemas.types import (
MUSIC_ENTITY_ALBUM, MUSIC_ENTITY_ALBUM,
MUSIC_ENTITY_ARTIST, MUSIC_ENTITY_ARTIST,
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.runtime import agent_runtime_manager from app.agent.runtime import agent_runtime_manager
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
class QueryPersonasInput(BaseModel): class QueryPersonasInput(BaseModel):
@@ -7,8 +7,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.plugin import PluginManager from app.extensions.plugin_manager import PluginManager
from app.log import logger from app.platform.log import logger
class QueryPluginCapabilitiesInput(BaseModel): class QueryPluginCapabilitiesInput(BaseModel):
+2 -2
View File
@@ -8,8 +8,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.agent.tools.impl._plugin_tool_utils import get_plugin_snapshot from app.agent.tools.impl._plugin_tool_utils import get_plugin_snapshot
from app.core.plugin import PluginManager from app.extensions.plugin_manager import PluginManager
from app.log import logger from app.platform.log import logger
class QueryPluginConfigInput(BaseModel): class QueryPluginConfigInput(BaseModel):
+1 -1
View File
@@ -13,7 +13,7 @@ from app.agent.tools.impl._plugin_tool_utils import (
get_plugin_snapshot, get_plugin_snapshot,
) )
from app.db.plugindata_oper import PluginDataOper from app.db.plugindata_oper import PluginDataOper
from app.log import logger from app.platform.log import logger
class QueryPluginDataInput(BaseModel): class QueryPluginDataInput(BaseModel):
@@ -8,9 +8,9 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.context import MediaInfo from app.domain.context import MediaInfo
from app.helper.server import MoviePilotServerHelper from app.integrations.server import MoviePilotServerHelper
from app.log import logger from app.platform.log import logger
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaType, media_type_to_agent from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaType, media_type_to_agent
from ._music_utils import normalize_music_type from ._music_utils import normalize_music_type
+1 -1
View File
@@ -13,7 +13,7 @@ from app.agent.tools.impl._filter_rule_utils import (
serialize_rule_group, serialize_rule_group,
RULE_STRING_SYNTAX, RULE_STRING_SYNTAX,
) )
from app.log import logger from app.platform.log import logger
class QueryRuleGroupsInput(BaseModel): class QueryRuleGroupsInput(BaseModel):
+1 -1
View File
@@ -7,7 +7,7 @@ from pydantic import BaseModel
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
class QuerySchedulersInput(BaseModel): class QuerySchedulersInput(BaseModel):
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.site_oper import SiteOper from app.db.site_oper import SiteOper
from app.log import logger from app.platform.log import logger
SITE_USERDATA_DETAIL_PREVIEW_LIMIT = 10 SITE_USERDATA_DETAIL_PREVIEW_LIMIT = 10
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.site_oper import SiteOper from app.db.site_oper import SiteOper
from app.log import logger from app.platform.log import logger
class QuerySitesInput(BaseModel): class QuerySitesInput(BaseModel):
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.subscribehistory_oper import SubscribeHistoryOper from app.db.subscribehistory_oper import SubscribeHistoryOper
from app.log import logger from app.platform.log import logger
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaType, media_type_to_agent from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaType, media_type_to_agent
from ._music_utils import normalize_music_type from ._music_utils import normalize_music_type
@@ -7,8 +7,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.helper.server import MoviePilotServerHelper from app.integrations.server import MoviePilotServerHelper
from app.log import logger from app.platform.log import logger
from app.schemas.types import MUSIC_ENTITY_RECORDING, media_type_to_agent from app.schemas.types import MUSIC_ENTITY_RECORDING, media_type_to_agent
from ._music_utils import normalize_music_type from ._music_utils import normalize_music_type
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.subscribe_oper import SubscribeOper from app.db.subscribe_oper import SubscribeOper
from app.log import logger from app.platform.log import logger
from app.schemas.subscribe import Subscribe as SubscribeSchema from app.schemas.subscribe import Subscribe as SubscribeSchema
from app.schemas.types import ( from app.schemas.types import (
MUSIC_ENTITY_RECORDING, MUSIC_ENTITY_RECORDING,
@@ -15,9 +15,9 @@ from app.agent.tools.impl._system_setting_utils import (
resolve_setting_spec, resolve_setting_spec,
should_redact_setting, should_redact_setting,
) )
from app.core.config import settings from app.platform.config import settings
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger from app.platform.log import logger
class QuerySystemSettingsInput(BaseModel): class QuerySystemSettingsInput(BaseModel):
@@ -8,9 +8,9 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.transferhistory_oper import TransferHistoryOper from app.db.transferhistory_oper import TransferHistoryOper
from app.log import logger from app.platform.log import logger
from app.schemas.types import media_type_to_agent from app.schemas.types import media_type_to_agent
from app.utils.jieba import cut as jieba_cut from app.foundation.jieba import cut as jieba_cut
class QueryTransferHistoryInput(BaseModel): class QueryTransferHistoryInput(BaseModel):
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.db.workflow_oper import WorkflowOper from app.db.workflow_oper import WorkflowOper
from app.log import logger from app.platform.log import logger
class QueryWorkflowsInput(BaseModel): class QueryWorkflowsInput(BaseModel):
+1 -1
View File
@@ -10,7 +10,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
# 最大读取大小 50KB # 最大读取大小 50KB
MAX_READ_SIZE = 50 * 1024 MAX_READ_SIZE = 50 * 1024
+3 -3
View File
@@ -7,9 +7,9 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.helper.browser import BrowserSessionHelper from app.infrastructure.browser import BrowserSessionHelper
from app.helper.ocr import OcrHelper from app.integrations.ocr import OcrHelper
from app.log import logger from app.platform.log import logger
class RecognizeCaptchaInput(BaseModel): class RecognizeCaptchaInput(BaseModel):
+5 -5
View File
@@ -9,11 +9,11 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.media import MediaChain from app.chain.media import MediaChain
from app.core.config import settings from app.platform.config import settings
from app.core.context import Context from app.domain.context import Context
from app.core.meta import MetaMusic from app.domain.meta.metamusic import MetaMusic
from app.core.metainfo import MetaInfo from app.domain.metainfo import MetaInfo
from app.log import logger from app.platform.log import logger
from app.schemas.types import MediaType, media_type_to_agent from app.schemas.types import MediaType, media_type_to_agent
from ._music_utils import simplify_music_info from ._music_utils import simplify_music_info
+1 -1
View File
@@ -11,7 +11,7 @@ from app.agent.tools.impl._plugin_tool_utils import (
get_plugin_snapshot, get_plugin_snapshot,
reload_plugin_runtime, reload_plugin_runtime,
) )
from app.log import logger from app.platform.log import logger
class ReloadPluginInput(BaseModel): class ReloadPluginInput(BaseModel):
+1 -1
View File
@@ -6,7 +6,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
class RunSchedulerInput(BaseModel): class RunSchedulerInput(BaseModel):
+2 -2
View File
@@ -7,8 +7,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.event import eventmanager from app.platform.events import eventmanager
from app.log import logger from app.platform.log import logger
from app.schemas.types import EventType, MessageChannel from app.schemas.types import EventType, MessageChannel
+1 -1
View File
@@ -8,7 +8,7 @@ from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.workflow import WorkflowChain from app.chain.workflow import WorkflowChain
from app.db.workflow_oper import WorkflowOper from app.db.workflow_oper import WorkflowOper
from app.log import logger from app.platform.log import logger
class RunWorkflowInput(BaseModel): class RunWorkflowInput(BaseModel):
+3 -3
View File
@@ -10,8 +10,8 @@ from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.media import MediaChain from app.chain.media import MediaChain
from app.chain.scraping import ScrapingChain from app.chain.scraping import ScrapingChain
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
from app.schemas import FileItem from app.schemas import FileItem
from app.schemas.types import ( from app.schemas.types import (
MUSIC_ENTITY_ARTIST, MUSIC_ENTITY_ARTIST,
@@ -19,7 +19,7 @@ from app.schemas.types import (
MediaType, MediaType,
media_type_to_agent, media_type_to_agent,
) )
from app.utils.media import normalize_media_source from app.domain.media import normalize_media_source
from ._music_utils import normalize_music_type, simplify_music_info from ._music_utils import normalize_music_type, simplify_music_info
+2 -2
View File
@@ -8,9 +8,9 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.media import MediaChain from app.chain.media import MediaChain
from app.log import logger from app.platform.log import logger
from app.schemas.types import MediaType, media_type_to_agent from app.schemas.types import MediaType, media_type_to_agent
from app.utils.media import resolve_media_identity from app.domain.media import resolve_media_identity
from ._music_utils import normalize_music_type, simplify_music_info from ._music_utils import normalize_music_type, simplify_music_info
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.media import MediaChain from app.chain.media import MediaChain
from app.log import logger from app.platform.log import logger
class SearchPersonInput(BaseModel): class SearchPersonInput(BaseModel):
@@ -10,8 +10,8 @@ from app.agent.tools.tags import ToolTag
from app.chain.douban import DoubanChain from app.chain.douban import DoubanChain
from app.chain.tmdb import TmdbChain from app.chain.tmdb import TmdbChain
from app.chain.bangumi import BangumiChain from app.chain.bangumi import BangumiChain
from app.log import logger from app.platform.log import logger
from app.utils.media import resolve_media_identity from app.domain.media import resolve_media_identity
class SearchPersonCreditsInput(BaseModel): class SearchPersonCreditsInput(BaseModel):
+1 -1
View File
@@ -9,7 +9,7 @@ from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.subscribe import SubscribeChain from app.chain.subscribe import SubscribeChain
from app.db.subscribe_oper import SubscribeOper from app.db.subscribe_oper import SubscribeOper
from app.log import logger from app.platform.log import logger
from app.schemas.types import media_type_to_agent from app.schemas.types import media_type_to_agent
+2 -2
View File
@@ -9,8 +9,8 @@ from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.chain.search import SearchChain from app.chain.search import SearchChain
from app.db.systemconfig_oper import SystemConfigOper from app.db.systemconfig_oper import SystemConfigOper
from app.helper.sites import SitesHelper # noqa from app.infrastructure.sites import SitesHelper # noqa
from app.log import logger from app.platform.log import logger
from app.schemas.types import MediaSource, MediaType, SystemConfigKey from app.schemas.types import MediaSource, MediaType, SystemConfigKey
from ._music_utils import normalize_music_type from ._music_utils import normalize_music_type
from ._torrent_search_utils import ( from ._torrent_search_utils import (
+2 -2
View File
@@ -9,8 +9,8 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
# 搜索超时时间(秒) # 搜索超时时间(秒)
SEARCH_TIMEOUT = 20 SEARCH_TIMEOUT = 20
+1 -1
View File
@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
from app.schemas import Notification, NotificationType from app.schemas import Notification, NotificationType
from app.schemas.message import ChannelCapabilityManager, ChannelCapability from app.schemas.message import ChannelCapabilityManager, ChannelCapability
from app.schemas.types import MessageChannel from app.schemas.types import MessageChannel
+1 -1
View File
@@ -6,7 +6,7 @@ from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.log import logger from app.platform.log import logger
from app.schemas import Notification from app.schemas import Notification
from app.schemas.types import NotificationType from app.schemas.types import NotificationType
+2 -2
View File
@@ -6,8 +6,8 @@ from pydantic import BaseModel, Field
from app.agent.llm.capability import AgentCapabilityManager from app.agent.llm.capability import AgentCapabilityManager
from app.agent.tools.base import MoviePilotTool from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag from app.agent.tools.tags import ToolTag
from app.core.config import settings from app.platform.config import settings
from app.log import logger from app.platform.log import logger
from app.schemas import Notification, NotificationType from app.schemas import Notification, NotificationType

Some files were not shown because too many files have changed in this diff Show More