deepy-cli 0.1.5__tar.gz → 0.1.7__tar.gz
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.
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/PKG-INFO +16 -5
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/README.md +15 -4
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/pyproject.toml +1 -1
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/__init__.py +1 -1
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/cli.py +7 -1
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/config/__init__.py +18 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/config/settings.py +107 -19
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/AskUserQuestion.md +3 -1
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/WebFetch.md +2 -1
- deepy_cli-0.1.7/src/deepy/data/tools/shell.md +13 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/__init__.py +2 -1
- deepy_cli-0.1.7/src/deepy/llm/compaction.py +269 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/context.py +14 -47
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/events.py +1 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/runner.py +29 -1
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/prompts/compact.py +40 -2
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/prompts/runtime_context.py +9 -7
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/prompts/system.py +5 -2
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/prompts/tool_docs.py +1 -1
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/sessions/jsonl.py +184 -4
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/sessions/manager.py +13 -15
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/status.py +8 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/tools/agents.py +10 -8
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/tools/builtin.py +230 -46
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/tools/shell_utils.py +84 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/ask_user_question.py +1 -1
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/message_view.py +121 -31
- deepy_cli-0.1.7/src/deepy/ui/model_picker.py +178 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/prompt_input.py +2 -4
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/slash_commands.py +2 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/styles.py +18 -21
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/terminal.py +361 -29
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/welcome.py +1 -2
- deepy_cli-0.1.5/src/deepy/data/tools/bash.md +0 -7
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/__main__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/__init__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/WebSearch.md +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/__init__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/edit.md +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/modify.md +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/read.md +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/data/tools/write.md +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/errors.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/agent.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/model_capabilities.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/provider.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/replay.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/llm/thinking.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/prompts/__init__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/prompts/rules.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/sessions/__init__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/skills.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/tools/__init__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/tools/file_state.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/tools/result.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/__init__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/app.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/exit_summary.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/loading_text.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/markdown.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/prompt_buffer.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/session_list.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/session_picker.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/theme_picker.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/ui/thinking_state.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/update_check.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/usage.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/utils/__init__.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/utils/debug_logger.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/utils/error_logger.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/utils/json.py +0 -0
- {deepy_cli-0.1.5 → deepy_cli-0.1.7}/src/deepy/utils/notify.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: deepy-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Deepy - Vibe coding for DeepSeek models in your terminal
|
|
5
5
|
Keywords: deepseek,coding-agent,terminal,cli,agents
|
|
6
6
|
Author: kirineko
|
|
@@ -62,7 +62,8 @@ context state visible while the agent works.
|
|
|
62
62
|
## Highlights
|
|
63
63
|
|
|
64
64
|
- DeepSeek-first model setup with `deepseek-v4-pro`, thinking enabled, and
|
|
65
|
-
`reasoning_effort=max` by default
|
|
65
|
+
`reasoning_effort=max` by default; `/model` can switch between V4 Pro and V4
|
|
66
|
+
Flash with `none`, `high`, or `max` thinking strength.
|
|
66
67
|
- OpenAI Agents SDK integration through `OpenAIChatCompletionsModel`.
|
|
67
68
|
- Project-aware coding tools for reading files, modifying files, running shell
|
|
68
69
|
commands, and showing readable diffs.
|
|
@@ -141,15 +142,24 @@ Deepy only uses TOML configuration. JSON config files are intentionally rejected
|
|
|
141
142
|
api_key = "sk-..."
|
|
142
143
|
name = "deepseek-v4-pro"
|
|
143
144
|
base_url = "https://api.deepseek.com"
|
|
145
|
+
thinking = true
|
|
146
|
+
reasoning_effort = "max" # high or max when thinking is enabled
|
|
144
147
|
|
|
145
148
|
[context]
|
|
146
149
|
window_tokens = 1048576
|
|
147
150
|
compact_trigger_ratio = 0.8
|
|
151
|
+
reserved_context_tokens = 50000
|
|
152
|
+
compact_preserve_recent_messages = 2
|
|
148
153
|
|
|
149
154
|
[ui]
|
|
150
155
|
theme = "auto" # auto, dark, or light
|
|
151
156
|
```
|
|
152
157
|
|
|
158
|
+
Supported interactive model choices are `deepseek-v4-pro` and
|
|
159
|
+
`deepseek-v4-flash`. In `/model`, thinking strength `none` saves
|
|
160
|
+
`thinking = false`; `high` and `max` save `thinking = true` with the matching
|
|
161
|
+
`reasoning_effort`.
|
|
162
|
+
|
|
153
163
|
WebSearch uses Deepy's hosted SearXNG endpoint by default. You can override it
|
|
154
164
|
with your own SearXNG instance:
|
|
155
165
|
|
|
@@ -192,8 +202,10 @@ Inside the interactive terminal:
|
|
|
192
202
|
|
|
193
203
|
```text
|
|
194
204
|
/skills List available skills
|
|
205
|
+
/model Select model and thinking strength
|
|
195
206
|
/new Start a fresh conversation
|
|
196
207
|
/resume Pick a previous session
|
|
208
|
+
/compact Compact the active session context
|
|
197
209
|
/theme Show or change UI theme
|
|
198
210
|
/reset Delete config and run setup again
|
|
199
211
|
/ Open the command menu
|
|
@@ -226,6 +238,5 @@ assets live outside the package directory and are not included in the wheel.
|
|
|
226
238
|
|
|
227
239
|
## Release Status
|
|
228
240
|
|
|
229
|
-
Deepy
|
|
230
|
-
|
|
231
|
-
primary distribution is the Python CLI.
|
|
241
|
+
Deepy `0.1.7` is released through GitHub and PyPI. Standalone binaries and npm
|
|
242
|
+
wrappers can be added later, but the primary distribution is the Python CLI.
|
|
@@ -34,7 +34,8 @@ context state visible while the agent works.
|
|
|
34
34
|
## Highlights
|
|
35
35
|
|
|
36
36
|
- DeepSeek-first model setup with `deepseek-v4-pro`, thinking enabled, and
|
|
37
|
-
`reasoning_effort=max` by default
|
|
37
|
+
`reasoning_effort=max` by default; `/model` can switch between V4 Pro and V4
|
|
38
|
+
Flash with `none`, `high`, or `max` thinking strength.
|
|
38
39
|
- OpenAI Agents SDK integration through `OpenAIChatCompletionsModel`.
|
|
39
40
|
- Project-aware coding tools for reading files, modifying files, running shell
|
|
40
41
|
commands, and showing readable diffs.
|
|
@@ -113,15 +114,24 @@ Deepy only uses TOML configuration. JSON config files are intentionally rejected
|
|
|
113
114
|
api_key = "sk-..."
|
|
114
115
|
name = "deepseek-v4-pro"
|
|
115
116
|
base_url = "https://api.deepseek.com"
|
|
117
|
+
thinking = true
|
|
118
|
+
reasoning_effort = "max" # high or max when thinking is enabled
|
|
116
119
|
|
|
117
120
|
[context]
|
|
118
121
|
window_tokens = 1048576
|
|
119
122
|
compact_trigger_ratio = 0.8
|
|
123
|
+
reserved_context_tokens = 50000
|
|
124
|
+
compact_preserve_recent_messages = 2
|
|
120
125
|
|
|
121
126
|
[ui]
|
|
122
127
|
theme = "auto" # auto, dark, or light
|
|
123
128
|
```
|
|
124
129
|
|
|
130
|
+
Supported interactive model choices are `deepseek-v4-pro` and
|
|
131
|
+
`deepseek-v4-flash`. In `/model`, thinking strength `none` saves
|
|
132
|
+
`thinking = false`; `high` and `max` save `thinking = true` with the matching
|
|
133
|
+
`reasoning_effort`.
|
|
134
|
+
|
|
125
135
|
WebSearch uses Deepy's hosted SearXNG endpoint by default. You can override it
|
|
126
136
|
with your own SearXNG instance:
|
|
127
137
|
|
|
@@ -164,8 +174,10 @@ Inside the interactive terminal:
|
|
|
164
174
|
|
|
165
175
|
```text
|
|
166
176
|
/skills List available skills
|
|
177
|
+
/model Select model and thinking strength
|
|
167
178
|
/new Start a fresh conversation
|
|
168
179
|
/resume Pick a previous session
|
|
180
|
+
/compact Compact the active session context
|
|
169
181
|
/theme Show or change UI theme
|
|
170
182
|
/reset Delete config and run setup again
|
|
171
183
|
/ Open the command menu
|
|
@@ -198,6 +210,5 @@ assets live outside the package directory and are not included in the wheel.
|
|
|
198
210
|
|
|
199
211
|
## Release Status
|
|
200
212
|
|
|
201
|
-
Deepy
|
|
202
|
-
|
|
203
|
-
primary distribution is the Python CLI.
|
|
213
|
+
Deepy `0.1.7` is released through GitHub and PyPI. Standalone binaries and npm
|
|
214
|
+
wrappers can be added later, but the primary distribution is the Python CLI.
|
|
@@ -226,6 +226,11 @@ def _doctor(args: argparse.Namespace) -> tuple[int, dict[str, object]]:
|
|
|
226
226
|
or settings.context.resolved_compact_threshold > 0,
|
|
227
227
|
str(settings.context.resolved_compact_threshold),
|
|
228
228
|
)
|
|
229
|
+
check(
|
|
230
|
+
"reserved_context",
|
|
231
|
+
settings.context.reserved_context_tokens > 0,
|
|
232
|
+
str(settings.context.reserved_context_tokens),
|
|
233
|
+
)
|
|
229
234
|
|
|
230
235
|
try:
|
|
231
236
|
build_provider_bundle(settings)
|
|
@@ -241,6 +246,7 @@ def _doctor(args: argparse.Namespace) -> tuple[int, dict[str, object]]:
|
|
|
241
246
|
"thinking": {
|
|
242
247
|
"enabled": settings.model.thinking_enabled,
|
|
243
248
|
"reasoning_effort": settings.model.reasoning_effort,
|
|
249
|
+
"reasoning_mode": settings.model.reasoning_mode,
|
|
244
250
|
},
|
|
245
251
|
}
|
|
246
252
|
|
|
@@ -306,7 +312,7 @@ def _cmd_doctor(args: argparse.Namespace) -> int:
|
|
|
306
312
|
status = "ok" if item["ok"] else "fail"
|
|
307
313
|
print(f"{status:4} {item['name']}: {item['detail']}")
|
|
308
314
|
thinking = report["thinking"]
|
|
309
|
-
print(f"info
|
|
315
|
+
print(f"info reasoning: mode={thinking['reasoning_mode']}")
|
|
310
316
|
live = report.get("live")
|
|
311
317
|
if isinstance(live, dict):
|
|
312
318
|
if live.get("ok"):
|
|
@@ -2,18 +2,27 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from .settings import (
|
|
4
4
|
ContextConfig,
|
|
5
|
+
DEEPSEEK_MODEL_CATALOG,
|
|
6
|
+
DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES,
|
|
7
|
+
DEFAULT_RESERVED_CONTEXT_TOKENS,
|
|
5
8
|
DEFAULT_UI_THEME,
|
|
6
9
|
DEFAULT_WEB_SEARCH_SEARXNG_URL,
|
|
10
|
+
DeepSeekModelInfo,
|
|
7
11
|
ModelConfig,
|
|
12
|
+
REASONING_MODES,
|
|
8
13
|
Settings,
|
|
14
|
+
SUPPORTED_DEEPSEEK_MODELS,
|
|
9
15
|
UI_THEME_OPTIONS,
|
|
10
16
|
UI_THEMES,
|
|
11
17
|
UiConfig,
|
|
12
18
|
default_config_path,
|
|
19
|
+
is_supported_deepseek_model,
|
|
13
20
|
is_valid_ui_theme,
|
|
21
|
+
is_valid_reasoning_mode,
|
|
14
22
|
load_settings,
|
|
15
23
|
mask_secret,
|
|
16
24
|
settings_to_toml_dict,
|
|
25
|
+
update_config_model_settings,
|
|
17
26
|
update_config_theme,
|
|
18
27
|
ui_theme_from_selection,
|
|
19
28
|
ui_theme_number,
|
|
@@ -22,18 +31,27 @@ from .settings import (
|
|
|
22
31
|
|
|
23
32
|
__all__ = [
|
|
24
33
|
"ContextConfig",
|
|
34
|
+
"DEEPSEEK_MODEL_CATALOG",
|
|
35
|
+
"DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES",
|
|
36
|
+
"DEFAULT_RESERVED_CONTEXT_TOKENS",
|
|
25
37
|
"DEFAULT_UI_THEME",
|
|
26
38
|
"DEFAULT_WEB_SEARCH_SEARXNG_URL",
|
|
39
|
+
"DeepSeekModelInfo",
|
|
27
40
|
"ModelConfig",
|
|
41
|
+
"REASONING_MODES",
|
|
28
42
|
"Settings",
|
|
43
|
+
"SUPPORTED_DEEPSEEK_MODELS",
|
|
29
44
|
"UI_THEME_OPTIONS",
|
|
30
45
|
"UI_THEMES",
|
|
31
46
|
"UiConfig",
|
|
32
47
|
"default_config_path",
|
|
48
|
+
"is_supported_deepseek_model",
|
|
33
49
|
"is_valid_ui_theme",
|
|
50
|
+
"is_valid_reasoning_mode",
|
|
34
51
|
"load_settings",
|
|
35
52
|
"mask_secret",
|
|
36
53
|
"settings_to_toml_dict",
|
|
54
|
+
"update_config_model_settings",
|
|
37
55
|
"update_config_theme",
|
|
38
56
|
"ui_theme_from_selection",
|
|
39
57
|
"ui_theme_number",
|
|
@@ -12,14 +12,40 @@ DEFAULT_MODEL = "deepseek-v4-pro"
|
|
|
12
12
|
DEFAULT_BASE_URL = "https://api.deepseek.com"
|
|
13
13
|
DEFAULT_CONTEXT_WINDOW_TOKENS = 1_048_576
|
|
14
14
|
DEFAULT_COMPACT_TRIGGER_RATIO = 0.8
|
|
15
|
-
|
|
15
|
+
DEFAULT_RESERVED_CONTEXT_TOKENS = 50_000
|
|
16
|
+
DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES = 2
|
|
16
17
|
DEFAULT_WEB_SEARCH_SEARXNG_URL = "https://s.kirineko.tech/"
|
|
17
18
|
DEFAULT_UI_THEME = "auto"
|
|
18
19
|
REASONING_EFFORTS = {"high", "max"}
|
|
20
|
+
REASONING_MODES = {"none", "high", "max"}
|
|
19
21
|
UI_THEMES = {"auto", "dark", "light"}
|
|
20
22
|
UI_THEME_OPTIONS = (("1", "auto"), ("2", "dark"), ("3", "light"))
|
|
21
23
|
|
|
22
24
|
|
|
25
|
+
@dataclass(frozen=True)
|
|
26
|
+
class DeepSeekModelInfo:
|
|
27
|
+
name: str
|
|
28
|
+
label: str
|
|
29
|
+
description: str
|
|
30
|
+
supports_thinking: bool = True
|
|
31
|
+
default_reasoning_mode: str = "max"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
DEEPSEEK_MODEL_CATALOG = (
|
|
35
|
+
DeepSeekModelInfo(
|
|
36
|
+
name="deepseek-v4-pro",
|
|
37
|
+
label="DeepSeek V4 Pro",
|
|
38
|
+
description="Higher quality for agentic coding and complex reasoning.",
|
|
39
|
+
),
|
|
40
|
+
DeepSeekModelInfo(
|
|
41
|
+
name="deepseek-v4-flash",
|
|
42
|
+
label="DeepSeek V4 Flash",
|
|
43
|
+
description="Lower latency and cost for faster everyday turns.",
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
SUPPORTED_DEEPSEEK_MODELS = frozenset(model.name for model in DEEPSEEK_MODEL_CATALOG)
|
|
47
|
+
|
|
48
|
+
|
|
23
49
|
def default_config_path() -> Path:
|
|
24
50
|
return Path.home() / ".deepy" / "config.toml"
|
|
25
51
|
|
|
@@ -96,14 +122,22 @@ class ModelConfig:
|
|
|
96
122
|
def thinking_enabled(self) -> bool:
|
|
97
123
|
if self.thinking is not None:
|
|
98
124
|
return self.thinking
|
|
99
|
-
return self.name.lower() in
|
|
125
|
+
return self.name.lower() in SUPPORTED_DEEPSEEK_MODELS
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def reasoning_mode(self) -> str:
|
|
129
|
+
if not self.thinking_enabled:
|
|
130
|
+
return "none"
|
|
131
|
+
return self.reasoning_effort if self.reasoning_effort in REASONING_EFFORTS else "max"
|
|
100
132
|
|
|
101
133
|
|
|
102
134
|
@dataclass(frozen=True)
|
|
103
135
|
class ContextConfig:
|
|
104
136
|
window_tokens: int = DEFAULT_CONTEXT_WINDOW_TOKENS
|
|
105
137
|
compact_trigger_ratio: float = DEFAULT_COMPACT_TRIGGER_RATIO
|
|
106
|
-
|
|
138
|
+
reserved_context_tokens: int = DEFAULT_RESERVED_CONTEXT_TOKENS
|
|
139
|
+
compact_preserve_recent_messages: int = DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES
|
|
140
|
+
compact_preserve_recent_tokens: int | None = None
|
|
107
141
|
|
|
108
142
|
@classmethod
|
|
109
143
|
def from_mapping(cls, raw: Mapping[str, Any]) -> Self:
|
|
@@ -111,18 +145,30 @@ class ContextConfig:
|
|
|
111
145
|
ratio = _as_float(raw.get("compact_trigger_ratio"), DEFAULT_COMPACT_TRIGGER_RATIO)
|
|
112
146
|
if ratio <= 0 or ratio > 1:
|
|
113
147
|
ratio = DEFAULT_COMPACT_TRIGGER_RATIO
|
|
114
|
-
|
|
115
|
-
|
|
148
|
+
reserved_context_tokens = _as_int(
|
|
149
|
+
raw.get("reserved_context_tokens"),
|
|
150
|
+
DEFAULT_RESERVED_CONTEXT_TOKENS,
|
|
151
|
+
)
|
|
152
|
+
preserve_recent_messages = _as_int(
|
|
153
|
+
raw.get("compact_preserve_recent_messages"),
|
|
154
|
+
DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES,
|
|
155
|
+
)
|
|
156
|
+
preserve_recent_tokens_raw = raw.get("compact_preserve_recent_tokens")
|
|
157
|
+
preserve_recent_tokens = (
|
|
158
|
+
_as_int(preserve_recent_tokens_raw, 0)
|
|
159
|
+
if preserve_recent_tokens_raw is not None
|
|
160
|
+
else None
|
|
161
|
+
)
|
|
116
162
|
return cls(
|
|
117
163
|
window_tokens=window_tokens,
|
|
118
164
|
compact_trigger_ratio=ratio,
|
|
119
|
-
|
|
165
|
+
reserved_context_tokens=reserved_context_tokens,
|
|
166
|
+
compact_preserve_recent_messages=preserve_recent_messages,
|
|
167
|
+
compact_preserve_recent_tokens=preserve_recent_tokens or None,
|
|
120
168
|
)
|
|
121
169
|
|
|
122
170
|
@property
|
|
123
171
|
def resolved_compact_threshold(self) -> int:
|
|
124
|
-
if self.compact_prompt_token_threshold:
|
|
125
|
-
return self.compact_prompt_token_threshold
|
|
126
172
|
return int(self.window_tokens * self.compact_trigger_ratio + 0.999999)
|
|
127
173
|
|
|
128
174
|
|
|
@@ -234,9 +280,6 @@ def settings_to_toml_dict(settings: Settings, *, reveal_secret: bool = False) ->
|
|
|
234
280
|
if api_key:
|
|
235
281
|
data["model"]["api_key"] = api_key if reveal_secret else mask_secret(api_key)
|
|
236
282
|
data["model"]["thinking"] = settings.model.thinking_enabled
|
|
237
|
-
data["context"]["compact_prompt_token_threshold"] = (
|
|
238
|
-
settings.context.resolved_compact_threshold
|
|
239
|
-
)
|
|
240
283
|
return _drop_empty(data)
|
|
241
284
|
|
|
242
285
|
|
|
@@ -244,6 +287,14 @@ def is_valid_ui_theme(value: str) -> bool:
|
|
|
244
287
|
return value in UI_THEMES
|
|
245
288
|
|
|
246
289
|
|
|
290
|
+
def is_supported_deepseek_model(value: str) -> bool:
|
|
291
|
+
return value in SUPPORTED_DEEPSEEK_MODELS
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def is_valid_reasoning_mode(value: str) -> bool:
|
|
295
|
+
return value in REASONING_MODES
|
|
296
|
+
|
|
297
|
+
|
|
247
298
|
def ui_theme_number(theme: str) -> str:
|
|
248
299
|
for number, value in UI_THEME_OPTIONS:
|
|
249
300
|
if value == theme:
|
|
@@ -288,7 +339,8 @@ def write_config(
|
|
|
288
339
|
"context": {
|
|
289
340
|
"window_tokens": DEFAULT_CONTEXT_WINDOW_TOKENS,
|
|
290
341
|
"compact_trigger_ratio": DEFAULT_COMPACT_TRIGGER_RATIO,
|
|
291
|
-
"
|
|
342
|
+
"reserved_context_tokens": DEFAULT_RESERVED_CONTEXT_TOKENS,
|
|
343
|
+
"compact_preserve_recent_messages": DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES,
|
|
292
344
|
},
|
|
293
345
|
"logging": {
|
|
294
346
|
"debug": False,
|
|
@@ -311,23 +363,59 @@ def write_config(
|
|
|
311
363
|
os.chmod(path, 0o600)
|
|
312
364
|
|
|
313
365
|
|
|
366
|
+
def update_config_model_settings(
|
|
367
|
+
config_path: Path,
|
|
368
|
+
*,
|
|
369
|
+
model: str | None = None,
|
|
370
|
+
reasoning_mode: str | None = None,
|
|
371
|
+
) -> None:
|
|
372
|
+
if model is not None and not is_supported_deepseek_model(model):
|
|
373
|
+
raise ValueError(
|
|
374
|
+
"Model must be one of: " + ", ".join(model_info.name for model_info in DEEPSEEK_MODEL_CATALOG)
|
|
375
|
+
)
|
|
376
|
+
if reasoning_mode is not None and not is_valid_reasoning_mode(reasoning_mode):
|
|
377
|
+
raise ValueError("Reasoning mode must be one of: none, high, max.")
|
|
378
|
+
path = config_path.expanduser()
|
|
379
|
+
if path.suffix == ".json":
|
|
380
|
+
raise ValueError("Deepy only supports TOML config files; JSON config is not supported.")
|
|
381
|
+
raw = _read_toml_mapping(path)
|
|
382
|
+
model_section = raw.get("model")
|
|
383
|
+
model_map = dict(model_section) if isinstance(model_section, Mapping) else {}
|
|
384
|
+
if model is not None:
|
|
385
|
+
model_map["name"] = model
|
|
386
|
+
if reasoning_mode is not None:
|
|
387
|
+
if reasoning_mode == "none":
|
|
388
|
+
model_map["thinking"] = False
|
|
389
|
+
else:
|
|
390
|
+
model_map["thinking"] = True
|
|
391
|
+
model_map["reasoning_effort"] = reasoning_mode
|
|
392
|
+
raw["model"] = model_map
|
|
393
|
+
_write_private_toml(path, raw)
|
|
394
|
+
|
|
395
|
+
|
|
314
396
|
def update_config_theme(config_path: Path, theme: str) -> None:
|
|
315
397
|
if not is_valid_ui_theme(theme):
|
|
316
398
|
raise ValueError("UI theme must be one of: auto, dark, light.")
|
|
317
399
|
path = config_path.expanduser()
|
|
318
400
|
if path.suffix == ".json":
|
|
319
401
|
raise ValueError("Deepy only supports TOML config files; JSON config is not supported.")
|
|
320
|
-
raw
|
|
321
|
-
if path.exists():
|
|
322
|
-
with path.open("rb") as fh:
|
|
323
|
-
loaded = tomllib.load(fh)
|
|
324
|
-
raw = dict(loaded)
|
|
325
|
-
else:
|
|
326
|
-
raw = {}
|
|
402
|
+
raw = _read_toml_mapping(path)
|
|
327
403
|
ui = raw.get("ui")
|
|
328
404
|
ui_map = dict(ui) if isinstance(ui, Mapping) else {}
|
|
329
405
|
ui_map["theme"] = theme
|
|
330
406
|
raw["ui"] = ui_map
|
|
407
|
+
_write_private_toml(path, raw)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def _read_toml_mapping(path: Path) -> dict[str, Any]:
|
|
411
|
+
if not path.exists():
|
|
412
|
+
return {}
|
|
413
|
+
with path.open("rb") as fh:
|
|
414
|
+
loaded = tomllib.load(fh)
|
|
415
|
+
return dict(loaded)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def _write_private_toml(path: Path, raw: Mapping[str, Any]) -> None:
|
|
331
419
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
332
420
|
path.write_text(tomli_w.dumps(raw), encoding="utf-8")
|
|
333
421
|
os.chmod(path, 0o600)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
## AskUserQuestion
|
|
2
2
|
|
|
3
|
-
Ask the user
|
|
3
|
+
Ask the user when clarification would materially improve the result: ambiguous intent,
|
|
4
|
+
unclear scope, user preferences, high-impact trade-offs, or required approval. Do not
|
|
5
|
+
ask for low-impact details when a reasonable assumption can keep progress moving.
|
|
4
6
|
|
|
5
7
|
Args: `questions` (non-empty array). Each question needs `question` and non-empty `options`;
|
|
6
8
|
each option needs `label` and may include `description`. Use `multiSelect=true` only when
|
|
@@ -5,5 +5,6 @@ Fetch a specific web page when the user provides a complete URL.
|
|
|
5
5
|
Args: `url`.
|
|
6
6
|
|
|
7
7
|
Accepts only complete `http://` or `https://` URLs. Returns the final URL, title,
|
|
8
|
-
content type, and extracted readable text for HTML pages
|
|
8
|
+
content type, and extracted readable text for HTML pages, including standard
|
|
9
|
+
description metadata when ordinary body text is unavailable. Use `WebSearch` to
|
|
9
10
|
discover URLs; use `WebFetch` when the URL is already known.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## shell
|
|
2
|
+
|
|
3
|
+
Run commands in the detected runtime shell for inspection, tests, builds, and
|
|
4
|
+
project operations.
|
|
5
|
+
|
|
6
|
+
Args: `command`, optional `timeout_ms`.
|
|
7
|
+
|
|
8
|
+
Use the runtime context's command dialect and path style: PowerShell uses
|
|
9
|
+
PowerShell commands and Windows paths, `cmd` uses cmd syntax, and `posix` uses
|
|
10
|
+
POSIX shell syntax.
|
|
11
|
+
|
|
12
|
+
Runs in the session cwd, preserves cwd between calls when supported, and returns
|
|
13
|
+
stdout/stderr JSON with cwd, exit-code, and shell metadata.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from .context import build_session_input_callback
|
|
3
|
+
from .context import build_session_input_callback, should_auto_compact
|
|
4
4
|
from .events import DeepyStreamEvent, normalize_stream_event
|
|
5
5
|
from .thinking import build_model_settings, build_thinking_extra_body
|
|
6
6
|
|
|
@@ -10,4 +10,5 @@ __all__ = [
|
|
|
10
10
|
"build_session_input_callback",
|
|
11
11
|
"build_thinking_extra_body",
|
|
12
12
|
"normalize_stream_event",
|
|
13
|
+
"should_auto_compact",
|
|
13
14
|
]
|