Skip to main content
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().
Every event your agent reports carries an id, and the platform acknowledges the ids it has taken responsibility for. That pair is what lets the SDK retry safely: without an id there is nothing to recognise a repeat by, and without an acknowledgement there is nothing to tell a write that landed from one that died with the connection. You do not have to do anything to get this. The SDK mints the ids, holds what has not been acknowledged, and replays it.

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.
It does not mean a memory exists. Extraction is asynchronous and happens later, after compaction. An acknowledgement is about delivery, nothing else.

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.
Both carry the id they were first sent with. The platform drops a second sighting of an id before it does anything with it, so a replay of something it already processed costs nothing and cannot record the same turn twice. The buffer is bounded: 100 events, or five minutes, whichever comes first. Past that the oldest is dropped with a warning in your logs, because a buffer that grows without limit during an outage is its own failure.
send_message() and the record_* methods do not raise while the stream is reconnecting. They buffer. They raise only if you never started a stream, or you stopped 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. The buffer lives in memory, so anything still in it when your process exits is gone. If your process can exit abruptly, call stop_listening() on your shutdown path.

Clients 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. Those clients send the same events over HTTP instead:
The response answers per event rather than per batch, because a repeat is not a failure and one bad event should not cost you the rest of a turn:
Include an event_id and the route is idempotent: retrying a batch that half-succeeded cannot double a turn.
HTTP cannot carry anticipated context back to you. Pushed bundles need the bidirectional stream. An HTTP caller fetches context the ordinary way, with context.fetch. Everything else about the event — persistence, anticipation, the learning loop — is the same on both doors.

See also