mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-04-01 00:18:18 +02:00
large number of PR comments addressed
This commit is contained in:
parent
118e8afbef
commit
5a95a5c9fd
@ -60,5 +60,5 @@ def process_llm_stream(
|
||||
writer,
|
||||
)
|
||||
|
||||
logger.info(f"Full answer: {full_answer}")
|
||||
logger.debug(f"Full answer: {full_answer}")
|
||||
return cast(AIMessageChunk, tool_call_chunk)
|
||||
|
@ -17,11 +17,11 @@ def format_initial_sub_answers(
|
||||
) -> SubQuestionResultsUpdate:
|
||||
now_start = datetime.now()
|
||||
|
||||
logger.info(f"--------{now_start}--------INGEST ANSWERS---")
|
||||
logger.debug(f"--------{now_start}--------INGEST ANSWERS---")
|
||||
documents = []
|
||||
context_documents = []
|
||||
cited_documents = []
|
||||
answer_results = state.answer_results if hasattr(state, "answer_results") else []
|
||||
answer_results = state.answer_results
|
||||
for answer_result in answer_results:
|
||||
documents.extend(answer_result.verified_reranked_documents)
|
||||
context_documents.extend(answer_result.context_documents)
|
||||
|
@ -29,6 +29,7 @@ from onyx.agents.agent_search.shared_graph_utils.utils import write_custom_event
|
||||
from onyx.chat.models import AgentAnswerPiece
|
||||
from onyx.chat.models import StreamStopInfo
|
||||
from onyx.chat.models import StreamStopReason
|
||||
from onyx.chat.models import StreamType
|
||||
from onyx.configs.agent_configs import AGENT_MAX_ANSWER_CONTEXT_DOCS
|
||||
from onyx.utils.logger import setup_logger
|
||||
|
||||
@ -45,7 +46,7 @@ def generate_sub_answer(
|
||||
graph_config = cast(GraphConfig, config["metadata"]["config"])
|
||||
question = state.question
|
||||
state.verified_reranked_documents
|
||||
level, question_nr = parse_question_id(state.question_id)
|
||||
level, question_num = parse_question_id(state.question_id)
|
||||
context_docs = state.context_documents[:AGENT_MAX_ANSWER_CONTEXT_DOCS]
|
||||
persona_contextualized_prompt = get_persona_agent_prompt_expressions(
|
||||
graph_config.inputs.search_request.persona
|
||||
@ -58,7 +59,7 @@ def generate_sub_answer(
|
||||
AgentAnswerPiece(
|
||||
answer_piece=answer_str,
|
||||
level=level,
|
||||
level_question_nr=question_nr,
|
||||
level_question_num=question_num,
|
||||
answer_type="agent_sub_answer",
|
||||
),
|
||||
writer,
|
||||
@ -90,7 +91,7 @@ def generate_sub_answer(
|
||||
AgentAnswerPiece(
|
||||
answer_piece=content,
|
||||
level=level,
|
||||
level_question_nr=question_nr,
|
||||
level_question_num=question_num,
|
||||
answer_type="agent_sub_answer",
|
||||
),
|
||||
writer,
|
||||
@ -113,9 +114,9 @@ def generate_sub_answer(
|
||||
|
||||
stop_event = StreamStopInfo(
|
||||
stop_reason=StreamStopReason.FINISHED,
|
||||
stream_type="sub_answer",
|
||||
stream_type=StreamType.SUB_ANSWER,
|
||||
level=level,
|
||||
level_question_nr=question_nr,
|
||||
level_question_num=question_num,
|
||||
)
|
||||
write_custom_event("stream_finished", stop_event, writer)
|
||||
|
||||
|
@ -35,13 +35,13 @@ def parallelize_initial_sub_question_answering(
|
||||
"answer_query_subgraph",
|
||||
AnswerQuestionInput(
|
||||
question=question,
|
||||
question_id=make_question_id(0, question_nr + 1),
|
||||
question_id=make_question_id(0, question_num + 1),
|
||||
log_messages=[
|
||||
f"{edge_start_time} -- Main Edge - Parallelize Initial Sub-question Answering"
|
||||
],
|
||||
),
|
||||
)
|
||||
for question_nr, question in enumerate(state.initial_sub_questions)
|
||||
for question_num, question in enumerate(state.initial_sub_questions)
|
||||
]
|
||||
|
||||
else:
|
||||
|
@ -112,7 +112,7 @@ def generate_initial_answer(
|
||||
id=tool_response.id,
|
||||
response=tool_response.response,
|
||||
level=0,
|
||||
level_question_nr=0, # 0, 0 is the base question
|
||||
level_question_num=0, # 0, 0 is the base question
|
||||
),
|
||||
writer,
|
||||
)
|
||||
@ -123,7 +123,7 @@ def generate_initial_answer(
|
||||
AgentAnswerPiece(
|
||||
answer_piece=UNKNOWN_ANSWER,
|
||||
level=0,
|
||||
level_question_nr=0,
|
||||
level_question_num=0,
|
||||
answer_type="agent_level_answer",
|
||||
),
|
||||
writer,
|
||||
@ -142,7 +142,7 @@ def generate_initial_answer(
|
||||
|
||||
good_qa_list: list[str] = []
|
||||
|
||||
sub_question_nr = 1
|
||||
sub_question_num = 1
|
||||
|
||||
for decomp_answer_result in decomp_answer_results:
|
||||
decomp_questions.append(decomp_answer_result.question)
|
||||
@ -155,10 +155,10 @@ def generate_initial_answer(
|
||||
SUB_QUESTION_ANSWER_TEMPLATE.format(
|
||||
sub_question=decomp_answer_result.question,
|
||||
sub_answer=decomp_answer_result.answer,
|
||||
sub_question_nr=sub_question_nr,
|
||||
sub_question_num=sub_question_num,
|
||||
)
|
||||
)
|
||||
sub_question_nr += 1
|
||||
sub_question_num += 1
|
||||
|
||||
# Determine which base prompt to use given the sub-question information
|
||||
if len(good_qa_list) > 0:
|
||||
@ -212,7 +212,7 @@ def generate_initial_answer(
|
||||
AgentAnswerPiece(
|
||||
answer_piece=content,
|
||||
level=0,
|
||||
level_question_nr=0,
|
||||
level_question_num=0,
|
||||
answer_type="agent_level_answer",
|
||||
),
|
||||
writer,
|
||||
|
@ -35,13 +35,13 @@ def parallelize_initial_sub_question_answering(
|
||||
"answer_sub_question_subgraphs",
|
||||
AnswerQuestionInput(
|
||||
question=question,
|
||||
question_id=make_question_id(0, question_nr + 1),
|
||||
question_id=make_question_id(0, question_num + 1),
|
||||
log_messages=[
|
||||
f"{edge_start_time} -- Main Edge - Parallelize Initial Sub-question Answering"
|
||||
],
|
||||
),
|
||||
)
|
||||
for question_nr, question in enumerate(state.initial_sub_questions)
|
||||
for question_num, question in enumerate(state.initial_sub_questions)
|
||||
]
|
||||
|
||||
else:
|
||||
|
@ -35,6 +35,7 @@ from onyx.agents.agent_search.shared_graph_utils.utils import (
|
||||
from onyx.agents.agent_search.shared_graph_utils.utils import write_custom_event
|
||||
from onyx.chat.models import StreamStopInfo
|
||||
from onyx.chat.models import StreamStopReason
|
||||
from onyx.chat.models import StreamType
|
||||
from onyx.chat.models import SubQuestionPiece
|
||||
from onyx.configs.agent_configs import AGENT_NUM_DOCS_FOR_DECOMPOSITION
|
||||
|
||||
@ -55,7 +56,6 @@ def decompose_orig_question(
|
||||
history = build_history_prompt(graph_config, question)
|
||||
|
||||
# Use the initial search results to inform the decomposition
|
||||
sample_doc_str = state.sample_doc_str if hasattr(state, "sample_doc_str") else ""
|
||||
agent_start_time = datetime.now()
|
||||
|
||||
# Initial search to inform decomposition. Just get top 3 fits
|
||||
@ -91,7 +91,7 @@ def decompose_orig_question(
|
||||
SubQuestionPiece(
|
||||
sub_question=question,
|
||||
level=0,
|
||||
level_question_nr=0,
|
||||
level_question_num=0,
|
||||
),
|
||||
writer,
|
||||
)
|
||||
@ -102,7 +102,7 @@ def decompose_orig_question(
|
||||
|
||||
stop_event = StreamStopInfo(
|
||||
stop_reason=StreamStopReason.FINISHED,
|
||||
stream_type="sub_questions",
|
||||
stream_type=StreamType.SUB_QUESTIONS,
|
||||
level=0,
|
||||
)
|
||||
write_custom_event("stream_finished", stop_event, writer)
|
||||
|
@ -22,7 +22,7 @@ def format_initial_sub_answers(
|
||||
documents = []
|
||||
context_documents = []
|
||||
cited_documents = []
|
||||
answer_results = state.answer_results if hasattr(state, "answer_results") else []
|
||||
answer_results = state.answer_results
|
||||
for answer_result in answer_results:
|
||||
documents.extend(answer_result.verified_reranked_documents)
|
||||
context_documents.extend(answer_result.context_documents)
|
||||
|
@ -60,13 +60,13 @@ def parallelize_initial_sub_question_answering(
|
||||
"answer_query_subgraph",
|
||||
AnswerQuestionInput(
|
||||
question=question,
|
||||
question_id=make_question_id(0, question_nr + 1),
|
||||
question_id=make_question_id(0, question_num + 1),
|
||||
log_messages=[
|
||||
f"{edge_start_time} -- Main Edge - Parallelize Initial Sub-question Answering"
|
||||
],
|
||||
),
|
||||
)
|
||||
for question_nr, question in enumerate(state.initial_sub_questions)
|
||||
for question_num, question in enumerate(state.initial_sub_questions)
|
||||
]
|
||||
|
||||
else:
|
||||
@ -100,13 +100,13 @@ def parallelize_refined_sub_question_answering(
|
||||
"answer_refined_question_subgraphs",
|
||||
AnswerQuestionInput(
|
||||
question=question_data.sub_question,
|
||||
question_id=make_question_id(1, question_nr),
|
||||
question_id=make_question_id(1, question_num),
|
||||
log_messages=[
|
||||
f"{edge_start_time} -- Main Edge - Parallelize Refined Sub-question Answering"
|
||||
],
|
||||
),
|
||||
)
|
||||
for question_nr, question_data in state.refined_sub_questions.items()
|
||||
for question_num, question_data in state.refined_sub_questions.items()
|
||||
]
|
||||
|
||||
else:
|
||||
|
@ -103,16 +103,16 @@ def create_refined_sub_questions(
|
||||
raise ValueError("LLM response is not a string")
|
||||
|
||||
refined_sub_question_dict = {}
|
||||
for sub_question_nr, sub_question in enumerate(parsed_response):
|
||||
for sub_question_num, sub_question in enumerate(parsed_response):
|
||||
refined_sub_question = FollowUpSubQuestion(
|
||||
sub_question=sub_question,
|
||||
sub_question_id=make_question_id(1, sub_question_nr + 1),
|
||||
sub_question_id=make_question_id(1, sub_question_num + 1),
|
||||
verified=False,
|
||||
answered=False,
|
||||
answer="",
|
||||
)
|
||||
|
||||
refined_sub_question_dict[sub_question_nr + 1] = refined_sub_question
|
||||
refined_sub_question_dict[sub_question_num + 1] = refined_sub_question
|
||||
|
||||
return RefinedQuestionDecompositionUpdate(
|
||||
refined_sub_questions=refined_sub_question_dict,
|
||||
|
@ -26,6 +26,7 @@ from onyx.agents.agent_search.shared_graph_utils.utils import format_docs
|
||||
from onyx.agents.agent_search.shared_graph_utils.utils import (
|
||||
get_langgraph_node_log_string,
|
||||
)
|
||||
from onyx.configs.constants import NUM_EXPLORATORY_DOCS
|
||||
|
||||
|
||||
def extract_entities_terms(
|
||||
@ -53,7 +54,7 @@ def extract_entities_terms(
|
||||
|
||||
# first four lines duplicates from generate_initial_answer
|
||||
question = graph_config.inputs.search_request.query
|
||||
initial_search_docs = state.exploratory_search_results[:15]
|
||||
initial_search_docs = state.exploratory_search_results[:NUM_EXPLORATORY_DOCS]
|
||||
|
||||
# start with the entity/term/extraction
|
||||
doc_context = format_docs(initial_search_docs)
|
||||
|
@ -112,7 +112,7 @@ def generate_refined_answer(
|
||||
id=tool_response.id,
|
||||
response=tool_response.response,
|
||||
level=1,
|
||||
level_question_nr=0, # 0, 0 is the base question
|
||||
level_question_num=0, # 0, 0 is the base question
|
||||
),
|
||||
writer,
|
||||
)
|
||||
@ -132,10 +132,10 @@ def generate_refined_answer(
|
||||
initial_good_sub_questions: list[str] = []
|
||||
new_revised_good_sub_questions: list[str] = []
|
||||
|
||||
sub_question_nr = 1
|
||||
sub_question_num = 1
|
||||
|
||||
for decomp_answer_result in decomp_answer_results:
|
||||
question_level, question_nr = parse_question_id(
|
||||
question_level, question_num = parse_question_id(
|
||||
decomp_answer_result.question_id
|
||||
)
|
||||
|
||||
@ -155,12 +155,12 @@ def generate_refined_answer(
|
||||
SUB_QUESTION_ANSWER_TEMPLATE_REVISED.format(
|
||||
sub_question=decomp_answer_result.question,
|
||||
sub_answer=decomp_answer_result.answer,
|
||||
sub_question_nr=sub_question_nr,
|
||||
sub_question_num=sub_question_num,
|
||||
sub_question_type=sub_question_type,
|
||||
)
|
||||
)
|
||||
|
||||
sub_question_nr += 1
|
||||
sub_question_num += 1
|
||||
|
||||
initial_good_sub_questions = list(set(initial_good_sub_questions))
|
||||
new_revised_good_sub_questions = list(set(new_revised_good_sub_questions))
|
||||
@ -239,7 +239,7 @@ def generate_refined_answer(
|
||||
AgentAnswerPiece(
|
||||
answer_piece=content,
|
||||
level=1,
|
||||
level_question_nr=0,
|
||||
level_question_num=0,
|
||||
answer_type="agent_level_answer",
|
||||
),
|
||||
writer,
|
||||
|
@ -20,7 +20,7 @@ def ingest_refined_answers(
|
||||
node_start_time = datetime.now()
|
||||
|
||||
documents = []
|
||||
answer_results = state.answer_results if hasattr(state, "answer_results") else []
|
||||
answer_results = state.answer_results
|
||||
for answer_result in answer_results:
|
||||
documents.extend(answer_result.verified_reranked_documents)
|
||||
|
||||
|
@ -20,13 +20,13 @@ logger = setup_logger()
|
||||
def dispatch_subquestion(
|
||||
level: int, writer: StreamWriter
|
||||
) -> Callable[[str, int], None]:
|
||||
def _helper(sub_question_part: str, num: int) -> None:
|
||||
def _helper(sub_question_part: str, sep_num: int) -> None:
|
||||
write_custom_event(
|
||||
"decomp_qs",
|
||||
SubQuestionPiece(
|
||||
sub_question=sub_question_part,
|
||||
level=level,
|
||||
level_question_nr=num,
|
||||
level_question_num=sep_num,
|
||||
),
|
||||
writer,
|
||||
)
|
||||
|
@ -41,9 +41,9 @@ def expand_queries(
|
||||
llm = graph_config.tooling.fast_llm
|
||||
sub_question_id = state.sub_question_id
|
||||
if sub_question_id is None:
|
||||
level, question_nr = 0, 0
|
||||
level, question_num = 0, 0
|
||||
else:
|
||||
level, question_nr = parse_question_id(sub_question_id)
|
||||
level, question_num = parse_question_id(sub_question_id)
|
||||
|
||||
msg = [
|
||||
HumanMessage(
|
||||
@ -52,7 +52,7 @@ def expand_queries(
|
||||
]
|
||||
|
||||
llm_response_list = dispatch_separated(
|
||||
llm.stream(prompt=msg), dispatch_subquery(level, question_nr, writer)
|
||||
llm.stream(prompt=msg), dispatch_subquery(level, question_num, writer)
|
||||
)
|
||||
|
||||
llm_response = merge_message_runs(llm_response_list, chunk_separator="")[0].content
|
||||
|
@ -30,7 +30,7 @@ def format_results(
|
||||
config: RunnableConfig,
|
||||
writer: StreamWriter = lambda _: None,
|
||||
) -> ExpandedRetrievalUpdate:
|
||||
level, question_nr = parse_question_id(state.sub_question_id or "0_0")
|
||||
level, question_num = parse_question_id(state.sub_question_id or "0_0")
|
||||
query_info = get_query_info(state.query_retrieval_results)
|
||||
|
||||
graph_config = cast(GraphConfig, config["metadata"]["config"])
|
||||
@ -38,7 +38,7 @@ def format_results(
|
||||
|
||||
reranked_documents = state.reranked_documents
|
||||
|
||||
if not (level == 0 and question_nr == 0):
|
||||
if not (level == 0 and question_num == 0):
|
||||
if len(reranked_documents) == 0:
|
||||
# The sub-question is used as the last query. If no verified documents are found, stream
|
||||
# the top 3 for that one. We may want to revisit this.
|
||||
@ -63,7 +63,7 @@ def format_results(
|
||||
id=tool_response.id,
|
||||
response=tool_response.response,
|
||||
level=level,
|
||||
level_question_nr=question_nr,
|
||||
level_question_num=question_num,
|
||||
),
|
||||
writer,
|
||||
)
|
||||
|
@ -15,7 +15,7 @@ logger = setup_logger()
|
||||
|
||||
|
||||
def dispatch_subquery(
|
||||
level: int, question_nr: int, writer: StreamWriter
|
||||
level: int, question_num: int, writer: StreamWriter
|
||||
) -> Callable[[str, int], None]:
|
||||
def helper(token: str, num: int) -> None:
|
||||
write_custom_event(
|
||||
@ -23,7 +23,7 @@ def dispatch_subquery(
|
||||
SubQueryPiece(
|
||||
sub_query=token,
|
||||
level=level,
|
||||
level_question_nr=question_nr,
|
||||
level_question_num=question_num,
|
||||
query_id=num,
|
||||
),
|
||||
writer,
|
||||
|
@ -112,7 +112,7 @@ def llm_tool_choice(
|
||||
|
||||
# If no tool calls are emitted by the LLM, we should not choose a tool
|
||||
if len(tool_message.tool_calls) == 0:
|
||||
logger.info("No tool calls emitted by LLM")
|
||||
logger.debug("No tool calls emitted by LLM")
|
||||
return ToolChoiceUpdate(
|
||||
tool_choice=None,
|
||||
)
|
||||
@ -142,7 +142,7 @@ def llm_tool_choice(
|
||||
f"Tool call attempted with tool {selected_tool}, request {selected_tool_call_request}"
|
||||
)
|
||||
|
||||
logger.info(f"Selected tool: {selected_tool.name}")
|
||||
logger.debug(f"Selected tool: {selected_tool.name}")
|
||||
logger.debug(f"Selected tool call request: {selected_tool_call_request}")
|
||||
|
||||
return ToolChoiceUpdate(
|
||||
|
@ -29,6 +29,7 @@ from onyx.configs.agent_configs import 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
|
||||
from onyx.tools.tool_runner import ToolCallKickoff
|
||||
from onyx.utils.logger import setup_logger
|
||||
|
||||
@ -144,8 +145,6 @@ def run_basic_graph(
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from onyx.llm.factory import get_default_llms
|
||||
|
||||
for _ in range(1):
|
||||
query_start_time = datetime.now()
|
||||
logger.debug(f"Start at {query_start_time}")
|
||||
@ -188,29 +187,29 @@ if __name__ == "__main__":
|
||||
elif isinstance(output, ExtendedToolResponse):
|
||||
tool_responses.append(output.response)
|
||||
logger.info(
|
||||
f" ---- ET {output.level} - {output.level_question_nr} | "
|
||||
f" ---- ET {output.level} - {output.level_question_num} | "
|
||||
)
|
||||
elif isinstance(output, SubQueryPiece):
|
||||
logger.info(
|
||||
f"Sq {output.level} - {output.level_question_nr} - {output.sub_query} | "
|
||||
f"Sq {output.level} - {output.level_question_num} - {output.sub_query} | "
|
||||
)
|
||||
elif isinstance(output, SubQuestionPiece):
|
||||
logger.info(
|
||||
f"SQ {output.level} - {output.level_question_nr} - {output.sub_question} | "
|
||||
f"SQ {output.level} - {output.level_question_num} - {output.sub_question} | "
|
||||
)
|
||||
elif (
|
||||
isinstance(output, AgentAnswerPiece)
|
||||
and output.answer_type == "agent_sub_answer"
|
||||
):
|
||||
logger.info(
|
||||
f" ---- SA {output.level} - {output.level_question_nr} {output.answer_piece} | "
|
||||
f" ---- SA {output.level} - {output.level_question_num} {output.answer_piece} | "
|
||||
)
|
||||
elif (
|
||||
isinstance(output, AgentAnswerPiece)
|
||||
and output.answer_type == "agent_level_answer"
|
||||
):
|
||||
logger.info(
|
||||
f" ---------- FA {output.level} - {output.level_question_nr} {output.answer_piece} | "
|
||||
f" ---------- FA {output.level} - {output.level_question_num} {output.answer_piece} | "
|
||||
)
|
||||
elif isinstance(output, RefinedAnswerImprovement):
|
||||
logger.info(
|
||||
|
@ -10,7 +10,6 @@ from onyx.agents.agent_search.shared_graph_utils.prompts import HISTORY_PROMPT
|
||||
from onyx.agents.agent_search.shared_graph_utils.utils import (
|
||||
get_persona_agent_prompt_expressions,
|
||||
)
|
||||
from onyx.agents.agent_search.shared_graph_utils.utils import get_today_prompt
|
||||
from onyx.agents.agent_search.shared_graph_utils.utils import remove_document_citations
|
||||
from onyx.agents.agent_search.shared_graph_utils.utils import summarize_history
|
||||
from onyx.configs.agent_configs import AGENT_MAX_STATIC_HISTORY_WORD_LENGTH
|
||||
@ -19,6 +18,7 @@ from onyx.llm.interfaces import LLMConfig
|
||||
from onyx.llm.utils import get_max_input_tokens
|
||||
from onyx.natural_language_processing.utils import get_tokenizer
|
||||
from onyx.natural_language_processing.utils import tokenizer_trim_content
|
||||
from onyx.prompts.prompt_utils import build_date_time_string
|
||||
|
||||
|
||||
def build_sub_question_answer_prompt(
|
||||
@ -32,12 +32,12 @@ def build_sub_question_answer_prompt(
|
||||
content=persona_specification,
|
||||
)
|
||||
|
||||
date_str = get_today_prompt()
|
||||
date_str = build_date_time_string()
|
||||
|
||||
docs_format_list = [
|
||||
f"""Document Number: [D{doc_nr + 1}]\n
|
||||
f"""Document Number: [D{doc_num + 1}]\n
|
||||
Content: {doc.combined_content}\n\n"""
|
||||
for doc_nr, doc in enumerate(docs)
|
||||
for doc_num, doc in enumerate(docs)
|
||||
]
|
||||
|
||||
docs_str = "\n\n".join(docs_format_list)
|
||||
@ -126,7 +126,7 @@ def get_prompt_enrichment_components(
|
||||
|
||||
history = build_history_prompt(config, config.inputs.search_request.query)
|
||||
|
||||
date_str = get_today_prompt()
|
||||
date_str = build_date_time_string()
|
||||
|
||||
return AgentPromptEnrichmentComponents(
|
||||
persona_prompts=persona_prompts,
|
||||
|
@ -765,11 +765,11 @@ You are an assistant for question-answering tasks. Here is more information abou
|
||||
"""
|
||||
|
||||
SUB_QUESTION_ANSWER_TEMPLATE = """\n
|
||||
Sub-Question: Q{sub_question_nr}\n Sub-Question:\n - \n{sub_question}\n --\nAnswer:\n -\n {sub_answer}\n\n
|
||||
Sub-Question: Q{sub_question_num}\n Sub-Question:\n - \n{sub_question}\n --\nAnswer:\n -\n {sub_answer}\n\n
|
||||
"""
|
||||
|
||||
SUB_QUESTION_ANSWER_TEMPLATE_REVISED = """\n
|
||||
Sub-Question: Q{sub_question_nr}\n
|
||||
Sub-Question: Q{sub_question_num}\n
|
||||
Type:
|
||||
\n----\n
|
||||
{sub_question_type}
|
||||
@ -787,12 +787,12 @@ Sub-Question:
|
||||
|
||||
|
||||
SUB_QUESTION_ANSWER_TEMPLATE_REVISED = """\n
|
||||
Sub-Question: Q{sub_question_nr}\n Type: {sub_question_type}\n Sub-Question:\n
|
||||
Sub-Question: Q{sub_question_num}\n Type: {sub_question_type}\n Sub-Question:\n
|
||||
- \n{sub_question}\n --\nAnswer:\n -\n {sub_answer}\n\n
|
||||
"""
|
||||
|
||||
SUB_QUESTION_SEARCH_RESULTS_TEMPLATE = """\n
|
||||
Sub-Question: Q{sub_question_nr}\n Sub-Question:\n - \n{sub_question}\n --\nRelevant Documents:\n
|
||||
Sub-Question: Q{sub_question_num}\n Sub-Question:\n - \n{sub_question}\n --\nRelevant Documents:\n
|
||||
-\n {formatted_sub_question_docs}\n\n
|
||||
"""
|
||||
|
||||
|
@ -33,7 +33,6 @@ from onyx.agents.agent_search.shared_graph_utils.prompts import (
|
||||
from onyx.agents.agent_search.shared_graph_utils.prompts import (
|
||||
ASSISTANT_SYSTEM_PROMPT_PERSONA,
|
||||
)
|
||||
from onyx.agents.agent_search.shared_graph_utils.prompts import DATE_PROMPT
|
||||
from onyx.agents.agent_search.shared_graph_utils.prompts import (
|
||||
HISTORY_CONTEXT_SUMMARY_PROMPT,
|
||||
)
|
||||
@ -45,11 +44,13 @@ from onyx.chat.models import PromptConfig
|
||||
from onyx.chat.models import SectionRelevancePiece
|
||||
from onyx.chat.models import StreamStopInfo
|
||||
from onyx.chat.models import StreamStopReason
|
||||
from onyx.chat.models import StreamType
|
||||
from onyx.chat.prompt_builder.answer_prompt_builder import AnswerPromptBuilder
|
||||
from onyx.configs.chat_configs import CHAT_TARGET_CHUNK_PERCENTAGE
|
||||
from onyx.configs.chat_configs import MAX_CHUNKS_FED_TO_CHAT
|
||||
from onyx.configs.constants import DEFAULT_PERSONA_ID
|
||||
from onyx.configs.constants import DISPATCH_SEP_CHAR
|
||||
from onyx.configs.constants import FORMAT_DOCS_SEPARATOR
|
||||
from onyx.context.search.enums import LLMEvaluationType
|
||||
from onyx.context.search.models import InferenceSection
|
||||
from onyx.context.search.models import RetrievalDetails
|
||||
@ -81,10 +82,10 @@ def normalize_whitespace(text: str) -> str:
|
||||
def format_docs(docs: Sequence[InferenceSection]) -> str:
|
||||
formatted_doc_list = []
|
||||
|
||||
for doc_nr, doc in enumerate(docs):
|
||||
formatted_doc_list.append(f"Document D{doc_nr + 1}:\n{doc.combined_content}")
|
||||
for doc_num, doc in enumerate(docs):
|
||||
formatted_doc_list.append(f"Document D{doc_num + 1}:\n{doc.combined_content}")
|
||||
|
||||
return "\n\n".join(formatted_doc_list)
|
||||
return FORMAT_DOCS_SEPARATOR.join(formatted_doc_list)
|
||||
|
||||
|
||||
def format_docs_content_flat(docs: Sequence[InferenceSection]) -> str:
|
||||
@ -93,7 +94,7 @@ def format_docs_content_flat(docs: Sequence[InferenceSection]) -> str:
|
||||
for _, doc in enumerate(docs):
|
||||
formatted_doc_list.append(f"\n...{doc.combined_content}\n")
|
||||
|
||||
return "\n\n".join(formatted_doc_list)
|
||||
return FORMAT_DOCS_SEPARATOR.join(formatted_doc_list)
|
||||
|
||||
|
||||
def clean_and_parse_list_string(json_string: str) -> list[dict]:
|
||||
@ -289,20 +290,27 @@ def get_persona_agent_prompt_expressions(persona: Persona | None) -> PersonaExpr
|
||||
)
|
||||
|
||||
|
||||
def make_question_id(level: int, question_nr: int) -> str:
|
||||
return f"{level}_{question_nr}"
|
||||
def make_question_id(level: int, question_num: int) -> str:
|
||||
return f"{level}_{question_num}"
|
||||
|
||||
|
||||
def parse_question_id(question_id: str) -> tuple[int, int]:
|
||||
level, question_nr = question_id.split("_")
|
||||
return int(level), int(question_nr)
|
||||
level, question_num = question_id.split("_")
|
||||
return int(level), int(question_num)
|
||||
|
||||
|
||||
def _dispatch_nonempty(
|
||||
content: str, dispatch_event: Callable[[str, int], None], num: int
|
||||
content: str, dispatch_event: Callable[[str, int], None], sep_num: int
|
||||
) -> None:
|
||||
"""
|
||||
Dispatch a content string if it is not empty using the given callback.
|
||||
This function is used in the context of dispatching some arbitrary number
|
||||
of similar objects which are separated by a separator during the LLM stream.
|
||||
The callback expects a sep_num denoting which object is being dispatched; these
|
||||
numbers go from 1 to however many strings the LLM decides to stream.
|
||||
"""
|
||||
if content != "":
|
||||
dispatch_event(content, num)
|
||||
dispatch_event(content, sep_num)
|
||||
|
||||
|
||||
def dispatch_separated(
|
||||
@ -331,16 +339,12 @@ def dispatch_separated(
|
||||
def dispatch_main_answer_stop_info(level: int, writer: StreamWriter) -> None:
|
||||
stop_event = StreamStopInfo(
|
||||
stop_reason=StreamStopReason.FINISHED,
|
||||
stream_type="main_answer",
|
||||
stream_type=StreamType.MAIN_ANSWER,
|
||||
level=level,
|
||||
)
|
||||
write_custom_event("stream_finished", stop_event, writer)
|
||||
|
||||
|
||||
def get_today_prompt() -> str:
|
||||
return DATE_PROMPT.format(date=datetime.now().strftime("%A, %B %d, %Y"))
|
||||
|
||||
|
||||
def retrieve_search_docs(
|
||||
search_tool: SearchTool, question: str
|
||||
) -> list[InferenceSection]:
|
||||
@ -379,13 +383,8 @@ def summarize_history(
|
||||
)
|
||||
|
||||
history_response = model.invoke(history_context_prompt)
|
||||
|
||||
if isinstance(history_response.content, str):
|
||||
history_context_response_str = history_response.content
|
||||
else:
|
||||
history_context_response_str = ""
|
||||
|
||||
return history_context_response_str
|
||||
assert isinstance(history_response.content, str)
|
||||
return history_response.content
|
||||
|
||||
|
||||
# taken from langchain_core.runnables.schema
|
||||
|
@ -19,6 +19,7 @@ from onyx.chat.models import CitationInfo
|
||||
from onyx.chat.models import OnyxAnswerPiece
|
||||
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.constants import BASIC_KEY
|
||||
from onyx.context.search.models import SearchRequest
|
||||
@ -32,6 +33,8 @@ from onyx.utils.logger import setup_logger
|
||||
|
||||
logger = setup_logger()
|
||||
|
||||
BASIC_SQ_KEY = SubQuestionKey(level=BASIC_KEY[0], question_num=BASIC_KEY[1])
|
||||
|
||||
|
||||
class Answer:
|
||||
def __init__(
|
||||
@ -164,6 +167,7 @@ class Answer:
|
||||
and packet.answer_piece
|
||||
and packet.answer_type == "agent_level_answer"
|
||||
):
|
||||
assert packet.level is not None
|
||||
answer_by_level[packet.level] += packet.answer_piece
|
||||
elif isinstance(packet, OnyxAnswerPiece) and packet.answer_piece:
|
||||
answer_by_level[BASIC_KEY[0]] += packet.answer_piece
|
||||
@ -178,19 +182,20 @@ class Answer:
|
||||
|
||||
return citations
|
||||
|
||||
# TODO: replace tuple of ints with SubQuestionId EVERYWHERE
|
||||
def citations_by_subquestion(self) -> dict[tuple[int, int], list[CitationInfo]]:
|
||||
def citations_by_subquestion(self) -> dict[SubQuestionKey, list[CitationInfo]]:
|
||||
citations_by_subquestion: dict[
|
||||
tuple[int, int], list[CitationInfo]
|
||||
SubQuestionKey, list[CitationInfo]
|
||||
] = defaultdict(list)
|
||||
for packet in self.processed_streamed_output:
|
||||
if isinstance(packet, CitationInfo):
|
||||
if packet.level_question_nr is not None and packet.level is not None:
|
||||
if packet.level_question_num is not None and packet.level is not None:
|
||||
citations_by_subquestion[
|
||||
(packet.level, packet.level_question_nr)
|
||||
SubQuestionKey(
|
||||
level=packet.level, question_num=packet.level_question_num
|
||||
)
|
||||
].append(packet)
|
||||
elif packet.level is None:
|
||||
citations_by_subquestion[BASIC_KEY].append(packet)
|
||||
citations_by_subquestion[BASIC_SQ_KEY].append(packet)
|
||||
return citations_by_subquestion
|
||||
|
||||
def is_cancelled(self) -> bool:
|
||||
|
@ -16,6 +16,8 @@ from onyx.context.search.enums import QueryFlow
|
||||
from onyx.context.search.enums import RecencyBiasSetting
|
||||
from onyx.context.search.enums import SearchType
|
||||
from onyx.context.search.models import RetrievalDocs
|
||||
from onyx.db.models import SearchDoc as DbSearchDoc
|
||||
from onyx.file_store.models import FileDescriptor
|
||||
from onyx.llm.override_models import PromptOverride
|
||||
from onyx.tools.models import ToolCallFinalResult
|
||||
from onyx.tools.models import ToolCallKickoff
|
||||
@ -41,16 +43,19 @@ class LlmDoc(BaseModel):
|
||||
match_highlights: list[str] | None
|
||||
|
||||
|
||||
class SubQuestionIdentifier(BaseModel):
|
||||
level: int | None = None
|
||||
level_question_num: int | None = None
|
||||
|
||||
|
||||
# First chunk of info for streaming QA
|
||||
class QADocsResponse(RetrievalDocs):
|
||||
class QADocsResponse(RetrievalDocs, SubQuestionIdentifier):
|
||||
rephrased_query: str | None = None
|
||||
predicted_flow: QueryFlow | None
|
||||
predicted_search: SearchType | None
|
||||
applied_source_filters: list[DocumentSource] | None
|
||||
applied_time_cutoff: datetime | None
|
||||
recency_bias_multiplier: float
|
||||
level: int | None = None
|
||||
level_question_nr: int | None = None
|
||||
|
||||
def model_dump(self, *args: list, **kwargs: dict[str, Any]) -> dict[str, Any]: # type: ignore
|
||||
initial_dict = super().model_dump(mode="json", *args, **kwargs) # type: ignore
|
||||
@ -67,13 +72,16 @@ class StreamStopReason(Enum):
|
||||
FINISHED = "finished"
|
||||
|
||||
|
||||
class StreamStopInfo(BaseModel):
|
||||
class StreamType(Enum):
|
||||
SUB_QUESTIONS = "sub_questions"
|
||||
SUB_ANSWER = "sub_answer"
|
||||
MAIN_ANSWER = "main_answer"
|
||||
|
||||
|
||||
class StreamStopInfo(SubQuestionIdentifier):
|
||||
stop_reason: StreamStopReason
|
||||
|
||||
stream_type: Literal["", "sub_questions", "sub_answer", "main_answer"] = ""
|
||||
# used to identify the stream that was stopped for agent search
|
||||
level: int | None = None
|
||||
level_question_nr: int | None = None
|
||||
stream_type: StreamType = StreamType.MAIN_ANSWER
|
||||
|
||||
def model_dump(self, *args: list, **kwargs: dict[str, Any]) -> dict[str, Any]: # type: ignore
|
||||
data = super().model_dump(mode="json", *args, **kwargs) # type: ignore
|
||||
@ -114,11 +122,9 @@ class OnyxAnswerPiece(BaseModel):
|
||||
|
||||
# An intermediate representation of citations, later translated into
|
||||
# a mapping of the citation [n] number to SearchDoc
|
||||
class CitationInfo(BaseModel):
|
||||
class CitationInfo(SubQuestionIdentifier):
|
||||
citation_num: int
|
||||
document_id: str
|
||||
level: int | None = None
|
||||
level_question_nr: int | None = None
|
||||
|
||||
|
||||
class AllCitations(BaseModel):
|
||||
@ -310,29 +316,22 @@ class PromptConfig(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
|
||||
class SubQueryPiece(BaseModel):
|
||||
class SubQueryPiece(SubQuestionIdentifier):
|
||||
sub_query: str
|
||||
level: int
|
||||
level_question_nr: int
|
||||
query_id: int
|
||||
|
||||
|
||||
class AgentAnswerPiece(BaseModel):
|
||||
class AgentAnswerPiece(SubQuestionIdentifier):
|
||||
answer_piece: str
|
||||
level: int
|
||||
level_question_nr: int
|
||||
answer_type: Literal["agent_sub_answer", "agent_level_answer"]
|
||||
|
||||
|
||||
class SubQuestionPiece(BaseModel):
|
||||
class SubQuestionPiece(SubQuestionIdentifier):
|
||||
sub_question: str
|
||||
level: int
|
||||
level_question_nr: int
|
||||
|
||||
|
||||
class ExtendedToolResponse(ToolResponse):
|
||||
level: int
|
||||
level_question_nr: int
|
||||
class ExtendedToolResponse(ToolResponse, SubQuestionIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class RefinedAnswerImprovement(BaseModel):
|
||||
@ -363,3 +362,29 @@ ResponsePart = (
|
||||
)
|
||||
|
||||
AnswerStream = Iterator[AnswerPacket]
|
||||
|
||||
|
||||
class AnswerPostInfo(BaseModel):
|
||||
ai_message_files: list[FileDescriptor]
|
||||
qa_docs_response: QADocsResponse | None = None
|
||||
reference_db_search_docs: list[DbSearchDoc] | None = None
|
||||
dropped_indices: list[int] | None = None
|
||||
tool_result: ToolCallFinalResult | None = None
|
||||
message_specific_citations: MessageSpecificCitations | None = None
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
class SubQuestionKey(BaseModel):
|
||||
level: int
|
||||
question_num: int
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.level, self.question_num))
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
return isinstance(other, SubQuestionKey) and (
|
||||
self.level,
|
||||
self.question_num,
|
||||
) == (other.level, other.question_num)
|
||||
|
@ -2,7 +2,6 @@ import traceback
|
||||
from collections import defaultdict
|
||||
from collections.abc import Callable
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from typing import cast
|
||||
|
||||
@ -13,6 +12,7 @@ from onyx.chat.chat_utils import create_chat_chain
|
||||
from onyx.chat.chat_utils import create_temporary_persona
|
||||
from onyx.chat.models import AgentSearchPacket
|
||||
from onyx.chat.models import AllCitations
|
||||
from onyx.chat.models import AnswerPostInfo
|
||||
from onyx.chat.models import AnswerStyleConfig
|
||||
from onyx.chat.models import ChatOnyxBotResponse
|
||||
from onyx.chat.models import CitationConfig
|
||||
@ -33,6 +33,7 @@ from onyx.chat.models import RefinedAnswerImprovement
|
||||
from onyx.chat.models import StreamingError
|
||||
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.chat.prompt_builder.answer_prompt_builder import default_build_system_message
|
||||
from onyx.chat.prompt_builder.answer_prompt_builder import default_build_user_message
|
||||
@ -196,9 +197,9 @@ def _handle_search_tool_response_summary(
|
||||
for db_search_doc in reference_db_search_docs
|
||||
]
|
||||
|
||||
level, question_nr = None, None
|
||||
level, question_num = None, None
|
||||
if isinstance(packet, ExtendedToolResponse):
|
||||
level, question_nr = packet.level, packet.level_question_nr
|
||||
level, question_num = packet.level, packet.level_question_num
|
||||
return (
|
||||
QADocsResponse(
|
||||
rephrased_query=response_sumary.rephrased_query,
|
||||
@ -209,7 +210,7 @@ def _handle_search_tool_response_summary(
|
||||
applied_time_cutoff=response_sumary.final_filters.time_cutoff,
|
||||
recency_bias_multiplier=response_sumary.recency_bias_multiplier,
|
||||
level=level,
|
||||
level_question_nr=question_nr,
|
||||
level_question_num=question_num,
|
||||
),
|
||||
reference_db_search_docs,
|
||||
dropped_inds,
|
||||
@ -310,17 +311,6 @@ ChatPacket = (
|
||||
ChatPacketStream = Iterator[ChatPacket]
|
||||
|
||||
|
||||
# can't store a DbSearchDoc in a Pydantic BaseModel
|
||||
@dataclass
|
||||
class AnswerPostInfo:
|
||||
ai_message_files: list[FileDescriptor]
|
||||
qa_docs_response: QADocsResponse | None = None
|
||||
reference_db_search_docs: list[DbSearchDoc] | None = None
|
||||
dropped_indices: list[int] | None = None
|
||||
tool_result: ToolCallFinalResult | None = None
|
||||
message_specific_citations: MessageSpecificCitations | None = None
|
||||
|
||||
|
||||
def stream_chat_message_objects(
|
||||
new_msg_req: CreateChatMessageRequest,
|
||||
user: User | None,
|
||||
@ -794,18 +784,22 @@ def stream_chat_message_objects(
|
||||
# tool_result = None
|
||||
|
||||
# TODO: different channels for stored info when it's coming from the agent flow
|
||||
info_by_subq: dict[tuple[int, int], AnswerPostInfo] = defaultdict(
|
||||
info_by_subq: dict[SubQuestionKey, AnswerPostInfo] = defaultdict(
|
||||
lambda: AnswerPostInfo(ai_message_files=[])
|
||||
)
|
||||
refined_answer_improvement = True
|
||||
for packet in answer.processed_streamed_output:
|
||||
if isinstance(packet, ToolResponse):
|
||||
level, level_question_nr = (
|
||||
(packet.level, packet.level_question_nr)
|
||||
level, level_question_num = (
|
||||
(packet.level, packet.level_question_num)
|
||||
if isinstance(packet, ExtendedToolResponse)
|
||||
else BASIC_KEY
|
||||
)
|
||||
info = info_by_subq[(level, level_question_nr)]
|
||||
assert level is not None
|
||||
assert level_question_num is not None
|
||||
info = info_by_subq[
|
||||
SubQuestionKey(level=level, question_num=level_question_num)
|
||||
]
|
||||
# TODO: don't need to dedupe here when we do it in agent flow
|
||||
if packet.id == SEARCH_RESPONSE_SUMMARY_ID:
|
||||
(
|
||||
@ -928,13 +922,15 @@ def stream_chat_message_objects(
|
||||
yield packet
|
||||
else:
|
||||
if isinstance(packet, ToolCallFinalResult):
|
||||
level, level_question_nr = (
|
||||
(packet.level, packet.level_question_nr)
|
||||
level, level_question_num = (
|
||||
(packet.level, packet.level_question_num)
|
||||
if packet.level is not None
|
||||
and packet.level_question_nr is not None
|
||||
and packet.level_question_num is not None
|
||||
else BASIC_KEY
|
||||
)
|
||||
info = info_by_subq[(level, level_question_nr)]
|
||||
info = info_by_subq[
|
||||
SubQuestionKey(level=level, question_num=level_question_num)
|
||||
]
|
||||
info.tool_result = packet
|
||||
yield cast(ChatPacket, packet)
|
||||
logger.debug("Reached end of stream")
|
||||
@ -971,26 +967,30 @@ def stream_chat_message_objects(
|
||||
tool_name_to_tool_id[tool.name] = tool_id
|
||||
|
||||
subq_citations = answer.citations_by_subquestion()
|
||||
for pair in subq_citations:
|
||||
level, level_question_nr = pair
|
||||
info = info_by_subq[(level, level_question_nr)]
|
||||
for subq_key in subq_citations:
|
||||
info = info_by_subq[subq_key]
|
||||
logger.debug("Post-LLM answer processing")
|
||||
if info.reference_db_search_docs:
|
||||
info.message_specific_citations = _translate_citations(
|
||||
citations_list=subq_citations[pair],
|
||||
citations_list=subq_citations[subq_key],
|
||||
db_docs=info.reference_db_search_docs,
|
||||
)
|
||||
|
||||
# TODO: AllCitations should contain subq info?
|
||||
if not answer.is_cancelled():
|
||||
yield AllCitations(citations=subq_citations[pair])
|
||||
yield AllCitations(citations=subq_citations[subq_key])
|
||||
|
||||
# Saving Gen AI answer and responding with message info
|
||||
|
||||
info = (
|
||||
info_by_subq[BASIC_KEY]
|
||||
info_by_subq[SubQuestionKey(level=BASIC_KEY[0], question_num=BASIC_KEY[1])]
|
||||
if BASIC_KEY in info_by_subq
|
||||
else info_by_subq[AGENT_SEARCH_INITIAL_KEY]
|
||||
else info_by_subq[
|
||||
SubQuestionKey(
|
||||
level=AGENT_SEARCH_INITIAL_KEY[0],
|
||||
question_num=AGENT_SEARCH_INITIAL_KEY[1],
|
||||
)
|
||||
]
|
||||
)
|
||||
gen_ai_response_message = partial_response(
|
||||
message=answer.llm_answer,
|
||||
@ -1025,7 +1025,11 @@ def stream_chat_message_objects(
|
||||
agent_answers = answer.llm_answer_by_level()
|
||||
while next_level in agent_answers:
|
||||
next_answer = agent_answers[next_level]
|
||||
info = info_by_subq[(next_level, AGENT_SEARCH_INITIAL_KEY[1])]
|
||||
info = info_by_subq[
|
||||
SubQuestionKey(
|
||||
level=next_level, question_num=AGENT_SEARCH_INITIAL_KEY[1]
|
||||
)
|
||||
]
|
||||
next_answer_message = create_new_chat_message(
|
||||
chat_session_id=chat_session_id,
|
||||
parent_message=prev_message,
|
||||
|
@ -43,6 +43,8 @@ BASIC_KEY = (-1, -1)
|
||||
AGENT_SEARCH_INITIAL_KEY = (0, 0)
|
||||
CANCEL_CHECK_INTERVAL = 20
|
||||
DISPATCH_SEP_CHAR = "\n"
|
||||
FORMAT_DOCS_SEPARATOR = "\n\n"
|
||||
NUM_EXPLORATORY_DOCS = 15
|
||||
# Postgres connection constants for application_name
|
||||
POSTGRES_WEB_APP_NAME = "web"
|
||||
POSTGRES_INDEXER_APP_NAME = "indexer"
|
||||
|
@ -889,7 +889,7 @@ def translate_db_sub_questions_to_server_objects(
|
||||
sub_questions.append(
|
||||
SubQuestionDetail(
|
||||
level=sub_question.level,
|
||||
level_question_nr=sub_question.level_question_num,
|
||||
level_question_num=sub_question.level_question_num,
|
||||
question=sub_question.sub_question,
|
||||
answer=sub_question.sub_answer,
|
||||
sub_queries=sub_queries,
|
||||
@ -1012,7 +1012,7 @@ def log_agent_sub_question_results(
|
||||
now = datetime.now()
|
||||
|
||||
for sub_question_answer_result in sub_question_answer_results:
|
||||
level, level_question_nr = [
|
||||
level, level_question_num = [
|
||||
int(x) for x in sub_question_answer_result.question_id.split("_")
|
||||
]
|
||||
sub_question = sub_question_answer_result.question
|
||||
@ -1025,7 +1025,7 @@ def log_agent_sub_question_results(
|
||||
chat_session_id=chat_session_id,
|
||||
primary_question_id=primary_message_id,
|
||||
level=level,
|
||||
level_question_num=level_question_nr,
|
||||
level_question_num=level_question_num,
|
||||
sub_question=sub_question,
|
||||
sub_answer=sub_answer,
|
||||
sub_question_doc_results=sub_document_results,
|
||||
@ -1033,7 +1033,6 @@ def log_agent_sub_question_results(
|
||||
|
||||
db_session.add(sub_question_object)
|
||||
db_session.commit()
|
||||
# db_session.flush()
|
||||
|
||||
sub_question_id = sub_question_object.id
|
||||
|
||||
@ -1047,7 +1046,6 @@ def log_agent_sub_question_results(
|
||||
|
||||
db_session.add(sub_query_object)
|
||||
db_session.commit()
|
||||
# db_session.flush()
|
||||
|
||||
search_docs = chunks_or_sections_to_search_docs(sub_query.search_results)
|
||||
for doc in search_docs:
|
||||
|
@ -429,8 +429,6 @@ def handle_new_chat_message(
|
||||
),
|
||||
is_connected=is_connected_func,
|
||||
):
|
||||
# with open('chat_packets.log', 'a') as log_file:
|
||||
# log_file.write(json.dumps(packet) + '\n')
|
||||
yield json.dumps(packet) if isinstance(packet, dict) else packet
|
||||
|
||||
except Exception as e:
|
||||
|
@ -215,7 +215,7 @@ class SubQueryDetail(BaseModel):
|
||||
|
||||
class SubQuestionDetail(BaseModel):
|
||||
level: int
|
||||
level_question_nr: int
|
||||
level_question_num: int
|
||||
question: str
|
||||
answer: str
|
||||
sub_queries: list[SubQueryDetail] | None = None
|
||||
|
@ -43,7 +43,7 @@ class ToolCallFinalResult(ToolCallKickoff):
|
||||
)
|
||||
# agentic additions; only need to set during agentic tool calls
|
||||
level: int | None = None
|
||||
level_question_nr: int | None = None
|
||||
level_question_num: int | None = None
|
||||
|
||||
|
||||
class DynamicSchemaInfo(BaseModel):
|
||||
|
@ -277,10 +277,10 @@ export function ChatPage({
|
||||
(assistant) => assistant.id === existingChatSessionAssistantId
|
||||
)
|
||||
: defaultAssistantId !== undefined
|
||||
? availableAssistants.find(
|
||||
(assistant) => assistant.id === defaultAssistantId
|
||||
)
|
||||
: undefined
|
||||
? availableAssistants.find(
|
||||
(assistant) => assistant.id === defaultAssistantId
|
||||
)
|
||||
: undefined
|
||||
);
|
||||
// Gather default temperature settings
|
||||
const search_param_temperature = searchParams.get(
|
||||
@ -290,12 +290,12 @@ export function ChatPage({
|
||||
const defaultTemperature = search_param_temperature
|
||||
? parseFloat(search_param_temperature)
|
||||
: selectedAssistant?.tools.some(
|
||||
(tool) =>
|
||||
tool.in_code_tool_id === SEARCH_TOOL_ID ||
|
||||
tool.in_code_tool_id === INTERNET_SEARCH_TOOL_ID
|
||||
)
|
||||
? 0
|
||||
: 0.7;
|
||||
(tool) =>
|
||||
tool.in_code_tool_id === SEARCH_TOOL_ID ||
|
||||
tool.in_code_tool_id === INTERNET_SEARCH_TOOL_ID
|
||||
)
|
||||
? 0
|
||||
: 0.7;
|
||||
|
||||
const setSelectedAssistantFromId = (assistantId: number) => {
|
||||
// NOTE: also intentionally look through available assistants here, so that
|
||||
@ -1234,8 +1234,8 @@ export function ChatPage({
|
||||
const currentAssistantId = alternativeAssistantOverride
|
||||
? alternativeAssistantOverride.id
|
||||
: alternativeAssistant
|
||||
? alternativeAssistant.id
|
||||
: liveAssistant.id;
|
||||
? alternativeAssistant.id
|
||||
: liveAssistant.id;
|
||||
|
||||
resetInputBar();
|
||||
let messageUpdates: Message[] | null = null;
|
||||
@ -1427,7 +1427,7 @@ export function ChatPage({
|
||||
// Continuously refine the sub_questions based on the packets that we receive
|
||||
if (
|
||||
Object.hasOwn(packet, "stop_reason") &&
|
||||
Object.hasOwn(packet, "level_question_nr")
|
||||
Object.hasOwn(packet, "level_question_num")
|
||||
) {
|
||||
sub_questions = constructSubQuestions(
|
||||
sub_questions,
|
||||
@ -1471,8 +1471,8 @@ export function ChatPage({
|
||||
}
|
||||
} else if (
|
||||
Object.hasOwn(packet, "top_documents") &&
|
||||
Object.hasOwn(packet, "level_question_nr") &&
|
||||
(packet as DocumentsResponse).level_question_nr != undefined
|
||||
Object.hasOwn(packet, "level_question_num") &&
|
||||
(packet as DocumentsResponse).level_question_num != undefined
|
||||
) {
|
||||
const documentsResponse = packet as DocumentsResponse;
|
||||
sub_questions = constructSubQuestions(
|
||||
@ -1481,12 +1481,12 @@ export function ChatPage({
|
||||
);
|
||||
|
||||
if (
|
||||
documentsResponse.level_question_nr === 0 &&
|
||||
documentsResponse.level_question_num === 0 &&
|
||||
documentsResponse.level == 0
|
||||
) {
|
||||
documents = (packet as DocumentsResponse).top_documents;
|
||||
} else if (
|
||||
documentsResponse.level_question_nr === 0 &&
|
||||
documentsResponse.level_question_num === 0 &&
|
||||
documentsResponse.level == 1
|
||||
) {
|
||||
agenticDocs = (packet as DocumentsResponse).top_documents;
|
||||
|
@ -158,7 +158,7 @@ export interface DocumentsResponse {
|
||||
top_documents: OnyxDocument[];
|
||||
rephrased_query: string | null;
|
||||
level?: number | null;
|
||||
level_question_nr?: number | null;
|
||||
level_question_num?: number | null;
|
||||
}
|
||||
|
||||
export interface FileChatDisplay {
|
||||
@ -209,7 +209,7 @@ export interface PromptData {
|
||||
|
||||
export interface BaseQuestionIdentifier {
|
||||
level: number;
|
||||
level_question_nr: number;
|
||||
level_question_num: number;
|
||||
}
|
||||
|
||||
export interface SubQuestionDetail extends BaseQuestionIdentifier {
|
||||
@ -239,34 +239,34 @@ export const constructSubQuestions = (
|
||||
if (!newDetail) {
|
||||
return subQuestions;
|
||||
}
|
||||
if (newDetail.level_question_nr == 0) {
|
||||
if (newDetail.level_question_num == 0) {
|
||||
return subQuestions;
|
||||
}
|
||||
|
||||
const updatedSubQuestions = [...subQuestions];
|
||||
// .filter(
|
||||
// (sq) => sq.level_question_nr !== 0
|
||||
// (sq) => sq.level_question_num !== 0
|
||||
// );
|
||||
|
||||
if ("stop_reason" in newDetail) {
|
||||
console.log("STOP REASON");
|
||||
console.log(newDetail);
|
||||
const { level, level_question_nr } = newDetail;
|
||||
const { level, level_question_num } = newDetail;
|
||||
let subQuestion = updatedSubQuestions.find(
|
||||
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
|
||||
(sq) => sq.level === level && sq.level_question_num === level_question_num
|
||||
);
|
||||
if (subQuestion) {
|
||||
subQuestion.is_complete = true;
|
||||
}
|
||||
} else if ("top_documents" in newDetail) {
|
||||
const { level, level_question_nr, top_documents } = newDetail;
|
||||
const { level, level_question_num, top_documents } = newDetail;
|
||||
let subQuestion = updatedSubQuestions.find(
|
||||
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
|
||||
(sq) => sq.level === level && sq.level_question_num === level_question_num
|
||||
);
|
||||
if (!subQuestion) {
|
||||
subQuestion = {
|
||||
level: level ?? 0,
|
||||
level_question_nr: level_question_nr ?? 0,
|
||||
level_question_num: level_question_num ?? 0,
|
||||
question: "",
|
||||
answer: "",
|
||||
sub_queries: [],
|
||||
@ -277,16 +277,16 @@ export const constructSubQuestions = (
|
||||
}
|
||||
} else if ("answer_piece" in newDetail) {
|
||||
// Handle AgentAnswerPiece
|
||||
const { level, level_question_nr, answer_piece } = newDetail;
|
||||
const { level, level_question_num, answer_piece } = newDetail;
|
||||
// Find or create the relevant SubQuestionDetail
|
||||
let subQuestion = updatedSubQuestions.find(
|
||||
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
|
||||
(sq) => sq.level === level && sq.level_question_num === level_question_num
|
||||
);
|
||||
|
||||
if (!subQuestion) {
|
||||
subQuestion = {
|
||||
level,
|
||||
level_question_nr,
|
||||
level_question_num,
|
||||
question: "",
|
||||
answer: "",
|
||||
sub_queries: [],
|
||||
@ -299,17 +299,17 @@ export const constructSubQuestions = (
|
||||
subQuestion.answer += answer_piece;
|
||||
} else if ("sub_question" in newDetail) {
|
||||
// Handle SubQuestionPiece
|
||||
const { level, level_question_nr, sub_question } = newDetail;
|
||||
const { level, level_question_num, sub_question } = newDetail;
|
||||
|
||||
// Find or create the relevant SubQuestionDetail
|
||||
let subQuestion = updatedSubQuestions.find(
|
||||
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
|
||||
(sq) => sq.level === level && sq.level_question_num === level_question_num
|
||||
);
|
||||
|
||||
if (!subQuestion) {
|
||||
subQuestion = {
|
||||
level,
|
||||
level_question_nr,
|
||||
level_question_num,
|
||||
question: "",
|
||||
answer: "",
|
||||
sub_queries: [],
|
||||
@ -322,18 +322,18 @@ export const constructSubQuestions = (
|
||||
subQuestion.question += sub_question;
|
||||
} else if ("sub_query" in newDetail) {
|
||||
// Handle SubQueryPiece
|
||||
const { level, level_question_nr, query_id, sub_query } = newDetail;
|
||||
const { level, level_question_num, query_id, sub_query } = newDetail;
|
||||
|
||||
// Find the relevant SubQuestionDetail
|
||||
let subQuestion = updatedSubQuestions.find(
|
||||
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
|
||||
(sq) => sq.level === level && sq.level_question_num === level_question_num
|
||||
);
|
||||
|
||||
if (!subQuestion) {
|
||||
// If we receive a sub_query before its parent question, create a placeholder
|
||||
subQuestion = {
|
||||
level,
|
||||
level_question_nr: level_question_nr,
|
||||
level_question_num: level_question_num,
|
||||
question: "",
|
||||
answer: "",
|
||||
sub_queries: [],
|
||||
|
@ -227,7 +227,7 @@ export const AgenticMessage = ({
|
||||
(question: SubQuestionDetail) => {
|
||||
setCurrentlyOpenQuestion({
|
||||
level: question.level,
|
||||
level_question_nr: question.level_question_nr,
|
||||
level_question_num: question.level_question_num,
|
||||
});
|
||||
setTimeout(() => {
|
||||
console.log("closing question");
|
||||
|
@ -93,7 +93,7 @@ export const useStreamingMessages = (
|
||||
if (!dynamicSubQuestionsRef.current[i]) {
|
||||
dynamicSubQuestionsRef.current[i] = {
|
||||
level: sq.level,
|
||||
level_question_nr: sq.level_question_nr,
|
||||
level_question_num: sq.level_question_num,
|
||||
question: "",
|
||||
answer: "",
|
||||
sub_queries: [],
|
||||
@ -270,11 +270,11 @@ export const useStreamingMessages = (
|
||||
// Check if this is the last subquestion at level 0
|
||||
if (
|
||||
sq.level === 0 &&
|
||||
sq.level_question_nr ===
|
||||
sq.level_question_num ===
|
||||
Math.max(
|
||||
...subQuestions
|
||||
.filter((q) => q.level === 0)
|
||||
.map((q) => q.level_question_nr)
|
||||
.map((q) => q.level_question_num)
|
||||
)
|
||||
) {
|
||||
console.log("ALLOW STREAMING");
|
||||
|
@ -30,7 +30,7 @@ const SubQuestionProgress: React.FC<SubQuestionProgressProps> = ({
|
||||
{subQuestions.map((sq, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>
|
||||
Level {sq.level}, Q{sq.level_question_nr}
|
||||
Level {sq.level}, Q{sq.level_question_num}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Popover>
|
||||
|
@ -634,16 +634,16 @@ const SubQuestionsDisplay: React.FC<SubQuestionsDisplayProps> = ({
|
||||
<SubQuestionDisplay
|
||||
currentlyOpen={
|
||||
currentlyOpenQuestion?.level === subQuestion.level &&
|
||||
currentlyOpenQuestion?.level_question_nr ===
|
||||
subQuestion.level_question_nr
|
||||
currentlyOpenQuestion?.level_question_num ===
|
||||
subQuestion.level_question_num
|
||||
}
|
||||
currentlyClosed={
|
||||
currentlyOpenQuestion != null &&
|
||||
currentlyOpenQuestion != undefined &&
|
||||
!(
|
||||
currentlyOpenQuestion.level === subQuestion.level &&
|
||||
currentlyOpenQuestion.level_question_nr ===
|
||||
subQuestion.level_question_nr
|
||||
currentlyOpenQuestion.level_question_num ===
|
||||
subQuestion.level_question_num
|
||||
)
|
||||
}
|
||||
key={index}
|
||||
@ -681,16 +681,16 @@ const SubQuestionsDisplay: React.FC<SubQuestionsDisplayProps> = ({
|
||||
}
|
||||
currentlyOpen={
|
||||
currentlyOpenQuestion?.level === subQuestion.level &&
|
||||
currentlyOpenQuestion?.level_question_nr ===
|
||||
subQuestion.level_question_nr
|
||||
currentlyOpenQuestion?.level_question_num ===
|
||||
subQuestion.level_question_num
|
||||
}
|
||||
currentlyClosed={
|
||||
currentlyOpenQuestion != null &&
|
||||
currentlyOpenQuestion != undefined &&
|
||||
!(
|
||||
currentlyOpenQuestion.level === subQuestion.level &&
|
||||
currentlyOpenQuestion.level_question_nr ===
|
||||
subQuestion.level_question_nr
|
||||
currentlyOpenQuestion.level_question_num ===
|
||||
subQuestion.level_question_num
|
||||
)
|
||||
}
|
||||
key={index}
|
||||
|
@ -21,7 +21,7 @@ export interface ProSearchPacket {
|
||||
sub_query?: string;
|
||||
tool_response?: ToolResponse;
|
||||
level: number;
|
||||
level_question_nr: number;
|
||||
level_question_num: number;
|
||||
}
|
||||
|
||||
export interface RefinedAnswerImprovement {
|
||||
@ -31,26 +31,26 @@ export interface RefinedAnswerImprovement {
|
||||
export interface AgentAnswerPiece {
|
||||
answer_piece: string;
|
||||
level: number;
|
||||
level_question_nr: number;
|
||||
level_question_num: number;
|
||||
answer_type: "agent_sub_answer" | "agent_level_answer";
|
||||
}
|
||||
|
||||
export interface SubQuestionPiece {
|
||||
sub_question: string;
|
||||
level: number;
|
||||
level_question_nr: number;
|
||||
level_question_num: number;
|
||||
}
|
||||
|
||||
export interface SubQueryPiece {
|
||||
sub_query: string;
|
||||
level: number;
|
||||
level_question_nr: number;
|
||||
level_question_num: number;
|
||||
query_id: number;
|
||||
}
|
||||
|
||||
export interface SubQuestionSearchDoc {
|
||||
context_docs: OnyxDocument[];
|
||||
level_question_nr: number;
|
||||
level_question_num: number;
|
||||
level: number;
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ export interface ToolResponse {
|
||||
}
|
||||
export interface ExtendedToolResponse extends ToolResponse {
|
||||
level: number;
|
||||
level_question_nr: number;
|
||||
level_question_num: number;
|
||||
}
|
||||
|
||||
export interface AnswerPiecePacket {
|
||||
@ -75,7 +75,7 @@ export enum StreamStopReason {
|
||||
export interface StreamStopInfo {
|
||||
stop_reason: StreamStopReason;
|
||||
level?: number;
|
||||
level_question_nr?: number;
|
||||
level_question_num?: number;
|
||||
}
|
||||
|
||||
export interface ErrorMessagePacket {
|
||||
|
Loading…
x
Reference in New Issue
Block a user