diff --git a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a1_search_objects.py b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a1_search_objects.py index f075ea12f3c..38d970a96a7 100644 --- a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a1_search_objects.py +++ b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a1_search_objects.py @@ -34,16 +34,14 @@ def search_objects( """ graph_config = cast(GraphConfig, config["metadata"]["config"]) - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query search_tool = graph_config.tooling.search_tool - if search_tool is None or graph_config.inputs.search_request.persona is None: + if search_tool is None or graph_config.inputs.persona is None: raise ValueError("Search tool and persona must be provided for DivCon search") try: - instructions = graph_config.inputs.search_request.persona.prompts[ - 0 - ].system_prompt + instructions = graph_config.inputs.persona.prompts[0].system_prompt agent_1_instructions = extract_section( instructions, "Agent Step 1:", "Agent Step 2:" diff --git a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a2_research_object_source.py b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a2_research_object_source.py index 0e567d578d7..8b142efcc88 100644 --- a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a2_research_object_source.py +++ b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a2_research_object_source.py @@ -35,18 +35,15 @@ def research_object_source( datetime.now() graph_config = cast(GraphConfig, config["metadata"]["config"]) - graph_config.inputs.search_request.query search_tool = graph_config.tooling.search_tool - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query object, document_source = state.object_source_combination - if search_tool is None or graph_config.inputs.search_request.persona is None: + if search_tool is None or graph_config.inputs.persona is None: raise ValueError("Search tool and persona must be provided for DivCon search") try: - instructions = graph_config.inputs.search_request.persona.prompts[ - 0 - ].system_prompt + instructions = graph_config.inputs.persona.prompts[0].system_prompt agent_2_instructions = extract_section( instructions, "Agent Step 2:", "Agent Step 3:" diff --git a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a3_structure_research_by_object.py b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a3_structure_research_by_object.py index fa05093225f..31450b985c0 100644 --- a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a3_structure_research_by_object.py +++ b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a3_structure_research_by_object.py @@ -1,6 +1,4 @@ from collections import defaultdict -from datetime import datetime -from typing import cast from typing import Dict from typing import List @@ -11,7 +9,6 @@ from onyx.agents.agent_search.dc_search_analysis.states import MainState from onyx.agents.agent_search.dc_search_analysis.states import ( ObjectResearchInformationUpdate, ) -from onyx.agents.agent_search.models import GraphConfig from onyx.agents.agent_search.shared_graph_utils.utils import write_custom_event from onyx.chat.models import AgentAnswerPiece from onyx.utils.logger import setup_logger @@ -25,10 +22,6 @@ def structure_research_by_object( """ LangGraph node to start the agentic search process. """ - datetime.now() - - graph_config = cast(GraphConfig, config["metadata"]["config"]) - graph_config.inputs.search_request.query write_custom_event( "initial_agent_answer", diff --git a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a4_consolidate_object_research.py b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a4_consolidate_object_research.py index b2db83d0c12..acd965db385 100644 --- a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a4_consolidate_object_research.py +++ b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a4_consolidate_object_research.py @@ -27,14 +27,13 @@ def consolidate_object_research( LangGraph node to start the agentic search process. """ graph_config = cast(GraphConfig, config["metadata"]["config"]) - graph_config.inputs.search_request.query search_tool = graph_config.tooling.search_tool - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query - if search_tool is None or graph_config.inputs.search_request.persona is None: + if search_tool is None or graph_config.inputs.persona is None: raise ValueError("Search tool and persona must be provided for DivCon search") - instructions = graph_config.inputs.search_request.persona.prompts[0].system_prompt + instructions = graph_config.inputs.persona.prompts[0].system_prompt agent_4_instructions = extract_section( instructions, "Agent Step 4:", "Agent Step 5:" diff --git a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a5_consolidate_research.py b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a5_consolidate_research.py index 74a98365d13..1ac89ab0e44 100644 --- a/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a5_consolidate_research.py +++ b/backend/onyx/agents/agent_search/dc_search_analysis/nodes/a5_consolidate_research.py @@ -28,10 +28,8 @@ def consolidate_research( """ LangGraph node to start the agentic search process. """ - datetime.now() graph_config = cast(GraphConfig, config["metadata"]["config"]) - graph_config.inputs.search_request.query search_tool = graph_config.tooling.search_tool @@ -46,11 +44,11 @@ def consolidate_research( writer, ) - if search_tool is None or graph_config.inputs.search_request.persona is None: + if search_tool is None or graph_config.inputs.persona is None: raise ValueError("Search tool and persona must be provided for DivCon search") # Populate prompt - instructions = graph_config.inputs.search_request.persona.prompts[0].system_prompt + instructions = graph_config.inputs.persona.prompts[0].system_prompt try: agent_5_instructions = extract_section( diff --git a/backend/onyx/agents/agent_search/deep_search/initial/generate_individual_sub_answer/nodes/generate_sub_answer.py b/backend/onyx/agents/agent_search/deep_search/initial/generate_individual_sub_answer/nodes/generate_sub_answer.py index b321b962f60..3ba16972a42 100644 --- a/backend/onyx/agents/agent_search/deep_search/initial/generate_individual_sub_answer/nodes/generate_sub_answer.py +++ b/backend/onyx/agents/agent_search/deep_search/initial/generate_individual_sub_answer/nodes/generate_sub_answer.py @@ -85,7 +85,7 @@ def generate_sub_answer( context_docs = dedup_sort_inference_section_list(context_docs) persona_contextualized_prompt = get_persona_agent_prompt_expressions( - graph_config.inputs.search_request.persona + graph_config.inputs.persona ).contextualized_prompt if len(context_docs) == 0: @@ -106,7 +106,7 @@ def generate_sub_answer( fast_llm = graph_config.tooling.fast_llm msg = build_sub_question_answer_prompt( question=question, - original_question=graph_config.inputs.search_request.query, + original_question=graph_config.inputs.prompt_builder.raw_user_query, docs=context_docs, persona_specification=persona_contextualized_prompt, config=fast_llm.config, diff --git a/backend/onyx/agents/agent_search/deep_search/initial/generate_initial_answer/nodes/generate_initial_answer.py b/backend/onyx/agents/agent_search/deep_search/initial/generate_initial_answer/nodes/generate_initial_answer.py index e087528778f..03c33592586 100644 --- a/backend/onyx/agents/agent_search/deep_search/initial/generate_initial_answer/nodes/generate_initial_answer.py +++ b/backend/onyx/agents/agent_search/deep_search/initial/generate_initial_answer/nodes/generate_initial_answer.py @@ -105,7 +105,7 @@ def generate_initial_answer( node_start_time = datetime.now() graph_config = cast(GraphConfig, config["metadata"]["config"]) - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query prompt_enrichment_components = get_prompt_enrichment_components(graph_config) # get all documents cited in sub-questions diff --git a/backend/onyx/agents/agent_search/deep_search/initial/generate_sub_answers/nodes/decompose_orig_question.py b/backend/onyx/agents/agent_search/deep_search/initial/generate_sub_answers/nodes/decompose_orig_question.py index 33e8577db53..af22ebdb8d3 100644 --- a/backend/onyx/agents/agent_search/deep_search/initial/generate_sub_answers/nodes/decompose_orig_question.py +++ b/backend/onyx/agents/agent_search/deep_search/initial/generate_sub_answers/nodes/decompose_orig_question.py @@ -75,7 +75,7 @@ def decompose_orig_question( node_start_time = datetime.now() graph_config = cast(GraphConfig, config["metadata"]["config"]) - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query perform_initial_search_decomposition = ( graph_config.behavior.perform_initial_search_decomposition ) diff --git a/backend/onyx/agents/agent_search/deep_search/initial/retrieve_orig_question_docs/nodes/format_orig_question_search_input.py b/backend/onyx/agents/agent_search/deep_search/initial/retrieve_orig_question_docs/nodes/format_orig_question_search_input.py index 070d9fb4606..d66c1a6add2 100644 --- a/backend/onyx/agents/agent_search/deep_search/initial/retrieve_orig_question_docs/nodes/format_orig_question_search_input.py +++ b/backend/onyx/agents/agent_search/deep_search/initial/retrieve_orig_question_docs/nodes/format_orig_question_search_input.py @@ -21,7 +21,7 @@ def format_orig_question_search_input( logger.debug("generate_raw_search_data") graph_config = cast(GraphConfig, config["metadata"]["config"]) return ExpandedRetrievalInput( - question=graph_config.inputs.search_request.query, + question=graph_config.inputs.prompt_builder.raw_user_query, base_search=True, sub_question_id=None, # This graph is always and only used for the original question log_messages=[], diff --git a/backend/onyx/agents/agent_search/deep_search/main/edges.py b/backend/onyx/agents/agent_search/deep_search/main/edges.py index 79989e8c9d0..9c97daa0dd4 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/edges.py +++ b/backend/onyx/agents/agent_search/deep_search/main/edges.py @@ -30,18 +30,18 @@ def route_initial_tool_choice( LangGraph edge to route to agent search. """ agent_config = cast(GraphConfig, config["metadata"]["config"]) - if state.tool_choice is not None: - if ( - agent_config.behavior.use_agentic_search - and agent_config.tooling.search_tool is not None - and state.tool_choice.tool.name == agent_config.tooling.search_tool.name - ): - return "start_agent_search" - else: - return "call_tool" - else: + if state.tool_choice is None: return "logging_node" + if ( + agent_config.behavior.use_agentic_search + and agent_config.tooling.search_tool is not None + and state.tool_choice.tool.name == agent_config.tooling.search_tool.name + ): + return "start_agent_search" + else: + return "call_tool" + def parallelize_initial_sub_question_answering( state: MainState, diff --git a/backend/onyx/agents/agent_search/deep_search/main/graph_builder.py b/backend/onyx/agents/agent_search/deep_search/main/graph_builder.py index 75e23a79205..c0ebc246bd5 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/graph_builder.py +++ b/backend/onyx/agents/agent_search/deep_search/main/graph_builder.py @@ -59,7 +59,7 @@ logger = setup_logger() test_mode = False -def main_graph_builder(test_mode: bool = False) -> StateGraph: +def agent_search_graph_builder() -> StateGraph: """ LangGraph graph builder for the main agent search process. """ @@ -76,7 +76,7 @@ def main_graph_builder(test_mode: bool = False) -> StateGraph: # Choose the initial tool graph.add_node( - node="initial_tool_choice", + node="choose_tool", action=choose_tool, ) @@ -162,11 +162,11 @@ def main_graph_builder(test_mode: bool = False) -> StateGraph: graph.add_edge( start_key="prepare_tool_input", - end_key="initial_tool_choice", + end_key="choose_tool", ) graph.add_conditional_edges( - "initial_tool_choice", + "choose_tool", route_initial_tool_choice, ["call_tool", "start_agent_search", "logging_node"], ) @@ -242,7 +242,7 @@ if __name__ == "__main__": from onyx.llm.factory import get_default_llms from onyx.context.search.models import SearchRequest - graph = main_graph_builder() + graph = agent_search_graph_builder() compiled_graph = graph.compile() primary_llm, fast_llm = get_default_llms() diff --git a/backend/onyx/agents/agent_search/deep_search/main/nodes/compare_answers.py b/backend/onyx/agents/agent_search/deep_search/main/nodes/compare_answers.py index 0624a6447a2..2c8cae75004 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/nodes/compare_answers.py +++ b/backend/onyx/agents/agent_search/deep_search/main/nodes/compare_answers.py @@ -69,7 +69,7 @@ def compare_answers( node_start_time = datetime.now() graph_config = cast(GraphConfig, config["metadata"]["config"]) - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query initial_answer = state.initial_answer refined_answer = state.refined_answer diff --git a/backend/onyx/agents/agent_search/deep_search/main/nodes/create_refined_sub_questions.py b/backend/onyx/agents/agent_search/deep_search/main/nodes/create_refined_sub_questions.py index d9e15b189b3..34207ce4797 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/nodes/create_refined_sub_questions.py +++ b/backend/onyx/agents/agent_search/deep_search/main/nodes/create_refined_sub_questions.py @@ -85,7 +85,7 @@ def create_refined_sub_questions( ToolCallKickoff( tool_name="agent_search_1", tool_args={ - "query": graph_config.inputs.search_request.query, + "query": graph_config.inputs.prompt_builder.raw_user_query, "answer": state.initial_answer, }, ), @@ -96,7 +96,7 @@ def create_refined_sub_questions( agent_refined_start_time = datetime.now() - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query base_answer = state.initial_answer history = build_history_prompt(graph_config, question) # get the entity term extraction dict and properly format it diff --git a/backend/onyx/agents/agent_search/deep_search/main/nodes/extract_entities_terms.py b/backend/onyx/agents/agent_search/deep_search/main/nodes/extract_entities_terms.py index e356f11dbee..1d05fc12b5d 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/nodes/extract_entities_terms.py +++ b/backend/onyx/agents/agent_search/deep_search/main/nodes/extract_entities_terms.py @@ -66,7 +66,7 @@ def extract_entities_terms( ) # first four lines duplicates from generate_initial_answer - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query initial_search_docs = state.exploratory_search_results[:NUM_EXPLORATORY_DOCS] # start with the entity/term/extraction diff --git a/backend/onyx/agents/agent_search/deep_search/main/nodes/generate_validate_refined_answer.py b/backend/onyx/agents/agent_search/deep_search/main/nodes/generate_validate_refined_answer.py index 12a150eff48..b2a1736211f 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/nodes/generate_validate_refined_answer.py +++ b/backend/onyx/agents/agent_search/deep_search/main/nodes/generate_validate_refined_answer.py @@ -124,7 +124,7 @@ def generate_validate_refined_answer( node_start_time = datetime.now() graph_config = cast(GraphConfig, config["metadata"]["config"]) - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query prompt_enrichment_components = get_prompt_enrichment_components(graph_config) persona_contextualized_prompt = ( diff --git a/backend/onyx/agents/agent_search/deep_search/main/nodes/persist_agent_results.py b/backend/onyx/agents/agent_search/deep_search/main/nodes/persist_agent_results.py index 258be96984a..e40b191ad01 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/nodes/persist_agent_results.py +++ b/backend/onyx/agents/agent_search/deep_search/main/nodes/persist_agent_results.py @@ -63,8 +63,8 @@ def persist_agent_results(state: MainState, config: RunnableConfig) -> MainOutpu persona_id = None graph_config = cast(GraphConfig, config["metadata"]["config"]) - if graph_config.inputs.search_request.persona: - persona_id = graph_config.inputs.search_request.persona.id + if graph_config.inputs.persona: + persona_id = graph_config.inputs.persona.id user_id = None assert ( diff --git a/backend/onyx/agents/agent_search/deep_search/main/nodes/start_agent_search.py b/backend/onyx/agents/agent_search/deep_search/main/nodes/start_agent_search.py index 39d3b89ad52..279a40053d9 100644 --- a/backend/onyx/agents/agent_search/deep_search/main/nodes/start_agent_search.py +++ b/backend/onyx/agents/agent_search/deep_search/main/nodes/start_agent_search.py @@ -28,7 +28,7 @@ def start_agent_search( node_start_time = datetime.now() graph_config = cast(GraphConfig, config["metadata"]["config"]) - question = graph_config.inputs.search_request.query + question = graph_config.inputs.prompt_builder.raw_user_query history = build_history_prompt(graph_config, question) diff --git a/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/edges.py b/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/edges.py index 7fd5f713057..6feb6c3ea2c 100644 --- a/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/edges.py +++ b/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/edges.py @@ -22,7 +22,9 @@ def parallel_retrieval_edge( """ graph_config = cast(GraphConfig, config["metadata"]["config"]) question = ( - state.question if state.question else graph_config.inputs.search_request.query + state.question + if state.question + else graph_config.inputs.prompt_builder.raw_user_query ) query_expansions = state.expanded_queries + [question] diff --git a/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/nodes/rerank_documents.py b/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/nodes/rerank_documents.py index f598a65fd11..5f3402979b3 100644 --- a/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/nodes/rerank_documents.py +++ b/backend/onyx/agents/agent_search/deep_search/shared/expanded_retrieval/nodes/rerank_documents.py @@ -47,14 +47,16 @@ def rerank_documents( graph_config = cast(GraphConfig, config["metadata"]["config"]) question = ( - state.question if state.question else graph_config.inputs.search_request.query + state.question + if state.question + else graph_config.inputs.prompt_builder.raw_user_query ) assert ( graph_config.tooling.search_tool ), "search_tool must be provided for agentic search" # Note that these are passed in values from the API and are overrides which are typically None - rerank_settings = graph_config.inputs.search_request.rerank_settings + rerank_settings = graph_config.inputs.rerank_settings allow_agent_reranking = graph_config.behavior.allow_agent_reranking if rerank_settings is None: @@ -95,7 +97,7 @@ def rerank_documents( return DocRerankingUpdate( reranked_documents=[ - doc for doc in reranked_documents if type(doc) == InferenceSection + doc for doc in reranked_documents if isinstance(doc, InferenceSection) ][:AGENT_RERANKING_MAX_QUERY_RETRIEVAL_RESULTS], sub_question_retrieval_stats=fit_scores, log_messages=[ diff --git a/backend/onyx/agents/agent_search/models.py b/backend/onyx/agents/agent_search/models.py index 1904ae7ea23..9cb3034d674 100644 --- a/backend/onyx/agents/agent_search/models.py +++ b/backend/onyx/agents/agent_search/models.py @@ -5,7 +5,8 @@ from pydantic import model_validator from sqlalchemy.orm import Session from onyx.chat.prompt_builder.answer_prompt_builder import AnswerPromptBuilder -from onyx.context.search.models import SearchRequest +from onyx.context.search.models import RerankingDetails +from onyx.db.models import Persona from onyx.file_store.utils import InMemoryChatFile from onyx.llm.interfaces import LLM from onyx.tools.force import ForceUseTool @@ -16,7 +17,8 @@ from onyx.tools.tool_implementations.search.search_tool import SearchTool class GraphInputs(BaseModel): """Input data required for the graph execution""" - search_request: SearchRequest + persona: Persona | None = None + rerank_settings: RerankingDetails | None = None prompt_builder: AnswerPromptBuilder files: list[InMemoryChatFile] | None = None structured_response_format: dict | None = None diff --git a/backend/onyx/agents/agent_search/orchestration/nodes/choose_tool.py b/backend/onyx/agents/agent_search/orchestration/nodes/choose_tool.py index 79be2063595..8abc5fca8bb 100644 --- a/backend/onyx/agents/agent_search/orchestration/nodes/choose_tool.py +++ b/backend/onyx/agents/agent_search/orchestration/nodes/choose_tool.py @@ -107,7 +107,10 @@ def choose_tool( keyword_thread: TimeoutThread[tuple[bool, list[str]]] | None = None expanded_keyword_thread: TimeoutThread[str] | None = None expanded_semantic_thread: TimeoutThread[str] | None = None - override_kwargs: SearchToolOverrideKwargs | None = None + # If we have override_kwargs, add them to the tool_args + override_kwargs: SearchToolOverrideKwargs = ( + force_use_tool.override_kwargs or SearchToolOverrideKwargs() + ) using_tool_calling_llm = agent_config.tooling.using_tool_calling_llm prompt_builder = state.prompt_snapshot or agent_config.inputs.prompt_builder @@ -122,29 +125,28 @@ def choose_tool( not force_use_tool.force_use or force_use_tool.tool_name == SearchTool._NAME ) ): - override_kwargs = SearchToolOverrideKwargs() # Run in a background thread to avoid blocking the main thread embedding_thread = run_in_background( get_query_embedding, - agent_config.inputs.search_request.query, + agent_config.inputs.prompt_builder.raw_user_query, agent_config.persistence.db_session, ) keyword_thread = run_in_background( query_analysis, - agent_config.inputs.search_request.query, + agent_config.inputs.prompt_builder.raw_user_query, ) if USE_SEMANTIC_KEYWORD_EXPANSIONS_BASIC_SEARCH: expanded_keyword_thread = run_in_background( _expand_query, - agent_config.inputs.search_request.query, + agent_config.inputs.prompt_builder.raw_user_query, QueryExpansionType.KEYWORD, prompt_builder, ) expanded_semantic_thread = run_in_background( _expand_query, - agent_config.inputs.search_request.query, + agent_config.inputs.prompt_builder.raw_user_query, QueryExpansionType.SEMANTIC, prompt_builder, ) @@ -179,11 +181,9 @@ def choose_tool( if embedding_thread and tool.name == SearchTool._NAME: # Wait for the embedding thread to finish embedding = wait_on_background(embedding_thread) - assert override_kwargs is not None, "must have override kwargs" override_kwargs.precomputed_query_embedding = embedding if keyword_thread and tool.name == SearchTool._NAME: is_keyword, keywords = wait_on_background(keyword_thread) - assert override_kwargs is not None, "must have override kwargs" override_kwargs.precomputed_is_keyword = is_keyword override_kwargs.precomputed_keywords = keywords return ToolChoiceUpdate( @@ -272,11 +272,9 @@ def choose_tool( if embedding_thread and selected_tool.name == SearchTool._NAME: # Wait for the embedding thread to finish embedding = wait_on_background(embedding_thread) - assert override_kwargs is not None, "must have override kwargs" override_kwargs.precomputed_query_embedding = embedding if keyword_thread and selected_tool.name == SearchTool._NAME: is_keyword, keywords = wait_on_background(keyword_thread) - assert override_kwargs is not None, "must have override kwargs" override_kwargs.precomputed_is_keyword = is_keyword override_kwargs.precomputed_keywords = keywords @@ -287,13 +285,14 @@ def choose_tool( ): keyword_expansion = wait_on_background(expanded_keyword_thread) semantic_expansion = wait_on_background(expanded_semantic_thread) - assert override_kwargs is not None, "must have override kwargs" override_kwargs.expanded_queries = QueryExpansions( keywords_expansions=[keyword_expansion], semantic_expansions=[semantic_expansion], ) - logger.info(f"Original query: {agent_config.inputs.search_request.query}") + logger.info( + f"Original query: {agent_config.inputs.prompt_builder.raw_user_query}" + ) logger.info(f"Expanded keyword queries: {keyword_expansion}") logger.info(f"Expanded semantic queries: {semantic_expansion}") diff --git a/backend/onyx/agents/agent_search/orchestration/states.py b/backend/onyx/agents/agent_search/orchestration/states.py index 917f60921b3..80cc9f8dbfe 100644 --- a/backend/onyx/agents/agent_search/orchestration/states.py +++ b/backend/onyx/agents/agent_search/orchestration/states.py @@ -36,7 +36,7 @@ class ToolChoice(BaseModel): tool: Tool tool_args: dict id: str | None - search_tool_override_kwargs: SearchToolOverrideKwargs | None = None + search_tool_override_kwargs: SearchToolOverrideKwargs = SearchToolOverrideKwargs() class Config: arbitrary_types_allowed = True diff --git a/backend/onyx/agents/agent_search/run_graph.py b/backend/onyx/agents/agent_search/run_graph.py index 2f993e93c0d..40f498340d7 100644 --- a/backend/onyx/agents/agent_search/run_graph.py +++ b/backend/onyx/agents/agent_search/run_graph.py @@ -13,7 +13,7 @@ from onyx.agents.agent_search.dc_search_analysis.graph_builder import ( ) from onyx.agents.agent_search.dc_search_analysis.states import MainInput as DCMainInput from onyx.agents.agent_search.deep_search.main.graph_builder import ( - main_graph_builder as main_graph_builder_a, + agent_search_graph_builder as agent_search_graph_builder, ) from onyx.agents.agent_search.deep_search.main.states import ( MainInput as MainInput, @@ -30,8 +30,6 @@ from onyx.chat.models import StreamStopInfo from onyx.chat.models import SubQueryPiece from onyx.chat.models import SubQuestionPiece from onyx.chat.models import ToolResponse -from onyx.configs.agent_configs import AGENT_ALLOW_REFINEMENT -from onyx.configs.agent_configs import INITIAL_SEARCH_DECOMPOSITION_ENABLED from onyx.context.search.models import SearchRequest from onyx.db.engine import get_session_context_manager from onyx.llm.factory import get_default_llms @@ -79,6 +77,11 @@ def _parse_agent_event( return cast(RefinedAnswerImprovement, event["data"]) elif event["name"] == "refined_sub_question_creation_error": return cast(StreamingError, event["data"]) + else: + logger.error(f"Unknown event name: {event['name']}") + return None + + logger.error(f"Unknown event type: {event_type}") return None @@ -101,10 +104,6 @@ def run_graph( config: GraphConfig, input: BasicInput | MainInput | DCMainInput, ) -> AnswerStream: - config.behavior.perform_initial_search_decomposition = ( - INITIAL_SEARCH_DECOMPOSITION_ENABLED - ) - config.behavior.allow_refinement = AGENT_ALLOW_REFINEMENT for event in manage_sync_streaming( compiled_graph=compiled_graph, config=config, graph_input=input @@ -120,22 +119,21 @@ def run_graph( def load_compiled_graph() -> CompiledStateGraph: global _COMPILED_GRAPH if _COMPILED_GRAPH is None: - graph = main_graph_builder_a() + graph = agent_search_graph_builder() _COMPILED_GRAPH = graph.compile() return _COMPILED_GRAPH -def run_main_graph( +def run_agent_search_graph( config: GraphConfig, ) -> AnswerStream: compiled_graph = load_compiled_graph() input = MainInput(log_messages=[]) - # Agent search is not a Tool per se, but this is helpful for the frontend yield ToolCallKickoff( tool_name="agent_search_0", - tool_args={"query": config.inputs.search_request.query}, + tool_args={"query": config.inputs.prompt_builder.raw_user_query}, ) yield from run_graph(compiled_graph, config, input) @@ -155,7 +153,9 @@ def run_dc_graph( graph = divide_and_conquer_graph_builder() compiled_graph = graph.compile() input = DCMainInput(log_messages=[]) - config.inputs.search_request.query = config.inputs.search_request.query.strip() + config.inputs.prompt_builder.raw_user_query = ( + config.inputs.prompt_builder.raw_user_query.strip() + ) return run_graph(compiled_graph, config, input) @@ -163,7 +163,7 @@ if __name__ == "__main__": for _ in range(1): query_start_time = datetime.now() logger.debug(f"Start at {query_start_time}") - graph = main_graph_builder_a() + graph = agent_search_graph_builder() compiled_graph = graph.compile() query_end_time = datetime.now() logger.debug(f"Graph compiled in {query_end_time - query_start_time} seconds") diff --git a/backend/onyx/agents/agent_search/shared_graph_utils/agent_prompt_ops.py b/backend/onyx/agents/agent_search/shared_graph_utils/agent_prompt_ops.py index 57ec8b724ef..960c95a3c7b 100644 --- a/backend/onyx/agents/agent_search/shared_graph_utils/agent_prompt_ops.py +++ b/backend/onyx/agents/agent_search/shared_graph_utils/agent_prompt_ops.py @@ -82,7 +82,7 @@ def trim_prompt_piece(config: LLMConfig, prompt_piece: str, reserved_str: str) - def build_history_prompt(config: GraphConfig, question: str) -> str: prompt_builder = config.inputs.prompt_builder persona_base = get_persona_agent_prompt_expressions( - config.inputs.search_request.persona + config.inputs.persona ).base_prompt if prompt_builder is None: @@ -126,11 +126,9 @@ def build_history_prompt(config: GraphConfig, question: str) -> str: def get_prompt_enrichment_components( config: GraphConfig, ) -> AgentPromptEnrichmentComponents: - persona_prompts = get_persona_agent_prompt_expressions( - config.inputs.search_request.persona - ) + persona_prompts = get_persona_agent_prompt_expressions(config.inputs.persona) - history = build_history_prompt(config, config.inputs.search_request.query) + history = build_history_prompt(config, config.inputs.prompt_builder.raw_user_query) date_str = build_date_time_string() diff --git a/backend/onyx/agents/agent_search/shared_graph_utils/utils.py b/backend/onyx/agents/agent_search/shared_graph_utils/utils.py index 7433ff21000..6ae1e48ea6d 100644 --- a/backend/onyx/agents/agent_search/shared_graph_utils/utils.py +++ b/backend/onyx/agents/agent_search/shared_graph_utils/utils.py @@ -214,7 +214,8 @@ def get_test_config( ) graph_inputs = GraphInputs( - search_request=search_request, + persona=search_request.persona, + rerank_settings=search_tool_config.rerank_settings, prompt_builder=AnswerPromptBuilder( user_message=HumanMessage(content=search_request.query), message_history=[], diff --git a/backend/onyx/chat/answer.py b/backend/onyx/chat/answer.py index bf3e72d5955..e8360da6563 100644 --- a/backend/onyx/chat/answer.py +++ b/backend/onyx/chat/answer.py @@ -9,9 +9,9 @@ from onyx.agents.agent_search.models import GraphInputs from onyx.agents.agent_search.models import GraphPersistence from onyx.agents.agent_search.models import GraphSearchConfig from onyx.agents.agent_search.models import GraphTooling +from onyx.agents.agent_search.run_graph import run_agent_search_graph from onyx.agents.agent_search.run_graph import run_basic_graph from onyx.agents.agent_search.run_graph import run_dc_graph -from onyx.agents.agent_search.run_graph import run_main_graph from onyx.chat.models import AgentAnswerPiece from onyx.chat.models import AnswerPacket from onyx.chat.models import AnswerStream @@ -22,13 +22,15 @@ from onyx.chat.models import StreamStopInfo from onyx.chat.models import StreamStopReason from onyx.chat.models import SubQuestionKey from onyx.chat.prompt_builder.answer_prompt_builder import AnswerPromptBuilder +from onyx.configs.agent_configs import AGENT_ALLOW_REFINEMENT +from onyx.configs.agent_configs import INITIAL_SEARCH_DECOMPOSITION_ENABLED from onyx.configs.constants import BASIC_KEY -from onyx.context.search.models import SearchRequest +from onyx.context.search.models import RerankingDetails +from onyx.db.models import Persona from onyx.file_store.utils import InMemoryChatFile from onyx.llm.interfaces import LLM from onyx.tools.force import ForceUseTool from onyx.tools.tool import Tool -from onyx.tools.tool_implementations.search.search_tool import QUERY_FIELD from onyx.tools.tool_implementations.search.search_tool import SearchTool from onyx.tools.utils import explicit_tool_calling_supported from onyx.utils.gpu_utils import fast_gpu_status_request @@ -47,7 +49,8 @@ class Answer: llm: LLM, fast_llm: LLM, force_use_tool: ForceUseTool, - search_request: SearchRequest, + persona: Persona | None, + rerank_settings: RerankingDetails | None, chat_session_id: UUID, current_agent_message_id: int, db_session: Session, @@ -83,30 +86,17 @@ class Answer: and not skip_explicit_tool_calling ) - rerank_settings = search_request.rerank_settings - using_cloud_reranking = ( rerank_settings is not None and rerank_settings.rerank_provider_type is not None ) - allow_agent_reranking = ( - fast_gpu_status_request(indexing=False) or using_cloud_reranking + allow_agent_reranking = using_cloud_reranking or fast_gpu_status_request( + indexing=False ) - # TODO: this is a hack to force the query to be used for the search tool - # this should be removed once we fully unify graph inputs (i.e. - # remove SearchQuery entirely) - if ( - force_use_tool.force_use - and search_tool - and force_use_tool.args - and force_use_tool.tool_name == search_tool.name - and QUERY_FIELD in force_use_tool.args - ): - search_request.query = force_use_tool.args[QUERY_FIELD] - self.graph_inputs = GraphInputs( - search_request=search_request, + persona=persona, + rerank_settings=rerank_settings, prompt_builder=prompt_builder, files=latest_query_files, structured_response_format=answer_style_config.structured_response_format, @@ -127,8 +117,9 @@ class Answer: self.search_behavior_config = GraphSearchConfig( use_agentic_search=use_agentic_search, skip_gen_ai_answer_generation=skip_gen_ai_answer_generation, - allow_refinement=True, + allow_refinement=AGENT_ALLOW_REFINEMENT, allow_agent_reranking=allow_agent_reranking, + perform_initial_search_decomposition=INITIAL_SEARCH_DECOMPOSITION_ENABLED, ) self.graph_config = GraphConfig( inputs=self.graph_inputs, @@ -144,10 +135,10 @@ class Answer: return if self.graph_config.behavior.use_agentic_search: - run_langgraph = run_main_graph + run_langgraph = run_agent_search_graph elif ( - self.graph_config.inputs.search_request.persona - and self.graph_config.inputs.search_request.persona.description.startswith( + self.graph_config.inputs.persona + and self.graph_config.inputs.persona.description.startswith( "DivCon Beta Agent" ) ): diff --git a/backend/onyx/chat/process_message.py b/backend/onyx/chat/process_message.py index 4ca4002a36b..5654b05e189 100644 --- a/backend/onyx/chat/process_message.py +++ b/backend/onyx/chat/process_message.py @@ -59,7 +59,6 @@ from onyx.context.search.enums import SearchType from onyx.context.search.models import BaseFilters from onyx.context.search.models import InferenceSection from onyx.context.search.models import RetrievalDetails -from onyx.context.search.models import SearchRequest from onyx.context.search.retrieval.search_runner import ( inference_sections_from_ids, ) @@ -1209,34 +1208,6 @@ def stream_chat_message_objects( "Performance: Forcing LLMEvaluationType.SKIP to prevent chunk evaluation for ordering-only search" ) - search_request = SearchRequest( - query=final_msg.message, - evaluation_type=( - LLMEvaluationType.SKIP - if search_for_ordering_only - else ( - LLMEvaluationType.BASIC - if persona.llm_relevance_filter - else LLMEvaluationType.SKIP - ) - ), - human_selected_filters=( - retrieval_options.filters if retrieval_options else None - ), - persona=persona, - offset=(retrieval_options.offset if retrieval_options else None), - limit=retrieval_options.limit if retrieval_options else None, - rerank_settings=new_msg_req.rerank_settings, - chunks_above=new_msg_req.chunks_above, - chunks_below=new_msg_req.chunks_below, - full_doc=new_msg_req.full_doc, - enable_auto_detect_filters=( - retrieval_options.enable_auto_detect_filters - if retrieval_options - else None - ), - ) - prompt_builder = AnswerPromptBuilder( user_message=default_build_user_message( user_query=final_msg.message, @@ -1273,7 +1244,8 @@ def stream_chat_message_objects( ), fast_llm=fast_llm, force_use_tool=force_use_tool, - search_request=search_request, + persona=persona, + rerank_settings=new_msg_req.rerank_settings, chat_session_id=chat_session_id, current_agent_message_id=reserved_message_id, tools=tools, diff --git a/backend/onyx/tools/models.py b/backend/onyx/tools/models.py index f6d5f1f8812..1f85deda8f6 100644 --- a/backend/onyx/tools/models.py +++ b/backend/onyx/tools/models.py @@ -75,9 +75,8 @@ class SearchToolOverrideKwargs(BaseModel): precomputed_keywords: list[str] | None = None user_file_ids: list[int] | None = None user_folder_ids: list[int] | None = None - ordering_only: bool | None = ( - None # Flag for fast path when search is only needed for ordering - ) + # Flag for fast path when search is only needed for ordering + ordering_only: bool | None = None document_sources: list[DocumentSource] | None = None time_cutoff: datetime | None = None expanded_queries: QueryExpansions | None = None diff --git a/backend/tests/regression/answer_quality/agent_test_script.py b/backend/tests/regression/answer_quality/agent_test_script.py index 2291c4d8f40..929d4f286fe 100644 --- a/backend/tests/regression/answer_quality/agent_test_script.py +++ b/backend/tests/regression/answer_quality/agent_test_script.py @@ -9,16 +9,13 @@ from typing import Any import yaml from onyx.agents.agent_search.deep_search.main.graph_builder import ( - main_graph_builder, -) -from onyx.agents.agent_search.deep_search.main.graph_builder import ( - main_graph_builder as main_graph_builder_a, + agent_search_graph_builder, ) from onyx.agents.agent_search.deep_search.main.states import ( MainInput as MainInput_a, ) +from onyx.agents.agent_search.run_graph import run_agent_search_graph from onyx.agents.agent_search.run_graph import run_basic_graph -from onyx.agents.agent_search.run_graph import run_main_graph from onyx.agents.agent_search.shared_graph_utils.utils import get_test_config from onyx.chat.models import AgentAnswerPiece from onyx.chat.models import OnyxAnswerPiece @@ -44,7 +41,7 @@ INPUT_DIR = CONFIG["agent_test_input_folder"] OUTPUT_DIR = CONFIG["agent_test_output_folder"] -graph = main_graph_builder(test_mode=True) +graph = agent_search_graph_builder() compiled_graph = graph.compile() primary_llm, fast_llm = get_default_llms() @@ -92,7 +89,7 @@ with get_session_context_manager() as db_session: logger.debug("\n\nTEST QUERY START\n\n") - graph = main_graph_builder_a() + graph = agent_search_graph_builder() compiled_graph = graph.compile() query_end_time = datetime.now() @@ -152,7 +149,7 @@ with get_session_context_manager() as db_session: lambda: defaultdict(str) ) - for output in run_main_graph(config): + for output in run_agent_search_graph(config): if isinstance(output, AgentAnswerPiece): if output.level == 0 and output.level_question_num == 0: answer_tokens["initial"].append(output.answer_piece) diff --git a/backend/tests/unit/onyx/agent_search/test_use_tool_response.py b/backend/tests/unit/onyx/agent_search/test_use_tool_response.py index 817862f19ba..c749017ab0a 100644 --- a/backend/tests/unit/onyx/agent_search/test_use_tool_response.py +++ b/backend/tests/unit/onyx/agent_search/test_use_tool_response.py @@ -30,7 +30,8 @@ from onyx.context.search.enums import SearchType from onyx.context.search.models import IndexFilters from onyx.context.search.models import InferenceChunk from onyx.context.search.models import InferenceSection -from onyx.context.search.models import SearchRequest +from onyx.context.search.models import RerankingDetails +from onyx.db.models import Persona from onyx.llm.interfaces import LLM from onyx.tools.force import ForceUseTool from onyx.tools.message import ToolCallSummary @@ -44,6 +45,8 @@ from onyx.tools.tool_implementations.search_like_tool_utils import ( FINAL_CONTEXT_DOCUMENTS_ID, ) +TEST_PROMPT = "test prompt" + def create_test_inference_chunk( document_id: str, @@ -86,9 +89,7 @@ def mock_state() -> BasicState: mock_tool.build_next_prompt = MagicMock( return_value=MagicMock(spec=AnswerPromptBuilder) ) - mock_tool.build_next_prompt.return_value.build = MagicMock( - return_value="test prompt" - ) + mock_tool.build_next_prompt.return_value.build = MagicMock(return_value=TEST_PROMPT) mock_tool_choice = MagicMock(spec=ToolChoice) mock_tool_choice.tool = mock_tool @@ -124,12 +125,16 @@ def mock_config() -> RunnableConfig: mock_search_tool = MagicMock(spec=SearchTool) mock_force_use_tool = MagicMock(spec=ForceUseTool) mock_prompt_builder = MagicMock(spec=AnswerPromptBuilder) - mock_search_request = MagicMock(spec=SearchRequest) + mock_persona = MagicMock(spec=Persona) + mock_rerank_settings = MagicMock(spec=RerankingDetails) mock_db_session = MagicMock(spec=Session) + mock_prompt_builder.raw_user_query = TEST_PROMPT + # Create the GraphConfig components graph_inputs = GraphInputs( - search_request=mock_search_request, + persona=mock_persona, + rerank_settings=mock_rerank_settings, prompt_builder=mock_prompt_builder, files=None, structured_response_format=None, @@ -333,7 +338,7 @@ def test_basic_use_tool_response_with_search_results( mock_config["metadata"][ "config" ].tooling.primary_llm.stream.assert_called_once_with( - prompt="test prompt", + prompt=TEST_PROMPT, structured_response_format=None, ) diff --git a/backend/tests/unit/onyx/chat/test_answer.py b/backend/tests/unit/onyx/chat/test_answer.py index 12c02a41cc6..fe252d5950f 100644 --- a/backend/tests/unit/onyx/chat/test_answer.py +++ b/backend/tests/unit/onyx/chat/test_answer.py @@ -26,7 +26,6 @@ from onyx.chat.prompt_builder.answer_prompt_builder import AnswerPromptBuilder from onyx.chat.prompt_builder.answer_prompt_builder import default_build_system_message from onyx.chat.prompt_builder.answer_prompt_builder import default_build_user_message from onyx.context.search.models import RerankingDetails -from onyx.context.search.models import SearchRequest from onyx.llm.interfaces import LLM from onyx.tools.force import ForceUseTool from onyx.tools.models import ToolCallFinalResult @@ -79,7 +78,8 @@ def _answer_fixture_impl( llm=mock_llm, fast_llm=mock_llm, force_use_tool=ForceUseTool(force_use=False, tool_name="", args=None), - search_request=SearchRequest(query=QUERY, rerank_settings=rerank_settings), + persona=None, + rerank_settings=rerank_settings, chat_session_id=UUID("123e4567-e89b-12d3-a456-426614174000"), current_agent_message_id=0, ) @@ -407,10 +407,7 @@ def test_no_slow_reranking( mock_llm, answer_style_config, prompt_config, rerank_settings=rerank_settings ) - assert ( - answer_instance.graph_config.inputs.search_request.rerank_settings - == rerank_settings - ) + assert answer_instance.graph_config.inputs.rerank_settings == rerank_settings assert ( answer_instance.graph_config.behavior.allow_agent_reranking == gpu_enabled or not is_local_model diff --git a/backend/tests/unit/onyx/chat/test_skip_gen_ai.py b/backend/tests/unit/onyx/chat/test_skip_gen_ai.py index 1a4bf3219e8..c99de5cdd33 100644 --- a/backend/tests/unit/onyx/chat/test_skip_gen_ai.py +++ b/backend/tests/unit/onyx/chat/test_skip_gen_ai.py @@ -11,7 +11,6 @@ from onyx.chat.answer import Answer from onyx.chat.models import AnswerStyleConfig from onyx.chat.models import PromptConfig from onyx.chat.prompt_builder.answer_prompt_builder import AnswerPromptBuilder -from onyx.context.search.models import SearchRequest from onyx.llm.interfaces import LLM from onyx.llm.utils import get_max_input_tokens from onyx.tools.force import ForceUseTool @@ -72,7 +71,8 @@ def test_skip_gen_ai_answer_generation_flag( ), skip_explicit_tool_calling=True, skip_gen_ai_answer_generation=skip_gen_ai_answer_generation, - search_request=SearchRequest(query=question), + persona=None, + rerank_settings=None, prompt_builder=AnswerPromptBuilder( user_message=HumanMessage(content=question), message_history=[],