kimi-cli 0.44__py3-none-any.whl → 0.45__py3-none-any.whl

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/CHANGELOG.md CHANGED
@@ -9,6 +9,18 @@ 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.45] - 2025-10-31
13
+
14
+ ### Added
15
+
16
+ - Allow `KIMI_MODEL_CAPABILITIES` environment variable to override model capabilities
17
+ - Add `--no-markdown` option to disable markdown rendering
18
+ - Support `openai_responses` LLM provider type
19
+
20
+ ### Fixed
21
+
22
+ - Fix crash when continuing a session
23
+
12
24
  ## [0.44] - 2025-10-30
13
25
 
14
26
  ### Changed
kimi_cli/app.py CHANGED
@@ -127,7 +127,7 @@ class KimiCLI:
127
127
  finally:
128
128
  os.chdir(original_cwd)
129
129
 
130
- async def run_shell_mode(self, command: str | None = None) -> bool:
130
+ async def run_shell_mode(self, command: str | None = None, markdown: bool = True) -> bool:
131
131
  from kimi_cli.ui.shell import ShellApp, WelcomeInfoItem
132
132
 
133
133
  welcome_info = [
@@ -167,7 +167,7 @@ class KimiCLI:
167
167
  )
168
168
  )
169
169
  with self._app_env():
170
- app = ShellApp(self._soul, welcome_info=welcome_info)
170
+ app = ShellApp(self._soul, welcome_info=welcome_info, markdown=markdown)
171
171
  return await app.run(command)
172
172
 
173
173
  async def run_print_mode(
kimi_cli/cli.py CHANGED
@@ -137,6 +137,12 @@ OutputFormat = Literal["text", "stream-json"]
137
137
  default=False,
138
138
  help="Automatically approve all actions. Default: no.",
139
139
  )
