seedcode-cli 7.2.5__py3-none-any.whl → 8.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.
- seedcode/__init__.py +1 -1
- seedcode/app.py +26 -22
- seedcode/codemode_state.py +1 -1
- seedcode/commands/agent.py +8 -8
- seedcode/commands/assist.py +35 -30
- seedcode/commands/chat.py +2 -2
- seedcode/commands/codemode.py +3 -3
- seedcode/commands/desktop.py +8 -8
- seedcode/commands/mode.py +23 -20
- seedcode/commands/palette.py +5 -5
- seedcode/commands/status.py +8 -7
- seedcode/computer/permissions.py +4 -4
- seedcode/core/models.py +38 -3
- seedcode/core/modes.py +126 -0
- seedcode/tools/desktop.py +2 -2
- seedcode/ui/__init__.py +1 -1
- seedcode/ui/codemode_header.py +2 -2
- seedcode/ui/dashboard.py +15 -13
- seedcode/ui/reference.py +1 -1
- seedcode/ui/statusbar.py +4 -2
- seedcode/ui/tasks.py +2 -2
- {seedcode_cli-7.2.5.dist-info → seedcode_cli-8.1.0.dist-info}/METADATA +55 -42
- {seedcode_cli-7.2.5.dist-info → seedcode_cli-8.1.0.dist-info}/RECORD +26 -25
- {seedcode_cli-7.2.5.dist-info → seedcode_cli-8.1.0.dist-info}/licenses/LICENSE +8 -0
- {seedcode_cli-7.2.5.dist-info → seedcode_cli-8.1.0.dist-info}/WHEEL +0 -0
- {seedcode_cli-7.2.5.dist-info → seedcode_cli-8.1.0.dist-info}/entry_points.txt +0 -0
seedcode/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@ Plant ideas. Grow code.
|
|
|
6
6
|
# Single source of truth for the application version. Every consumer reads it:
|
|
7
7
|
# the PyPI build (via [tool.hatch.version]), the CLI --version flag, the
|
|
8
8
|
# Windows installer metadata, the GitHub release tag, and the WinGet manifest.
|
|
9
|
-
__version__ = "
|
|
9
|
+
__version__ = "8.1.0"
|
|
10
10
|
__author__ = "Al Shahriar Sowan"
|
|
11
11
|
__publisher__ = "Eagox Studio"
|
|
12
12
|
# Current author/company links, surfaced by /about and the README credits.
|
seedcode/app.py
CHANGED
|
@@ -150,23 +150,28 @@ def _key_status(config: AppConfig) -> str:
|
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
def _mode_status(config: AppConfig) -> str:
|
|
153
|
-
"""Menu status for the Code Mode item (ON only when really active).
|
|
153
|
+
"""Menu status for the Code Mode item (ON only when really active).
|
|
154
|
+
|
|
155
|
+
Code Mode has its own workspace session, so its status must reflect that
|
|
156
|
+
session alone. Reading ``agent_mode`` here made the item read ON whenever
|
|
157
|
+
Agent Mode was on, even though no Code Mode workspace was active — a live
|
|
158
|
+
status that did not match the live state.
|
|
159
|
+
"""
|
|
154
160
|
try:
|
|
155
161
|
from .codemode_state import codemode_state
|
|
156
162
|
|
|
157
|
-
if codemode_state().enabled
|
|
158
|
-
return "ON"
|
|
163
|
+
return "ON" if codemode_state().enabled else "OFF"
|
|
159
164
|
except Exception:
|
|
160
|
-
|
|
161
|
-
return "ON" if config.agent_mode else "OFF"
|
|
165
|
+
return "OFF"
|
|
162
166
|
|
|
163
167
|
|
|
164
168
|
def _main_menu(config: AppConfig):
|
|
165
169
|
"""The interactive main menu; returns an action id or None (exit).
|
|
166
170
|
|
|
167
|
-
v6.2.5 reference layout: the
|
|
171
|
+
v6.2.5 reference layout: the mode/setup actions carry Ctrl+1..Ctrl+5
|
|
168
172
|
shortcuts that execute the real handlers (no decorative items), followed
|
|
169
|
-
by the chat/setup actions kept from earlier releases.
|
|
173
|
+
by the chat/setup actions kept from earlier releases. There are exactly
|
|
174
|
+
three modes; Assist Mode no longer exists as a menu entry.
|
|
170
175
|
"""
|
|
171
176
|
provider = PROVIDERS.get(config.provider)
|
|
172
177
|
badge = badge_for_status(provider.status if provider is not None else "")
|
|
@@ -174,10 +179,9 @@ def _main_menu(config: AppConfig):
|
|
|
174
179
|
[
|
|
175
180
|
MenuItem("Code Mode", "codemode", status=_mode_status(config), shortcut="1"),
|
|
176
181
|
MenuItem("Agent Mode", "agent", shortcut="2"),
|
|
177
|
-
MenuItem("
|
|
178
|
-
MenuItem("
|
|
179
|
-
MenuItem("
|
|
180
|
-
MenuItem("Exit", "exit", shortcut="6"),
|
|
182
|
+
MenuItem("Project Memory", "memory", shortcut="3"),
|
|
183
|
+
MenuItem("Settings", "settings", shortcut="4"),
|
|
184
|
+
MenuItem("Exit", "exit", shortcut="5"),
|
|
181
185
|
MenuItem("Start Chat", "chat", status=_model_status(config), badge=badge),
|
|
182
186
|
MenuItem("Provider", "provider", status=_provider_status(config)),
|
|
183
187
|
MenuItem("API Key", "apikey", status=_key_status(config)),
|
|
@@ -324,7 +328,7 @@ class _TaskPresenter:
|
|
|
324
328
|
elif kind == "retry":
|
|
325
329
|
self.ui.dim(f" {detail}")
|
|
326
330
|
elif kind == "limit":
|
|
327
|
-
self.ui.warning(f"
|
|
331
|
+
self.ui.warning(f"Agent Mode stopped: {detail}")
|
|
328
332
|
elif kind == "call" and flow is None:
|
|
329
333
|
# With a task view on screen the step list already shows the tool
|
|
330
334
|
# work; without one, narrate it (the plain/legacy experience).
|
|
@@ -497,7 +501,7 @@ def agent_presenter(agent: AgentEngine) -> _TaskPresenter | None:
|
|
|
497
501
|
|
|
498
502
|
|
|
499
503
|
def _task_mode_label(config: AppConfig) -> str:
|
|
500
|
-
"""The mode named in a task header (Code Mode
|
|
504
|
+
"""The mode named in a task header (Chat / Code Mode / Agent Mode)."""
|
|
501
505
|
try:
|
|
502
506
|
from .codemode_state import codemode_state
|
|
503
507
|
|
|
@@ -505,7 +509,9 @@ def _task_mode_label(config: AppConfig) -> str:
|
|
|
505
509
|
return "Code Mode"
|
|
506
510
|
except Exception:
|
|
507
511
|
pass
|
|
508
|
-
|
|
512
|
+
from .core.modes import active_mode, mode_title
|
|
513
|
+
|
|
514
|
+
return mode_title(active_mode(config))
|
|
509
515
|
|
|
510
516
|
|
|
511
517
|
def _save_codemode_summary(agent: AgentEngine, text: str, outcome: str) -> None:
|
|
@@ -681,7 +687,7 @@ def _handle_agent(
|
|
|
681
687
|
text: str,
|
|
682
688
|
presenter: _TaskPresenter | None = None,
|
|
683
689
|
) -> None:
|
|
684
|
-
"""Run one full
|
|
690
|
+
"""Run one full Agent/Code turn (tool loop) and render the final answer.
|
|
685
691
|
|
|
686
692
|
The turn is shown as a compact live task flow whose step states follow real
|
|
687
693
|
engine activity (see :mod:`seedcode.ui.tasks`) — never a fake progress bar.
|
|
@@ -766,7 +772,7 @@ def _handle_agent(
|
|
|
766
772
|
def _make_agent(
|
|
767
773
|
ui: UI, config: AppConfig, presenter: "_TaskPresenter | None" = None
|
|
768
774
|
) -> AgentEngine:
|
|
769
|
-
"""Build an
|
|
775
|
+
"""Build an Agent Mode engine bound to the CWD and configured permissions."""
|
|
770
776
|
# Lazy import (matching _make_desktop_session): the optional, platform-
|
|
771
777
|
# specific computer package stays out of app.py's top-level import graph.
|
|
772
778
|
from .computer import is_available
|
|
@@ -818,7 +824,7 @@ def _make_desktop_session(ui: UI):
|
|
|
818
824
|
|
|
819
825
|
The session is bound to the process-wide
|
|
820
826
|
:class:`~seedcode.computer.SessionPermissionManager` so a permission the
|
|
821
|
-
user granted once at ``/
|
|
827
|
+
user granted once at ``/agent on`` keeps holding even though this gate is
|
|
822
828
|
rebuilt whenever the permission level changes.
|
|
823
829
|
"""
|
|
824
830
|
from .computer import DesktopGrant, DesktopSession, session_permissions
|
|
@@ -866,14 +872,14 @@ def _chat_loop(
|
|
|
866
872
|
) -> None:
|
|
867
873
|
"""Interactive chat until /exit (returns to the main menu).
|
|
868
874
|
|
|
869
|
-
Only an explicit exit leaves here: a finished task (Code Mode,
|
|
870
|
-
Mode
|
|
875
|
+
Only an explicit exit leaves here: a finished task (Code Mode, Agent
|
|
876
|
+
Mode or a plain chat turn) returns to the prompt with
|
|
871
877
|
``Ready for next task.`` and the session keeps running.
|
|
872
878
|
"""
|
|
873
879
|
ctx = CommandContext(ui=ui, config=config, engine=engine)
|
|
874
880
|
ui.dim(INPUT_HINT)
|
|
875
881
|
|
|
876
|
-
# The
|
|
882
|
+
# The Agent engine is built lazily on the first agent-mode turn and
|
|
877
883
|
# rebuilt when the permission or desktop mode changes (its system
|
|
878
884
|
# prompt and permission gates reflect both). The presenter that owns the
|
|
879
885
|
# live step view lives for the whole chat session, so each turn can bind
|
|
@@ -1120,8 +1126,6 @@ def run(ui: UI) -> None:
|
|
|
1120
1126
|
_dispatch_command(ui, config, engine, "/codemode on")
|
|
1121
1127
|
elif choice == "agent":
|
|
1122
1128
|
_dispatch_command(ui, config, engine, "/agent on")
|
|
1123
|
-
elif choice == "assist":
|
|
1124
|
-
_dispatch_command(ui, config, engine, "/assist on")
|
|
1125
1129
|
elif choice == "memory":
|
|
1126
1130
|
_dispatch_command(ui, config, engine, "/codemode status")
|
|
1127
1131
|
elif choice == "settings":
|
seedcode/codemode_state.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Code Mode state (v6.2.0): workspace-aware coding agent session state.
|
|
2
2
|
|
|
3
|
-
Code Mode is
|
|
3
|
+
Code Mode is the workspace-aware coding mode for the current project:
|
|
4
4
|
|
|
5
5
|
* the CWD at ``/codemode on`` becomes the *workspace* root;
|
|
6
6
|
* ``.seedcode/`` project memory is ensured and the index refreshed
|
seedcode/commands/agent.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Agent Mode commands: /agent and /permission (v8.1.0).
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/agent is the primary route into Agent Mode — the single general-purpose
|
|
4
|
+
execution mode that the retired Assist Mode folded into. /assist and
|
|
5
|
+
/desktop remain accepted aliases so an existing habit keeps working.
|
|
4
6
|
/permission keeps its dedicated interactive picker; /index and /tools stay
|
|
5
7
|
as inspection commands.
|
|
6
8
|
"""
|
|
@@ -15,7 +17,7 @@ from . import CommandContext, CommandResult, command, show_session_bar
|
|
|
15
17
|
from .assist import disable_assist, enable_assist
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
@command("agent", "
|
|
20
|
+
@command("agent", "Select Agent Mode (general-purpose execution). Usage: /agent [on|off]")
|
|
19
21
|
def _agent(ctx: CommandContext, arg: str) -> CommandResult:
|
|
20
22
|
raw = arg.strip().lower()
|
|
21
23
|
if raw in ("on", "off"):
|
|
@@ -27,8 +29,6 @@ def _agent(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
27
29
|
ctx.ui.dim("Expected: /agent on|off")
|
|
28
30
|
return CommandResult()
|
|
29
31
|
|
|
30
|
-
# Agent Mode was merged into Assist Mode — route there transparently.
|
|
31
|
-
ctx.ui.dim("(/agent is now Assist Mode)")
|
|
32
32
|
if enable:
|
|
33
33
|
enable_assist(ctx.ui, ctx.config)
|
|
34
34
|
else:
|
|
@@ -39,7 +39,7 @@ def _agent(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
39
39
|
|
|
40
40
|
@command(
|
|
41
41
|
"permission",
|
|
42
|
-
"Show or set the
|
|
42
|
+
"Show or set the tool permission level",
|
|
43
43
|
aliases=("perm", "permissions"),
|
|
44
44
|
)
|
|
45
45
|
def _permission(ctx: CommandContext, arg: str) -> CommandResult:
|
|
@@ -85,7 +85,7 @@ def _index(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
85
85
|
return CommandResult()
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
@command("tools", "List the tools available
|
|
88
|
+
@command("tools", "List the tools available to the agent modes")
|
|
89
89
|
def _tools(ctx: CommandContext, arg: str) -> CommandResult:
|
|
90
90
|
from ..ui.layout import columns_grid
|
|
91
91
|
|
|
@@ -95,6 +95,6 @@ def _tools(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
95
95
|
kind = "changes files/system" if tool.mutates else "read-only"
|
|
96
96
|
rows.append((name, f"{tool.description} ({kind})"))
|
|
97
97
|
ctx.ui.panel(
|
|
98
|
-
columns_grid(rows, ("seed.primary", "seed.text")), title="
|
|
98
|
+
columns_grid(rows, ("seed.primary", "seed.text")), title="Agent Tools"
|
|
99
99
|
)
|
|
100
100
|
return CommandResult()
|
seedcode/commands/assist.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Agent Mode: unified AI + tool/computer execution (v8.1.0).
|
|
2
2
|
|
|
3
|
-
/
|
|
4
|
-
git, browser, keyboard, mouse, windows, vision, OCR,
|
|
5
|
-
automation).
|
|
6
|
-
/
|
|
3
|
+
/agent on — selects Agent Mode: the full capability set (AI, filesystem,
|
|
4
|
+
terminal, git, browser, keyboard, mouse, windows, vision, OCR,
|
|
5
|
+
desktop automation).
|
|
6
|
+
/agent off — back to plain Chat Mode.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Agent Mode is the single general-purpose execution mode. The retired Assist
|
|
9
|
+
Mode is this mode under its old name: ``/assist`` and ``/desktop`` still work
|
|
10
|
+
and route here, but they never create a fourth mode. Code Mode is the
|
|
11
|
+
workspace-aware coding agent (see :mod:`seedcode.commands.codemode`).
|
|
10
12
|
"""
|
|
11
13
|
|
|
12
14
|
from __future__ import annotations
|
|
@@ -18,7 +20,7 @@ from ..config import save_config
|
|
|
18
20
|
from ..tools import TOOL_REGISTRY, PermissionMode
|
|
19
21
|
from . import CommandContext, CommandResult, command, show_session_bar
|
|
20
22
|
|
|
21
|
-
# The
|
|
23
|
+
# The Agent Mode capability set, in display order. Desktop-engine rows are
|
|
22
24
|
# marked so they can be dimmed when the Computer Engine is unavailable.
|
|
23
25
|
_CAPABILITIES: tuple[tuple[str, str, bool], ...] = (
|
|
24
26
|
("AI", "Chat, reasoning, and code generation", False),
|
|
@@ -35,7 +37,7 @@ _CAPABILITIES: tuple[tuple[str, str, bool], ...] = (
|
|
|
35
37
|
)
|
|
36
38
|
|
|
37
39
|
|
|
38
|
-
@command("assist", "
|
|
40
|
+
@command("assist", "Legacy alias for Agent Mode. Usage: /assist [on|off]")
|
|
39
41
|
def _assist(ctx: CommandContext, arg: str) -> CommandResult:
|
|
40
42
|
raw = arg.strip().lower()
|
|
41
43
|
if raw in ("on", "off"):
|
|
@@ -46,7 +48,7 @@ def _assist(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
46
48
|
return CommandResult()
|
|
47
49
|
else:
|
|
48
50
|
ctx.ui.warning("[Command Error] Invalid syntax.")
|
|
49
|
-
ctx.ui.dim("Expected: /assist on|off")
|
|
51
|
+
ctx.ui.dim("Expected: /agent on|off (or /assist on|off)")
|
|
50
52
|
return CommandResult()
|
|
51
53
|
|
|
52
54
|
if enable:
|
|
@@ -58,7 +60,7 @@ def _assist(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
58
60
|
|
|
59
61
|
|
|
60
62
|
def capability_table(desktop_ok: bool) -> Table:
|
|
61
|
-
"""The
|
|
63
|
+
"""The Agent Mode capability list (✓ rows; unavailable rows dim).
|
|
62
64
|
|
|
63
65
|
OCR is probed independently of the rest of the desktop stack: it needs a
|
|
64
66
|
native engine the Python packages do not supply, so marking it available
|
|
@@ -91,12 +93,13 @@ def _ocr_available() -> bool:
|
|
|
91
93
|
|
|
92
94
|
|
|
93
95
|
def enable_assist(ui, config) -> None:
|
|
94
|
-
"""
|
|
95
|
-
config.
|
|
96
|
+
"""Select Agent Mode: the full capability set in one switch."""
|
|
97
|
+
config.mode = "agent"
|
|
96
98
|
|
|
97
|
-
# Desktop capabilities require the Computer Engine. When available,
|
|
98
|
-
# runs at the ``desktop`` level so the AI can drive the computer;
|
|
99
|
-
# it stays at ``workspace`` (AI + filesystem + terminal + git
|
|
99
|
+
# Desktop capabilities require the Computer Engine. When available, Agent
|
|
100
|
+
# Mode runs at the ``desktop`` level so the AI can drive the computer;
|
|
101
|
+
# otherwise it stays at ``workspace`` (AI + filesystem + terminal + git
|
|
102
|
+
# still work).
|
|
100
103
|
desktop_ok, desktop_reason = is_available()
|
|
101
104
|
config.permission_mode = (
|
|
102
105
|
PermissionMode.DESKTOP.value_str if desktop_ok
|
|
@@ -104,9 +107,9 @@ def enable_assist(ui, config) -> None:
|
|
|
104
107
|
)
|
|
105
108
|
save_config(config)
|
|
106
109
|
|
|
107
|
-
ui.success("
|
|
110
|
+
ui.success("Agent Mode ON")
|
|
108
111
|
ui.blank()
|
|
109
|
-
ui.panel(capability_table(desktop_ok), title="
|
|
112
|
+
ui.panel(capability_table(desktop_ok), title="Agent Mode")
|
|
110
113
|
if not desktop_ok:
|
|
111
114
|
ui.dim(f"Desktop capabilities unavailable: {desktop_reason}")
|
|
112
115
|
ui.blank()
|
|
@@ -143,14 +146,14 @@ def request_session_permissions(ui) -> bool:
|
|
|
143
146
|
f" • {CATEGORY_LABELS.get(c, c)}" for c in SESSION_GRANT_CATEGORIES
|
|
144
147
|
)
|
|
145
148
|
description = (
|
|
146
|
-
"Grant these for this session so
|
|
149
|
+
"Grant these for this session so Agent Mode doesn't interrupt every step:\n"
|
|
147
150
|
f"{wanted}\n"
|
|
148
151
|
"Sensitive actions (registry writes, passwords, system power, deletions, "
|
|
149
152
|
"purchases) will still ask each time."
|
|
150
153
|
)
|
|
151
154
|
|
|
152
155
|
try:
|
|
153
|
-
answer = ui.confirm_desktop("
|
|
156
|
+
answer = ui.confirm_desktop("Agent Mode session permissions", description)
|
|
154
157
|
except Exception:
|
|
155
158
|
# No interactive prompt available (headless/non-TTY): leave the
|
|
156
159
|
# per-action flow in place rather than silently granting anything.
|
|
@@ -161,25 +164,27 @@ def request_session_permissions(ui) -> bool:
|
|
|
161
164
|
session.request(SESSION_GRANT_CATEGORIES, allow=True)
|
|
162
165
|
ui.dim("Desktop control granted for this session — you won't be asked again.")
|
|
163
166
|
else:
|
|
164
|
-
ui.dim("Declined:
|
|
167
|
+
ui.dim("Declined: Agent Mode will ask before each desktop action.")
|
|
165
168
|
return allowed
|
|
166
169
|
|
|
167
170
|
|
|
168
171
|
def disable_assist(ui, config) -> None:
|
|
169
|
-
"""
|
|
172
|
+
"""Leave Agent Mode: back to plain Chat."""
|
|
170
173
|
from ..computer.permissions import session_permissions
|
|
171
174
|
|
|
172
|
-
config.
|
|
175
|
+
config.mode = "chat"
|
|
173
176
|
# Drop back to the safe editing level (removes desktop capability).
|
|
174
177
|
config.permission_mode = PermissionMode.WORKSPACE.value_str
|
|
175
178
|
save_config(config)
|
|
176
|
-
# Forget the session-wide desktop grant: turning
|
|
179
|
+
# Forget the session-wide desktop grant: turning Agent Mode back on asks again.
|
|
177
180
|
session_permissions().reset()
|
|
178
|
-
ui.success("
|
|
181
|
+
ui.success("Agent Mode OFF — back to plain chat")
|
|
179
182
|
|
|
180
183
|
|
|
181
184
|
def _show_status(ctx: CommandContext) -> None:
|
|
182
|
-
"""Show current
|
|
185
|
+
"""Show current Agent Mode status."""
|
|
186
|
+
from ..core.modes import active_mode, mode_title
|
|
187
|
+
|
|
183
188
|
on = ctx.config.agent_mode
|
|
184
189
|
desktop_ok, desktop_reason = is_available()
|
|
185
190
|
|
|
@@ -188,8 +193,8 @@ def _show_status(ctx: CommandContext) -> None:
|
|
|
188
193
|
table.add_column()
|
|
189
194
|
|
|
190
195
|
state = "[seed.accent]ON[/seed.accent]" if on else "[seed.dim]OFF[/seed.dim]"
|
|
191
|
-
table.add_row("
|
|
192
|
-
table.add_row("Mode",
|
|
196
|
+
table.add_row("Agent Mode", state)
|
|
197
|
+
table.add_row("Mode", mode_title(active_mode(ctx.config)))
|
|
193
198
|
if not desktop_ok:
|
|
194
199
|
table.add_row("Desktop", f"Unavailable: {desktop_reason}")
|
|
195
200
|
table.add_row("Permission", ctx.config.permission_mode.replace("_", " ").title())
|
|
@@ -198,6 +203,6 @@ def _show_status(ctx: CommandContext) -> None:
|
|
|
198
203
|
desktop_tools = [n for n, t in TOOL_REGISTRY.items() if t.group == "desktop"]
|
|
199
204
|
table.add_row("Available tools", f"{len(core_tools)} core, {len(desktop_tools)} desktop")
|
|
200
205
|
|
|
201
|
-
ctx.ui.panel(table, title="
|
|
206
|
+
ctx.ui.panel(table, title="Agent Mode")
|
|
202
207
|
ctx.ui.blank()
|
|
203
|
-
ctx.ui.dim("Toggle with: /
|
|
208
|
+
ctx.ui.dim("Toggle with: /agent on | /agent off (alias: /assist)")
|
seedcode/commands/chat.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""/chat — explicit Chat Mode (plain conversation, no tools).
|
|
2
2
|
|
|
3
3
|
/chat — show the current mode.
|
|
4
|
-
/chat on — leave
|
|
4
|
+
/chat on — leave Code/Agent Mode and return to plain Chat: the AI answers
|
|
5
5
|
with text only and never touches the filesystem or terminal.
|
|
6
6
|
|
|
7
7
|
Chat Mode is the default runtime mode; this command exists so a user can
|
|
@@ -19,7 +19,7 @@ def _chat(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
19
19
|
raw = arg.strip().lower()
|
|
20
20
|
if raw in ("", "status"):
|
|
21
21
|
ctx.ui.info(f"Mode: {mode_label(ctx.config)}")
|
|
22
|
-
ctx.ui.dim("Switch with: /chat on · /
|
|
22
|
+
ctx.ui.dim("Switch with: /chat on · /agent on · /codemode on (or /mode chat|code|agent)")
|
|
23
23
|
return CommandResult()
|
|
24
24
|
|
|
25
25
|
if raw != "on":
|
seedcode/commands/codemode.py
CHANGED
|
@@ -57,13 +57,13 @@ def _enable_codemode(ctx: CommandContext) -> None:
|
|
|
57
57
|
state = codemode_state()
|
|
58
58
|
workspace = state.workspace # already set? keep it (re-enable same project)
|
|
59
59
|
|
|
60
|
-
# Agent
|
|
60
|
+
# Agent Mode is the engine Code Mode sharpens; turn it on when off.
|
|
61
61
|
if not config.agent_mode:
|
|
62
62
|
from .assist import enable_assist
|
|
63
63
|
|
|
64
64
|
enable_assist(ctx.ui, config)
|
|
65
|
-
#
|
|
66
|
-
# *coding* workflow, so keep the editing level (workspace) unless the user
|
|
65
|
+
# Agent Mode prefers the desktop level when the engine exists; Code Mode is
|
|
66
|
+
# a *coding* workflow, so keep the editing level (workspace) unless the user
|
|
67
67
|
# had already chosen something stronger.
|
|
68
68
|
if PermissionMode.parse(config.permission_mode) == PermissionMode.DESKTOP:
|
|
69
69
|
config.permission_mode = PermissionMode.WORKSPACE.value_str
|
seedcode/commands/desktop.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"""Desktop-related commands: /desktop (legacy →
|
|
1
|
+
"""Desktop-related commands: /desktop (legacy → Agent Mode), /computer,
|
|
2
2
|
/screenshot, /windows.
|
|
3
3
|
|
|
4
|
-
The old Desktop Mode was merged into
|
|
4
|
+
The old Desktop Mode was merged into Agent Mode — /desktop now routes
|
|
5
5
|
there. /computer shows engine status; /screenshot and /windows work
|
|
6
|
-
immediately (no
|
|
6
|
+
immediately (no Agent Mode turn needed) so the user can sanity-check the
|
|
7
7
|
engine by hand.
|
|
8
8
|
"""
|
|
9
9
|
|
|
@@ -16,19 +16,19 @@ from . import CommandContext, CommandResult, command, show_session_bar
|
|
|
16
16
|
from .assist import disable_assist, enable_assist
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
@command("desktop", "Legacy alias for
|
|
19
|
+
@command("desktop", "Legacy alias for Agent Mode. Usage: /desktop [on|off]")
|
|
20
20
|
def _desktop(ctx: CommandContext, arg: str) -> CommandResult:
|
|
21
21
|
raw = arg.strip().lower()
|
|
22
22
|
if raw in ("on", "off"):
|
|
23
23
|
enable = raw == "on"
|
|
24
24
|
elif not raw:
|
|
25
|
-
enable = not ctx.config.agent_mode # bare /desktop toggles
|
|
25
|
+
enable = not ctx.config.agent_mode # bare /desktop toggles Agent Mode
|
|
26
26
|
else:
|
|
27
27
|
ctx.ui.warning("Usage: /desktop [on|off]")
|
|
28
28
|
return CommandResult()
|
|
29
29
|
|
|
30
|
-
# Desktop Mode was merged into
|
|
31
|
-
ctx.ui.dim("(/desktop is now
|
|
30
|
+
# Desktop Mode was merged into Agent Mode — route there transparently.
|
|
31
|
+
ctx.ui.dim("(/desktop is now Agent Mode)")
|
|
32
32
|
if enable:
|
|
33
33
|
enable_assist(ctx.ui, ctx.config)
|
|
34
34
|
else:
|
|
@@ -44,7 +44,7 @@ def _computer(ctx: CommandContext, arg: str) -> CommandResult:
|
|
|
44
44
|
table = Table.grid(padding=(0, 3))
|
|
45
45
|
table.add_column(style="seed.dim", justify="right", no_wrap=True)
|
|
46
46
|
table.add_column(style="seed.text")
|
|
47
|
-
table.add_row("Mode", "
|
|
47
|
+
table.add_row("Mode", "Agent" if ctx.config.agent_mode else "Chat (/agent on)")
|
|
48
48
|
table.add_row("Engine", reason if not ok else "Available")
|
|
49
49
|
missing = missing_packages()
|
|
50
50
|
if missing:
|
seedcode/commands/mode.py
CHANGED
|
@@ -1,52 +1,55 @@
|
|
|
1
|
-
"""/mode —
|
|
1
|
+
"""/mode — the generic switcher for the three canonical modes (v8.1.0).
|
|
2
2
|
|
|
3
3
|
/mode — show the current mode.
|
|
4
4
|
/mode chat — plain conversation (no tools).
|
|
5
|
-
/mode
|
|
6
|
-
/mode
|
|
7
|
-
/mode agent — legacy alias of assist.
|
|
5
|
+
/mode code — the workspace coding agent (Code Mode).
|
|
6
|
+
/mode agent — general-purpose execution (Agent Mode).
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
``assist`` is accepted as an input alias and resolves to Agent Mode — the
|
|
9
|
+
retired Assist Mode is Agent Mode now, so no fourth mode can be selected.
|
|
10
|
+
|
|
11
|
+
The individual commands (/chat, /codemode, /agent) remain the direct routes;
|
|
10
12
|
this command is the single entry point that understands all of them.
|
|
11
13
|
"""
|
|
12
14
|
|
|
13
15
|
from __future__ import annotations
|
|
14
16
|
|
|
17
|
+
from ..core.modes import MODE_DESCRIPTIONS, Mode, active_mode, mode_title, parse_mode
|
|
15
18
|
from . import CommandContext, CommandResult, command, show_session_bar
|
|
16
19
|
from .status import mode_label
|
|
17
20
|
|
|
18
21
|
|
|
19
|
-
@command("mode", "Show or switch the runtime mode. Usage: /mode [chat|
|
|
22
|
+
@command("mode", "Show or switch the runtime mode. Usage: /mode [chat|code|agent]")
|
|
20
23
|
def _mode(ctx: CommandContext, arg: str) -> CommandResult:
|
|
21
24
|
raw = arg.strip().lower()
|
|
22
25
|
|
|
23
26
|
if not raw:
|
|
24
27
|
ctx.ui.info(f"Mode: {mode_label(ctx.config)}")
|
|
25
|
-
ctx.ui.dim("Switch with: /mode chat|
|
|
28
|
+
ctx.ui.dim("Switch with: /mode chat|code|agent")
|
|
26
29
|
return CommandResult()
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
mode = parse_mode(raw, default=Mode.CHAT)
|
|
32
|
+
if raw not in ("chat", "code", "agent", "assist", "codemode"):
|
|
33
|
+
ctx.ui.warning("[Command Error] Invalid syntax.")
|
|
34
|
+
ctx.ui.dim("Expected: /mode chat|code|agent")
|
|
35
|
+
return CommandResult()
|
|
36
|
+
|
|
37
|
+
if raw == "assist":
|
|
38
|
+
ctx.ui.dim("(Assist Mode is Agent Mode now — selecting Agent Mode)")
|
|
39
|
+
|
|
40
|
+
if mode is Mode.CHAT:
|
|
29
41
|
from .chat import _enter_chat
|
|
30
42
|
|
|
31
43
|
_enter_chat(ctx)
|
|
32
|
-
elif
|
|
33
|
-
from .assist import enable_assist
|
|
34
|
-
|
|
35
|
-
enable_assist(ctx.ui, ctx.config)
|
|
36
|
-
elif raw == "code":
|
|
44
|
+
elif mode is Mode.CODE:
|
|
37
45
|
from .codemode import _enable_codemode
|
|
38
46
|
|
|
39
47
|
_enable_codemode(ctx)
|
|
40
|
-
|
|
41
|
-
# Agent Mode merged into Assist Mode; keep the name working.
|
|
48
|
+
else: # Mode.AGENT
|
|
42
49
|
from .assist import enable_assist
|
|
43
50
|
|
|
44
51
|
enable_assist(ctx.ui, ctx.config)
|
|
45
|
-
ctx.ui.dim("(Agent Mode is Assist Mode now — same engine, same tools)")
|
|
46
|
-
else:
|
|
47
|
-
ctx.ui.warning("[Command Error] Invalid syntax.")
|
|
48
|
-
ctx.ui.dim("Expected: /mode chat|assist|code|agent")
|
|
49
|
-
return CommandResult()
|
|
50
52
|
|
|
53
|
+
ctx.ui.dim(f"Mode: {mode_title(active_mode(ctx.config))} — {MODE_DESCRIPTIONS[mode]}")
|
|
51
54
|
show_session_bar(ctx.ui, ctx.config)
|
|
52
55
|
return CommandResult()
|
seedcode/commands/palette.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""/palette and /files — the command palette (Ctrl+K) and project search (Ctrl+P).
|
|
2
2
|
|
|
3
3
|
The palette lists every high-level action (Change Provider, Change Model,
|
|
4
|
-
Settings, History, Doctor, Clear History, About, Theme,
|
|
4
|
+
Settings, History, Doctor, Clear History, About, Theme, Agent Mode, Search
|
|
5
5
|
Projects) as a fuzzy-searchable selector, VS Code style. The chat REPL
|
|
6
6
|
binds Ctrl+K / Ctrl+P to these commands so they open mid-conversation.
|
|
7
7
|
"""
|
|
@@ -16,7 +16,7 @@ from . import CommandContext, CommandResult, command, dispatch
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def _actions(ctx: CommandContext) -> list[PaletteAction]:
|
|
19
|
-
|
|
19
|
+
agent_on = ctx.config.agent_mode
|
|
20
20
|
return [
|
|
21
21
|
PaletteAction("Change Provider", "/provider", detail="switch AI backend"),
|
|
22
22
|
PaletteAction("Change Model", "/model", detail="browse the live catalogue"),
|
|
@@ -28,9 +28,9 @@ def _actions(ctx: CommandContext) -> list[PaletteAction]:
|
|
|
28
28
|
PaletteAction("About", "/about", detail="version and credits"),
|
|
29
29
|
PaletteAction("Theme", "/theme", detail="pick a colour theme (live preview)"),
|
|
30
30
|
PaletteAction(
|
|
31
|
-
"
|
|
32
|
-
f"/
|
|
33
|
-
detail=f"currently {'on' if
|
|
31
|
+
"Agent Mode",
|
|
32
|
+
f"/agent {'off' if agent_on else 'on'}",
|
|
33
|
+
detail=f"currently {'on' if agent_on else 'off'}",
|
|
34
34
|
),
|
|
35
35
|
PaletteAction("Search Projects", "__files__", detail="fuzzy project file search"),
|
|
36
36
|
PaletteAction("Keyboard Shortcuts", "/shortcuts", detail="key reference"),
|
seedcode/commands/status.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""/status — the live runtime state of the current session (v7.1.0).
|
|
2
2
|
|
|
3
3
|
One panel, every value read from real application state: the active provider
|
|
4
|
-
and its backend, the selected model, the current mode (Chat /
|
|
4
|
+
and its backend, the selected model, the current mode (Chat / Code / Agent),
|
|
5
5
|
the Code Mode session (its state, verified progress and whether a stopped one
|
|
6
6
|
can be resumed), the workspace, the provider connection status, and where
|
|
7
7
|
config and project memory live. Nothing here is hardcoded or fabricated — a
|
|
@@ -23,14 +23,15 @@ from . import CommandContext, CommandResult, command
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def mode_label(config) -> str:
|
|
26
|
-
"""The active mode:
|
|
26
|
+
"""The active mode label: Chat Mode / Code Mode / Agent Mode.
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
Delegates to the single mode resolver (:mod:`seedcode.core.modes`) so
|
|
29
|
+
/status, /mode, /chat, the dashboard and the header can never disagree,
|
|
30
|
+
and the retired Assist Mode can never reappear as a fourth name.
|
|
30
31
|
"""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return
|
|
32
|
+
from ..core.modes import mode_label as _label
|
|
33
|
+
|
|
34
|
+
return _label(config)
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
# Backward-compatible private name.
|
seedcode/computer/permissions.py
CHANGED
|
@@ -50,7 +50,7 @@ SENSITIVE_CATEGORIES = frozenset(
|
|
|
50
50
|
}
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
-
# The non-sensitive categories
|
|
53
|
+
# The non-sensitive categories Agent Mode grants up-front in ONE prompt when it
|
|
54
54
|
# starts, so the session never re-asks for routine control during a task. These
|
|
55
55
|
# are exactly the categories a normal automation session touches; sensitive
|
|
56
56
|
# categories are deliberately excluded — they always confirm per action.
|
|
@@ -84,10 +84,10 @@ def _deny_all(category: str, description: str) -> DesktopGrant:
|
|
|
84
84
|
|
|
85
85
|
@dataclass
|
|
86
86
|
class SessionPermissionManager:
|
|
87
|
-
"""Session-wide desktop grants, requested ONCE when
|
|
87
|
+
"""Session-wide desktop grants, requested ONCE when Agent Mode starts.
|
|
88
88
|
|
|
89
89
|
This is the fix for "asks for permission on every action": instead of
|
|
90
|
-
prompting lazily the first time each category is touched,
|
|
90
|
+
prompting lazily the first time each category is touched, Agent Mode calls
|
|
91
91
|
:meth:`request` at start-up to grant the whole routine-control set in a
|
|
92
92
|
single dialog. Every :class:`DesktopSession` created for the session
|
|
93
93
|
(the app rebuilds them whenever the permission level changes) consults the
|
|
@@ -123,7 +123,7 @@ class SessionPermissionManager:
|
|
|
123
123
|
return category in self.denied
|
|
124
124
|
|
|
125
125
|
def reset(self) -> None:
|
|
126
|
-
"""Forget the session decision (
|
|
126
|
+
"""Forget the session decision (Agent Mode turned off)."""
|
|
127
127
|
self.granted.clear()
|
|
128
128
|
self.denied.clear()
|
|
129
129
|
self.requested = False
|