-
Notifications
You must be signed in to change notification settings - Fork 104
[Agentic Search] Convert agentic query translator processor to system-generated processor #1568
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,6 +49,7 @@ public final class AgenticSearchQueryBuilder extends AbstractQueryBuilder<Agenti | |
| public static final String NAME = "agentic"; | ||
| public static final ParseField QUERY_TEXT_FIELD = new ParseField("query_text"); | ||
| public static final ParseField QUERY_FIELDS = new ParseField("query_fields"); | ||
| public static final ParseField AGENT_ID_FIELD = new ParseField("agent_id"); | ||
|
|
||
| // Regex patterns for sanitizing query text | ||
| private static final String SYSTEM_INSTRUCTION_PATTERN = "(?i)\\b(system|instruction|prompt)\\s*:"; | ||
|
|
@@ -57,6 +58,7 @@ public final class AgenticSearchQueryBuilder extends AbstractQueryBuilder<Agenti | |
| private static final int MAX_QUERY_LENGTH = 1000; | ||
| public String queryText; | ||
| public List<String> queryFields; | ||
| public String agentId; | ||
|
|
||
| // setting accessor to retrieve agentic search feature flag | ||
| private static NeuralSearchSettingsAccessor SETTINGS_ACCESSOR; | ||
|
|
@@ -69,6 +71,7 @@ public AgenticSearchQueryBuilder(StreamInput in) throws IOException { | |
| super(in); | ||
| this.queryText = in.readString(); | ||
| this.queryFields = in.readOptionalStringList(); | ||
| this.agentId = in.readOptionalString(); | ||
| } | ||
|
|
||
| public String getQueryText() { | ||
|
|
@@ -79,6 +82,10 @@ public List<String> getQueryFields() { | |
| return queryFields; | ||
| } | ||
|
|
||
| public String getAgentId() { | ||
| return agentId; | ||
| } | ||
|
|
||
| @Override | ||
| protected void doWriteTo(StreamOutput out) throws IOException { | ||
| // feature flag check | ||
|
|
@@ -89,6 +96,7 @@ protected void doWriteTo(StreamOutput out) throws IOException { | |
| } | ||
| out.writeString(this.queryText); | ||
| out.writeOptionalStringCollection(this.queryFields); | ||
| out.writeOptionalString(this.agentId); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -106,6 +114,9 @@ protected void doXContent(XContentBuilder xContentBuilder, Params params) throws | |
| if (Objects.nonNull(queryFields) && !queryFields.isEmpty()) { | ||
| xContentBuilder.field(QUERY_FIELDS.getPreferredName(), queryFields); | ||
| } | ||
| if (Objects.nonNull(agentId)) { | ||
| xContentBuilder.field(AGENT_ID_FIELD.getPreferredName(), agentId); | ||
| } | ||
| xContentBuilder.endObject(); | ||
| } | ||
|
|
||
|
|
@@ -115,6 +126,7 @@ protected void doXContent(XContentBuilder xContentBuilder, Params params) throws | |
| * { | ||
| * "agentic": { | ||
| * "query_text": "string", | ||
| * "agent_id": "string" | ||
| * "query_fields": ["string", "string"..] | ||
| * } | ||
| * } | ||
|
|
@@ -133,6 +145,8 @@ public static AgenticSearchQueryBuilder fromXContent(XContentParser parser) thro | |
| } else if (token.isValue()) { | ||
| if (QUERY_TEXT_FIELD.match(currentFieldName, parser.getDeprecationHandler())) { | ||
| agenticSearchQueryBuilder.queryText = parser.text(); | ||
| } else if (AGENT_ID_FIELD.match(currentFieldName, parser.getDeprecationHandler())) { | ||
| agenticSearchQueryBuilder.agentId = parser.text(); | ||
| } else { | ||
| throw new ParsingException(parser.getTokenLocation(), "Unknown field [" + currentFieldName + "]"); | ||
| } | ||
|
|
@@ -157,6 +171,9 @@ public static AgenticSearchQueryBuilder fromXContent(XContentParser parser) thro | |
| throw new ParsingException(parser.getTokenLocation(), "[" + QUERY_TEXT_FIELD.getPreferredName() + "] is required"); | ||
| } | ||
|
|
||
| if (agenticSearchQueryBuilder.agentId == null || agenticSearchQueryBuilder.agentId.trim().isEmpty()) { | ||
| throw new ParsingException(parser.getTokenLocation(), "[" + AGENT_ID_FIELD.getPreferredName() + "] is required"); | ||
| } | ||
| // Sanitize query text to prevent prompt injection | ||
| agenticSearchQueryBuilder.queryText = sanitizeQueryText(agenticSearchQueryBuilder.queryText); | ||
|
|
||
|
|
@@ -171,8 +188,21 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws | |
|
|
||
| @Override | ||
| protected Query doToQuery(QueryShardContext context) throws IOException { | ||
| // This should not be reached if the system-generated processor is working correctly | ||
| if (agentId == null || agentId.trim().isEmpty()) { | ||
| throw new IllegalStateException("Agentic search query requires an agent_id. Provide agent_id in the query."); | ||
| } | ||
| // Check if the system-generated processor is enabled | ||
| if (!SETTINGS_ACCESSOR.isSystemGenerateProcessorEnabled("agentic_query_translator")) { | ||
| throw new IllegalStateException( | ||
| "Agentic search requires the agentic_query_translator system processor to be enabled. " | ||
| + "Add 'agentic_query_translator' to the 'cluster.search.enabled_system_generated_factories' setting." | ||
| ); | ||
| } | ||
|
|
||
| throw new IllegalStateException( | ||
| "Agentic search query must be used as top-level query, not nested inside other queries. Should be used with agentic_query_translator search processor" | ||
| "Agentic search query must be processed by the agentic_query_translator system processor before query execution. " | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can add a validation in the AgenticSearchQueryBuilder to ensure the processor is enabled in the cluster setting
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added a new generic method |
||
| + "Ensure the neural search plugin is properly installed and the agentic search feature is enabled." | ||
| ); | ||
| } | ||
|
|
||
|
|
@@ -183,12 +213,13 @@ protected boolean doEquals(AgenticSearchQueryBuilder obj) { | |
| EqualsBuilder equalsBuilder = new EqualsBuilder(); | ||
| equalsBuilder.append(queryText, obj.queryText); | ||
| equalsBuilder.append(queryFields, obj.queryFields); | ||
| equalsBuilder.append(agentId, obj.agentId); | ||
| return equalsBuilder.isEquals(); | ||
| } | ||
|
|
||
| @Override | ||
| protected int doHashCode() { | ||
| return new HashCodeBuilder().append(queryText).append(queryFields).toHashCode(); | ||
| return new HashCodeBuilder().append(queryText).append(queryFields).append(agentId).toHashCode(); | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,12 +26,17 @@ public class NeuralSearchSettingsAccessor { | |
| @Getter | ||
| private volatile boolean isAgenticSearchEnabled; | ||
|
|
||
| private static final String SYSTEM_GENERATED_PIPELINE_SETTINGS = "cluster.search.enabled_system_generated_factories"; | ||
|
|
||
| private final ClusterService clusterService; | ||
|
|
||
| /** | ||
| * Constructor, registers callbacks to update settings | ||
| * @param clusterService | ||
| * @param settings | ||
| */ | ||
| public NeuralSearchSettingsAccessor(ClusterService clusterService, Settings settings) { | ||
| this.clusterService = clusterService; | ||
| isStatsEnabled = NeuralSearchSettings.NEURAL_STATS_ENABLED.get(settings); | ||
| isAgenticSearchEnabled = NeuralSearchSettings.AGENTIC_SEARCH_ENABLED.get(settings); | ||
| registerSettingsCallbacks(clusterService, settings); | ||
|
|
@@ -59,4 +64,13 @@ private void registerSettingsCallbacks(ClusterService clusterService, Settings s | |
| ClusterTrainingExecutor.updateThreadPoolSize(maxThreadQty, setting); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Checks if the system processor is enabled | ||
| * @return true if the processor is enabled in cluster settings | ||
| */ | ||
| public boolean isSystemGenerateProcessorEnabled(String processor) { | ||
| String enabledFactories = String.valueOf(clusterService.getClusterSettings().get(SYSTEM_GENERATED_PIPELINE_SETTINGS)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
And we also need to check if it has "*" which will enabled all the system processors. |
||
| return enabledFactories != null && enabledFactories.contains(processor); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.