khoj 1.42.1.dev10__py3-none-any.whl → 1.42.2.dev1__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.
- khoj/database/adapters/__init__.py +3 -1
- khoj/database/models/__init__.py +9 -9
- khoj/interface/compiled/404/index.html +2 -2
- khoj/interface/compiled/_next/static/chunks/{2327-aa22697ed9c8d54a.js → 2327-f03b2a77f67b8f8c.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/{5138-2cce449fd2454abf.js → 5138-81457f7f59956b56.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/agents/layout-e00fb81dca656a10.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/chat/layout-33934fc2d6ae6838.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/chat/{page-898079bcea5376f4.js → page-1726184cf1c1b86e.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/{webpack-964e8ed3380daff1.js → webpack-1c900156837baf90.js} +1 -1
- khoj/interface/compiled/_next/static/css/{2945c4a857922f3b.css → c34713c98384ee87.css} +1 -1
- khoj/interface/compiled/agents/index.html +2 -2
- khoj/interface/compiled/agents/index.txt +2 -2
- khoj/interface/compiled/automations/index.html +2 -2
- khoj/interface/compiled/automations/index.txt +3 -3
- khoj/interface/compiled/chat/index.html +2 -2
- khoj/interface/compiled/chat/index.txt +2 -2
- khoj/interface/compiled/index.html +2 -2
- khoj/interface/compiled/index.txt +2 -2
- khoj/interface/compiled/search/index.html +2 -2
- khoj/interface/compiled/search/index.txt +2 -2
- khoj/interface/compiled/settings/index.html +2 -2
- khoj/interface/compiled/settings/index.txt +4 -4
- khoj/interface/compiled/share/chat/index.html +2 -2
- khoj/interface/compiled/share/chat/index.txt +2 -2
- khoj/processor/conversation/anthropic/anthropic_chat.py +7 -7
- khoj/processor/conversation/google/gemini_chat.py +7 -7
- khoj/processor/conversation/offline/chat_model.py +6 -6
- khoj/processor/conversation/openai/gpt.py +7 -7
- khoj/processor/conversation/utils.py +94 -89
- khoj/processor/image/generate.py +16 -11
- khoj/processor/operator/__init__.py +2 -3
- khoj/processor/operator/operator_agent_binary.py +11 -11
- khoj/processor/tools/online_search.py +9 -3
- khoj/processor/tools/run_code.py +5 -5
- khoj/routers/api.py +14 -8
- khoj/routers/api_chat.py +16 -16
- khoj/routers/helpers.py +44 -43
- khoj/routers/research.py +8 -10
- {khoj-1.42.1.dev10.dist-info → khoj-1.42.2.dev1.dist-info}/METADATA +1 -1
- {khoj-1.42.1.dev10.dist-info → khoj-1.42.2.dev1.dist-info}/RECORD +51 -51
- khoj/interface/compiled/_next/static/chunks/app/agents/layout-4e2a134ec26aa606.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/chat/layout-ad4d1792ab1a4108.js +0 -1
- /khoj/interface/compiled/_next/static/{2niR8lV9_OpGs1vdb2yMp → Dzg_ViqMwQEjqMgetZPRc}/_buildManifest.js +0 -0
- /khoj/interface/compiled/_next/static/{2niR8lV9_OpGs1vdb2yMp → Dzg_ViqMwQEjqMgetZPRc}/_ssgManifest.js +0 -0
- /khoj/interface/compiled/_next/static/chunks/{1915-1943ee8a628b893c.js → 1915-ab4353eaca76f690.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{2117-5a41630a2bd2eae8.js → 2117-1c18aa2098982bf9.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{4363-e6ac2203564d1a3b.js → 4363-4efaf12abe696251.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{4447-e038b251d626c340.js → 4447-5d44807c40355b1a.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{8667-8136f74e9a086fca.js → 8667-adbe6017a66cef10.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{9259-640fdd77408475df.js → 9259-d8bcd9da9e80c81e.js} +0 -0
- {khoj-1.42.1.dev10.dist-info → khoj-1.42.2.dev1.dist-info}/WHEEL +0 -0
- {khoj-1.42.1.dev10.dist-info → khoj-1.42.2.dev1.dist-info}/entry_points.txt +0 -0
- {khoj-1.42.1.dev10.dist-info → khoj-1.42.2.dev1.dist-info}/licenses/LICENSE +0 -0
@@ -24,7 +24,13 @@ from pydantic import BaseModel
|
|
24
24
|
from transformers import AutoTokenizer, PreTrainedTokenizer, PreTrainedTokenizerFast
|
25
25
|
|
26
26
|
from khoj.database.adapters import ConversationAdapters
|
27
|
-
from khoj.database.models import
|
27
|
+
from khoj.database.models import (
|
28
|
+
ChatMessageModel,
|
29
|
+
ChatModel,
|
30
|
+
ClientApplication,
|
31
|
+
Intent,
|
32
|
+
KhojUser,
|
33
|
+
)
|
28
34
|
from khoj.processor.conversation import prompts
|
29
35
|
from khoj.processor.conversation.offline.utils import download_model, infer_max_tokens
|
30
36
|
from khoj.search_filter.base_filter import BaseFilter
|
@@ -161,8 +167,8 @@ def construct_iteration_history(
|
|
161
167
|
previous_iterations: List[ResearchIteration],
|
162
168
|
previous_iteration_prompt: str,
|
163
169
|
query: str = None,
|
164
|
-
) -> list[
|
165
|
-
iteration_history: list[
|
170
|
+
) -> list[ChatMessageModel]:
|
171
|
+
iteration_history: list[ChatMessageModel] = []
|
166
172
|
previous_iteration_messages: list[dict] = []
|
167
173
|
for idx, iteration in enumerate(previous_iterations):
|
168
174
|
iteration_data = previous_iteration_prompt.format(
|
@@ -176,46 +182,46 @@ def construct_iteration_history(
|
|
176
182
|
|
177
183
|
if previous_iteration_messages:
|
178
184
|
if query:
|
179
|
-
iteration_history.append(
|
185
|
+
iteration_history.append(ChatMessageModel(by="you", message=query))
|
180
186
|
iteration_history.append(
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
187
|
+
ChatMessageModel(
|
188
|
+
by="khoj",
|
189
|
+
intent={"type": "remember", "query": query},
|
190
|
+
message=previous_iteration_messages,
|
191
|
+
)
|
186
192
|
)
|
187
193
|
return iteration_history
|
188
194
|
|
189
195
|
|
190
|
-
def construct_chat_history(
|
191
|
-
|
192
|
-
for chat in
|
193
|
-
if chat
|
194
|
-
if chat
|
195
|
-
|
196
|
-
|
197
|
-
elif chat
|
198
|
-
|
199
|
-
|
200
|
-
elif chat
|
201
|
-
|
202
|
-
|
203
|
-
elif chat
|
204
|
-
|
205
|
-
raw_query_files = chat.
|
196
|
+
def construct_chat_history(chat_history: list[ChatMessageModel], n: int = 4, agent_name="AI") -> str:
|
197
|
+
chat_history_str = ""
|
198
|
+
for chat in chat_history[-n:]:
|
199
|
+
if chat.by == "khoj" and chat.intent.type in ["remember", "reminder", "summarize"]:
|
200
|
+
if chat.intent.inferred_queries:
|
201
|
+
chat_history_str += f'{agent_name}: {{"queries": {chat.intent.inferred_queries}}}\n'
|
202
|
+
chat_history_str += f"{agent_name}: {chat.message}\n\n"
|
203
|
+
elif chat.by == "khoj" and chat.images:
|
204
|
+
chat_history_str += f"User: {chat.intent.query}\n"
|
205
|
+
chat_history_str += f"{agent_name}: [generated image redacted for space]\n"
|
206
|
+
elif chat.by == "khoj" and ("excalidraw" in chat.intent.type):
|
207
|
+
chat_history_str += f"User: {chat.intent.query}\n"
|
208
|
+
chat_history_str += f"{agent_name}: {chat.intent.inferred_queries[0]}\n"
|
209
|
+
elif chat.by == "you":
|
210
|
+
chat_history_str += f"User: {chat.message}\n"
|
211
|
+
raw_query_files = chat.queryFiles
|
206
212
|
if raw_query_files:
|
207
213
|
query_files: Dict[str, str] = {}
|
208
214
|
for file in raw_query_files:
|
209
215
|
query_files[file["name"]] = file["content"]
|
210
216
|
|
211
217
|
query_file_context = gather_raw_query_files(query_files)
|
212
|
-
|
218
|
+
chat_history_str += f"User: {query_file_context}\n"
|
213
219
|
|
214
|
-
return
|
220
|
+
return chat_history_str
|
215
221
|
|
216
222
|
|
217
223
|
def construct_question_history(
|
218
|
-
conversation_log:
|
224
|
+
conversation_log: list[ChatMessageModel],
|
219
225
|
include_query: bool = True,
|
220
226
|
lookback: int = 6,
|
221
227
|
query_prefix: str = "Q",
|
@@ -226,16 +232,16 @@ def construct_question_history(
|
|
226
232
|
"""
|
227
233
|
history_parts = ""
|
228
234
|
original_query = None
|
229
|
-
for chat in conversation_log
|
230
|
-
if chat
|
231
|
-
original_query = chat.
|
235
|
+
for chat in conversation_log[-lookback:]:
|
236
|
+
if chat.by == "you":
|
237
|
+
original_query = json.dumps(chat.message)
|
232
238
|
history_parts += f"{query_prefix}: {original_query}\n"
|
233
|
-
if chat
|
239
|
+
if chat.by == "khoj":
|
234
240
|
if original_query is None:
|
235
241
|
continue
|
236
242
|
|
237
|
-
message = chat.
|
238
|
-
inferred_queries_list = chat.
|
243
|
+
message = chat.message
|
244
|
+
inferred_queries_list = chat.intent.inferred_queries or []
|
239
245
|
|
240
246
|
# Ensure inferred_queries_list is a list, defaulting to the original query in a list
|
241
247
|
if not inferred_queries_list:
|
@@ -246,7 +252,7 @@ def construct_question_history(
|
|
246
252
|
|
247
253
|
if include_query:
|
248
254
|
# Ensure 'type' exists and is a string before checking 'to-image'
|
249
|
-
intent_type = chat.
|
255
|
+
intent_type = chat.intent.type if chat.intent and chat.intent.type else ""
|
250
256
|
if "to-image" not in intent_type:
|
251
257
|
history_parts += f'{agent_name}: {{"queries": {inferred_queries_list}}}\n'
|
252
258
|
history_parts += f"A: {message}\n\n"
|
@@ -259,7 +265,7 @@ def construct_question_history(
|
|
259
265
|
return history_parts
|
260
266
|
|
261
267
|
|
262
|
-
def construct_chat_history_for_operator(conversation_history:
|
268
|
+
def construct_chat_history_for_operator(conversation_history: List[ChatMessageModel], n: int = 6) -> list[AgentMessage]:
|
263
269
|
"""
|
264
270
|
Construct chat history for operator agent in conversation log.
|
265
271
|
Only include last n completed turns (i.e with user and khoj message).
|
@@ -267,22 +273,22 @@ def construct_chat_history_for_operator(conversation_history: dict, n: int = 6)
|
|
267
273
|
chat_history: list[AgentMessage] = []
|
268
274
|
user_message: Optional[AgentMessage] = None
|
269
275
|
|
270
|
-
for chat in conversation_history
|
276
|
+
for chat in conversation_history:
|
271
277
|
if len(chat_history) >= n:
|
272
278
|
break
|
273
|
-
if chat
|
274
|
-
content = [{"type": "text", "text": chat
|
275
|
-
for file in chat.
|
279
|
+
if chat.by == "you" and chat.message:
|
280
|
+
content = [{"type": "text", "text": chat.message}]
|
281
|
+
for file in chat.queryFiles or []:
|
276
282
|
content += [{"type": "text", "text": f'## File: {file["name"]}\n\n{file["content"]}'}]
|
277
283
|
user_message = AgentMessage(role="user", content=content)
|
278
|
-
elif chat
|
279
|
-
chat_history += [user_message, AgentMessage(role="assistant", content=chat
|
284
|
+
elif chat.by == "khoj" and chat.message:
|
285
|
+
chat_history += [user_message, AgentMessage(role="assistant", content=chat.message)]
|
280
286
|
return chat_history
|
281
287
|
|
282
288
|
|
283
289
|
def construct_tool_chat_history(
|
284
290
|
previous_iterations: List[ResearchIteration], tool: ConversationCommand = None
|
285
|
-
) ->
|
291
|
+
) -> List[ChatMessageModel]:
|
286
292
|
"""
|
287
293
|
Construct chat history from previous iterations for a specific tool
|
288
294
|
|
@@ -313,22 +319,23 @@ def construct_tool_chat_history(
|
|
313
319
|
tool or ConversationCommand(iteration.tool), base_extractor
|
314
320
|
)
|
315
321
|
chat_history += [
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
322
|
+
ChatMessageModel(
|
323
|
+
by="you",
|
324
|
+
message=iteration.query,
|
325
|
+
),
|
326
|
+
ChatMessageModel(
|
327
|
+
by="khoj",
|
328
|
+
intent=Intent(
|
329
|
+
type="remember",
|
330
|
+
query=iteration.query,
|
331
|
+
inferred_queries=inferred_query_extractor(iteration),
|
332
|
+
memory_type="notes",
|
333
|
+
),
|
334
|
+
message=iteration.summarizedResult,
|
335
|
+
),
|
329
336
|
]
|
330
337
|
|
331
|
-
return
|
338
|
+
return chat_history
|
332
339
|
|
333
340
|
|
334
341
|
class ChatEvent(Enum):
|
@@ -349,8 +356,8 @@ def message_to_log(
|
|
349
356
|
chat_response,
|
350
357
|
user_message_metadata={},
|
351
358
|
khoj_message_metadata={},
|
352
|
-
|
353
|
-
):
|
359
|
+
chat_history: List[ChatMessageModel] = [],
|
360
|
+
) -> List[ChatMessageModel]:
|
354
361
|
"""Create json logs from messages, metadata for conversation log"""
|
355
362
|
default_khoj_message_metadata = {
|
356
363
|
"intent": {"type": "remember", "memory-type": "notes", "query": user_message},
|
@@ -369,15 +376,17 @@ def message_to_log(
|
|
369
376
|
khoj_log = merge_dicts(khoj_message_metadata, default_khoj_message_metadata)
|
370
377
|
khoj_log = merge_dicts({"message": chat_response, "by": "khoj", "created": khoj_response_time}, khoj_log)
|
371
378
|
|
372
|
-
|
373
|
-
|
379
|
+
human_message = ChatMessageModel(**human_log)
|
380
|
+
khoj_message = ChatMessageModel(**khoj_log)
|
381
|
+
chat_history.extend([human_message, khoj_message])
|
382
|
+
return chat_history
|
374
383
|
|
375
384
|
|
376
385
|
async def save_to_conversation_log(
|
377
386
|
q: str,
|
378
387
|
chat_response: str,
|
379
388
|
user: KhojUser,
|
380
|
-
|
389
|
+
chat_history: List[ChatMessageModel],
|
381
390
|
user_message_time: str = None,
|
382
391
|
compiled_references: List[Dict[str, Any]] = [],
|
383
392
|
online_results: Dict[str, Any] = {},
|
@@ -427,11 +436,11 @@ async def save_to_conversation_log(
|
|
427
436
|
chat_response=chat_response,
|
428
437
|
user_message_metadata=user_message_metadata,
|
429
438
|
khoj_message_metadata=khoj_message_metadata,
|
430
|
-
|
439
|
+
chat_history=chat_history,
|
431
440
|
)
|
432
441
|
await ConversationAdapters.save_conversation(
|
433
442
|
user,
|
434
|
-
|
443
|
+
updated_conversation,
|
435
444
|
client_application=client_application,
|
436
445
|
conversation_id=conversation_id,
|
437
446
|
user_message=q,
|
@@ -502,7 +511,7 @@ def gather_raw_query_files(
|
|
502
511
|
def generate_chatml_messages_with_context(
|
503
512
|
user_message: str,
|
504
513
|
system_message: str = None,
|
505
|
-
|
514
|
+
chat_history: list[ChatMessageModel] = [],
|
506
515
|
model_name="gpt-4o-mini",
|
507
516
|
loaded_model: Optional[Llama] = None,
|
508
517
|
max_prompt_size=None,
|
@@ -529,21 +538,21 @@ def generate_chatml_messages_with_context(
|
|
529
538
|
|
530
539
|
# Extract Chat History for Context
|
531
540
|
chatml_messages: List[ChatMessage] = []
|
532
|
-
for chat in
|
541
|
+
for chat in chat_history:
|
533
542
|
message_context = []
|
534
543
|
message_attached_files = ""
|
535
544
|
|
536
545
|
generated_assets = {}
|
537
546
|
|
538
|
-
chat_message = chat.
|
539
|
-
role = "user" if chat
|
547
|
+
chat_message = chat.message
|
548
|
+
role = "user" if chat.by == "you" else "assistant"
|
540
549
|
|
541
550
|
# Legacy code to handle excalidraw diagrams prior to Dec 2024
|
542
|
-
if chat
|
543
|
-
chat_message = chat[
|
551
|
+
if chat.by == "khoj" and "excalidraw" in chat.intent.type or "":
|
552
|
+
chat_message = (chat.intent.inferred_queries or [])[0]
|
544
553
|
|
545
|
-
if chat.
|
546
|
-
raw_query_files = chat.
|
554
|
+
if chat.queryFiles:
|
555
|
+
raw_query_files = chat.queryFiles
|
547
556
|
query_files_dict = dict()
|
548
557
|
for file in raw_query_files:
|
549
558
|
query_files_dict[file["name"]] = file["content"]
|
@@ -551,24 +560,24 @@ def generate_chatml_messages_with_context(
|
|
551
560
|
message_attached_files = gather_raw_query_files(query_files_dict)
|
552
561
|
chatml_messages.append(ChatMessage(content=message_attached_files, role=role))
|
553
562
|
|
554
|
-
if not is_none_or_empty(chat.
|
563
|
+
if not is_none_or_empty(chat.onlineContext):
|
555
564
|
message_context += [
|
556
565
|
{
|
557
566
|
"type": "text",
|
558
|
-
"text": f"{prompts.online_search_conversation.format(online_results=chat.
|
567
|
+
"text": f"{prompts.online_search_conversation.format(online_results=chat.onlineContext)}",
|
559
568
|
}
|
560
569
|
]
|
561
570
|
|
562
|
-
if not is_none_or_empty(chat.
|
571
|
+
if not is_none_or_empty(chat.codeContext):
|
563
572
|
message_context += [
|
564
573
|
{
|
565
574
|
"type": "text",
|
566
|
-
"text": f"{prompts.code_executed_context.format(code_results=chat.
|
575
|
+
"text": f"{prompts.code_executed_context.format(code_results=chat.codeContext)}",
|
567
576
|
}
|
568
577
|
]
|
569
578
|
|
570
|
-
if not is_none_or_empty(chat.
|
571
|
-
operator_context = chat.
|
579
|
+
if not is_none_or_empty(chat.operatorContext):
|
580
|
+
operator_context = chat.operatorContext
|
572
581
|
operator_content = "\n\n".join([f'## Task: {oc["query"]}\n{oc["response"]}\n' for oc in operator_context])
|
573
582
|
message_context += [
|
574
583
|
{
|
@@ -577,13 +586,9 @@ def generate_chatml_messages_with_context(
|
|
577
586
|
}
|
578
587
|
]
|
579
588
|
|
580
|
-
if not is_none_or_empty(chat.
|
589
|
+
if not is_none_or_empty(chat.context):
|
581
590
|
references = "\n\n".join(
|
582
|
-
{
|
583
|
-
f"# File: {item['file']}\n## {item['compiled']}\n"
|
584
|
-
for item in chat.get("context") or []
|
585
|
-
if isinstance(item, dict)
|
586
|
-
}
|
591
|
+
{f"# File: {item.file}\n## {item.compiled}\n" for item in chat.context or [] if isinstance(item, dict)}
|
587
592
|
)
|
588
593
|
message_context += [{"type": "text", "text": f"{prompts.notes_conversation.format(references=references)}"}]
|
589
594
|
|
@@ -591,14 +596,14 @@ def generate_chatml_messages_with_context(
|
|
591
596
|
reconstructed_context_message = ChatMessage(content=message_context, role="user")
|
592
597
|
chatml_messages.insert(0, reconstructed_context_message)
|
593
598
|
|
594
|
-
if not is_none_or_empty(chat.
|
599
|
+
if not is_none_or_empty(chat.images) and role == "assistant":
|
595
600
|
generated_assets["image"] = {
|
596
|
-
"query": chat.
|
601
|
+
"query": (chat.intent.inferred_queries or [user_message])[0],
|
597
602
|
}
|
598
603
|
|
599
|
-
if not is_none_or_empty(chat.
|
604
|
+
if not is_none_or_empty(chat.mermaidjsDiagram) and role == "assistant":
|
600
605
|
generated_assets["diagram"] = {
|
601
|
-
"query": chat.
|
606
|
+
"query": (chat.intent.inferred_queries or [user_message])[0],
|
602
607
|
}
|
603
608
|
|
604
609
|
if not is_none_or_empty(generated_assets):
|
@@ -610,7 +615,7 @@ def generate_chatml_messages_with_context(
|
|
610
615
|
)
|
611
616
|
|
612
617
|
message_content = construct_structured_message(
|
613
|
-
chat_message, chat.
|
618
|
+
chat_message, chat.images if role == "user" else [], model_type, vision_enabled
|
614
619
|
)
|
615
620
|
|
616
621
|
reconstructed_message = ChatMessage(content=message_content, role=role)
|
khoj/processor/image/generate.py
CHANGED
@@ -10,7 +10,12 @@ from google import genai
|
|
10
10
|
from google.genai import types as gtypes
|
11
11
|
|
12
12
|
from khoj.database.adapters import ConversationAdapters
|
13
|
-
from khoj.database.models import
|
13
|
+
from khoj.database.models import (
|
14
|
+
Agent,
|
15
|
+
ChatMessageModel,
|
16
|
+
KhojUser,
|
17
|
+
TextToImageModelConfig,
|
18
|
+
)
|
14
19
|
from khoj.routers.helpers import ChatEvent, generate_better_image_prompt
|
15
20
|
from khoj.routers.storage import upload_generated_image_to_bucket
|
16
21
|
from khoj.utils import state
|
@@ -23,7 +28,7 @@ logger = logging.getLogger(__name__)
|
|
23
28
|
async def text_to_image(
|
24
29
|
message: str,
|
25
30
|
user: KhojUser,
|
26
|
-
|
31
|
+
chat_history: List[ChatMessageModel],
|
27
32
|
location_data: LocationData,
|
28
33
|
references: List[Dict[str, Any]],
|
29
34
|
online_results: Dict[str, Any],
|
@@ -46,14 +51,14 @@ async def text_to_image(
|
|
46
51
|
return
|
47
52
|
|
48
53
|
text2image_model = text_to_image_config.model_name
|
49
|
-
|
50
|
-
for chat in
|
51
|
-
if chat
|
52
|
-
|
53
|
-
|
54
|
-
elif chat
|
55
|
-
|
56
|
-
|
54
|
+
chat_history_str = ""
|
55
|
+
for chat in chat_history[-4:]:
|
56
|
+
if chat.by == "khoj" and chat.intent and chat.intent.type in ["remember", "reminder"]:
|
57
|
+
chat_history_str += f"Q: {chat.intent.query or ''}\n"
|
58
|
+
chat_history_str += f"A: {chat.message}\n"
|
59
|
+
elif chat.by == "khoj" and chat.images:
|
60
|
+
chat_history_str += f"Q: {chat.intent.query}\n"
|
61
|
+
chat_history_str += f"A: Improved Prompt: {chat.intent.inferred_queries[0]}\n"
|
57
62
|
|
58
63
|
if send_status_func:
|
59
64
|
async for event in send_status_func("**Enhancing the Painting Prompt**"):
|
@@ -63,7 +68,7 @@ async def text_to_image(
|
|
63
68
|
# Use the user's message, chat history, and other context
|
64
69
|
image_prompt = await generate_better_image_prompt(
|
65
70
|
message,
|
66
|
-
|
71
|
+
chat_history_str,
|
67
72
|
location_data=location_data,
|
68
73
|
note_references=references,
|
69
74
|
online_results=online_results,
|
@@ -5,10 +5,9 @@ import os
|
|
5
5
|
from typing import Callable, List, Optional
|
6
6
|
|
7
7
|
from khoj.database.adapters import AgentAdapters, ConversationAdapters
|
8
|
-
from khoj.database.models import Agent, ChatModel, KhojUser
|
8
|
+
from khoj.database.models import Agent, ChatMessageModel, ChatModel, KhojUser
|
9
9
|
from khoj.processor.conversation.utils import (
|
10
10
|
OperatorRun,
|
11
|
-
construct_chat_history,
|
12
11
|
construct_chat_history_for_operator,
|
13
12
|
)
|
14
13
|
from khoj.processor.operator.operator_actions import *
|
@@ -34,7 +33,7 @@ logger = logging.getLogger(__name__)
|
|
34
33
|
async def operate_environment(
|
35
34
|
query: str,
|
36
35
|
user: KhojUser,
|
37
|
-
conversation_log:
|
36
|
+
conversation_log: List[ChatMessageModel],
|
38
37
|
location_data: LocationData,
|
39
38
|
previous_trajectory: Optional[OperatorRun] = None,
|
40
39
|
environment_type: EnvironmentType = EnvironmentType.COMPUTER,
|
@@ -4,7 +4,7 @@ from datetime import datetime
|
|
4
4
|
from textwrap import dedent
|
5
5
|
from typing import List, Optional
|
6
6
|
|
7
|
-
from khoj.database.models import ChatModel
|
7
|
+
from khoj.database.models import ChatMessageModel, ChatModel
|
8
8
|
from khoj.processor.conversation.utils import (
|
9
9
|
AgentMessage,
|
10
10
|
OperatorRun,
|
@@ -119,13 +119,13 @@ class BinaryOperatorAgent(OperatorAgent):
|
|
119
119
|
query_screenshot = self._get_message_images(current_message)
|
120
120
|
|
121
121
|
# Construct input for visual reasoner history
|
122
|
-
visual_reasoner_history =
|
122
|
+
visual_reasoner_history = self._format_message_for_api(self.messages)
|
123
123
|
try:
|
124
124
|
natural_language_action = await send_message_to_model_wrapper(
|
125
125
|
query=query_text,
|
126
126
|
query_images=query_screenshot,
|
127
127
|
system_message=reasoning_system_prompt,
|
128
|
-
|
128
|
+
chat_history=visual_reasoner_history,
|
129
129
|
agent_chat_model=self.reasoning_model,
|
130
130
|
tracer=self.tracer,
|
131
131
|
)
|
@@ -238,11 +238,11 @@ class BinaryOperatorAgent(OperatorAgent):
|
|
238
238
|
|
239
239
|
async def summarize(self, env_state: EnvState, summarize_prompt: str = None) -> str:
|
240
240
|
summarize_prompt = summarize_prompt or self.summarize_prompt
|
241
|
-
conversation_history =
|
241
|
+
conversation_history = self._format_message_for_api(self.messages)
|
242
242
|
try:
|
243
243
|
summary = await send_message_to_model_wrapper(
|
244
244
|
query=summarize_prompt,
|
245
|
-
|
245
|
+
chat_history=conversation_history,
|
246
246
|
agent_chat_model=self.reasoning_model,
|
247
247
|
tracer=self.tracer,
|
248
248
|
)
|
@@ -296,14 +296,14 @@ class BinaryOperatorAgent(OperatorAgent):
|
|
296
296
|
images = [item["image_url"]["url"] for item in message.content if item["type"] == "image_url"]
|
297
297
|
return images
|
298
298
|
|
299
|
-
def _format_message_for_api(self, messages: list[AgentMessage]) -> List[
|
299
|
+
def _format_message_for_api(self, messages: list[AgentMessage]) -> List[ChatMessageModel]:
|
300
300
|
"""Format operator agent messages into the Khoj conversation history format."""
|
301
301
|
formatted_messages = [
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
302
|
+
ChatMessageModel(
|
303
|
+
message=self._get_message_text(message),
|
304
|
+
images=self._get_message_images(message),
|
305
|
+
by="you" if message.role in ["user", "environment"] else message.role,
|
306
|
+
)
|
307
307
|
for message in messages
|
308
308
|
]
|
309
309
|
return formatted_messages
|
@@ -10,7 +10,13 @@ from bs4 import BeautifulSoup
|
|
10
10
|
from markdownify import markdownify
|
11
11
|
|
12
12
|
from khoj.database.adapters import ConversationAdapters
|
13
|
-
from khoj.database.models import
|
13
|
+
from khoj.database.models import (
|
14
|
+
Agent,
|
15
|
+
ChatMessageModel,
|
16
|
+
KhojUser,
|
17
|
+
ServerChatSettings,
|
18
|
+
WebScraper,
|
19
|
+
)
|
14
20
|
from khoj.processor.conversation import prompts
|
15
21
|
from khoj.routers.helpers import (
|
16
22
|
ChatEvent,
|
@@ -59,7 +65,7 @@ OLOSTEP_QUERY_PARAMS = {
|
|
59
65
|
|
60
66
|
async def search_online(
|
61
67
|
query: str,
|
62
|
-
conversation_history:
|
68
|
+
conversation_history: List[ChatMessageModel],
|
63
69
|
location: LocationData,
|
64
70
|
user: KhojUser,
|
65
71
|
send_status_func: Optional[Callable] = None,
|
@@ -361,7 +367,7 @@ async def search_with_serper(query: str, location: LocationData) -> Tuple[str, D
|
|
361
367
|
|
362
368
|
async def read_webpages(
|
363
369
|
query: str,
|
364
|
-
conversation_history:
|
370
|
+
conversation_history: List[ChatMessageModel],
|
365
371
|
location: LocationData,
|
366
372
|
user: KhojUser,
|
367
373
|
send_status_func: Optional[Callable] = None,
|
khoj/processor/tools/run_code.py
CHANGED
@@ -20,7 +20,7 @@ from tenacity import (
|
|
20
20
|
)
|
21
21
|
|
22
22
|
from khoj.database.adapters import FileObjectAdapters
|
23
|
-
from khoj.database.models import Agent, FileObject, KhojUser
|
23
|
+
from khoj.database.models import Agent, ChatMessageModel, FileObject, KhojUser
|
24
24
|
from khoj.processor.conversation import prompts
|
25
25
|
from khoj.processor.conversation.utils import (
|
26
26
|
ChatEvent,
|
@@ -50,7 +50,7 @@ class GeneratedCode(NamedTuple):
|
|
50
50
|
|
51
51
|
async def run_code(
|
52
52
|
query: str,
|
53
|
-
conversation_history:
|
53
|
+
conversation_history: List[ChatMessageModel],
|
54
54
|
context: str,
|
55
55
|
location_data: LocationData,
|
56
56
|
user: KhojUser,
|
@@ -116,7 +116,7 @@ async def run_code(
|
|
116
116
|
|
117
117
|
async def generate_python_code(
|
118
118
|
q: str,
|
119
|
-
|
119
|
+
chat_history: List[ChatMessageModel],
|
120
120
|
context: str,
|
121
121
|
location_data: LocationData,
|
122
122
|
user: KhojUser,
|
@@ -127,7 +127,7 @@ async def generate_python_code(
|
|
127
127
|
) -> GeneratedCode:
|
128
128
|
location = f"{location_data}" if location_data else "Unknown"
|
129
129
|
username = prompts.user_name.format(name=user.get_full_name()) if user.get_full_name() else ""
|
130
|
-
|
130
|
+
chat_history_str = construct_chat_history(chat_history)
|
131
131
|
|
132
132
|
utc_date = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d")
|
133
133
|
personality_context = (
|
@@ -143,7 +143,7 @@ async def generate_python_code(
|
|
143
143
|
|
144
144
|
code_generation_prompt = prompts.python_code_generation_prompt.format(
|
145
145
|
query=q,
|
146
|
-
chat_history=
|
146
|
+
chat_history=chat_history_str,
|
147
147
|
context=context,
|
148
148
|
has_network_access=network_access_context,
|
149
149
|
current_date=utc_date,
|
khoj/routers/api.py
CHANGED
@@ -29,7 +29,13 @@ from khoj.database.adapters import (
|
|
29
29
|
get_default_search_model,
|
30
30
|
get_user_photo,
|
31
31
|
)
|
32
|
-
from khoj.database.models import
|
32
|
+
from khoj.database.models import (
|
33
|
+
Agent,
|
34
|
+
ChatMessageModel,
|
35
|
+
ChatModel,
|
36
|
+
KhojUser,
|
37
|
+
SpeechToTextModelOptions,
|
38
|
+
)
|
33
39
|
from khoj.processor.conversation import prompts
|
34
40
|
from khoj.processor.conversation.anthropic.anthropic_chat import (
|
35
41
|
extract_questions_anthropic,
|
@@ -353,7 +359,7 @@ def set_user_name(
|
|
353
359
|
|
354
360
|
async def extract_references_and_questions(
|
355
361
|
user: KhojUser,
|
356
|
-
|
362
|
+
chat_history: list[ChatMessageModel],
|
357
363
|
q: str,
|
358
364
|
n: int,
|
359
365
|
d: float,
|
@@ -432,7 +438,7 @@ async def extract_references_and_questions(
|
|
432
438
|
defiltered_query,
|
433
439
|
model=chat_model,
|
434
440
|
loaded_model=loaded_model,
|
435
|
-
|
441
|
+
chat_history=chat_history,
|
436
442
|
should_extract_questions=True,
|
437
443
|
location_data=location_data,
|
438
444
|
user=user,
|
@@ -450,7 +456,7 @@ async def extract_references_and_questions(
|
|
450
456
|
model=chat_model_name,
|
451
457
|
api_key=api_key,
|
452
458
|
api_base_url=base_url,
|
453
|
-
|
459
|
+
chat_history=chat_history,
|
454
460
|
location_data=location_data,
|
455
461
|
user=user,
|
456
462
|
query_images=query_images,
|
@@ -469,7 +475,7 @@ async def extract_references_and_questions(
|
|
469
475
|
model=chat_model_name,
|
470
476
|
api_key=api_key,
|
471
477
|
api_base_url=api_base_url,
|
472
|
-
|
478
|
+
chat_history=chat_history,
|
473
479
|
location_data=location_data,
|
474
480
|
user=user,
|
475
481
|
vision_enabled=vision_enabled,
|
@@ -487,7 +493,7 @@ async def extract_references_and_questions(
|
|
487
493
|
model=chat_model_name,
|
488
494
|
api_key=api_key,
|
489
495
|
api_base_url=api_base_url,
|
490
|
-
|
496
|
+
chat_history=chat_history,
|
491
497
|
location_data=location_data,
|
492
498
|
max_tokens=chat_model.max_prompt_size,
|
493
499
|
user=user,
|
@@ -606,7 +612,7 @@ def post_automation(
|
|
606
612
|
return Response(content="Invalid crontime", status_code=400)
|
607
613
|
|
608
614
|
# Infer subject, query to run
|
609
|
-
_, query_to_run, generated_subject = schedule_query(q,
|
615
|
+
_, query_to_run, generated_subject = schedule_query(q, chat_history=[], user=user)
|
610
616
|
subject = subject or generated_subject
|
611
617
|
|
612
618
|
# Normalize query parameters
|
@@ -712,7 +718,7 @@ def edit_job(
|
|
712
718
|
return Response(content="Invalid automation", status_code=403)
|
713
719
|
|
714
720
|
# Infer subject, query to run
|
715
|
-
_, query_to_run, _ = schedule_query(q,
|
721
|
+
_, query_to_run, _ = schedule_query(q, chat_history=[], user=user)
|
716
722
|
subject = subject
|
717
723
|
|
718
724
|
# Normalize query parameters
|