Skip to content

Commit 25c64df

Browse files
committed
fix(shell): keep image paths literal in shell mode
1 parent a4b7ae0 commit 25c64df

3 files changed

Lines changed: 44 additions & 6 deletions

File tree

src/kimi_cli/ui/shell/placeholders.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,9 @@ def maybe_placeholderize_pasted_text(self, text: str) -> str:
583583
def create_image_placeholder(self, image: Image.Image) -> str | None:
584584
return self._image_handler.create_placeholder(image)
585585

586-
def resolve_command(self, command: str) -> ResolvedPromptCommand:
586+
def resolve_command(
587+
self, command: str, *, attach_literal_images: bool = True
588+
) -> ResolvedPromptCommand:
587589
content: list[ContentPart] = []
588590
resolved_chunks: list[str] = []
589591
cursor = 0
@@ -592,12 +594,22 @@ def resolve_command(self, command: str) -> ResolvedPromptCommand:
592594
while match := self._find_next_match(command, cursor):
593595
if match.start > cursor:
594596
literal = command[cursor : match.start]
595-
self._append_literal_content(literal, content, attached_image_paths)
597+
self._append_literal_content(
598+
literal,
599+
content,
600+
attached_image_paths,
601+
attach_images=attach_literal_images,
602+
)
596603
resolved_chunks.append(literal)
597604

598605
resolved_content = match.handler.resolve_content(match)
599606
if resolved_content is None:
600-
self._append_literal_content(match.raw, content, attached_image_paths)
607+
self._append_literal_content(
608+
match.raw,
609+
content,
610+
attached_image_paths,
611+
attach_images=attach_literal_images,
612+
)
601613
resolved_chunks.append(match.raw)
602614
else:
603615
content.extend(resolved_content)
@@ -608,7 +620,12 @@ def resolve_command(self, command: str) -> ResolvedPromptCommand:
608620

609621
if cursor < len(command):
610622
literal = command[cursor:]
611-
self._append_literal_content(literal, content, attached_image_paths)
623+
self._append_literal_content(
624+
literal,
625+
content,
626+
attached_image_paths,
627+
attach_images=attach_literal_images,
628+
)
612629
resolved_chunks.append(literal)
613630

614631
return ResolvedPromptCommand(
@@ -670,10 +687,12 @@ def _append_literal_content(
670687
literal: str,
671688
content: list[ContentPart],
672689
attached_image_paths: set[Path],
690+
*,
691+
attach_images: bool,
673692
) -> None:
674693
if not literal:
675694
return
676-
if not self._supports_image_input():
695+
if not attach_images or not self._supports_image_input():
677696
content.append(TextPart(text=literal))
678697
return
679698

src/kimi_cli/ui/shell/prompt.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2066,7 +2066,10 @@ async def _prompt_once(self, *, append_history: bool | None) -> UserInput:
20662066
def _build_user_input(self, command: str) -> UserInput:
20672067
manager = self._get_placeholder_manager()
20682068
manager.update_model_capabilities(set(self._model_capabilities))
2069-
resolved = manager.resolve_command(command)
2069+
resolved = manager.resolve_command(
2070+
command,
2071+
attach_literal_images=self._mode == PromptMode.AGENT,
2072+
)
20702073

20712074
return UserInput(
20722075
mode=self._mode,

tests/ui_and_conv/test_prompt_tips.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,22 @@ def build_user_input(command: str) -> UserInput:
933933
assert history == []
934934

935935

936+
def test_build_user_input_keeps_shell_image_paths_literal(tmp_path) -> None:
937+
prompt_session = object.__new__(CustomPromptSession)
938+
prompt_session._mode = PromptMode.SHELL
939+
prompt_session._model_capabilities = {"image_in"}
940+
941+
command = f"cat {tmp_path / 'missing.png'}"
942+
943+
user_input = prompt_session._build_user_input(command)
944+
945+
assert user_input.mode == PromptMode.SHELL
946+
assert user_input.command == command
947+
assert user_input.resolved_command == command
948+
assert len(user_input.content) == 1
949+
assert user_input.content[0].text == command
950+
951+
936952
@pytest.mark.asyncio
937953
async def test_prompt_next_skips_history_for_running_submission() -> None:
938954
prompt_session = object.__new__(CustomPromptSession)

0 commit comments

Comments
 (0)