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
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"""高级对话引擎。
|
|
2
|
+
|
|
3
|
+
本模块提供高级对话引擎,管理对话历史和工具感知的模型循环。
|
|
4
|
+
|
|
5
|
+
主要功能:
|
|
6
|
+
- 管理对话历史
|
|
7
|
+
- 执行用户消息提交
|
|
8
|
+
- 支持待续工具调用继续
|
|
9
|
+
- 跟踪令牌使用成本
|
|
10
|
+
|
|
11
|
+
主要类:
|
|
12
|
+
- QueryEngine: 对话引擎主类
|
|
13
|
+
|
|
14
|
+
使用示例:
|
|
15
|
+
>>> from illusion.engine import QueryEngine
|
|
16
|
+
>>> engine = QueryEngine(
|
|
17
|
+
... api_client=client,
|
|
18
|
+
... tool_registry=registry,
|
|
19
|
+
... permission_checker=checker,
|
|
20
|
+
... cwd=".",
|
|
21
|
+
... model="claude-3-opus",
|
|
22
|
+
... system_prompt="你是一个助手"
|
|
23
|
+
... )
|
|
24
|
+
>>> async for event in engine.submit_message("你好"):
|
|
25
|
+
... print(event)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from typing import AsyncIterator
|
|
32
|
+
|
|
33
|
+
from illusion.api.client import SupportsStreamingMessages
|
|
34
|
+
from illusion.api.effort import EffortLevel
|
|
35
|
+
from illusion.engine.cost_tracker import CostTracker
|
|
36
|
+
from illusion.engine.messages import ConversationMessage, ToolResultBlock
|
|
37
|
+
from illusion.engine.query import AskUserPrompt, BackgroundAgentTracker, PermissionPrompt, QueryContext, run_query
|
|
38
|
+
from illusion.engine.stream_events import StreamEvent
|
|
39
|
+
from illusion.hooks import HookExecutor
|
|
40
|
+
from illusion.permissions.checker import PermissionChecker
|
|
41
|
+
from illusion.services.compact import AutoCompactState
|
|
42
|
+
from illusion.services.file_history import FileHistoryState, track_edit, make_snapshot
|
|
43
|
+
from illusion.tools.base import ToolRegistry
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class QueryEngine:
|
|
47
|
+
"""拥有对话历史和工具感知模型循环的高级引擎。
|
|
48
|
+
|
|
49
|
+
管理整个对话生命周期,包括消息提交、工具执行、成本跟踪等。
|
|
50
|
+
|
|
51
|
+
Attributes:
|
|
52
|
+
messages: 当前对话历史(只读)
|
|
53
|
+
max_turns: 每个用户输入的最大智能体轮次数
|
|
54
|
+
total_usage: 跨所有轮次的总使用量
|
|
55
|
+
|
|
56
|
+
使用示例:
|
|
57
|
+
>>> engine = QueryEngine(
|
|
58
|
+
... api_client=client,
|
|
59
|
+
... tool_registry=registry,
|
|
60
|
+
... permission_checker=checker,
|
|
61
|
+
... cwd=".",
|
|
62
|
+
... model="claude-3-opus",
|
|
63
|
+
... system_prompt="你是一个助手"
|
|
64
|
+
... )
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
*,
|
|
70
|
+
api_client: SupportsStreamingMessages,
|
|
71
|
+
tool_registry: ToolRegistry,
|
|
72
|
+
permission_checker: PermissionChecker,
|
|
73
|
+
cwd: str | Path,
|
|
74
|
+
model: str,
|
|
75
|
+
system_prompt: str,
|
|
76
|
+
max_tokens: int = 4096,
|
|
77
|
+
max_turns: int | None = 8,
|
|
78
|
+
permission_prompt: PermissionPrompt | None = None,
|
|
79
|
+
ask_user_prompt: AskUserPrompt | None = None,
|
|
80
|
+
hook_executor: HookExecutor | None = None,
|
|
81
|
+
tool_metadata: dict[str, object] | None = None,
|
|
82
|
+
effort: EffortLevel | None = None,
|
|
83
|
+
session_id: str = "",
|
|
84
|
+
) -> None:
|
|
85
|
+
self._api_client = api_client # API客户端
|
|
86
|
+
self._tool_registry = tool_registry # 工具注册表
|
|
87
|
+
self._permission_checker = permission_checker # 权限检查器
|
|
88
|
+
self._cwd = Path(cwd).resolve() # 当前工作目录
|
|
89
|
+
self._model = model # 模型名称
|
|
90
|
+
self._system_prompt = system_prompt # 系统提示词
|
|
91
|
+
self._max_tokens = max_tokens # 最大令牌数
|
|
92
|
+
self._max_turns = max_turns # 最大轮次
|
|
93
|
+
self._permission_prompt = permission_prompt # 权限提示回调
|
|
94
|
+
self._ask_user_prompt = ask_user_prompt # 用户询问回调
|
|
95
|
+
self._hook_executor = hook_executor # 钩子执行器
|
|
96
|
+
self._tool_metadata = tool_metadata or {} # 工具元数据
|
|
97
|
+
self._effort = effort # effort 级别
|
|
98
|
+
self._messages: list[ConversationMessage] = [] # 对话消息历史
|
|
99
|
+
self._cost_tracker = CostTracker() # 成本跟踪器
|
|
100
|
+
self._bg_agent_tracker = BackgroundAgentTracker() # 后台代理追踪器
|
|
101
|
+
self._compact_state = AutoCompactState() # 自动压缩状态(跨会话持久)
|
|
102
|
+
self._file_history: FileHistoryState | None = None # 文件历史状态
|
|
103
|
+
self._session_id: str = session_id or "" # 会话 ID(用于文件历史目录)
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def effort(self) -> EffortLevel | None:
|
|
107
|
+
"""返回当前的 effort 级别。
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
EffortLevel | None: 当前的 effort 级别
|
|
111
|
+
"""
|
|
112
|
+
return self._effort
|
|
113
|
+
|
|
114
|
+
@effort.setter
|
|
115
|
+
def effort(self, value: EffortLevel | None) -> None:
|
|
116
|
+
"""设置 effort 级别。
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
value: 新的 effort 级别
|
|
120
|
+
"""
|
|
121
|
+
self._effort = value
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def messages(self) -> list[ConversationMessage]:
|
|
125
|
+
"""返回当前对话历史。
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
list[ConversationMessage]: 消息列表的副本
|
|
129
|
+
"""
|
|
130
|
+
return list(self._messages)
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def max_turns(self) -> int | None:
|
|
134
|
+
"""返回每个用户输入的最大智能体轮次数(如果有上限)。
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
int | None: 最大轮次数或None(无限制)
|
|
138
|
+
"""
|
|
139
|
+
return self._max_turns
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def total_usage(self):
|
|
143
|
+
"""返回跨所有轮次的总使用量。
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
UsageSnapshot: 累积的使用量快照
|
|
147
|
+
"""
|
|
148
|
+
return self._cost_tracker.total
|
|
149
|
+
|
|
150
|
+
def clear(self) -> None:
|
|
151
|
+
"""清除内存中的对话历史。
|
|
152
|
+
|
|
153
|
+
同时重置成本跟踪器。
|
|
154
|
+
"""
|
|
155
|
+
self._messages.clear()
|
|
156
|
+
self._cost_tracker = CostTracker()
|
|
157
|
+
|
|
158
|
+
def set_system_prompt(self, prompt: str) -> None:
|
|
159
|
+
"""更新未来轮次的活跃系统提示词。
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
prompt: 新的系统提示词
|
|
163
|
+
"""
|
|
164
|
+
self._system_prompt = prompt
|
|
165
|
+
|
|
166
|
+
def set_model(self, model: str) -> None:
|
|
167
|
+
"""更新未来轮次的活跃模型。
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
model: 新的模型名称
|
|
171
|
+
"""
|
|
172
|
+
self._model = model
|
|
173
|
+
|
|
174
|
+
def set_api_client(self, api_client: SupportsStreamingMessages) -> None:
|
|
175
|
+
"""更新未来轮次的活跃API客户端。
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
api_client: 新的API客户端
|
|
179
|
+
"""
|
|
180
|
+
self._api_client = api_client
|
|
181
|
+
|
|
182
|
+
def set_max_turns(self, max_turns: int | None) -> None:
|
|
183
|
+
"""更新每个用户输入的最大智能体轮次数。
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
max_turns: 最大轮次数,None表示无限制
|
|
187
|
+
"""
|
|
188
|
+
self._max_turns = None if max_turns is None else max(1, int(max_turns))
|
|
189
|
+
|
|
190
|
+
def set_permission_checker(self, checker: PermissionChecker) -> None:
|
|
191
|
+
"""更新未来轮次的活跃权限检查器。
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
checker: 新的权限检查器
|
|
195
|
+
"""
|
|
196
|
+
self._permission_checker = checker
|
|
197
|
+
|
|
198
|
+
def load_messages(self, messages: list[ConversationMessage]) -> None:
|
|
199
|
+
"""替换内存中的对话历史。
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
messages: 新的消息列表
|
|
203
|
+
"""
|
|
204
|
+
self._messages = list(messages)
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def file_history(self) -> FileHistoryState | None:
|
|
208
|
+
"""返回文件历史状态。"""
|
|
209
|
+
return self._file_history
|
|
210
|
+
|
|
211
|
+
def _extract_file_paths(self, tool_name: str, tool_input: dict) -> list[str]:
|
|
212
|
+
"""从工具输入中提取文件路径。"""
|
|
213
|
+
path_keys = ("path", "file_path", "notebook_path")
|
|
214
|
+
paths = []
|
|
215
|
+
for key in path_keys:
|
|
216
|
+
if key in tool_input and isinstance(tool_input[key], str):
|
|
217
|
+
paths.append(tool_input[key])
|
|
218
|
+
return paths
|
|
219
|
+
|
|
220
|
+
def has_pending_continuation(self) -> bool:
|
|
221
|
+
"""当对话以等待后续模型轮次的工具结果结束时返回True。
|
|
222
|
+
|
|
223
|
+
用于检查是否有待续的工具调用需要继续执行。
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
bool: 是否有待续的继续
|
|
227
|
+
"""
|
|
228
|
+
if not self._messages:
|
|
229
|
+
return False
|
|
230
|
+
last = self._messages[-1]
|
|
231
|
+
if last.role != "user":
|
|
232
|
+
return False
|
|
233
|
+
if not any(isinstance(block, ToolResultBlock) for block in last.content):
|
|
234
|
+
return False
|
|
235
|
+
for msg in reversed(self._messages[:-1]):
|
|
236
|
+
if msg.role != "assistant":
|
|
237
|
+
continue
|
|
238
|
+
return bool(msg.tool_uses)
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
async def submit_message(self, prompt: str) -> AsyncIterator[StreamEvent]:
|
|
242
|
+
"""追加用户消息并执行查询循环。
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
prompt: 用户输入的提示词
|
|
246
|
+
|
|
247
|
+
Yields:
|
|
248
|
+
StreamEvent: 流式事件
|
|
249
|
+
|
|
250
|
+
使用示例:
|
|
251
|
+
>>> async for event in engine.submit_message("你好"):
|
|
252
|
+
... print(event)
|
|
253
|
+
"""
|
|
254
|
+
# 初始化文件历史状态(如尚未初始化)
|
|
255
|
+
if self._file_history is None:
|
|
256
|
+
self._file_history = FileHistoryState(
|
|
257
|
+
session_id=self._session_id or __import__('uuid').uuid4().hex[:12],
|
|
258
|
+
cwd=str(self._cwd),
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# 将用户文本转换为消息并添加到历史记录
|
|
262
|
+
self._messages.append(ConversationMessage.from_user_text(prompt))
|
|
263
|
+
|
|
264
|
+
# 为这条用户消息创建文件历史快照(用消息列表长度作为 ID)
|
|
265
|
+
make_snapshot(self._file_history, str(len(self._messages)))
|
|
266
|
+
|
|
267
|
+
# 文件历史回调:工具执行前备份文件
|
|
268
|
+
def _on_before_tool_execute(tool_name: str, tool_input: dict) -> None:
|
|
269
|
+
if self._file_history is None:
|
|
270
|
+
return
|
|
271
|
+
# 跳过只读工具(如 grep、glob),它们不会修改文件
|
|
272
|
+
tool = self._tool_registry.get(tool_name)
|
|
273
|
+
if tool is not None:
|
|
274
|
+
try:
|
|
275
|
+
parsed_input = tool.input_model.model_validate(tool_input)
|
|
276
|
+
if tool.is_read_only(parsed_input):
|
|
277
|
+
return
|
|
278
|
+
except Exception:
|
|
279
|
+
pass
|
|
280
|
+
for fpath in self._extract_file_paths(tool_name, tool_input):
|
|
281
|
+
track_edit(self._file_history, fpath)
|
|
282
|
+
|
|
283
|
+
context = QueryContext(
|
|
284
|
+
api_client=self._api_client,
|
|
285
|
+
tool_registry=self._tool_registry,
|
|
286
|
+
permission_checker=self._permission_checker,
|
|
287
|
+
cwd=self._cwd,
|
|
288
|
+
model=self._model,
|
|
289
|
+
system_prompt=self._system_prompt,
|
|
290
|
+
max_tokens=self._max_tokens,
|
|
291
|
+
max_turns=self._max_turns,
|
|
292
|
+
permission_prompt=self._permission_prompt,
|
|
293
|
+
ask_user_prompt=self._ask_user_prompt,
|
|
294
|
+
hook_executor=self._hook_executor,
|
|
295
|
+
tool_metadata=self._tool_metadata,
|
|
296
|
+
effort=self._effort,
|
|
297
|
+
bg_agent_tracker=self._bg_agent_tracker,
|
|
298
|
+
compact_state=self._compact_state,
|
|
299
|
+
on_before_tool_execute=_on_before_tool_execute,
|
|
300
|
+
)
|
|
301
|
+
async for event, usage in run_query(context, self._messages):
|
|
302
|
+
if usage is not None:
|
|
303
|
+
self._cost_tracker.add(usage) # 累加使用量
|
|
304
|
+
yield event
|
|
305
|
+
# 同步工具导致的 CWD 变更(如 enter/exit_worktree)
|
|
306
|
+
if context.cwd != self._cwd:
|
|
307
|
+
self._cwd = context.cwd
|
|
308
|
+
|
|
309
|
+
async def continue_pending(self, *, max_turns: int | None = None) -> AsyncIterator[StreamEvent]:
|
|
310
|
+
"""继续被中断的工具循环,而不追加新的用户消息。
|
|
311
|
+
|
|
312
|
+
用于恢复之前因工具执行而中断的对话。
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
max_turns: 最大轮次数(可选,默认使用引擎设置)
|
|
316
|
+
|
|
317
|
+
Yields:
|
|
318
|
+
StreamEvent: 流式事件
|
|
319
|
+
"""
|
|
320
|
+
context = QueryContext(
|
|
321
|
+
api_client=self._api_client,
|
|
322
|
+
tool_registry=self._tool_registry,
|
|
323
|
+
permission_checker=self._permission_checker,
|
|
324
|
+
cwd=self._cwd,
|
|
325
|
+
model=self._model,
|
|
326
|
+
system_prompt=self._system_prompt,
|
|
327
|
+
max_tokens=self._max_tokens,
|
|
328
|
+
max_turns=max_turns if max_turns is not None else self._max_turns,
|
|
329
|
+
permission_prompt=self._permission_prompt,
|
|
330
|
+
ask_user_prompt=self._ask_user_prompt,
|
|
331
|
+
hook_executor=self._hook_executor,
|
|
332
|
+
tool_metadata=self._tool_metadata,
|
|
333
|
+
effort=self._effort,
|
|
334
|
+
bg_agent_tracker=self._bg_agent_tracker,
|
|
335
|
+
compact_state=self._compact_state,
|
|
336
|
+
)
|
|
337
|
+
async for event, usage in run_query(context, self._messages):
|
|
338
|
+
if usage is not None:
|
|
339
|
+
self._cost_tracker.add(usage) # 累加使用量
|
|
340
|
+
yield event
|
|
341
|
+
# 同步工具导致的 CWD 变更(如 enter/exit_worktree)
|
|
342
|
+
if context.cwd != self._cwd:
|
|
343
|
+
self._cwd = context.cwd
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""查询引擎产生的事件。
|
|
2
|
+
|
|
3
|
+
本模块定义查询引擎在执行过程中产生的各种事件类型。
|
|
4
|
+
|
|
5
|
+
主要事件类:
|
|
6
|
+
- AssistantTextDelta: 助手文本增量
|
|
7
|
+
- AssistantTurnComplete: 助手轮次完成
|
|
8
|
+
- ToolExecutionStarted: 工具执行开始
|
|
9
|
+
- ToolExecutionCompleted: 工具执行完成
|
|
10
|
+
- ToolChainStarted: 工具链开始
|
|
11
|
+
- ToolChainCompleted: 工具链完成
|
|
12
|
+
- ErrorEvent: 错误事件
|
|
13
|
+
- StatusEvent: 状态事件
|
|
14
|
+
|
|
15
|
+
使用示例:
|
|
16
|
+
>>> from illusion.engine.stream_events import StreamEvent, AssistantTextDelta
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from enum import Enum
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
from illusion.api.usage import UsageSnapshot
|
|
26
|
+
from illusion.engine.messages import ConversationMessage
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SessionPhase(Enum):
|
|
30
|
+
"""智能体会话阶段。
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
IDLE: 空闲状态
|
|
34
|
+
THINKING: 思考中
|
|
35
|
+
TOOL_EXECUTING: 工具执行中
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
IDLE = "idle"
|
|
39
|
+
THINKING = "thinking"
|
|
40
|
+
TOOL_EXECUTING = "tool_executing"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class AssistantTextDelta:
|
|
45
|
+
"""增量助手文本。
|
|
46
|
+
|
|
47
|
+
在流式响应过程中逐步产生的文本片段。
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
text: 新增的文本内容
|
|
51
|
+
reasoning: 新增的思考内容(可选)
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
text: str
|
|
55
|
+
reasoning: str | None = None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass(frozen=True)
|
|
59
|
+
class AssistantTurnComplete:
|
|
60
|
+
"""助手轮次完成。
|
|
61
|
+
|
|
62
|
+
当助手完成一个完整的响应轮次时产生,包含最终消息和使用量统计。
|
|
63
|
+
|
|
64
|
+
Attributes:
|
|
65
|
+
message: 助手生成的消息
|
|
66
|
+
usage: 本轮使用的令牌统计
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
message: ConversationMessage
|
|
70
|
+
usage: UsageSnapshot
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(frozen=True)
|
|
74
|
+
class ToolExecutionStarted:
|
|
75
|
+
"""引擎即将执行工具。
|
|
76
|
+
|
|
77
|
+
在工具执行开始时产生,包含工具名称和输入参数。
|
|
78
|
+
|
|
79
|
+
Attributes:
|
|
80
|
+
tool_name: 工具名称
|
|
81
|
+
tool_input: 工具输入参数字典
|
|
82
|
+
tool_use_id: 工具调用ID(可选,用于去重提前通知的工具调用)
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
tool_name: str
|
|
86
|
+
tool_input: dict[str, Any]
|
|
87
|
+
tool_use_id: str = ""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass(frozen=True)
|
|
91
|
+
class ToolExecutionCompleted:
|
|
92
|
+
"""工具执行完成。
|
|
93
|
+
|
|
94
|
+
工具执行完成后产生,包含工具名称、输出结果和是否出错。
|
|
95
|
+
|
|
96
|
+
Attributes:
|
|
97
|
+
tool_name: 工具名称
|
|
98
|
+
output: 工具执行输出
|
|
99
|
+
is_error: 是否为错误结果
|
|
100
|
+
tool_use_id: 工具调用ID(可选,用于匹配并发工具调用的结果)
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
tool_name: str
|
|
104
|
+
output: str
|
|
105
|
+
is_error: bool = False
|
|
106
|
+
tool_use_id: str = ""
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass(frozen=True)
|
|
110
|
+
class ErrorEvent:
|
|
111
|
+
"""应向用户显示的错误。
|
|
112
|
+
|
|
113
|
+
包含错误信息和是否可恢复。
|
|
114
|
+
|
|
115
|
+
Attributes:
|
|
116
|
+
message: 错误消息
|
|
117
|
+
recoverable: 是否可恢复(默认True)
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
message: str
|
|
121
|
+
recoverable: bool = True
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass(frozen=True)
|
|
125
|
+
class StatusEvent:
|
|
126
|
+
"""向用户显示的瞬态系统状态消息。
|
|
127
|
+
|
|
128
|
+
Attributes:
|
|
129
|
+
message: 状态消息内容
|
|
130
|
+
bg_agent: 是否为后台代理相关状态(用于前端 shimmer 区域显示)
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
message: str
|
|
134
|
+
bg_agent: bool = False
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass(frozen=True)
|
|
138
|
+
class ToolChainStarted:
|
|
139
|
+
"""一批工具执行即将开始。
|
|
140
|
+
|
|
141
|
+
Attributes:
|
|
142
|
+
tool_count: 即将执行的工具数量
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
tool_count: int
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@dataclass(frozen=True)
|
|
149
|
+
class ToolChainCompleted:
|
|
150
|
+
"""批处理中的所有工具已完成执行。
|
|
151
|
+
|
|
152
|
+
Attributes:
|
|
153
|
+
results_summary: 工具执行结果摘要列表
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
results_summary: list[dict[str, Any]]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# 事件联合类型:所有可能的流事件类型
|
|
160
|
+
StreamEvent = (
|
|
161
|
+
AssistantTextDelta
|
|
162
|
+
| AssistantTurnComplete
|
|
163
|
+
| ToolExecutionStarted
|
|
164
|
+
| ToolExecutionCompleted
|
|
165
|
+
| ErrorEvent
|
|
166
|
+
| StatusEvent
|
|
167
|
+
| ToolChainStarted
|
|
168
|
+
| ToolChainCompleted
|
|
169
|
+
)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
钩子模块
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
本模块提供 IllusionCode 钩子系统功能。
|
|
6
|
+
|
|
7
|
+
主要组件:
|
|
8
|
+
- HookEvent: 钩子事件
|
|
9
|
+
- HookExecutionContext: 钩子执行上下文
|
|
10
|
+
- HookExecutor: 钩子执行器
|
|
11
|
+
- HookRegistry: 钩子注册表
|
|
12
|
+
- HookResult: 钩子结果
|
|
13
|
+
- AggregatedHookResult: 聚合钩子结果
|
|
14
|
+
- load_hook_registry: 加载钩子注册表
|
|
15
|
+
|
|
16
|
+
使用示例:
|
|
17
|
+
>>> from illusion.hooks import HookRegistry, HookExecutor
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import TYPE_CHECKING
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
25
|
+
from illusion.hooks.events import HookEvent
|
|
26
|
+
from illusion.hooks.executor import HookExecutionContext, HookExecutor
|
|
27
|
+
from illusion.hooks.loader import HookRegistry
|
|
28
|
+
from illusion.hooks.types import AggregatedHookResult, HookResult
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"AggregatedHookResult",
|
|
32
|
+
"HookEvent",
|
|
33
|
+
"HookExecutionContext",
|
|
34
|
+
"HookExecutor",
|
|
35
|
+
"HookRegistry",
|
|
36
|
+
"HookResult",
|
|
37
|
+
"load_hook_registry",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def __getattr__(name: str):
|
|
42
|
+
if name == "HookEvent":
|
|
43
|
+
from illusion.hooks.events import HookEvent
|
|
44
|
+
|
|
45
|
+
return HookEvent
|
|
46
|
+
if name in {"HookExecutionContext", "HookExecutor"}:
|
|
47
|
+
from illusion.hooks.executor import HookExecutionContext, HookExecutor
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
"HookExecutionContext": HookExecutionContext,
|
|
51
|
+
"HookExecutor": HookExecutor,
|
|
52
|
+
}[name]
|
|
53
|
+
if name in {"HookRegistry", "load_hook_registry"}:
|
|
54
|
+
from illusion.hooks.loader import HookRegistry, load_hook_registry
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
"HookRegistry": HookRegistry,
|
|
58
|
+
"load_hook_registry": load_hook_registry,
|
|
59
|
+
}[name]
|
|
60
|
+
if name in {"AggregatedHookResult", "HookResult"}:
|
|
61
|
+
from illusion.hooks.types import AggregatedHookResult, HookResult
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
"AggregatedHookResult": AggregatedHookResult,
|
|
65
|
+
"HookResult": HookResult,
|
|
66
|
+
}[name]
|
|
67
|
+
raise AttributeError(name)
|
illusion/hooks/events.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
钩子事件定义模块
|
|
3
|
+
================
|
|
4
|
+
|
|
5
|
+
本模块定义 IllusionCode 支持的钩子事件类型。
|
|
6
|
+
|
|
7
|
+
支持的事件:
|
|
8
|
+
- SESSION_START: 会话开始时触发
|
|
9
|
+
- SESSION_END: 会话结束时触发
|
|
10
|
+
- PRE_TOOL_USE: 工具使用前触发
|
|
11
|
+
- POST_TOOL_USE: 工具使用后触发
|
|
12
|
+
|
|
13
|
+
使用示例:
|
|
14
|
+
>>> from illusion.hooks.events import HookEvent
|
|
15
|
+
>>> event = HookEvent.PRE_TOOL_USE
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from enum import Enum
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class HookEvent(str, Enum):
|
|
24
|
+
"""
|
|
25
|
+
钩子事件枚举
|
|
26
|
+
|
|
27
|
+
定义可以触发钩子的所有事件类型。
|
|
28
|
+
|
|
29
|
+
枚举值:
|
|
30
|
+
SESSION_START: 会话开始事件
|
|
31
|
+
SESSION_END: 会话结束事件
|
|
32
|
+
PRE_TOOL_USE: 工具使用前事件
|
|
33
|
+
POST_TOOL_USE: 工具使用后事件
|
|
34
|
+
|
|
35
|
+
使用示例:
|
|
36
|
+
>>> event = HookEvent.PRE_TOOL_USE
|
|
37
|
+
>>> print(event.value) # 输出: "pre_tool_use"
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
SESSION_START = "session_start" # 会话开始
|
|
41
|
+
SESSION_END = "session_end" # 会话结束
|
|
42
|
+
PRE_TOOL_USE = "pre_tool_use" # 工具使用前
|
|
43
|
+
POST_TOOL_USE = "post_tool_use" # 工具使用后
|