voidx 1.0.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.
- voidx/__init__.py +3 -0
- voidx/agent/__init__.py +0 -0
- voidx/agent/agents.py +439 -0
- voidx/agent/attachments.py +235 -0
- voidx/agent/graph.py +463 -0
- voidx/agent/graph_components/__init__.py +1 -0
- voidx/agent/graph_components/compaction.py +268 -0
- voidx/agent/graph_components/permissions.py +139 -0
- voidx/agent/graph_components/run_loop.py +532 -0
- voidx/agent/graph_components/runtime.py +14 -0
- voidx/agent/graph_components/streaming.py +351 -0
- voidx/agent/graph_components/subagent.py +278 -0
- voidx/agent/graph_components/tool_execution.py +208 -0
- voidx/agent/runtime_context.py +368 -0
- voidx/agent/slash.py +466 -0
- voidx/agent/slash_components/__init__.py +1 -0
- voidx/agent/slash_components/code_ide.py +68 -0
- voidx/agent/slash_components/lsp.py +105 -0
- voidx/agent/slash_components/mcp.py +332 -0
- voidx/agent/slash_components/model.py +419 -0
- voidx/agent/slash_components/runtime.py +55 -0
- voidx/agent/slash_components/skills.py +94 -0
- voidx/agent/state.py +32 -0
- voidx/agent/task_state.py +278 -0
- voidx/agent/tool_filters.py +27 -0
- voidx/config.py +707 -0
- voidx/llm/__init__.py +0 -0
- voidx/llm/catalog.py +188 -0
- voidx/llm/compaction.py +267 -0
- voidx/llm/context.py +43 -0
- voidx/llm/instruction.py +220 -0
- voidx/llm/provider.py +312 -0
- voidx/llm/usage.py +341 -0
- voidx/lsp/__init__.py +30 -0
- voidx/lsp/client.py +259 -0
- voidx/lsp/config.py +172 -0
- voidx/lsp/detector.py +512 -0
- voidx/lsp/errors.py +19 -0
- voidx/lsp/manager.py +280 -0
- voidx/lsp/schema.py +179 -0
- voidx/lsp/service.py +103 -0
- voidx/main.py +154 -0
- voidx/mcp/__init__.py +33 -0
- voidx/mcp/client.py +458 -0
- voidx/mcp/manager.py +267 -0
- voidx/mcp/schema.py +112 -0
- voidx/mcp/tool.py +122 -0
- voidx/mcp_servers/__init__.py +1 -0
- voidx/mcp_servers/web.py +104 -0
- voidx/memory/__init__.py +0 -0
- voidx/memory/context_frames.py +188 -0
- voidx/memory/model_profiles.py +98 -0
- voidx/memory/runtime_state.py +240 -0
- voidx/memory/session.py +272 -0
- voidx/memory/store.py +245 -0
- voidx/memory/transcript.py +137 -0
- voidx/permission/__init__.py +28 -0
- voidx/permission/engine.py +430 -0
- voidx/permission/evaluate.py +114 -0
- voidx/permission/sandbox.py +280 -0
- voidx/permission/schema.py +24 -0
- voidx/permission/service.py +314 -0
- voidx/permission/wildcard.py +34 -0
- voidx/skills/__init__.py +18 -0
- voidx/skills/bundled/superpowers/receiving-code-review/SKILL.md +30 -0
- voidx/skills/bundled/superpowers/requesting-code-review/SKILL.md +27 -0
- voidx/skills/bundled/superpowers/systematic-debugging/SKILL.md +36 -0
- voidx/skills/bundled/superpowers/test-driven-development/SKILL.md +33 -0
- voidx/skills/bundled/superpowers/verification-before-completion/SKILL.md +31 -0
- voidx/skills/bundled/superpowers/writing-plans/SKILL.md +27 -0
- voidx/skills/policy.py +97 -0
- voidx/skills/registry.py +162 -0
- voidx/skills/schema.py +47 -0
- voidx/skills/service.py +199 -0
- voidx/tools/__init__.py +0 -0
- voidx/tools/agent.py +81 -0
- voidx/tools/base.py +86 -0
- voidx/tools/bash.py +105 -0
- voidx/tools/file_ops.py +193 -0
- voidx/tools/lsp.py +155 -0
- voidx/tools/registry.py +104 -0
- voidx/tools/repomap.py +238 -0
- voidx/tools/search.py +162 -0
- voidx/tools/task_status.py +57 -0
- voidx/tools/task_tracker.py +81 -0
- voidx/tools/todo.py +82 -0
- voidx/tools/web_content.py +357 -0
- voidx/tools/web_mcp.py +107 -0
- voidx/tools/webfetch.py +155 -0
- voidx/tools/websearch.py +276 -0
- voidx/ui/__init__.py +0 -0
- voidx/ui/app.py +1033 -0
- voidx/ui/app_components/__init__.py +1 -0
- voidx/ui/app_components/clipboard_image.py +245 -0
- voidx/ui/app_components/commands.py +18 -0
- voidx/ui/app_components/controls.py +29 -0
- voidx/ui/app_components/file_picker.py +115 -0
- voidx/ui/app_components/formatting.py +187 -0
- voidx/ui/app_components/git_changes.py +51 -0
- voidx/ui/app_components/rendering.py +1169 -0
- voidx/ui/browse.py +160 -0
- voidx/ui/capture.py +169 -0
- voidx/ui/code_ide.py +251 -0
- voidx/ui/commands.py +83 -0
- voidx/ui/console.py +381 -0
- voidx/ui/console_components/__init__.py +1 -0
- voidx/ui/console_components/formatting.py +96 -0
- voidx/ui/console_components/streaming.py +253 -0
- voidx/ui/diff.py +331 -0
- voidx/ui/dock.py +372 -0
- voidx/ui/dock_components/__init__.py +1 -0
- voidx/ui/dock_components/formatting.py +123 -0
- voidx/ui/dock_components/nodes.py +401 -0
- voidx/ui/dock_components/state.py +51 -0
- voidx/ui/event_components/__init__.py +1 -0
- voidx/ui/event_components/schema.py +249 -0
- voidx/ui/events.py +341 -0
- voidx/ui/session_changes.py +163 -0
- voidx/ui/startup.py +161 -0
- voidx/ui/transcript.py +148 -0
- voidx/ui/tree.py +316 -0
- voidx-1.0.0.dist-info/METADATA +59 -0
- voidx-1.0.0.dist-info/RECORD +126 -0
- voidx-1.0.0.dist-info/WHEEL +5 -0
- voidx-1.0.0.dist-info/entry_points.txt +2 -0
- voidx-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Multi-turn task intent state."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from voidx.agent.runtime_context import (
|
|
12
|
+
InteractionMode,
|
|
13
|
+
TaskIntent,
|
|
14
|
+
implementation_allowed_for_intent,
|
|
15
|
+
infer_task_intent,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_APPROVAL_ONLY_HINTS = {
|
|
20
|
+
"ok",
|
|
21
|
+
"okay",
|
|
22
|
+
"yes",
|
|
23
|
+
"yeah",
|
|
24
|
+
"yep",
|
|
25
|
+
"sure",
|
|
26
|
+
"confirm",
|
|
27
|
+
"confirmed",
|
|
28
|
+
"approve",
|
|
29
|
+
"goahead",
|
|
30
|
+
"go",
|
|
31
|
+
"yesgo",
|
|
32
|
+
"\u597d",
|
|
33
|
+
"\u597d\u7684",
|
|
34
|
+
"\u884c",
|
|
35
|
+
"\u53ef\u4ee5",
|
|
36
|
+
"\u53ef\u4ee5\u7684",
|
|
37
|
+
"\u53ef\u4ee5\u4e86",
|
|
38
|
+
"\u5bf9\u53ef\u4ee5",
|
|
39
|
+
"\u5bf9\u7684",
|
|
40
|
+
"\u5bf9",
|
|
41
|
+
"\u55ef",
|
|
42
|
+
"\u786e\u8ba4",
|
|
43
|
+
"\u786e\u8ba4\u4e86",
|
|
44
|
+
"\u662f\u7684",
|
|
45
|
+
"\u540c\u610f",
|
|
46
|
+
"\u6279\u51c6",
|
|
47
|
+
"\u6ca1\u95ee\u9898",
|
|
48
|
+
"\u6ca1\u95ee\u9898\u4e86",
|
|
49
|
+
"\u5f00\u59cb\u5427",
|
|
50
|
+
"\u505a\u5427",
|
|
51
|
+
"\u6309\u8fd9\u4e2a\u505a",
|
|
52
|
+
"\u5c31\u8fd9\u6837",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
_DIRECT_IMPLEMENT_COMMANDS = {
|
|
56
|
+
"change",
|
|
57
|
+
"edit",
|
|
58
|
+
"fix",
|
|
59
|
+
"implement",
|
|
60
|
+
"modify",
|
|
61
|
+
"patch",
|
|
62
|
+
"doit",
|
|
63
|
+
"goaheadandchange",
|
|
64
|
+
"\u6539",
|
|
65
|
+
"\u6539\u5427",
|
|
66
|
+
"\u4fee\u6539",
|
|
67
|
+
"\u4fee\u6539\u5427",
|
|
68
|
+
"\u4fee",
|
|
69
|
+
"\u4fee\u5427",
|
|
70
|
+
"\u4fee\u590d",
|
|
71
|
+
"\u4fee\u590d\u5427",
|
|
72
|
+
"\u5b9e\u73b0",
|
|
73
|
+
"\u5b9e\u73b0\u5427",
|
|
74
|
+
"\u505a",
|
|
75
|
+
"\u505a\u5427",
|
|
76
|
+
"\u5f00\u59cb\u6539",
|
|
77
|
+
"\u5f00\u59cb\u505a",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TaskPhase(str, Enum):
|
|
82
|
+
CLARIFY = "clarify"
|
|
83
|
+
INSPECT = "inspect"
|
|
84
|
+
DESIGN = "design"
|
|
85
|
+
IMPLEMENT = "implement"
|
|
86
|
+
VERIFY = "verify"
|
|
87
|
+
REVIEW = "review"
|
|
88
|
+
DONE = "done"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class TaskRunStatus(str, Enum):
|
|
92
|
+
IDLE = "idle"
|
|
93
|
+
ACTIVE = "active"
|
|
94
|
+
DONE = "done"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TaskRun(BaseModel):
|
|
98
|
+
goal: str = ""
|
|
99
|
+
phase: TaskPhase = TaskPhase.CLARIFY
|
|
100
|
+
status: TaskRunStatus = TaskRunStatus.IDLE
|
|
101
|
+
approved_scope: str = ""
|
|
102
|
+
awaiting_implementation_approval: bool = False
|
|
103
|
+
turn_count: int = 0
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def active(self) -> bool:
|
|
107
|
+
return self.status == TaskRunStatus.ACTIVE and bool(self.goal)
|
|
108
|
+
|
|
109
|
+
def set_goal(self, goal: str) -> None:
|
|
110
|
+
self.goal = _summarize_scope(goal)
|
|
111
|
+
self.phase = TaskPhase.CLARIFY
|
|
112
|
+
self.status = TaskRunStatus.ACTIVE if self.goal else TaskRunStatus.IDLE
|
|
113
|
+
self.approved_scope = ""
|
|
114
|
+
self.awaiting_implementation_approval = False
|
|
115
|
+
self.turn_count = 0
|
|
116
|
+
|
|
117
|
+
def clear(self) -> None:
|
|
118
|
+
self.goal = ""
|
|
119
|
+
self.phase = TaskPhase.CLARIFY
|
|
120
|
+
self.status = TaskRunStatus.IDLE
|
|
121
|
+
self.approved_scope = ""
|
|
122
|
+
self.awaiting_implementation_approval = False
|
|
123
|
+
self.turn_count = 0
|
|
124
|
+
|
|
125
|
+
def update_after_turn(
|
|
126
|
+
self,
|
|
127
|
+
resolution: "IntentResolution",
|
|
128
|
+
user_text: str,
|
|
129
|
+
*,
|
|
130
|
+
scope_text: str | None = None,
|
|
131
|
+
) -> None:
|
|
132
|
+
if not self.goal:
|
|
133
|
+
self.set_goal(scope_text or user_text)
|
|
134
|
+
if not self.goal:
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
self.status = TaskRunStatus.ACTIVE
|
|
138
|
+
self.turn_count += 1
|
|
139
|
+
self.phase = _phase_for_intent(resolution.intent)
|
|
140
|
+
|
|
141
|
+
if resolution.intent == TaskIntent.DESIGN:
|
|
142
|
+
self.awaiting_implementation_approval = True
|
|
143
|
+
self.approved_scope = _summarize_scope(scope_text or self.goal or user_text)
|
|
144
|
+
return
|
|
145
|
+
|
|
146
|
+
if resolution.intent == TaskIntent.IMPLEMENT:
|
|
147
|
+
self.awaiting_implementation_approval = False
|
|
148
|
+
self.approved_scope = ""
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
if resolution.intent != TaskIntent.AMBIGUOUS:
|
|
152
|
+
self.awaiting_implementation_approval = False
|
|
153
|
+
self.approved_scope = ""
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class TaskState(BaseModel):
|
|
157
|
+
current_intent: TaskIntent = TaskIntent.CHAT
|
|
158
|
+
previous_intent: TaskIntent | None = None
|
|
159
|
+
current_goal: str = ""
|
|
160
|
+
awaiting_implementation_approval: bool = False
|
|
161
|
+
approved_scope: str = ""
|
|
162
|
+
last_plan_summary: str = ""
|
|
163
|
+
|
|
164
|
+
def update_after_turn(
|
|
165
|
+
self,
|
|
166
|
+
resolution: "IntentResolution",
|
|
167
|
+
user_text: str,
|
|
168
|
+
*,
|
|
169
|
+
scope_text: str | None = None,
|
|
170
|
+
) -> None:
|
|
171
|
+
self.previous_intent = self.current_intent
|
|
172
|
+
self.current_intent = resolution.intent
|
|
173
|
+
self.current_goal = _summarize_scope(scope_text or user_text)
|
|
174
|
+
|
|
175
|
+
if resolution.intent == TaskIntent.DESIGN:
|
|
176
|
+
scope = _summarize_scope(scope_text or user_text)
|
|
177
|
+
self.awaiting_implementation_approval = True
|
|
178
|
+
self.approved_scope = scope
|
|
179
|
+
self.last_plan_summary = scope
|
|
180
|
+
return
|
|
181
|
+
|
|
182
|
+
if resolution.intent == TaskIntent.IMPLEMENT:
|
|
183
|
+
self.awaiting_implementation_approval = False
|
|
184
|
+
self.approved_scope = ""
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
if resolution.intent != TaskIntent.AMBIGUOUS:
|
|
188
|
+
self.awaiting_implementation_approval = False
|
|
189
|
+
self.approved_scope = ""
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class IntentResolution(BaseModel):
|
|
193
|
+
intent: TaskIntent
|
|
194
|
+
implementation_allowed: bool
|
|
195
|
+
reason: str
|
|
196
|
+
awaiting_implementation_approval: bool = False
|
|
197
|
+
approved_scope: str = ""
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def resolve_turn_intent(
|
|
201
|
+
text: str,
|
|
202
|
+
interaction_mode: str | InteractionMode | None = None,
|
|
203
|
+
task_state: TaskState | None = None,
|
|
204
|
+
) -> IntentResolution:
|
|
205
|
+
mode = InteractionMode.parse(interaction_mode)
|
|
206
|
+
state = task_state or TaskState()
|
|
207
|
+
|
|
208
|
+
if mode == InteractionMode.PLAN:
|
|
209
|
+
return _resolution(TaskIntent.DESIGN, "interaction mode forces design")
|
|
210
|
+
|
|
211
|
+
if _is_approval_only(text):
|
|
212
|
+
if state.awaiting_implementation_approval:
|
|
213
|
+
return _resolution(
|
|
214
|
+
TaskIntent.IMPLEMENT,
|
|
215
|
+
"user confirmed the pending implementation plan",
|
|
216
|
+
awaiting_implementation_approval=True,
|
|
217
|
+
approved_scope=state.approved_scope,
|
|
218
|
+
)
|
|
219
|
+
return _resolution(
|
|
220
|
+
TaskIntent.AMBIGUOUS,
|
|
221
|
+
"approval phrase without a pending implementation plan",
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
if _is_direct_implementation_command(text):
|
|
225
|
+
return _resolution(
|
|
226
|
+
TaskIntent.IMPLEMENT,
|
|
227
|
+
"direct short command asks to modify the current task",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
intent = infer_task_intent(text, mode)
|
|
231
|
+
return _resolution(intent, f"single-turn classifier matched {intent.value}")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _resolution(
|
|
235
|
+
intent: TaskIntent,
|
|
236
|
+
reason: str,
|
|
237
|
+
*,
|
|
238
|
+
awaiting_implementation_approval: bool = False,
|
|
239
|
+
approved_scope: str = "",
|
|
240
|
+
) -> IntentResolution:
|
|
241
|
+
return IntentResolution(
|
|
242
|
+
intent=intent,
|
|
243
|
+
implementation_allowed=implementation_allowed_for_intent(intent),
|
|
244
|
+
reason=reason,
|
|
245
|
+
awaiting_implementation_approval=awaiting_implementation_approval,
|
|
246
|
+
approved_scope=approved_scope,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _is_approval_only(text: str) -> bool:
|
|
251
|
+
return _normalize_approval_text(text) in _APPROVAL_ONLY_HINTS
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _is_direct_implementation_command(text: str) -> bool:
|
|
255
|
+
return _normalize_approval_text(text) in _DIRECT_IMPLEMENT_COMMANDS
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _normalize_approval_text(text: str) -> str:
|
|
259
|
+
return re.sub(r"[\s,.;:!?,。;:!?、]+", "", text.strip().lower())
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _summarize_scope(text: str) -> str:
|
|
263
|
+
first_line = text.strip().splitlines()[0] if text.strip() else ""
|
|
264
|
+
return first_line[:160]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _phase_for_intent(intent: TaskIntent) -> TaskPhase:
|
|
268
|
+
if intent == TaskIntent.INSPECT:
|
|
269
|
+
return TaskPhase.INSPECT
|
|
270
|
+
if intent == TaskIntent.DESIGN:
|
|
271
|
+
return TaskPhase.DESIGN
|
|
272
|
+
if intent == TaskIntent.IMPLEMENT:
|
|
273
|
+
return TaskPhase.IMPLEMENT
|
|
274
|
+
if intent == TaskIntent.REVIEW:
|
|
275
|
+
return TaskPhase.REVIEW
|
|
276
|
+
if intent == TaskIntent.DEBUG:
|
|
277
|
+
return TaskPhase.INSPECT
|
|
278
|
+
return TaskPhase.CLARIFY
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Tool definition filters shared by primary and worker-role loops."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def filter_unavailable_lsp_tools(tool_defs: list[dict], lsp_manager: Any | None) -> list[dict]:
|
|
9
|
+
if _has_available_lsp_server(lsp_manager):
|
|
10
|
+
return tool_defs
|
|
11
|
+
return [
|
|
12
|
+
tool
|
|
13
|
+
for tool in tool_defs
|
|
14
|
+
if not str(tool.get("function", {}).get("name", "")).startswith("lsp_")
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _has_available_lsp_server(lsp_manager: Any | None) -> bool:
|
|
19
|
+
if lsp_manager is None or not hasattr(lsp_manager, "doctor"):
|
|
20
|
+
return False
|
|
21
|
+
try:
|
|
22
|
+
return any(
|
|
23
|
+
getattr(check, "enabled", False) and getattr(check, "available", False)
|
|
24
|
+
for check in lsp_manager.doctor()
|
|
25
|
+
)
|
|
26
|
+
except Exception:
|
|
27
|
+
return False
|