deepy-cli 0.1.14__tar.gz → 0.2.0__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.14 → deepy_cli-0.2.0}/PKG-INFO +76 -7
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/README.md +74 -6
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/pyproject.toml +2 -1
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/__init__.py +1 -1
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/config/__init__.py +6 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/config/settings.py +85 -0
- deepy_cli-0.2.0/src/deepy/data/skills/skill-creator/SKILL.md +54 -0
- deepy_cli-0.2.0/src/deepy/data/skills/skill-installer/SKILL.md +34 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/WebSearch.md +5 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/agent.py +14 -2
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/events.py +11 -1
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/runner.py +71 -18
- deepy_cli-0.2.0/src/deepy/mcp.py +561 -0
- deepy_cli-0.2.0/src/deepy/prompts/init_agents.py +36 -0
- deepy_cli-0.2.0/src/deepy/prompts/rules.py +139 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/prompts/system.py +43 -3
- deepy_cli-0.2.0/src/deepy/skill_market.py +350 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/skills.py +26 -8
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/status.py +9 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/tools/agents.py +47 -6
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/tools/builtin.py +31 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/message_view.py +113 -0
- deepy_cli-0.2.0/src/deepy/ui/skill_picker.py +433 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/slash_commands.py +13 -7
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/terminal.py +538 -115
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/welcome.py +1 -1
- deepy_cli-0.1.14/src/deepy/prompts/rules.py +0 -24
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/__main__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/cli.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/AskUserQuestion.md +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/WebFetch.md +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/edit.md +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/modify.md +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/read.md +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/shell.md +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/data/tools/write.md +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/errors.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/compaction.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/context.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/model_capabilities.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/provider.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/replay.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/llm/thinking.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/prompts/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/prompts/compact.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/prompts/runtime_context.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/prompts/tool_docs.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/sessions/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/sessions/jsonl.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/sessions/manager.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/tools/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/tools/file_state.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/tools/result.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/tools/shell_output.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/tools/shell_utils.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/app.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/ask_user_question.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/exit_summary.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/file_mentions.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/loading_text.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/local_command.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/markdown.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/model_picker.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/prompt_buffer.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/prompt_input.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/session_list.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/session_picker.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/styles.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/theme_picker.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/ui/thinking_state.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/update_check.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/usage.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/utils/__init__.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/utils/debug_logger.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/utils/error_logger.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/src/deepy/utils/json.py +0 -0
- {deepy_cli-0.1.14 → deepy_cli-0.2.0}/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.
|
|
3
|
+
Version: 0.2.0
|
|
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
|
|
@@ -17,6 +17,7 @@ Requires-Dist: openai>=2.26,<3
|
|
|
17
17
|
Requires-Dist: orjson>=3.10,<4
|
|
18
18
|
Requires-Dist: pydantic>=2.12,<3
|
|
19
19
|
Requires-Dist: prompt-toolkit>=3.0,<4
|
|
20
|
+
Requires-Dist: pyyaml>=6.0,<7
|
|
20
21
|
Requires-Dist: rich>=13.9,<15
|
|
21
22
|
Requires-Dist: tiktoken>=0.9,<1
|
|
22
23
|
Requires-Dist: tomli-w>=1
|
|
@@ -268,6 +269,30 @@ WebSearch uses Deepy's hosted SearXNG endpoint by default. You can override it:
|
|
|
268
269
|
searxng_url = "https://your-searxng.example/"
|
|
269
270
|
```
|
|
270
271
|
|
|
272
|
+
Deepy can also load MCP servers through the OpenAI Agents SDK. Most users only
|
|
273
|
+
need `~/.deepy/mcp.json`:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"mcpServers": {
|
|
278
|
+
"tavily": {
|
|
279
|
+
"transport": "stdio",
|
|
280
|
+
"command": "npx",
|
|
281
|
+
"args": ["-y", "tavily-mcp"],
|
|
282
|
+
"env": {"TAVILY_API_KEY": "${TAVILY_API_KEY}"},
|
|
283
|
+
"roles": ["web_search"]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
When an active MCP tool is marked or detected as web search, Deepy instructs the
|
|
290
|
+
model to prefer it over built-in WebSearch and keeps built-in WebSearch as a
|
|
291
|
+
fallback. Project MCP config is ignored by default because stdio MCP servers can
|
|
292
|
+
start local commands; enable `mcp.allow_project_config` only for trusted
|
|
293
|
+
projects. Use `/mcp` to inspect server status and exposed tools. Advanced MCP
|
|
294
|
+
configuration is documented in [docs/mcp.md](docs/mcp.md).
|
|
295
|
+
|
|
271
296
|
## Command Reference
|
|
272
297
|
|
|
273
298
|
```bash
|
|
@@ -284,15 +309,59 @@ deepy sessions show <session-id>
|
|
|
284
309
|
deepy run "summarize this project"
|
|
285
310
|
```
|
|
286
311
|
|
|
287
|
-
|
|
312
|
+
Inside the interactive terminal:
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
/skills Manage local and market skills
|
|
316
|
+
/skills list List discovered skills
|
|
317
|
+
/skills search <query> Search the configured skill market
|
|
318
|
+
/skills install <name> Install a market skill
|
|
319
|
+
/skill:<name> [request] Invoke a skill directly
|
|
320
|
+
/init Create or update project AGENTS.md
|
|
321
|
+
/mcp Show MCP server status and tools
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## AGENTS.md Instructions And Skills
|
|
325
|
+
|
|
326
|
+
Deepy automatically loads agent-facing instructions from:
|
|
327
|
+
|
|
328
|
+
- `~/.deepy/AGENTS.md` for Deepy-wide personal guidance
|
|
329
|
+
- `AGENTS.md` files from the git root down to the current working directory
|
|
330
|
+
- `.agents/skills/*/SKILL.md`
|
|
288
331
|
|
|
289
|
-
|
|
332
|
+
Project `AGENTS.md` files are loaded from broad to specific. A file in a nested
|
|
333
|
+
directory appears after the repository root file and takes precedence when rules
|
|
334
|
+
conflict. Direct user instructions still take precedence over loaded
|
|
335
|
+
`AGENTS.md` guidance.
|
|
336
|
+
|
|
337
|
+
A concise `AGENTS.md` works best:
|
|
338
|
+
|
|
339
|
+
```markdown
|
|
340
|
+
# AGENTS.md
|
|
341
|
+
|
|
342
|
+
## Commands
|
|
343
|
+
- Test: `uv run pytest`
|
|
344
|
+
- Lint: `uv run ruff check`
|
|
345
|
+
- Type check: `uv run pyright`
|
|
346
|
+
|
|
347
|
+
## Architecture
|
|
348
|
+
- Keep CLI entry points thin; put reusable behavior under `src/`.
|
|
349
|
+
|
|
350
|
+
## Style
|
|
351
|
+
- Prefer small, focused changes that match existing patterns.
|
|
352
|
+
|
|
353
|
+
## Verification
|
|
354
|
+
- Run focused tests for touched code before broader checks.
|
|
355
|
+
|
|
356
|
+
## Boundaries
|
|
357
|
+
- Do not rewrite unrelated files or revert user changes.
|
|
358
|
+
```
|
|
290
359
|
|
|
291
|
-
|
|
292
|
-
-
|
|
360
|
+
Skills remain standard Agent Skills under `.agents/skills/*/SKILL.md` and are
|
|
361
|
+
loaded through the skill progressive-disclosure flow.
|
|
293
362
|
|
|
294
|
-
|
|
295
|
-
|
|
363
|
+
Run `/init` in the interactive terminal to have Deepy inspect the repository and
|
|
364
|
+
create or refresh the project root `AGENTS.md`.
|
|
296
365
|
|
|
297
366
|
## Development
|
|
298
367
|
|
|
@@ -240,6 +240,30 @@ WebSearch uses Deepy's hosted SearXNG endpoint by default. You can override it:
|
|
|
240
240
|
searxng_url = "https://your-searxng.example/"
|
|
241
241
|
```
|
|
242
242
|
|
|
243
|
+
Deepy can also load MCP servers through the OpenAI Agents SDK. Most users only
|
|
244
|
+
need `~/.deepy/mcp.json`:
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"mcpServers": {
|
|
249
|
+
"tavily": {
|
|
250
|
+
"transport": "stdio",
|
|
251
|
+
"command": "npx",
|
|
252
|
+
"args": ["-y", "tavily-mcp"],
|
|
253
|
+
"env": {"TAVILY_API_KEY": "${TAVILY_API_KEY}"},
|
|
254
|
+
"roles": ["web_search"]
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
When an active MCP tool is marked or detected as web search, Deepy instructs the
|
|
261
|
+
model to prefer it over built-in WebSearch and keeps built-in WebSearch as a
|
|
262
|
+
fallback. Project MCP config is ignored by default because stdio MCP servers can
|
|
263
|
+
start local commands; enable `mcp.allow_project_config` only for trusted
|
|
264
|
+
projects. Use `/mcp` to inspect server status and exposed tools. Advanced MCP
|
|
265
|
+
configuration is documented in [docs/mcp.md](docs/mcp.md).
|
|
266
|
+
|
|
243
267
|
## Command Reference
|
|
244
268
|
|
|
245
269
|
```bash
|
|
@@ -256,15 +280,59 @@ deepy sessions show <session-id>
|
|
|
256
280
|
deepy run "summarize this project"
|
|
257
281
|
```
|
|
258
282
|
|
|
259
|
-
|
|
283
|
+
Inside the interactive terminal:
|
|
284
|
+
|
|
285
|
+
```text
|
|
286
|
+
/skills Manage local and market skills
|
|
287
|
+
/skills list List discovered skills
|
|
288
|
+
/skills search <query> Search the configured skill market
|
|
289
|
+
/skills install <name> Install a market skill
|
|
290
|
+
/skill:<name> [request] Invoke a skill directly
|
|
291
|
+
/init Create or update project AGENTS.md
|
|
292
|
+
/mcp Show MCP server status and tools
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## AGENTS.md Instructions And Skills
|
|
296
|
+
|
|
297
|
+
Deepy automatically loads agent-facing instructions from:
|
|
298
|
+
|
|
299
|
+
- `~/.deepy/AGENTS.md` for Deepy-wide personal guidance
|
|
300
|
+
- `AGENTS.md` files from the git root down to the current working directory
|
|
301
|
+
- `.agents/skills/*/SKILL.md`
|
|
260
302
|
|
|
261
|
-
|
|
303
|
+
Project `AGENTS.md` files are loaded from broad to specific. A file in a nested
|
|
304
|
+
directory appears after the repository root file and takes precedence when rules
|
|
305
|
+
conflict. Direct user instructions still take precedence over loaded
|
|
306
|
+
`AGENTS.md` guidance.
|
|
307
|
+
|
|
308
|
+
A concise `AGENTS.md` works best:
|
|
309
|
+
|
|
310
|
+
```markdown
|
|
311
|
+
# AGENTS.md
|
|
312
|
+
|
|
313
|
+
## Commands
|
|
314
|
+
- Test: `uv run pytest`
|
|
315
|
+
- Lint: `uv run ruff check`
|
|
316
|
+
- Type check: `uv run pyright`
|
|
317
|
+
|
|
318
|
+
## Architecture
|
|
319
|
+
- Keep CLI entry points thin; put reusable behavior under `src/`.
|
|
320
|
+
|
|
321
|
+
## Style
|
|
322
|
+
- Prefer small, focused changes that match existing patterns.
|
|
323
|
+
|
|
324
|
+
## Verification
|
|
325
|
+
- Run focused tests for touched code before broader checks.
|
|
326
|
+
|
|
327
|
+
## Boundaries
|
|
328
|
+
- Do not rewrite unrelated files or revert user changes.
|
|
329
|
+
```
|
|
262
330
|
|
|
263
|
-
|
|
264
|
-
-
|
|
331
|
+
Skills remain standard Agent Skills under `.agents/skills/*/SKILL.md` and are
|
|
332
|
+
loaded through the skill progressive-disclosure flow.
|
|
265
333
|
|
|
266
|
-
|
|
267
|
-
|
|
334
|
+
Run `/init` in the interactive terminal to have Deepy inspect the repository and
|
|
335
|
+
create or refresh the project root `AGENTS.md`.
|
|
268
336
|
|
|
269
337
|
## Development
|
|
270
338
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "deepy-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Deepy - Vibe coding for DeepSeek models in your terminal"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -23,6 +23,7 @@ dependencies = [
|
|
|
23
23
|
"orjson>=3.10,<4",
|
|
24
24
|
"pydantic>=2.12,<3",
|
|
25
25
|
"prompt-toolkit>=3.0,<4",
|
|
26
|
+
"pyyaml>=6.0,<7",
|
|
26
27
|
"rich>=13.9,<15",
|
|
27
28
|
"tiktoken>=0.9,<1",
|
|
28
29
|
"tomli-w>=1",
|
|
@@ -8,6 +8,8 @@ from .settings import (
|
|
|
8
8
|
DEFAULT_UI_THEME,
|
|
9
9
|
DEFAULT_WEB_SEARCH_SEARXNG_URL,
|
|
10
10
|
DeepSeekModelInfo,
|
|
11
|
+
McpConfig,
|
|
12
|
+
McpWebSearchConfig,
|
|
11
13
|
ModelConfig,
|
|
12
14
|
REASONING_MODES,
|
|
13
15
|
Settings,
|
|
@@ -16,6 +18,7 @@ from .settings import (
|
|
|
16
18
|
UI_THEMES,
|
|
17
19
|
UiConfig,
|
|
18
20
|
default_config_path,
|
|
21
|
+
default_mcp_config_path,
|
|
19
22
|
is_supported_deepseek_model,
|
|
20
23
|
is_valid_ui_theme,
|
|
21
24
|
is_valid_reasoning_mode,
|
|
@@ -37,6 +40,8 @@ __all__ = [
|
|
|
37
40
|
"DEFAULT_UI_THEME",
|
|
38
41
|
"DEFAULT_WEB_SEARCH_SEARXNG_URL",
|
|
39
42
|
"DeepSeekModelInfo",
|
|
43
|
+
"McpConfig",
|
|
44
|
+
"McpWebSearchConfig",
|
|
40
45
|
"ModelConfig",
|
|
41
46
|
"REASONING_MODES",
|
|
42
47
|
"Settings",
|
|
@@ -45,6 +50,7 @@ __all__ = [
|
|
|
45
50
|
"UI_THEMES",
|
|
46
51
|
"UiConfig",
|
|
47
52
|
"default_config_path",
|
|
53
|
+
"default_mcp_config_path",
|
|
48
54
|
"is_supported_deepseek_model",
|
|
49
55
|
"is_valid_ui_theme",
|
|
50
56
|
"is_valid_reasoning_mode",
|
|
@@ -16,6 +16,11 @@ DEFAULT_RESERVED_CONTEXT_TOKENS = 50_000
|
|
|
16
16
|
DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES = 2
|
|
17
17
|
DEFAULT_WEB_SEARCH_SEARXNG_URL = "https://s.kirineko.tech/"
|
|
18
18
|
DEFAULT_UI_THEME = "auto"
|
|
19
|
+
DEFAULT_MCP_ENABLED = True
|
|
20
|
+
DEFAULT_MCP_CONNECT_TIMEOUT_SECONDS = 10.0
|
|
21
|
+
DEFAULT_MCP_CLEANUP_TIMEOUT_SECONDS = 10.0
|
|
22
|
+
DEFAULT_MCP_CLIENT_SESSION_TIMEOUT_SECONDS = 30.0
|
|
23
|
+
DEFAULT_MCP_CACHE_TOOLS_LIST = True
|
|
19
24
|
REASONING_EFFORTS = {"high", "max"}
|
|
20
25
|
REASONING_MODES = {"none", "high", "max"}
|
|
21
26
|
UI_THEMES = {"auto", "dark", "light"}
|
|
@@ -50,6 +55,12 @@ def default_config_path() -> Path:
|
|
|
50
55
|
return Path.home() / ".deepy" / "config.toml"
|
|
51
56
|
|
|
52
57
|
|
|
58
|
+
def default_mcp_config_path(config_path: Path | None = None) -> Path:
|
|
59
|
+
if config_path is not None:
|
|
60
|
+
return config_path.expanduser().parent / "mcp.json"
|
|
61
|
+
return Path.home() / ".deepy" / "mcp.json"
|
|
62
|
+
|
|
63
|
+
|
|
53
64
|
def mask_secret(value: str | None) -> str:
|
|
54
65
|
if not value:
|
|
55
66
|
return ""
|
|
@@ -212,6 +223,63 @@ class ToolsConfig:
|
|
|
212
223
|
return cls(web_search=WebSearchToolConfig.from_mapping(_as_mapping(raw.get("web_search"))))
|
|
213
224
|
|
|
214
225
|
|
|
226
|
+
@dataclass(frozen=True)
|
|
227
|
+
class McpWebSearchConfig:
|
|
228
|
+
prefer_mcp: bool = True
|
|
229
|
+
preferred_server: str | None = None
|
|
230
|
+
preferred_tools: tuple[str, ...] = ()
|
|
231
|
+
fallback_to_builtin: bool = True
|
|
232
|
+
|
|
233
|
+
@classmethod
|
|
234
|
+
def from_mapping(cls, raw: Mapping[str, Any]) -> Self:
|
|
235
|
+
tools = raw.get("preferred_tools")
|
|
236
|
+
preferred_tools = (
|
|
237
|
+
tuple(item.strip() for item in tools if isinstance(item, str) and item.strip())
|
|
238
|
+
if isinstance(tools, list)
|
|
239
|
+
else ()
|
|
240
|
+
)
|
|
241
|
+
return cls(
|
|
242
|
+
prefer_mcp=_as_bool(raw.get("prefer_mcp"), True),
|
|
243
|
+
preferred_server=_as_str(raw.get("preferred_server")) or None,
|
|
244
|
+
preferred_tools=preferred_tools,
|
|
245
|
+
fallback_to_builtin=_as_bool(raw.get("fallback_to_builtin"), True),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@dataclass(frozen=True)
|
|
250
|
+
class McpConfig:
|
|
251
|
+
enabled: bool = DEFAULT_MCP_ENABLED
|
|
252
|
+
connect_timeout_seconds: float = DEFAULT_MCP_CONNECT_TIMEOUT_SECONDS
|
|
253
|
+
cleanup_timeout_seconds: float = DEFAULT_MCP_CLEANUP_TIMEOUT_SECONDS
|
|
254
|
+
client_session_timeout_seconds: float = DEFAULT_MCP_CLIENT_SESSION_TIMEOUT_SECONDS
|
|
255
|
+
cache_tools_list: bool = DEFAULT_MCP_CACHE_TOOLS_LIST
|
|
256
|
+
allow_project_config: bool = False
|
|
257
|
+
prefer_mcp_web_search: bool = True
|
|
258
|
+
web_search: McpWebSearchConfig = field(default_factory=McpWebSearchConfig)
|
|
259
|
+
|
|
260
|
+
@classmethod
|
|
261
|
+
def from_mapping(cls, raw: Mapping[str, Any]) -> Self:
|
|
262
|
+
return cls(
|
|
263
|
+
enabled=_as_bool(raw.get("enabled"), DEFAULT_MCP_ENABLED),
|
|
264
|
+
connect_timeout_seconds=_as_float(
|
|
265
|
+
raw.get("connect_timeout_seconds"),
|
|
266
|
+
DEFAULT_MCP_CONNECT_TIMEOUT_SECONDS,
|
|
267
|
+
),
|
|
268
|
+
cleanup_timeout_seconds=_as_float(
|
|
269
|
+
raw.get("cleanup_timeout_seconds"),
|
|
270
|
+
DEFAULT_MCP_CLEANUP_TIMEOUT_SECONDS,
|
|
271
|
+
),
|
|
272
|
+
client_session_timeout_seconds=_as_float(
|
|
273
|
+
raw.get("client_session_timeout_seconds"),
|
|
274
|
+
DEFAULT_MCP_CLIENT_SESSION_TIMEOUT_SECONDS,
|
|
275
|
+
),
|
|
276
|
+
cache_tools_list=_as_bool(raw.get("cache_tools_list"), DEFAULT_MCP_CACHE_TOOLS_LIST),
|
|
277
|
+
allow_project_config=_as_bool(raw.get("allow_project_config"), False),
|
|
278
|
+
prefer_mcp_web_search=_as_bool(raw.get("prefer_mcp_web_search"), True),
|
|
279
|
+
web_search=McpWebSearchConfig.from_mapping(_as_mapping(raw.get("web_search"))),
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
215
283
|
@dataclass(frozen=True)
|
|
216
284
|
class UiConfig:
|
|
217
285
|
theme: str = DEFAULT_UI_THEME
|
|
@@ -232,6 +300,7 @@ class Settings:
|
|
|
232
300
|
logging: LoggingConfig = field(default_factory=LoggingConfig)
|
|
233
301
|
notify: NotifyConfig = field(default_factory=NotifyConfig)
|
|
234
302
|
tools: ToolsConfig = field(default_factory=ToolsConfig)
|
|
303
|
+
mcp: McpConfig = field(default_factory=McpConfig)
|
|
235
304
|
ui: UiConfig = field(default_factory=UiConfig)
|
|
236
305
|
path: Path | None = None
|
|
237
306
|
|
|
@@ -249,6 +318,7 @@ class Settings:
|
|
|
249
318
|
logging=LoggingConfig.from_mapping(_as_mapping(raw.get("logging"))),
|
|
250
319
|
notify=NotifyConfig.from_mapping(_as_mapping(raw.get("notify"))),
|
|
251
320
|
tools=ToolsConfig.from_mapping(_as_mapping(raw.get("tools"))),
|
|
321
|
+
mcp=McpConfig.from_mapping(_as_mapping(raw.get("mcp"))),
|
|
252
322
|
ui=UiConfig.from_mapping(_as_mapping(raw.get("ui"))),
|
|
253
323
|
path=path,
|
|
254
324
|
)
|
|
@@ -354,6 +424,21 @@ def write_config(
|
|
|
354
424
|
"searxng_url": DEFAULT_WEB_SEARCH_SEARXNG_URL,
|
|
355
425
|
},
|
|
356
426
|
},
|
|
427
|
+
"mcp": {
|
|
428
|
+
"enabled": DEFAULT_MCP_ENABLED,
|
|
429
|
+
"connect_timeout_seconds": DEFAULT_MCP_CONNECT_TIMEOUT_SECONDS,
|
|
430
|
+
"cleanup_timeout_seconds": DEFAULT_MCP_CLEANUP_TIMEOUT_SECONDS,
|
|
431
|
+
"client_session_timeout_seconds": DEFAULT_MCP_CLIENT_SESSION_TIMEOUT_SECONDS,
|
|
432
|
+
"cache_tools_list": DEFAULT_MCP_CACHE_TOOLS_LIST,
|
|
433
|
+
"allow_project_config": False,
|
|
434
|
+
"prefer_mcp_web_search": True,
|
|
435
|
+
"web_search": {
|
|
436
|
+
"prefer_mcp": True,
|
|
437
|
+
"preferred_server": "",
|
|
438
|
+
"preferred_tools": [],
|
|
439
|
+
"fallback_to_builtin": True,
|
|
440
|
+
},
|
|
441
|
+
},
|
|
357
442
|
"ui": {
|
|
358
443
|
"theme": theme,
|
|
359
444
|
},
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: Create or update Agent Skills for Deepy. Use when the user wants to design, write, validate, or improve a reusable skill.
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Create or update an Agent Skill
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Skill Creator
|
|
9
|
+
|
|
10
|
+
Use this skill when creating or improving an Agent Skill.
|
|
11
|
+
|
|
12
|
+
## Skill Shape
|
|
13
|
+
|
|
14
|
+
An Agent Skill is a directory with a required `SKILL.md` file:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
skill-name/
|
|
18
|
+
├── SKILL.md
|
|
19
|
+
├── scripts/
|
|
20
|
+
├── references/
|
|
21
|
+
└── assets/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`SKILL.md` uses YAML frontmatter followed by concise Markdown instructions:
|
|
25
|
+
|
|
26
|
+
```markdown
|
|
27
|
+
---
|
|
28
|
+
name: code-review
|
|
29
|
+
description: Review code changes for correctness, regressions, and missing tests.
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# Code Review
|
|
33
|
+
|
|
34
|
+
Review the change before summarizing it. Lead with findings.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Rules
|
|
38
|
+
|
|
39
|
+
- Store user skills in `~/.agents/skills/<name>/SKILL.md`.
|
|
40
|
+
- Store project skills in `<project>/.agents/skills/<name>/SKILL.md`.
|
|
41
|
+
- Use lowercase letters, digits, and hyphens for skill names.
|
|
42
|
+
- Keep `SKILL.md` focused. Move detailed material to `references/`.
|
|
43
|
+
- Use `scripts/` for deterministic repeated operations.
|
|
44
|
+
- Use `assets/` for templates or files that support final outputs.
|
|
45
|
+
- Do not add market-specific metadata to the skill directory.
|
|
46
|
+
|
|
47
|
+
## Creation Process
|
|
48
|
+
|
|
49
|
+
1. Identify the concrete situations that should trigger the skill.
|
|
50
|
+
2. Choose a short hyphen-case name.
|
|
51
|
+
3. Write a clear `description` that says when to use the skill.
|
|
52
|
+
4. Keep the main workflow in `SKILL.md`.
|
|
53
|
+
5. Add references, scripts, or assets only when they remove real repetition or ambiguity.
|
|
54
|
+
6. Validate that the skill can be discovered by Deepy with `/skills list`.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-installer
|
|
3
|
+
description: Install, uninstall, update, and inspect Deepy skills from the configured Deepy skill market.
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Install skills from Deepy's market
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Skill Installer
|
|
9
|
+
|
|
10
|
+
Use this skill when the user wants to browse, install, uninstall, update, or inspect skills.
|
|
11
|
+
|
|
12
|
+
## Deepy Skill Commands
|
|
13
|
+
|
|
14
|
+
- `/skills` shows available management commands.
|
|
15
|
+
- `/skills list` lists local project, user, and built-in skills.
|
|
16
|
+
- `/skills search [query]` searches the configured Deepy skill market.
|
|
17
|
+
- `/skills install <name>` installs a market skill into `~/.agents/skills/<name>`.
|
|
18
|
+
- `/skills uninstall <name>` removes a skill installed by Deepy's market installer.
|
|
19
|
+
- `/skills installed` lists market-installed skills.
|
|
20
|
+
- `/skills update <name>` updates one market-installed skill when a newer upload exists.
|
|
21
|
+
- `/skills update --all` updates all market-installed skills when newer uploads exist.
|
|
22
|
+
- `/skill:<name> [request]` actively invokes an installed or built-in skill.
|
|
23
|
+
|
|
24
|
+
## Storage Rules
|
|
25
|
+
|
|
26
|
+
- Skill content must stay in standard Agent Skills directories.
|
|
27
|
+
- User-installed skills go under `~/.agents/skills`.
|
|
28
|
+
- Project skills go under `.agents/skills`.
|
|
29
|
+
- Deepy market installation records live under `~/.deepy/skill-market/`.
|
|
30
|
+
- Do not put market lock files inside a skill directory.
|
|
31
|
+
|
|
32
|
+
## Safety
|
|
33
|
+
|
|
34
|
+
Before uninstalling or updating a market-installed skill, compare the current skill content hash with Deepy's install record. If the user modified the skill locally, report the modification and do not overwrite or delete it by default.
|
|
@@ -10,6 +10,11 @@ SearXNG instances with limiter enabled are less likely to reject the request as
|
|
|
10
10
|
bot traffic. If SearXNG cannot be reached or returns no parseable results, falls
|
|
11
11
|
back to Deepy's built-in DuckDuckGo HTML search implementation.
|
|
12
12
|
|
|
13
|
+
If MCP web-search tools are listed in the system prompt, prefer those MCP tools
|
|
14
|
+
first for web/current-information searches. Use this built-in WebSearch as the
|
|
15
|
+
fallback when MCP search is unavailable, fails, or the user explicitly asks for
|
|
16
|
+
Deepy's built-in search.
|
|
17
|
+
|
|
13
18
|
Keep searches targeted. After several successful searches, stop searching and
|
|
14
19
|
synthesize from the gathered sources. Use `WebFetch` for exact URLs that need
|
|
15
20
|
deeper reading instead of continuing broad search queries.
|
|
@@ -18,14 +18,26 @@ def build_deepy_agent(
|
|
|
18
18
|
project_root: Path,
|
|
19
19
|
provider: ProviderBundle | None = None,
|
|
20
20
|
loaded_skills: list[SkillInfo] | None = None,
|
|
21
|
+
mcp_servers: list[object] | None = None,
|
|
22
|
+
preferred_mcp_web_search_tools: list[str] | None = None,
|
|
21
23
|
):
|
|
22
24
|
from agents import Agent
|
|
23
25
|
|
|
24
26
|
provider = provider or build_provider_bundle(settings)
|
|
25
27
|
return Agent(
|
|
26
28
|
name="Deepy",
|
|
27
|
-
instructions=build_system_prompt(
|
|
29
|
+
instructions=build_system_prompt(
|
|
30
|
+
project_root,
|
|
31
|
+
settings,
|
|
32
|
+
loaded_skills=loaded_skills,
|
|
33
|
+
preferred_mcp_web_search_tools=preferred_mcp_web_search_tools,
|
|
34
|
+
),
|
|
28
35
|
model=provider.model,
|
|
29
36
|
model_settings=provider.model_settings,
|
|
30
|
-
tools=build_function_tools(
|
|
37
|
+
tools=build_function_tools(
|
|
38
|
+
runtime,
|
|
39
|
+
preferred_mcp_web_search_tools=preferred_mcp_web_search_tools,
|
|
40
|
+
),
|
|
41
|
+
mcp_servers=list(mcp_servers or []),
|
|
42
|
+
mcp_config={"include_server_in_tool_names": True},
|
|
31
43
|
)
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from typing import Any, Literal
|
|
5
5
|
|
|
6
|
+
from deepy.utils import json as json_utils
|
|
7
|
+
|
|
6
8
|
StreamKind = Literal[
|
|
7
9
|
"text_delta",
|
|
8
10
|
"reasoning_delta",
|
|
@@ -84,7 +86,7 @@ def normalize_stream_event(event: Any) -> DeepyStreamEvent | None:
|
|
|
84
86
|
return DeepyStreamEvent(
|
|
85
87
|
kind="tool_output",
|
|
86
88
|
name=_tool_name(item),
|
|
87
|
-
text=
|
|
89
|
+
text=_tool_output_text(output),
|
|
88
90
|
payload={"call_id": _call_id(item)},
|
|
89
91
|
)
|
|
90
92
|
if name == "message_output_created":
|
|
@@ -159,6 +161,14 @@ def _tool_arguments(item: Any) -> str:
|
|
|
159
161
|
return value if isinstance(value, str) else ""
|
|
160
162
|
|
|
161
163
|
|
|
164
|
+
def _tool_output_text(output: Any) -> str:
|
|
165
|
+
if isinstance(output, str):
|
|
166
|
+
return output
|
|
167
|
+
if output is None:
|
|
168
|
+
return ""
|
|
169
|
+
return json_utils.dumps(output)
|
|
170
|
+
|
|
171
|
+
|
|
162
172
|
def _call_id(item: Any) -> str:
|
|
163
173
|
if item is None:
|
|
164
174
|
return ""
|