Skip to content
Merged

Dev #20

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
<p align="center">Built with Rust, Cortex Memory gives your AI agents a high-performance, persistent, and intelligent long-term memory.</p>

<p align="center">
<a href="https://crates.io/crates/cortex-mem-core"><img src="https://img.shields.io/crates/v/cortex-mem-core?color=44a1c9&label=Crates" /></a>
<a href="https://github.com/sopaco/cortex-mem/tree/main/litho.docs"><img alt="Litho Docs" src="https://img.shields.io/badge/Litho-Docs-green?logo=Gitbook&color=%23008a60">
</a>
<a href="https://raw.githubusercontent.com/sopaco/cortex-mem/refs/heads/main/assets/benchmark/cortex_mem_vs_langmem.png"><img alt="Benchmark" src="https://img.shields.io/badge/Benchmark-Perfect-green?logo=speedtest&labelColor=%231150af&color=%2300b89f"></a>
<a href="https://github.com/sopaco/cortex-mem/actions/workflows/rust.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/sopaco/cortex-mem/rust.yml?label=Build"></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg?label=LICENSE" /></a>
<a href="./LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-blue.svg?label=LICENSE" /></a>
</p>

<hr />
Expand Down
89 changes: 54 additions & 35 deletions cortex-mem-core/src/vector_store/qdrant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,29 @@ impl QdrantVectorStore {

// Store entities and topics as arrays
if !memory.metadata.entities.is_empty() {
let entities_json =
serde_json::to_string(&memory.metadata.entities).unwrap_or_default();
payload.insert("entities".to_string(), entities_json.into());
let entities_values: Vec<qdrant_client::qdrant::Value> =
memory.metadata.entities.iter()
.map(|entity| entity.to_string().into())
.collect();
payload.insert("entities".to_string(), qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::ListValue(
qdrant_client::qdrant::ListValue {
values: entities_values,
})),
});
}

if !memory.metadata.topics.is_empty() {
let topics_json = serde_json::to_string(&memory.metadata.topics).unwrap_or_default();
payload.insert("topics".to_string(), topics_json.into());
let topics_values: Vec<qdrant_client::qdrant::Value> =
memory.metadata.topics.iter()
.map(|topic| topic.to_string().into())
.collect();
payload.insert("topics".to_string(), qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::ListValue(
qdrant_client::qdrant::ListValue {
values: topics_values,
})),
});
}

// Custom metadata
Expand Down Expand Up @@ -278,25 +293,15 @@ impl QdrantVectorStore {
// Filter by topics - check if any of the requested topics are present
if let Some(topics) = &filters.topics {
if !topics.is_empty() {
let topic_conditions: Vec<Condition> = topics
.iter()
.map(|topic| Condition {
for topic in topics {
conditions.push(Condition {
condition_one_of: Some(condition::ConditionOneOf::Field(FieldCondition {
key: "topics".to_string(),
r#match: Some(Match {
match_value: Some(r#match::MatchValue::Text(topic.clone())),
match_value: Some(r#match::MatchValue::Keyword(topic.clone())),
}),
..Default::default()
})),
})
.collect();

if !topic_conditions.is_empty() {
conditions.push(Condition {
condition_one_of: Some(condition::ConditionOneOf::Filter(Filter {
should: topic_conditions,
..Default::default()
})),
});
}
}
Expand All @@ -305,25 +310,15 @@ impl QdrantVectorStore {
// Filter by entities - check if any of the requested entities are present
if let Some(entities) = &filters.entities {
if !entities.is_empty() {
let entity_conditions: Vec<Condition> = entities
.iter()
.map(|entity| Condition {
for entity in entities {
conditions.push(Condition {
condition_one_of: Some(condition::ConditionOneOf::Field(FieldCondition {
key: "entities".to_string(),
r#match: Some(Match {
match_value: Some(r#match::MatchValue::Text(entity.clone())),
match_value: Some(r#match::MatchValue::Keyword(entity.clone())),
}),
..Default::default()
})),
})
.collect();

if !entity_conditions.is_empty() {
conditions.push(Condition {
condition_one_of: Some(condition::ConditionOneOf::Filter(Filter {
should: entity_conditions,
..Default::default()
})),
});
}
}
Expand Down Expand Up @@ -548,22 +543,46 @@ impl QdrantVectorStore {
entities: payload
.get("entities")
.and_then(|v| match v {
qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::ListValue(list)),
} => {
Some(list.values.iter().filter_map(|val| match val {
qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::StringValue(s)),
} => Some(s.clone()),
_ => None,
}).collect::<Vec<String>>())
},
qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::StringValue(s)),
} => Some(s.as_str()),
} => {
// Backward compatibility: parse JSON string format
serde_json::from_str(s).ok()
},
_ => None,
})
.and_then(|s| serde_json::from_str(s).ok())
.unwrap_or_default(),
topics: payload
.get("topics")
.and_then(|v| match v {
qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::ListValue(list)),
} => {
Some(list.values.iter().filter_map(|val| match val {
qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::StringValue(s)),
} => Some(s.clone()),
_ => None,
}).collect::<Vec<String>>())
},
qdrant_client::qdrant::Value {
kind: Some(qdrant_client::qdrant::value::Kind::StringValue(s)),
} => Some(s.as_str()),
} => {
// Backward compatibility: parse JSON string format
serde_json::from_str(s).ok()
},
_ => None,
})
.and_then(|s| serde_json::from_str(s).ok())
.unwrap_or_default(),
custom,
};
Expand Down
Loading