kimi-code/.changeset/fix-skill-command-media.md
liruifengv 20615902c2
fix(tui): deliver pasted media in /skill args and Ctrl-S steer (#1588)
* fix(tui): deliver pasted media in /skill and plugin command args via file tags

Skill and plugin command args are a plain-text RPC channel, so pasted image/video placeholders never reached the model. Rewrite matched placeholders into <image|video path="..."> tags pointing at cache-dir copies (the same convention pasted videos already use), and gate them on model media capabilities like the normal prompt path.

* fix(tui): deliver pasted media when steering with Ctrl-S

Ctrl-S steer dropped media: queued messages were reduced to their text and the editor draft never went through placeholder extraction, so session.steer only ever received placeholder strings. Carry the queued items' extracted parts, extract the editor draft on the spot (with the same capability gate as a normal submit), and merge everything into a part list when any item has media.

* fix(tui): avoid empty text separator when steering consecutive media

The '\n\n' item separator could land as a standalone whitespace-only text part between two media parts, which normalizePromptInput rejects — failing the steer after the queue and editor draft were already cleared. Only append the separator onto a trailing text part so it always merges.

* fix(tui): keep blank-line separator between media and text steer items

The separator was only appended onto trailing text parts, so a media item followed by a plain-text steer item lost the historical '\n\n' separation. Always append it — it merges into the adjacent text part — except between two touching media parts, where a standalone whitespace-only text part would be rejected by normalizePromptInput.

* fix(tui): use escape-proof media references in /skill args

Skill args are XML-escaped on render (renderSkillAttributes + expandSkillParameters), which mangled the <image|video path> tags into escaped text. Add a 'plain' reference style (Attached image file: <path> (open it with ReadMediaFile)) with no tag/attribute boundary characters and use it for the skill channel; plugin command args expand verbatim and keep the tag form.

* fix(tui): strip XML boundary chars from plain-style video cache names

Video cache names carry the original label, which permits <>&"; in the plain (/skill) reference style those chars get XML-escaped in args and the reference no longer matches the file on disk. Strip them from the cache name in plain mode; the tag channel is unchanged (its attribute escaping already handles them).

* fix(tui): surface media materialization failures as TUI errors

The cache copy inside media placeholder rewriting can throw (unwritable cache dir, vanished video source) before any RPC .catch is installed, escaping the fire-and-forget slash-command dispatcher as an unhandled rejection. Catch it in sendSkillActivation, activatePluginCommand, and the Ctrl-S draft extraction, show an error, and leave queue/draft/session state untouched.
2026-07-13 16:16:44 +08:00

114 B

@moonshot-ai/kimi-code
patch

Fix pasted media being dropped from /skill and plugin command arguments.