kimi-cli 0.41__tar.gz → 0.51__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.

Potentially problematic release.


This version of kimi-cli might be problematic. Click here for more details.

Files changed (105) hide show
  1. {kimi_cli-0.41 → kimi_cli-0.51}/PKG-INFO +22 -20
  2. {kimi_cli-0.41 → kimi_cli-0.51}/README.md +3 -2
  3. {kimi_cli-0.41 → kimi_cli-0.51}/pyproject.toml +22 -21
  4. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/CHANGELOG.md +102 -0
  5. {kimi_cli-0.41/src/kimi_cli/agents/koder → kimi_cli-0.51/src/kimi_cli/agents/default}/agent.yaml +1 -1
  6. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/agentspec.py +19 -8
  7. kimi_cli-0.51/src/kimi_cli/app.py +208 -0
  8. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/cli.py +71 -41
  9. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/config.py +33 -16
  10. kimi_cli-0.51/src/kimi_cli/exception.py +16 -0
  11. kimi_cli-0.51/src/kimi_cli/llm.py +149 -0
  12. kimi_cli-0.51/src/kimi_cli/metadata.py +54 -0
  13. kimi_cli-0.51/src/kimi_cli/session.py +81 -0
  14. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/__init__.py +34 -9
  15. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/agent.py +28 -26
  16. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/context.py +0 -5
  17. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/kimisoul.py +70 -27
  18. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/message.py +1 -1
  19. kimi_cli-0.41/src/kimi_cli/soul/globals.py → kimi_cli-0.51/src/kimi_cli/soul/runtime.py +17 -13
  20. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/toolset.py +2 -1
  21. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/__init__.py +34 -30
  22. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/bash/__init__.py +15 -6
  23. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/dmail/__init__.py +5 -4
  24. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/glob.py +3 -3
  25. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/grep.py +34 -18
  26. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/patch.py +41 -11
  27. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/read.py +6 -5
  28. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/replace.py +5 -5
  29. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/write.py +5 -5
  30. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/mcp.py +6 -3
  31. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/task/__init__.py +42 -24
  32. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/todo/__init__.py +4 -2
  33. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/search.py +9 -8
  34. kimi_cli-0.51/src/kimi_cli/ui/__init__.py +0 -0
  35. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/acp/__init__.py +60 -30
  36. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/print/__init__.py +28 -34
  37. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/__init__.py +78 -43
  38. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/keyboard.py +82 -14
  39. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/metacmd.py +8 -13
  40. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/prompt.py +216 -24
  41. kimi_cli-0.51/src/kimi_cli/ui/shell/replay.py +104 -0
  42. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/setup.py +11 -9
  43. kimi_cli-0.51/src/kimi_cli/ui/shell/visualize.py +576 -0
  44. kimi_cli-0.51/src/kimi_cli/ui/wire/README.md +109 -0
  45. kimi_cli-0.51/src/kimi_cli/ui/wire/__init__.py +340 -0
  46. kimi_cli-0.51/src/kimi_cli/ui/wire/jsonrpc.py +48 -0
  47. kimi_cli-0.51/src/kimi_cli/utils/__init__.py +0 -0
  48. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/changelog.py +3 -1
  49. kimi_cli-0.51/src/kimi_cli/utils/clipboard.py +10 -0
  50. kimi_cli-0.51/src/kimi_cli/utils/message.py +22 -0
  51. kimi_cli-0.51/src/kimi_cli/utils/rich/__init__.py +33 -0
  52. kimi_cli-0.51/src/kimi_cli/utils/rich/markdown.py +882 -0
  53. kimi_cli-0.51/src/kimi_cli/utils/rich/markdown_sample.md +108 -0
  54. kimi_cli-0.51/src/kimi_cli/utils/rich/markdown_sample_short.md +2 -0
  55. kimi_cli-0.51/src/kimi_cli/utils/signals.py +41 -0
  56. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/string.py +8 -0
  57. kimi_cli-0.51/src/kimi_cli/utils/term.py +114 -0
  58. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/wire/__init__.py +17 -1
  59. kimi_cli-0.51/src/kimi_cli/wire/message.py +191 -0
  60. kimi_cli-0.41/src/kimi_cli/__init__.py +0 -125
  61. kimi_cli-0.41/src/kimi_cli/agents/koder/README.md +0 -3
  62. kimi_cli-0.41/src/kimi_cli/llm.py +0 -77
  63. kimi_cli-0.41/src/kimi_cli/metadata.py +0 -117
  64. kimi_cli-0.41/src/kimi_cli/ui/shell/liveview.py +0 -386
  65. kimi_cli-0.41/src/kimi_cli/ui/shell/visualize.py +0 -114
  66. kimi_cli-0.41/src/kimi_cli/utils/message.py +0 -8
  67. kimi_cli-0.41/src/kimi_cli/wire/message.py +0 -91
  68. {kimi_cli-0.41/src/kimi_cli/ui → kimi_cli-0.51/src/kimi_cli}/__init__.py +0 -0
  69. {kimi_cli-0.41/src/kimi_cli/agents/koder → kimi_cli-0.51/src/kimi_cli/agents/default}/sub.yaml +0 -0
  70. {kimi_cli-0.41/src/kimi_cli/agents/koder → kimi_cli-0.51/src/kimi_cli/agents/default}/system.md +0 -0
  71. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/constant.py +0 -0
  72. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/prompts/__init__.py +0 -0
  73. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/prompts/compact.md +0 -0
  74. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/prompts/init.md +0 -0
  75. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/py.typed +0 -0
  76. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/share.py +0 -0
  77. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/approval.py +0 -0
  78. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/compaction.py +0 -0
  79. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/denwarenji.py +0 -0
  80. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/bash/bash.md +0 -0
  81. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/dmail/dmail.md +0 -0
  82. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/__init__.py +0 -0
  83. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/glob.md +0 -0
  84. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/grep.md +0 -0
  85. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/patch.md +0 -0
  86. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/read.md +0 -0
  87. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/replace.md +0 -0
  88. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/write.md +0 -0
  89. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/task/task.md +0 -0
  90. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/test.py +0 -0
  91. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/think/__init__.py +0 -0
  92. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/think/think.md +0 -0
  93. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/todo/set_todo_list.md +0 -0
  94. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/utils.py +0 -0
  95. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/__init__.py +0 -0
  96. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/fetch.md +0 -0
  97. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/fetch.py +0 -0
  98. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/search.md +0 -0
  99. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/console.py +0 -0
  100. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/debug.py +0 -0
  101. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/update.py +0 -0
  102. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/aiohttp.py +0 -0
  103. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/logging.py +0 -0
  104. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/path.py +0 -0
  105. {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/pyinstaller.py +0 -0
@@ -1,24 +1,25 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: kimi-cli
3
- Version: 0.41
3
+ Version: 0.51
4
4
  Summary: Kimi CLI is your next CLI agent.
5
- Requires-Dist: agent-client-protocol>=0.4.9
6
- Requires-Dist: aiofiles>=25.1.0
7
- Requires-Dist: aiohttp>=3.13.1
8
- Requires-Dist: click>=8.3.0
9
- Requires-Dist: kosong>=0.15.0
10
- Requires-Dist: loguru>=0.7.3
11
- Requires-Dist: patch-ng>=1.19.0
12
- Requires-Dist: prompt-toolkit>=3.0.52
13
- Requires-Dist: pyyaml>=6.0.3
14
- Requires-Dist: rich>=14.2.0
15
- Requires-Dist: ripgrepy>=2.2.0
16
- Requires-Dist: streamingjson>=0.0.5
17
- Requires-Dist: trafilatura>=2.0.0
18
- Requires-Dist: tenacity>=9.1.2
19
- Requires-Dist: fastmcp>=2.12.5
20
- Requires-Dist: pydantic>=2.12.3
21
- Requires-Dist: httpx[socks]>=0.28.0
5
+ Requires-Dist: agent-client-protocol==0.6.3
6
+ Requires-Dist: aiofiles==25.1.0
7
+ Requires-Dist: aiohttp==3.13.2
8
+ Requires-Dist: click==8.3.0
9
+ Requires-Dist: kosong==0.19.0
10
+ Requires-Dist: loguru==0.7.3
11
+ Requires-Dist: patch-ng==1.19.0
12
+ Requires-Dist: prompt-toolkit==3.0.52
13
+ Requires-Dist: pillow==12.0.0
14
+ Requires-Dist: pyyaml==6.0.3
15
+ Requires-Dist: rich==14.2.0
16
+ Requires-Dist: ripgrepy==2.2.0
17
+ Requires-Dist: streamingjson==0.0.5
18
+ Requires-Dist: trafilatura==2.0.0
19
+ Requires-Dist: tenacity==9.1.2
20
+ Requires-Dist: fastmcp==2.12.5
21
+ Requires-Dist: pydantic==2.12.4
22
+ Requires-Dist: httpx[socks]==0.28.1
22
23
  Requires-Python: >=3.13
23
24
  Description-Content-Type: text/markdown
24
25
 
@@ -28,6 +29,7 @@ Description-Content-Type: text/markdown
28
29
  [![Checks](https://img.shields.io/github/check-runs/MoonshotAI/kimi-cli/main)](https://github.com/MoonshotAI/kimi-cli/actions)
29
30
  [![Version](https://img.shields.io/pypi/v/kimi-cli)](https://pypi.org/project/kimi-cli/)
30
31
  [![Downloads](https://img.shields.io/pypi/dw/kimi-cli)](https://pypistats.org/packages/kimi-cli)
32
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/MoonshotAI/kimi-cli)
31
33
 
32
34
  [中文](https://www.kimi.com/coding/docs/kimi-cli.html)
33
35
 
@@ -84,7 +86,7 @@ After setup, Kimi CLI will be ready to use. You can send `/help` to get more inf
84
86
 
85
87
  ### Shell mode
86
88
 
87
- Kimi CLI is not only a coding agent, but also a shell. You can switch the mode by pressing `Ctrl-K`. In shell mode, you can directly run shell commands without leaving Kimi CLI.
89
+ Kimi CLI is not only a coding agent, but also a shell. You can switch the mode by pressing `Ctrl-X`. In shell mode, you can directly run shell commands without leaving Kimi CLI.
88
90
 
89
91
  > [!NOTE]
90
92
  > Built-in shell commands like `cd` are not supported yet.
@@ -109,7 +111,7 @@ Then add `kimi-cli` to your Zsh plugin list in `~/.zshrc`:
109
111
  plugins=(... kimi-cli)
110
112
  ```
111
113
 
112
- After restarting Zsh, you can switch to agent mode by pressing `Ctrl-K`.
114
+ After restarting Zsh, you can switch to agent mode by pressing `Ctrl-X`.
113
115
 
114
116
  ### ACP support
115
117
 
@@ -4,6 +4,7 @@
4
4
  [![Checks](https://img.shields.io/github/check-runs/MoonshotAI/kimi-cli/main)](https://github.com/MoonshotAI/kimi-cli/actions)
5
5
  [![Version](https://img.shields.io/pypi/v/kimi-cli)](https://pypi.org/project/kimi-cli/)
6
6
  [![Downloads](https://img.shields.io/pypi/dw/kimi-cli)](https://pypistats.org/packages/kimi-cli)
7
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/MoonshotAI/kimi-cli)
7
8
 
8
9
  [中文](https://www.kimi.com/coding/docs/kimi-cli.html)
9
10
 
@@ -60,7 +61,7 @@ After setup, Kimi CLI will be ready to use. You can send `/help` to get more inf
60
61
 
61
62
  ### Shell mode
62
63
 
63
- Kimi CLI is not only a coding agent, but also a shell. You can switch the mode by pressing `Ctrl-K`. In shell mode, you can directly run shell commands without leaving Kimi CLI.
64
+ Kimi CLI is not only a coding agent, but also a shell. You can switch the mode by pressing `Ctrl-X`. In shell mode, you can directly run shell commands without leaving Kimi CLI.
64
65
 
65
66
  > [!NOTE]
66
67
  > Built-in shell commands like `cd` are not supported yet.
@@ -85,7 +86,7 @@ Then add `kimi-cli` to your Zsh plugin list in `~/.zshrc`:
85
86
  plugins=(... kimi-cli)
86
87
  ```
87
88
 
88
- After restarting Zsh, you can switch to agent mode by pressing `Ctrl-K`.
89
+ After restarting Zsh, you can switch to agent mode by pressing `Ctrl-X`.
89
90
 
90
91
  ### ACP support
91
92
 
@@ -1,37 +1,38 @@
1
1
  [project]
2
2
  name = "kimi-cli"
3
- version = "0.41"
3
+ version = "0.51"
4
4
  description = "Kimi CLI is your next CLI agent."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
7
7
  dependencies = [
8
- "agent-client-protocol>=0.4.9",
9
- "aiofiles>=25.1.0",
10
- "aiohttp>=3.13.1",
11
- "click>=8.3.0",
12
- "kosong>=0.15.0",
13
- "loguru>=0.7.3",
14
- "patch-ng>=1.19.0",
15
- "prompt-toolkit>=3.0.52",
16
- "pyyaml>=6.0.3",
17
- "rich>=14.2.0",
18
- "ripgrepy>=2.2.0",
19
- "streamingjson>=0.0.5",
20
- "trafilatura>=2.0.0",
21
- "tenacity>=9.1.2",
22
- "fastmcp>=2.12.5",
23
- "pydantic>=2.12.3",
24
- "httpx[socks]>=0.28.0",
8
+ "agent-client-protocol==0.6.3",
9
+ "aiofiles==25.1.0",
10
+ "aiohttp==3.13.2",
11
+ "click==8.3.0",
12
+ "kosong==0.19.0",
13
+ "loguru==0.7.3",
14
+ "patch-ng==1.19.0",
15
+ "prompt-toolkit==3.0.52",
16
+ "pillow==12.0.0",
17
+ "pyyaml==6.0.3",
18
+ "rich==14.2.0",
19
+ "ripgrepy==2.2.0",
20
+ "streamingjson==0.0.5",
21
+ "trafilatura==2.0.0",
22
+ "tenacity==9.1.2",
23
+ "fastmcp==2.12.5",
24
+ "pydantic==2.12.4",
25
+ "httpx[socks]==0.28.1",
25
26
  ]
26
27
 
27
28
  [dependency-groups]
28
29
  dev = [
29
- "inline-snapshot[black]>=0.30.1",
30
+ "inline-snapshot[black]>=0.31.1",
30
31
  "pyinstaller>=6.16.0",
31
- "pyright>=1.1.406",
32
+ "pyright>=1.1.407",
32
33
  "pytest>=8.4.2",
33
34
  "pytest-asyncio>=1.2.0",
34
- "ruff>=0.14.1",
35
+ "ruff>=0.14.4",
35
36
  ]
36
37
 
37
38
  [build-system]
@@ -9,6 +9,108 @@ Internal builds may append content to the Unreleased section.
9
9
  Only write entries that are worth mentioning to users.
10
10
  -->
11
11
 
12
+ ## [0.51] - 2025-11-8
13
+
14
+ - Lib: Rename `Soul.model` to `Soul.model_name`
15
+ - Lib: Rename `LLMModelCapability` to `ModelCapability` and move to `kimi_cli.llm`
16
+ - Lib: Add `"thinking"` to `ModelCapability`
17
+ - Lib: Remove `LLM.supports_image_in` property
18
+ - Lib: Add required `Soul.model_capabilities` property
19
+ - Lib: Add `thinking: bool` parameter to `ShellApp.run` method
20
+ - Lib: Rename `KimiSoul.set_thinking_mode` to `KimiSoul.set_thinking`
21
+ - UI: Better checks and notices for LLM model capabilities
22
+ - UI: Clear the screen for `/clear` meta command
23
+ - Tool: Support auto-downloading ripgrep on Windows
24
+ - CLI: Add `--thinking` option to start in thinking mode
25
+ - ACP: Support thinking content in ACP mode
26
+
27
+ ## [0.50] - 2025-11-07
28
+
29
+ ### Changed
30
+
31
+ - Improve UI look and feel
32
+ - Improve Task tool observability
33
+
34
+ ## [0.49] - 2025-11-06
35
+
36
+ ### Fixed
37
+
38
+ - Minor UX improvements
39
+
40
+ ## [0.48] - 2025-11-06
41
+
42
+ ### Added
43
+
44
+ - Support Kimi K2 thinking mode
45
+
46
+ ## [0.47] - 2025-11-05
47
+
48
+ ### Fixed
49
+
50
+ - Fix Ctrl-W not working in some environments
51
+ - Do not load SearchWeb tool when the search service is not configured
52
+
53
+ ## [0.46] - 2025-11-03
54
+
55
+ ### Added
56
+
57
+ - Introduce Wire over stdio for local IPC (experimental, subject to change)
58
+ - Support Anthropic provider type
59
+
60
+ ### Fixed
61
+
62
+ - Fix binary packed by PyInstaller not working due to wrong entrypoint
63
+
64
+ ## [0.45] - 2025-10-31
65
+
66
+ ### Added
67
+
68
+ - Allow `KIMI_MODEL_CAPABILITIES` environment variable to override model capabilities
69
+ - Add `--no-markdown` option to disable markdown rendering
70
+ - Support `openai_responses` LLM provider type
71
+
72
+ ### Fixed
73
+
74
+ - Fix crash when continuing a session
75
+
76
+ ## [0.44] - 2025-10-30
77
+
78
+ ### Changed
79
+
80
+ - Improve startup time
81
+
82
+ ### Fixed
83
+
84
+ - Fix potential invalid bytes in user input
85
+
86
+ ## [0.43] - 2025-10-30
87
+
88
+ ### Added
89
+
90
+ - Basic Windows support (experimental)
91
+ - Display warnings when base URL or API key is overridden in environment variables
92
+ - Support image input if the LLM model supports it
93
+ - Replay recent context history when continuing a session
94
+
95
+ ### Fixed
96
+
97
+ - Ensure new line after executing shell commands
98
+
99
+ ## [0.42] - 2025-10-28
100
+
101
+ ### Added
102
+
103
+ - Support Ctrl-J or Alt-Enter to insert a new line
104
+
105
+ ### Changed
106
+
107
+ - Change mode switch shortcut from Ctrl-K to Ctrl-X
108
+ - Improve overall robustness
109
+
110
+ ### Fixed
111
+
112
+ - Fix ACP server `no attribute` error
113
+
12
114
  ## [0.41] - 2025-10-26
13
115
 
14
116
  ### Fixed
@@ -19,6 +19,6 @@ agent:
19
19
  - "kimi_cli.tools.web:SearchWeb"
20
20
  - "kimi_cli.tools.web:FetchURL"
21
21
  subagents:
22
- koder:
22
+ coder:
23
23
  path: ./sub.yaml
24
24
  description: "Good at general software engineering tasks."
@@ -4,12 +4,14 @@ from typing import Any, NamedTuple
4
4
  import yaml
5
5
  from pydantic import BaseModel, Field
6
6
 
7
+ from kimi_cli.exception import AgentSpecError
8
+
7
9
 
8
10
  def get_agents_dir() -> Path:
9
11
  return Path(__file__).parent / "agents"
10
12
 
11
13
 
12
- DEFAULT_AGENT_FILE = get_agents_dir() / "koder" / "agent.yaml"
14
+ DEFAULT_AGENT_FILE = get_agents_dir() / "default" / "agent.yaml"
13
15
 
14
16
 
15
17
  class AgentSpec(BaseModel):
@@ -47,15 +49,21 @@ class ResolvedAgentSpec(NamedTuple):
47
49
 
48
50
 
49
51
  def load_agent_spec(agent_file: Path) -> ResolvedAgentSpec:
50
- """Load agent specification from file."""
52
+ """
53
+ Load agent specification from file.
54
+
55
+ Raises:
56
+ FileNotFoundError: If the agent spec file is not found.
57
+ AgentSpecError: If the agent spec is not valid.
58
+ """
51
59
  agent_spec = _load_agent_spec(agent_file)
52
60
  assert agent_spec.extend is None, "agent extension should be recursively resolved"
53
61
  if agent_spec.name is None:
54
- raise ValueError("Agent name is required")
62
+ raise AgentSpecError("Agent name is required")
55
63
  if agent_spec.system_prompt_path is None:
56
- raise ValueError("System prompt path is required")
64
+ raise AgentSpecError("System prompt path is required")
57
65
  if agent_spec.tools is None:
58
- raise ValueError("Tools are required")
66
+ raise AgentSpecError("Tools are required")
59
67
  return ResolvedAgentSpec(
60
68
  name=agent_spec.name,
61
69
  system_prompt_path=agent_spec.system_prompt_path,
@@ -68,12 +76,15 @@ def load_agent_spec(agent_file: Path) -> ResolvedAgentSpec:
68
76
 
69
77
  def _load_agent_spec(agent_file: Path) -> AgentSpec:
70
78
  assert agent_file.is_file(), "expect agent file to exist"
71
- with open(agent_file, encoding="utf-8") as f:
72
- data: dict[str, Any] = yaml.safe_load(f)
79
+ try:
80
+ with open(agent_file, encoding="utf-8") as f:
81
+ data: dict[str, Any] = yaml.safe_load(f)
82
+ except yaml.YAMLError as e:
83
+ raise AgentSpecError(f"Invalid YAML in agent spec file: {e}") from e
73
84
 
74
85
  version = data.get("version", 1)
75
86
  if version != 1:
76
- raise ValueError(f"Unsupported agent spec version: {version}")
87
+ raise AgentSpecError(f"Unsupported agent spec version: {version}")
77
88
 
78
89
  agent_spec = AgentSpec(**data.get("agent", {}))
79
90
  if agent_spec.system_prompt_path is not None:
@@ -0,0 +1,208 @@
1
+ import contextlib
2
+ import os
3
+ import warnings
4
+ from collections.abc import Generator
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from pydantic import SecretStr
9
+
10
+ from kimi_cli.agentspec import DEFAULT_AGENT_FILE
11
+ from kimi_cli.cli import InputFormat, OutputFormat
12
+ from kimi_cli.config import LLMModel, LLMProvider, load_config
13
+ from kimi_cli.llm import augment_provider_with_env_vars, create_llm
14
+ from kimi_cli.session import Session
15
+ from kimi_cli.soul import LLMNotSet, LLMNotSupported
16
+ from kimi_cli.soul.agent import load_agent
17
+ from kimi_cli.soul.context import Context
18
+ from kimi_cli.soul.kimisoul import KimiSoul
19
+ from kimi_cli.soul.runtime import Runtime
20
+ from kimi_cli.utils.logging import StreamToLogger, logger
21
+
22
+
23
+ class KimiCLI:
24
+ @staticmethod
25
+ async def create(
26
+ session: Session,
27
+ *,
28
+ yolo: bool = False,
29
+ stream: bool = True, # TODO: remove this when we have a correct print mode impl
30
+ mcp_configs: list[dict[str, Any]] | None = None,
31
+ config_file: Path | None = None,
32
+ model_name: str | None = None,
33
+ thinking: bool = False,
34
+ agent_file: Path | None = None,
35
+ ) -> "KimiCLI":
36
+ """
37
+ Create a KimiCLI instance.
38
+
39
+ Args:
40
+ session (Session): A session created by `Session.create` or `Session.continue_`.
41
+ yolo (bool, optional): Approve all actions without confirmation. Defaults to False.
42
+ stream (bool, optional): Use stream mode when calling LLM API. Defaults to True.
43
+ config_file (Path | None, optional): Path to the configuration file. Defaults to None.
44
+ model_name (str | None, optional): Name of the model to use. Defaults to None.
45
+ agent_file (Path | None, optional): Path to the agent file. Defaults to None.
46
+
47
+ Raises:
48
+ FileNotFoundError: When the agent file is not found.
49
+ ConfigError(KimiCLIException): When the configuration is invalid.
50
+ AgentSpecError(KimiCLIException): When the agent specification is invalid.
51
+ """
52
+ config = load_config(config_file)
53
+ logger.info("Loaded config: {config}", config=config)
54
+
55
+ model: LLMModel | None = None
56
+ provider: LLMProvider | None = None
57
+
58
+ # try to use config file
59
+ if not model_name and config.default_model:
60
+ # no --model specified && default model is set in config
61
+ model = config.models[config.default_model]
62
+ provider = config.providers[model.provider]
63
+ if model_name and model_name in config.models:
64
+ # --model specified && model is set in config
65
+ model = config.models[model_name]
66
+ provider = config.providers[model.provider]
67
+
68
+ if not model:
69
+ model = LLMModel(provider="", model="", max_context_size=100_000)
70
+ provider = LLMProvider(type="kimi", base_url="", api_key=SecretStr(""))
71
+
72
+ # try overwrite with environment variables
73
+ assert provider is not None
74
+ assert model is not None
75
+ env_overrides = augment_provider_with_env_vars(provider, model)
76
+
77
+ if not provider.base_url or not model.model:
78
+ llm = None
79
+ else:
80
+ logger.info("Using LLM provider: {provider}", provider=provider)
81
+ logger.info("Using LLM model: {model}", model=model)
82
+ llm = create_llm(provider, model, stream=stream, session_id=session.id)
83
+
84
+ runtime = await Runtime.create(config, llm, session, yolo)
85
+
86
+ if agent_file is None:
87
+ agent_file = DEFAULT_AGENT_FILE
88
+ agent = await load_agent(agent_file, runtime, mcp_configs=mcp_configs or [])
89
+
90
+ context = Context(session.history_file)
91
+ await context.restore()
92
+
93
+ soul = KimiSoul(
94
+ agent,
95
+ runtime,
96
+ context=context,
97
+ )
98
+ try:
99
+ soul.set_thinking(thinking)
100
+ except (LLMNotSet, LLMNotSupported) as e:
101
+ logger.warning("Failed to enable thinking mode: {error}", error=e)
102
+ return KimiCLI(soul, runtime, env_overrides)
103
+
104
+ def __init__(
105
+ self,
106
+ _soul: KimiSoul,
107
+ _runtime: Runtime,
108
+ _env_overrides: dict[str, str],
109
+ ) -> None:
110
+ self._soul = _soul
111
+ self._runtime = _runtime
112
+ self._env_overrides = _env_overrides
113
+
114
+ @property
115
+ def soul(self) -> KimiSoul:
116
+ """Get the KimiSoul instance."""
117
+ return self._soul
118
+
119
+ @property
120
+ def session(self) -> Session:
121
+ """Get the Session instance."""
122
+ return self._runtime.session
123
+
124
+ @contextlib.contextmanager
125
+ def _app_env(self) -> Generator[None]:
126
+ original_cwd = Path.cwd()
127
+ os.chdir(self._runtime.session.work_dir)
128
+ try:
129
+ # to ignore possible warnings from dateparser
130
+ warnings.filterwarnings("ignore", category=DeprecationWarning)
131
+ with contextlib.redirect_stderr(StreamToLogger()):
132
+ yield
133
+ finally:
134
+ os.chdir(original_cwd)
135
+
136
+ async def run_shell_mode(self, command: str | None = None) -> bool:
137
+ from kimi_cli.ui.shell import ShellApp, WelcomeInfoItem
138
+
139
+ welcome_info = [
140
+ WelcomeInfoItem(name="Directory", value=str(self._runtime.session.work_dir)),
141
+ WelcomeInfoItem(name="Session", value=self._runtime.session.id),
142
+ ]
143
+ if base_url := self._env_overrides.get("KIMI_BASE_URL"):
144
+ welcome_info.append(
145
+ WelcomeInfoItem(
146
+ name="API URL",
147
+ value=f"{base_url} (from KIMI_BASE_URL)",
148
+ level=WelcomeInfoItem.Level.WARN,
149
+ )
150
+ )
151
+ if not self._runtime.llm:
152
+ welcome_info.append(
153
+ WelcomeInfoItem(
154
+ name="Model",
155
+ value="not set, send /setup to configure",
156
+ level=WelcomeInfoItem.Level.WARN,
157
+ )
158
+ )
159
+ elif "KIMI_MODEL_NAME" in self._env_overrides:
160
+ welcome_info.append(
161
+ WelcomeInfoItem(
162
+ name="Model",
163
+ value=f"{self._soul.model_name} (from KIMI_MODEL_NAME)",
164
+ level=WelcomeInfoItem.Level.WARN,
165
+ )
166
+ )
167
+ else:
168
+ welcome_info.append(
169
+ WelcomeInfoItem(
170
+ name="Model",
171
+ value=self._soul.model_name,
172
+ level=WelcomeInfoItem.Level.INFO,
173
+ )
174
+ )
175
+ with self._app_env():
176
+ app = ShellApp(self._soul, welcome_info=welcome_info)
177
+ return await app.run(command)
178
+
179
+ async def run_print_mode(
180
+ self,
181
+ input_format: InputFormat,
182
+ output_format: OutputFormat,
183
+ command: str | None = None,
184
+ ) -> bool:
185
+ from kimi_cli.ui.print import PrintApp
186
+
187
+ with self._app_env():
188
+ app = PrintApp(
189
+ self._soul,
190
+ input_format,
191
+ output_format,
192
+ self._runtime.session.history_file,
193
+ )
194
+ return await app.run(command)
195
+
196
+ async def run_acp_server(self) -> bool:
197
+ from kimi_cli.ui.acp import ACPServer
198
+
199
+ with self._app_env():
200
+ app = ACPServer(self._soul)
201
+ return await app.run()
202
+
203
+ async def run_wire_server(self) -> bool:
204
+ from kimi_cli.ui.wire import WireServer
205
+
206
+ with self._app_env():
207
+ server = WireServer(self._soul)
208
+ return await server.run()