khoj 1.24.2.dev3__py3-none-any.whl → 1.25.1.dev34__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 (109) hide show
  1. khoj/configure.py +13 -4
  2. khoj/database/adapters/__init__.py +289 -52
  3. khoj/database/admin.py +20 -1
  4. khoj/database/migrations/0065_remove_agent_avatar_remove_agent_public_and_more.py +49 -0
  5. khoj/database/migrations/0066_remove_agent_tools_agent_input_tools_and_more.py +69 -0
  6. khoj/database/migrations/0067_alter_agent_style_icon.py +50 -0
  7. khoj/database/migrations/0068_alter_agent_output_modes.py +24 -0
  8. khoj/database/migrations/0069_webscraper_serverchatsettings_web_scraper.py +89 -0
  9. khoj/database/models/__init__.py +136 -18
  10. khoj/interface/compiled/404/index.html +1 -1
  11. khoj/interface/compiled/_next/static/chunks/1603-fa3ee48860b9dc5c.js +1 -0
  12. khoj/interface/compiled/_next/static/chunks/2697-a38d01981ad3bdf8.js +1 -0
  13. khoj/interface/compiled/_next/static/chunks/3110-ef2cacd1b8d79ad8.js +1 -0
  14. khoj/interface/compiled/_next/static/chunks/4086-2c74808ba38a5a0f.js +1 -0
  15. khoj/interface/compiled/_next/static/chunks/477-ec86e93db10571c1.js +1 -0
  16. khoj/interface/compiled/_next/static/chunks/51-e8f5bdb69b5ea421.js +1 -0
  17. khoj/interface/compiled/_next/static/chunks/7762-79f2205740622b5c.js +1 -0
  18. khoj/interface/compiled/_next/static/chunks/9178-899fe9a6b754ecfe.js +1 -0
  19. khoj/interface/compiled/_next/static/chunks/9417-29502e39c3e7d60c.js +1 -0
  20. khoj/interface/compiled/_next/static/chunks/9479-7eed36fc954ef804.js +1 -0
  21. khoj/interface/compiled/_next/static/chunks/app/agents/{layout-e71c8e913cccf792.js → layout-75636ab3a413fa8e.js} +1 -1
  22. khoj/interface/compiled/_next/static/chunks/app/agents/page-fa282831808ee536.js +1 -0
  23. khoj/interface/compiled/_next/static/chunks/app/automations/page-5480731341f34450.js +1 -0
  24. khoj/interface/compiled/_next/static/chunks/app/chat/{layout-8102549127db3067.js → layout-96fcf62857bf8f30.js} +1 -1
  25. khoj/interface/compiled/_next/static/chunks/app/chat/page-702057ccbcf27881.js +1 -0
  26. khoj/interface/compiled/_next/static/chunks/app/factchecker/page-e7b34316ec6f44de.js +1 -0
  27. khoj/interface/compiled/_next/static/chunks/app/{layout-f3e40d346da53112.js → layout-d0f0a9067427fb20.js} +1 -1
  28. khoj/interface/compiled/_next/static/chunks/app/page-10a5aad6e04f3cf8.js +1 -0
  29. khoj/interface/compiled/_next/static/chunks/app/search/page-d56541c746fded7d.js +1 -0
  30. khoj/interface/compiled/_next/static/chunks/app/settings/{layout-6f9314b0d7a26046.js → layout-a8f33dfe92f997fb.js} +1 -1
  31. khoj/interface/compiled/_next/static/chunks/app/settings/page-e044a999468a7c5d.js +1 -0
  32. khoj/interface/compiled/_next/static/chunks/app/share/chat/{layout-39f03f9e32399f0f.js → layout-2df56074e42adaa0.js} +1 -1
  33. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-fbbd66a4d4633438.js +1 -0
  34. khoj/interface/compiled/_next/static/chunks/{webpack-d4781cada9b58e75.js → webpack-c0cd5a6afb1f0798.js} +1 -1
  35. khoj/interface/compiled/_next/static/css/2de69f0be774c768.css +1 -0
  36. khoj/interface/compiled/_next/static/css/467a524c75e7d7c0.css +1 -0
  37. khoj/interface/compiled/_next/static/css/592ca99f5122e75a.css +1 -0
  38. khoj/interface/compiled/_next/static/css/b9a6bf04305d98d7.css +25 -0
  39. khoj/interface/compiled/agents/index.html +1 -1
  40. khoj/interface/compiled/agents/index.txt +2 -2
  41. khoj/interface/compiled/automations/index.html +1 -1
  42. khoj/interface/compiled/automations/index.txt +2 -2
  43. khoj/interface/compiled/chat/index.html +1 -1
  44. khoj/interface/compiled/chat/index.txt +2 -2
  45. khoj/interface/compiled/factchecker/index.html +1 -1
  46. khoj/interface/compiled/factchecker/index.txt +2 -2
  47. khoj/interface/compiled/index.html +1 -1
  48. khoj/interface/compiled/index.txt +2 -2
  49. khoj/interface/compiled/search/index.html +1 -1
  50. khoj/interface/compiled/search/index.txt +2 -2
  51. khoj/interface/compiled/settings/index.html +1 -1
  52. khoj/interface/compiled/settings/index.txt +3 -3
  53. khoj/interface/compiled/share/chat/index.html +1 -1
  54. khoj/interface/compiled/share/chat/index.txt +2 -2
  55. khoj/interface/web/assets/icons/agents.svg +1 -0
  56. khoj/interface/web/assets/icons/automation.svg +1 -0
  57. khoj/interface/web/assets/icons/chat.svg +24 -0
  58. khoj/interface/web/login.html +11 -22
  59. khoj/processor/content/notion/notion_to_entries.py +2 -1
  60. khoj/processor/conversation/anthropic/anthropic_chat.py +2 -0
  61. khoj/processor/conversation/google/gemini_chat.py +6 -19
  62. khoj/processor/conversation/google/utils.py +33 -15
  63. khoj/processor/conversation/offline/chat_model.py +3 -1
  64. khoj/processor/conversation/openai/gpt.py +2 -0
  65. khoj/processor/conversation/prompts.py +67 -5
  66. khoj/processor/conversation/utils.py +3 -7
  67. khoj/processor/embeddings.py +6 -3
  68. khoj/processor/image/generate.py +4 -3
  69. khoj/processor/tools/online_search.py +139 -44
  70. khoj/routers/api.py +35 -6
  71. khoj/routers/api_agents.py +235 -4
  72. khoj/routers/api_chat.py +102 -530
  73. khoj/routers/api_content.py +14 -0
  74. khoj/routers/api_model.py +1 -1
  75. khoj/routers/auth.py +9 -1
  76. khoj/routers/helpers.py +181 -68
  77. khoj/routers/subscription.py +18 -4
  78. khoj/search_type/text_search.py +11 -3
  79. khoj/utils/helpers.py +64 -8
  80. khoj/utils/initialization.py +0 -3
  81. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/METADATA +19 -21
  82. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/RECORD +87 -81
  83. khoj/interface/compiled/_next/static/chunks/1603-3e2e1528e3b6ea1d.js +0 -1
  84. khoj/interface/compiled/_next/static/chunks/2697-a29cb9191a9e339c.js +0 -1
  85. khoj/interface/compiled/_next/static/chunks/6648-ee109f4ea33a74e2.js +0 -1
  86. khoj/interface/compiled/_next/static/chunks/7071-b4711cecca6619a8.js +0 -1
  87. khoj/interface/compiled/_next/static/chunks/743-1a64254447cda71f.js +0 -1
  88. khoj/interface/compiled/_next/static/chunks/8423-62ac6c832be2461b.js +0 -1
  89. khoj/interface/compiled/_next/static/chunks/9162-0be016519a18568b.js +0 -1
  90. khoj/interface/compiled/_next/static/chunks/9178-7e815211edcb3657.js +0 -1
  91. khoj/interface/compiled/_next/static/chunks/9417-5d14ac74aaab2c66.js +0 -1
  92. khoj/interface/compiled/_next/static/chunks/9984-e410179c6fac7cf1.js +0 -1
  93. khoj/interface/compiled/_next/static/chunks/app/agents/page-d302911777a3e027.js +0 -1
  94. khoj/interface/compiled/_next/static/chunks/app/automations/page-0a5de8c254c29a1c.js +0 -1
  95. khoj/interface/compiled/_next/static/chunks/app/chat/page-d96bf6a84bb05290.js +0 -1
  96. khoj/interface/compiled/_next/static/chunks/app/factchecker/page-32e61af29e6b431d.js +0 -1
  97. khoj/interface/compiled/_next/static/chunks/app/page-96cab08c985716f4.js +0 -1
  98. khoj/interface/compiled/_next/static/chunks/app/search/page-b3193d46c65571c5.js +0 -1
  99. khoj/interface/compiled/_next/static/chunks/app/settings/page-0db9b708366606ec.js +0 -1
  100. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-f06ac16cfe5b5a16.js +0 -1
  101. khoj/interface/compiled/_next/static/css/1538cedb321e3a97.css +0 -1
  102. khoj/interface/compiled/_next/static/css/24f141a6e37cd204.css +0 -25
  103. khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +0 -1
  104. khoj/interface/compiled/_next/static/css/f768dddada62459d.css +0 -1
  105. /khoj/interface/compiled/_next/static/{_29ceahp81LhuIHo5QgOD → Jid9q6Qg851ioDaaO_fth}/_buildManifest.js +0 -0
  106. /khoj/interface/compiled/_next/static/{_29ceahp81LhuIHo5QgOD → Jid9q6Qg851ioDaaO_fth}/_ssgManifest.js +0 -0
  107. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/WHEEL +0 -0
  108. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/entry_points.txt +0 -0
  109. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,22 @@
