Skip to main content

weavatrix_memory/extraction/engine/
mod.rs

1mod build;
2mod validation;
3
4use super::{EntityLinker, ExtractionInput, ExtractionPlan, ExtractionProvider, LinkPolicy};
5use crate::{
6    domain::MemoryView,
7    error::{MemoryError, Result},
8};
9
10#[derive(Debug, Clone, Copy, Default)]
11pub struct AutoExtractionEngine {
12    policy: LinkPolicy,
13}
14
15impl AutoExtractionEngine {
16    #[must_use]
17    pub const fn new(policy: LinkPolicy) -> Self {
18        Self { policy }
19    }
20
21    /// Extracts, links, and converts one source into an idempotent event plan.
22    ///
23    /// # Errors
24    ///
25    /// Rejects invalid provider output, unsafe ambiguity, provenance mismatch,
26    /// identifier collisions, and invalid temporal facts.
27    pub fn plan<P: ExtractionProvider>(
28        &self,
29        provider: &P,
30        input: &ExtractionInput,
31        view: &MemoryView,
32    ) -> Result<ExtractionPlan> {
33        let linker = EntityLinker::from_view(view)?;
34        self.plan_with_linker(provider, input, &linker)
35    }
36
37    /// Uses a reusable linker for batch extraction against one projection.
38    ///
39    /// # Errors
40    ///
41    /// Has the same validation contract as [`Self::plan`].
42    pub fn plan_with_linker<P: ExtractionProvider>(
43        &self,
44        provider: &P,
45        input: &ExtractionInput,
46        linker: &EntityLinker,
47    ) -> Result<ExtractionPlan> {
48        input.validate()?;
49        crate::domain::validate_text("extraction.provider", provider.name())?;
50        let output = provider.extract(input).map_err(|error| {
51            if error.provider == provider.name() {
52                MemoryError::from(error)
53            } else {
54                MemoryError::Extraction {
55                    provider: provider.name().to_owned(),
56                    message: "provider error identity does not match provider name".to_owned(),
57                }
58            }
59        })?;
60        validation::validate_output(&output, input)?;
61        build::build_plan(self.policy, provider.name(), input, linker, &output)
62    }
63}