fix(tui): always call input.detect_drop for reliable image attachment

Remove frontend regex pre-check that truncated paths containing spaces,
quotes, or Windows drive letters. Backend _detect_file_drop correctly
handles these patterns. This fixes image attachment for common filenames
like "Screenshot 2026-04-29.png".

Add tests:
- test_input_detect_drop_path_with_spaces: attaches image with spaces in name
- test_input_detect_drop_path_with_spaces_and_remainder: remainder handling

Also restored missing  in test_rollback_restore_resolves_number_and_file_path.

Scope: tui, vision, tests
This commit is contained in:
Harry Riddle 2026-04-29 20:39:52 +07:00 committed by Teknium
parent 19136dfc07
commit cc340c4a4d
2 changed files with 52 additions and 7 deletions

View file

@ -1923,6 +1923,55 @@ def test_input_detect_drop_attaches_image(monkeypatch):
assert resp["result"]["text"] == "[User attached image: cat.png]" assert resp["result"]["text"] == "[User attached image: cat.png]"
def test_input_detect_drop_path_with_spaces(tmp_path):
"""input.detect_drop correctly handles image paths containing spaces."""
# Create a minimal PNG file with a space in its name
img = tmp_path / "screenshot with spaces.png"
img.write_bytes(b"\x89PNG\r\n\x1a\n") # valid PNG header
server._sessions["sid"] = _session()
resp = server.handle_request(
{
"id": "2",
"method": "input.detect_drop",
"params": {"session_id": "sid", "text": str(img)},
}
)
assert resp["result"]["matched"] is True
assert resp["result"]["is_image"] is True
assert resp["result"]["path"] == str(img)
assert resp["result"]["text"] == f"[User attached image: {img.name}]"
# Verify attachment was recorded in the session
assert len(server._sessions["sid"]["attached_images"]) == 1
assert server._sessions["sid"]["attached_images"][0] == str(img)
def test_input_detect_drop_path_with_spaces_and_remainder(tmp_path):
"""input.detect_drop splits remainder when path contains spaces."""
img = tmp_path / "photo with space.jpg"
img.write_bytes(b"\xff\xd8\xff" + b"fakejpeg") # minimal-ish JPEG header
server._sessions["sid"] = _session()
user_input = f"{img} describe this image"
resp = server.handle_request(
{
"id": "3",
"method": "input.detect_drop",
"params": {"session_id": "sid", "text": user_input},
}
)
assert resp["result"]["matched"] is True
assert resp["result"]["is_image"] is True
assert resp["result"]["path"] == str(img)
# Remainder becomes the text sent to the model
assert resp["result"]["text"] == "describe this image"
assert server._sessions["sid"]["attached_images"][0] == str(img)
def test_rollback_restore_resolves_number_and_file_path(): def test_rollback_restore_resolves_number_and_file_path():
calls = {} calls = {}

View file

@ -126,13 +126,9 @@ export function useSubmission(opts: UseSubmissionOptions) {
return sys('session not ready yet') return sys('session not ready yet')
} }
// Plain prompts are the common path and should not pay an extra RPC // Always ask the backend whether this looks like a file drop.
// before prompt.submit. File-drop detection still runs for absolute, // The backend's _detect_file_drop handles paths with spaces, quotes,
// tilde, file://, and explicit relative paths. // Windows drive letters, and escaped characters correctly.
if (!looksLikeSlashCommand(text) && !/(?:^|\s)(?:file:\/\/|~\/|\.?\.\/|\/)[^\s]+/.test(text)) {
return startSubmit(text, expand(text), showUserMessage)
}
gw.request<InputDetectDropResponse>('input.detect_drop', { session_id: sid, text }) gw.request<InputDetectDropResponse>('input.detect_drop', { session_id: sid, text })
.then(r => { .then(r => {
if (!r?.matched) { if (!r?.matched) {