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.
- {kimi_cli-0.41 → kimi_cli-0.51}/PKG-INFO +22 -20
- {kimi_cli-0.41 → kimi_cli-0.51}/README.md +3 -2
- {kimi_cli-0.41 → kimi_cli-0.51}/pyproject.toml +22 -21
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/CHANGELOG.md +102 -0
- {kimi_cli-0.41/src/kimi_cli/agents/koder → kimi_cli-0.51/src/kimi_cli/agents/default}/agent.yaml +1 -1
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/agentspec.py +19 -8
- kimi_cli-0.51/src/kimi_cli/app.py +208 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/cli.py +71 -41
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/config.py +33 -16
- kimi_cli-0.51/src/kimi_cli/exception.py +16 -0
- kimi_cli-0.51/src/kimi_cli/llm.py +149 -0
- kimi_cli-0.51/src/kimi_cli/metadata.py +54 -0
- kimi_cli-0.51/src/kimi_cli/session.py +81 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/__init__.py +34 -9
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/agent.py +28 -26
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/context.py +0 -5
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/kimisoul.py +70 -27
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/message.py +1 -1
- kimi_cli-0.41/src/kimi_cli/soul/globals.py → kimi_cli-0.51/src/kimi_cli/soul/runtime.py +17 -13
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/toolset.py +2 -1
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/__init__.py +34 -30
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/bash/__init__.py +15 -6
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/dmail/__init__.py +5 -4
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/glob.py +3 -3
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/grep.py +34 -18
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/patch.py +41 -11
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/read.py +6 -5
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/replace.py +5 -5
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/write.py +5 -5
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/mcp.py +6 -3
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/task/__init__.py +42 -24
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/todo/__init__.py +4 -2
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/search.py +9 -8
- kimi_cli-0.51/src/kimi_cli/ui/__init__.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/acp/__init__.py +60 -30
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/print/__init__.py +28 -34
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/__init__.py +78 -43
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/keyboard.py +82 -14
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/metacmd.py +8 -13
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/prompt.py +216 -24
- kimi_cli-0.51/src/kimi_cli/ui/shell/replay.py +104 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/setup.py +11 -9
- kimi_cli-0.51/src/kimi_cli/ui/shell/visualize.py +576 -0
- kimi_cli-0.51/src/kimi_cli/ui/wire/README.md +109 -0
- kimi_cli-0.51/src/kimi_cli/ui/wire/__init__.py +340 -0
- kimi_cli-0.51/src/kimi_cli/ui/wire/jsonrpc.py +48 -0
- kimi_cli-0.51/src/kimi_cli/utils/__init__.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/changelog.py +3 -1
- kimi_cli-0.51/src/kimi_cli/utils/clipboard.py +10 -0
- kimi_cli-0.51/src/kimi_cli/utils/message.py +22 -0
- kimi_cli-0.51/src/kimi_cli/utils/rich/__init__.py +33 -0
- kimi_cli-0.51/src/kimi_cli/utils/rich/markdown.py +882 -0
- kimi_cli-0.51/src/kimi_cli/utils/rich/markdown_sample.md +108 -0
- kimi_cli-0.51/src/kimi_cli/utils/rich/markdown_sample_short.md +2 -0
- kimi_cli-0.51/src/kimi_cli/utils/signals.py +41 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/string.py +8 -0
- kimi_cli-0.51/src/kimi_cli/utils/term.py +114 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/wire/__init__.py +17 -1
- kimi_cli-0.51/src/kimi_cli/wire/message.py +191 -0
- kimi_cli-0.41/src/kimi_cli/__init__.py +0 -125
- kimi_cli-0.41/src/kimi_cli/agents/koder/README.md +0 -3
- kimi_cli-0.41/src/kimi_cli/llm.py +0 -77
- kimi_cli-0.41/src/kimi_cli/metadata.py +0 -117
- kimi_cli-0.41/src/kimi_cli/ui/shell/liveview.py +0 -386
- kimi_cli-0.41/src/kimi_cli/ui/shell/visualize.py +0 -114
- kimi_cli-0.41/src/kimi_cli/utils/message.py +0 -8
- kimi_cli-0.41/src/kimi_cli/wire/message.py +0 -91
- {kimi_cli-0.41/src/kimi_cli/ui → kimi_cli-0.51/src/kimi_cli}/__init__.py +0 -0
- {kimi_cli-0.41/src/kimi_cli/agents/koder → kimi_cli-0.51/src/kimi_cli/agents/default}/sub.yaml +0 -0
- {kimi_cli-0.41/src/kimi_cli/agents/koder → kimi_cli-0.51/src/kimi_cli/agents/default}/system.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/constant.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/prompts/__init__.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/prompts/compact.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/prompts/init.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/py.typed +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/share.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/approval.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/compaction.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/soul/denwarenji.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/bash/bash.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/dmail/dmail.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/__init__.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/glob.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/grep.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/patch.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/read.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/replace.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/file/write.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/task/task.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/test.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/think/__init__.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/think/think.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/todo/set_todo_list.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/utils.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/__init__.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/fetch.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/fetch.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/tools/web/search.md +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/console.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/debug.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/ui/shell/update.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/aiohttp.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/logging.py +0 -0
- {kimi_cli-0.41 → kimi_cli-0.51}/src/kimi_cli/utils/path.py +0 -0
- {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.
|
|
3
|
+
Version: 0.51
|
|
4
4
|
Summary: Kimi CLI is your next CLI agent.
|
|
5
|
-
Requires-Dist: agent-client-protocol
|
|
6
|
-
Requires-Dist: aiofiles
|
|
7
|
-
Requires-Dist: aiohttp
|
|
8
|
-
Requires-Dist: click
|
|
9
|
-
Requires-Dist: kosong
|
|
10
|
-
Requires-Dist: loguru
|
|
11
|
-
Requires-Dist: patch-ng
|
|
12
|
-
Requires-Dist: prompt-toolkit
|
|
13
|
-
Requires-Dist:
|
|
14
|
-
Requires-Dist:
|
|
15
|
-
Requires-Dist:
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist:
|
|
21
|
-
Requires-Dist:
|
|
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
|
[](https://github.com/MoonshotAI/kimi-cli/actions)
|
|
29
30
|
[](https://pypi.org/project/kimi-cli/)
|
|
30
31
|
[](https://pypistats.org/packages/kimi-cli)
|
|
32
|
+
[](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-
|
|
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-
|
|
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
|
[](https://github.com/MoonshotAI/kimi-cli/actions)
|
|
5
5
|
[](https://pypi.org/project/kimi-cli/)
|
|
6
6
|
[](https://pypistats.org/packages/kimi-cli)
|
|
7
|
+
[](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-
|
|
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-
|
|
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.
|
|
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
|
|
9
|
-
"aiofiles
|
|
10
|
-
"aiohttp
|
|
11
|
-
"click
|
|
12
|
-
"kosong
|
|
13
|
-
"loguru
|
|
14
|
-
"patch-ng
|
|
15
|
-
"prompt-toolkit
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
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
|
+
"inline-snapshot[black]>=0.31.1",
|
|
30
31
|
"pyinstaller>=6.16.0",
|
|
31
|
-
"pyright>=1.1.
|
|
32
|
+
"pyright>=1.1.407",
|
|
32
33
|
"pytest>=8.4.2",
|
|
33
34
|
"pytest-asyncio>=1.2.0",
|
|
34
|
-
"ruff>=0.14.
|
|
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
|
|
@@ -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() / "
|
|
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
|
-
"""
|
|
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
|
|
62
|
+
raise AgentSpecError("Agent name is required")
|
|
55
63
|
if agent_spec.system_prompt_path is None:
|
|
56
|
-
raise
|
|
64
|
+
raise AgentSpecError("System prompt path is required")
|
|
57
65
|
if agent_spec.tools is None:
|
|
58
|
-
raise
|
|
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
|
-
|
|
72
|
-
|
|
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
|
|
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()
|