anamnesis_core/adapter.rs
1//! The `MemoryAdapter` trait every source connector implements.
2
3use async_trait::async_trait;
4use chrono::{DateTime, Utc};
5use futures::stream::BoxStream;
6use serde::{Deserialize, Serialize};
7
8use crate::error::Result;
9use crate::model::{AnamnesisRecord, SourceDescriptor};
10
11/// Options passed to `MemoryAdapter::scan`.
12#[derive(Debug, Clone, Default)]
13pub struct ScanOpts {
14 /// If set, only records modified since this time are returned.
15 pub since: Option<DateTime<Utc>>,
16 /// If true, skip the dedup hash check and re-emit everything.
17 pub full: bool,
18}
19
20/// Options passed to `MemoryAdapter::watch`.
21#[derive(Debug, Clone, Default)]
22pub struct WatchOpts {
23 /// Polling interval, if the adapter falls back to polling.
24 pub poll_interval: Option<std::time::Duration>,
25}
26
27/// A raw record as produced by an adapter scan, before normalization.
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct RawRecord {
30 /// Source-native id.
31 pub native_id: String,
32 /// Optional path or DB reference.
33 pub native_path: Option<String>,
34 /// Opaque adapter-specific payload.
35 pub payload: serde_json::Value,
36 /// When the record was captured.
37 pub captured_at: DateTime<Utc>,
38}
39
40/// A change event surfaced by `MemoryAdapter::watch`.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub enum RawDelta {
43 /// A new or updated raw record.
44 Upsert(RawRecord),
45 /// A record was removed from the source.
46 Delete {
47 /// Native id of the removed record.
48 native_id: String,
49 },
50}
51
52/// Adapter health status.
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct HealthStatus {
55 /// Is the adapter usable right now?
56 pub ok: bool,
57 /// Human-readable detail.
58 pub detail: String,
59}
60
61/// The contract every memory source connector implements.
62#[async_trait]
63pub trait MemoryAdapter: Send + Sync {
64 /// Self-describing metadata.
65 fn descriptor(&self) -> SourceDescriptor;
66
67 /// Stream raw records from the source.
68 fn scan<'a>(&'a self, opts: ScanOpts) -> BoxStream<'a, Result<RawRecord>>;
69
70 /// Optional incremental watcher. Default: not supported.
71 fn watch<'a>(&'a self, _opts: WatchOpts) -> Option<BoxStream<'a, Result<RawDelta>>> {
72 None
73 }
74
75 /// Normalize a raw record into one or more canonical records.
76 ///
77 /// Returning multiple records is allowed when one source row maps to
78 /// several memories (e.g. one conversation → multiple extracted facts).
79 fn normalize(&self, raw: RawRecord) -> Result<Vec<AnamnesisRecord>>;
80
81 /// Cheap credential / path / connectivity check.
82 async fn health(&self) -> HealthStatus;
83}