pub trait AttachmentSource: Send + Sync {
// Required method
fn fetch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
turn_id: &'life1 TurnId,
attachment: &'life2 AttachmentRef,
) -> Pin<Box<dyn Future<Output = Result<AttachmentContent, AttachmentError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
}Expand description
Where the bytes of a turn’s attachments come from.
§Why this is a port and not a store
AttachmentRef carries identity and metadata and says plainly that the
content is fetched by the application. That is deliberate: where a file
lives, how long it lives and who may read it are product decisions, and at
least one adopter’s answer is that the bytes exist for one turn and are never
written down. A library that stored them would be wrong for that deployment
and could not be made right by configuration.
§What it is for
Attachments already travel end to end at the plan level: a turn carries
them, the schema offers attachment_extraction as evidence, and an act can
name a file so an application’s own extractor fetches the bytes and rewrites
the command — which is how a document’s numbers reach a record without
passing through a model at all. That half needs nothing from here.
The other half is the model seeing the file. Without it a turn carrying a photograph reaches the model as a sentence mentioning one, so a domain extractor that returns nothing — a receipt photographed at an angle, a scan of a scan, a document that is not what the prompt asks for — has no fallback but “I cannot read this”, on the turn where the user has just done the work of taking the picture.
§What the runtime does with a failure
Nothing that costs the turn. The file is absent from the request, the user is told which ones were left out, and the writing stage is told too, so the prose cannot answer about a document nobody looked at.
Required Methods§
Sourcefn fetch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
turn_id: &'life1 TurnId,
attachment: &'life2 AttachmentRef,
) -> Pin<Box<dyn Future<Output = Result<AttachmentContent, AttachmentError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn fetch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
turn_id: &'life1 TurnId,
attachment: &'life2 AttachmentRef,
) -> Pin<Box<dyn Future<Output = Result<AttachmentContent, AttachmentError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
The bytes of one attachment of turn_id.
The whole AttachmentRef is passed rather than only its identifier,
because an implementation usually wants the media type or the size it
already declared, and asking it to look them up again would be the
library making a call cheaper for itself.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".