Why traces help
Synap’s anticipation agent prepares the context your agent will need on its next turn. Without traces it sees only the edges of a turn: what the user asked and what your agent replied. With them it also sees how the reply was reached: what your agent decided to check, which tool it called with which arguments, and what came back. The next question usually follows from that. A user who has been told their order shipped asks when it arrives, and the agent that saw the order lookup can prepare for that question before it is asked.Before you start
You need an open stream. There is no REST method for traces, so they can only travel on the stream thatinstance.listen() opens. Open it once per process.
Each trace carries the same ids as the turn it belongs to. Synap files a trace under its conversation, and drops a trace that has no conversation_id.
send_message: a user_message when the user speaks and an assistant_message after it replies. The reply is what makes Synap act on the traces, so do not skip it.
Send each kind of trace
Reasoning
Send one reasoning step per call withrecord_thinking. This is the only trace that shows intent: a tool call says what your agent looked at, and a reasoning step says why. step_index orders the steps within a turn, and thought_type labels the kind of step, for example "plan", "reflect", "tool_decision" or "self_correction".
A tool call
Report each tool your agent invokes withrecord_tool_call, before you run it. The tool name and its arguments say what your agent is about to need, which is often what the user asks about next. Give each call a tool_call_id and pass the same id with its result, so a turn with several tools in flight still pairs each result with the call that asked for it.
send_message(event_type="tool_call"). Every event carries both an event type and a role, and this method sets the two together, so they always agree.
A tool’s result
Report what the tool returned withrecord_tool_result. The result is the material your agent built its reply from, so it is the strongest clue to what the user will ask next. The SDK also keeps it in a local archive so that history search can find it after a compaction.
One turn, end to end
A small helper that wraps every tool call keeps the call, the result and their shared id together, so no tool runs unreported.What Synap does with each
All three kinds of trace go to the same place: the working thread that Synap’s anticipation agent keeps for the conversation.- They do not wake it. A trace arrives while your agent is still working on the turn, and a bundle pushed then would arrive after your agent had already fetched. So traces join the thread, and the anticipation agent reads them when your
assistant_messageends the turn. - They do not become memory. Only
user_messageandassistant_messageevents are stored as conversation turns. Reasoning, tool calls and tool results are never compacted and never extracted into long-term memory. When your agent’s reply states something a tool returned, that reply is stored as a turn like any other. For a fact that must be remembered on its own, usememories.create. - Their words are short-lived. The thread keeps the conversation’s 80 most recent events. It expires 30 minutes after the conversation’s last event, and is deleted when the session ends.
- Only their shape is kept longer. Synap’s anticipation debugging records keep the outline of each step for 30 days: the tool name, the call id,
step_index,thought_type, and how many characters each field held. They do not keep the words of your reasoning, your tool arguments or your tool results.
The local turn archive
The SDK keeps an archive of each conversation’s turns on the machine it runs on: the turns your process recorded, and earlier turns it fetched from Synap.record_tool_result adds the tool’s result to this archive before it sends the event, by calling archive_tool_result. The archived copy is never sent anywhere.
The reason is what a compaction leaves out. A compaction summarises what people said; the exact values a tool returned, such as an order number, a date or an amount, are the details a summary drops. Once a conversation has compacted, conversation.context.get_context_for_prompt searches the earlier turns in this archive (by default for the latest user message) and appends the best matches word for word after the recent messages, in history_excerpts. Archived tool results are part of that search, so a figure a tool returned many turns ago can still reach the prompt.
A result is archived as a turn with the role tool, written as [tool result: lookup_order] followed by the result as compact JSON (or the string itself), cut at 16,000 characters.
Without a stream
record_thinking, record_tool_call and record_tool_result raise ListeningNotActiveError when listen() was never called or stop_listening() has run. While the stream is reconnecting they do not raise: events are buffered (up to 100 events or five minutes) and replayed when it returns. See Event delivery.
record_tool_result archives the result before it sends, so the local copy is kept even when the call raises. A long-running process that writes its turns over REST with record_message and never opens a stream can still keep tool results searchable by archiving them directly:
Common mistakes
- A trace without
conversation_id. Synap cannot place it in a conversation and drops it. Use the same UUID as the turn. - No
assistant_message. The anticipation agent reads the traces when the reply arrives. A turn that never reports its reply leaves the traces unread. - Tool events built by hand with
send_message. You have to set the event type, the role and the tool fields yourself, and keep them consistent.record_tool_callandrecord_tool_resultset all of them for you. - Several tools in flight without
tool_call_id. Three calls and three results arrive with nothing saying which result answers which call. - The whole record as a result. Send the fields your agent used. The anticipation agent reads the first 2,000 characters, and the rest only adds data that leaves your process.
- Expecting a trace to become a memory. Traces are hints for the next turn. Store lasting facts as turns or with
memories.create. - Opening a stream per request to send traces. A serverless handler exits before a bundle can arrive. See gRPC vs REST.
Related
- instance.record_thinking, instance.record_tool_call, instance.record_tool_result: the three trace methods in full.
- instance.send_message: the turn events and the full event table.
- instance.listen: opening the stream.
- Real-time anticipation: what Synap does with everything the stream carries.
- Erasing a person: deletion in Synap, alongside the local copy described above.