a3s_memory/repository/
change.rs1use super::validation::{
2 validate_count, validate_required_text, MAX_CHANGE_OPERATIONS, MAX_IDENTIFIER_BYTES,
3};
4use super::{
5 EvidenceRef, MemoryNamespace, MemoryNode, MemoryNodeDraft, MemoryRelation,
6 MemoryRepositoryError, MemoryStatus, RevisionMode,
7};
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13#[serde(tag = "operation", rename_all = "snake_case")]
14pub enum MemoryOperation {
15 Create {
16 node: MemoryNodeDraft,
17 },
18 Activate {
19 node_id: String,
20 expected_revision: u64,
21 evidence: Vec<EvidenceRef>,
23 },
24 Corroborate {
25 node_id: String,
26 expected_revision: u64,
27 evidence: Vec<EvidenceRef>,
28 },
29 Revise {
30 node_id: String,
31 expected_revision: u64,
32 content: String,
33 mode: RevisionMode,
34 evidence: Vec<EvidenceRef>,
35 confidence: Option<f32>,
36 importance: Option<f32>,
37 },
38 AddRelation {
39 node_id: String,
40 expected_revision: u64,
41 relation: MemoryRelation,
42 },
43 RemoveRelation {
44 node_id: String,
45 expected_revision: u64,
46 relation: MemoryRelation,
47 },
48 SetStatus {
49 node_id: String,
50 expected_revision: u64,
51 status: MemoryStatus,
52 },
53}
54
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
57#[serde(rename_all = "camelCase")]
58pub struct MemoryChangeSet {
59 pub idempotency_key: String,
60 pub namespace: MemoryNamespace,
61 pub occurred_at: DateTime<Utc>,
62 pub operations: Vec<MemoryOperation>,
63}
64
65impl MemoryChangeSet {
66 pub fn new(
67 idempotency_key: impl Into<String>,
68 namespace: MemoryNamespace,
69 occurred_at: DateTime<Utc>,
70 operations: Vec<MemoryOperation>,
71 ) -> Self {
72 Self {
73 idempotency_key: idempotency_key.into(),
74 namespace,
75 occurred_at,
76 operations,
77 }
78 }
79
80 pub(crate) fn validate_shape(&self) -> Result<(), MemoryRepositoryError> {
81 self.namespace.validate()?;
82 validate_required_text(
83 "changeSet.idempotencyKey",
84 &self.idempotency_key,
85 MAX_IDENTIFIER_BYTES,
86 )?;
87 if self.operations.is_empty() {
88 return Err(MemoryRepositoryError::invalid(
89 "changeSet.operations",
90 "must contain at least one operation",
91 ));
92 }
93 validate_count(
94 "change-set operations",
95 self.operations.len(),
96 MAX_CHANGE_OPERATIONS,
97 )
98 }
99}
100
101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
103#[serde(rename_all = "camelCase")]
104pub struct MemoryChangeResult {
105 pub idempotency_key: String,
106 pub occurred_at: DateTime<Utc>,
107 pub nodes: Vec<MemoryNode>,
108}