illusion-code 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- illusion/__init__.py +24 -0
- illusion/__main__.py +15 -0
- illusion/_frontend/dist/index.mjs +39208 -0
- illusion/_frontend/package.json +27 -0
- illusion/_frontend/src/App.tsx +624 -0
- illusion/_frontend/src/components/CommandPicker.tsx +98 -0
- illusion/_frontend/src/components/Composer.tsx +55 -0
- illusion/_frontend/src/components/ComposerController.tsx +128 -0
- illusion/_frontend/src/components/ConversationView.tsx +750 -0
- illusion/_frontend/src/components/Footer.tsx +25 -0
- illusion/_frontend/src/components/MarkdownContent.tsx +537 -0
- illusion/_frontend/src/components/MarkdownTable.tsx +245 -0
- illusion/_frontend/src/components/ModalHost.tsx +425 -0
- illusion/_frontend/src/components/MultilineTextInput.tsx +250 -0
- illusion/_frontend/src/components/PromptInput.tsx +64 -0
- illusion/_frontend/src/components/SelectModal.tsx +78 -0
- illusion/_frontend/src/components/SidePanel.tsx +175 -0
- illusion/_frontend/src/components/Spinner.tsx +77 -0
- illusion/_frontend/src/components/StatusBar.tsx +142 -0
- illusion/_frontend/src/components/SwarmPanel.tsx +141 -0
- illusion/_frontend/src/components/TodoPanel.tsx +126 -0
- illusion/_frontend/src/components/ToolCallDisplay.tsx +202 -0
- illusion/_frontend/src/components/TranscriptPane.tsx +79 -0
- illusion/_frontend/src/components/WelcomeBanner.tsx +37 -0
- illusion/_frontend/src/hooks/useBackendSession.ts +468 -0
- illusion/_frontend/src/hooks/useTerminalSize.ts +9 -0
- illusion/_frontend/src/i18n.ts +78 -0
- illusion/_frontend/src/index.tsx +42 -0
- illusion/_frontend/src/theme/ThemeContext.tsx +19 -0
- illusion/_frontend/src/theme/builtinThemes.ts +89 -0
- illusion/_frontend/src/types.ts +110 -0
- illusion/_frontend/src/utils/markdown.ts +33 -0
- illusion/_frontend/src/utils/thinking.ts +191 -0
- illusion/_frontend/tsconfig.json +13 -0
- illusion/_web_dist/assets/index-BseIw-ik.css +10 -0
- illusion/_web_dist/assets/index-C_0ZWMuW.js +82 -0
- illusion/_web_dist/index.html +16 -0
- illusion/api/__init__.py +36 -0
- illusion/api/client.py +568 -0
- illusion/api/codex_client.py +563 -0
- illusion/api/compat.py +138 -0
- illusion/api/effort.py +128 -0
- illusion/api/errors.py +57 -0
- illusion/api/openai_client.py +819 -0
- illusion/api/provider.py +148 -0
- illusion/api/registry.py +479 -0
- illusion/api/usage.py +45 -0
- illusion/auth/__init__.py +50 -0
- illusion/auth/copilot.py +419 -0
- illusion/auth/external.py +612 -0
- illusion/auth/flows.py +58 -0
- illusion/auth/manager.py +214 -0
- illusion/auth/storage.py +372 -0
- illusion/bridge/__init__.py +38 -0
- illusion/bridge/manager.py +190 -0
- illusion/bridge/session_runner.py +84 -0
- illusion/bridge/types.py +113 -0
- illusion/bridge/work_secret.py +131 -0
- illusion/cli.py +1228 -0
- illusion/commands/__init__.py +32 -0
- illusion/commands/registry.py +1934 -0
- illusion/config/__init__.py +39 -0
- illusion/config/i18n.py +522 -0
- illusion/config/paths.py +259 -0
- illusion/config/settings.py +564 -0
- illusion/coordinator/__init__.py +41 -0
- illusion/coordinator/agent_definitions.py +1093 -0
- illusion/coordinator/coordinator_mode.py +127 -0
- illusion/engine/__init__.py +95 -0
- illusion/engine/cost_tracker.py +55 -0
- illusion/engine/messages.py +369 -0
- illusion/engine/query.py +632 -0
- illusion/engine/query_engine.py +343 -0
- illusion/engine/stream_events.py +169 -0
- illusion/hooks/__init__.py +67 -0
- illusion/hooks/events.py +43 -0
- illusion/hooks/executor.py +397 -0
- illusion/hooks/hot_reload.py +74 -0
- illusion/hooks/loader.py +133 -0
- illusion/hooks/schemas.py +121 -0
- illusion/hooks/types.py +86 -0
- illusion/mcp/__init__.py +104 -0
- illusion/mcp/client.py +377 -0
- illusion/mcp/config.py +140 -0
- illusion/mcp/types.py +175 -0
- illusion/memory/__init__.py +36 -0
- illusion/memory/manager.py +94 -0
- illusion/memory/memdir.py +58 -0
- illusion/memory/paths.py +57 -0
- illusion/memory/scan.py +120 -0
- illusion/memory/search.py +83 -0
- illusion/memory/types.py +43 -0
- illusion/output_styles/__init__.py +15 -0
- illusion/output_styles/loader.py +64 -0
- illusion/permissions/__init__.py +39 -0
- illusion/permissions/checker.py +174 -0
- illusion/permissions/modes.py +38 -0
- illusion/platforms.py +148 -0
- illusion/plugins/__init__.py +71 -0
- illusion/plugins/bundled/__init__.py +0 -0
- illusion/plugins/installer.py +59 -0
- illusion/plugins/loader.py +301 -0
- illusion/plugins/schemas.py +51 -0
- illusion/plugins/types.py +56 -0
- illusion/prompts/__init__.py +29 -0
- illusion/prompts/claudemd.py +74 -0
- illusion/prompts/context.py +187 -0
- illusion/prompts/environment.py +189 -0
- illusion/prompts/system_prompt.py +155 -0
- illusion/py.typed +0 -0
- illusion/sandbox/__init__.py +29 -0
- illusion/sandbox/adapter.py +174 -0
- illusion/services/__init__.py +59 -0
- illusion/services/compact/__init__.py +1015 -0
- illusion/services/cron.py +338 -0
- illusion/services/cron_scheduler.py +715 -0
- illusion/services/file_history.py +258 -0
- illusion/services/lsp/__init__.py +455 -0
- illusion/services/session_storage.py +237 -0
- illusion/services/token_estimation.py +72 -0
- illusion/skills/__init__.py +60 -0
- illusion/skills/bundled/__init__.py +110 -0
- illusion/skills/bundled/content/batch.md +86 -0
- illusion/skills/bundled/content/coding-guidelines.md +70 -0
- illusion/skills/bundled/content/debug.md +38 -0
- illusion/skills/bundled/content/loop.md +82 -0
- illusion/skills/bundled/content/remember.md +105 -0
- illusion/skills/bundled/content/simplify.md +53 -0
- illusion/skills/bundled/content/skillify.md +113 -0
- illusion/skills/bundled/content/stuck.md +54 -0
- illusion/skills/bundled/content/update-config.md +329 -0
- illusion/skills/bundled/content/verify.md +74 -0
- illusion/skills/loader.py +219 -0
- illusion/skills/registry.py +40 -0
- illusion/skills/types.py +24 -0
- illusion/state/__init__.py +18 -0
- illusion/state/app_state.py +67 -0
- illusion/state/store.py +93 -0
- illusion/swarm/__init__.py +71 -0
- illusion/swarm/agent_executor.py +857 -0
- illusion/swarm/in_process.py +259 -0
- illusion/swarm/subprocess_backend.py +136 -0
- illusion/swarm/team_helpers.py +123 -0
- illusion/swarm/types.py +159 -0
- illusion/swarm/worktree.py +347 -0
- illusion/tasks/__init__.py +33 -0
- illusion/tasks/local_agent_task.py +42 -0
- illusion/tasks/local_shell_task.py +27 -0
- illusion/tasks/manager.py +377 -0
- illusion/tasks/stop_task.py +21 -0
- illusion/tasks/types.py +88 -0
- illusion/tools/__init__.py +126 -0
- illusion/tools/agent_tool.py +388 -0
- illusion/tools/ask_user_question_tool.py +186 -0
- illusion/tools/base.py +149 -0
- illusion/tools/bash_tool.py +413 -0
- illusion/tools/config_tool.py +90 -0
- illusion/tools/cron_tool.py +473 -0
- illusion/tools/enter_plan_mode_tool.py +147 -0
- illusion/tools/enter_worktree_tool.py +188 -0
- illusion/tools/exit_plan_mode_tool.py +69 -0
- illusion/tools/exit_worktree_tool.py +225 -0
- illusion/tools/file_edit_tool.py +283 -0
- illusion/tools/file_read_tool.py +294 -0
- illusion/tools/file_write_tool.py +184 -0
- illusion/tools/glob_tool.py +165 -0
- illusion/tools/grep_tool.py +190 -0
- illusion/tools/list_mcp_resources_tool.py +80 -0
- illusion/tools/lsp_tool.py +333 -0
- illusion/tools/mcp_auth_tool.py +100 -0
- illusion/tools/mcp_tool.py +75 -0
- illusion/tools/notebook_edit_tool.py +242 -0
- illusion/tools/powershell_tool.py +334 -0
- illusion/tools/read_mcp_resource_tool.py +63 -0
- illusion/tools/repl_tool.py +100 -0
- illusion/tools/send_message_tool.py +112 -0
- illusion/tools/shell_common.py +187 -0
- illusion/tools/skill_tool.py +86 -0
- illusion/tools/sleep_tool.py +62 -0
- illusion/tools/structured_output_tool.py +58 -0
- illusion/tools/task_create_tool.py +98 -0
- illusion/tools/task_get_tool.py +94 -0
- illusion/tools/task_list_tool.py +94 -0
- illusion/tools/task_output_tool.py +55 -0
- illusion/tools/task_stop_tool.py +52 -0
- illusion/tools/task_update_tool.py +224 -0
- illusion/tools/team_create_tool.py +236 -0
- illusion/tools/team_delete_tool.py +104 -0
- illusion/tools/todo_write_tool.py +198 -0
- illusion/tools/tool_search_tool.py +156 -0
- illusion/tools/web_fetch_tool.py +264 -0
- illusion/tools/web_search_tool.py +186 -0
- illusion/ui/__init__.py +23 -0
- illusion/ui/app.py +258 -0
- illusion/ui/backend_host.py +1180 -0
- illusion/ui/input.py +86 -0
- illusion/ui/output.py +363 -0
- illusion/ui/permission_dialog.py +47 -0
- illusion/ui/permission_store.py +99 -0
- illusion/ui/protocol.py +384 -0
- illusion/ui/react_launcher.py +280 -0
- illusion/ui/runtime.py +787 -0
- illusion/ui/textual_app.py +603 -0
- illusion/ui/web/__init__.py +10 -0
- illusion/ui/web/server.py +87 -0
- illusion/ui/web/ws_host.py +1197 -0
- illusion/utils/__init__.py +0 -0
- illusion/utils/ripgrep.py +299 -0
- illusion/utils/shell.py +248 -0
- illusion_code-0.1.0.dist-info/METADATA +1159 -0
- illusion_code-0.1.0.dist-info/RECORD +214 -0
- illusion_code-0.1.0.dist-info/WHEEL +4 -0
- illusion_code-0.1.0.dist-info/entry_points.txt +2 -0
- illusion_code-0.1.0.dist-info/licenses/LICENSE +21 -0
illusion/mcp/config.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP 服务器配置加载模块
|
|
3
|
+
=====================
|
|
4
|
+
|
|
5
|
+
本模块提供从设置、插件和项目目录加载 MCP 服务器配置的功能。
|
|
6
|
+
|
|
7
|
+
主要功能:
|
|
8
|
+
- 从全局设置中加载 MCP 服务器配置
|
|
9
|
+
- 从已加载的插件中合并 MCP 服务器配置
|
|
10
|
+
- 从项目级配置目录加载 MCP 服务器配置
|
|
11
|
+
- 插件配置优先级高于全局设置(同名配置)
|
|
12
|
+
|
|
13
|
+
函数说明:
|
|
14
|
+
- load_mcp_server_configs: 加载并合并 MCP 服务器配置
|
|
15
|
+
- load_project_mcp_configs: 从项目目录加载 MCP 配置
|
|
16
|
+
|
|
17
|
+
使用示例:
|
|
18
|
+
>>> from illusion.mcp.config import load_mcp_server_configs
|
|
19
|
+
>>> configs = load_mcp_server_configs(settings, plugins, cwd="/path/to/project")
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import logging
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
from illusion.plugins.types import LoadedPlugin
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def load_project_mcp_configs(cwd: str | Path) -> dict[str, object]:
|
|
34
|
+
"""
|
|
35
|
+
从项目目录加载 MCP 服务器配置
|
|
36
|
+
|
|
37
|
+
扫描 <project>/.illusion/mcp/ 目录下的所有 JSON 文件,
|
|
38
|
+
每个文件可以包含一个或多个 MCP 服务器配置。
|
|
39
|
+
|
|
40
|
+
文件格式支持:
|
|
41
|
+
1. 单个服务器配置(文件名作为服务器名):
|
|
42
|
+
{"type": "stdio", "command": "python", "args": ["server.py"]}
|
|
43
|
+
|
|
44
|
+
2. 多个服务器配置(使用 mcpServers 键):
|
|
45
|
+
{"mcpServers": {"server1": {...}, "server2": {...}}}
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
cwd: 当前工作目录
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
dict[str, object]: 服务器名称到配置的映射字典
|
|
52
|
+
"""
|
|
53
|
+
from pydantic import TypeAdapter
|
|
54
|
+
|
|
55
|
+
from illusion.config.paths import get_project_mcp_dir
|
|
56
|
+
from illusion.mcp.types import McpJsonConfig, McpServerConfig
|
|
57
|
+
|
|
58
|
+
_server_adapter = TypeAdapter(McpServerConfig)
|
|
59
|
+
servers: dict[str, object] = {}
|
|
60
|
+
mcp_dir = get_project_mcp_dir(cwd)
|
|
61
|
+
|
|
62
|
+
if not mcp_dir.exists():
|
|
63
|
+
return servers
|
|
64
|
+
|
|
65
|
+
for json_file in sorted(mcp_dir.glob("*.json")):
|
|
66
|
+
try:
|
|
67
|
+
raw = json.loads(json_file.read_text(encoding="utf-8"))
|
|
68
|
+
except (json.JSONDecodeError, OSError) as exc:
|
|
69
|
+
logger.warning("Failed to read MCP config %s: %s", json_file, exc)
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
# 兼容 mcp_servers(snake_case)键
|
|
73
|
+
if "mcp_servers" in raw and "mcpServers" not in raw:
|
|
74
|
+
raw["mcpServers"] = raw.pop("mcp_servers")
|
|
75
|
+
|
|
76
|
+
# 尝试解析为多服务器格式(mcpServers 键)
|
|
77
|
+
if "mcpServers" in raw:
|
|
78
|
+
try:
|
|
79
|
+
parsed = McpJsonConfig.model_validate(raw)
|
|
80
|
+
for name, config in parsed.mcpServers.items():
|
|
81
|
+
if getattr(config, "enabled", True):
|
|
82
|
+
servers[name] = config
|
|
83
|
+
except Exception as exc:
|
|
84
|
+
logger.warning("Failed to parse MCP config %s: %s", json_file, exc)
|
|
85
|
+
continue
|
|
86
|
+
|
|
87
|
+
# 尝试解析为单服务器格式(文件名作为服务器名)
|
|
88
|
+
try:
|
|
89
|
+
config = _server_adapter.validate_python(raw)
|
|
90
|
+
if getattr(config, "enabled", True):
|
|
91
|
+
server_name = json_file.stem
|
|
92
|
+
servers[server_name] = config
|
|
93
|
+
except Exception as exc:
|
|
94
|
+
logger.warning("Failed to parse MCP config %s: %s", json_file, exc)
|
|
95
|
+
|
|
96
|
+
return servers
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def load_mcp_server_configs(settings, plugins: list[LoadedPlugin], cwd: str | Path | None = None) -> dict[str, object]:
|
|
100
|
+
"""
|
|
101
|
+
加载 MCP 服务器配置
|
|
102
|
+
|
|
103
|
+
从全局设置、项目目录和已加载的插件中合并 MCP 服务器配置。
|
|
104
|
+
优先级(从高到低):插件 > 项目级 > 全局设置
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
settings: 全局设置对象,包含 mcp_servers 属性
|
|
108
|
+
plugins: 已加载的插件列表,每个插件包含 mcp_servers 属性
|
|
109
|
+
cwd: 当前工作目录,用于加载项目级配置
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
dict[str, object]: 服务器名称到配置的映射字典
|
|
113
|
+
键的格式为 "插件名:服务器名"(来自插件)或仅"服务器名"(来自其他来源)
|
|
114
|
+
|
|
115
|
+
使用示例:
|
|
116
|
+
>>> configs = load_mcp_server_configs(settings, plugins, cwd="/path/to/project")
|
|
117
|
+
>>> for name, config in configs.items():
|
|
118
|
+
... print(f"{name}: {config}")
|
|
119
|
+
"""
|
|
120
|
+
# 从全局设置中获取 MCP 服务器配置(跳过已禁用的服务器)
|
|
121
|
+
servers = {name: cfg for name, cfg in settings.mcp_servers.items()
|
|
122
|
+
if getattr(cfg, "enabled", True)}
|
|
123
|
+
|
|
124
|
+
# 从项目目录加载 MCP 配置(覆盖全局设置)
|
|
125
|
+
if cwd is not None:
|
|
126
|
+
project_configs = load_project_mcp_configs(cwd)
|
|
127
|
+
servers.update(project_configs)
|
|
128
|
+
|
|
129
|
+
# 遍历所有已加载的插件
|
|
130
|
+
for plugin in plugins:
|
|
131
|
+
# 跳过未启用的插件
|
|
132
|
+
if not plugin.enabled:
|
|
133
|
+
continue
|
|
134
|
+
# 将插件的 MCP 服务器配置合并到结果中(跳过已禁用的服务器)
|
|
135
|
+
for name, config in plugin.mcp_servers.items():
|
|
136
|
+
if not getattr(config, "enabled", True):
|
|
137
|
+
continue
|
|
138
|
+
# 使用 "插件名:服务器名" 格式作为键,避免与全局设置冲突
|
|
139
|
+
servers.setdefault(f"{plugin.manifest.name}:{name}", config)
|
|
140
|
+
return servers
|
illusion/mcp/types.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP 配置和状态模型
|
|
3
|
+
==================
|
|
4
|
+
|
|
5
|
+
本模块定义 MCP(Model Context Protocol)相关的配置和数据类型。
|
|
6
|
+
|
|
7
|
+
主要功能:
|
|
8
|
+
- 定义 MCP 服务器配置(STDIO、HTTP、WebSocket)
|
|
9
|
+
- 定义 MCP 工具和资源信息
|
|
10
|
+
- 定义 MCP 连接状态
|
|
11
|
+
|
|
12
|
+
类说明:
|
|
13
|
+
- McpStdioServerConfig: STDIO 类型 MCP 服务器配置
|
|
14
|
+
- McpHttpServerConfig: HTTP 类型 MCP 服务器配置
|
|
15
|
+
- McpWebSocketServerConfig: WebSocket 类型 MCP 服务器配置
|
|
16
|
+
- McpServerConfig: MCP 服务器配置联合类型
|
|
17
|
+
- McpJsonConfig: 配置文件格式(用于插件和项目文件)
|
|
18
|
+
- McpToolInfo: MCP 工具元数据
|
|
19
|
+
- McpResourceInfo: MCP 资源元数据
|
|
20
|
+
- McpConnectionStatus: MCP 服务器运行时状态
|
|
21
|
+
|
|
22
|
+
使用示例:
|
|
23
|
+
>>> from illusion.mcp.types import McpStdioServerConfig
|
|
24
|
+
>>> config = McpStdioServerConfig(command="node", args=["server.js"])
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from dataclasses import dataclass, field
|
|
30
|
+
from typing import Literal
|
|
31
|
+
|
|
32
|
+
from pydantic import BaseModel, Field
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class McpStdioServerConfig(BaseModel):
|
|
36
|
+
"""
|
|
37
|
+
STDIO 类型 MCP 服务器配置
|
|
38
|
+
|
|
39
|
+
通过标准输入输出流与 MCP 服务器通信的配置。
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
type: 服务器类型,固定为 "stdio"
|
|
43
|
+
command: 要执行的命令
|
|
44
|
+
args: 命令参数列表
|
|
45
|
+
env: 环境变量字典
|
|
46
|
+
cwd: 工作目录
|
|
47
|
+
log_file: stderr 日志重定向文件路径,设置后 MCP 服务器的 stderr 输出将写入该文件
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
type: Literal["stdio"] = "stdio"
|
|
51
|
+
command: str
|
|
52
|
+
args: list[str] = Field(default_factory=list)
|
|
53
|
+
env: dict[str, str] | None = None
|
|
54
|
+
cwd: str | None = None
|
|
55
|
+
log_file: str | None = None
|
|
56
|
+
enabled: bool = True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class McpHttpServerConfig(BaseModel):
|
|
60
|
+
"""
|
|
61
|
+
HTTP 类型 MCP 服务器配置
|
|
62
|
+
|
|
63
|
+
通过 HTTP 协议与 MCP 服务器通信的配置。
|
|
64
|
+
|
|
65
|
+
Attributes:
|
|
66
|
+
type: 服务器类型,固定为 "http"
|
|
67
|
+
url: 服务器 URL 地址
|
|
68
|
+
headers: HTTP 请求头字典
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
type: Literal["http"] = "http"
|
|
72
|
+
url: str
|
|
73
|
+
headers: dict[str, str] = Field(default_factory=dict)
|
|
74
|
+
enabled: bool = True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class McpWebSocketServerConfig(BaseModel):
|
|
78
|
+
"""
|
|
79
|
+
WebSocket 类型 MCP 服务器配置
|
|
80
|
+
|
|
81
|
+
通过 WebSocket 协议与 MCP 服务器通信的配置。
|
|
82
|
+
|
|
83
|
+
Attributes:
|
|
84
|
+
type: 服务器类型,固定为 "ws"
|
|
85
|
+
url: 服务器 WebSocket URL 地址
|
|
86
|
+
headers: WebSocket 连接请求头字典
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
type: Literal["ws"] = "ws"
|
|
90
|
+
url: str
|
|
91
|
+
headers: dict[str, str] = Field(default_factory=dict)
|
|
92
|
+
enabled: bool = True
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# MCP 服务器配置联合类型,支持 STDIO、HTTP、WebSocket 三种传输方式
|
|
96
|
+
McpServerConfig = McpStdioServerConfig | McpHttpServerConfig | McpWebSocketServerConfig
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class McpJsonConfig(BaseModel):
|
|
100
|
+
"""
|
|
101
|
+
MCP 配置文件格式
|
|
102
|
+
|
|
103
|
+
用于插件和项目文件中的 MCP 服务器配置格式。
|
|
104
|
+
|
|
105
|
+
Attributes:
|
|
106
|
+
mcp_servers: MCP 服务器名称到配置的映射字典
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
mcpServers: dict[str, McpServerConfig] = Field(default_factory=dict)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass(frozen=True)
|
|
113
|
+
class McpToolInfo:
|
|
114
|
+
"""
|
|
115
|
+
MCP 工具信息
|
|
116
|
+
|
|
117
|
+
MCP 服务器暴露的工具元数据,包含工具名称、描述和输入模式。
|
|
118
|
+
|
|
119
|
+
Attributes:
|
|
120
|
+
server_name: 所属服务器名称
|
|
121
|
+
name: 工具名称
|
|
122
|
+
description: 工具描述
|
|
123
|
+
input_schema: 工具输入参数的 JSON Schema 定义
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
server_name: str
|
|
127
|
+
name: str
|
|
128
|
+
description: str
|
|
129
|
+
input_schema: dict[str, object]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass(frozen=True)
|
|
133
|
+
class McpResourceInfo:
|
|
134
|
+
"""
|
|
135
|
+
MCP 资源信息
|
|
136
|
+
|
|
137
|
+
MCP 服务器暴露的资源元数据,包含资源名称、URI 和描述。
|
|
138
|
+
|
|
139
|
+
Attributes:
|
|
140
|
+
server_name: 所属服务器名称
|
|
141
|
+
name: 资源名称
|
|
142
|
+
uri: 资源统一标识符
|
|
143
|
+
description: 资源描述
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
server_name: str
|
|
147
|
+
name: str
|
|
148
|
+
uri: str
|
|
149
|
+
description: str = ""
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@dataclass
|
|
153
|
+
class McpConnectionStatus:
|
|
154
|
+
"""
|
|
155
|
+
MCP 连接状态
|
|
156
|
+
|
|
157
|
+
MCP 服务器的运行时状态信息,包含连接状态、传输类型、认证配置、工具和资源列表。
|
|
158
|
+
|
|
159
|
+
Attributes:
|
|
160
|
+
name: 服务器名称
|
|
161
|
+
state: 连接状态(connected/failed/pending/disabled)
|
|
162
|
+
detail: 状态详情或错误信息
|
|
163
|
+
transport: 传输类型(stdio/http/ws)
|
|
164
|
+
auth_configured: 是否配置了认证
|
|
165
|
+
tools: 该服务器提供的工具列表
|
|
166
|
+
resources: 该服务器提供的资源列表
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
name: str
|
|
170
|
+
state: Literal["connected", "failed", "pending", "disabled"]
|
|
171
|
+
detail: str = ""
|
|
172
|
+
transport: str = "unknown"
|
|
173
|
+
auth_configured: bool = False
|
|
174
|
+
tools: list[McpToolInfo] = field(default_factory=list)
|
|
175
|
+
resources: list[McpResourceInfo] = field(default_factory=list)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
记忆模块
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
本模块提供 IllusionCode 记忆/上下文管理功能。
|
|
6
|
+
|
|
7
|
+
主要组件:
|
|
8
|
+
- add_memory_entry: 添加记忆条目
|
|
9
|
+
- find_relevant_memories: 查找相关记忆
|
|
10
|
+
- get_memory_entrypoint: 获取记忆入口点
|
|
11
|
+
- get_project_memory_dir: 获取项目记忆目录
|
|
12
|
+
- list_memory_files: 列出记忆文件
|
|
13
|
+
- load_memory_prompt: 加载记忆提示词
|
|
14
|
+
- remove_memory_entry: 移除记忆条目
|
|
15
|
+
- scan_memory_files: 扫描记忆文件
|
|
16
|
+
|
|
17
|
+
使用示例:
|
|
18
|
+
>>> from illusion.memory import add_memory_entry, find_relevant_memories
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from illusion.memory.memdir import load_memory_prompt
|
|
22
|
+
from illusion.memory.manager import add_memory_entry, list_memory_files, remove_memory_entry
|
|
23
|
+
from illusion.memory.paths import get_memory_entrypoint, get_project_memory_dir
|
|
24
|
+
from illusion.memory.scan import scan_memory_files
|
|
25
|
+
from illusion.memory.search import find_relevant_memories
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"add_memory_entry",
|
|
29
|
+
"find_relevant_memories",
|
|
30
|
+
"get_memory_entrypoint",
|
|
31
|
+
"get_project_memory_dir",
|
|
32
|
+
"list_memory_files",
|
|
33
|
+
"load_memory_prompt",
|
|
34
|
+
"remove_memory_entry",
|
|
35
|
+
"scan_memory_files",
|
|
36
|
+
]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
记忆管理模块
|
|
3
|
+
==========
|
|
4
|
+
|
|
5
|
+
本模块提供记忆文件的管理操作功能。
|
|
6
|
+
|
|
7
|
+
主要功能:
|
|
8
|
+
- 列出项目记忆文件
|
|
9
|
+
- 添加/移除记忆条目
|
|
10
|
+
|
|
11
|
+
函数说明:
|
|
12
|
+
- list_memory_files: 列出记忆文件
|
|
13
|
+
- add_memory_entry: 添加记忆条目
|
|
14
|
+
- remove_memory_entry: 移除记忆条目
|
|
15
|
+
|
|
16
|
+
使用示例:
|
|
17
|
+
>>> from illusion.memory import list_memory_files, add_memory_entry, remove_memory_entry
|
|
18
|
+
>>> files = list_memory_files(".")
|
|
19
|
+
>>> path = add_memory_entry(".", "Test", "# Test memory content")
|
|
20
|
+
>>> remove_memory_entry(".", "test")
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from re import sub
|
|
27
|
+
|
|
28
|
+
from illusion.memory.paths import get_memory_entrypoint, get_project_memory_dir
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def list_memory_files(cwd: str | Path) -> list[Path]:
|
|
32
|
+
"""列出项目的所有记忆markdown文件
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
cwd: 当前工作目录
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
list[Path]: 排序后的记忆文件路径列表
|
|
39
|
+
"""
|
|
40
|
+
memory_dir = get_project_memory_dir(cwd) # 获取记忆目录
|
|
41
|
+
return sorted(path for path in memory_dir.glob("*.md")) # 返回排序后的文件列表
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def add_memory_entry(cwd: str | Path, title: str, content: str) -> Path:
|
|
45
|
+
"""创建记忆文件并添加到MEMORY.md索引
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
cwd: 当前工作目录
|
|
49
|
+
title: 记忆标题
|
|
50
|
+
content: 记忆内容
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Path: 创建的记忆文件路径
|
|
54
|
+
"""
|
|
55
|
+
memory_dir = get_project_memory_dir(cwd) # 获取记忆目录
|
|
56
|
+
slug = sub(r"[^a-zA-Z0-9]+", "_", title.strip().lower()).strip("_") or "memory" # 转换为slug
|
|
57
|
+
path = memory_dir / f"{slug}.md" # 构建文件路径
|
|
58
|
+
path.write_text(content.strip() + "\n", encoding="utf-8") # 写入内容
|
|
59
|
+
|
|
60
|
+
entrypoint = get_memory_entrypoint(cwd) # 获取入口点
|
|
61
|
+
existing = entrypoint.read_text(encoding="utf-8") if entrypoint.exists() else "# Memory Index\n" # 读取现有内容
|
|
62
|
+
if path.name not in existing: # 如果不存在
|
|
63
|
+
existing = existing.rstrip() + f"\n- [{title}]({path.name})\n" # 添加索引条目
|
|
64
|
+
entrypoint.write_text(existing, encoding="utf-8") # 写入索引
|
|
65
|
+
return path # 返回创建的文件路径
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def remove_memory_entry(cwd: str | Path, name: str) -> bool:
|
|
69
|
+
"""删除记忆文件及其在MEMORY.md中的索引条目
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
cwd: 当前工作目录
|
|
73
|
+
name: 记忆文件名称 (不带.md扩展名)
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
bool: 是否成功删除
|
|
77
|
+
"""
|
|
78
|
+
memory_dir = get_project_memory_dir(cwd) # 获取记忆目录
|
|
79
|
+
matches = [path for path in memory_dir.glob("*.md") if path.stem == name or path.name == name] # 查找匹配文件
|
|
80
|
+
if not matches: # 没有匹配
|
|
81
|
+
return False
|
|
82
|
+
path = matches[0] # 取第一个匹配
|
|
83
|
+
if path.exists(): # 文件存在
|
|
84
|
+
path.unlink() # 删除文件
|
|
85
|
+
|
|
86
|
+
entrypoint = get_memory_entrypoint(cwd) # 获取入口点
|
|
87
|
+
if entrypoint.exists(): # 入口点存在
|
|
88
|
+
lines = [
|
|
89
|
+
line # 保留的行
|
|
90
|
+
for line in entrypoint.read_text(encoding="utf-8").splitlines()
|
|
91
|
+
if path.name not in line # 排除包含删除文件名的行
|
|
92
|
+
]
|
|
93
|
+
entrypoint.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8") # 重写入口点
|
|
94
|
+
return True # 返回成功
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
记忆提示词模块
|
|
3
|
+
=============
|
|
4
|
+
|
|
5
|
+
本模块提供记忆相关的提示词构建功能。
|
|
6
|
+
|
|
7
|
+
主要功能:
|
|
8
|
+
- 加载项目记忆提示词段落
|
|
9
|
+
- 格式化记忆目录信息
|
|
10
|
+
|
|
11
|
+
函数说明:
|
|
12
|
+
- load_memory_prompt: 加载记忆提示词
|
|
13
|
+
|
|
14
|
+
使用示例:
|
|
15
|
+
>>> from illusion.memory import load_memory_prompt
|
|
16
|
+
>>> prompt = load_memory_prompt(".", max_entrypoint_lines=200)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from illusion.memory.paths import get_memory_entrypoint, get_project_memory_dir
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def load_memory_prompt(cwd: str | Path, *, max_entrypoint_lines: int = 200) -> str | None:
|
|
27
|
+
"""构建当前项目的记忆提示词段落
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
cwd: 当前工作目录
|
|
31
|
+
max_entrypoint_lines: 入口点文件最大行数
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
str | None: 格式化后的记忆提示词,如果失败返回None
|
|
35
|
+
"""
|
|
36
|
+
memory_dir = get_project_memory_dir(cwd) # 获取记忆目录
|
|
37
|
+
entrypoint = get_memory_entrypoint(cwd) # 获取入口点文件
|
|
38
|
+
lines = [
|
|
39
|
+
"# Memory", # 标题
|
|
40
|
+
f"- Persistent memory directory: {memory_dir}", # 记忆目录
|
|
41
|
+
"- Use this directory to store durable user or project context that should survive future sessions.", # 说明1
|
|
42
|
+
"- Prefer concise topic files plus an index entry in MEMORY.md.", # 说明2
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
if entrypoint.exists(): # 入口点文件存在
|
|
46
|
+
content_lines = entrypoint.read_text(encoding="utf-8").splitlines()[:max_entrypoint_lines] # 读取内容
|
|
47
|
+
if content_lines: # 有内容
|
|
48
|
+
lines.extend(["", "## MEMORY.md", "```md", *content_lines, "```"]) # 添加到提示词
|
|
49
|
+
else: # 入口点不存在
|
|
50
|
+
lines.extend(
|
|
51
|
+
[
|
|
52
|
+
"", # 空行
|
|
53
|
+
"## MEMORY.md", # 标题
|
|
54
|
+
"(not created yet)", # 提示未创建
|
|
55
|
+
]
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return "\n".join(lines) # 返回合并后的字符串
|
illusion/memory/paths.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
记忆路径模块
|
|
3
|
+
==========
|
|
4
|
+
|
|
5
|
+
本模块提供持久化项目记忆的路径管理功能。
|
|
6
|
+
|
|
7
|
+
主要功能:
|
|
8
|
+
- 生成基于项目路径的唯一记忆目录
|
|
9
|
+
- 管理MEMORY.md入口点文件
|
|
10
|
+
|
|
11
|
+
函数说明:
|
|
12
|
+
- get_project_memory_dir: 获取项目记忆目录
|
|
13
|
+
- get_memory_entrypoint: 获取记忆入口点文件
|
|
14
|
+
|
|
15
|
+
使用示例:
|
|
16
|
+
>>> from illusion.memory import get_project_memory_dir, get_memory_entrypoint
|
|
17
|
+
>>> mem_dir = get_project_memory_dir(".")
|
|
18
|
+
>>> entrypoint = get_memory_entrypoint(".")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from hashlib import sha1
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
from illusion.config.paths import get_data_dir
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_project_memory_dir(cwd: str | Path) -> Path:
|
|
30
|
+
"""获取项目持久化记忆目录
|
|
31
|
+
|
|
32
|
+
目录名格式: {项目名}-{sha1哈希前12位}
|
|
33
|
+
使用项目路径的哈希确保唯一性
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
cwd: 当前工作目录
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Path: 记忆目录的Path对象
|
|
40
|
+
"""
|
|
41
|
+
path = Path(cwd).resolve() # 解析为绝对路径
|
|
42
|
+
digest = sha1(str(path).encode("utf-8")).hexdigest()[:12] # 计算哈希
|
|
43
|
+
memory_dir = get_data_dir() / "memory" / f"{path.name}-{digest}" # 构建目录路径
|
|
44
|
+
memory_dir.mkdir(parents=True, exist_ok=True) # 创建目录
|
|
45
|
+
return memory_dir # 返回目录
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_memory_entrypoint(cwd: str | Path) -> Path:
|
|
49
|
+
"""获取项目记忆入口点文件
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
cwd: 当前工作目录
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Path: MEMORY.md文件的Path对象
|
|
56
|
+
"""
|
|
57
|
+
return get_project_memory_dir(cwd) / "MEMORY.md" # 返回入口点文件路径
|
illusion/memory/scan.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
记忆文件扫描模块
|
|
3
|
+
================
|
|
4
|
+
|
|
5
|
+
本模块提供记忆文件的扫描和解析功能。
|
|
6
|
+
|
|
7
|
+
主要功能:
|
|
8
|
+
- 扫描项目中的记忆Markdown文件
|
|
9
|
+
- 解析YAML frontmatter提取元数据
|
|
10
|
+
- 按修改时间排序返回记忆列表
|
|
11
|
+
|
|
12
|
+
函数说明:
|
|
13
|
+
- scan_memory_files: 扫描记忆文件
|
|
14
|
+
- _parse_memory_file: 解析单个记忆文件
|
|
15
|
+
|
|
16
|
+
使用示例:
|
|
17
|
+
>>> from illusion.memory import scan_memory_files
|
|
18
|
+
>>> headers = scan_memory_files(".", max_files=50)
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
from illusion.memory.paths import get_project_memory_dir
|
|
26
|
+
from illusion.memory.types import MemoryHeader
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def scan_memory_files(cwd: str | Path, *, max_files: int = 50) -> list[MemoryHeader]:
|
|
30
|
+
"""扫描并返回记忆文件头,按最新修改时间排序
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
cwd: 当前工作目录
|
|
34
|
+
max_files: 最大返回文件数量
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
list[MemoryHeader]: 按修改时间倒序排列的记忆头列表
|
|
38
|
+
"""
|
|
39
|
+
memory_dir = get_project_memory_dir(cwd) # 获取记忆目录
|
|
40
|
+
headers: list[MemoryHeader] = [] # 初始化头列表
|
|
41
|
+
for path in memory_dir.glob("*.md"): # 遍历所有md文件
|
|
42
|
+
if path.name == "MEMORY.md": # 跳过索引文件
|
|
43
|
+
continue
|
|
44
|
+
try:
|
|
45
|
+
text = path.read_text(encoding="utf-8") # 读取文件内容
|
|
46
|
+
except OSError: # 读取失败则跳过
|
|
47
|
+
continue
|
|
48
|
+
header = _parse_memory_file(path, text) # 解析文件
|
|
49
|
+
headers.append(header) # 添加到列表
|
|
50
|
+
headers.sort(key=lambda item: item.modified_at, reverse=True) # 按时间倒序排序
|
|
51
|
+
return headers[:max_files] # 返回Top N结果
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _parse_memory_file(path: Path, content: str) -> MemoryHeader:
|
|
55
|
+
"""解析记忆文件,提取YAML frontmatter中的元数据
|
|
56
|
+
|
|
57
|
+
支持从frontmatter提取: name, description, type
|
|
58
|
+
如果没有frontmatter,使用第一行非空非标题行作为description
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
path: 文件路径
|
|
62
|
+
content: 文件内容
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
MemoryHeader: 解析后的记忆头
|
|
66
|
+
"""
|
|
67
|
+
lines = content.splitlines() # 分割行
|
|
68
|
+
title = path.stem # 默认使用文件名作为标题
|
|
69
|
+
description = "" # 描述
|
|
70
|
+
memory_type = "" # 记忆类型
|
|
71
|
+
body_start = 0 # 内容起始行索引
|
|
72
|
+
|
|
73
|
+
# 解析YAML frontmatter (--- ... ---)
|
|
74
|
+
if lines and lines[0].strip() == "---": # 检查是否有frontmatter
|
|
75
|
+
for i, line in enumerate(lines[1:], 1): # 遍历内容行
|
|
76
|
+
if line.strip() == "---": # 找到结束标记
|
|
77
|
+
for fm_line in lines[1:i]: # 解析frontmatter
|
|
78
|
+
key, _, value = fm_line.partition(":") # 分割键值对
|
|
79
|
+
key = key.strip() # 清理键
|
|
80
|
+
value = value.strip().strip("'\"") # 清理值
|
|
81
|
+
if not value: # 跳过空值
|
|
82
|
+
continue
|
|
83
|
+
if key == "name": # 名称字段
|
|
84
|
+
title = value
|
|
85
|
+
elif key == "description": # 描述字段
|
|
86
|
+
description = value
|
|
87
|
+
elif key == "type": # 类型字段
|
|
88
|
+
memory_type = value
|
|
89
|
+
body_start = i + 1 # 内容从结束标记后开始
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
# 后备方案:第一行非空非frontmatter非标题行作为描述
|
|
93
|
+
desc_line_idx: int | None = None # 描述行索引
|
|
94
|
+
if not description: # 如果没有描述
|
|
95
|
+
for idx, line in enumerate(lines[body_start:body_start + 10], body_start): # 遍历前10���
|
|
96
|
+
stripped = line.strip() # 去除空白
|
|
97
|
+
if stripped and stripped != "---" and not stripped.startswith("#"): # 非空非标记非标题
|
|
98
|
+
description = stripped[:200] # 截取前200字符
|
|
99
|
+
desc_line_idx = idx # 记录行索引
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
# 从frontmatter之后的内容构建body preview
|
|
103
|
+
# 排除已用作description的行以保持搜索评分一致性
|
|
104
|
+
body_lines = [
|
|
105
|
+
line.strip() # 去除空白
|
|
106
|
+
for idx, line in enumerate(lines[body_start:], body_start)
|
|
107
|
+
if line.strip() # 非空行
|
|
108
|
+
and not line.strip().startswith("#") # 非标题行
|
|
109
|
+
and idx != desc_line_idx # 排除描述行
|
|
110
|
+
]
|
|
111
|
+
body_preview = " ".join(body_lines)[:300] # 合并并截断
|
|
112
|
+
|
|
113
|
+
return MemoryHeader(
|
|
114
|
+
path=path, # 文件路径
|
|
115
|
+
title=title, # 标题
|
|
116
|
+
description=description, # 描述
|
|
117
|
+
modified_at=path.stat().st_mtime, # 修改时间
|
|
118
|
+
memory_type=memory_type, # 记忆类型
|
|
119
|
+
body_preview=body_preview, # 内容预览
|
|
120
|
+
)
|