khoj 1.42.2.dev1__py3-none-any.whl → 1.42.2.dev19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. khoj/configure.py +2 -0
  2. khoj/database/adapters/__init__.py +6 -6
  3. khoj/interface/compiled/404/index.html +2 -2
  4. khoj/interface/compiled/_next/static/chunks/{2117-1c18aa2098982bf9.js → 2117-056a00add390772b.js} +1 -1
  5. khoj/interface/compiled/_next/static/chunks/{2327-f03b2a77f67b8f8c.js → 2327-aa22697ed9c8d54a.js} +1 -1
  6. khoj/interface/compiled/_next/static/chunks/7127-79a3af5138960272.js +1 -0
  7. khoj/interface/compiled/_next/static/chunks/{5138-81457f7f59956b56.js → 7211-7fedd2ee3655239c.js} +1 -1
  8. khoj/interface/compiled/_next/static/chunks/app/agents/{page-2fac1d5ac7192e73.js → page-774c78ff0f55a228.js} +1 -1
  9. khoj/interface/compiled/_next/static/chunks/app/automations/page-fc4f5a3ca7201154.js +1 -0
  10. khoj/interface/compiled/_next/static/chunks/app/chat/page-14cf05b18e3c00ad.js +1 -0
  11. khoj/interface/compiled/_next/static/chunks/app/{page-45ae5e99e8a61821.js → page-f7a0286dfc31ad6b.js} +1 -1
  12. khoj/interface/compiled/_next/static/chunks/app/search/layout-f5881c7ae3ba0795.js +1 -0
  13. khoj/interface/compiled/_next/static/chunks/app/search/{page-afb5e7ed13d221c1.js → page-f1a7f278c89e09b6.js} +1 -1
  14. khoj/interface/compiled/_next/static/chunks/app/settings/{page-8fb6cc97be8774a7.js → page-5d9134d4a97f8834.js} +1 -1
  15. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-abb6c5f4239ad7be.js +1 -0
  16. khoj/interface/compiled/_next/static/chunks/app/share/chat/{page-9a167dc9b5fcd464.js → page-bcc8f41edcfbcb6c.js} +1 -1
  17. khoj/interface/compiled/_next/static/chunks/{main-876327ac335776ab.js → main-63d6432f34cdf74b.js} +1 -1
  18. khoj/interface/compiled/_next/static/chunks/{webpack-1c900156837baf90.js → webpack-f39eedae8f597e56.js} +1 -1
  19. khoj/interface/compiled/_next/static/css/{c34713c98384ee87.css → 4398afc6d5a37666.css} +1 -1
  20. khoj/interface/compiled/_next/static/css/{9c223d337a984468.css → 7017ee76c2f2cd87.css} +1 -1
  21. khoj/interface/compiled/_next/static/css/e1bf03aa79521f86.css +1 -0
  22. khoj/interface/compiled/agents/index.html +2 -2
  23. khoj/interface/compiled/agents/index.txt +2 -2
  24. khoj/interface/compiled/automations/index.html +2 -2
  25. khoj/interface/compiled/automations/index.txt +3 -3
  26. khoj/interface/compiled/chat/index.html +2 -2
  27. khoj/interface/compiled/chat/index.txt +2 -2
  28. khoj/interface/compiled/index.html +2 -2
  29. khoj/interface/compiled/index.txt +2 -2
  30. khoj/interface/compiled/search/index.html +2 -2
  31. khoj/interface/compiled/search/index.txt +2 -2
  32. khoj/interface/compiled/settings/index.html +2 -2
  33. khoj/interface/compiled/settings/index.txt +4 -4
  34. khoj/interface/compiled/share/chat/index.html +2 -2
  35. khoj/interface/compiled/share/chat/index.txt +2 -2
  36. khoj/processor/conversation/anthropic/anthropic_chat.py +17 -132
  37. khoj/processor/conversation/anthropic/utils.py +1 -1
  38. khoj/processor/conversation/google/gemini_chat.py +18 -139
  39. khoj/processor/conversation/offline/chat_model.py +21 -151
  40. khoj/processor/conversation/openai/gpt.py +12 -126
  41. khoj/processor/conversation/prompts.py +2 -63
  42. khoj/routers/api.py +5 -533
  43. khoj/routers/api_automation.py +243 -0
  44. khoj/routers/api_chat.py +35 -116
  45. khoj/routers/helpers.py +329 -80
  46. khoj/routers/research.py +3 -33
  47. khoj/utils/helpers.py +0 -6
  48. {khoj-1.42.2.dev1.dist-info → khoj-1.42.2.dev19.dist-info}/METADATA +2 -2
  49. {khoj-1.42.2.dev1.dist-info → khoj-1.42.2.dev19.dist-info}/RECORD +59 -58
  50. khoj/interface/compiled/_next/static/chunks/7127-d3199617463d45f0.js +0 -1
  51. khoj/interface/compiled/_next/static/chunks/app/automations/page-465741d9149dfd48.js +0 -1
  52. khoj/interface/compiled/_next/static/chunks/app/chat/page-1726184cf1c1b86e.js +0 -1
  53. khoj/interface/compiled/_next/static/chunks/app/search/layout-c02531d586972d7d.js +0 -1
  54. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-e8e5db7830bf3f47.js +0 -1
  55. khoj/interface/compiled/_next/static/css/fca983d49c3dd1a3.css +0 -1
  56. /khoj/interface/compiled/_next/static/chunks/{1915-ab4353eaca76f690.js → 1915-1943ee8a628b893c.js} +0 -0
  57. /khoj/interface/compiled/_next/static/chunks/{4363-4efaf12abe696251.js → 4363-e6ac2203564d1a3b.js} +0 -0
  58. /khoj/interface/compiled/_next/static/chunks/{4447-5d44807c40355b1a.js → 4447-e038b251d626c340.js} +0 -0
  59. /khoj/interface/compiled/_next/static/chunks/{8667-adbe6017a66cef10.js → 8667-8136f74e9a086fca.js} +0 -0
  60. /khoj/interface/compiled/_next/static/chunks/{9259-d8bcd9da9e80c81e.js → 9259-640fdd77408475df.js} +0 -0
  61. /khoj/interface/compiled/_next/static/{Dzg_ViqMwQEjqMgetZPRc → oXUhXGFp7bJNGngoyQu8D}/_buildManifest.js +0 -0
  62. /khoj/interface/compiled/_next/static/{Dzg_ViqMwQEjqMgetZPRc → oXUhXGFp7bJNGngoyQu8D}/_ssgManifest.js +0 -0
  63. {khoj-1.42.2.dev1.dist-info → khoj-1.42.2.dev19.dist-info}/WHEEL +0 -0
  64. {khoj-1.42.2.dev1.dist-info → khoj-1.42.2.dev19.dist-info}/entry_points.txt +0 -0
  65. {khoj-1.42.2.dev1.dist-info → khoj-1.42.2.dev19.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,243 @@
1
+ import json
2
+ import logging
3
+ import threading
4
+ from typing import Optional
5
+
6
+ import cron_descriptor
7
+ import pytz
8
+ from apscheduler.job import Job
9
+ from apscheduler.triggers.cron import CronTrigger
10
+ from fastapi import APIRouter, Request
11
+ from fastapi.responses import Response
12
+ from starlette.authentication import requires
13
+
14
+ from khoj.database.adapters import AutomationAdapters, ConversationAdapters
15
+ from khoj.database.models import KhojUser
16
+ from khoj.processor.conversation.utils import clean_json
17
+ from khoj.routers.helpers import schedule_automation, schedule_query
18
+ from khoj.utils.helpers import is_none_or_empty
19
+
20
+ # Initialize Router
21
+ api_automation = APIRouter()
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ @api_automation.get("", response_class=Response)
26
+ @requires(["authenticated"])
27
+ def get_automations(request: Request) -> Response:
28
+ user: KhojUser = request.user.object
29
+
30
+ # Collate all automations created by user that are still active
31
+ automations_info = [automation_info for automation_info in AutomationAdapters.get_automations_metadata(user)]
32
+
33
+ # Return tasks information as a JSON response
34
+ return Response(content=json.dumps(automations_info), media_type="application/json", status_code=200)
35
+
36
+
37
+ @api_automation.delete("", response_class=Response)
38
+ @requires(["authenticated"])
39
+ def delete_automation(request: Request, automation_id: str) -> Response:
40
+ user: KhojUser = request.user.object
41
+
42
+ try:
43
+ automation_info = AutomationAdapters.delete_automation(user, automation_id)
44
+ except ValueError:
45
+ return Response(status_code=204)
46
+
47
+ # Return deleted automation information as a JSON response
48
+ return Response(content=json.dumps(automation_info), media_type="application/json", status_code=200)
49
+
50
+
51
+ @api_automation.post("", response_class=Response)
52
+ @requires(["authenticated"])
53
+ def post_automation(
54
+ request: Request,
55
+ q: str,
56
+ crontime: str,
57
+ subject: Optional[str] = None,
58
+ city: Optional[str] = None,
59
+ region: Optional[str] = None,
60
+ country: Optional[str] = None,
61
+ timezone: Optional[str] = None,
62
+ ) -> Response:
63
+ user: KhojUser = request.user.object
64
+
65
+ # Perform validation checks
66
+ if is_none_or_empty(q) or is_none_or_empty(crontime):
67
+ return Response(content="A query and crontime is required", status_code=400)
68
+ if not cron_descriptor.get_description(crontime):
69
+ return Response(content="Invalid crontime", status_code=400)
70
+
71
+ # Infer subject, query to run
72
+ _, query_to_run, generated_subject = schedule_query(q, chat_history=[], user=user)
73
+ subject = subject or generated_subject
74
+
75
+ # Normalize query parameters
76
+ # Add /automated_task prefix to query if not present
77
+ query_to_run = query_to_run.strip()
78
+ if not query_to_run.startswith("/automated_task"):
79
+ query_to_run = f"/automated_task {query_to_run}"
80
+
81
+ # Normalize crontime for AP Scheduler CronTrigger
82
+ crontime = crontime.strip()
83
+ if len(crontime.split(" ")) > 5:
84
+ # Truncate crontime to 5 fields
85
+ crontime = " ".join(crontime.split(" ")[:5])
86
+
87
+ # Convert crontime to standard unix crontime
88
+ crontime = crontime.replace("?", "*")
89
+
90
+ # Disallow minute level automation recurrence
91
+ minute_value = crontime.split(" ")[0]
92
+ if not minute_value.isdigit():
93
+ return Response(
94
+ content="Minute level recurrence is unsupported. Please create a less frequent schedule.",
95
+ status_code=400,
96
+ )
97
+
98
+ # Create new Conversation Session associated with this new task
99
+ title = f"Automation: {subject}"
100
+ conversation = ConversationAdapters.create_conversation_session(user, request.user.client_app, title=title)
101
+
102
+ # Schedule automation with query_to_run, timezone, subject directly provided by user
103
+ try:
104
+ # Use the query to run as the scheduling request if the scheduling request is unset
105
+ calling_url = request.url.replace(query=f"{request.url.query}")
106
+ automation = schedule_automation(
107
+ query_to_run, subject, crontime, timezone, q, user, calling_url, str(conversation.id)
108
+ )
109
+ except Exception as e:
110
+ logger.error(f"Error creating automation {q} for {user.email}: {e}", exc_info=True)
111
+ return Response(
112
+ content=f"Unable to create automation. Ensure the automation doesn't already exist.",
113
+ media_type="text/plain",
114
+ status_code=500,
115
+ )
116
+
117
+ # Collate info about the created user automation
118
+ automation_info = AutomationAdapters.get_automation_metadata(user, automation)
119
+
120
+ # Return information about the created automation as a JSON response
121
+ return Response(content=json.dumps(automation_info), media_type="application/json", status_code=200)
122
+
123
+
124
+ @api_automation.post("/trigger", response_class=Response)
125
+ @requires(["authenticated"])
126
+ def trigger_manual_job(
127
+ request: Request,
128
+ automation_id: str,
129
+ ):
130
+ user: KhojUser = request.user.object
131
+
132
+ # Check, get automation to edit
133
+ try:
134
+ automation: Job = AutomationAdapters.get_automation(user, automation_id)
135
+ except ValueError as e:
136
+ logger.error(f"Error triggering automation {automation_id} for {user.email}: {e}", exc_info=True)
137
+ return Response(content="Invalid automation", status_code=403)
138
+
139
+ # Trigger the job without waiting for the result.
140
+ scheduled_chat_func = automation.func
141
+
142
+ # Run the function in a separate thread
143
+ thread = threading.Thread(target=scheduled_chat_func, args=automation.args, kwargs=automation.kwargs)
144
+ thread.start()
145
+
146
+ return Response(content="Automation triggered", status_code=200)
147
+
148
+
149
+ @api_automation.put("", response_class=Response)
150
+ @requires(["authenticated"])
151
+ def edit_job(
152
+ request: Request,
153
+ automation_id: str,
154
+ q: Optional[str],
155
+ subject: Optional[str],
156
+ crontime: Optional[str],
157
+ city: Optional[str] = None,
158
+ region: Optional[str] = None,
159
+ country: Optional[str] = None,
160
+ timezone: Optional[str] = None,
161
+ ) -> Response:
162
+ user: KhojUser = request.user.object
163
+
164
+ # Perform validation checks
165
+ if is_none_or_empty(q) or is_none_or_empty(subject) or is_none_or_empty(crontime):
166
+ return Response(content="A query, subject and crontime is required", status_code=400)
167
+ if not cron_descriptor.get_description(crontime):
168
+ return Response(content="Invalid crontime", status_code=400)
169
+
170
+ # Check, get automation to edit
171
+ try:
172
+ automation: Job = AutomationAdapters.get_automation(user, automation_id)
173
+ except ValueError as e:
174
+ logger.error(f"Error editing automation {automation_id} for {user.email}: {e}", exc_info=True)
175
+ return Response(content="Invalid automation", status_code=403)
176
+
177
+ # Infer subject, query to run
178
+ _, query_to_run, _ = schedule_query(q, chat_history=[], user=user)
179
+ subject = subject
180
+
181
+ # Normalize query parameters
182
+ # Add /automated_task prefix to query if not present
183
+ query_to_run = query_to_run.strip()
184
+ if not query_to_run.startswith("/automated_task"):
185
+ query_to_run = f"/automated_task {query_to_run}"
186
+ # Normalize crontime for AP Scheduler CronTrigger
187
+ crontime = crontime.strip()
188
+ if len(crontime.split(" ")) > 5:
189
+ # Truncate crontime to 5 fields
190
+ crontime = " ".join(crontime.split(" ")[:5])
191
+ # Convert crontime to standard unix crontime
192
+ crontime = crontime.replace("?", "*")
193
+
194
+ # Disallow minute level automation recurrence
195
+ minute_value = crontime.split(" ")[0]
196
+ if not minute_value.isdigit():
197
+ return Response(
198
+ content="Recurrence of every X minutes is unsupported. Please create a less frequent schedule.",
199
+ status_code=400,
200
+ )
201
+
202
+ # Construct updated automation metadata
203
+ automation_metadata: dict[str, str] = json.loads(clean_json(automation.name))
204
+ automation_metadata["scheduling_request"] = q
205
+ automation_metadata["query_to_run"] = query_to_run
206
+ automation_metadata["subject"] = subject.strip()
207
+ automation_metadata["crontime"] = crontime
208
+ conversation_id = automation_metadata.get("conversation_id")
209
+
210
+ if not conversation_id:
211
+ title = f"Automation: {subject}"
212
+
213
+ # Create new Conversation Session associated with this new task
214
+ conversation = ConversationAdapters.create_conversation_session(user, request.user.client_app, title=title)
215
+
216
+ conversation_id = str(conversation.id)
217
+ automation_metadata["conversation_id"] = conversation_id
218
+
219
+ # Modify automation with updated query, subject
220
+ automation.modify(
221
+ name=json.dumps(automation_metadata),
222
+ kwargs={
223
+ "query_to_run": query_to_run,
224
+ "subject": subject,
225
+ "scheduling_request": q,
226
+ "user": user,
227
+ "calling_url": request.url,
228
+ "conversation_id": conversation_id,
229
+ },
230
+ )
231
+
232
+ # Reschedule automation if crontime updated
233
+ user_timezone = pytz.timezone(timezone)
234
+ trigger = CronTrigger.from_crontab(crontime, user_timezone)
235
+ if automation.trigger != trigger:
236
+ automation.reschedule(trigger=trigger)
237
+
238
+ # Collate info about the updated user automation
239
+ automation = AutomationAdapters.get_automation(user, automation.id)
240
+ automation_info = AutomationAdapters.get_automation_metadata(user, automation)
241
+
242
+ # Return modified automation information as a JSON response
243
+ return Response(content=json.dumps(automation_info), media_type="application/json", status_code=200)
khoj/routers/api_chat.py CHANGED
@@ -40,7 +40,6 @@ from khoj.processor.tools.online_search import (
40
40
  search_online,
41
41
  )
42
42
  from khoj.processor.tools.run_code import run_code
43
- from khoj.routers.api import extract_references_and_questions
44
43
  from khoj.routers.email import send_query_feedback
45
44
  from khoj.routers.helpers import (
46
45
  ApiImageRateLimiter,
@@ -63,6 +62,7 @@ from khoj.routers.helpers import (
63
62
  is_query_empty,
64
63
  is_ready_to_chat,
65
64
  read_chat_stream,
65
+ search_documents,
66
66
  update_telemetry_state,
67
67
  validate_chat_model,
68
68
  )
@@ -1055,113 +1055,11 @@ async def chat(
1055
1055
  if state.verbose > 1:
1056
1056
  logger.debug(f'Researched Results: {"".join(r.summarizedResult for r in research_results)}')
1057
1057
 
1058
- used_slash_summarize = conversation_commands == [ConversationCommand.Summarize]
1059
- # Skip trying to summarize if
1060
- if (
1061
- # summarization intent was inferred
1062
- ConversationCommand.Summarize in conversation_commands
1063
- # and not triggered via slash command
1064
- and not used_slash_summarize
1065
- # but we can't actually summarize
1066
- and len(file_filters) == 0
1067
- ):
1068
- conversation_commands.remove(ConversationCommand.Summarize)
1069
- elif ConversationCommand.Summarize in conversation_commands:
1070
- response_log = ""
1071
- agent_has_entries = await EntryAdapters.aagent_has_entries(agent)
1072
- if len(file_filters) == 0 and not agent_has_entries:
1073
- response_log = "No files selected for summarization. Please add files using the section on the left."
1074
- async for result in send_llm_response(response_log, tracer.get("usage")):
1075
- yield result
1076
- else:
1077
- async for response in generate_summary_from_files(
1078
- q=q,
1079
- user=user,
1080
- file_filters=file_filters,
1081
- chat_history=conversation.messages,
1082
- query_images=uploaded_images,
1083
- agent=agent,
1084
- send_status_func=partial(send_event, ChatEvent.STATUS),
1085
- query_files=attached_file_context,
1086
- tracer=tracer,
1087
- ):
1088
- if isinstance(response, dict) and ChatEvent.STATUS in response:
1089
- yield response[ChatEvent.STATUS]
1090
- else:
1091
- if isinstance(response, str):
1092
- response_log = response
1093
- async for result in send_llm_response(response, tracer.get("usage")):
1094
- yield result
1095
-
1096
- summarized_document = FileAttachment(
1097
- name="Summarized Document",
1098
- content=response_log,
1099
- type="text/plain",
1100
- size=len(response_log.encode("utf-8")),
1101
- )
1102
-
1103
- async for result in send_event(ChatEvent.GENERATED_ASSETS, {"files": [summarized_document.model_dump()]}):
1104
- yield result
1105
-
1106
- generated_files.append(summarized_document)
1107
-
1108
- custom_filters = []
1109
- if conversation_commands == [ConversationCommand.Help]:
1110
- if not q:
1111
- chat_model = await ConversationAdapters.aget_user_chat_model(user)
1112
- if chat_model == None:
1113
- chat_model = await ConversationAdapters.aget_default_chat_model(user)
1114
- model_type = chat_model.model_type
1115
- formatted_help = help_message.format(model=model_type, version=state.khoj_version, device=get_device())
1116
- async for result in send_llm_response(formatted_help, tracer.get("usage")):
1117
- yield result
1118
- return
1119
- # Adding specification to search online specifically on khoj.dev pages.
1120
- custom_filters.append("site:khoj.dev")
1121
- conversation_commands.append(ConversationCommand.Online)
1122
-
1123
- if ConversationCommand.Automation in conversation_commands:
1124
- try:
1125
- automation, crontime, query_to_run, subject = await create_automation(
1126
- q, timezone, user, request.url, chat_history, tracer=tracer
1127
- )
1128
- except Exception as e:
1129
- logger.error(f"Error scheduling task {q} for {user.email}: {e}")
1130
- error_message = f"Unable to create automation. Ensure the automation doesn't already exist."
1131
- async for result in send_llm_response(error_message, tracer.get("usage")):
1132
- yield result
1133
- return
1134
-
1135
- llm_response = construct_automation_created_message(automation, crontime, query_to_run, subject)
1136
- # Trigger task to save conversation to DB
1137
- asyncio.create_task(
1138
- save_to_conversation_log(
1139
- q,
1140
- llm_response,
1141
- user,
1142
- chat_history,
1143
- user_message_time,
1144
- intent_type="automation",
1145
- client_application=request.user.client_app,
1146
- conversation_id=conversation_id,
1147
- inferred_queries=[query_to_run],
1148
- automation_id=automation.id,
1149
- query_images=uploaded_images,
1150
- train_of_thought=train_of_thought,
1151
- raw_query_files=raw_query_files,
1152
- tracer=tracer,
1153
- )
1154
- )
1155
- # Send LLM Response
1156
- async for result in send_llm_response(llm_response, tracer.get("usage")):
1157
- yield result
1158
- return
1159
-
1160
1058
  # Gather Context
1161
1059
  ## Extract Document References
1162
1060
  if not ConversationCommand.Research in conversation_commands:
1163
1061
  try:
1164
- async for result in extract_references_and_questions(
1062
+ async for result in search_documents(
1165
1063
  user,
1166
1064
  chat_history,
1167
1065
  q,
@@ -1216,7 +1114,7 @@ async def chat(
1216
1114
  location,
1217
1115
  user,
1218
1116
  partial(send_event, ChatEvent.STATUS),
1219
- custom_filters,
1117
+ custom_filters=[],
1220
1118
  max_online_searches=3,
1221
1119
  query_images=uploaded_images,
1222
1120
  query_files=attached_file_context,
@@ -1463,33 +1361,29 @@ async def chat(
1463
1361
  code_results,
1464
1362
  operator_results,
1465
1363
  research_results,
1466
- inferred_queries,
1467
- conversation_commands,
1468
1364
  user,
1469
- request.user.client_app,
1470
1365
  location,
1471
1366
  user_name,
1472
1367
  uploaded_images,
1473
- train_of_thought,
1474
1368
  attached_file_context,
1475
- raw_query_files,
1476
- generated_images,
1477
1369
  generated_files,
1478
- generated_mermaidjs_diagram,
1479
1370
  program_execution_context,
1480
1371
  generated_asset_results,
1481
1372
  is_subscribed,
1482
1373
  tracer,
1483
1374
  )
1484
1375
 
1376
+ full_response = ""
1485
1377
  async for item in llm_response:
1486
- # Should not happen with async generator, end is signaled by loop exit. Skip.
1487
- if item is None:
1378
+ # Should not happen with async generator. Skip.
1379
+ if item is None or not isinstance(item, ResponseWithThought):
1380
+ logger.warning(f"Unexpected item type in LLM response: {type(item)}. Skipping.")
1488
1381
  continue
1489
1382
  if cancellation_event.is_set():
1490
1383
  break
1491
- message = item.response if isinstance(item, ResponseWithThought) else item
1492
- if isinstance(item, ResponseWithThought) and item.thought:
1384
+ message = item.response
1385
+ full_response += message if message else ""
1386
+ if item.thought:
1493
1387
  async for result in send_event(ChatEvent.THOUGHT, item.thought):
1494
1388
  yield result
1495
1389
  continue
@@ -1506,6 +1400,31 @@ async def chat(
1506
1400
  logger.warning(f"Error during streaming. Stopping send: {e}")
1507
1401
  break
1508
1402
 
1403
+ # Save conversation once finish streaming
1404
+ asyncio.create_task(
1405
+ save_to_conversation_log(
1406
+ q,
1407
+ chat_response=full_response,
1408
+ user=user,
1409
+ chat_history=chat_history,
1410
+ compiled_references=compiled_references,
1411
+ online_results=online_results,
1412
+ code_results=code_results,
1413
+ operator_results=operator_results,
1414
+ research_results=research_results,
1415
+ inferred_queries=inferred_queries,
1416
+ client_application=request.user.client_app,
1417
+ conversation_id=str(conversation.id),
1418
+ query_images=uploaded_images,
1419
+ train_of_thought=train_of_thought,
1420
+ raw_query_files=raw_query_files,
1421
+ generated_images=generated_images,
1422
+ raw_generated_files=generated_files,
1423
+ generated_mermaidjs_diagram=generated_mermaidjs_diagram,
1424
+ tracer=tracer,
1425
+ )
1426
+ )
1427
+
1509
1428
  # Signal end of LLM response after the loop finishes
1510
1429
  if not cancellation_event.is_set():
1511
1430
  async for result in send_event(ChatEvent.END_LLM_RESPONSE, ""):