Summary
Typing kimi export can fail with a Moonshot API 400 error when the session enters context compaction. The compaction message contains empty/whitespace-only TextParts, which the API rejects.
Environment
- kimi-cli version: 1.45.0
- Python version: 3.12.13
- OS: Linux 6.18.27-amd64-desktop-rolling (x86_64)
- Model: kimi-code/kimi-for-coding
Steps to Reproduce
- Start a session that accumulates enough context to trigger auto-compaction.
- Ensure some messages in history have empty or whitespace-only
TextParts (e.g., tool results with no text output).
- Run
kimi export.
- The shell begins compaction (
CompactionBegin) and immediately crashes.
Actual Behavior
2026-05-28 21:11:28.599 | CompactionBegin
2026-05-28 21:11:30.254 | StepInterrupted
2026-05-28 21:11:30.254 | ERROR | Context compaction failed at step 1: APIStatusError: Error code: 400 - text content is empty
Expected Behavior
kimi export should complete successfully even when the context contains messages with empty text content.
Root Cause
In kimi_cli/soul/compaction.py, SimpleCompaction.prepare() builds a compaction prompt by iterating over historical messages and appending their TextParts:
compact_message.content.extend(
part for part in msg.content if isinstance(part, TextPart)
)
This does not filter out TextParts where text == "" or text.strip() == "". When the resulting compaction message is sent to kosong.step(), the Moonshot API rejects it with:
{"error": {"message": "text content is empty", "type": "invalid_request_error"}}
A similar bug for tool messages was previously fixed (see #1663 in message.py), but the compaction path was missed.
Proposed Fix
Two defensive changes in kimi_cli/soul/compaction.py, method SimpleCompaction.prepare():
1. Filter empty text parts
compact_message.content.extend(
part for part in msg.content
if isinstance(part, TextPart) and part.text.strip()
)
2. Skip compaction if nothing meaningful remains
compact_message.content.append(TextPart(text=prompt_text))
if not any(
isinstance(p, TextPart) and p.text.strip()
for p in compact_message.content
):
return self.PrepareResult(compact_message=None, to_preserve=messages)
return self.PrepareResult(compact_message=compact_message, to_preserve=to_preserve)
Attachments
Sanitized session export (PII redacted): session-df52da1f-sanitized.zip
Related PR
Additional Context
The crash occurs at the kosong.step() call inside SimpleCompaction.compact(), not during serialization of the final compacted result. Therefore the fix must be applied before the LLM call, not after.
Summary
Typing
kimi exportcan fail with a Moonshot API 400 error when the session enters context compaction. The compaction message contains empty/whitespace-onlyTextParts, which the API rejects.Environment
Steps to Reproduce
TextParts (e.g., tool results with no text output).kimi export.CompactionBegin) and immediately crashes.Actual Behavior
Expected Behavior
kimi exportshould complete successfully even when the context contains messages with empty text content.Root Cause
In
kimi_cli/soul/compaction.py,SimpleCompaction.prepare()builds a compaction prompt by iterating over historical messages and appending theirTextParts:This does not filter out
TextParts wheretext == ""ortext.strip() == "". When the resulting compaction message is sent tokosong.step(), the Moonshot API rejects it with:{"error": {"message": "text content is empty", "type": "invalid_request_error"}}A similar bug for tool messages was previously fixed (see
#1663inmessage.py), but the compaction path was missed.Proposed Fix
Two defensive changes in
kimi_cli/soul/compaction.py, methodSimpleCompaction.prepare():1. Filter empty text parts
2. Skip compaction if nothing meaningful remains
Attachments
Sanitized session export (PII redacted): session-df52da1f-sanitized.zip
Related PR
Additional Context
The crash occurs at the
kosong.step()call insideSimpleCompaction.compact(), not during serialization of the final compacted result. Therefore the fix must be applied before the LLM call, not after.