agno 2.3.7__py3-none-any.whl → 2.3.9__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 (71) hide show
  1. agno/agent/agent.py +391 -335
  2. agno/db/mongo/async_mongo.py +0 -24
  3. agno/db/mongo/mongo.py +0 -16
  4. agno/db/mysql/__init__.py +2 -1
  5. agno/db/mysql/async_mysql.py +2888 -0
  6. agno/db/mysql/mysql.py +17 -27
  7. agno/db/mysql/utils.py +139 -6
  8. agno/db/postgres/async_postgres.py +10 -26
  9. agno/db/postgres/postgres.py +7 -25
  10. agno/db/redis/redis.py +0 -4
  11. agno/db/schemas/evals.py +1 -0
  12. agno/db/singlestore/singlestore.py +5 -12
  13. agno/db/sqlite/async_sqlite.py +2 -26
  14. agno/db/sqlite/sqlite.py +0 -20
  15. agno/eval/__init__.py +10 -0
  16. agno/eval/agent_as_judge.py +860 -0
  17. agno/eval/base.py +29 -0
  18. agno/eval/utils.py +2 -1
  19. agno/exceptions.py +7 -0
  20. agno/knowledge/embedder/openai.py +8 -8
  21. agno/knowledge/knowledge.py +1142 -176
  22. agno/media.py +22 -6
  23. agno/models/aws/claude.py +8 -7
  24. agno/models/base.py +160 -11
  25. agno/models/deepseek/deepseek.py +67 -0
  26. agno/models/google/gemini.py +65 -11
  27. agno/models/google/utils.py +22 -0
  28. agno/models/message.py +2 -0
  29. agno/models/openai/chat.py +4 -0
  30. agno/models/openai/responses.py +3 -2
  31. agno/os/app.py +64 -74
  32. agno/os/interfaces/a2a/router.py +3 -4
  33. agno/os/interfaces/a2a/utils.py +1 -1
  34. agno/os/interfaces/agui/router.py +2 -0
  35. agno/os/middleware/jwt.py +8 -6
  36. agno/os/router.py +3 -1607
  37. agno/os/routers/agents/__init__.py +3 -0
  38. agno/os/routers/agents/router.py +581 -0
  39. agno/os/routers/agents/schema.py +261 -0
  40. agno/os/routers/evals/evals.py +26 -6
  41. agno/os/routers/evals/schemas.py +34 -2
  42. agno/os/routers/evals/utils.py +101 -20
  43. agno/os/routers/knowledge/knowledge.py +1 -1
  44. agno/os/routers/teams/__init__.py +3 -0
  45. agno/os/routers/teams/router.py +496 -0
  46. agno/os/routers/teams/schema.py +257 -0
  47. agno/os/routers/workflows/__init__.py +3 -0
  48. agno/os/routers/workflows/router.py +545 -0
  49. agno/os/routers/workflows/schema.py +75 -0
  50. agno/os/schema.py +1 -559
  51. agno/os/utils.py +139 -2
  52. agno/team/team.py +159 -100
  53. agno/tools/file_generation.py +12 -6
  54. agno/tools/firecrawl.py +15 -7
  55. agno/tools/workflow.py +8 -1
  56. agno/utils/hooks.py +64 -5
  57. agno/utils/http.py +2 -2
  58. agno/utils/media.py +11 -1
  59. agno/utils/print_response/agent.py +8 -0
  60. agno/utils/print_response/team.py +8 -0
  61. agno/vectordb/pgvector/pgvector.py +88 -51
  62. agno/workflow/parallel.py +11 -5
  63. agno/workflow/step.py +17 -5
  64. agno/workflow/types.py +38 -2
  65. agno/workflow/workflow.py +12 -4
  66. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/METADATA +8 -3
  67. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/RECORD +70 -58
  68. agno/tools/memori.py +0 -339
  69. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/WHEEL +0 -0
  70. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/licenses/LICENSE +0 -0
  71. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/top_level.txt +0 -0
@@ -57,6 +57,7 @@ class SingleStoreDb(BaseDb):
57
57
  versions_table: Optional[str] = None,
58
58
  traces_table: Optional[str] = None,
59
59
  spans_table: Optional[str] = None,
60
+ create_schema: bool = True,
60
61
  ):