1
1
  import json
2
2
  import logging
3
+ from typing import Dict, List, Optional
3
4
 
5
+ from asgiref.sync import sync_to_async
4
6
  from fastapi import APIRouter, Request
5
7
  from fastapi.requests import Request
6
8
  from fastapi.responses import Response
9
+ from pydantic import BaseModel
10
+ from starlette.authentication import requires
7
11
 
8
12
  from khoj.database.adapters import AgentAdapters
9
- from khoj.database.models import KhojUser
10
- from khoj.routers.helpers import CommonQueryParams
13
+ from khoj.database.models import Agent, KhojUser
14
+ from khoj.routers.helpers import CommonQueryParams, acheck_if_safe_prompt
15
+ from khoj.utils.helpers import (
16
+ ConversationCommand,
17
+ command_descriptions_for_agent,
18
+ mode_descriptions_for_agent,
19
+ )
11
20
 
12
21
  # Initialize Router
13
22
  logger = logging.getLogger(__name__)
@@ -16,6 +25,19 @@ logger = logging.getLogger(__name__)
16
25
  api_agents = APIRouter()
17
26
 
18
27
 
28
+ class ModifyAgentBody(BaseModel):
29
+ name: str
30
+ persona: str
31
+ privacy_level: str
32
+ icon: str
33
+ color: str
34
+ chat_model: str
35
+ files: Optional[List[str]] = []
36
+ input_tools: Optional[List[str]] = []
37
+ output_modes: Optional[List[str]] = []
38
+ slug: Optional[str] = None
39
+
40
+
19
41
  @api_agents.get("", response_class=Response)
