deepy-cli 0.2.5__tar.gz → 0.2.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.
Files changed (98) hide show
  1. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/PKG-INFO +41 -2
  2. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/README.md +38 -0
  3. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/pyproject.toml +3 -2
  4. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/__init__.py +1 -1
  5. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/cli.py +28 -11
  6. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/config/__init__.py +4 -0
  7. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/config/settings.py +25 -2
  8. deepy_cli-0.2.7/src/deepy/input_suggestions.py +455 -0
  9. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/mcp.py +21 -2
  10. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/sessions/jsonl.py +44 -0
  11. deepy_cli-0.2.7/src/deepy/status.py +319 -0
  12. deepy_cli-0.2.7/src/deepy/tui/__init__.py +5 -0
  13. deepy_cli-0.2.7/src/deepy/tui/app.py +1935 -0
  14. deepy_cli-0.2.7/src/deepy/tui/commands.py +90 -0
  15. deepy_cli-0.2.7/src/deepy/tui/compat.py +7 -0
  16. deepy_cli-0.2.7/src/deepy/tui/diff.py +115 -0
  17. deepy_cli-0.2.7/src/deepy/tui/runner.py +36 -0
  18. deepy_cli-0.2.7/src/deepy/tui/screens.py +409 -0
  19. deepy_cli-0.2.7/src/deepy/tui/state.py +101 -0
  20. deepy_cli-0.2.7/src/deepy/tui/widgets.py +917 -0
  21. deepy_cli-0.2.7/src/deepy/ui/exit_summary.py +188 -0
  22. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/message_view.py +6 -2
  23. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/prompt_input.py +103 -12
  24. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/slash_commands.py +7 -1
  25. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/terminal.py +140 -8
  26. deepy_cli-0.2.5/src/deepy/status.py +0 -82
  27. deepy_cli-0.2.5/src/deepy/ui/exit_summary.py +0 -143
  28. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/__main__.py +0 -0
  29. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/__init__.py +0 -0
  30. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/skills/skill-creator/SKILL.md +0 -0
  31. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/skills/skill-installer/SKILL.md +0 -0
  32. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/AskUserQuestion.md +0 -0
  33. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/WebFetch.md +0 -0
  34. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/WebSearch.md +0 -0
  35. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/__init__.py +0 -0
  36. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/edit.md +0 -0
  37. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/modify.md +0 -0
  38. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/read.md +0 -0
  39. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/shell.md +0 -0
  40. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/todo_write.md +0 -0
  41. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/data/tools/write.md +0 -0
  42. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/errors.py +0 -0
  43. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/__init__.py +0 -0
  44. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/agent.py +0 -0
  45. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/compaction.py +0 -0
  46. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/context.py +0 -0
  47. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/events.py +0 -0
  48. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/model_capabilities.py +0 -0
  49. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/provider.py +0 -0
  50. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/replay.py +0 -0
  51. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/runner.py +0 -0
  52. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/llm/thinking.py +0 -0
  53. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/prompts/__init__.py +0 -0
  54. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/prompts/compact.py +0 -0
  55. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/prompts/init_agents.py +0 -0
  56. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/prompts/rules.py +0 -0
  57. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/prompts/runtime_context.py +0 -0
  58. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/prompts/system.py +0 -0
  59. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/prompts/tool_docs.py +0 -0
  60. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/sessions/__init__.py +0 -0
  61. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/sessions/manager.py +0 -0
  62. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/skill_market.py +0 -0
  63. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/skills.py +0 -0
  64. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/todos.py +0 -0
  65. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/tools/__init__.py +0 -0
  66. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/tools/agents.py +0 -0
  67. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/tools/builtin.py +0 -0
  68. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/tools/file_state.py +0 -0
  69. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/tools/result.py +0 -0
  70. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/tools/shell_output.py +0 -0
  71. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/tools/shell_utils.py +0 -0
  72. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/types/__init__.py +0 -0
  73. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/types/sdk.py +0 -0
  74. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/types/tool_payloads.py +0 -0
  75. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/__init__.py +0 -0
  76. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/app.py +0 -0
  77. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/ask_user_question.py +0 -0
  78. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/file_mentions.py +0 -0
  79. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/loading_text.py +0 -0
  80. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/local_command.py +0 -0
  81. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/markdown.py +0 -0
  82. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/model_picker.py +0 -0
  83. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/prompt_buffer.py +0 -0
  84. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/session_list.py +0 -0
  85. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/session_picker.py +0 -0
  86. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/skill_picker.py +0 -0
  87. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/status_footer.py +0 -0
  88. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/styles.py +0 -0
  89. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/theme_picker.py +0 -0
  90. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/thinking_state.py +0 -0
  91. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/ui/welcome.py +0 -0
  92. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/update_check.py +0 -0
  93. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/usage.py +0 -0
  94. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/utils/__init__.py +0 -0
  95. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/utils/debug_logger.py +0 -0
  96. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/utils/error_logger.py +0 -0
  97. {deepy_cli-0.2.5 → deepy_cli-0.2.7}/src/deepy/utils/json.py +0 -0
  98. {deepy_cli-0.2.5 → deepy_cli-0.2.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.2.5
3
+ Version: 0.2.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
@@ -18,7 +18,8 @@ Requires-Dist: orjson>=3.10,<4
18
18
  Requires-Dist: pydantic>=2.12,<3
19
19
  Requires-Dist: prompt-toolkit>=3.0,<4
20
20
  Requires-Dist: pyyaml>=6.0,<7
21
- Requires-Dist: rich>=13.9,<15
21
+ Requires-Dist: rich>=14.2,<15
22
+ Requires-Dist: textual>=8.2,<9
22
23
  Requires-Dist: tiktoken>=0.9,<1
23
24
  Requires-Dist: tomli-w>=1
24
25
  Requires-Python: >=3.12
@@ -153,6 +154,41 @@ cd your-project
153
154
  deepy
154
155
  ```
155
156
 
157
+ ### Experimental Textual TUI
158
+
159
+ Deepy's stable default UI is still launched with `deepy`. Users who want to try
160
+ the new opt-in Textual interface can run:
161
+
162
+ ```bash
163
+ deepy tui
164
+ ```
165
+
166
+ This first iteration focuses on experience and TUI-native interactions: a
167
+ scrollable transcript, live thinking and assistant blocks, prompt suggestions
168
+ for slash commands and `@file` mentions, status/help surfaces, and a Deepy-owned
169
+ diff view. It is experimental and may change between releases.
170
+
171
+ ![Deepy Textual TUI](https://raw.githubusercontent.com/kirineko/deepy/main/asset/deepy-tui.webp)
172
+
173
+ `/status` is available in both the stable terminal UI and the TUI. It shows
174
+ session/project usage, context window pressure, and DeepSeek balance in one
175
+ compact view. The balance API is called only when `/status` is invoked, not on
176
+ startup, model turns, input suggestions, or exit.
177
+
178
+ ![Deepy TUI status panel](https://raw.githubusercontent.com/kirineko/deepy/main/asset/tui-status.webp)
179
+
180
+ `/exit`, `/quit`, and pressing Ctrl+D twice now print the same compact session
181
+ summary in both UIs.
182
+
183
+ ![Deepy TUI session summary](https://raw.githubusercontent.com/kirineko/deepy/main/asset/tui-summary.webp)
184
+
185
+ Known limitations: the TUI does not add interactive shell/PTTY support yet, and
186
+ toad / textual-diff-view are only design references. Deepy does not copy their
187
+ AGPL source or depend on those packages.
188
+
189
+ Please report feedback through GitHub Issues and include your terminal, shell,
190
+ operating system, and the exact `deepy tui` workflow you tried.
191
+
156
192
  ## Installation Notes
157
193
 
158
194
  Use this order for a fresh machine:
@@ -213,6 +249,7 @@ Inside an interactive Deepy session:
213
249
 
214
250
  ```text
215
251
  /model Select model and thinking strength
252
+ /status Show usage, context pressure, and DeepSeek balance
216
253
  /resume Resume a previous project session
217
254
  /new Start a fresh session
218
255
  /compact Compact the active session context
@@ -303,6 +340,7 @@ deepy config theme
303
340
  deepy doctor
304
341
  deepy doctor --live --json
305
342
  deepy status
343
+ deepy tui
306
344
  deepy skills list
307
345
  deepy sessions list
308
346
  deepy sessions show <session-id>
@@ -319,6 +357,7 @@ Inside the interactive terminal:
319
357
  /skill:<name> [request] Invoke a skill directly
320
358
  /init Create or update project AGENTS.md
321
359
  /mcp Show MCP server status and tools
360
+ /status Show usage, context pressure, and DeepSeek balance
322
361
  ```
323
362
 
324
363
  ## AGENTS.md Instructions And Skills
@@ -124,6 +124,41 @@ cd your-project
124
124
  deepy
125
125
  ```
126
126
 
127
+ ### Experimental Textual TUI
128
+
129
+ Deepy's stable default UI is still launched with `deepy`. Users who want to try
130
+ the new opt-in Textual interface can run:
131
+
132
+ ```bash
133
+ deepy tui
134
+ ```
135
+
136
+ This first iteration focuses on experience and TUI-native interactions: a
137
+ scrollable transcript, live thinking and assistant blocks, prompt suggestions
138
+ for slash commands and `@file` mentions, status/help surfaces, and a Deepy-owned
139
+ diff view. It is experimental and may change between releases.
140
+
141
+ ![Deepy Textual TUI](https://raw.githubusercontent.com/kirineko/deepy/main/asset/deepy-tui.webp)
142
+
143
+ `/status` is available in both the stable terminal UI and the TUI. It shows
144
+ session/project usage, context window pressure, and DeepSeek balance in one
145
+ compact view. The balance API is called only when `/status` is invoked, not on
146
+ startup, model turns, input suggestions, or exit.
147
+
148
+ ![Deepy TUI status panel](https://raw.githubusercontent.com/kirineko/deepy/main/asset/tui-status.webp)
149
+
150
+ `/exit`, `/quit`, and pressing Ctrl+D twice now print the same compact session
151
+ summary in both UIs.
152
+
153
+ ![Deepy TUI session summary](https://raw.githubusercontent.com/kirineko/deepy/main/asset/tui-summary.webp)
154
+
155
+ Known limitations: the TUI does not add interactive shell/PTTY support yet, and
156
+ toad / textual-diff-view are only design references. Deepy does not copy their
157
+ AGPL source or depend on those packages.
158
+
159
+ Please report feedback through GitHub Issues and include your terminal, shell,
160
+ operating system, and the exact `deepy tui` workflow you tried.
161
+
127
162
  ## Installation Notes
128
163
 
129
164
  Use this order for a fresh machine:
@@ -184,6 +219,7 @@ Inside an interactive Deepy session:
184
219
 
185
220
  ```text
186
221
  /model Select model and thinking strength
222
+ /status Show usage, context pressure, and DeepSeek balance
187
223
  /resume Resume a previous project session
188
224
  /new Start a fresh session
189
225
  /compact Compact the active session context
@@ -274,6 +310,7 @@ deepy config theme
274
310
  deepy doctor
275
311
  deepy doctor --live --json
276
312
  deepy status
313
+ deepy tui
277
314
  deepy skills list
278
315
  deepy sessions list
279
316
  deepy sessions show <session-id>
@@ -290,6 +327,7 @@ Inside the interactive terminal:
290
327
  /skill:<name> [request] Invoke a skill directly
291
328
  /init Create or update project AGENTS.md
292
329
  /mcp Show MCP server status and tools
330
+ /status Show usage, context pressure, and DeepSeek balance
293
331
  ```
294
332
 
295
333
  ## AGENTS.md Instructions And Skills
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "deepy-cli"
3
- version = "0.2.5"
3
+ version = "0.2.7"
4
4
  description = "Deepy - Vibe coding for DeepSeek models in your terminal"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -24,7 +24,8 @@ dependencies = [
24
24
  "pydantic>=2.12,<3",
25
25
  "prompt-toolkit>=3.0,<4",
26
26
  "pyyaml>=6.0,<7",
27
- "rich>=13.9,<15",
27
+ "rich>=14.2,<15",
28
+ "textual>=8.2,<9",
28
29
  "tiktoken>=0.9,<1",
29
30
  "tomli-w>=1",
30
31
  ]
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.2.5"
3
+ __version__ = "0.2.7"
4
4
 
5
5
 
6
6
  def main() -> None:
@@ -78,6 +78,8 @@ def _build_parser() -> argparse.ArgumentParser:
78
78
  run_parser.add_argument("--session", help="Resume an existing session id.")
79
79
  run_parser.add_argument("--skill", action="append", default=[], help="Load a skill by name.")
80
80
 
81
+ subparsers.add_parser("tui", help="Start the experimental Textual TUI.")
82
+
81
83
  sessions_parser = subparsers.add_parser("sessions", help="Inspect project sessions.")
82
84
  sessions_sub = sessions_parser.add_subparsers(dest="sessions_command", required=True)
83
85
  sessions_sub.add_parser("list", help="List sessions for the current project.")
@@ -410,6 +412,29 @@ def _cmd_status(args: argparse.Namespace) -> int:
410
412
  return 0
411
413
 
412
414
 
415
+ def _ensure_interactive_settings(args: argparse.Namespace) -> Settings:
416
+ settings = load_settings(args.config)
417
+ if not settings.model.api_key:
418
+ print("Deepy needs a DeepSeek API key before starting interactive mode.")
419
+ setup_args = argparse.Namespace(config=args.config, force=True)
420
+ _cmd_config_setup(setup_args)
421
+ settings = load_settings(args.config)
422
+ if settings.path is not None and not settings.ui.theme_configured:
423
+ theme = _prompt_theme_value(default=settings.ui.theme)
424
+ update_config_theme(settings.path, theme)
425
+ settings = load_settings(args.config)
426
+ return settings
427
+
428
+
429
+ def _cmd_tui(args: argparse.Namespace) -> int:
430
+ if not sys.stdin.isatty():
431
+ print("experimental TUI requires a TTY; use `deepy` for the stable terminal UI.", file=sys.stderr)
432
+ return 1
433
+ from deepy.tui import run_tui
434
+
435
+ return run_tui(_ensure_interactive_settings(args), project_root=Path.cwd())
436
+
437
+
413
438
  def main(argv: Sequence[str] | None = None) -> int:
414
439
  parser = _build_parser()
415
440
  args = parser.parse_args(argv)
@@ -435,20 +460,12 @@ def main(argv: Sequence[str] | None = None) -> int:
435
460
  return _cmd_skills(args)
436
461
  if args.command == "status":
437
462
  return _cmd_status(args)
463
+ if args.command == "tui":
464
+ return _cmd_tui(args)
438
465
 
439
466
  if not sys.stdin.isatty():
440
467
  parser.error("interactive mode requires a TTY; use `deepy doctor` or `deepy config show`.")
441
- settings = load_settings(args.config)
442
- if not settings.model.api_key:
443
- print("Deepy needs a DeepSeek API key before starting interactive mode.")
444
- setup_args = argparse.Namespace(config=args.config, force=True)
445
- _cmd_config_setup(setup_args)
446
- settings = load_settings(args.config)
447
- if settings.path is not None and not settings.ui.theme_configured:
448
- theme = _prompt_theme_value(default=settings.ui.theme)
449
- update_config_theme(settings.path, theme)
450
- settings = load_settings(args.config)
451
- return run_interactive(settings)
468
+ return run_interactive(_ensure_interactive_settings(args))
452
469
 
453
470
 
454
471
  if __name__ == "__main__":
@@ -4,6 +4,7 @@ from .settings import (
4
4
  ContextConfig,
5
5
  DEEPSEEK_MODEL_CATALOG,
6
6
  DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES,
7
+ DEFAULT_INPUT_SUGGESTIONS_ENABLED,
7
8
  DEFAULT_RESERVED_CONTEXT_TOKENS,
8
9
  DEFAULT_UI_THEME,
9
10
  DEFAULT_WEB_SEARCH_SEARXNG_URL,
@@ -26,6 +27,7 @@ from .settings import (
26
27
  mask_secret,
27
28
  settings_to_toml_dict,
28
29
  update_config_model_settings,
30
+ update_config_input_suggestions_enabled,
29
31
  update_config_theme,
30
32
  ui_theme_from_selection,
31
33
  ui_theme_number,
@@ -36,6 +38,7 @@ __all__ = [
36
38
  "ContextConfig",
37
39
  "DEEPSEEK_MODEL_CATALOG",
38
40
  "DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES",
41
+ "DEFAULT_INPUT_SUGGESTIONS_ENABLED",
39
42
  "DEFAULT_RESERVED_CONTEXT_TOKENS",
40
43
  "DEFAULT_UI_THEME",
41
44
  "DEFAULT_WEB_SEARCH_SEARXNG_URL",
@@ -58,6 +61,7 @@ __all__ = [
58
61
  "mask_secret",
59
62
  "settings_to_toml_dict",
60
63
  "update_config_model_settings",
64
+ "update_config_input_suggestions_enabled",
61
65
  "update_config_theme",
62
66
  "ui_theme_from_selection",
63
67
  "ui_theme_number",
@@ -21,6 +21,7 @@ DEFAULT_MCP_CONNECT_TIMEOUT_SECONDS = 10.0
21
21
  DEFAULT_MCP_CLEANUP_TIMEOUT_SECONDS = 10.0
22
22
  DEFAULT_MCP_CLIENT_SESSION_TIMEOUT_SECONDS = 30.0
23
23
  DEFAULT_MCP_CACHE_TOOLS_LIST = True
24
+ DEFAULT_INPUT_SUGGESTIONS_ENABLED = True
24
25
  REASONING_EFFORTS = {"high", "max"}
25
26
  REASONING_MODES = {"none", "high", "max"}
26
27
  UI_THEMES = {"auto", "dark", "light"}
@@ -284,13 +285,22 @@ class McpConfig:
284
285
  class UiConfig:
285
286
  theme: str = DEFAULT_UI_THEME
286
287
  theme_configured: bool = False
288
+ input_suggestions_enabled: bool = DEFAULT_INPUT_SUGGESTIONS_ENABLED
287
289
 
288
290
  @classmethod
289
291
  def from_mapping(cls, raw: Mapping[str, Any]) -> Self:
290
292
  theme = raw.get("theme")
293
+ input_suggestions_enabled = _as_bool(
294
+ raw.get("input_suggestions_enabled"),
295
+ DEFAULT_INPUT_SUGGESTIONS_ENABLED,
296
+ )
291
297
  if isinstance(theme, str) and theme.strip() in UI_THEMES:
292
- return cls(theme=theme.strip(), theme_configured=True)
293
- return cls()
298
+ return cls(
299
+ theme=theme.strip(),
300
+ theme_configured=True,
301
+ input_suggestions_enabled=input_suggestions_enabled,
302
+ )
303
+ return cls(input_suggestions_enabled=input_suggestions_enabled)
294
304
 
295
305
 
296
306
  @dataclass(frozen=True)
@@ -441,6 +451,7 @@ def write_config(
441
451
  },
442
452
  "ui": {
443
453
  "theme": theme,
454
+ "input_suggestions_enabled": DEFAULT_INPUT_SUGGESTIONS_ENABLED,
444
455
  },
445
456
  }
446
457
  path.parent.mkdir(parents=True, exist_ok=True)
@@ -492,6 +503,18 @@ def update_config_theme(config_path: Path, theme: str) -> None:
492
503
  _write_private_toml(path, raw)
493
504
 
494
505
 
506
+ def update_config_input_suggestions_enabled(config_path: Path, enabled: bool) -> None:
507
+ path = config_path.expanduser()
508
+ if path.suffix == ".json":
509
+ raise ValueError("Deepy only supports TOML config files; JSON config is not supported.")
510
+ raw = _read_toml_mapping(path)
511
+ ui = raw.get("ui")
512
+ ui_map = dict(ui) if isinstance(ui, Mapping) else {}
513
+ ui_map["input_suggestions_enabled"] = bool(enabled)
514
+ raw["ui"] = ui_map
515
+ _write_private_toml(path, raw)
516
+
517
+
495
518
  def _read_toml_mapping(path: Path) -> dict[str, Any]:
496
519
  if not path.exists():
497
520
  return {}