140
+ @click.option(
141
+ "--markdown/--no-markdown",
142
+ is_flag=True,
143
+ default=True,
144
+ help="Enable/disable markdown rendering in shell UI. Default: yes.",
145
+ )
140
146
  def kimi(
141
147
  verbose: bool,
142
148
  debug: bool,
@@ -151,6 +157,7 @@ def kimi(
151
157
  mcp_config_file: list[Path],
152
158
  mcp_config: list[str],
153
159
  yolo: bool,
160
+ markdown: bool,
154
161
  ):
155
162
  """Kimi, your next CLI agent."""
156
163
  from kimi_cli.app import KimiCLI
@@ -220,7 +227,7 @@ def kimi(
220
227
  )
221
228
  match ui:
222
229
  case "shell":
223
- return await instance.run_shell_mode(command)
230
+ return await instance.run_shell_mode(command, markdown=markdown)
224
231
  case "print":
225
232
  return await instance.run_print_mode(
226
233
  input_format or "text",
kimi_cli/config.py CHANGED
@@ -12,7 +12,7 @@ from kimi_cli.utils.logging import logger
12
12
  class LLMProvider(BaseModel):
13
13
  """LLM provider configuration."""
14
14
 
15
- type: Literal["kimi", "openai_legacy", "_chaos"]
15
+ type: Literal["kimi", "openai_legacy", "openai_responses", "_chaos"]
16
16
  """Provider type"""
17
17
  base_url: str
18
18
  """API base URL"""
kimi_cli/llm.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import os
2
- from typing import NamedTuple
2
+ from typing import NamedTuple, cast, get_args
3
3
 
4
4
  from kosong.base.chat_provider import ChatProvider
5
5
  from pydantic import SecretStr
@@ -41,11 +41,19 @@ def augment_provider_with_env_vars(provider: LLMProvider, model: LLMModel) -> di
41
41
  applied["KIMI_API_KEY"] = "******"
42
42
  if model_name := os.getenv("KIMI_MODEL_NAME"):
43
43
  model.model = model_name
44
- applied["KIMI_MODEL_NAME"] = model.model
44
+ applied["KIMI_MODEL_NAME"] = model_name
45
45
  if max_context_size := os.getenv("KIMI_MODEL_MAX_CONTEXT_SIZE"):
46
46
  model.max_context_size = int(max_context_size)
47
- applied["KIMI_MODEL_MAX_CONTEXT_SIZE"] = str(model.max_context_size)
48
- case "openai_legacy":
47
+ applied["KIMI_MODEL_MAX_CONTEXT_SIZE"] = max_context_size
48
+ if capabilities := os.getenv("KIMI_MODEL_CAPABILITIES"):
49
+ caps_lower = (cap.strip().lower() for cap in capabilities.split(",") if cap.strip())
50
+ model.capabilities = set(
51
+ cast(LLMModelCapability, cap)
52
+ for cap in caps_lower
53
+ if cap in get_args(LLMModelCapability)
54
+ )
55
+ applied["KIMI_MODEL_CAPABILITIES"] = capabilities
56
+ case "openai_legacy" | "openai_responses":
49
57
  if base_url := os.getenv("OPENAI_BASE_URL"):
50
58
  provider.base_url = base_url
51
59
  if api_key := os.getenv("OPENAI_API_KEY"):
@@ -88,6 +96,15 @@ def create_llm(
88
96
  api_key=provider.api_key.get_secret_value(),
89
97
  stream=stream,
90
98
  )
99
+ case "openai_responses":
100
+ from kosong.chat_provider.openai_responses import OpenAIResponses
101
+
102
+ chat_provider = OpenAIResponses(
103
+ model=model.model,
104
+ base_url=provider.base_url,
105
+ api_key=provider.api_key.get_secret_value(),
106
+ stream=stream,
107
+ )
91
108
  case "_chaos":
92
109
  from kosong.chat_provider.chaos import ChaosChatProvider, ChaosConfig
93
110
 
@@ -24,10 +24,16 @@ from kimi_cli.utils.signals import install_sigint_handler
24
24
 
25
25
 
26
26
  class ShellApp:
27
- def __init__(self, soul: Soul, welcome_info: list["WelcomeInfoItem"] | None = None):
27
+ def __init__(
28
+ self,
29
+ soul: Soul,
30
+ welcome_info: list["WelcomeInfoItem"] | None = None,
31
+ markdown: bool = True,
32
+ ):
28
33
  self.soul = soul
29
34
  self._welcome_info = list(welcome_info or [])
30
35
  self._background_tasks: set[asyncio.Task[Any]] = set()
36
+ self._markdown = markdown
31
37
 
32
38
  async def run(self, command: str | None = None) -> bool:
33
39
  if command is not None:
@@ -168,7 +174,10 @@ class ShellApp:
168
174
  self.soul,
169
175
  user_input,
170
176
  lambda wire: visualize(
171
- wire, initial_status=self.soul.status, cancel_event=cancel_event
177
+ wire,
178
+ initial_status=self.soul.status,
179
+ cancel_event=cancel_event,
180
+ markdown=self._markdown,
172
181
  ),
173
182
  cancel_event,
174
183
  )
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  from collections import deque
3
+ from typing import Literal
3
4
 
4
5
  import streamingjson
5
6
  from kosong.base.message import ToolCall, ToolCallPart
@@ -129,6 +130,7 @@ class StepLiveView:
129
130
  def __init__(self, status: StatusSnapshot, cancel_event: asyncio.Event | None = None):
130
131
  # message content
131
132
  self._line_buffer = Text("")
133
+ self._last_text_mode: Literal["text", "think", ""] = ""
132
134
 
133
135
  # tool call
134
136
  self._tool_calls: dict[str, _ToolCallDisplay] = {}
@@ -187,7 +189,21 @@ class StepLiveView:
187
189
  """
188
190
  console.print(renderable)
189
191
 
190
- def append_text(self, text: str):
192
+ def append_text(self, text: str, mode: Literal["text", "think"] = "text"):
193
+ if not text:
194
+ # Ignore empty message
195
+ return
196
+ if self._last_text_mode != mode:
197
+ if self._line_buffer:
198
+ self._push_out(self._line_buffer)
199
+ self._push_out("") # Add extra line between different modes
200
+ self._line_buffer.plain = ""
201
+ self._last_text_mode = mode
202
+ match mode:
203
+ case "text":
204
+ self._line_buffer.style = ""
205
+ case "think":
206
+ self._line_buffer.style = "grey50 italic"
191
207
  lines = text.split("\n")
192
208
  prev_is_empty = not self._line_buffer
193
209
  for line in lines[:-1]:
@@ -313,7 +329,14 @@ class StepLiveViewWithMarkdown(StepLiveView):
313
329
  self._buffer_status_active = False
314
330
  self._buffer_status_obj: Status | None = None
315
331
 
316
- def append_text(self, text: str):
332
+ def append_text(self, text: str, mode: Literal["text", "think"] = "text"):
333
+ if not text:
334
+ # Ignore empty message
335
+ return
336
+ if self._last_text_mode != mode:
337
+ if self._flush_markdown():
338
+ self._push_out("") # Add extra line between different modes
339
+ self._last_text_mode = mode
317
340
  if not self._pending_markdown_parts:
318
341
  self._show_thinking_status()
319
342
  self._pending_markdown_parts.append(text)
@@ -334,14 +357,22 @@ class StepLiveViewWithMarkdown(StepLiveView):
334
357
  self._flush_markdown()
335
358
  return super().__exit__(exc_type, exc_value, traceback)
336
359
 
337
- def _flush_markdown(self):
360
+ def _flush_markdown(self) -> bool:
338
361
  self._hide_thinking_status()
339
362
  if not self._pending_markdown_parts:
340
- return
363
+ return False
341
364
  markdown_text = "".join(self._pending_markdown_parts)
342
365
  self._pending_markdown_parts.clear()
343
366
  if markdown_text.strip():
344
- self._push_out(_LeftAlignedMarkdown(markdown_text, justify="left"))
367
+ self._push_out(
368
+ _LeftAlignedMarkdown(
369
+ markdown_text,
370
+ justify="left",
371
+ style="grey50 italic" if self._last_text_mode == "think" else "none",
372
+ )
373
+ )
374
+ return True
375
+ return False
345
376
 
346
377
  def _show_thinking_status(self):
347
378
  if self._buffer_status_active:
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  from contextlib import asynccontextmanager, suppress
3
3
 
4
- from kosong.base.message import ContentPart, TextPart, ToolCall, ToolCallPart
4
+ from kosong.base.message import ContentPart, TextPart, ThinkPart, ToolCall, ToolCallPart
5
5
  from kosong.tooling import ToolResult
6
6
 
7
7
  from kimi_cli.soul import StatusSnapshot
@@ -42,6 +42,7 @@ async def visualize(
42
42
  *,
43
43
  initial_status: StatusSnapshot,
44
44
  cancel_event: asyncio.Event | None = None,
45
+ markdown: bool = True,
45
46
  ):
46
47
  """
47
48
  A loop to consume agent events and visualize the agent behavior.
@@ -60,7 +61,8 @@ async def visualize(
60
61
  while True:
61
62
  # TODO: Maybe we can always have a StepLiveView here.
62
63
  # No need to recreate for each step.
63
- with StepLiveViewWithMarkdown(latest_status, cancel_event) as step:
64
+ LiveView = StepLiveViewWithMarkdown if markdown else StepLiveView
65
+ with LiveView(latest_status, cancel_event) as step:
64
66
  async with _keyboard_listener(step):
65
67
  # spin the moon at the beginning of each step
66
68
  with console.status("", spinner="moon"):
@@ -78,7 +80,9 @@ async def visualize(
78
80
  while True:
79
81
  match msg:
80
82
  case TextPart(text=text):
81
- step.append_text(text)
83
+ step.append_text(text, mode="text")
84
+ case ThinkPart(think=think):
85
+ step.append_text(think, mode="think")
82
86
  case ContentPart():
83
87
  # TODO: support more content parts
84
88
  step.append_text(f"[{msg.__class__.__name__}]")
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: kimi-cli
3
- Version: 0.44
3
+ Version: 0.45
4
4
  Summary: Kimi CLI is your next CLI agent.
5
5
  Requires-Dist: agent-client-protocol==0.6.2
6
6
  Requires-Dist: aiofiles==25.1.0
7
7
  Requires-Dist: aiohttp==3.13.2
8
8
  Requires-Dist: click==8.3.0
9
- Requires-Dist: kosong==0.16.1
9
+ Requires-Dist: kosong==0.16.2
10
10
  Requires-Dist: loguru==0.7.3
11
11
  Requires-Dist: patch-ng==1.19.0
12
12
  Requires-Dist: prompt-toolkit==3.0.52
@@ -1,15 +1,15 @@
1
- kimi_cli/CHANGELOG.md,sha256=f3231982f148e227198bfab938f3878052366c02d80c3432e5ac48d3a9dbd234,8325
1
+ kimi_cli/CHANGELOG.md,sha256=0affdbd19f99b6dedb4cc2cac63eb2f9f942d8cfab44f01b445374764b572a10,8603
2
2
  kimi_cli/__init__.py,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
3
3
  kimi_cli/agents/default/agent.yaml,sha256=6e5c51987ef5cfc0c4c4e34cc20b6fc975953ee219623fccae81a19155aab7b3,709
4
4
  kimi_cli/agents/default/sub.yaml,sha256=e0c1ea34fdb04b0d6dc635709f0f130aff25d7f9fb97e238470143c8145be251,634
5
5
  kimi_cli/agents/default/system.md,sha256=1d8fd4956b2442215396b5e9651771c9da8f9505ccbd3b6d5e91b1ac4ff35418,5001
6
6
  kimi_cli/agentspec.py,sha256=1148b5184ca610b2fb261ce365a63eb2fc9d09497330fe0ea4b2567fc98d5657,4307
7
- kimi_cli/app.py,sha256=973684726d6c7bc0140f4c7940d1c3585899d828b5ab1c25b4e322c7fa6f7c35,7011
8
- kimi_cli/cli.py,sha256=3c73fea4dd930a1c80b97ea4b8a71cdf482208d3a0304a769bd59b4e95c1c664,6713
9
- kimi_cli/config.py,sha256=1bdd90554d33c45848d9ed9499a7914aecdf51e9166abe1b211d95aaa05a6382,4992
7
+ kimi_cli/app.py,sha256=34fde6911d3b4fa6ada013f5ae714cdf354be479da9adb26c6460de0a9ba10c3,7053
8
+ kimi_cli/cli.py,sha256=5731276d9c13e58962c39cdf9db3a57bd875a7a09d560c64498454df62b717a0,6910
9
+ kimi_cli/config.py,sha256=5524c2dd7d3d10e7965901253c754185a4e4b1d30937598ff2b321a070c760be,5012
10
10
  kimi_cli/constant.py,sha256=78e25b9304cca7b6f70bb08bf0e1fee4b066297a05386e56dd6935ba42027cd9,110
11
11
  kimi_cli/exception.py,sha256=a3fec07566da7d2d34be8cc454fb825f34109bbde3cddf69e1ece6ab21b4b219,259
12
- kimi_cli/llm.py,sha256=d53be2d6f75bd8c92304df9841a236671d7e53ac325eb87293a22fadf90d6a18,3628
12
+ kimi_cli/llm.py,sha256=fdb4f944d6ccec9fe5b8bc1f80bb283df629663659fcdbffe405af2f61f73733,4442
13
13
  kimi_cli/metadata.py,sha256=9e9d4bc12ff26fc34e0e09d9068be989f2ff3c8b682ef453de69e442f8f672a1,1557
14
14
  kimi_cli/prompts/__init__.py,sha256=6dc5ed2d841f145c09550075f30853cdc51f00d2f5d9aa1097f8edea770536e7,174
15
15
  kimi_cli/prompts/compact.md,sha256=6655bd7d8270b24d8f97b51ef7c471cf71d686c56f8ec9a5cc9e47caa3aae87c,1877
@@ -62,17 +62,17 @@ kimi_cli/tools/web/search.py,sha256=85de343b20bc9e58de8a09aba7c3aac619d6fc6d30a6
62
62
  kimi_cli/ui/__init__.py,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
63
63
  kimi_cli/ui/acp/__init__.py,sha256=a35e17273e943168882865f90d922180c5a1f01de0d128c899ffcfe55a9db3c3,17120
64
64
  kimi_cli/ui/print/__init__.py,sha256=ca402bec701a253acd6de5b57d59635ac0b05d4013cebc26877c5aa4aa2c27c7,5546
65
- kimi_cli/ui/shell/__init__.py,sha256=aa30b512004be5ad9c8b8ab420bbdb574532dc90968067682dab58ff19e8b660,11289
65
+ kimi_cli/ui/shell/__init__.py,sha256=c9644dbc27f899baea38aeee1b4b5ae3b82f84d0321f939477bd03f2ad7532b9,11471
66
66
  kimi_cli/ui/shell/console.py,sha256=bcbf7efd214cba3d2259f2a2c1842250cde96d49e4f9f1e0b60273cf1c366be3,842
67
67
  kimi_cli/ui/shell/debug.py,sha256=cd4e7259c83f099b5c6519713be5306580f30d3fa4944e07916d4468e960c9c7,5562
68
68
  kimi_cli/ui/shell/keyboard.py,sha256=23e5fbc4b6acda4c0f3b5297a0ae6eb09a90f4b5b37b2e95b7ce86a2da0d5dca,5160
69
- kimi_cli/ui/shell/liveview.py,sha256=f4e6ac37c446740b5c55cf37d5ebd327b5d41334d41d5e54ad8ad15445c1a492,14239
69
+ kimi_cli/ui/shell/liveview.py,sha256=2f780323dfc7d9b35491a17ccc2b4f6320176ae00c596b426ea7d7f513d3e42c,15478
70
70
  kimi_cli/ui/shell/metacmd.py,sha256=a0e52e9cbd8758c1ba13f025599341aa59dd5bc5e244840da2ff9bb71f952a20,7678
71
71
  kimi_cli/ui/shell/prompt.py,sha256=d18003de33da0c9711bf54496cb4d5f6f5aa6b2179b1618e4475b1f020208f6c,25808
72
72
  kimi_cli/ui/shell/replay.py,sha256=e54f58acebc46ad944e1a2cdf54d81559262d2cf8baf5da391ed903926f1ccf1,3767
73
73
  kimi_cli/ui/shell/setup.py,sha256=8fbf2935fc5b972d2c3946e8dc9f4a7e9d2953810b57c0fb6f22172abf3e6fb5,5369
74
74
  kimi_cli/ui/shell/update.py,sha256=56dcb0bd1da82b98c22bfdddca717a2805bd8ac3e93bf23fb3b508549c41fae8,7340
75
- kimi_cli/ui/shell/visualize.py,sha256=1abaa53cf78836f71b1f83085b6bfe3f86624951fa3297d5086a06bafa97f960,3884
75
+ kimi_cli/ui/shell/visualize.py,sha256=1ca7a1e766f96f108318640d48552111d42b433e4ddb551af869d331c074d950,4112
76
76
  kimi_cli/utils/aiohttp.py,sha256=f8f61e3beaf6439e949c33c3a10db3035bf88136e882b09c858ea92a4c888e00,245
77
77
  kimi_cli/utils/changelog.py,sha256=bfcf5a5a360b13648bb7a6abc83e427270caa502646b5acc950d62148510641c,3402
78
78
  kimi_cli/utils/logging.py,sha256=129298ac214ecd8d913c3431cc05d754f9c4c8c4042c458618bf9e8ddebdb763,399
@@ -83,7 +83,7 @@ kimi_cli/utils/signals.py,sha256=20e0d158a1043189d44815fe3624cd0bfe41e99620a18ac
83
83
  kimi_cli/utils/string.py,sha256=0d437d3633199df1051813af8b49a2f808c6525547310cc5c3d427710d2eae06,593
84
84
  kimi_cli/wire/__init__.py,sha256=9f1d7eb58f76885edaf76f769371c363ec801b46cada03883eeb3536fa2677f7,1896
85
85
  kimi_cli/wire/message.py,sha256=72222d3f3d7228a323dbba7b1084f35018104c58e4bb2aa51d0827984791841d,2398
86
- kimi_cli-0.44.dist-info/WHEEL,sha256=70ab3c2925fe316809860cb034f99ba13c4b49819b339959274aab755cc084a8,78
87
- kimi_cli-0.44.dist-info/entry_points.txt,sha256=97e051756296e9db3167f6dce61d6c88e58d170314a2d63d18c84c73a5c1333b,44
88
- kimi_cli-0.44.dist-info/METADATA,sha256=02a3d900f175956a579d59cc4a039fb64cc0409e8d4f3baf43289b312e6aeb32,5217
89
- kimi_cli-0.44.dist-info/RECORD,,
86
+ kimi_cli-0.45.dist-info/WHEEL,sha256=70ab3c2925fe316809860cb034f99ba13c4b49819b339959274aab755cc084a8,78
87
+ kimi_cli-0.45.dist-info/entry_points.txt,sha256=97e051756296e9db3167f6dce61d6c88e58d170314a2d63d18c84c73a5c1333b,44
88
+ kimi_cli-0.45.dist-info/METADATA,sha256=bac942d1519d1a5f2650199cb6add467e99274392d3e9b839707915a1acd58d0,5217
89
+ kimi_cli-0.45.dist-info/RECORD,,