61
62
  """
62
63
  Interface for interacting with a SingleStore database.
@@ -78,6 +79,8 @@ class SingleStoreDb(BaseDb):
78
79
  eval_table (Optional[str]): Name of the table to store evaluation runs data.
79
80
  knowledge_table (Optional[str]): Name of the table to store knowledge content.
80
81
  versions_table (Optional[str]): Name of the table to store schema versions.
82
+ create_schema (bool): Whether to automatically create the database schema if it doesn't exist.
83
+ Set to False if schema is managed externally (e.g., via migrations). Defaults to True.
81
84
  Raises:
82
85
  ValueError: If neither db_url nor db_engine is provided.
83
86
  ValueError: If none of the tables are provided.
@@ -117,6 +120,7 @@ class SingleStoreDb(BaseDb):
117
120
  self.db_engine: Engine = _engine
118
121
  self.db_schema: Optional[str] = db_schema
119
122
  self.metadata: MetaData = MetaData(schema=self.db_schema)
123
+ self.create_schema: bool = create_schema
120
124
 
121
125
  # Initialize database session
122
126
  self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
@@ -240,7 +244,7 @@ class SingleStoreDb(BaseDb):
240
244
  table.append_constraint(Index(idx_name, idx_col))
241
245
 
242
246
  # Create schema if one is specified
243
- if self.db_schema is not None:
247
+ if self.create_schema and self.db_schema is not None:
244
248
  with self.Session() as sess, sess.begin():
245
249
  create_schema(session=sess, db_schema=self.db_schema)
246
250
 
@@ -2461,14 +2465,6 @@ class SingleStoreDb(BaseDb):
2461
2465
  if trace.workflow_id is not None:
2462
2466
  update_values["workflow_id"] = trace.workflow_id
2463
2467
 
2464
- log_debug(
2465
- f" Updating trace with context: run_id={update_values.get('run_id', 'unchanged')}, "
2466
- f"session_id={update_values.get('session_id', 'unchanged')}, "
2467
- f"user_id={update_values.get('user_id', 'unchanged')}, "
2468
- f"agent_id={update_values.get('agent_id', 'unchanged')}, "
2469
- f"team_id={update_values.get('team_id', 'unchanged')}, "
2470
- )
2471
-
2472
2468
  update_stmt = update(table).where(table.c.trace_id == trace.trace_id).values(**update_values)
2473
2469
  sess.execute(update_stmt)
2474
2470
  else:
@@ -2589,7 +2585,6 @@ class SingleStoreDb(BaseDb):
2589
2585
  if run_id:
2590
2586
  base_stmt = base_stmt.where(table.c.run_id == run_id)
2591
2587
  if session_id:
2592
- log_debug(f"Filtering by session_id={session_id}")
2593
2588
  base_stmt = base_stmt.where(table.c.session_id == session_id)
2594
2589
  if user_id:
2595
2590
  base_stmt = base_stmt.where(table.c.user_id == user_id)
@@ -2611,14 +2606,12 @@ class SingleStoreDb(BaseDb):
2611
2606
  # Get total count
2612
2607
  count_stmt = select(func.count()).select_from(base_stmt.alias())
2613
2608
  total_count = sess.execute(count_stmt).scalar() or 0
2614
- log_debug(f"Total matching traces: {total_count}")
2615
2609
 
2616
2610
  # Apply pagination
2617
2611
  offset = (page - 1) * limit if page and limit else 0
2618
2612
  paginated_stmt = base_stmt.order_by(table.c.start_time.desc()).limit(limit).offset(offset)
2619
2613
 
2620
2614
  results = sess.execute(paginated_stmt).fetchall()
2621
- log_debug(f"Returning page {page} with {len(results)} traces")
2622
2615
 
2623
2616
  traces = [Trace.from_dict(dict(row._mapping)) for row in results]
2624
2617
  return traces, total_count
@@ -363,7 +363,6 @@ class AsyncSqliteDb(AsyncBaseDb):
363
363
  return Table(table_name, self.metadata, autoload_with=connection)
364
364
 
365
365
  table = await conn.run_sync(load_table)
366
- log_debug(f"Loaded existing table {table_name}")
367
366
  return table
368
367
 
369
368
  except Exception as e:
@@ -1541,7 +1540,7 @@ class AsyncSqliteDb(AsyncBaseDb):
1541
1540
  Exception: If an error occurs during retrieval.
1542
1541
  """
1543
1542
  try:
1544
- table = await self._get_table(table_type="sessions")
1543
+ table = await self._get_table(table_type="sessions", create_table_if_not_found=True)
1545
1544
  if table is None:
1546
1545
  return []
1547
1546
 
@@ -1879,7 +1878,7 @@ class AsyncSqliteDb(AsyncBaseDb):
1879
1878
  Exception: If an error occurs during creation.
