lance-context 0.2.4__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lance_context-0.2.4 → lance_context-0.3.0}/PKG-INFO +7 -6
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context/Cargo.toml +2 -2
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context-core/Cargo.toml +11 -8
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context-core/src/lib.rs +5 -2
- lance_context-0.3.0/crates/lance-context-core/src/record.rs +197 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context-core/src/serde.rs +1 -0
- lance_context-0.3.0/crates/lance-context-core/src/store.rs +2016 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/pyproject.toml +8 -6
- {lance_context-0.2.4 → lance_context-0.3.0}/python/Cargo.toml +2 -1
- lance_context-0.3.0/python/lance_context/__init__.py +9 -0
- lance_context-0.3.0/python/lance_context/api.py +687 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/python/python/tests/test_context.py +13 -0
- lance_context-0.3.0/python/src/lib.rs +741 -0
- lance_context-0.3.0/python/tests/test_add_many.py +67 -0
- lance_context-0.3.0/python/tests/test_async.py +177 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/python/tests/test_compaction.py +8 -5
- lance_context-0.3.0/python/tests/test_delete.py +97 -0
- lance_context-0.3.0/python/tests/test_external_id.py +50 -0
- lance_context-0.3.0/python/tests/test_gcs_persistence.py +90 -0
- lance_context-0.3.0/python/tests/test_id_index.py +84 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/python/tests/test_persistence.py +125 -10
- lance_context-0.3.0/python/tests/test_search.py +670 -0
- lance_context-0.3.0/python/tests/test_storage_options.py +176 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/python/uv.lock +669 -33
- lance_context-0.2.4/crates/lance-context-core/src/record.rs +0 -33
- lance_context-0.2.4/crates/lance-context-core/src/store.rs +0 -953
- lance_context-0.2.4/python/lance_context/__init__.py +0 -5
- lance_context-0.2.4/python/lance_context/api.py +0 -343
- lance_context-0.2.4/python/src/lib.rs +0 -406
- lance_context-0.2.4/python/tests/test_search.py +0 -292
- {lance_context-0.2.4 → lance_context-0.3.0}/Cargo.toml +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/LICENSE +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/README.md +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context/README.md +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context/src/lib.rs +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context-core/README.md +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/crates/lance-context-core/src/context.rs +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/python/Cargo.lock +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/python/LICENSE +0 -0
- {lance_context-0.2.4 → lance_context-0.3.0}/python/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lance-context
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Science/Research
|
|
6
6
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -14,15 +14,16 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Programming Language :: Rust
|
|
16
16
|
Classifier: Topic :: Scientific/Engineering
|
|
17
|
-
Requires-Dist: pylance==
|
|
18
|
-
Requires-Dist: lancedb==0.
|
|
19
|
-
Requires-Dist: lance-namespace==0.
|
|
20
|
-
Requires-Dist: lance-graph==0.4
|
|
17
|
+
Requires-Dist: pylance==7.0.0
|
|
18
|
+
Requires-Dist: lancedb==0.27.1
|
|
19
|
+
Requires-Dist: lance-namespace==0.7.7
|
|
20
|
+
Requires-Dist: lance-graph==0.5.4
|
|
21
21
|
Requires-Dist: ruff ; extra == 'dev'
|
|
22
22
|
Requires-Dist: pyright ; extra == 'dev'
|
|
23
23
|
Requires-Dist: pytest ; extra == 'tests'
|
|
24
|
+
Requires-Dist: pytest-asyncio ; extra == 'tests'
|
|
24
25
|
Requires-Dist: ruff ; extra == 'tests'
|
|
25
|
-
Requires-Dist: moto[s3] ; extra == 'tests'
|
|
26
|
+
Requires-Dist: moto[s3,server] ; extra == 'tests'
|
|
26
27
|
Requires-Dist: boto3 ; extra == 'tests'
|
|
27
28
|
Requires-Dist: botocore ; extra == 'tests'
|
|
28
29
|
Provides-Extra: dev
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "lance-context"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
authors = ["Lance Devs <dev@lancedb.com>"]
|
|
@@ -9,4 +9,4 @@ description = "Public re-export crate for lance-context bindings"
|
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
|
|
11
11
|
[dependencies]
|
|
12
|
-
lance-context-core = { version = "0.
|
|
12
|
+
lance-context-core = { version = "0.3.0", path = "../lance-context-core" }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "lance-context-core"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
authors = ["Lance Devs <dev@lancedb.com>"]
|
|
@@ -11,18 +11,21 @@ keywords = ["context", "multimodal", "lance", "agents", "storage"]
|
|
|
11
11
|
categories = ["database", "data-structures", "science"]
|
|
12
12
|
|
|
13
13
|
[dependencies]
|
|
14
|
-
arrow-array = "
|
|
15
|
-
arrow-ipc = "
|
|
16
|
-
arrow-schema = "
|
|
14
|
+
arrow-array = "58"
|
|
15
|
+
arrow-ipc = "58"
|
|
16
|
+
arrow-schema = "58"
|
|
17
17
|
chrono = { version = "0.4", default-features = false, features = ["clock"] }
|
|
18
|
-
lance = "
|
|
19
|
-
|
|
20
|
-
lance-namespace = "
|
|
21
|
-
|
|
18
|
+
lance = "7.0.0"
|
|
19
|
+
lance-index = "7.0.0"
|
|
20
|
+
lance-namespace = "7.0.0"
|
|
21
|
+
lancedb = "0.30.0"
|
|
22
|
+
lance-graph = "0.5.4"
|
|
22
23
|
serde = { version = "1", features = ["derive"] }
|
|
24
|
+
serde_json = "1"
|
|
23
25
|
futures = "0.3"
|
|
24
26
|
tokio = { version = "1", features = ["sync", "time"] }
|
|
25
27
|
tracing = "0.1"
|
|
28
|
+
uuid = { version = "1.20.0", features = ["v4", "v5"] }
|
|
26
29
|
|
|
27
30
|
[dev-dependencies]
|
|
28
31
|
tempfile = "3"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//! Core types for the lance-context storage layer.
|
|
2
|
+
#![recursion_limit = "256"]
|
|
2
3
|
|
|
3
4
|
mod context;
|
|
4
5
|
mod record;
|
|
@@ -6,8 +7,10 @@ pub mod serde;
|
|
|
6
7
|
mod store;
|
|
7
8
|
|
|
8
9
|
pub use context::{Context, ContextEntry, Snapshot};
|
|
9
|
-
pub use record::{ContextRecord, SearchResult, StateMetadata};
|
|
10
|
-
pub use store::{
|
|
10
|
+
pub use record::{ContextRecord, MetadataFilter, RecordFilters, SearchResult, StateMetadata};
|
|
11
|
+
pub use store::{
|
|
12
|
+
CompactionConfig, CompactionStats, ContextStore, ContextStoreOptions, IdIndexType,
|
|
13
|
+
};
|
|
11
14
|
|
|
12
15
|
// Re-export CompactionMetrics from lance for Python bindings
|
|
13
16
|
pub use lance::dataset::optimize::CompactionMetrics;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
use chrono::{DateTime, Utc};
|
|
2
|
+
use serde_json::Value;
|
|
3
|
+
use std::collections::HashMap;
|
|
4
|
+
|
|
5
|
+
use crate::serde::CONTENT_TYPE_TOMBSTONE;
|
|
6
|
+
|
|
7
|
+
/// Structured metadata captured alongside each context entry.
|
|
8
|
+
#[derive(Debug, Clone, Default)]
|
|
9
|
+
pub struct StateMetadata {
|
|
10
|
+
pub step: Option<i32>,
|
|
11
|
+
pub active_plan_id: Option<String>,
|
|
12
|
+
pub tokens_used: Option<i32>,
|
|
13
|
+
pub custom: Option<String>,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// User-facing representation of a context entry written to storage.
|
|
17
|
+
#[derive(Debug, Clone)]
|
|
18
|
+
pub struct ContextRecord {
|
|
19
|
+
pub id: String,
|
|
20
|
+
pub external_id: Option<String>,
|
|
21
|
+
pub run_id: String,
|
|
22
|
+
pub bot_id: Option<String>,
|
|
23
|
+
pub session_id: Option<String>,
|
|
24
|
+
pub created_at: DateTime<Utc>,
|
|
25
|
+
pub role: String,
|
|
26
|
+
pub state_metadata: Option<StateMetadata>,
|
|
27
|
+
pub metadata: Option<Value>,
|
|
28
|
+
pub content_type: String,
|
|
29
|
+
pub text_payload: Option<String>,
|
|
30
|
+
pub binary_payload: Option<Vec<u8>>,
|
|
31
|
+
pub embedding: Option<Vec<f32>>,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
impl ContextRecord {
|
|
35
|
+
#[must_use]
|
|
36
|
+
pub fn is_tombstone(&self) -> bool {
|
|
37
|
+
self.content_type == CONTENT_TYPE_TOMBSTONE
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Result returned from a vector similarity search.
|
|
42
|
+
#[derive(Debug, Clone)]
|
|
43
|
+
pub struct SearchResult {
|
|
44
|
+
pub record: ContextRecord,
|
|
45
|
+
pub distance: f32,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Metadata matching operation for filtered retrieval.
|
|
49
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
50
|
+
pub enum MetadataFilter {
|
|
51
|
+
Equals(Value),
|
|
52
|
+
Contains(Value),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// Filters applied to records before list pagination or search ranking.
|
|
56
|
+
#[derive(Debug, Clone, Default, PartialEq)]
|
|
57
|
+
pub struct RecordFilters {
|
|
58
|
+
pub bot_id: Option<String>,
|
|
59
|
+
pub session_id: Option<String>,
|
|
60
|
+
pub role: Option<String>,
|
|
61
|
+
pub content_type: Option<String>,
|
|
62
|
+
pub created_at_start: Option<DateTime<Utc>>,
|
|
63
|
+
pub created_at_end: Option<DateTime<Utc>>,
|
|
64
|
+
pub metadata: HashMap<String, MetadataFilter>,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
impl RecordFilters {
|
|
68
|
+
#[must_use]
|
|
69
|
+
pub fn is_empty(&self) -> bool {
|
|
70
|
+
self.bot_id.is_none()
|
|
71
|
+
&& self.session_id.is_none()
|
|
72
|
+
&& self.role.is_none()
|
|
73
|
+
&& self.content_type.is_none()
|
|
74
|
+
&& self.created_at_start.is_none()
|
|
75
|
+
&& self.created_at_end.is_none()
|
|
76
|
+
&& self.metadata.is_empty()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[must_use]
|
|
80
|
+
pub fn matches(&self, record: &ContextRecord) -> bool {
|
|
81
|
+
if self
|
|
82
|
+
.bot_id
|
|
83
|
+
.as_deref()
|
|
84
|
+
.is_some_and(|value| record.bot_id.as_deref() != Some(value))
|
|
85
|
+
{
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if self
|
|
89
|
+
.session_id
|
|
90
|
+
.as_deref()
|
|
91
|
+
.is_some_and(|value| record.session_id.as_deref() != Some(value))
|
|
92
|
+
{
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if self
|
|
96
|
+
.role
|
|
97
|
+
.as_deref()
|
|
98
|
+
.is_some_and(|value| record.role != value)
|
|
99
|
+
{
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
if self
|
|
103
|
+
.content_type
|
|
104
|
+
.as_deref()
|
|
105
|
+
.is_some_and(|value| record.content_type != value)
|
|
106
|
+
{
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if self
|
|
110
|
+
.created_at_start
|
|
111
|
+
.is_some_and(|start| record.created_at < start)
|
|
112
|
+
{
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if self
|
|
116
|
+
.created_at_end
|
|
117
|
+
.is_some_and(|end| record.created_at > end)
|
|
118
|
+
{
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
self.metadata.iter().all(|(key, filter)| {
|
|
123
|
+
let Some(Value::Object(metadata)) = &record.metadata else {
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
let Some(value) = metadata.get(key) else {
|
|
127
|
+
return false;
|
|
128
|
+
};
|
|
129
|
+
match filter {
|
|
130
|
+
MetadataFilter::Equals(expected) => value == expected,
|
|
131
|
+
MetadataFilter::Contains(expected) => metadata_contains(value, expected),
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fn metadata_contains(value: &Value, expected: &Value) -> bool {
|
|
138
|
+
match (value, expected) {
|
|
139
|
+
(Value::Array(items), expected) => items.iter().any(|item| item == expected),
|
|
140
|
+
(Value::String(value), Value::String(expected)) => value.contains(expected),
|
|
141
|
+
_ => false,
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
#[cfg(test)]
|
|
146
|
+
mod tests {
|
|
147
|
+
use super::*;
|
|
148
|
+
use chrono::TimeZone;
|
|
149
|
+
use serde_json::json;
|
|
150
|
+
|
|
151
|
+
fn record() -> ContextRecord {
|
|
152
|
+
ContextRecord {
|
|
153
|
+
id: "rec-1".to_string(),
|
|
154
|
+
external_id: None,
|
|
155
|
+
run_id: "run-1".to_string(),
|
|
156
|
+
bot_id: Some("support-bot".to_string()),
|
|
157
|
+
session_id: Some("incident-1".to_string()),
|
|
158
|
+
created_at: Utc.with_ymd_and_hms(2026, 6, 9, 3, 0, 0).unwrap(),
|
|
159
|
+
role: "assistant".to_string(),
|
|
160
|
+
state_metadata: None,
|
|
161
|
+
metadata: Some(json!({
|
|
162
|
+
"scope": "team",
|
|
163
|
+
"tags": ["runbook", "ownership"],
|
|
164
|
+
"confidence": 0.92
|
|
165
|
+
})),
|
|
166
|
+
content_type: "text/plain".to_string(),
|
|
167
|
+
text_payload: Some("hello".to_string()),
|
|
168
|
+
binary_payload: None,
|
|
169
|
+
embedding: None,
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#[test]
|
|
174
|
+
fn filters_match_builtin_fields_timestamps_and_metadata() {
|
|
175
|
+
let mut filters = RecordFilters {
|
|
176
|
+
bot_id: Some("support-bot".to_string()),
|
|
177
|
+
session_id: Some("incident-1".to_string()),
|
|
178
|
+
role: Some("assistant".to_string()),
|
|
179
|
+
content_type: Some("text/plain".to_string()),
|
|
180
|
+
created_at_start: Some(Utc.with_ymd_and_hms(2026, 6, 9, 2, 0, 0).unwrap()),
|
|
181
|
+
created_at_end: Some(Utc.with_ymd_and_hms(2026, 6, 9, 4, 0, 0).unwrap()),
|
|
182
|
+
metadata: HashMap::new(),
|
|
183
|
+
};
|
|
184
|
+
filters
|
|
185
|
+
.metadata
|
|
186
|
+
.insert("scope".to_string(), MetadataFilter::Equals(json!("team")));
|
|
187
|
+
filters.metadata.insert(
|
|
188
|
+
"tags".to_string(),
|
|
189
|
+
MetadataFilter::Contains(json!("runbook")),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
assert!(filters.matches(&record()));
|
|
193
|
+
|
|
194
|
+
filters.session_id = Some("other".to_string());
|
|
195
|
+
assert!(!filters.matches(&record()));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
|
|
5
5
|
|
|
6
6
|
pub const CONTENT_TYPE_TEXT: &str = "text/plain";
|
|
7
7
|
pub const CONTENT_TYPE_ARROW_STREAM: &str = "application/vnd.apache.arrow.stream";
|
|
8
|
+
pub const CONTENT_TYPE_TOMBSTONE: &str = "application/vnd.lance-context.tombstone";
|
|
8
9
|
|
|
9
10
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
10
11
|
pub struct SerializedContent {
|