-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Agent search feature #3749
Agent search feature #3749
Changes from all commits
4fd6e36
e4c93be
b9bd2ea
b7f9e43
8aa82be
dd26014
50bacc0
470c4d1
00cee71
4e47c81
deea9c8
3ced9bc
ca1f176
2032fb1
80d248e
71eafe0
3b298e1
3c3900f
1ced892
e5fa411
eb6dbf4
dd494d2
d32d1c6
28ba01b
4b0a4a2
982040c
ddbfc65
db20045
2bbe20e
5e9b2e4
eea6f27
2d8486b
5bf6a47
46402a9
fc60fd0
aa8cb44
3b3b0c8
3bf6b77
f96a3ee
d4e0d0d
bf06710
1393749
7d494cd
f14b282
d52a0b9
25f6543
a0af8ee
a224736
50ef511
4baf3dc
8c9577a
de5ce8a
7487b15
9e9bd44
812172f
1fe966d
3a07093
f842e15
568f927
0496ec3
f1d9634
9bad129
efa32a8
1a22af4
110c9f7
f2aeeb7
18d9255
325892a
12d1186
69e8c5f
da4a086
4817fa0
6bef5ca
91b929d
ff4df6f
4e17fc0
7e98936
73769c6
d70bbcc
8fea571
3d99ad7
6c7f8ea
48e42af
c062097
a63b341
7879ba6
5bff8bc
a43a662
1dbf561
bd3b194
01e6e9a
c43c232
23bf50b
e3e855c
3ca4d53
f050d28
42780d5
55ed6e2
60fb06d
8cbdc6d
0578c31
f33a2ff
e191e51
6442c56
0a6808c
ef6e6f9
3b13380
ceaaa05
2517aa3
b0c3098
2b8cd63
bb6d557
4b82440
8af4f1d
756a1cb
4a0b2a6
a340529
385b344
23ae454
1a2760e
d53dd1e
732861a
0ccd83e
95fcc00
d5661ba
8342168
118e8af
5a95a5c
29440f5
b90e083
9438f9d
feaa3b6
eaffdee
a96728f
2adeaae
71304e4
e23dd0a
9b6e51b
a067b32
506a9f1
570fe43
16265d2
9a3ce50
c984c6c
59c65a4
87a53d6
b1e9e03
8f7db92
024207e
3f6de79
3f3b04a
25a57e2
eb227c0
cb85be4
4834ee6
3cd057d
7ac6d3e
3ce8923
b46c09a
4b0d22f
b500c91
b928201
b978191
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,107 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"""agent_tracking | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
Revision ID: 98a5008d8711 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Revises: 2f80c6a2550f | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Create Date: 2025-01-29 17:00:00.000001 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
from alembic import op | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import sqlalchemy as sa | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
from sqlalchemy.dialects import postgresql | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
from sqlalchemy.dialects.postgresql import UUID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
# revision identifiers, used by Alembic. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
revision = "98a5008d8711" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
down_revision = "2f80c6a2550f" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
branch_labels = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
depends_on = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
def upgrade() -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.create_table( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"agent__search_metrics", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("id", sa.Integer(), nullable=False), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("user_id", postgresql.UUID(as_uuid=True), nullable=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("persona_id", sa.Integer(), nullable=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("agent_type", sa.String(), nullable=False), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("start_time", sa.DateTime(timezone=True), nullable=False), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("base_duration_s", sa.Float(), nullable=False), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("full_duration_s", sa.Float(), nullable=False), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("base_metrics", postgresql.JSONB(), nullable=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("refined_metrics", postgresql.JSONB(), nullable=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("all_metrics", postgresql.JSONB(), nullable=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.ForeignKeyConstraint( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
["persona_id"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
["persona.id"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.ForeignKeyConstraint(["user_id"], ["user.id"], ondelete="CASCADE"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.PrimaryKeyConstraint("id"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Create sub_question table | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.create_table( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"agent__sub_question", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("id", sa.Integer, primary_key=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("primary_question_id", sa.Integer, sa.ForeignKey("chat_message.id")), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"chat_session_id", UUID(as_uuid=True), sa.ForeignKey("chat_session.id") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("sub_question", sa.Text), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: sub_question.sub_question column should be marked as nullable=False since it appears to be a required field |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"time_created", sa.DateTime(timezone=True), server_default=sa.func.now() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("sub_answer", sa.Text), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("sub_question_doc_results", postgresql.JSONB(), nullable=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("level", sa.Integer(), nullable=False), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("level_question_num", sa.Integer(), nullable=False), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+45
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: sub_question table is missing foreign key constraints for primary_question_id and chat_session_id. This could lead to orphaned records if parent records are deleted.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Create sub_query table | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.create_table( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"agent__sub_query", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("id", sa.Integer, primary_key=True), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"parent_question_id", sa.Integer, sa.ForeignKey("agent__sub_question.id") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"chat_session_id", UUID(as_uuid=True), sa.ForeignKey("chat_session.id") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+64
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: sub_query table is missing ondelete behavior for foreign key constraints. Should specify CASCADE or SET NULL to handle parent record deletion.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column("sub_query", sa.Text), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"time_created", sa.DateTime(timezone=True), server_default=sa.func.now() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Create sub_query__search_doc association table | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.create_table( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"agent__sub_query__search_doc", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"sub_query_id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Integer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.ForeignKey("agent__sub_query.id"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
primary_key=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"search_doc_id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Integer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.ForeignKey("search_doc.id"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
primary_key=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.add_column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"chat_message", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"refined_answer_improvement", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
sa.Boolean(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
nullable=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
def downgrade() -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.drop_column("chat_message", "refined_answer_improvement") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.drop_table("agent__sub_query__search_doc") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.drop_table("agent__sub_query") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.drop_table("agent__sub_question") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
op.drop_table("agent__search_metrics") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
from langgraph.graph import END | ||
from langgraph.graph import START | ||
from langgraph.graph import StateGraph | ||
|
||
from onyx.agents.agent_search.basic.states import BasicInput | ||
from onyx.agents.agent_search.basic.states import BasicOutput | ||
from onyx.agents.agent_search.basic.states import BasicState | ||
from onyx.agents.agent_search.orchestration.nodes.basic_use_tool_response import ( | ||
basic_use_tool_response, | ||
) | ||
from onyx.agents.agent_search.orchestration.nodes.llm_tool_choice import llm_tool_choice | ||
from onyx.agents.agent_search.orchestration.nodes.prepare_tool_input import ( | ||
prepare_tool_input, | ||
) | ||
from onyx.agents.agent_search.orchestration.nodes.tool_call import tool_call | ||
from onyx.utils.logger import setup_logger | ||
|
||
logger = setup_logger() | ||
|
||
|
||
def basic_graph_builder() -> StateGraph: | ||
graph = StateGraph( | ||
state_schema=BasicState, | ||
input=BasicInput, | ||
output=BasicOutput, | ||
) | ||
|
||
### Add nodes ### | ||
|
||
graph.add_node( | ||
node="prepare_tool_input", | ||
action=prepare_tool_input, | ||
) | ||
|
||
graph.add_node( | ||
node="llm_tool_choice", | ||
action=llm_tool_choice, | ||
) | ||
|
||
graph.add_node( | ||
node="tool_call", | ||
action=tool_call, | ||
) | ||
|
||
graph.add_node( | ||
node="basic_use_tool_response", | ||
action=basic_use_tool_response, | ||
) | ||
|
||
### Add edges ### | ||
|
||
graph.add_edge(start_key=START, end_key="prepare_tool_input") | ||
|
||
graph.add_edge(start_key="prepare_tool_input", end_key="llm_tool_choice") | ||
|
||
graph.add_conditional_edges("llm_tool_choice", should_continue, ["tool_call", END]) | ||
|
||
graph.add_edge( | ||
start_key="tool_call", | ||
end_key="basic_use_tool_response", | ||
) | ||
|
||
graph.add_edge( | ||
start_key="basic_use_tool_response", | ||
end_key=END, | ||
) | ||
|
||
return graph | ||
|
||
|
||
def should_continue(state: BasicState) -> str: | ||
return ( | ||
# If there are no tool calls, basic graph already streamed the answer | ||
END | ||
if state.tool_choice is None | ||
else "tool_call" | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
from onyx.db.engine import get_session_context_manager | ||
from onyx.context.search.models import SearchRequest | ||
from onyx.llm.factory import get_default_llms | ||
from onyx.agents.agent_search.shared_graph_utils.utils import get_test_config | ||
|
||
graph = basic_graph_builder() | ||
compiled_graph = graph.compile() | ||
input = BasicInput(_unused=True) | ||
primary_llm, fast_llm = get_default_llms() | ||
with get_session_context_manager() as db_session: | ||
config, _ = get_test_config( | ||
db_session=db_session, | ||
primary_llm=primary_llm, | ||
fast_llm=fast_llm, | ||
search_request=SearchRequest(query="How does onyx use FastAPI?"), | ||
) | ||
compiled_graph.invoke(input, config={"metadata": {"config": config}}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from typing import TypedDict | ||
|
||
from langchain_core.messages import AIMessageChunk | ||
from pydantic import BaseModel | ||
|
||
from onyx.agents.agent_search.orchestration.states import ToolCallUpdate | ||
from onyx.agents.agent_search.orchestration.states import ToolChoiceInput | ||
from onyx.agents.agent_search.orchestration.states import ToolChoiceUpdate | ||
|
||
# States contain values that change over the course of graph execution, | ||
# Config is for values that are set at the start and never change. | ||
# If you are using a value from the config and realize it needs to change, | ||
# you should add it to the state and use/update the version in the state. | ||
|
||
|
||
## Graph Input State | ||
class BasicInput(BaseModel): | ||
# Langgraph needs a nonempty input, but we pass in all static | ||
# data through a RunnableConfig. | ||
_unused: bool = True | ||
|
||
|
||
## Graph Output State | ||
class BasicOutput(TypedDict): | ||
tool_call_chunk: AIMessageChunk | ||
|
||
|
||
## Graph State | ||
class BasicState( | ||
BasicInput, | ||
ToolChoiceInput, | ||
ToolCallUpdate, | ||
ToolChoiceUpdate, | ||
): | ||
pass |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,63 @@ | ||||||||||||||||||||||||||||||
from collections.abc import Iterator | ||||||||||||||||||||||||||||||
from typing import cast | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
from langchain_core.messages import AIMessageChunk | ||||||||||||||||||||||||||||||
from langchain_core.messages import BaseMessage | ||||||||||||||||||||||||||||||
from langgraph.types import StreamWriter | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
from onyx.agents.agent_search.shared_graph_utils.utils import write_custom_event | ||||||||||||||||||||||||||||||
from onyx.chat.models import LlmDoc | ||||||||||||||||||||||||||||||
from onyx.chat.stream_processing.answer_response_handler import AnswerResponseHandler | ||||||||||||||||||||||||||||||
from onyx.chat.stream_processing.answer_response_handler import CitationResponseHandler | ||||||||||||||||||||||||||||||
from onyx.chat.stream_processing.answer_response_handler import ( | ||||||||||||||||||||||||||||||
PassThroughAnswerResponseHandler, | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
from onyx.chat.stream_processing.utils import map_document_id_order | ||||||||||||||||||||||||||||||
from onyx.utils.logger import setup_logger | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
logger = setup_logger() | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
def process_llm_stream( | ||||||||||||||||||||||||||||||
messages: Iterator[BaseMessage], | ||||||||||||||||||||||||||||||
should_stream_answer: bool, | ||||||||||||||||||||||||||||||
writer: StreamWriter, | ||||||||||||||||||||||||||||||
final_search_results: list[LlmDoc] | None = None, | ||||||||||||||||||||||||||||||
displayed_search_results: list[LlmDoc] | None = None, | ||||||||||||||||||||||||||||||
) -> AIMessageChunk: | ||||||||||||||||||||||||||||||
tool_call_chunk = AIMessageChunk(content="") | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if final_search_results and displayed_search_results: | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yuhongsun96 we're using a CitationResponseHandler here, but using other code to handle agent search citations. A little unfortunate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably use the same style of objects at least, even if there is more than one of them for each case. |
||||||||||||||||||||||||||||||
answer_handler: AnswerResponseHandler = CitationResponseHandler( | ||||||||||||||||||||||||||||||
context_docs=final_search_results, | ||||||||||||||||||||||||||||||
final_doc_id_to_rank_map=map_document_id_order(final_search_results), | ||||||||||||||||||||||||||||||
display_doc_id_to_rank_map=map_document_id_order(displayed_search_results), | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
Comment on lines
+30
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: CitationResponseHandler is only created if both results are non-None, but individual nulls aren't handled. Could cause issues if only one is None
Suggested change
|
||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||
answer_handler = PassThroughAnswerResponseHandler() | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
full_answer = "" | ||||||||||||||||||||||||||||||
# This stream will be the llm answer if no tool is chosen. When a tool is chosen, | ||||||||||||||||||||||||||||||
# the stream will contain AIMessageChunks with tool call information. | ||||||||||||||||||||||||||||||
for message in messages: | ||||||||||||||||||||||||||||||
answer_piece = message.content | ||||||||||||||||||||||||||||||
if not isinstance(answer_piece, str): | ||||||||||||||||||||||||||||||
# this is only used for logging, so fine to | ||||||||||||||||||||||||||||||
# just add the string representation | ||||||||||||||||||||||||||||||
answer_piece = str(answer_piece) | ||||||||||||||||||||||||||||||
full_answer += answer_piece | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if isinstance(message, AIMessageChunk) and ( | ||||||||||||||||||||||||||||||
message.tool_call_chunks or message.tool_calls | ||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||
tool_call_chunk += message # type: ignore | ||||||||||||||||||||||||||||||
elif should_stream_answer: | ||||||||||||||||||||||||||||||
for response_part in answer_handler.handle_response_part(message, []): | ||||||||||||||||||||||||||||||
write_custom_event( | ||||||||||||||||||||||||||||||
"basic_response", | ||||||||||||||||||||||||||||||
response_part, | ||||||||||||||||||||||||||||||
writer, | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
logger.debug(f"Full answer: {full_answer}") | ||||||||||||||||||||||||||||||
return cast(AIMessageChunk, tool_call_chunk) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider adding a .gitignore entry for all test_data.json files recursively using **/test_data.json to catch any future test data files