Skip to main content

weavatrix_memory/extraction/
engine.rs

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