1880
1879
  """
1881
1880
  try:
1882
- table = await self._get_table(table_type="evals")
1881
+ table = await self._get_table(table_type="evals", create_table_if_not_found=True)
1883
1882
  if table is None:
1884
1883
  return None
1885
1884
 
@@ -2513,14 +2512,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2513
2512
  if trace.workflow_id is not None:
2514
2513
  update_values["workflow_id"] = trace.workflow_id
2515
2514
 
2516
- log_debug(
2517
- f" Updating trace with context: run_id={update_values.get('run_id', 'unchanged')}, "
2518
- f"session_id={update_values.get('session_id', 'unchanged')}, "
2519
- f"user_id={update_values.get('user_id', 'unchanged')}, "
2520
- f"agent_id={update_values.get('agent_id', 'unchanged')}, "
2521
- f"team_id={update_values.get('team_id', 'unchanged')}, "
2522
- )
2523
-
2524
2515
  stmt = update(table).where(table.c.trace_id == trace.trace_id).values(**update_values)
2525
2516
  await sess.execute(stmt)
2526
2517
  else:
@@ -2622,10 +2613,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2622
2613
  try:
2623
2614
  from agno.tracing.schemas import Trace
2624
2615
 
2625
- log_debug(
2626
- f"get_traces called with filters: run_id={run_id}, session_id={session_id}, user_id={user_id}, agent_id={agent_id}, page={page}, limit={limit}"
2627
- )
2628
-
2629
2616
  table = await self._get_table(table_type="traces")
2630
2617
  if table is None:
2631
2618
  log_debug("Traces table not found")
@@ -2642,7 +2629,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2642
2629
  if run_id:
2643
2630
  base_stmt = base_stmt.where(table.c.run_id == run_id)
2644
2631
  if session_id:
2645
- log_debug(f"Filtering by session_id={session_id}")
2646
2632
  base_stmt = base_stmt.where(table.c.session_id == session_id)
2647
2633
  if user_id:
2648
2634
  base_stmt = base_stmt.where(table.c.user_id == user_id)
@@ -2664,7 +2650,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2664
2650
  # Get total count
2665
2651
  count_stmt = select(func.count()).select_from(base_stmt.alias())
2666
2652
  total_count = await sess.scalar(count_stmt) or 0
2667
- log_debug(f"Total matching traces: {total_count}")
2668
2653
 
2669
2654
  # Apply pagination
2670
2655
  offset = (page - 1) * limit if page and limit else 0
@@ -2672,7 +2657,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2672
2657
 
2673
2658
  result = await sess.execute(paginated_stmt)
2674
2659
  results = result.fetchall()
2675
- log_debug(f"Returning page {page} with {len(results)} traces")
2676
2660
 
2677
2661
  traces = [Trace.from_dict(dict(row._mapping)) for row in results]
2678
2662
  return traces, total_count
@@ -2710,12 +2694,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2710
2694
  workflow_id, first_trace_at, last_trace_at.
2711
2695
  """
2712
2696
  try:
2713
- log_debug(
2714
- f"get_trace_stats called with filters: user_id={user_id}, agent_id={agent_id}, "
2715
- f"workflow_id={workflow_id}, team_id={team_id}, "
2716
- f"start_time={start_time}, end_time={end_time}, page={page}, limit={limit}"
2717
- )
2718
-
2719
2697
  table = await self._get_table(table_type="traces")
2720
2698
  if table is None:
2721
2699
  log_debug("Traces table not found")
@@ -2759,7 +2737,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2759
2737
  # Get total count of sessions
2760
2738
  count_stmt = select(func.count()).select_from(base_stmt.alias())
2761
2739
  total_count = await sess.scalar(count_stmt) or 0
2762
- log_debug(f"Total matching sessions: {total_count}")
2763
2740
 
2764
2741
  # Apply pagination and ordering
2765
2742
  offset = (page - 1) * limit if page and limit else 0
@@ -2767,7 +2744,6 @@ class AsyncSqliteDb(AsyncBaseDb):
2767
2744
 
2768
2745
  result = await sess.execute(paginated_stmt)
2769
2746
  results = result.fetchall()
2770
- log_debug(f"Returning page {page} with {len(results)} session stats")
2771
2747
 
2772
2748
  # Convert to list of dicts with datetime objects
2773
2749
  stats_list = []
agno/db/sqlite/sqlite.py CHANGED
@@ -362,7 +362,6 @@ class SqliteDb(BaseDb):
362
362
 
363
363
  try:
364
364
  table = Table(table_name, self.metadata, autoload_with=self.db_engine)
365
- log_debug(f"Loaded existing table {table_name}")
366
365
  return table
367
366
 
368
367
  except Exception as e:
@@ -2217,14 +2216,6 @@ class SqliteDb(BaseDb):
2217
2216
  if trace.workflow_id is not None:
2218
2217
  update_values["workflow_id"] = trace.workflow_id
2219
2218
 
