Merge remote-tracking branch 'origin/main' into feat/knowledge-retrieval-core
# Conflicts: # README.md # backend/app/routes.py # docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md # docs/development/Knowledge与Retrieval-Core开发说明.md
This commit is contained in:
+259
-2
@@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Any, Literal
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, SecretStr, field_validator
|
||||
|
||||
@@ -205,7 +205,7 @@ class ToolDefinition(Contract):
|
||||
description: str
|
||||
parameters: dict[str, Any] = Field(default_factory=dict)
|
||||
permission: str | None = None
|
||||
source: Literal["builtin", "plugin"] = "builtin"
|
||||
source: Literal["builtin", "plugin", "mcp_server"] = "builtin"
|
||||
|
||||
|
||||
class ToolCall(Contract):
|
||||
@@ -492,6 +492,263 @@ class PluginHostStatus(Contract):
|
||||
error: str | None = None
|
||||
|
||||
|
||||
# Independent user-managed MCP Server Registry. This is deliberately separate
|
||||
# from Plugin manifests: a server can contribute tools without being a Plugin.
|
||||
class McpServerTransport(str, Enum):
|
||||
stdio = "stdio"
|
||||
streamable_http = "streamable_http"
|
||||
sse = "sse"
|
||||
|
||||
|
||||
class McpServerConfig(Contract):
|
||||
name: str = Field(min_length=1, max_length=80)
|
||||
transport: McpServerTransport = McpServerTransport.stdio
|
||||
command: str | None = Field(default=None, max_length=1024)
|
||||
args: list[str] = Field(default_factory=list, max_length=64)
|
||||
url: str | None = Field(default=None, max_length=4096)
|
||||
headers: dict[str, str] = Field(default_factory=dict)
|
||||
environment: dict[str, str] = Field(default_factory=dict)
|
||||
secret_environment_keys: list[str] = Field(default_factory=list)
|
||||
secret_header_keys: list[str] = Field(default_factory=list)
|
||||
permissions: list[str] = Field(default_factory=list)
|
||||
startup_timeout_seconds: float = Field(default=15, ge=1, le=120)
|
||||
tool_timeout_seconds: float = Field(default=30, ge=1, le=300)
|
||||
|
||||
|
||||
class McpServerCreateRequest(McpServerConfig):
|
||||
pass
|
||||
|
||||
|
||||
class McpServerUpdateRequest(McpServerConfig):
|
||||
version: int = Field(ge=1)
|
||||
|
||||
|
||||
class McpServerSecretWriteRequest(Contract):
|
||||
secret: SecretStr = Field(min_length=1, max_length=32768)
|
||||
|
||||
|
||||
class McpServerSecretStatus(Contract):
|
||||
key: str
|
||||
configured: bool
|
||||
|
||||
|
||||
class McpServerTrustRequest(Contract):
|
||||
command_digest: str = Field(min_length=64, max_length=64)
|
||||
|
||||
|
||||
class McpServerStatus(Contract):
|
||||
enabled: bool = False
|
||||
status: PluginHostState = PluginHostState.stopped
|
||||
tools_count: int = 0
|
||||
protocol_version: str | None = None
|
||||
remote_server_name: str | None = None
|
||||
remote_server_version: str | None = None
|
||||
error: str | None = None
|
||||
last_tested_at: datetime | None = None
|
||||
last_test_succeeded: bool | None = None
|
||||
|
||||
|
||||
class McpServer(McpServerStatus):
|
||||
server_id: str
|
||||
version: int
|
||||
name: str
|
||||
transport: McpServerTransport
|
||||
command: str | None = None
|
||||
args: list[str] = Field(default_factory=list)
|
||||
url: str | None = None
|
||||
headers: dict[str, str] = Field(default_factory=dict)
|
||||
environment: dict[str, str] = Field(default_factory=dict)
|
||||
permissions: list[str] = Field(default_factory=list)
|
||||
startup_timeout_seconds: float
|
||||
tool_timeout_seconds: float
|
||||
secret_environment: dict[str, bool] = Field(default_factory=dict)
|
||||
secret_headers: dict[str, bool] = Field(default_factory=dict)
|
||||
trusted: bool = False
|
||||
command_digest: str
|
||||
command_summary: str
|
||||
|
||||
|
||||
class McpServerListResponse(Contract):
|
||||
items: list[McpServer] = Field(default_factory=list)
|
||||
|
||||
|
||||
class McpToolSummary(Contract):
|
||||
name: str
|
||||
remote_name: str
|
||||
description: str
|
||||
permission: str | None = None
|
||||
|
||||
|
||||
class McpToolSummaryListResponse(Contract):
|
||||
items: list[McpToolSummary] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PluginCommandLocation(str, Enum):
|
||||
command_palette = "command_palette"
|
||||
context_menu = "context_menu"
|
||||
toolbar = "toolbar"
|
||||
|
||||
|
||||
class PluginCommand(Contract):
|
||||
command_id: str
|
||||
plugin_id: str
|
||||
title: str
|
||||
description: str = ""
|
||||
icon: str | None = None
|
||||
locations: list[PluginCommandLocation] = Field(default_factory=list)
|
||||
when: list[str] = Field(default_factory=list)
|
||||
parameters: dict[str, Any] = Field(default_factory=dict)
|
||||
enabled: bool = True
|
||||
|
||||
|
||||
class PluginCommandListResponse(Contract):
|
||||
items: list[PluginCommand] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PluginCommandContext(Contract):
|
||||
vault_id: str | None = None
|
||||
note_id: str | None = None
|
||||
file_path: str | None = None
|
||||
selection: str | None = None
|
||||
|
||||
|
||||
class PluginCommandExecuteRequest(Contract):
|
||||
arguments: dict[str, Any] = Field(default_factory=dict)
|
||||
context: PluginCommandContext = Field(default_factory=PluginCommandContext)
|
||||
|
||||
|
||||
class PluginNotificationEffectPayload(Contract):
|
||||
level: Literal["info", "success", "warning", "error"] = "info"
|
||||
message: str = Field(min_length=1, max_length=4096)
|
||||
|
||||
|
||||
class PluginNavigateEffectPayload(Contract):
|
||||
route: Literal[
|
||||
"vault-entry",
|
||||
"workspace",
|
||||
"search",
|
||||
"chat",
|
||||
"agent",
|
||||
"tasks",
|
||||
"skills",
|
||||
"plugins",
|
||||
"themes",
|
||||
"settings",
|
||||
]
|
||||
|
||||
|
||||
class PluginRefreshEffectPayload(Contract):
|
||||
scope: Literal["workspace", "commands", "settings", "plugins"]
|
||||
|
||||
|
||||
class PluginJobEffectPayload(Contract):
|
||||
job_id: str = Field(
|
||||
min_length=1,
|
||||
max_length=128,
|
||||
pattern=r"^[A-Za-z0-9][A-Za-z0-9._:-]*$",
|
||||
)
|
||||
|
||||
|
||||
class PluginNoEffectPayload(Contract):
|
||||
pass
|
||||
|
||||
|
||||
class PluginNoEffect(Contract):
|
||||
type: Literal["none"] = "none"
|
||||
payload: PluginNoEffectPayload = Field(default_factory=PluginNoEffectPayload)
|
||||
|
||||
|
||||
class PluginNotificationEffect(Contract):
|
||||
type: Literal["notification"] = "notification"
|
||||
payload: PluginNotificationEffectPayload
|
||||
|
||||
|
||||
class PluginNavigateEffect(Contract):
|
||||
type: Literal["navigate"] = "navigate"
|
||||
payload: PluginNavigateEffectPayload
|
||||
|
||||
|
||||
class PluginRefreshEffect(Contract):
|
||||
type: Literal["refresh"] = "refresh"
|
||||
payload: PluginRefreshEffectPayload
|
||||
|
||||
|
||||
class PluginJobEffect(Contract):
|
||||
type: Literal["job"] = "job"
|
||||
payload: PluginJobEffectPayload
|
||||
|
||||
|
||||
PluginCommandEffect = Annotated[
|
||||
PluginNoEffect
|
||||
| PluginNotificationEffect
|
||||
| PluginNavigateEffect
|
||||
| PluginRefreshEffect
|
||||
| PluginJobEffect,
|
||||
Field(discriminator="type"),
|
||||
]
|
||||
|
||||
PLUGIN_COMMAND_EFFECT_TYPES = (
|
||||
PluginNoEffect,
|
||||
PluginNotificationEffect,
|
||||
PluginNavigateEffect,
|
||||
PluginRefreshEffect,
|
||||
PluginJobEffect,
|
||||
)
|
||||
|
||||
|
||||
class PluginCommandResult(Contract):
|
||||
command_id: str
|
||||
status: Literal["completed"] = "completed"
|
||||
effect: PluginCommandEffect = Field(default_factory=PluginNoEffect)
|
||||
|
||||
|
||||
class PluginSettingType(str, Enum):
|
||||
string = "string"
|
||||
number = "number"
|
||||
boolean = "boolean"
|
||||
select = "select"
|
||||
secret = "secret"
|
||||
|
||||
|
||||
class PluginSettingField(Contract):
|
||||
key: str
|
||||
label: str
|
||||
description: str = ""
|
||||
type: PluginSettingType
|
||||
required: bool = False
|
||||
default: Any | None = None
|
||||
minimum: float | None = None
|
||||
maximum: float | None = None
|
||||
options: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PluginSecretState(Contract):
|
||||
configured: bool = False
|
||||
|
||||
|
||||
class PluginSettingsSchema(Contract):
|
||||
plugin_id: str
|
||||
schema_version: int = Field(ge=1)
|
||||
fields: list[PluginSettingField] = Field(default_factory=list)
|
||||
values: dict[str, Any] = Field(default_factory=dict)
|
||||
secrets: dict[str, PluginSecretState] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class PluginSettingsUpdateRequest(Contract):
|
||||
schema_version: int = Field(ge=1)
|
||||
values: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class PluginSecretWriteRequest(Contract):
|
||||
secret: SecretStr
|
||||
|
||||
|
||||
class PluginSecretStatus(Contract):
|
||||
plugin_id: str
|
||||
key: str
|
||||
configured: bool
|
||||
|
||||
|
||||
class PluginPermissionGrantRequest(Contract):
|
||||
permissions: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user