Requires
maximem-synap 0.5.1 or newer (Python) and
@maximem/synap-js-sdk 0.5.1 or newer (JS). Earlier versions do not
have this method, and 0.5.0 loses events sent immediately after
listen().What an acknowledgement means
An acknowledgement says the platform has the event: recorded so a repeat is recognised, queued for anticipation, and for conversation turns handed to the writer that persists them.When the stream drops
Two things can be in flight when a connection goes:- Events you sent while there was no stream. They are buffered and sent when one comes back.
- Events that went out but were never acknowledged. The write succeeded and the stream broke before the platform confirmed it. These are replayed first, because they happened first.
Across a restart
The buffer is also written to disk, so a process that dies with events still in it does not lose them. Both SDKs append each change to a journal file,~/.synap/outbox/<instance_id>.jsonl by default. The next time that instance calls listen(), the SDK reads the file back and sends what was left (events that were never acknowledged first, then the ones that never went out) before anything new. Each keeps its original id, so an event the platform had already processed is recognised and dropped.
- Where the file lives. Set
SYNAP_STORAGE_PATHto move it; the file is then<that path>/outbox/<instance_id>.jsonl. Python also takes astorage_pathin its config, which wins over the variable. The JavaScript SDK reads the variable only. - What it holds. The event payloads, which include the text of conversation turns. Treat the directory as you would any place your process writes conversation text.
- When it cannot be written. If the disk is read-only or full, the SDK logs one warning and keeps buffering in memory only, so those events do not survive a restart.
- It is local to the machine. There is one file per instance id, in the home directory (or storage path) of the user running your process. A replacement process on another machine, or under another user, does not see it.
Closing cleanly
stop_listening() flushes what is still buffered before the stream goes away, with a short deadline, and closes any session it opened. If your process exits abruptly instead, whatever was still buffered is in the journal file and goes out on the next listen() from the same machine and home directory. Call stop_listening() on your shutdown path anyway, so events are delivered now rather than on the next start.
Processes that cannot hold a stream
The gRPC stream needs a connection held open for the length of a conversation. A serverless function, a short-lived worker, or anything that suspends between requests cannot do that, so none of the delivery behaviour above applies to it: there is no stream to buffer for. Such a process reports conversation turns withconversation.record_message instead, one request per turn, which stores the turn before it returns. The cost is that pushed anticipation bundles need the stream, so a process without one fetches context the ordinary way, with context.fetch. See gRPC vs REST for the full comparison.
See also
- instance.listen: opening the stream.
- instance.send_message: the event table.
- Real-time anticipation: what the platform does with the events.