agno 2.2.13__py3-none-any.whl → 2.4.3__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 +6 -0
- agno/agent/agent.py +5252 -3145
- agno/agent/remote.py +525 -0
- agno/api/api.py +2 -0
- agno/client/__init__.py +3 -0
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/client/os.py +2669 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/manager.py +2 -2
- agno/db/base.py +927 -6
- agno/db/dynamo/dynamo.py +788 -2
- agno/db/dynamo/schemas.py +128 -0
- agno/db/dynamo/utils.py +26 -3
- agno/db/firestore/firestore.py +674 -50
- agno/db/firestore/schemas.py +41 -0
- agno/db/firestore/utils.py +25 -10
- agno/db/gcs_json/gcs_json_db.py +506 -3
- agno/db/gcs_json/utils.py +14 -2
- agno/db/in_memory/in_memory_db.py +203 -4
- agno/db/in_memory/utils.py +14 -2
- agno/db/json/json_db.py +498 -2
- agno/db/json/utils.py +14 -2
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +977 -0
- agno/db/mongo/async_mongo.py +1013 -39
- agno/db/mongo/mongo.py +684 -4
- agno/db/mongo/schemas.py +48 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2958 -0
- agno/db/mysql/mysql.py +722 -53
- agno/db/mysql/schemas.py +77 -11
- agno/db/mysql/utils.py +151 -8
- agno/db/postgres/async_postgres.py +1254 -137
- agno/db/postgres/postgres.py +2316 -93
- agno/db/postgres/schemas.py +153 -21
- agno/db/postgres/utils.py +22 -7
- agno/db/redis/redis.py +531 -3
- agno/db/redis/schemas.py +36 -0
- agno/db/redis/utils.py +31 -15
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +20 -9
- agno/db/singlestore/schemas.py +70 -1
- agno/db/singlestore/singlestore.py +737 -74
- agno/db/singlestore/utils.py +13 -3
- agno/db/sqlite/async_sqlite.py +1069 -89
- agno/db/sqlite/schemas.py +133 -1
- agno/db/sqlite/sqlite.py +2203 -165
- agno/db/sqlite/utils.py +21 -11
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +603 -1
- agno/db/utils.py +60 -0
- agno/eval/__init__.py +26 -3
- agno/eval/accuracy.py +25 -12
- agno/eval/agent_as_judge.py +871 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/eval/utils.py +2 -1
- agno/exceptions.py +42 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +13 -2
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +90 -0
- agno/knowledge/chunking/document.py +65 -4
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/markdown.py +102 -11
- agno/knowledge/chunking/recursive.py +2 -2
- agno/knowledge/chunking/semantic.py +130 -48
- agno/knowledge/chunking/strategy.py +18 -0
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/knowledge/embedder/mistral.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/openai.py +16 -12
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +4261 -1199
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +3 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +91 -42
- agno/knowledge/reader/docx_reader.py +9 -10
- agno/knowledge/reader/excel_reader.py +225 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
- agno/knowledge/reader/firecrawl_reader.py +3 -2
- agno/knowledge/reader/json_reader.py +16 -22
- agno/knowledge/reader/markdown_reader.py +15 -14
- agno/knowledge/reader/pdf_reader.py +33 -28
- agno/knowledge/reader/pptx_reader.py +9 -10
- agno/knowledge/reader/reader_factory.py +135 -1
- agno/knowledge/reader/s3_reader.py +8 -16
- agno/knowledge/reader/tavily_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +15 -14
- agno/knowledge/reader/utils/__init__.py +17 -0
- agno/knowledge/reader/utils/spreadsheet.py +114 -0
- agno/knowledge/reader/web_search_reader.py +8 -65
- agno/knowledge/reader/website_reader.py +16 -13
- agno/knowledge/reader/wikipedia_reader.py +36 -3
- agno/knowledge/reader/youtube_reader.py +3 -2
- agno/knowledge/remote_content/__init__.py +33 -0
- agno/knowledge/remote_content/config.py +266 -0
- agno/knowledge/remote_content/remote_content.py +105 -17
- agno/knowledge/utils.py +76 -22
- agno/learn/__init__.py +71 -0
- agno/learn/config.py +463 -0
- agno/learn/curate.py +185 -0
- agno/learn/machine.py +725 -0
- agno/learn/schemas.py +1114 -0
- agno/learn/stores/__init__.py +38 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/entity_memory.py +3275 -0
- agno/learn/stores/learned_knowledge.py +1583 -0
- agno/learn/stores/protocol.py +117 -0
- agno/learn/stores/session_context.py +1217 -0
- agno/learn/stores/user_memory.py +1495 -0
- agno/learn/stores/user_profile.py +1220 -0
- agno/learn/utils.py +209 -0
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +223 -8
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +434 -59
- agno/models/aws/bedrock.py +121 -20
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +10 -6
- agno/models/azure/openai_chat.py +33 -10
- agno/models/base.py +1162 -561
- agno/models/cerebras/cerebras.py +120 -24
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +65 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +959 -89
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +48 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +88 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +24 -5
- agno/models/meta/llama.py +40 -13
- agno/models/meta/llama_openai.py +22 -21
- agno/models/metrics.py +12 -0
- agno/models/mistral/mistral.py +8 -4
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/__init__.py +2 -0
- agno/models/ollama/chat.py +17 -6
- agno/models/ollama/responses.py +100 -0
- agno/models/openai/__init__.py +2 -0
- agno/models/openai/chat.py +117 -26
- agno/models/openai/open_responses.py +46 -0
- agno/models/openai/responses.py +110 -32
- agno/models/openrouter/__init__.py +2 -0
- agno/models/openrouter/openrouter.py +67 -2
- agno/models/openrouter/responses.py +146 -0
- agno/models/perplexity/perplexity.py +19 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +19 -2
- agno/models/response.py +20 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/claude.py +124 -4
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +467 -137
- agno/os/auth.py +253 -5
- agno/os/config.py +22 -0
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +635 -26
- agno/os/interfaces/a2a/utils.py +32 -33
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +26 -16
- agno/os/interfaces/agui/utils.py +97 -57
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +16 -7
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +35 -7
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +652 -79
- agno/os/middleware/__init__.py +4 -0
- agno/os/middleware/jwt.py +718 -115
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +105 -1558
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +655 -0
- agno/os/routers/agents/schema.py +288 -0
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/database.py +155 -0
- agno/os/routers/evals/evals.py +111 -18
- agno/os/routers/evals/schemas.py +38 -5
- agno/os/routers/evals/utils.py +80 -11
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +284 -35
- agno/os/routers/knowledge/schemas.py +14 -2
- agno/os/routers/memory/memory.py +274 -11
- agno/os/routers/memory/schemas.py +44 -3
- agno/os/routers/metrics/metrics.py +30 -15
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/session/session.py +143 -14
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +550 -0
- agno/os/routers/teams/schema.py +280 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +549 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +757 -0
- agno/os/routers/workflows/schema.py +139 -0
- agno/os/schema.py +157 -584
- agno/os/scopes.py +469 -0
- agno/os/settings.py +3 -0
- agno/os/utils.py +574 -185
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +102 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +87 -3
- agno/reasoning/groq.py +109 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +1238 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +115 -1
- agno/reasoning/vertexai.py +85 -1
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +581 -0
- agno/run/__init__.py +2 -4
- agno/run/agent.py +134 -19
- agno/run/base.py +49 -1
- agno/run/cancel.py +65 -52
- agno/run/cancellation_management/__init__.py +9 -0
- agno/run/cancellation_management/base.py +78 -0
- agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
- agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +111 -19
- agno/run/workflow.py +2 -1
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -115
- agno/session/workflow.py +353 -57
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +377 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/table.py +10 -0
- agno/team/__init__.py +5 -1
- agno/team/remote.py +447 -0
- agno/team/team.py +3769 -2202
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +225 -16
- agno/tools/crawl4ai.py +3 -0
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/file.py +14 -13
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +94 -113
- agno/tools/google_bigquery.py +11 -2
- agno/tools/google_drive.py +4 -3
- agno/tools/knowledge.py +9 -4
- agno/tools/mcp/mcp.py +301 -18
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/parallel.py +0 -7
- agno/tools/postgres.py +76 -36
- agno/tools/python.py +14 -6
- agno/tools/reasoning.py +30 -23
- agno/tools/redshift.py +406 -0
- agno/tools/shopify.py +1519 -0
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +4 -1
- agno/tools/toolkit.py +253 -18
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +56 -48
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +161 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +112 -0
- agno/utils/agent.py +251 -10
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +264 -7
- agno/utils/hooks.py +111 -3
- agno/utils/http.py +161 -2
- agno/utils/mcp.py +49 -8
- agno/utils/media.py +22 -1
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +20 -5
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/os.py +0 -0
- agno/utils/print_response/agent.py +99 -16
- agno/utils/print_response/team.py +223 -24
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/prompts.py +8 -6
- agno/utils/remote.py +23 -0
- agno/utils/response.py +1 -13
- agno/utils/string.py +91 -2
- agno/utils/team.py +62 -12
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +15 -2
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/__init__.py +2 -1
- agno/vectordb/chroma/chromadb.py +468 -23
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/vectordb/lancedb/lance_db.py +7 -38
- agno/vectordb/lightrag/lightrag.py +7 -6
- agno/vectordb/milvus/milvus.py +118 -84
- agno/vectordb/mongodb/__init__.py +2 -1
- agno/vectordb/mongodb/mongodb.py +14 -31
- agno/vectordb/pgvector/pgvector.py +120 -66
- agno/vectordb/pineconedb/pineconedb.py +2 -19
- agno/vectordb/qdrant/__init__.py +2 -1
- agno/vectordb/qdrant/qdrant.py +33 -56
- agno/vectordb/redis/__init__.py +2 -1
- agno/vectordb/redis/redisdb.py +19 -31
- agno/vectordb/singlestore/singlestore.py +17 -9
- agno/vectordb/surrealdb/surrealdb.py +2 -38
- agno/vectordb/weaviate/__init__.py +2 -1
- agno/vectordb/weaviate/weaviate.py +7 -3
- agno/workflow/__init__.py +5 -1
- agno/workflow/agent.py +2 -2
- agno/workflow/condition.py +12 -10
- agno/workflow/loop.py +28 -9
- agno/workflow/parallel.py +21 -13
- agno/workflow/remote.py +362 -0
- agno/workflow/router.py +12 -9
- agno/workflow/step.py +261 -36
- agno/workflow/steps.py +12 -8
- agno/workflow/types.py +40 -77
- agno/workflow/workflow.py +939 -213
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
- agno-2.4.3.dist-info/RECORD +677 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
- agno/tools/googlesearch.py +0 -98
- agno/tools/memori.py +0 -339
- agno-2.2.13.dist-info/RECORD +0 -575
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
3
|
+
|
|
4
|
+
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from agno.os.auth import get_authentication_dependency
|
|
8
|
+
from agno.os.schema import (
|
|
9
|
+
BadRequestResponse,
|
|
10
|
+
InternalServerErrorResponse,
|
|
11
|
+
NotFoundResponse,
|
|
12
|
+
PaginatedResponse,
|
|
13
|
+
PaginationInfo,
|
|
14
|
+
UnauthenticatedResponse,
|
|
15
|
+
ValidationErrorResponse,
|
|
16
|
+
)
|
|
17
|
+
from agno.os.settings import AgnoAPISettings
|
|
18
|
+
from agno.registry import Registry
|
|
19
|
+
from agno.tools.function import Function
|
|
20
|
+
from agno.tools.toolkit import Toolkit
|
|
21
|
+
from agno.utils.log import log_error
|
|
22
|
+
|
|
23
|
+
ComponentType = Literal["tool", "toolkit", "model", "db", "vector_db", "schema"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ============================================
|
|
27
|
+
# Response Schema
|
|
28
|
+
# ============================================
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ComponentResponse(BaseModel):
|
|
32
|
+
name: str
|
|
33
|
+
component_type: ComponentType
|
|
34
|
+
description: Optional[str] = None
|
|
35
|
+
metadata: Dict[str, Any] = Field(default_factory=dict)
|
|
36
|
+
# Tool-specific fields (matching config format)
|
|
37
|
+
parameters: Optional[Dict[str, Any]] = None
|
|
38
|
+
requires_confirmation: Optional[bool] = None
|
|
39
|
+
external_execution: Optional[bool] = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ============================================
|
|
43
|
+
# Router
|
|
44
|
+
# ============================================
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_registry_router(registry: Registry, settings: AgnoAPISettings = AgnoAPISettings()) -> APIRouter:
|
|
48
|
+
router = APIRouter(
|
|
49
|
+
dependencies=[Depends(get_authentication_dependency(settings))],
|
|
50
|
+
tags=["Registry"],
|
|
51
|
+
responses={
|
|
52
|
+
400: {"description": "Bad Request", "model": BadRequestResponse},
|
|
53
|
+
401: {"description": "Unauthorized", "model": UnauthenticatedResponse},
|
|
54
|
+
404: {"description": "Not Found", "model": NotFoundResponse},
|
|
55
|
+
422: {"description": "Validation Error", "model": ValidationErrorResponse},
|
|
56
|
+
500: {"description": "Internal Server Error", "model": InternalServerErrorResponse},
|
|
57
|
+
},
|
|
58
|
+
)
|
|
59
|
+
return attach_routes(router=router, registry=registry)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def attach_routes(router: APIRouter, registry: Registry) -> APIRouter:
|
|
63
|
+
def _safe_str(v: Any) -> Optional[str]:
|
|
64
|
+
if v is None:
|
|
65
|
+
return None
|
|
66
|
+
if isinstance(v, str):
|
|
67
|
+
s = v.strip()
|
|
68
|
+
return s or None
|
|
69
|
+
return str(v)
|
|
70
|
+
|
|
71
|
+
def _safe_name(obj: Any, fallback: str) -> str:
|
|
72
|
+
n = getattr(obj, "name", None)
|
|
73
|
+
n = _safe_str(n)
|
|
74
|
+
return n or fallback
|
|
75
|
+
|
|
76
|
+
def _class_path(obj: Any) -> str:
|
|
77
|
+
cls = obj.__class__
|
|
78
|
+
return f"{cls.__module__}.{cls.__name__}"
|
|
79
|
+
|
|
80
|
+
def _maybe_jsonable(value: Any) -> Any:
|
|
81
|
+
# Best-effort: keep only data that is likely JSON serializable
|
|
82
|
+
# If your Function.parameters is a Pydantic model or custom object, this avoids 500s.
|
|
83
|
+
if value is None:
|
|
84
|
+
return None
|
|
85
|
+
if isinstance(value, (str, int, float, bool)):
|
|
86
|
+
return value
|
|
87
|
+
if isinstance(value, list):
|
|
88
|
+
return [_maybe_jsonable(x) for x in value]
|
|
89
|
+
if isinstance(value, dict):
|
|
90
|
+
out: Dict[str, Any] = {}
|
|
91
|
+
for k, v in value.items():
|
|
92
|
+
out[str(k)] = _maybe_jsonable(v)
|
|
93
|
+
return out
|
|
94
|
+
# Fallback to string to avoid serialization errors
|
|
95
|
+
return str(value)
|
|
96
|
+
|
|
97
|
+
def _get_all_components(include_schema: bool) -> List[ComponentResponse]:
|
|
98
|
+
components: List[ComponentResponse] = []
|
|
99
|
+
|
|
100
|
+
# Tools
|
|
101
|
+
for tool in getattr(registry, "tools", []) or []:
|
|
102
|
+
if isinstance(tool, Toolkit):
|
|
103
|
+
toolkit_name = _safe_name(tool, fallback=tool.__class__.__name__)
|
|
104
|
+
functions = getattr(tool, "functions", {}) or {}
|
|
105
|
+
|
|
106
|
+
components.append(
|
|
107
|
+
ComponentResponse(
|
|
108
|
+
name=toolkit_name,
|
|
109
|
+
component_type="toolkit",
|
|
110
|
+
description=_safe_str(getattr(tool, "description", None)),
|
|
111
|
+
metadata={
|
|
112
|
+
"class_path": _class_path(tool),
|
|
113
|
+
"functions": sorted(list(functions.keys())),
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Also expose individual functions within toolkit
|
|
119
|
+
for func in functions.values():
|
|
120
|
+
func_name = _safe_name(func, fallback=func.__class__.__name__)
|
|
121
|
+
# Check if function requires confirmation or external execution
|
|
122
|
+
# First check function-level settings, then toolkit-level settings
|
|
123
|
+
requires_confirmation = getattr(func, "requires_confirmation", None)
|
|
124
|
+
external_execution = getattr(func, "external_execution", None)
|
|
125
|
+
|
|
126
|
+
# If not set on function, check toolkit settings
|
|
127
|
+
if requires_confirmation is None and hasattr(tool, "requires_confirmation_tools"):
|
|
128
|
+
requires_confirmation = func_name in (tool.requires_confirmation_tools or [])
|
|
129
|
+
if external_execution is None and hasattr(tool, "external_execution_required_tools"):
|
|
130
|
+
external_execution = func_name in (tool.external_execution_required_tools or [])
|
|
131
|
+
|
|
132
|
+
# Get parameters - ensure they're processed if needed
|
|
133
|
+
func_params = func.parameters
|
|
134
|
+
# If parameters are empty/default and function has entrypoint, try to process it
|
|
135
|
+
default_params = {"type": "object", "properties": {}, "required": []}
|
|
136
|
+
if func_params == default_params and func.entrypoint and not func.skip_entrypoint_processing:
|
|
137
|
+
try:
|
|
138
|
+
# Create a copy to avoid modifying the original
|
|
139
|
+
func_copy = func.model_copy(deep=False)
|
|
140
|
+
func_copy.process_entrypoint(strict=False)
|
|
141
|
+
func_params = func_copy.parameters
|
|
142
|
+
except Exception:
|
|
143
|
+
# If processing fails, use original parameters
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
components.append(
|
|
147
|
+
ComponentResponse(
|
|
148
|
+
name=func_name,
|
|
149
|
+
component_type="tool",
|
|
150
|
+
description=_safe_str(getattr(func, "description", None)),
|
|
151
|
+
parameters=_maybe_jsonable(func_params),
|
|
152
|
+
requires_confirmation=requires_confirmation,
|
|
153
|
+
external_execution=external_execution,
|
|
154
|
+
metadata={
|
|
155
|
+
"class_path": _class_path(func),
|
|
156
|
+
"toolkit": toolkit_name,
|
|
157
|
+
"has_entrypoint": bool(getattr(func, "entrypoint", None)),
|
|
158
|
+
},
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
elif isinstance(tool, Function):
|
|
163
|
+
func_name = _safe_name(tool, fallback=tool.__class__.__name__)
|
|
164
|
+
requires_confirmation = getattr(tool, "requires_confirmation", None)
|
|
165
|
+
external_execution = getattr(tool, "external_execution", None)
|
|
166
|
+
|
|
167
|
+
# Get parameters - ensure they're processed if needed
|
|
168
|
+
func_params = tool.parameters
|
|
169
|
+
# If parameters are empty/default and function has entrypoint, try to process it
|
|
170
|
+
default_params = {"type": "object", "properties": {}, "required": []}
|
|
171
|
+
if func_params == default_params and tool.entrypoint and not tool.skip_entrypoint_processing:
|
|
172
|
+
try:
|
|
173
|
+
# Create a copy to avoid modifying the original
|
|
174
|
+
tool_copy = tool.model_copy(deep=False)
|
|
175
|
+
tool_copy.process_entrypoint(strict=False)
|
|
176
|
+
func_params = tool_copy.parameters
|
|
177
|
+
except Exception:
|
|
178
|
+
# If processing fails, use original parameters
|
|
179
|
+
pass
|
|
180
|
+
|
|
181
|
+
components.append(
|
|
182
|
+
ComponentResponse(
|
|
183
|
+
name=func_name,
|
|
184
|
+
component_type="tool",
|
|
185
|
+
description=_safe_str(getattr(tool, "description", None)),
|
|
186
|
+
parameters=_maybe_jsonable(func_params),
|
|
187
|
+
requires_confirmation=requires_confirmation,
|
|
188
|
+
external_execution=external_execution,
|
|
189
|
+
metadata={
|
|
190
|
+
"class_path": _class_path(tool),
|
|
191
|
+
"has_entrypoint": bool(getattr(tool, "entrypoint", None)),
|
|
192
|
+
},
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
elif callable(tool):
|
|
197
|
+
call_name = getattr(tool, "__name__", None) or tool.__class__.__name__
|
|
198
|
+
components.append(
|
|
199
|
+
ComponentResponse(
|
|
200
|
+
name=str(call_name),
|
|
201
|
+
component_type="tool",
|
|
202
|
+
description=_safe_str(getattr(tool, "__doc__", None)),
|
|
203
|
+
metadata={"class_path": _class_path(tool)},
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# Models
|
|
208
|
+
for model in getattr(registry, "models", []) or []:
|
|
209
|
+
model_name = (
|
|
210
|
+
_safe_str(getattr(model, "id", None))
|
|
211
|
+
or _safe_str(getattr(model, "name", None))
|
|
212
|
+
or model.__class__.__name__
|
|
213
|
+
)
|
|
214
|
+
components.append(
|
|
215
|
+
ComponentResponse(
|
|
216
|
+
name=model_name,
|
|
217
|
+
component_type="model",
|
|
218
|
+
description=_safe_str(getattr(model, "description", None)),
|
|
219
|
+
metadata={
|
|
220
|
+
"class_path": _class_path(model),
|
|
221
|
+
"provider": _safe_str(getattr(model, "provider", None)),
|
|
222
|
+
"model_id": _safe_str(getattr(model, "id", None)),
|
|
223
|
+
},
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Databases
|
|
228
|
+
for db in getattr(registry, "dbs", []) or []:
|
|
229
|
+
db_name = (
|
|
230
|
+
_safe_str(getattr(db, "name", None))
|
|
231
|
+
or _safe_str(getattr(db, "id", None))
|
|
232
|
+
or _safe_str(getattr(db, "table_name", None))
|
|
233
|
+
or db.__class__.__name__
|
|
234
|
+
)
|
|
235
|
+
components.append(
|
|
236
|
+
ComponentResponse(
|
|
237
|
+
name=db_name,
|
|
238
|
+
component_type="db",
|
|
239
|
+
metadata={
|
|
240
|
+
"class_path": _class_path(db),
|
|
241
|
+
"db_id": _safe_str(getattr(db, "id", None)),
|
|
242
|
+
"table_name": _safe_str(getattr(db, "table_name", None)),
|
|
243
|
+
},
|
|
244
|
+
)
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# Vector databases
|
|
248
|
+
for vdb in getattr(registry, "vector_dbs", []) or []:
|
|
249
|
+
vdb_name = (
|
|
250
|
+
_safe_str(getattr(vdb, "name", None))
|
|
251
|
+
or _safe_str(getattr(vdb, "id", None))
|
|
252
|
+
or _safe_str(getattr(vdb, "collection", None))
|
|
253
|
+
or _safe_str(getattr(vdb, "table_name", None))
|
|
254
|
+
or vdb.__class__.__name__
|
|
255
|
+
)
|
|
256
|
+
components.append(
|
|
257
|
+
ComponentResponse(
|
|
258
|
+
name=vdb_name,
|
|
259
|
+
component_type="vector_db",
|
|
260
|
+
metadata={
|
|
261
|
+
"class_path": _class_path(vdb),
|
|
262
|
+
"vector_db_id": _safe_str(getattr(vdb, "id", None)),
|
|
263
|
+
"collection": _safe_str(getattr(vdb, "collection", None)),
|
|
264
|
+
"table_name": _safe_str(getattr(vdb, "table_name", None)),
|
|
265
|
+
},
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Schemas
|
|
270
|
+
for schema in getattr(registry, "schemas", []) or []:
|
|
271
|
+
schema_name = schema.__name__
|
|
272
|
+
meta: Dict[str, Any] = {"class_path": _class_path(schema)}
|
|
273
|
+
if include_schema:
|
|
274
|
+
try:
|
|
275
|
+
meta["schema"] = schema.model_json_schema() if hasattr(schema, "model_json_schema") else {}
|
|
276
|
+
except Exception as e:
|
|
277
|
+
meta["schema_error"] = str(e)
|
|
278
|
+
|
|
279
|
+
components.append(
|
|
280
|
+
ComponentResponse(
|
|
281
|
+
name=schema_name,
|
|
282
|
+
component_type="schema",
|
|
283
|
+
metadata=meta,
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# Stable ordering helps pagination
|
|
288
|
+
components.sort(key=lambda c: (c.component_type, c.name))
|
|
289
|
+
return components
|
|
290
|
+
|
|
291
|
+
@router.get(
|
|
292
|
+
"/registry",
|
|
293
|
+
response_model=PaginatedResponse[ComponentResponse],
|
|
294
|
+
response_model_exclude_none=True,
|
|
295
|
+
status_code=200,
|
|
296
|
+
operation_id="list_registry",
|
|
297
|
+
summary="List Registry",
|
|
298
|
+
description="List all components in the registry with optional filtering.",
|
|
299
|
+
)
|
|
300
|
+
async def list_registry(
|
|
301
|
+
component_type: Optional[ComponentType] = Query(None, description="Filter by component type"),
|
|
302
|
+
name: Optional[str] = Query(None, description="Filter by name (partial match)"),
|
|
303
|
+
include_schema: bool = Query(False, description="Include JSON schema for schema components"),
|
|
304
|
+
page: int = Query(1, ge=1, description="Page number"),
|
|
305
|
+
limit: int = Query(20, ge=1, le=100, description="Items per page"),
|
|
306
|
+
) -> PaginatedResponse[ComponentResponse]:
|
|
307
|
+
try:
|
|
308
|
+
start_time_ms = time.time() * 1000
|
|
309
|
+
components = _get_all_components(include_schema=include_schema)
|
|
310
|
+
|
|
311
|
+
if component_type:
|
|
312
|
+
components = [c for c in components if c.component_type == component_type]
|
|
313
|
+
|
|
314
|
+
if name:
|
|
315
|
+
needle = name.lower().strip()
|
|
316
|
+
components = [c for c in components if needle in c.name.lower()]
|
|
317
|
+
|
|
318
|
+
total_count = len(components)
|
|
319
|
+
total_pages = (total_count + limit - 1) // limit if limit > 0 else 0
|
|
320
|
+
start_idx = (page - 1) * limit
|
|
321
|
+
paginated = components[start_idx : start_idx + limit]
|
|
322
|
+
|
|
323
|
+
return PaginatedResponse(
|
|
324
|
+
data=paginated,
|
|
325
|
+
meta=PaginationInfo(
|
|
326
|
+
page=page,
|
|
327
|
+
limit=limit,
|
|
328
|
+
total_pages=total_pages,
|
|
329
|
+
total_count=total_count,
|
|
330
|
+
search_time_ms=round(time.time() * 1000 - start_time_ms, 2),
|
|
331
|
+
),
|
|
332
|
+
)
|
|
333
|
+
except Exception as e:
|
|
334
|
+
log_error(f"Error listing components: {e}")
|
|
335
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
336
|
+
|
|
337
|
+
return router
|
|
@@ -6,7 +6,7 @@ from uuid import uuid4
|
|
|
6
6
|
from fastapi import APIRouter, Body, Depends, HTTPException, Path, Query, Request
|
|
7
7
|
|
|
8
8
|
from agno.db.base import AsyncBaseDb, BaseDb, SessionType
|
|
9
|
-
from agno.os.auth import get_authentication_dependency
|
|
9
|
+
from agno.os.auth import get_auth_token_from_request, get_authentication_dependency
|
|
10
10
|
from agno.os.schema import (
|
|
11
11
|
AgentSessionDetailSchema,
|
|
12
12
|
BadRequestResponse,
|
|
@@ -29,13 +29,14 @@ from agno.os.schema import (
|
|
|
29
29
|
)
|
|
30
30
|
from agno.os.settings import AgnoAPISettings
|
|
31
31
|
from agno.os.utils import get_db
|
|
32
|
+
from agno.remote.base import RemoteDb
|
|
32
33
|
from agno.session import AgentSession, TeamSession, WorkflowSession
|
|
33
34
|
|
|
34
35
|
logger = logging.getLogger(__name__)
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
def get_session_router(
|
|
38
|
-
dbs: dict[str, list[Union[BaseDb, AsyncBaseDb]]], settings: AgnoAPISettings = AgnoAPISettings()
|
|
39
|
+
dbs: dict[str, list[Union[BaseDb, AsyncBaseDb, RemoteDb]]], settings: AgnoAPISettings = AgnoAPISettings()
|
|
39
40
|
) -> APIRouter:
|
|
40
41
|
"""Create session router with comprehensive OpenAPI documentation for session management endpoints."""
|
|
41
42
|
session_router = APIRouter(
|
|
@@ -52,7 +53,7 @@ def get_session_router(
|
|
|
52
53
|
return attach_routes(router=session_router, dbs=dbs)
|
|
53
54
|
|
|
54
55
|
|
|
55
|
-
def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBaseDb]]]) -> APIRouter:
|
|
56
|
+
def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBaseDb, RemoteDb]]]) -> APIRouter:
|
|
56
57
|
@router.get(
|
|
57
58
|
"/sessions",
|
|
58
59
|
response_model=PaginatedResponse[SessionSchema],
|
|
@@ -64,6 +65,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
64
65
|
"Supports filtering by session type (agent, team, workflow), component, user, and name. "
|
|
65
66
|
"Sessions represent conversation histories and execution contexts."
|
|
66
67
|
),
|
|
68
|
+
response_model_exclude_none=True,
|
|
67
69
|
responses={
|
|
68
70
|
200: {
|
|
69
71
|
"description": "Sessions retrieved successfully",
|
|
@@ -105,8 +107,8 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
105
107
|
),
|
|
106
108
|
user_id: Optional[str] = Query(default=None, description="Filter sessions by user ID"),
|
|
107
109
|
session_name: Optional[str] = Query(default=None, description="Filter sessions by name (partial match)"),
|
|
108
|
-
limit: Optional[int] = Query(default=20, description="Number of sessions to return per page"),
|
|
109
|
-
page: Optional[int] = Query(default=1, description="Page number for pagination"),
|
|
110
|
+
limit: Optional[int] = Query(default=20, description="Number of sessions to return per page", ge=1),
|
|
111
|
+
page: Optional[int] = Query(default=1, description="Page number for pagination", ge=0),
|
|
110
112
|
sort_by: Optional[str] = Query(default="created_at", description="Field to sort sessions by"),
|
|
111
113
|
sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
|
|
112
114
|
db_id: Optional[str] = Query(default=None, description="Database ID to query sessions from"),
|
|
@@ -117,9 +119,26 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
117
119
|
except Exception as e:
|
|
118
120
|
raise HTTPException(status_code=404, detail=f"{e}")
|
|
119
121
|
|
|
120
|
-
if hasattr(request.state, "user_id"):
|
|
122
|
+
if hasattr(request.state, "user_id") and request.state.user_id is not None:
|
|
121
123
|
user_id = request.state.user_id
|
|
122
124
|
|
|
125
|
+
if isinstance(db, RemoteDb):
|
|
126
|
+
auth_token = get_auth_token_from_request(request)
|
|
127
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
128
|
+
return await db.get_sessions(
|
|
129
|
+
session_type=session_type,
|
|
130
|
+
component_id=component_id,
|
|
131
|
+
user_id=user_id,
|
|
132
|
+
session_name=session_name,
|
|
133
|
+
limit=limit,
|
|
134
|
+
page=page,
|
|
135
|
+
sort_by=sort_by,
|
|
136
|
+
sort_order=sort_order.value if sort_order else None,
|
|
137
|
+
db_id=db_id,
|
|
138
|
+
table=table,
|
|
139
|
+
headers=headers,
|
|
140
|
+
)
|
|
141
|
+
|
|
123
142
|
if isinstance(db, AsyncBaseDb):
|
|
124
143
|
db = cast(AsyncBaseDb, db)
|
|
125
144
|
sessions, total_count = await db.get_sessions(
|
|
@@ -168,6 +187,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
168
187
|
"before running any agent/team/workflow interactions. "
|
|
169
188
|
"The session can later be used by providing its session_id in run requests."
|
|
170
189
|
),
|
|
190
|
+
response_model_exclude_none=True,
|
|
171
191
|
responses={
|
|
172
192
|
201: {
|
|
173
193
|
"description": "Session created successfully",
|
|
@@ -211,9 +231,26 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
211
231
|
|
|
212
232
|
# Get user_id from request state if available (from auth middleware)
|
|
213
233
|
user_id = create_session_request.user_id
|
|
214
|
-
if hasattr(request.state, "user_id"):
|
|
234
|
+
if hasattr(request.state, "user_id") and request.state.user_id is not None:
|
|
215
235
|
user_id = request.state.user_id
|
|
216
236
|
|
|
237
|
+
if isinstance(db, RemoteDb):
|
|
238
|
+
auth_token = get_auth_token_from_request(request)
|
|
239
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
240
|
+
return await db.create_session(
|
|
241
|
+
session_type=session_type,
|
|
242
|
+
session_id=create_session_request.session_id,
|
|
243
|
+
session_name=create_session_request.session_name,
|
|
244
|
+
session_state=create_session_request.session_state,
|
|
245
|
+
metadata=create_session_request.metadata,
|
|
246
|
+
user_id=user_id,
|
|
247
|
+
agent_id=create_session_request.agent_id,
|
|
248
|
+
team_id=create_session_request.team_id,
|
|
249
|
+
workflow_id=create_session_request.workflow_id,
|
|
250
|
+
db_id=db_id,
|
|
251
|
+
headers=headers,
|
|
252
|
+
)
|
|
253
|
+
|
|
217
254
|
# Generate session_id if not provided
|
|
218
255
|
session_id = create_session_request.session_id or str(uuid4())
|
|
219
256
|
|
|
@@ -293,6 +330,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
293
330
|
"Retrieve detailed information about a specific session including metadata, configuration, "
|
|
294
331
|
"and run history. Response schema varies based on session type (agent, team, or workflow)."
|
|
295
332
|
),
|
|
333
|
+
response_model_exclude_none=True,
|
|
296
334
|
responses={
|
|
297
335
|
200: {
|
|
298
336
|
"description": "Session details retrieved successfully",
|
|
@@ -382,9 +420,21 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
382
420
|
) -> Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema]:
|
|
383
421
|
db = await get_db(dbs, db_id, table)
|
|
384
422
|
|
|
385
|
-
if hasattr(request.state, "user_id"):
|
|
423
|
+
if hasattr(request.state, "user_id") and request.state.user_id is not None:
|
|
386
424
|
user_id = request.state.user_id
|
|
387
425
|
|
|
426
|
+
if isinstance(db, RemoteDb):
|
|
427
|
+
auth_token = get_auth_token_from_request(request)
|
|
428
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
429
|
+
return await db.get_session(
|
|
430
|
+
session_id=session_id,
|
|
431
|
+
session_type=session_type,
|
|
432
|
+
user_id=user_id,
|
|
433
|
+
db_id=db_id,
|
|
434
|
+
table=table,
|
|
435
|
+
headers=headers,
|
|
436
|
+
)
|
|
437
|
+
|
|
388
438
|
if isinstance(db, AsyncBaseDb):
|
|
389
439
|
db = cast(AsyncBaseDb, db)
|
|
390
440
|
session = await db.get_session(session_id=session_id, session_type=session_type, user_id=user_id)
|
|
@@ -413,6 +463,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
413
463
|
"Runs represent individual interactions or executions within a session. "
|
|
414
464
|
"Response schema varies based on session type."
|
|
415
465
|
),
|
|
466
|
+
response_model_exclude_none=True,
|
|
416
467
|
responses={
|
|
417
468
|
200: {
|
|
418
469
|
"description": "Session runs retrieved successfully",
|
|
@@ -538,9 +589,23 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
538
589
|
) -> List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]]:
|
|
539
590
|
db = await get_db(dbs, db_id, table)
|
|
540
591
|
|
|
541
|
-
if hasattr(request.state, "user_id"):
|
|
592
|
+
if hasattr(request.state, "user_id") and request.state.user_id is not None:
|
|
542
593
|
user_id = request.state.user_id
|
|
543
594
|
|
|
595
|
+
if isinstance(db, RemoteDb):
|
|
596
|
+
auth_token = get_auth_token_from_request(request)
|
|
597
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
598
|
+
return await db.get_session_runs(
|
|
599
|
+
session_id=session_id,
|
|
600
|
+
session_type=session_type,
|
|
601
|
+
user_id=user_id,
|
|
602
|
+
created_after=created_after,
|
|
603
|
+
created_before=created_before,
|
|
604
|
+
db_id=db_id,
|
|
605
|
+
table=table,
|
|
606
|
+
headers=headers,
|
|
607
|
+
)
|
|
608
|
+
|
|
544
609
|
# Use timestamp filters directly (already in epoch format)
|
|
545
610
|
start_timestamp = created_after
|
|
546
611
|
end_timestamp = created_before
|
|
@@ -650,12 +715,26 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
650
715
|
),
|
|
651
716
|
user_id: Optional[str] = Query(default=None, description="User ID to query run from"),
|
|
652
717
|
db_id: Optional[str] = Query(default=None, description="Database ID to query run from"),
|
|
718
|
+
table: Optional[str] = Query(default=None, description="Table to query run from"),
|
|
653
719
|
) -> Union[RunSchema, TeamRunSchema, WorkflowRunSchema]:
|
|
654
720
|
db = await get_db(dbs, db_id)
|
|
655
721
|
|
|
656
|
-
if hasattr(request.state, "user_id"):
|
|
722
|
+
if hasattr(request.state, "user_id") and request.state.user_id is not None:
|
|
657
723
|
user_id = request.state.user_id
|
|
658
724
|
|
|
725
|
+
if isinstance(db, RemoteDb):
|
|
726
|
+
auth_token = get_auth_token_from_request(request)
|
|
727
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
728
|
+
return await db.get_session_run(
|
|
729
|
+
session_id=session_id,
|
|
730
|
+
run_id=run_id,
|
|
731
|
+
session_type=session_type,
|
|
732
|
+
user_id=user_id,
|
|
733
|
+
db_id=db_id,
|
|
734
|
+
table=table,
|
|
735
|
+
headers=headers,
|
|
736
|
+
)
|
|
737
|
+
|
|
659
738
|
if isinstance(db, AsyncBaseDb):
|
|
660
739
|
db = cast(AsyncBaseDb, db)
|
|
661
740
|
session = await db.get_session(
|
|
@@ -707,11 +786,19 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
707
786
|
},
|
|
708
787
|
)
|
|
709
788
|
async def delete_session(
|
|
789
|
+
request: Request,
|
|
710
790
|
session_id: str = Path(description="Session ID to delete"),
|
|
711
791
|
db_id: Optional[str] = Query(default=None, description="Database ID to use for deletion"),
|
|
712
792
|
table: Optional[str] = Query(default=None, description="Table to use for deletion"),
|
|
713
793
|
) -> None:
|
|
714
794
|
db = await get_db(dbs, db_id, table)
|
|
795
|
+
|
|
796
|
+
if isinstance(db, RemoteDb):
|
|
797
|
+
auth_token = get_auth_token_from_request(request)
|
|
798
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
799
|
+
await db.delete_session(session_id=session_id, db_id=db_id, table=table, headers=headers)
|
|
800
|
+
return
|
|
801
|
+
|
|
715
802
|
if isinstance(db, AsyncBaseDb):
|
|
716
803
|
db = cast(AsyncBaseDb, db)
|
|
717
804
|
await db.delete_session(session_id=session_id)
|
|
@@ -737,10 +824,8 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
737
824
|
},
|
|
738
825
|
)
|
|
739
826
|
async def delete_sessions(
|
|
827
|
+
http_request: Request,
|
|
740
828
|
request: DeleteSessionRequest,
|
|
741
|
-
session_type: SessionType = Query(
|
|
742
|
-
default=SessionType.AGENT, description="Default session type filter", alias="type"
|
|
743
|
-
),
|
|
744
829
|
db_id: Optional[str] = Query(default=None, description="Database ID to use for deletion"),
|
|
745
830
|
table: Optional[str] = Query(default=None, description="Table to use for deletion"),
|
|
746
831
|
) -> None:
|
|
@@ -748,6 +833,19 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
748
833
|
raise HTTPException(status_code=400, detail="Session IDs and session types must have the same length")
|
|
749
834
|
|
|
750
835
|
db = await get_db(dbs, db_id, table)
|
|
836
|
+
|
|
837
|
+
if isinstance(db, RemoteDb):
|
|
838
|
+
auth_token = get_auth_token_from_request(http_request)
|
|
839
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
840
|
+
await db.delete_sessions(
|
|
841
|
+
session_ids=request.session_ids,
|
|
842
|
+
session_types=request.session_types,
|
|
843
|
+
db_id=db_id,
|
|
844
|
+
table=table,
|
|
845
|
+
headers=headers,
|
|
846
|
+
)
|
|
847
|
+
return
|
|
848
|
+
|
|
751
849
|
if isinstance(db, AsyncBaseDb):
|
|
752
850
|
db = cast(AsyncBaseDb, db)
|
|
753
851
|
await db.delete_sessions(session_ids=request.session_ids)
|
|
@@ -843,6 +941,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
843
941
|
},
|
|
844
942
|
)
|
|
845
943
|
async def rename_session(
|
|
944
|
+
request: Request,
|
|
846
945
|
session_id: str = Path(description="Session ID to rename"),
|
|
847
946
|
session_type: SessionType = Query(
|
|
848
947
|
default=SessionType.AGENT, description="Session type (agent, team, or workflow)", alias="type"
|
|
@@ -852,6 +951,19 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
852
951
|
table: Optional[str] = Query(default=None, description="Table to use for rename operation"),
|
|
853
952
|
) -> Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema]:
|
|
854
953
|
db = await get_db(dbs, db_id, table)
|
|
954
|
+
|
|
955
|
+
if isinstance(db, RemoteDb):
|
|
956
|
+
auth_token = get_auth_token_from_request(request)
|
|
957
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
958
|
+
return await db.rename_session(
|
|
959
|
+
session_id=session_id,
|
|
960
|
+
session_name=session_name,
|
|
961
|
+
session_type=session_type,
|
|
962
|
+
db_id=db_id,
|
|
963
|
+
table=table,
|
|
964
|
+
headers=headers,
|
|
965
|
+
)
|
|
966
|
+
|
|
855
967
|
if isinstance(db, AsyncBaseDb):
|
|
856
968
|
db = cast(AsyncBaseDb, db)
|
|
857
969
|
session = await db.rename_session(
|
|
@@ -935,12 +1047,29 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
935
1047
|
update_data: UpdateSessionRequest = Body(description="Session update data"),
|
|
936
1048
|
user_id: Optional[str] = Query(default=None, description="User ID"),
|
|
937
1049
|
db_id: Optional[str] = Query(default=None, description="Database ID to use for update operation"),
|
|
1050
|
+
table: Optional[str] = Query(default=None, description="Table to use for update operation"),
|
|
938
1051
|
) -> Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema]:
|
|
939
1052
|
db = await get_db(dbs, db_id)
|
|
940
1053
|
|
|
941
|
-
if hasattr(request.state, "user_id"):
|
|
1054
|
+
if hasattr(request.state, "user_id") and request.state.user_id is not None:
|
|
942
1055
|
user_id = request.state.user_id
|
|
943
1056
|
|
|
1057
|
+
if isinstance(db, RemoteDb):
|
|
1058
|
+
auth_token = get_auth_token_from_request(request)
|
|
1059
|
+
headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else None
|
|
1060
|
+
return await db.update_session(
|
|
1061
|
+
session_id=session_id,
|
|
1062
|
+
session_type=session_type,
|
|
1063
|
+
session_name=update_data.session_name,
|
|
1064
|
+
session_state=update_data.session_state,
|
|
1065
|
+
metadata=update_data.metadata,
|
|
1066
|
+
summary=update_data.summary,
|
|
1067
|
+
user_id=user_id,
|
|
1068
|
+
db_id=db_id,
|
|
1069
|
+
table=table,
|
|
1070
|
+
headers=headers,
|
|
1071
|
+
)
|
|
1072
|
+
|
|
944
1073
|
# Get the existing session
|
|
945
1074
|
if isinstance(db, AsyncBaseDb):
|
|
946
1075
|
db = cast(AsyncBaseDb, db)
|