Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/kimi_cli/tools/ask_user/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@ async def __call__(self, params: Params) -> ToolReturnValue:

if not answers:
return ToolReturnValue(
is_error=False,
output='{"answers": {}, "note": "User dismissed the question without answering."}',
is_error=True,
output="User dismissed the question without answering. "
"Do NOT assume any answer or proceed on the user's behalf. "
"Stop and wait for the user's next message.",
message="User dismissed the question without answering.",
display=[BriefDisplayBlock(text="User dismissed")],
)
Expand Down
6 changes: 3 additions & 3 deletions src/kimi_cli/tools/plan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ async def __call__(self, params: Params) -> ToolReturnValue:

if not answers:
return ToolReturnValue(
is_error=False,
output="User dismissed without choosing. Plan mode remains active. "
"Continue working on your plan or call ExitPlanMode again when ready.",
is_error=True,
output="User dismissed the plan review without choosing. Plan mode remains active. "
"Do NOT proceed with implementation. Stop and wait for the user's next message.",
message="Dismissed",
display=[BriefDisplayBlock(text="Dismissed")],
)
Expand Down
5 changes: 3 additions & 2 deletions src/kimi_cli/tools/plan/enter.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ async def __call__(self, params: Params) -> ToolReturnValue:

if not answers:
return ToolReturnValue(
is_error=False,
output="User dismissed without choosing. Proceed with implementation directly.",
is_error=True,
output="User dismissed the plan mode prompt without choosing. "
"Do NOT proceed with implementation. Stop and wait for the user's next message.",
message="Dismissed",
display=[BriefDisplayBlock(text="Dismissed")],
)
Expand Down
8 changes: 5 additions & 3 deletions tests/core/test_plan_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ async def test_revise_without_feedback(
assert not result.is_error
assert "User feedback:" not in _tool_output_text(result)

async def test_dismissed_returns_continue(
async def test_dismissed_returns_error(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
tool, toggle_cb, _ = _setup_exit_tool(tmp_path)
Expand All @@ -387,8 +387,9 @@ async def test_dismissed_returns_continue(

result = await tool(tool.params())
assert isinstance(result, ToolReturnValue)
assert not result.is_error
assert result.is_error
assert "dismissed" in _tool_output_text(result).lower()
assert "do not proceed" in _tool_output_text(result).lower()
toggle_cb.assert_not_awaited()

async def test_question_not_supported(
Expand Down Expand Up @@ -475,8 +476,9 @@ async def test_dismissed(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch)

result = await tool(tool.params())
assert isinstance(result, ToolReturnValue)
assert not result.is_error
assert result.is_error
assert "dismissed" in _tool_output_text(result).lower()
assert "do not proceed" in _tool_output_text(result).lower()
toggle_cb.assert_not_awaited()

async def test_question_not_supported(
Expand Down
9 changes: 4 additions & 5 deletions tests/tools/test_ask_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ async def test_ask_user_basic(ask_user_tool: AskUserQuestion):


async def test_ask_user_dismissed(ask_user_tool: AskUserQuestion):
"""Test that user dismiss returns a non-error result with dismiss note."""
"""Test that user dismiss returns an error result instructing the LLM to stop."""
wire = Wire()
wire_token = _current_wire.set(wire)
tool_call = ToolCall(
Expand All @@ -100,11 +100,10 @@ async def test_ask_user_dismissed(ask_user_tool: AskUserQuestion):
msg.resolve({})

result = await asyncio.wait_for(tool_task, timeout=2.0)
assert not result.is_error
assert result.is_error
assert isinstance(result.output, str)
parsed = json.loads(result.output)
assert parsed["answers"] == {}
assert "dismissed" in parsed.get("note", "").lower()
assert "dismissed" in result.output.lower()
assert "do not" in result.output.lower()
finally:
wire.shutdown()
current_tool_call.reset(tc_token)
Expand Down
6 changes: 2 additions & 4 deletions tests_e2e/test_wire_question.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,8 @@ def error_handler(msg: dict[str, Any]) -> dict[str, Any]:
for tr in tool_results:
if tr["payload"]["tool_call_id"] == "tc-q2":
rv = tr["payload"]["return_value"]
assert not rv["is_error"]
output = json.loads(rv["output"])
assert output["answers"] == {}
assert "dismissed" in output.get("note", "").lower()
assert rv["is_error"]
assert "dismissed" in rv["output"].lower()
break
else:
raise AssertionError("ToolResult for tc-q2 not found")
Expand Down
Loading