runifold_agent/conversation/durable.rs
1//! Atomic conversation-and-checkpoint commit boundary.
2
3use runifold_core::{Checkpoint, CheckpointId, CheckpointStore};
4
5use super::{
6 ConversationAppend, ConversationContextPolicy, ConversationId, ConversationStore,
7 ConversationStoreError, ConversationStoreFuture, ConversationVersion, MemoryNamespace,
8};
9
10/// Stable identities and context policy for one new durable Agent turn.
11#[derive(Clone, Debug)]
12pub struct DurableConversationRequest {
13 /// Fresh checkpoint identity used as the turn's idempotency identity.
14 pub checkpoint_id: CheckpointId,
15 /// Conversation receiving the completed turn.
16 pub conversation_id: ConversationId,
17 /// Isolation namespace owning the conversation.
18 pub namespace: MemoryNamespace,
19 /// Bounded context selection policy.
20 pub policy: ConversationContextPolicy,
21}
22
23/// Final state of one durable conversational Agent turn.
24///
25/// Implementations must validate both optimistic preconditions and commit the
26/// transcript append and checkpoint replacement in one storage transaction.
27#[derive(Clone, Debug)]
28pub struct DurableConversationCommit {
29 /// Namespace owning the conversation.
30 pub namespace: MemoryNamespace,
31 /// Canonical messages produced by the single Agent execution.
32 pub append: ConversationAppend,
33 /// Completed checkpoint revision to persist with the transcript.
34 pub checkpoint: Checkpoint,
35 /// Checkpoint revision observed immediately before the final commit.
36 pub expected_checkpoint_revision: u64,
37}
38
39/// Store capable of atomically committing conversation and recovery state.
40///
41/// Merely implementing [`ConversationStore`] and [`CheckpointStore`] is not
42/// sufficient: the final writes must share one real transaction.
43pub trait DurableConversationStore: ConversationStore + CheckpointStore {
44 /// Atomically appends a transcript turn and advances its checkpoint.
45 fn commit_durable_turn(
46 &self,
47 command: DurableConversationCommit,
48 ) -> ConversationStoreFuture<'_, Result<ConversationVersion, ConversationStoreError>>;
49}