pub trait ConversationStore: Send + Sync {
Show 23 methods
// Required methods
fn mark_seen<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
event_id: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn append<'life0, 'async_trait>(
&'life0 self,
message: NewMessage,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn recent<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<StoredMessage>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn reset<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn session<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<Option<(String, String)>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn set_session<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
backend: &'life2 str,
session: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
fn record_run<'life0, 'async_trait>(
&'life0 self,
run: AgentRunRecord,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn owners<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(ChannelId, UserId)>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn remove_owner<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn create_pairing_code<'life0, 'life1, 'async_trait>(
&'life0 self,
code: &'life1 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn redeem_pairing_code<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
code: &'life1 str,
channel: &'life2 ChannelId,
user: &'life3 UserId,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
fn claim_fire<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 str,
fire_at: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Fire, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn set_fire<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 str,
fire_at: Timestamp,
state: FireState,
attempts: u32,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn recent_fires<'life0, 'async_trait>(
&'life0 self,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Fire>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn set_direct_chat<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
conversation: &'life3 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
fn direct_chat<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
) -> Pin<Box<dyn Future<Output = Result<Option<ConversationKey>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn usage_since<'life0, 'life1, 'async_trait>(
&'life0 self,
person: &'life1 str,
since: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Usage, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn record_tool_call<'life0, 'async_trait>(
&'life0 self,
call: ToolCallRecord,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn tool_calls<'life0, 'async_trait>(
&'life0 self,
since: Timestamp,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<ToolCallRecord>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn grant_role<'life0, 'async_trait>(
&'life0 self,
grant: RoleGrant,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn revoke_role<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
role: &'life1 str,
account: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn role_grants<'life0, 'async_trait>(
&'life0 self,
now: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Vec<RoleGrant>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn purge_before<'life0, 'async_trait>(
&'life0 self,
before: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}Expand description
Stores conversations, deduplication marks and the audit trail (design §6.1).
Required Methods§
Sourcefn mark_seen<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
event_id: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn mark_seen<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
event_id: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Records an inbound event id. Returns false when it was already seen within ttl.
Sourcefn append<'life0, 'async_trait>(
&'life0 self,
message: NewMessage,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn append<'life0, 'async_trait>(
&'life0 self,
message: NewMessage,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Appends a message to a conversation.
Sourcefn recent<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<StoredMessage>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn recent<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<StoredMessage>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
The newest limit messages after the last reset, oldest first.
Sourcefn reset<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn reset<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Starts a fresh history for the conversation (/reset). Old messages stay for audit
until retention removes them.
Sourcefn session<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<Option<(String, String)>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn session<'life0, 'life1, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<Option<(String, String)>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
The native agent session of a conversation: (backend, session id).
Sourcefn set_session<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
backend: &'life2 str,
session: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn set_session<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
conversation: &'life1 ConversationKey,
backend: &'life2 str,
session: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Remembers the native agent session of a conversation (cleared by ConversationStore::reset).
Sourcefn record_run<'life0, 'async_trait>(
&'life0 self,
run: AgentRunRecord,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn record_run<'life0, 'async_trait>(
&'life0 self,
run: AgentRunRecord,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Records an agent run.
Sourcefn owners<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(ChannelId, UserId)>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn owners<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(ChannelId, UserId)>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Accounts of the owner of a personal bot (paired with ConversationStore::redeem_pairing_code).
Sourcefn remove_owner<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn remove_owner<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Removes an owner account. Returns whether it was one.
Sourcefn create_pairing_code<'life0, 'life1, 'async_trait>(
&'life0 self,
code: &'life1 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn create_pairing_code<'life0, 'life1, 'async_trait>(
&'life0 self,
code: &'life1 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Stores a one-time pairing code, valid for ttl.
Sourcefn redeem_pairing_code<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
code: &'life1 str,
channel: &'life2 ChannelId,
user: &'life3 UserId,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn redeem_pairing_code<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
code: &'life1 str,
channel: &'life2 ChannelId,
user: &'life3 UserId,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Consumes code and makes (channel, user) an owner account when the code is valid.
A wrong code counts as a failed attempt against every pending code; after
PAIRING_MAX_FAILURES failures the pending codes are cancelled, so codes cannot be
guessed.
Sourcefn claim_fire<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 str,
fire_at: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Fire, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn claim_fire<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 str,
fire_at: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Fire, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Claims a task firing: records it as FireState::Sending the first time and returns its
current record, so a firing that was already sent is never sent again.
Sourcefn set_fire<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 str,
fire_at: Timestamp,
state: FireState,
attempts: u32,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_fire<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 str,
fire_at: Timestamp,
state: FireState,
attempts: u32,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Updates a claimed firing.
Sourcefn recent_fires<'life0, 'async_trait>(
&'life0 self,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Fire>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn recent_fires<'life0, 'async_trait>(
&'life0 self,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Fire>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
The newest limit firings, newest first (for okbot doctor and okbot task).
Sourcefn set_direct_chat<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
conversation: &'life3 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn set_direct_chat<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
conversation: &'life3 ConversationKey,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Remembers the direct conversation of user on channel (reminders sent there).
Sourcefn direct_chat<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
) -> Pin<Box<dyn Future<Output = Result<Option<ConversationKey>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn direct_chat<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
channel: &'life1 ChannelId,
user: &'life2 UserId,
) -> Pin<Box<dyn Future<Output = Result<Option<ConversationKey>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
The latest direct conversation of user on channel.
Sourcefn usage_since<'life0, 'life1, 'async_trait>(
&'life0 self,
person: &'life1 str,
since: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Usage, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn usage_since<'life0, 'life1, 'async_trait>(
&'life0 self,
person: &'life1 str,
since: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Usage, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Turns and tokens of person (person_key) in runs started at or after since.
Sourcefn record_tool_call<'life0, 'async_trait>(
&'life0 self,
call: ToolCallRecord,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn record_tool_call<'life0, 'async_trait>(
&'life0 self,
call: ToolCallRecord,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Records a tool call.
Sourcefn tool_calls<'life0, 'async_trait>(
&'life0 self,
since: Timestamp,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<ToolCallRecord>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn tool_calls<'life0, 'async_trait>(
&'life0 self,
since: Timestamp,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<ToolCallRecord>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Tool calls made at or after since, newest first, at most limit.
Sourcefn grant_role<'life0, 'async_trait>(
&'life0 self,
grant: RoleGrant,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn grant_role<'life0, 'async_trait>(
&'life0 self,
grant: RoleGrant,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Grants a role until grant.expires_at, replacing an earlier grant of the same role to the
same account.
Sourcefn revoke_role<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
role: &'life1 str,
account: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn revoke_role<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
role: &'life1 str,
account: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Ends a grant before it expires. Returns whether there was one.
Sourcefn role_grants<'life0, 'async_trait>(
&'life0 self,
now: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Vec<RoleGrant>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn role_grants<'life0, 'async_trait>(
&'life0 self,
now: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<Vec<RoleGrant>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Grants that have not expired at now.
Sourcefn purge_before<'life0, 'async_trait>(
&'life0 self,
before: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn purge_before<'life0, 'async_trait>(
&'life0 self,
before: Timestamp,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Deletes messages, runs, tool calls, expired grants, dedupe marks and finished firings older
than before. Returns rows removed.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".