20
42
  async def all_agents(
21
43
  request: Request,
@@ -25,17 +47,22 @@ async def all_agents(
25
47
  agents = await AgentAdapters.aget_all_accessible_agents(user)
26
48
  agents_packet = list()
27
49
  for agent in agents:
50
+ files = agent.fileobject_set.all()
51
+ file_names = [file.file_name for file in files]
28
52
  agents_packet.append(
29
53
  {
30
54
  "slug": agent.slug,
31
- "avatar": agent.avatar,
32
55
  "name": agent.name,
33
56
  "persona": agent.personality,
34
- "public": agent.public,
35
57
  "creator": agent.creator.username if agent.creator else None,
36
58
  "managed_by_admin": agent.managed_by_admin,
37
59
  "color": agent.style_color,
38
60
  "icon": agent.style_icon,
61
+ "privacy_level": agent.privacy_level,
62
+ "chat_model": agent.chat_model.chat_model,
63
+ "files": file_names,
64
+ "input_tools": agent.input_tools,
65
+ "output_modes": agent.output_modes,
39
66
  }
40
67
  )
41
68
 
@@ -43,3 +70,207 @@ async def all_agents(
43
70
  agents_packet.sort(key=lambda x: x["name"])
44
71
  agents_packet.sort(key=lambda x: x["slug"] == "khoj", reverse=True)
45
72
  return Response(content=json.dumps(agents_packet), media_type="application/json", status_code=200)
73
+
74
+
75
+ @api_agents.get("/options", response_class=Response)
76
+ async def get_agent_configuration_options(
77
+ request: Request,
78
+ common: CommonQueryParams,
79
+ ) -> Response:
80
+ agent_input_tools = [key for key, _ in Agent.InputToolOptions.choices]
81
+ agent_output_modes = [key for key, _ in Agent.OutputModeOptions.choices]
82
+
83
+ agent_input_tool_with_descriptions: Dict[str, str] = {}
84
+ for key in agent_input_tools:
85
+ conversation_command = ConversationCommand(key)
86
+ agent_input_tool_with_descriptions[key] = command_descriptions_for_agent[conversation_command]
87
+
88
+ agent_output_modes_with_descriptions: Dict[str, str] = {}
89
+ for key in agent_output_modes:
90
+ conversation_command = ConversationCommand(key)
91
+ agent_output_modes_with_descriptions[key] = mode_descriptions_for_agent[conversation_command]
92
+
93
+ return Response(
94
+ content=json.dumps(
95
+ {
96
+ "input_tools": agent_input_tool_with_descriptions,
97
+ "output_modes": agent_output_modes_with_descriptions,
98
+ }
99
+ ),
100
+ media_type="application/json",
101
+ status_code=200,
102
+ )
103
+
104
+
105
+ @api_agents.get("/{agent_slug}", response_class=Response)
106
+ async def get_agent(
107
+ request: Request,
108
+ common: CommonQueryParams,
109
+ agent_slug: str,
110
+ ) -> Response:
111
+ user: KhojUser = request.user.object if request.user.is_authenticated else None
112
+ agent = await AgentAdapters.aget_readonly_agent_by_slug(agent_slug, user)
113
+
114
+ if not agent:
115
+ return Response(
116
+ content=json.dumps({"error": f"Agent with name {agent_slug} not found."}),
117
+ media_type="application/json",
118
+ status_code=404,
119
+ )
120
+
121
+ files = agent.fileobject_set.all()
122
+ file_names = [file.file_name for file in files]
123
+ agents_packet = {
124
+ "slug": agent.slug,
125
+ "name": agent.name,
126
+ "persona": agent.personality,
127
+ "creator": agent.creator.username if agent.creator else None,
128
+ "managed_by_admin": agent.managed_by_admin,
129
+ "color": agent.style_color,
130
+ "icon": agent.style_icon,
131
+ "privacy_level": agent.privacy_level,
132
+ "chat_model": agent.chat_model.chat_model,
133
+ "files": file_names,
134
+ "input_tools": agent.input_tools,
135
+ "output_modes": agent.output_modes,
136
+ }
137
+
138
+ return Response(content=json.dumps(agents_packet), media_type="application/json", status_code=200)
139
+
140
+
141
+ @api_agents.delete("/{agent_slug}", response_class=Response)
142
+ @requires(["authenticated"])
143
+ async def delete_agent(
144
+ request: Request,
145
+ common: CommonQueryParams,
146
+ agent_slug: str,
147
+ ) -> Response:
148
+ user: KhojUser = request.user.object
149
+
150
+ agent = await AgentAdapters.aget_agent_by_slug(agent_slug, user)
151
+
152
+ if not agent:
153
+ return Response(
154
+ content=json.dumps({"error": f"Agent with name {agent_slug} not found."}),
155
+ media_type="application/json",
156
+ status_code=404,
157
+ )
158
+
159
+ await AgentAdapters.adelete_agent_by_slug(agent_slug, user)
160
+
161
+ return Response(content=json.dumps({"message": "Agent deleted."}), media_type="application/json", status_code=200)
162
+
163
+
164
+ @api_agents.post("", response_class=Response)
165
+ @requires(["authenticated", "premium"])
166
+ async def create_agent(
167
+ request: Request,
168
+ common: CommonQueryParams,
169
+ body: ModifyAgentBody,
170
+ ) -> Response:
171
+ user: KhojUser = request.user.object
172
+
173
+ is_safe_prompt, reason = True, ""
174
+
175
+ if body.privacy_level != Agent.PrivacyLevel.PRIVATE:
176
+ is_safe_prompt, reason = await acheck_if_safe_prompt(body.persona)
177
+
178
+ if not is_safe_prompt:
179
+ return Response(
180
+ content=json.dumps({"error": f"{reason}"}),
181
+ media_type="application/json",
182
+ status_code=400,
183
+ )
184
+
185
+ agent = await AgentAdapters.aupdate_agent(
186
+ user,
187
+ body.name,
188
+ body.persona,
189
+ body.privacy_level,
190
+ body.icon,
191
+ body.color,
192
+ body.chat_model,
193
+ body.files,
194
+ body.input_tools,
195
+ body.output_modes,
196
+ body.slug,
197
+ )
198
+
199
+ agents_packet = {
200
+ "slug": agent.slug,
201
+ "name": agent.name,
202
+ "persona": agent.personality,
203
+ "creator": agent.creator.username if agent.creator else None,
204
+ "managed_by_admin": agent.managed_by_admin,
205
+ "color": agent.style_color,
206
+ "icon": agent.style_icon,
207
+ "privacy_level": agent.privacy_level,
208
+ "chat_model": agent.chat_model.chat_model,
209
+ "files": body.files,
210
+ "input_tools": agent.input_tools,
211
+ "output_modes": agent.output_modes,
212
+ }
213
+
214
+ return Response(content=json.dumps(agents_packet), media_type="application/json", status_code=200)
215
+
216
+
217
+ @api_agents.patch("", response_class=Response)
218
+ @requires(["authenticated", "premium"])
219
+ async def update_agent(
220
+ request: Request,
221
+ common: CommonQueryParams,
222
+ body: ModifyAgentBody,
223
+ ) -> Response:
224
+ user: KhojUser = request.user.object
225
+
226
+ is_safe_prompt, reason = True, ""
227
+
228
+ if body.privacy_level != Agent.PrivacyLevel.PRIVATE:
229
+ is_safe_prompt, reason = await acheck_if_safe_prompt(body.persona)
230
+
231
+ if not is_safe_prompt:
232
+ return Response(
233
+ content=json.dumps({"error": f"{reason}"}),
234
+ media_type="application/json",
235
+ status_code=400,
236
+ )
237
+
238
+ selected_agent = await AgentAdapters.aget_agent_by_slug(body.slug, user)
239
+
240
+ if not selected_agent:
241
+ return Response(
242
+ content=json.dumps({"error": f"Agent with name {body.name} not found."}),
243
+ media_type="application/json",
244
+ status_code=404,
245
+ )
246
+
247
+ agent = await AgentAdapters.aupdate_agent(
248
+ user,
249
+ body.name,
250
+ body.persona,
251
+ body.privacy_level,
252
+ body.icon,
253
+ body.color,
254
+ body.chat_model,
255
+ body.files,
256
+ body.input_tools,
257
+ body.output_modes,
258
+ body.slug,
259
+ )
260
+
261
+ agents_packet = {
262
+ "slug": agent.slug,
263
+ "name": agent.name,
264
+ "persona": agent.personality,
265
+ "creator": agent.creator.username if agent.creator else None,
266
+ "managed_by_admin": agent.managed_by_admin,
267
+ "color": agent.style_color,
268
+ "icon": agent.style_icon,
269
+ "privacy_level": agent.privacy_level,
270
+ "chat_model": agent.chat_model.chat_model,
271
+ "files": body.files,
272
+ "input_tools": agent.input_tools,
273
+ "output_modes": agent.output_modes,
274
+ }
275
+
276
+ return Response(content=json.dumps(agents_packet), media_type="application/json", status_code=200)