pub fn synthesize_replay_messages(messages: &[Value]) -> Vec<Message>Expand description
Synthesise on-disk transcript JSONL into the forge_primitives::Message
envelopes the live wire stream produces. Consumers read these
identically to live messages, unifying replay + live code paths.
Replay-specific transforms applied here:
-
An image or document block keeps its mime and the size its payload weighed, and loses that payload: the read draws the same attachment row the live path draws for it, and that row shows no bytes. A queued prompt’s own block list is walked the same way - its attachments draw the same row, and a payload left there rides every page read.
A tool result’s nested image is passed through untouched - payload and all - because a call row draws a result’s image from its own data URL, and nothing here should change what that gets.
Thinking blocks are kept. A thinking block is the row the chat draws
for a thought, and the live path draws it (a thinking block in an
assistant frame), so a read that dropped the block drew a different
conversation from the same turn - the read and live paths have to fold
the same frames (rule 25).
The session_id field on each Message is left empty; the caller
(forge_sdk_worker::spawn_session) is responsible for stamping the
correct id before emitting AgentEvent::Connected. The row’s uuid
is carried across when it has one: it is the id the same message
arrives under on the wire, so a reader can tell the two apart.