2220
- log_debug(
2221
- f" Updating trace with context: run_id={update_values.get('run_id', 'unchanged')}, "
2222
- f"session_id={update_values.get('session_id', 'unchanged')}, "
2223
- f"user_id={update_values.get('user_id', 'unchanged')}, "
2224
- f"agent_id={update_values.get('agent_id', 'unchanged')}, "
2225
- f"team_id={update_values.get('team_id', 'unchanged')}, "
2226
- )
2227
-
2228
2219
  stmt = update(table).where(table.c.trace_id == trace.trace_id).values(**update_values)
2229
2220
  sess.execute(stmt)
2230
2221
  else:
@@ -2347,7 +2338,6 @@ class SqliteDb(BaseDb):
2347
2338
  if run_id:
2348
2339
  base_stmt = base_stmt.where(table.c.run_id == run_id)
2349
2340
  if session_id:
2350
- log_debug(f"Filtering by session_id={session_id}")
2351
2341
  base_stmt = base_stmt.where(table.c.session_id == session_id)
2352
2342
  if user_id:
2353
2343
  base_stmt = base_stmt.where(table.c.user_id == user_id)
@@ -2369,14 +2359,12 @@ class SqliteDb(BaseDb):
2369
2359
  # Get total count
2370
2360
  count_stmt = select(func.count()).select_from(base_stmt.alias())
2371
2361
  total_count = sess.execute(count_stmt).scalar() or 0
2372
- log_debug(f"Total matching traces: {total_count}")
2373
2362
 
2374
2363
  # Apply pagination
2375
2364
  offset = (page - 1) * limit if page and limit else 0
2376
2365
  paginated_stmt = base_stmt.order_by(table.c.start_time.desc()).limit(limit).offset(offset)
2377
2366
 
2378
2367
  results = sess.execute(paginated_stmt).fetchall()
2379
- log_debug(f"Returning page {page} with {len(results)} traces")
2380
2368
 
2381
2369
  traces = [Trace.from_dict(dict(row._mapping)) for row in results]
2382
2370
  return traces, total_count
@@ -2414,12 +2402,6 @@ class SqliteDb(BaseDb):
2414
2402
  try:
2415
2403
  from sqlalchemy import func
2416
2404
 
2417
- log_debug(
2418
- f"get_trace_stats called with filters: user_id={user_id}, agent_id={agent_id}, "
2419
- f"workflow_id={workflow_id}, team_id={team_id}, "
2420
- f"start_time={start_time}, end_time={end_time}, page={page}, limit={limit}"
2421
- )
2422
-
2423
2405
  table = self._get_table(table_type="traces")
2424
2406
  if table is None:
2425
2407
  log_debug("Traces table not found")
@@ -2463,14 +2445,12 @@ class SqliteDb(BaseDb):
2463
2445
  # Get total count of sessions
2464
2446
  count_stmt = select(func.count()).select_from(base_stmt.alias())
2465
2447
  total_count = sess.execute(count_stmt).scalar() or 0
2466
- log_debug(f"Total matching sessions: {total_count}")
2467
2448
 
2468
2449
  # Apply pagination and ordering
2469
2450
  offset = (page - 1) * limit if page and limit else 0
2470
2451
  paginated_stmt = base_stmt.order_by(func.max(table.c.created_at).desc()).limit(limit).offset(offset)
2471
2452
 
2472
2453
  results = sess.execute(paginated_stmt).fetchall()
2473
- log_debug(f"Returning page {page} with {len(results)} session stats")
2474
2454
 
2475
2455
  # Convert to list of dicts with datetime objects
2476
2456
  from datetime import datetime
agno/eval/__init__.py CHANGED
@@ -1,4 +1,10 @@
1
1
  from agno.eval.accuracy import AccuracyAgentResponse, AccuracyEval, AccuracyEvaluation, AccuracyResult
2
+ from agno.eval.agent_as_judge import (
3
+ AgentAsJudgeEval,
4
+ AgentAsJudgeEvaluation,
5
+ AgentAsJudgeResult,
6
+ )
7
+ from agno.eval.base import BaseEval
2
8
  from agno.eval.performance import PerformanceEval, PerformanceResult
3
9
  from agno.eval.reliability import ReliabilityEval, ReliabilityResult
4
10
 
@@ -7,6 +13,10 @@ __all__ = [
7
13
  "AccuracyEvaluation",
8
14
  "AccuracyResult",
9
15
  "AccuracyEval",
16
+ "AgentAsJudgeEval",
17
+ "AgentAsJudgeEvaluation",
18
+ "AgentAsJudgeResult",
19
+ "BaseEval",
10
20
  "PerformanceEval",
11
21
  "PerformanceResult",
12
22
  "ReliabilityEval",