agno 2.3.16__py3-none-any.whl → 2.3.18__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.
- agno/agent/__init__.py +2 -0
- agno/agent/agent.py +4 -53
- agno/agent/remote.py +351 -0
- agno/client/__init__.py +3 -0
- agno/client/os.py +2669 -0
- agno/db/base.py +20 -0
- agno/db/mongo/async_mongo.py +11 -0
- agno/db/mongo/mongo.py +10 -0
- agno/db/mysql/async_mysql.py +9 -0
- agno/db/mysql/mysql.py +9 -0
- agno/db/postgres/async_postgres.py +9 -0
- agno/db/postgres/postgres.py +9 -0
- agno/db/postgres/utils.py +3 -2
- agno/db/sqlite/async_sqlite.py +9 -0
- agno/db/sqlite/sqlite.py +11 -1
- agno/exceptions.py +23 -0
- agno/knowledge/chunking/semantic.py +123 -46
- agno/knowledge/reader/csv_reader.py +1 -1
- agno/knowledge/reader/field_labeled_csv_reader.py +1 -1
- agno/knowledge/reader/json_reader.py +1 -1
- agno/models/google/gemini.py +5 -0
- agno/os/app.py +108 -25
- agno/os/auth.py +25 -1
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +13 -13
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +23 -16
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +6 -6
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +29 -6
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +651 -79
- agno/os/router.py +125 -18
- agno/os/routers/agents/router.py +65 -22
- agno/os/routers/agents/schema.py +16 -4
- agno/os/routers/database.py +5 -0
- agno/os/routers/evals/evals.py +93 -11
- agno/os/routers/evals/utils.py +6 -6
- agno/os/routers/knowledge/knowledge.py +104 -16
- agno/os/routers/memory/memory.py +124 -7
- agno/os/routers/metrics/metrics.py +21 -4
- agno/os/routers/session/session.py +141 -12
- agno/os/routers/teams/router.py +40 -14
- agno/os/routers/teams/schema.py +12 -4
- agno/os/routers/traces/traces.py +54 -4
- agno/os/routers/workflows/router.py +223 -117
- agno/os/routers/workflows/schema.py +65 -1
- agno/os/schema.py +38 -12
- agno/os/utils.py +87 -166
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +484 -0
- agno/run/workflow.py +1 -0
- agno/team/__init__.py +2 -0
- agno/team/remote.py +287 -0
- agno/team/team.py +25 -54
- agno/tracing/exporter.py +10 -6
- agno/tracing/setup.py +2 -1
- agno/utils/agent.py +58 -1
- agno/utils/http.py +68 -20
- agno/utils/os.py +0 -0
- agno/utils/remote.py +23 -0
- agno/vectordb/chroma/chromadb.py +452 -16
- agno/vectordb/pgvector/pgvector.py +7 -0
- agno/vectordb/redis/redisdb.py +1 -1
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +2 -2
- agno/workflow/remote.py +222 -0
- agno/workflow/types.py +0 -73
- agno/workflow/workflow.py +119 -68
- {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/METADATA +1 -1
- {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/RECORD +76 -66
- {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/WHEEL +0 -0
- {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/top_level.txt +0 -0
agno/os/routers/evals/evals.py
CHANGED
|
@@ -2,13 +2,13 @@ import logging
|
|
|
2
2
|
from copy import deepcopy
|
|
3
3
|
from typing import List, Optional, Union, cast
|
|
4
4
|
|
|
5
|
-
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
5
|
+
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
|
6
6
|
|
|
7
|
-
from agno.agent
|
|
7
|
+
from agno.agent import Agent, RemoteAgent
|
|
8
8
|
from agno.db.base import AsyncBaseDb, BaseDb
|
|
9
9
|
from agno.db.schemas.evals import EvalFilterType, EvalType
|
|
10
10
|
from agno.models.utils import get_model
|
|
11
|
-
from agno.os.auth import get_authentication_dependency
|
|
11
|
+
from agno.os.auth import get_auth_token_from_request, get_authentication_dependency
|
|
12
12
|
from agno.os.routers.evals.schemas import (
|
|
13
13
|
DeleteEvalRunsRequest,
|
|
14
14
|
EvalRunInput,
|
|
@@ -33,15 +33,17 @@ from agno.os.schema import (
|
|
|
33
33
|
)
|
|
34
34
|
from agno.os.settings import AgnoAPISettings
|
|
35
35
|
from agno.os.utils import get_agent_by_id, get_db, get_team_by_id
|
|
36
|
-
from agno.
|
|
36
|
+
from agno.remote.base import RemoteDb
|
|
37
|
+
from agno.team import RemoteTeam, Team
|
|
38
|
+
from agno.utils.log import log_warning
|
|
37
39
|
|
|
38
40
|
logger = logging.getLogger(__name__)
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
def get_eval_router(
|
|
42
|
-
dbs: dict[str, list[Union[BaseDb, AsyncBaseDb]]],
|
|
43
|
-
agents: Optional[List[Agent]] = None,
|
|
44
|
-
teams: Optional[List[Team]] = None,
|
|
44
|
+
dbs: dict[str, list[Union[BaseDb, AsyncBaseDb, RemoteDb]]],
|
|
45
|
+
agents: Optional[List[Union[Agent, RemoteAgent]]] = None,
|
|
46
|
+
teams: Optional[List[Union[Team, RemoteTeam]]] = None,
|
|
45
47
|
settings: AgnoAPISettings = AgnoAPISettings(),
|
|
46
48
|
) -> APIRouter:
|
|
47
49
|
"""Create eval router with comprehensive OpenAPI documentation for agent/team evaluation endpoints."""
|
|
@@ -61,9 +63,9 @@ def get_eval_router(
|
|
|
61
63
|
|
|
62
64
|
def attach_routes(
|
|
63
65
|
router: APIRouter,
|
|
64
|
-
dbs: dict[str, list[Union[BaseDb, AsyncBaseDb]]],
|
|
65
|
-
agents: Optional[List[Agent]] = None,
|
|
66
|
-
teams: Optional[List[Team]] = None,
|
|
66
|
+
dbs: dict[str, list[Union[BaseDb, AsyncBaseDb, RemoteDb]]],
|
|
67
|
+
agents: Optional[List[Union[Agent, RemoteAgent]]] = None,
|
|
68
|
+
teams: Optional[List[Union[Team, RemoteTeam]]] = None,
|
|
67
69
|
) -> APIRouter:
|
|
68
70
|
@router.get(
|
|
69
71
|
"/eval-runs",
|
|
@@ -109,6 +111,7 @@ def attach_routes(
|
|
|
109
111
|
},
|
|
110
112
|
)
|
|
111
113
|
async def get_eval_runs(
|
|
114
|
+
request: Request,
|
|
112
115
|
agent_id: Optional[str] = Query(default=None, description="Agent ID"),
|
|
113
116
|
team_id: Optional[str] = Query(default=None, description="Team ID"),
|
|
114
117
|
workflow_id: Optional[str] = Query(default=None, description="Workflow ID"),
|
|
@@ -124,6 +127,23 @@ def attach_routes(
|
|
|
124
127
|
) -> PaginatedResponse[EvalSchema]:
|
|
125
128
|
db = await get_db(dbs, db_id, table)
|
|
126
129
|
|
|
130
|
+
if isinstance(db, RemoteDb):
|
|
131
|
+
auth_token = get_auth_token_from_request(request)
|
|
132
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
133
|
+
return await db.get_eval_runs(
|
|
134
|
+
limit=limit,
|
|
135
|
+
page=page,
|
|
136
|
+
sort_by=sort_by,
|
|
137
|
+
sort_order=sort_order.value if sort_order else None,
|
|
138
|
+
agent_id=agent_id,
|
|
139
|
+
team_id=team_id,
|
|
140
|
+
workflow_id=workflow_id,
|
|
141
|
+
model_id=model_id,
|
|
142
|
+
eval_types=eval_types,
|
|
143
|
+
filter_type=filter_type.value if filter_type else None,
|
|
144
|
+
headers=headers,
|
|
145
|
+
)
|
|
146
|
+
|
|
127
147
|
# TODO: Delete me:
|
|
128
148
|
# Filtering out agent-as-judge by default for now,
|
|
129
149
|
# as they are not supported yet in the AgentOS UI.
|
|
@@ -211,11 +231,17 @@ def attach_routes(
|
|
|
211
231
|
},
|
|
212
232
|
)
|
|
213
233
|
async def get_eval_run(
|
|
234
|
+
request: Request,
|
|
214
235
|
eval_run_id: str,
|
|
215
236
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
216
237
|
table: Optional[str] = Query(default=None, description="Table to query eval run from"),
|
|
217
238
|
) -> EvalSchema:
|
|
218
239
|
db = await get_db(dbs, db_id, table)
|
|
240
|
+
if isinstance(db, RemoteDb):
|
|
241
|
+
auth_token = get_auth_token_from_request(request)
|
|
242
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
243
|
+
return await db.get_eval_run(eval_run_id=eval_run_id, db_id=db_id, table=table, headers=headers)
|
|
244
|
+
|
|
219
245
|
if isinstance(db, AsyncBaseDb):
|
|
220
246
|
db = cast(AsyncBaseDb, db)
|
|
221
247
|
eval_run = await db.get_eval_run(eval_run_id=eval_run_id, deserialize=False)
|
|
@@ -238,12 +264,20 @@ def attach_routes(
|
|
|
238
264
|
},
|
|
239
265
|
)
|
|
240
266
|
async def delete_eval_runs(
|
|
267
|
+
http_request: Request,
|
|
241
268
|
request: DeleteEvalRunsRequest,
|
|
242
269
|
db_id: Optional[str] = Query(default=None, description="Database ID to use for deletion"),
|
|
243
270
|
table: Optional[str] = Query(default=None, description="Table to use for deletion"),
|
|
244
271
|
) -> None:
|
|
245
272
|
try:
|
|
246
273
|
db = await get_db(dbs, db_id, table)
|
|
274
|
+
if isinstance(db, RemoteDb):
|
|
275
|
+
auth_token = get_auth_token_from_request(http_request)
|
|
276
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
277
|
+
return await db.delete_eval_runs(
|
|
278
|
+
eval_run_ids=request.eval_run_ids, db_id=db_id, table=table, headers=headers
|
|
279
|
+
)
|
|
280
|
+
|
|
247
281
|
if isinstance(db, AsyncBaseDb):
|
|
248
282
|
db = cast(AsyncBaseDb, db)
|
|
249
283
|
await db.delete_eval_runs(eval_run_ids=request.eval_run_ids)
|
|
@@ -291,6 +325,7 @@ def attach_routes(
|
|
|
291
325
|
},
|
|
292
326
|
)
|
|
293
327
|
async def update_eval_run(
|
|
328
|
+
http_request: Request,
|
|
294
329
|
eval_run_id: str,
|
|
295
330
|
request: UpdateEvalRunRequest,
|
|
296
331
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
@@ -298,6 +333,13 @@ def attach_routes(
|
|
|
298
333
|
) -> EvalSchema:
|
|
299
334
|
try:
|
|
300
335
|
db = await get_db(dbs, db_id, table)
|
|
336
|
+
if isinstance(db, RemoteDb):
|
|
337
|
+
auth_token = get_auth_token_from_request(http_request)
|
|
338
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
339
|
+
return await db.update_eval_run(
|
|
340
|
+
eval_run_id=eval_run_id, name=request.name, db_id=db_id, table=table, headers=headers
|
|
341
|
+
)
|
|
342
|
+
|
|
301
343
|
if isinstance(db, AsyncBaseDb):
|
|
302
344
|
db = cast(AsyncBaseDb, db)
|
|
303
345
|
eval_run = await db.rename_eval_run(eval_run_id=eval_run_id, name=request.name, deserialize=False)
|
|
@@ -352,11 +394,29 @@ def attach_routes(
|
|
|
352
394
|
},
|
|
353
395
|
)
|
|
354
396
|
async def run_eval(
|
|
397
|
+
request: Request,
|
|
355
398
|
eval_run_input: EvalRunInput,
|
|
356
399
|
db_id: Optional[str] = Query(default=None, description="Database ID to use for evaluation"),
|
|
357
400
|
table: Optional[str] = Query(default=None, description="Table to use for evaluation"),
|
|
358
401
|
) -> Optional[EvalSchema]:
|
|
359
402
|
db = await get_db(dbs, db_id, table)
|
|
403
|
+
if isinstance(db, RemoteDb):
|
|
404
|
+
auth_token = get_auth_token_from_request(request)
|
|
405
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
406
|
+
return await db.create_eval_run(
|
|
407
|
+
eval_type=eval_run_input.eval_type,
|
|
408
|
+
input_text=eval_run_input.input,
|
|
409
|
+
agent_id=eval_run_input.agent_id,
|
|
410
|
+
team_id=eval_run_input.team_id,
|
|
411
|
+
model_id=eval_run_input.model_id,
|
|
412
|
+
model_provider=eval_run_input.model_provider,
|
|
413
|
+
expected_output=eval_run_input.expected_output,
|
|
414
|
+
expected_tool_calls=eval_run_input.expected_tool_calls,
|
|
415
|
+
num_iterations=eval_run_input.num_iterations,
|
|
416
|
+
db_id=db_id,
|
|
417
|
+
table=table,
|
|
418
|
+
headers=headers,
|
|
419
|
+
)
|
|
360
420
|
|
|
361
421
|
if eval_run_input.agent_id and eval_run_input.team_id:
|
|
362
422
|
raise HTTPException(status_code=400, detail="Only one of agent_id or team_id must be provided")
|
|
@@ -365,6 +425,9 @@ def attach_routes(
|
|
|
365
425
|
agent = get_agent_by_id(agent_id=eval_run_input.agent_id, agents=agents)
|
|
366
426
|
if not agent:
|
|
367
427
|
raise HTTPException(status_code=404, detail=f"Agent with id '{eval_run_input.agent_id}' not found")
|
|
428
|
+
if isinstance(agent, RemoteAgent):
|
|
429
|
+
log_warning("Evaluation against remote agents are not supported yet")
|
|
430
|
+
return None
|
|
368
431
|
|
|
369
432
|
default_model = None
|
|
370
433
|
if (
|
|
@@ -387,6 +450,9 @@ def attach_routes(
|
|
|
387
450
|
team = get_team_by_id(team_id=eval_run_input.team_id, teams=teams)
|
|
388
451
|
if not team:
|
|
389
452
|
raise HTTPException(status_code=404, detail=f"Team with id '{eval_run_input.team_id}' not found")
|
|
453
|
+
if isinstance(team, RemoteTeam):
|
|
454
|
+
log_warning("Evaluation against remote teams are not supported yet")
|
|
455
|
+
return None
|
|
390
456
|
|
|
391
457
|
# If model_id/model_provider specified, override team's model temporarily
|
|
392
458
|
default_model = None
|
|
@@ -411,21 +477,37 @@ def attach_routes(
|
|
|
411
477
|
|
|
412
478
|
# Run the evaluation
|
|
413
479
|
if eval_run_input.eval_type == EvalType.ACCURACY:
|
|
480
|
+
if isinstance(agent, RemoteAgent) or isinstance(team, RemoteTeam):
|
|
481
|
+
# TODO: Handle remote evaluation
|
|
482
|
+
log_warning("Evaluation against remote agents are not supported yet")
|
|
483
|
+
return None
|
|
414
484
|
return await run_accuracy_eval(
|
|
415
485
|
eval_run_input=eval_run_input, db=db, agent=agent, team=team, default_model=default_model
|
|
416
486
|
)
|
|
417
487
|
|
|
418
488
|
elif eval_run_input.eval_type == EvalType.AGENT_AS_JUDGE:
|
|
419
489
|
return await run_agent_as_judge_eval(
|
|
420
|
-
eval_run_input=eval_run_input,
|
|
490
|
+
eval_run_input=eval_run_input,
|
|
491
|
+
db=db,
|
|
492
|
+
agent=agent,
|
|
493
|
+
team=team,
|
|
494
|
+
default_model=default_model, # type: ignore
|
|
421
495
|
)
|
|
422
496
|
|
|
423
497
|
elif eval_run_input.eval_type == EvalType.PERFORMANCE:
|
|
498
|
+
if isinstance(agent, RemoteAgent) or isinstance(team, RemoteTeam):
|
|
499
|
+
# TODO: Handle remote evaluation
|
|
500
|
+
log_warning("Evaluation against remote agents are not supported yet")
|
|
501
|
+
return None
|
|
424
502
|
return await run_performance_eval(
|
|
425
503
|
eval_run_input=eval_run_input, db=db, agent=agent, team=team, default_model=default_model
|
|
426
504
|
)
|
|
427
505
|
|
|
428
506
|
else:
|
|
507
|
+
if isinstance(agent, RemoteAgent) or isinstance(team, RemoteTeam):
|
|
508
|
+
# TODO: Handle remote evaluation
|
|
509
|
+
log_warning("Evaluation against remote agents are not supported yet")
|
|
510
|
+
return None
|
|
429
511
|
return await run_reliability_eval(
|
|
430
512
|
eval_run_input=eval_run_input, db=db, agent=agent, team=team, default_model=default_model
|
|
431
513
|
)
|
agno/os/routers/evals/utils.py
CHANGED
|
@@ -2,7 +2,7 @@ from typing import Optional, Union
|
|
|
2
2
|
|
|
3
3
|
from fastapi import HTTPException
|
|
4
4
|
|
|
5
|
-
from agno.agent
|
|
5
|
+
from agno.agent import Agent, RemoteAgent
|
|
6
6
|
from agno.db.base import AsyncBaseDb, BaseDb
|
|
7
7
|
from agno.eval.accuracy import AccuracyEval
|
|
8
8
|
from agno.eval.agent_as_judge import AgentAsJudgeEval
|
|
@@ -10,7 +10,7 @@ from agno.eval.performance import PerformanceEval
|
|
|
10
10
|
from agno.eval.reliability import ReliabilityEval
|
|
11
11
|
from agno.models.base import Model
|
|
12
12
|
from agno.os.routers.evals.schemas import EvalRunInput, EvalSchema
|
|
13
|
-
from agno.team
|
|
13
|
+
from agno.team import RemoteTeam, Team
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
async def run_accuracy_eval(
|
|
@@ -56,8 +56,8 @@ async def run_accuracy_eval(
|
|
|
56
56
|
async def run_agent_as_judge_eval(
|
|
57
57
|
eval_run_input: EvalRunInput,
|
|
58
58
|
db: Union[BaseDb, AsyncBaseDb],
|
|
59
|
-
agent: Optional[Agent] = None,
|
|
60
|
-
team: Optional[Team] = None,
|
|
59
|
+
agent: Optional[Union[Agent, RemoteAgent]] = None,
|
|
60
|
+
team: Optional[Union[Team, RemoteTeam]] = None,
|
|
61
61
|
default_model: Optional[Model] = None,
|
|
62
62
|
) -> EvalSchema:
|
|
63
63
|
"""Run an AgentAsJudge evaluation for the given agent or team"""
|
|
@@ -109,9 +109,9 @@ async def run_agent_as_judge_eval(
|
|
|
109
109
|
|
|
110
110
|
# Restore original model after eval
|
|
111
111
|
if default_model is not None:
|
|
112
|
-
if agent is not None:
|
|
112
|
+
if agent is not None and isinstance(agent, Agent):
|
|
113
113
|
agent.model = default_model
|
|
114
|
-
elif team is not None:
|
|
114
|
+
elif team is not None and isinstance(team, Team):
|
|
115
115
|
team.model = default_model
|
|
116
116
|
|
|
117
117
|
return eval_run
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import math
|
|
4
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
+
from typing import Any, Dict, List, Optional, Union
|
|
5
5
|
|
|
6
|
-
from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, Path, Query, UploadFile
|
|
6
|
+
from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, Path, Query, Request, UploadFile
|
|
7
7
|
|
|
8
8
|
from agno.knowledge.content import Content, FileData
|
|
9
9
|
from agno.knowledge.knowledge import Knowledge
|
|
10
10
|
from agno.knowledge.reader import ReaderFactory
|
|
11
11
|
from agno.knowledge.reader.base import Reader
|
|
12
12
|
from agno.knowledge.utils import get_all_chunkers_info, get_all_readers_info, get_content_types_to_readers_mapping
|
|
13
|
-
from agno.os.auth import get_authentication_dependency
|
|
13
|
+
from agno.os.auth import get_auth_token_from_request, get_authentication_dependency
|
|
14
14
|
from agno.os.routers.knowledge.schemas import (
|
|
15
15
|
ChunkerSchema,
|
|
16
16
|
ConfigResponseSchema,
|
|
@@ -35,6 +35,7 @@ from agno.os.schema import (
|
|
|
35
35
|
)
|
|
36
36
|
from agno.os.settings import AgnoAPISettings
|
|
37
37
|
from agno.os.utils import get_knowledge_instance_by_db_id
|
|
38
|
+
from agno.remote.base import RemoteKnowledge
|
|
38
39
|
from agno.utils.log import log_debug, log_info
|
|
39
40
|
from agno.utils.string import generate_id
|
|
40
41
|
|
|
@@ -42,7 +43,7 @@ logger = logging.getLogger(__name__)
|
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
def get_knowledge_router(
|
|
45
|
-
knowledge_instances: List[Knowledge], settings: AgnoAPISettings = AgnoAPISettings()
|
|
46
|
+
knowledge_instances: List[Union[Knowledge, RemoteKnowledge]], settings: AgnoAPISettings = AgnoAPISettings()
|
|
46
47
|
) -> APIRouter:
|
|
47
48
|
"""Create knowledge router with comprehensive OpenAPI documentation for content management endpoints."""
|
|
48
49
|
router = APIRouter(
|
|
@@ -59,7 +60,7 @@ def get_knowledge_router(
|
|
|
59
60
|
return attach_routes(router=router, knowledge_instances=knowledge_instances)
|
|
60
61
|
|
|
61
62
|
|
|
62
|
-
def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> APIRouter:
|
|
63
|
+
def attach_routes(router: APIRouter, knowledge_instances: List[Union[Knowledge, RemoteKnowledge]]) -> APIRouter:
|
|
63
64
|
@router.post(
|
|
64
65
|
"/knowledge/content",
|
|
65
66
|
response_model=ContentResponseSchema,
|
|
@@ -93,6 +94,7 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
93
94
|
},
|
|
94
95
|
)
|
|
95
96
|
async def upload_content(
|
|
97
|
+
request: Request,
|
|
96
98
|
background_tasks: BackgroundTasks,
|
|
97
99
|
name: Optional[str] = Form(None, description="Content name (auto-generated from file/URL if not provided)"),
|
|
98
100
|
description: Optional[str] = Form(None, description="Content description for context"),
|
|
@@ -107,7 +109,6 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
107
109
|
db_id: Optional[str] = Query(default=None, description="Database ID to use for content storage"),
|
|
108
110
|
):
|
|
109
111
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
|
|
110
|
-
log_info(f"Adding content: {name}, {description}, {url}, {metadata}")
|
|
111
112
|
|
|
112
113
|
parsed_metadata = None
|
|
113
114
|
if metadata:
|
|
@@ -116,6 +117,25 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
116
117
|
except json.JSONDecodeError:
|
|
117
118
|
# If it's not valid JSON, treat as a simple key-value pair
|
|
118
119
|
parsed_metadata = {"value": metadata} if metadata != "string" else None
|
|
120
|
+
|
|
121
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
122
|
+
auth_token = get_auth_token_from_request(request)
|
|
123
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
124
|
+
return await knowledge.upload_content(
|
|
125
|
+
name=name,
|
|
126
|
+
description=description,
|
|
127
|
+
url=url,
|
|
128
|
+
metadata=parsed_metadata,
|
|
129
|
+
file=file,
|
|
130
|
+
text_content=text_content,
|
|
131
|
+
reader_id=reader_id,
|
|
132
|
+
chunker=chunker,
|
|
133
|
+
chunk_size=chunk_size,
|
|
134
|
+
chunk_overlap=chunk_overlap,
|
|
135
|
+
db_id=db_id,
|
|
136
|
+
headers=headers,
|
|
137
|
+
)
|
|
138
|
+
|
|
119
139
|
if file:
|
|
120
140
|
content_bytes = await file.read()
|
|
121
141
|
elif text_content:
|
|
@@ -225,6 +245,7 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
225
245
|
},
|
|
226
246
|
)
|
|
227
247
|
async def update_content(
|
|
248
|
+
request: Request,
|
|
228
249
|
content_id: str = Path(..., description="Content ID"),
|
|
229
250
|
name: Optional[str] = Form(None, description="Content name"),
|
|
230
251
|
description: Optional[str] = Form(None, description="Content description"),
|
|
@@ -242,6 +263,19 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
242
263
|
except json.JSONDecodeError:
|
|
243
264
|
raise HTTPException(status_code=400, detail="Invalid JSON format for metadata")
|
|
244
265
|
|
|
266
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
267
|
+
auth_token = get_auth_token_from_request(request)
|
|
268
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
269
|
+
return await knowledge.update_content(
|
|
270
|
+
content_id=content_id,
|
|
271
|
+
name=name,
|
|
272
|
+
description=description,
|
|
273
|
+
metadata=parsed_metadata,
|
|
274
|
+
reader_id=reader_id,
|
|
275
|
+
db_id=db_id,
|
|
276
|
+
headers=headers,
|
|
277
|
+
)
|
|
278
|
+
|
|
245
279
|
# Create ContentUpdateSchema object from form data
|
|
246
280
|
update_data = ContentUpdateSchema(
|
|
247
281
|
name=name if name and name.strip() else None,
|
|
@@ -309,6 +343,7 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
309
343
|
},
|
|
310
344
|
)
|
|
311
345
|
async def get_content(
|
|
346
|
+
request: Request,
|
|
312
347
|
limit: Optional[int] = Query(default=20, description="Number of content entries to return"),
|
|
313
348
|
page: Optional[int] = Query(default=1, description="Page number"),
|
|
314
349
|
sort_by: Optional[str] = Query(default="created_at", description="Field to sort by"),
|
|
@@ -316,6 +351,19 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
316
351
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
317
352
|
) -> PaginatedResponse[ContentResponseSchema]:
|
|
318
353
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
|
|
354
|
+
|
|
355
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
356
|
+
auth_token = get_auth_token_from_request(request)
|
|
357
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
358
|
+
return await knowledge.get_content(
|
|
359
|
+
limit=limit,
|
|
360
|
+
page=page,
|
|
361
|
+
sort_by=sort_by,
|
|
362
|
+
sort_order=sort_order.value if sort_order else None,
|
|
363
|
+
db_id=db_id,
|
|
364
|
+
headers=headers,
|
|
365
|
+
)
|
|
366
|
+
|
|
319
367
|
contents, count = await knowledge.aget_content(limit=limit, page=page, sort_by=sort_by, sort_order=sort_order)
|
|
320
368
|
|
|
321
369
|
return PaginatedResponse(
|
|
@@ -377,11 +425,16 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
377
425
|
},
|
|
378
426
|
)
|
|
379
427
|
async def get_content_by_id(
|
|
428
|
+
request: Request,
|
|
380
429
|
content_id: str,
|
|
381
430
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
382
431
|
) -> ContentResponseSchema:
|
|
383
|
-
log_info(f"Getting content by id: {content_id}")
|
|
384
432
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
|
|
433
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
434
|
+
auth_token = get_auth_token_from_request(request)
|
|
435
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
436
|
+
return await knowledge.get_content_by_id(content_id=content_id, db_id=db_id, headers=headers)
|
|
437
|
+
|
|
385
438
|
content = await knowledge.aget_content_by_id(content_id=content_id)
|
|
386
439
|
if not content:
|
|
387
440
|
raise HTTPException(status_code=404, detail=f"Content not found: {content_id}")
|
|
@@ -417,12 +470,17 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
417
470
|
},
|
|
418
471
|
)
|
|
419
472
|
async def delete_content_by_id(
|
|
473
|
+
request: Request,
|
|
420
474
|
content_id: str,
|
|
421
475
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
422
476
|
) -> ContentResponseSchema:
|
|
423
477
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
|
|
424
|
-
|
|
425
|
-
|
|
478
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
479
|
+
auth_token = get_auth_token_from_request(request)
|
|
480
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
481
|
+
await knowledge.delete_content_by_id(content_id=content_id, db_id=db_id, headers=headers)
|
|
482
|
+
else:
|
|
483
|
+
await knowledge.aremove_content_by_id(content_id=content_id)
|
|
426
484
|
|
|
427
485
|
return ContentResponseSchema(
|
|
428
486
|
id=content_id,
|
|
@@ -442,12 +500,17 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
442
500
|
500: {"description": "Failed to delete all content", "model": InternalServerErrorResponse},
|
|
443
501
|
},
|
|
444
502
|
)
|
|
445
|
-
def delete_all_content(
|
|
503
|
+
async def delete_all_content(
|
|
504
|
+
request: Request,
|
|
446
505
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
447
506
|
):
|
|
448
507
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
|
|
449
|
-
|
|
450
|
-
|
|
508
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
509
|
+
auth_token = get_auth_token_from_request(request)
|
|
510
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
511
|
+
return await knowledge.delete_all_content(db_id=db_id, headers=headers)
|
|
512
|
+
|
|
513
|
+
await knowledge.aremove_all_content()
|
|
451
514
|
return "success"
|
|
452
515
|
|
|
453
516
|
@router.get(
|
|
@@ -481,11 +544,16 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
481
544
|
},
|
|
482
545
|
)
|
|
483
546
|
async def get_content_status(
|
|
547
|
+
request: Request,
|
|
484
548
|
content_id: str,
|
|
485
549
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
486
550
|
) -> ContentStatusResponse:
|
|
487
|
-
log_info(f"Getting content status: {content_id}")
|
|
488
551
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
|
|
552
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
553
|
+
auth_token = get_auth_token_from_request(request)
|
|
554
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
555
|
+
return await knowledge.get_content_status(content_id=content_id, db_id=db_id, headers=headers)
|
|
556
|
+
|
|
489
557
|
knowledge_status, status_message = await knowledge.aget_content_status(content_id=content_id)
|
|
490
558
|
|
|
491
559
|
# Handle the case where content is not found
|
|
@@ -550,13 +618,27 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
550
618
|
404: {"description": "No documents found"},
|
|
551
619
|
},
|
|
552
620
|
)
|
|
553
|
-
def search_knowledge(
|
|
621
|
+
async def search_knowledge(
|
|
622
|
+
http_request: Request, request: VectorSearchRequestSchema
|
|
623
|
+
) -> PaginatedResponse[VectorSearchResult]:
|
|
554
624
|
import time
|
|
555
625
|
|
|
556
626
|
start_time = time.time()
|
|
557
627
|
|
|
558
628
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, request.db_id)
|
|
559
629
|
|
|
630
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
631
|
+
auth_token = get_auth_token_from_request(http_request)
|
|
632
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
633
|
+
return await knowledge.search_knowledge(
|
|
634
|
+
query=request.query,
|
|
635
|
+
max_results=request.max_results,
|
|
636
|
+
filters=request.filters,
|
|
637
|
+
search_type=request.search_type,
|
|
638
|
+
db_id=request.db_id,
|
|
639
|
+
headers=headers,
|
|
640
|
+
)
|
|
641
|
+
|
|
560
642
|
# For now, validate the vector db ids exist in the knowledge base
|
|
561
643
|
# We will add more logic around this once we have multi vectordb support
|
|
562
644
|
# If vector db ids are provided, check if any of them match the knowledge's vector db
|
|
@@ -578,7 +660,7 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
578
660
|
# Use max_results if specified, otherwise use a higher limit for search then paginate
|
|
579
661
|
search_limit = request.max_results
|
|
580
662
|
|
|
581
|
-
results = knowledge.
|
|
663
|
+
results = await knowledge.async_search(
|
|
582
664
|
query=request.query, max_results=search_limit, filters=request.filters, search_type=request.search_type
|
|
583
665
|
)
|
|
584
666
|
|
|
@@ -869,11 +951,17 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
|
|
|
869
951
|
}
|
|
870
952
|
},
|
|
871
953
|
)
|
|
872
|
-
def get_config(
|
|
954
|
+
async def get_config(
|
|
955
|
+
request: Request,
|
|
873
956
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
874
957
|
) -> ConfigResponseSchema:
|
|
875
958
|
knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
|
|
876
959
|
|
|
960
|
+
if isinstance(knowledge, RemoteKnowledge):
|
|
961
|
+
auth_token = get_auth_token_from_request(request)
|
|
962
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
963
|
+
return await knowledge.get_config(headers=headers)
|
|
964
|
+
|
|
877
965
|
# Get factory readers info (including custom readers from this knowledge instance)
|
|
878
966
|
readers_info = get_all_readers_info(knowledge)
|
|
879
967
|
reader_schemas = {}
|