Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.redis.agentmemory.models.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.List;

/**
* Filter for tag-style string fields (user_id, session_id, namespace, topics, entities).
* Match the server-side TagFilter; supports eq, ne, any, all, and startswith operators.
*
* <p>
* Example — match any of several user IDs in one search:
* <pre>{@code
* SearchRequest.builder()
* .userId(TagFilter.any("user-123", "__account__"))
* .build()
* }</pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class TagFilter {

@Nullable
private String eq;

@Nullable
private String ne;

@Nullable
@JsonProperty("any")
private List<String> any;

@Nullable
@JsonProperty("all")
private List<String> all;

@Nullable
private String startswith;

private TagFilter() {}

public static TagFilter eq(@NotNull String value) {
TagFilter f = new TagFilter();
f.eq = value;
return f;
}

public static TagFilter ne(@NotNull String value) {
TagFilter f = new TagFilter();
f.ne = value;
return f;
}

public static TagFilter any(@NotNull List<String> values) {
if (values.isEmpty()) {
throw new IllegalArgumentException("any cannot be an empty list");
}
TagFilter f = new TagFilter();
f.any = List.copyOf(values);
return f;
}

public static TagFilter any(@NotNull String... values) {
return any(Arrays.asList(values));
}

public static TagFilter all(@NotNull List<String> values) {
if (values.isEmpty()) {
throw new IllegalArgumentException("all cannot be an empty list");
}
TagFilter f = new TagFilter();
f.all = List.copyOf(values);
return f;
}

public static TagFilter all(@NotNull String... values) {
return all(Arrays.asList(values));
}
Comment thread
cursor[bot] marked this conversation as resolved.

public static TagFilter startsWith(@NotNull String prefix) {
if (prefix.isEmpty()) {
throw new IllegalArgumentException("startswith cannot be an empty string");
}
TagFilter f = new TagFilter();
f.startswith = prefix;
return f;
}

@Nullable
public String getEq() { return eq; }

@Nullable
public String getNe() { return ne; }

@Nullable
public List<String> getAny() { return any; }

@Nullable
public List<String> getAll() { return all; }

@Nullable
public String getStartswith() { return startswith; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.redis.agentmemory.models.common.TagFilter;
import org.jetbrains.annotations.Nullable;

import java.util.List;
Expand Down Expand Up @@ -29,20 +30,20 @@ public class SearchRequest {

@Nullable
@JsonProperty("session_id")
private String sessionId;
private TagFilter sessionId;

@Nullable
private String namespace;
private TagFilter namespace;

@Nullable
private List<String> topics;
private TagFilter topics;

@Nullable
private List<String> entities;
private TagFilter entities;

@Nullable
@JsonProperty("user_id")
private String userId;
private TagFilter userId;

@Nullable
@JsonProperty("distance_threshold")
Expand Down Expand Up @@ -129,47 +130,69 @@ public void setTextScorer(@Nullable String textScorer) {
}

@Nullable
public String getSessionId() {
public TagFilter getSessionId() {
return sessionId;
}

public void setSessionId(@Nullable String sessionId) {
this.sessionId = sessionId != null ? TagFilter.eq(sessionId) : null;
}

public void setSessionId(@Nullable TagFilter sessionId) {
this.sessionId = sessionId;
}

@Nullable
public String getNamespace() {
public TagFilter getNamespace() {
return namespace;
}

public void setNamespace(@Nullable String namespace) {
this.namespace = namespace != null ? TagFilter.eq(namespace) : null;
}

public void setNamespace(@Nullable TagFilter namespace) {
this.namespace = namespace;
}

@Nullable
public List<String> getTopics() {
public TagFilter getTopics() {
return topics;
}

public void setTopics(@Nullable List<String> topics) {
var present = topics != null && !topics.isEmpty();
this.topics = present ? TagFilter.any(topics) : null;
}

public void setTopics(@Nullable TagFilter topics) {
this.topics = topics;
}

@Nullable
public List<String> getEntities() {
public TagFilter getEntities() {
return entities;
}

public void setEntities(@Nullable List<String> entities) {
var present = entities != null && !entities.isEmpty();
this.entities = present ? TagFilter.any(entities) : null;
}

public void setEntities(@Nullable TagFilter entities) {
this.entities = entities;
}

@Nullable
public String getUserId() {
public TagFilter getUserId() {
return userId;
}

public void setUserId(@Nullable String userId) {
this.userId = userId != null ? TagFilter.eq(userId) : null;
}

public void setUserId(@Nullable TagFilter userId) {
this.userId = userId;
}

Expand Down Expand Up @@ -286,11 +309,11 @@ public String toString() {
", searchMode='" + searchMode + '\'' +
", hybridAlpha=" + hybridAlpha +
", textScorer='" + textScorer + '\'' +
", sessionId='" + sessionId + '\'' +
", namespace='" + namespace + '\'' +
", sessionId=" + sessionId +
", namespace=" + namespace +
", topics=" + topics +
", entities=" + entities +
", userId='" + userId + '\'' +
", userId=" + userId +
", distanceThreshold=" + distanceThreshold +
", extractionStrategy='" + extractionStrategy + '\'' +
", limit=" + limit +
Expand Down Expand Up @@ -341,26 +364,53 @@ public Builder textScorer(@Nullable String textScorer) {
}

public Builder sessionId(@Nullable String sessionId) {
request.sessionId = sessionId != null ? TagFilter.eq(sessionId) : null;
return this;
}

public Builder sessionId(@Nullable TagFilter sessionId) {
request.sessionId = sessionId;
return this;
}

public Builder namespace(@Nullable String namespace) {
request.namespace = namespace != null ? TagFilter.eq(namespace) : null;
return this;
}

public Builder namespace(@Nullable TagFilter namespace) {
request.namespace = namespace;
return this;
}

public Builder topics(@Nullable List<String> topics) {
var present = topics != null && !topics.isEmpty();
request.topics = present ? TagFilter.any(topics) : null;
return this;
}

public Builder topics(@Nullable TagFilter topics) {
request.topics = topics;
return this;
}

public Builder entities(@Nullable List<String> entities) {
var present = entities != null && !entities.isEmpty();
request.entities = present ? TagFilter.any(entities) : null;
return this;
}

public Builder entities(@Nullable TagFilter entities) {
request.entities = entities;
return this;
}

public Builder userId(@Nullable String userId) {
request.userId = userId != null ? TagFilter.eq(userId) : null;
return this;
}

public Builder userId(@Nullable TagFilter userId) {
request.userId = userId;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.redis.agentmemory.exceptions.MemoryClientException;
import com.redis.agentmemory.models.common.AckResponse;
import com.redis.agentmemory.models.common.TagFilter;
import com.redis.agentmemory.models.longtermemory.*;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -86,22 +87,22 @@ public MemoryRecordResults searchLongTermMemories(@NotNull SearchRequest request

// Add filters if present
if (request.getSessionId() != null) {
payload.put("session_id", Map.of("eq", request.getSessionId()));
payload.put("session_id", request.getSessionId());
}
if (request.getUserId() != null) {
payload.put("user_id", Map.of("eq", request.getUserId()));
payload.put("user_id", request.getUserId());
}
if (request.getNamespace() != null) {
payload.put("namespace", Map.of("eq", request.getNamespace()));
payload.put("namespace", request.getNamespace());
} else if (defaultNamespace != null) {
payload.put("namespace", Map.of("eq", defaultNamespace));
payload.put("namespace", TagFilter.eq(defaultNamespace));
}

if (request.getTopics() != null && !request.getTopics().isEmpty()) {
payload.put("topics", Map.of("any", request.getTopics()));
if (request.getTopics() != null) {
payload.put("topics", request.getTopics());
}
if (request.getEntities() != null && !request.getEntities().isEmpty()) {
payload.put("entities", Map.of("any", request.getEntities()));
if (request.getEntities() != null) {
payload.put("entities", request.getEntities());
}
if (request.getDistanceThreshold() != null) {
payload.put("distance_threshold", request.getDistanceThreshold());
Expand Down
Loading