Fix Photon iMessage voice replies and threading - #65322
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the Photon media path; current main does drop reply_to in plugins/platforms/photon/adapter.py:1083-1143, and .caf is absent from gateway/platforms/base.py:30.
Problems
- The usual gateway auto-TTS path calls
play_tts()withoutreply_toatgateway/platforms/base.py:5054-5059; normal response media similarly callssend_voice()without it atgateway/platforms/base.py:5159-5164andgateway/run.py:13516-13521. The new adapter plumbing therefore does not thread those common voice/media replies. plugins/platforms/photon/adapter.py:1083-1111deterministically writes<stem>-imessage.m4ausing ffmpeg-y. It can overwrite an existing sibling file, then delete it on a failed conversion.- The attachment is threaded at
plugins/platforms/photon/sidecar/index.mjs:771, but its caption remains a flatspace.send()at line 777.
Suggested changes
- Propagate the event reply anchor through the BasePlatformAdapter and streamed-media dispatch paths, with end-to-end dispatch tests.
- Use a unique temporary/cache conversion output and clean up only the file created for this send.
- Send captions via
sendWithOptionalReplyand cover the caption-plus-reply case.
Automated hermes-sweeper review.
| output = source.with_name(f"{source.stem}-imessage.m4a") | ||
| proc = await asyncio.create_subprocess_exec( | ||
| ffmpeg, | ||
| "-y", |
There was a problem hiding this comment.
-y overwrites an existing <stem>-imessage.m4a sibling. If conversion then fails, lines 1103-1111 unlink that path, so sending voice.mp3 can replace and delete a pre-existing voice-imessage.m4a. Please use a unique temporary/cache output and clean up only the file created by this invocation.
| : attachment(path, Object.keys(opts).length ? opts : undefined); | ||
|
|
||
| const result = await space.send(builder); | ||
| const result = await sendWithOptionalReply(space, builder, replyToId); |
There was a problem hiding this comment.
This threads the attachment, but the caption immediately below is still sent with bare space.send() at line 777. For any attachment with a caption and replyToId, the caption escapes the native reply. Route it through sendWithOptionalReply as well and add coverage.
|
One deployment gap in the current voice-normalization path: We reproduced this with normal Hermes TTS MP3 output. A robust fix was to ship a deterministic ffmpeg binary with the Photon sidecar ( Also worth preserving in the final implementation: Spectrum keeps the supplied content name, so M4A bytes with an |
|
I opened #65836 as a focused companion for the remaining final-hop gap: it installs Spectrum’s optional static-ffmpeg peer, aligns transcoded upload filenames to |
|
Verification (Vox Lockin lane 08 — platform adapter voice class): verified against
Recommendation: rebase the draft on main if the outbound half is still desired; no inbound-STT work remains for it to carry. No duplicate PR will be opened. |
What changed
audio/mp4shape.send_voiceinstead ofsend_document.Why
Hermes TTS normally emits MP3, while one iMessage fallback emitted CAF. CAF was omitted from the shared native-audio extension set, so the normal gateway path treated it as a document and bypassed Photon voice normalization. Manual MP3-to-CAF conversion was also unreliable.
Impact
Photon iMessage voice replies are normalized to an iMessage-compatible M4A voice payload, including when the source is MP3 or CAF. Replies can retain their native message anchor.
Verification
pytest -q tests/plugins/platforms/photon/test_outbound_media.pypytest -q tests/gateway/test_platform_base.py -k ShouldSendMediaAsAudio