agno 1.7.8__tar.gz → 1.7.10__tar.gz
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-1.7.8 → agno-1.7.10}/PKG-INFO +2 -1
- {agno-1.7.8 → agno-1.7.10}/agno/agent/agent.py +33 -27
- agno-1.7.10/agno/document/reader/pdf_reader.py +511 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/agent.py +68 -72
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/pdf.py +32 -8
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/pdf_url.py +13 -5
- {agno-1.7.8 → agno-1.7.10}/agno/models/openai/responses.py +30 -1
- {agno-1.7.8 → agno-1.7.10}/agno/run/response.py +10 -0
- {agno-1.7.8 → agno-1.7.10}/agno/run/team.py +10 -0
- {agno-1.7.8 → agno-1.7.10}/agno/team/team.py +39 -20
- {agno-1.7.8 → agno-1.7.10}/agno/tools/aws_lambda.py +10 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/github.py +54 -18
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/lancedb/lance_db.py +10 -2
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/pgvector/pgvector.py +3 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/weaviate/weaviate.py +84 -18
- {agno-1.7.8 → agno-1.7.10}/agno.egg-info/PKG-INFO +2 -1
- {agno-1.7.8 → agno-1.7.10}/agno.egg-info/requires.txt +1 -0
- {agno-1.7.8 → agno-1.7.10}/pyproject.toml +2 -1
- agno-1.7.8/agno/document/reader/pdf_reader.py +0 -352
- {agno-1.7.8 → agno-1.7.10}/LICENSE +0 -0
- {agno-1.7.8 → agno-1.7.10}/README.md +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/agent/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/agent/metrics.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/agent.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/api.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/evals.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/playground.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/routes.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/agent.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/evals.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/playground.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/response.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/team.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/user.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/workflows.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/schemas/workspace.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/team.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/user.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/workflows.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/api/workspace.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/agui/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/agui/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/agui/async_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/agui/sync_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/agui/utils.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/discord/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/discord/client.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/fastapi/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/fastapi/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/fastapi/async_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/fastapi/sync_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/async_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/deploy.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/operator.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/schemas.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/serve.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/settings.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/sync_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/playground/utils.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/settings.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/slack/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/slack/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/slack/async_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/slack/security.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/slack/sync_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/utils.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/whatsapp/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/whatsapp/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/whatsapp/async_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/whatsapp/security.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/app/whatsapp/sync_router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/auth_server.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/config.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/console.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/credentials.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/entrypoint.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/operator.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/settings.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/ws/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/cli/ws/ws_cli.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/constants.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/debug.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/agentic.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/document.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/fixed.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/markdown.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/recursive.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/row.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/semantic.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/chunking/strategy.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/arxiv_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/csv_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/docx_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/firecrawl_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/gcs/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/gcs/pdf_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/json_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/markdown_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/s3/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/s3/pdf_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/s3/text_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/text_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/url_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/website_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/document/reader/youtube_reader.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/aws_bedrock.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/azure_openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/cohere.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/fastembed.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/fireworks.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/google.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/huggingface.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/jina.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/langdb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/mistral.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/nebius.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/ollama.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/sentence_transformer.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/together.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/embedder/voyageai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/eval/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/eval/accuracy.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/eval/performance.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/eval/reliability.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/eval/utils.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/exceptions.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/file/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/file/file.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/file/local/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/file/local/csv.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/file/local/txt.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/infra/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/infra/app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/infra/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/infra/context.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/infra/db_app.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/infra/resource.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/infra/resources.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/arxiv.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/combined.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/csv.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/csv_url.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/document.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/docx.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/firecrawl.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/gcs/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/gcs/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/gcs/pdf.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/json.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/langchain.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/light_rag.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/llamaindex.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/markdown.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/pdf_bytes.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/s3/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/s3/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/s3/pdf.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/s3/text.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/text.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/url.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/website.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/wikipedia.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/knowledge/youtube.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/media.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/agent.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/classifier.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/db/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/db/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/db/mongodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/db/postgres.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/db/sqlite.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/manager.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/memory.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/row.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/summarizer.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/summary.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/team.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/firestore.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/mongodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/postgres.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/redis.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/schema.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/db/sqlite.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/manager.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/memory.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/schema.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/v2/summarizer.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/memory/workflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/aimlapi/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/aimlapi/aimlapi.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/anthropic/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/anthropic/claude.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/aws/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/aws/bedrock.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/aws/claude.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/azure/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/azure/ai_foundry.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/azure/openai_chat.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/cerebras/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/cerebras/cerebras.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/cerebras/cerebras_openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/cohere/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/cohere/chat.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/deepinfra/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/deepinfra/deepinfra.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/deepseek/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/deepseek/deepseek.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/defaults.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/fireworks/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/fireworks/fireworks.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/google/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/google/gemini.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/groq/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/groq/groq.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/huggingface/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/huggingface/huggingface.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/ibm/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/ibm/watsonx.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/internlm/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/internlm/internlm.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/langdb/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/langdb/langdb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/litellm/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/litellm/chat.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/litellm/litellm_openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/lmstudio/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/lmstudio/lmstudio.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/message.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/meta/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/meta/llama.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/meta/llama_openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/mistral/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/mistral/mistral.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/nebius/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/nebius/nebius.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/nvidia/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/nvidia/nvidia.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/ollama/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/ollama/chat.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/ollama/tools.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/openai/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/openai/chat.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/openai/like.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/openrouter/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/openrouter/openrouter.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/perplexity/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/perplexity/perplexity.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/portkey/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/portkey/portkey.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/response.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/sambanova/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/sambanova/sambanova.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/together/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/together/together.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/vercel/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/vercel/v0.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/vllm/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/vllm/vllm.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/xai/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/models/xai/xai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/playground/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/playground/deploy.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/playground/playground.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/playground/serve.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/playground/settings.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/py.typed +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/azure_ai_foundry.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/deepseek.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/default.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/groq.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/helpers.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/ollama.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reasoning/step.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reranker/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reranker/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reranker/cohere.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reranker/infinity.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/reranker/sentence_transformer.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/run/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/run/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/run/messages.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/run/v2/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/run/v2/workflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/run/workflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/dynamodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/json.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/mongodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/postgres.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/singlestore.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/sqlite.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/agent/yaml.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/dynamodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/firestore.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/gcs_json.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/json.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/mongodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/mysql.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/postgres.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/redis.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/session/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/session/agent.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/session/team.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/session/v2/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/session/v2/workflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/session/workflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/singlestore.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/sqlite.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/workflow/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/workflow/mongodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/workflow/postgres.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/workflow/sqlite.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/storage/yaml.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/team/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/agentql.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/airflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/api.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/apify.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/arxiv.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/aws_ses.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/baidusearch.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/bitbucket.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/bravesearch.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/brightdata.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/browserbase.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/calcom.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/calculator.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/cartesia.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/clickup_tool.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/confluence.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/crawl4ai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/csv_toolkit.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/dalle.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/daytona.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/decorator.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/desi_vocal.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/discord.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/docker.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/duckdb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/duckduckgo.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/e2b.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/eleven_labs.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/email.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/evm.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/exa.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/fal.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/file.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/financial_datasets.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/firecrawl.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/function.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/giphy.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/gmail.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/google_bigquery.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/google_maps.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/googlecalendar.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/googlesearch.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/googlesheets.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/hackernews.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/jina.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/jira.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/knowledge.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/linear.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/linkup.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/local_file_system.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/lumalab.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/mcp.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/mem0.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/mlx_transcribe.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/models/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/models/azure_openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/models/gemini.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/models/groq.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/models/morph.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/models/nebius.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/models_labs.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/moviepy_video.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/newspaper.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/newspaper4k.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/openbb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/opencv.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/openweather.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/oxylabs.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/pandas.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/postgres.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/pubmed.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/python.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/reasoning.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/reddit.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/replicate.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/resend.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/scrapegraph.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/searxng.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/serpapi.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/serper.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/shell.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/slack.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/sleep.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/spider.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/sql.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/streamlit/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/streamlit/components.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/tavily.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/telegram.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/thinking.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/todoist.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/tool_registry.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/toolkit.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/trello.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/twilio.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/user_control_flow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/valyu.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/visualization.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/webbrowser.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/webex.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/website.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/webtools.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/whatsapp.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/wikipedia.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/x.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/yfinance.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/youtube.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/zendesk.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/zep.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/tools/zoom.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/audio.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/certs.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/code_execution.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/common.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/defaults.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/dttm.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/enum.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/env.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/events.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/filesystem.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/format_str.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/functions.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/gemini.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/git.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/http.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/json_io.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/json_schema.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/load_env.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/location.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/log.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/mcp.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/media.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/merge_dict.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/message.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/ai_foundry.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/aws_claude.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/claude.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/cohere.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/llama.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/mistral.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/openai_responses.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/schema_utils.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/models/watsonx.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/openai.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/pickle.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/pprint.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/prompts.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/py_io.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/pyproject.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/resource_filter.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/response.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/response_iterator.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/safe_formatter.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/shell.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/string.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/timer.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/tools.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/web.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/whatsapp.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/utils/yaml_io.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/base.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/cassandra/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/cassandra/cassandra.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/cassandra/extra_param_mixin.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/cassandra/index.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/chroma/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/chroma/chromadb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/clickhouse/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/clickhouse/clickhousedb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/clickhouse/index.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/couchbase/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/couchbase/couchbase.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/distance.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/lancedb/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/milvus/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/milvus/milvus.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/mongodb/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/mongodb/mongodb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/pgvector/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/pgvector/index.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/pineconedb/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/pineconedb/pineconedb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/qdrant/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/qdrant/qdrant.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/search.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/singlestore/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/singlestore/index.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/singlestore/singlestore.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/surrealdb/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/surrealdb/surrealdb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/upstashdb/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/upstashdb/upstashdb.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/weaviate/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/vectordb/weaviate/index.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/condition.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/loop.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/parallel.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/router.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/step.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/steps.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/types.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/v2/workflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workflow/workflow.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workspace/__init__.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workspace/config.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workspace/enums.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workspace/helpers.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workspace/operator.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno/workspace/settings.py +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno.egg-info/SOURCES.txt +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno.egg-info/dependency_links.txt +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno.egg-info/entry_points.txt +0 -0
- {agno-1.7.8 → agno-1.7.10}/agno.egg-info/top_level.txt +0 -0
- {agno-1.7.8 → agno-1.7.10}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agno
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.10
|
|
4
4
|
Summary: Agno: a lightweight library for building Multi-Agent Systems
|
|
5
5
|
Author-email: Ashpreet Bedi <ashpreet@agno.com>
|
|
6
6
|
License: Copyright (c) Agno, Inc.
|
|
@@ -400,6 +400,7 @@ License-File: LICENSE
|
|
|
400
400
|
Requires-Dist: docstring-parser
|
|
401
401
|
Requires-Dist: gitpython
|
|
402
402
|
Requires-Dist: httpx
|
|
403
|
+
Requires-Dist: packaging
|
|
403
404
|
Requires-Dist: pydantic-settings
|
|
404
405
|
Requires-Dist: pydantic
|
|
405
406
|
Requires-Dist: python-dotenv
|
|
@@ -893,7 +893,7 @@ class Agent:
|
|
|
893
893
|
):
|
|
894
894
|
yield event
|
|
895
895
|
else:
|
|
896
|
-
from agno.
|
|
896
|
+
from agno.run.response import IntermediateRunResponseContentEvent, RunResponseContentEvent
|
|
897
897
|
|
|
898
898
|
for event in self._handle_model_response_stream(
|
|
899
899
|
run_response=run_response,
|
|
@@ -903,7 +903,10 @@ class Agent:
|
|
|
903
903
|
):
|
|
904
904
|
if isinstance(event, RunResponseContentEvent):
|
|
905
905
|
if stream_intermediate_steps:
|
|
906
|
-
yield
|
|
906
|
+
yield IntermediateRunResponseContentEvent(
|
|
907
|
+
content=event.content,
|
|
908
|
+
content_type=event.content_type,
|
|
909
|
+
)
|
|
907
910
|
else:
|
|
908
911
|
yield event
|
|
909
912
|
|
|
@@ -1331,7 +1334,7 @@ class Agent:
|
|
|
1331
1334
|
):
|
|
1332
1335
|
yield event
|
|
1333
1336
|
else:
|
|
1334
|
-
from agno.
|
|
1337
|
+
from agno.run.response import IntermediateRunResponseContentEvent, RunResponseContentEvent
|
|
1335
1338
|
|
|
1336
1339
|
async for event in self._ahandle_model_response_stream(
|
|
1337
1340
|
run_response=run_response,
|
|
@@ -1341,7 +1344,10 @@ class Agent:
|
|
|
1341
1344
|
):
|
|
1342
1345
|
if isinstance(event, RunResponseContentEvent):
|
|
1343
1346
|
if stream_intermediate_steps:
|
|
1344
|
-
yield
|
|
1347
|
+
yield IntermediateRunResponseContentEvent(
|
|
1348
|
+
content=event.content,
|
|
1349
|
+
content_type=event.content_type,
|
|
1350
|
+
)
|
|
1345
1351
|
else:
|
|
1346
1352
|
yield event
|
|
1347
1353
|
|
|
@@ -4973,9 +4979,26 @@ class Agent:
|
|
|
4973
4979
|
|
|
4974
4980
|
run_messages.messages += history_copy
|
|
4975
4981
|
|
|
4976
|
-
# 4.Add
|
|
4982
|
+
# 4. Add messages to run_messages if provided
|
|
4983
|
+
if messages is not None and len(messages) > 0:
|
|
4984
|
+
for _m in messages:
|
|
4985
|
+
if isinstance(_m, Message):
|
|
4986
|
+
run_messages.messages.append(_m)
|
|
4987
|
+
if run_messages.extra_messages is None:
|
|
4988
|
+
run_messages.extra_messages = []
|
|
4989
|
+
run_messages.extra_messages.append(_m)
|
|
4990
|
+
elif isinstance(_m, dict):
|
|
4991
|
+
try:
|
|
4992
|
+
run_messages.messages.append(Message.model_validate(_m))
|
|
4993
|
+
if run_messages.extra_messages is None:
|
|
4994
|
+
run_messages.extra_messages = []
|
|
4995
|
+
run_messages.extra_messages.append(Message.model_validate(_m))
|
|
4996
|
+
except Exception as e:
|
|
4997
|
+
log_warning(f"Failed to validate message: {e}")
|
|
4998
|
+
|
|
4999
|
+
# 5. Add user message to run_messages
|
|
4977
5000
|
user_message: Optional[Message] = None
|
|
4978
|
-
#
|
|
5001
|
+
# 5.1 Build user message if message is None, str or list
|
|
4979
5002
|
if message is None or isinstance(message, str) or isinstance(message, list):
|
|
4980
5003
|
user_message = self.get_user_message(
|
|
4981
5004
|
message=message,
|
|
@@ -4986,16 +5009,16 @@ class Agent:
|
|
|
4986
5009
|
knowledge_filters=knowledge_filters,
|
|
4987
5010
|
**kwargs,
|
|
4988
5011
|
)
|
|
4989
|
-
#
|
|
5012
|
+
# 5.2 If message is provided as a Message, use it directly
|
|
4990
5013
|
elif isinstance(message, Message):
|
|
4991
5014
|
user_message = message
|
|
4992
|
-
#
|
|
5015
|
+
# 5.3 If message is provided as a dict, try to validate it as a Message
|
|
4993
5016
|
elif isinstance(message, dict):
|
|
4994
5017
|
try:
|
|
4995
5018
|
user_message = Message.model_validate(message)
|
|
4996
5019
|
except Exception as e:
|
|
4997
5020
|
log_warning(f"Failed to validate message: {e}")
|
|
4998
|
-
#
|
|
5021
|
+
# 5.4 If message is provided as a BaseModel, convert it to a Message
|
|
4999
5022
|
elif isinstance(message, BaseModel):
|
|
5000
5023
|
try:
|
|
5001
5024
|
# Create a user message with the BaseModel content
|
|
@@ -5008,23 +5031,6 @@ class Agent:
|
|
|
5008
5031
|
run_messages.user_message = user_message
|
|
5009
5032
|
run_messages.messages.append(user_message)
|
|
5010
5033
|
|
|
5011
|
-
# 5. Add messages to run_messages if provided
|
|
5012
|
-
if messages is not None and len(messages) > 0:
|
|
5013
|
-
for _m in messages:
|
|
5014
|
-
if isinstance(_m, Message):
|
|
5015
|
-
run_messages.messages.append(_m)
|
|
5016
|
-
if run_messages.extra_messages is None:
|
|
5017
|
-
run_messages.extra_messages = []
|
|
5018
|
-
run_messages.extra_messages.append(_m)
|
|
5019
|
-
elif isinstance(_m, dict):
|
|
5020
|
-
try:
|
|
5021
|
-
run_messages.messages.append(Message.model_validate(_m))
|
|
5022
|
-
if run_messages.extra_messages is None:
|
|
5023
|
-
run_messages.extra_messages = []
|
|
5024
|
-
run_messages.extra_messages.append(Message.model_validate(_m))
|
|
5025
|
-
except Exception as e:
|
|
5026
|
-
log_warning(f"Failed to validate message: {e}")
|
|
5027
|
-
|
|
5028
5034
|
return run_messages
|
|
5029
5035
|
|
|
5030
5036
|
def get_continue_run_messages(
|
|
@@ -6866,7 +6872,7 @@ class Agent:
|
|
|
6866
6872
|
document_name = query.replace(" ", "_").replace("?", "").replace("!", "").replace(".", "")
|
|
6867
6873
|
document_content = json.dumps({"query": query, "result": result})
|
|
6868
6874
|
log_info(f"Adding document to knowledge base: {document_name}: {document_content}")
|
|
6869
|
-
self.knowledge.
|
|
6875
|
+
self.knowledge.load_document(
|
|
6870
6876
|
document=Document(
|
|
6871
6877
|
name=document_name,
|
|
6872
6878
|
content=document_content,
|
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import re
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import IO, Any, List, Optional, Tuple, Union
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from agno.document.base import Document
|
|
8
|
+
from agno.document.reader.base import Reader
|
|
9
|
+
from agno.utils.http import async_fetch_with_retry, fetch_with_retry
|
|
10
|
+
from agno.utils.log import log_error, log_info, logger
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from pypdf import PdfReader as DocumentReader # noqa: F401
|
|
14
|
+
from pypdf.errors import PdfStreamError
|
|
15
|
+
except ImportError:
|
|
16
|
+
raise ImportError("`pypdf` not installed. Please install it via `pip install pypdf`.")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
PAGE_START_NUMBERING_FORMAT_DEFAULT = "<start page {page_nr}>"
|
|
20
|
+
PAGE_END_NUMBERING_FORMAT_DEFAULT = "<end page {page_nr}>"
|
|
21
|
+
PAGE_NUMBERING_CORRECTNESS_RATIO_FOR_REMOVAL = 0.4
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _ocr_reader(page: Any) -> str:
|
|
25
|
+
"""A single PDF page object."""
|
|
26
|
+
try:
|
|
27
|
+
import rapidocr_onnxruntime as rapidocr
|
|
28
|
+
except ImportError:
|
|
29
|
+
raise ImportError(
|
|
30
|
+
"`rapidocr_onnxruntime` not installed. Please install it via `pip install rapidocr_onnxruntime`."
|
|
31
|
+
)
|
|
32
|
+
ocr = rapidocr.RapidOCR()
|
|
33
|
+
images_text_list = []
|
|
34
|
+
|
|
35
|
+
# Extract and process images
|
|
36
|
+
for image_object in page.images:
|
|
37
|
+
image_data = image_object.data
|
|
38
|
+
|
|
39
|
+
# Perform OCR on the image
|
|
40
|
+
ocr_result, elapse = ocr(image_data)
|
|
41
|
+
|
|
42
|
+
# Extract text from OCR result
|
|
43
|
+
images_text_list += [item[1] for item in ocr_result] if ocr_result else []
|
|
44
|
+
|
|
45
|
+
return "\n".join(images_text_list)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def _async_ocr_reader(page: Any) -> str:
|
|
49
|
+
"""page: A single PDF page object."""
|
|
50
|
+
try:
|
|
51
|
+
import rapidocr_onnxruntime as rapidocr
|
|
52
|
+
except ImportError:
|
|
53
|
+
raise ImportError(
|
|
54
|
+
"`rapidocr_onnxruntime` not installed. Please install it via `pip install rapidocr_onnxruntime`."
|
|
55
|
+
)
|
|
56
|
+
ocr = rapidocr.RapidOCR()
|
|
57
|
+
|
|
58
|
+
# Process images in parallel
|
|
59
|
+
async def process_image(image_data: bytes) -> List[str]:
|
|
60
|
+
ocr_result, _ = ocr(image_data)
|
|
61
|
+
return [item[1] for item in ocr_result] if ocr_result else []
|
|
62
|
+
|
|
63
|
+
image_tasks = [process_image(image.data) for image in page.images]
|
|
64
|
+
images_results = await asyncio.gather(*image_tasks)
|
|
65
|
+
|
|
66
|
+
images_text_list: List = []
|
|
67
|
+
for result in images_results:
|
|
68
|
+
images_text_list.extend(result)
|
|
69
|
+
|
|
70
|
+
images_text = "\n".join(images_text_list)
|
|
71
|
+
return images_text
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _clean_page_numbers(
|
|
75
|
+
page_content_list: List[str],
|
|
76
|
+
extra_content: List[str] = [],
|
|
77
|
+
page_start_numbering_format: str = PAGE_START_NUMBERING_FORMAT_DEFAULT,
|
|
78
|
+
page_end_numbering_format: str = PAGE_END_NUMBERING_FORMAT_DEFAULT,
|
|
79
|
+
) -> Tuple[List[str], Optional[int]]:
|
|
80
|
+
f"""
|
|
81
|
+
Identifies and removes or reformats page numbers from a list of PDF page contents, based on the most consistent sequential numbering.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
page_content_list (List[str]): A list of strings where each string represents the content of a PDF page.
|
|
85
|
+
extra_content (List[str]): A list of strings where each string will be appended after the main content. Can be used for appending image information.
|
|
86
|
+
page_start_numbering_format (str): A format string to prepend to the page content, with `{{page_nr}}` as a placeholder for the page number.
|
|
87
|
+
Defaults to {PAGE_START_NUMBERING_FORMAT_DEFAULT}. Make it an empty string to remove the page number.
|
|
88
|
+
page_end_numbering_format (str): A format string to append to the page content, with `{{page_nr}}` as a placeholder for the page number.
|
|
89
|
+
Defaults to {PAGE_END_NUMBERING_FORMAT_DEFAULT}. Make it an empty string to remove the page number.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
List[str]: The list of page contents with page numbers removed or reformatted based on the detected sequence.
|
|
93
|
+
Optional[Int]: The shift for the page numbering. Can be (-2, -1, 0, 1, 2).
|
|
94
|
+
|
|
95
|
+
Notes:
|
|
96
|
+
- The function scans for page numbers using a regular expression that matches digits at the start or end of a string.
|
|
97
|
+
- It evaluates several potential starting points for numbering (-2, -1, 0, 1, 2 shifts) to determine the most consistent sequence.
|
|
98
|
+
- If at least a specified ratio of pages (defined by `PAGE_NUMBERING_CORRECTNESS_RATIO_FOR_REMOVAL`) has correct sequential numbering,
|
|
99
|
+
the page numbers are processed.
|
|
100
|
+
- If page numbers are found, the function will add formatted page numbers to each page's content if `page_start_numbering_format` or
|
|
101
|
+
`page_end_numbering_format` is provided.
|
|
102
|
+
"""
|
|
103
|
+
assert len(extra_content) == 0 or len(extra_content) == len(page_content_list), (
|
|
104
|
+
"Please provide an equally sized list of extra content if provided."
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Regex to match potential page numbers at the start or end of a string
|
|
108
|
+
page_number_regex = re.compile(r"^\s*(\d+)\s*|\s*(\d+)\s*$")
|
|
109
|
+
|
|
110
|
+
def find_page_number(content):
|
|
111
|
+
match = page_number_regex.search(content)
|
|
112
|
+
if match:
|
|
113
|
+
return int(match.group(1) or match.group(2))
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
page_numbers = [find_page_number(content) for content in page_content_list]
|
|
117
|
+
if all(x is None or x > 5 for x in page_numbers):
|
|
118
|
+
# This approach won't work reliably for higher page numbers.
|
|
119
|
+
return page_content_list, None
|
|
120
|
+
|
|
121
|
+
# Possible range shifts to detect page numbering
|
|
122
|
+
range_shifts = [-2, -1, 0, 1, 2]
|
|
123
|
+
best_match, best_correct_count, best_shift = _identify_best_page_sequence(page_numbers, range_shifts)
|
|
124
|
+
|
|
125
|
+
# Check if at least ..% of the pages have correct sequential numbering
|
|
126
|
+
if best_match and best_correct_count / len(page_numbers) >= PAGE_NUMBERING_CORRECTNESS_RATIO_FOR_REMOVAL:
|
|
127
|
+
# Remove the page numbers from the content
|
|
128
|
+
for i, expected_number in enumerate(best_match):
|
|
129
|
+
page_content_list[i] = re.sub(
|
|
130
|
+
rf"^\s*{expected_number}\s*|\s*{expected_number}\s*$", "", page_content_list[i]
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
page_start = (
|
|
134
|
+
page_start_numbering_format.format(page_nr=expected_number) + "\n"
|
|
135
|
+
if page_start_numbering_format
|
|
136
|
+
else ""
|
|
137
|
+
)
|
|
138
|
+
page_end = (
|
|
139
|
+
"\n" + page_end_numbering_format.format(page_nr=expected_number) if page_end_numbering_format else ""
|
|
140
|
+
)
|
|
141
|
+
extra_info = "\n" + extra_content[i] if extra_content else ""
|
|
142
|
+
|
|
143
|
+
# Add formatted page numbering if configured.
|
|
144
|
+
page_content_list[i] = page_start + page_content_list[i] + extra_info + page_end
|
|
145
|
+
else:
|
|
146
|
+
best_shift = None
|
|
147
|
+
|
|
148
|
+
return page_content_list, best_shift
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _identify_best_page_sequence(page_numbers, range_shifts):
|
|
152
|
+
best_match = None
|
|
153
|
+
best_shift: Optional[int] = None
|
|
154
|
+
best_correct_count = 0
|
|
155
|
+
|
|
156
|
+
for shift in range_shifts:
|
|
157
|
+
expected_numbers = [i + shift for i in range(len(page_numbers))]
|
|
158
|
+
# Check if expected number occurs (or that the expected "2" occurs in an incorrectly merged number like 25,
|
|
159
|
+
# where 2 is the page number and 5 is part of the PDF content).
|
|
160
|
+
correct_count = sum(
|
|
161
|
+
1
|
|
162
|
+
for actual, expected in zip(page_numbers, expected_numbers)
|
|
163
|
+
if actual == expected or str(actual).startswith(str(expected)) or str(actual).endswith(str(expected))
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
if correct_count > best_correct_count:
|
|
167
|
+
best_correct_count = correct_count
|
|
168
|
+
best_match = expected_numbers
|
|
169
|
+
best_shift = shift
|
|
170
|
+
|
|
171
|
+
return best_match, best_correct_count, best_shift
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class BasePDFReader(Reader):
|
|
175
|
+
def __init__(
|
|
176
|
+
self,
|
|
177
|
+
split_on_pages: bool = True,
|
|
178
|
+
page_start_numbering_format: Optional[str] = None,
|
|
179
|
+
page_end_numbering_format: Optional[str] = None,
|
|
180
|
+
password: Optional[str] = None,
|
|
181
|
+
**kwargs,
|
|
182
|
+
):
|
|
183
|
+
if page_start_numbering_format is None:
|
|
184
|
+
page_start_numbering_format = PAGE_START_NUMBERING_FORMAT_DEFAULT
|
|
185
|
+
if page_end_numbering_format is None:
|
|
186
|
+
page_end_numbering_format = PAGE_END_NUMBERING_FORMAT_DEFAULT
|
|
187
|
+
|
|
188
|
+
self.split_on_pages = split_on_pages
|
|
189
|
+
self.page_start_numbering_format = page_start_numbering_format
|
|
190
|
+
self.page_end_numbering_format = page_end_numbering_format
|
|
191
|
+
self.password = password
|
|
192
|
+
|
|
193
|
+
super().__init__(**kwargs)
|
|
194
|
+
|
|
195
|
+
def _build_chunked_documents(self, documents: List[Document]) -> List[Document]:
|
|
196
|
+
chunked_documents: List[Document] = []
|
|
197
|
+
for document in documents:
|
|
198
|
+
chunked_documents.extend(self.chunk_document(document))
|
|
199
|
+
return chunked_documents
|
|
200
|
+
|
|
201
|
+
def _decrypt_pdf(self, doc_reader: DocumentReader, doc_name: str, password: Optional[str] = None) -> bool:
|
|
202
|
+
if not doc_reader.is_encrypted:
|
|
203
|
+
return True
|
|
204
|
+
|
|
205
|
+
# Use provided password or fall back to instance password
|
|
206
|
+
pdf_password = password or self.password
|
|
207
|
+
if not pdf_password:
|
|
208
|
+
logger.error(f"PDF {doc_name} is password protected but no password provided")
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
decrypted_pdf = doc_reader.decrypt(pdf_password)
|
|
213
|
+
if decrypted_pdf:
|
|
214
|
+
log_info(f"Successfully decrypted PDF {doc_name} with user password")
|
|
215
|
+
return True
|
|
216
|
+
else:
|
|
217
|
+
log_error(f"Failed to decrypt PDF {doc_name}: incorrect password")
|
|
218
|
+
return False
|
|
219
|
+
except Exception as e:
|
|
220
|
+
log_error(f"Error decrypting PDF {doc_name}: {e}")
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
def _create_documents(self, pdf_content: List[str], doc_name: str, use_uuid_for_id: bool, page_number_shift):
|
|
224
|
+
if self.split_on_pages:
|
|
225
|
+
shift = page_number_shift if page_number_shift is not None else 1
|
|
226
|
+
documents: List[Document] = []
|
|
227
|
+
for page_number, page_content in enumerate(pdf_content, start=shift):
|
|
228
|
+
documents.append(
|
|
229
|
+
Document(
|
|
230
|
+
name=doc_name,
|
|
231
|
+
id=(str(uuid4()) if use_uuid_for_id else f"{doc_name}_{page_number}"),
|
|
232
|
+
meta_data={"page": page_number},
|
|
233
|
+
content=page_content,
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
else:
|
|
237
|
+
pdf_content_str = "\n".join(pdf_content)
|
|
238
|
+
document = Document(
|
|
239
|
+
name=doc_name,
|
|
240
|
+
id=str(uuid4()) if use_uuid_for_id else doc_name,
|
|
241
|
+
meta_data={},
|
|
242
|
+
content=pdf_content_str,
|
|
243
|
+
)
|
|
244
|
+
documents = [document]
|
|
245
|
+
|
|
246
|
+
if self.chunk:
|
|
247
|
+
return self._build_chunked_documents(documents)
|
|
248
|
+
|
|
249
|
+
return documents
|
|
250
|
+
|
|
251
|
+
def _pdf_reader_to_documents(
|
|
252
|
+
self,
|
|
253
|
+
doc_reader: DocumentReader,
|
|
254
|
+
doc_name,
|
|
255
|
+
read_images=False,
|
|
256
|
+
use_uuid_for_id=False,
|
|
257
|
+
):
|
|
258
|
+
pdf_content = []
|
|
259
|
+
pdf_images_text = []
|
|
260
|
+
for page in doc_reader.pages:
|
|
261
|
+
pdf_content.append(page.extract_text())
|
|
262
|
+
if read_images:
|
|
263
|
+
pdf_images_text.append(_ocr_reader(page))
|
|
264
|
+
|
|
265
|
+
pdf_content, shift = _clean_page_numbers(
|
|
266
|
+
page_content_list=pdf_content,
|
|
267
|
+
extra_content=pdf_images_text,
|
|
268
|
+
page_start_numbering_format=self.page_start_numbering_format,
|
|
269
|
+
page_end_numbering_format=self.page_end_numbering_format,
|
|
270
|
+
)
|
|
271
|
+
return self._create_documents(pdf_content, doc_name, use_uuid_for_id, shift)
|
|
272
|
+
|
|
273
|
+
async def _async_pdf_reader_to_documents(
|
|
274
|
+
self,
|
|
275
|
+
doc_reader: DocumentReader,
|
|
276
|
+
doc_name: str,
|
|
277
|
+
read_images=False,
|
|
278
|
+
use_uuid_for_id=False,
|
|
279
|
+
):
|
|
280
|
+
async def _read_pdf_page(page, read_images) -> Tuple[str, str]:
|
|
281
|
+
# We tried "asyncio.to_thread(page.extract_text)", but it maintains state internally, which leads to issues.
|
|
282
|
+
page_text = page.extract_text()
|
|
283
|
+
|
|
284
|
+
if read_images:
|
|
285
|
+
pdf_images_text = await _async_ocr_reader(page)
|
|
286
|
+
else:
|
|
287
|
+
pdf_images_text = ""
|
|
288
|
+
|
|
289
|
+
return page_text, pdf_images_text
|
|
290
|
+
|
|
291
|
+
# Process pages in parallel using asyncio.gather
|
|
292
|
+
pdf_content: List[Tuple[str, str]] = await asyncio.gather(
|
|
293
|
+
*[_read_pdf_page(page, read_images) for page in doc_reader.pages]
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
pdf_content_clean, shift = _clean_page_numbers(
|
|
297
|
+
page_content_list=[x[0] for x in pdf_content],
|
|
298
|
+
extra_content=[x[1] for x in pdf_content],
|
|
299
|
+
page_start_numbering_format=self.page_start_numbering_format,
|
|
300
|
+
page_end_numbering_format=self.page_end_numbering_format,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
return self._create_documents(pdf_content_clean, doc_name, use_uuid_for_id, shift)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class PDFReader(BasePDFReader):
|
|
307
|
+
"""Reader for PDF files"""
|
|
308
|
+
|
|
309
|
+
def read(self, pdf: Union[str, Path, IO[Any]], password: Optional[str] = None) -> List[Document]:
|
|
310
|
+
try:
|
|
311
|
+
if isinstance(pdf, str):
|
|
312
|
+
doc_name = pdf.split("/")[-1].split(".")[0].replace(" ", "_")
|
|
313
|
+
else:
|
|
314
|
+
doc_name = pdf.name.split(".")[0]
|
|
315
|
+
except Exception:
|
|
316
|
+
doc_name = "pdf"
|
|
317
|
+
|
|
318
|
+
log_info(f"Reading: {doc_name}")
|
|
319
|
+
|
|
320
|
+
try:
|
|
321
|
+
pdf_reader = DocumentReader(pdf)
|
|
322
|
+
except PdfStreamError as e:
|
|
323
|
+
logger.error(f"Error reading PDF: {e}")
|
|
324
|
+
return []
|
|
325
|
+
|
|
326
|
+
# Handle PDF decryption
|
|
327
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
328
|
+
return []
|
|
329
|
+
|
|
330
|
+
# Read and chunk.
|
|
331
|
+
return self._pdf_reader_to_documents(pdf_reader, doc_name, use_uuid_for_id=True)
|
|
332
|
+
|
|
333
|
+
async def async_read(self, pdf: Union[str, Path, IO[Any]], password: Optional[str] = None) -> List[Document]:
|
|
334
|
+
try:
|
|
335
|
+
if isinstance(pdf, str):
|
|
336
|
+
doc_name = pdf.split("/")[-1].split(".")[0].replace(" ", "_")
|
|
337
|
+
else:
|
|
338
|
+
doc_name = pdf.name.split(".")[0]
|
|
339
|
+
except Exception:
|
|
340
|
+
doc_name = "pdf"
|
|
341
|
+
|
|
342
|
+
log_info(f"Reading: {doc_name}")
|
|
343
|
+
|
|
344
|
+
try:
|
|
345
|
+
pdf_reader = DocumentReader(pdf)
|
|
346
|
+
except PdfStreamError as e:
|
|
347
|
+
logger.error(f"Error reading PDF: {e}")
|
|
348
|
+
return []
|
|
349
|
+
|
|
350
|
+
# Handle PDF decryption
|
|
351
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
352
|
+
return []
|
|
353
|
+
|
|
354
|
+
# Read and chunk.
|
|
355
|
+
return await self._async_pdf_reader_to_documents(pdf_reader, doc_name, use_uuid_for_id=True)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class PDFUrlReader(BasePDFReader):
|
|
359
|
+
"""Reader for PDF files from URL"""
|
|
360
|
+
|
|
361
|
+
def __init__(self, proxy: Optional[str] = None, password: Optional[str] = None, **kwargs):
|
|
362
|
+
super().__init__(password=password, **kwargs)
|
|
363
|
+
self.proxy = proxy
|
|
364
|
+
|
|
365
|
+
def read(self, url: str, password: Optional[str] = None) -> List[Document]:
|
|
366
|
+
if not url:
|
|
367
|
+
raise ValueError("No url provided")
|
|
368
|
+
|
|
369
|
+
from io import BytesIO
|
|
370
|
+
|
|
371
|
+
log_info(f"Reading: {url}")
|
|
372
|
+
|
|
373
|
+
# Retry the request up to 3 times with exponential backoff
|
|
374
|
+
response = fetch_with_retry(url, proxy=self.proxy)
|
|
375
|
+
|
|
376
|
+
doc_name = url.split("/")[-1].split(".")[0].replace("/", "_").replace(" ", "_")
|
|
377
|
+
pdf_reader = DocumentReader(BytesIO(response.content))
|
|
378
|
+
|
|
379
|
+
# Handle PDF decryption
|
|
380
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
381
|
+
return []
|
|
382
|
+
|
|
383
|
+
# Read and chunk.
|
|
384
|
+
return self._pdf_reader_to_documents(pdf_reader, doc_name, use_uuid_for_id=False)
|
|
385
|
+
|
|
386
|
+
async def async_read(self, url: str, password: Optional[str] = None) -> List[Document]:
|
|
387
|
+
if not url:
|
|
388
|
+
raise ValueError("No url provided")
|
|
389
|
+
|
|
390
|
+
from io import BytesIO
|
|
391
|
+
|
|
392
|
+
import httpx
|
|
393
|
+
|
|
394
|
+
log_info(f"Reading: {url}")
|
|
395
|
+
|
|
396
|
+
client_args = {"proxy": self.proxy} if self.proxy else {}
|
|
397
|
+
async with httpx.AsyncClient(**client_args) as client: # type: ignore
|
|
398
|
+
response = await async_fetch_with_retry(url, client=client)
|
|
399
|
+
|
|
400
|
+
doc_name = url.split("/")[-1].split(".")[0].replace("/", "_").replace(" ", "_")
|
|
401
|
+
pdf_reader = DocumentReader(BytesIO(response.content))
|
|
402
|
+
|
|
403
|
+
# Handle PDF decryption
|
|
404
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
405
|
+
return []
|
|
406
|
+
|
|
407
|
+
# Read and chunk.
|
|
408
|
+
return await self._async_pdf_reader_to_documents(pdf_reader, doc_name, use_uuid_for_id=False)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
class PDFImageReader(BasePDFReader):
|
|
412
|
+
"""Reader for PDF files with text and images extraction"""
|
|
413
|
+
|
|
414
|
+
def read(self, pdf: Union[str, Path, IO[Any]], password: Optional[str] = None) -> List[Document]:
|
|
415
|
+
if not pdf:
|
|
416
|
+
raise ValueError("No pdf provided")
|
|
417
|
+
|
|
418
|
+
try:
|
|
419
|
+
if isinstance(pdf, str):
|
|
420
|
+
doc_name = pdf.split("/")[-1].split(".")[0].replace(" ", "_")
|
|
421
|
+
else:
|
|
422
|
+
doc_name = pdf.name.split(".")[0]
|
|
423
|
+
except Exception:
|
|
424
|
+
doc_name = "pdf"
|
|
425
|
+
|
|
426
|
+
log_info(f"Reading: {doc_name}")
|
|
427
|
+
pdf_reader = DocumentReader(pdf)
|
|
428
|
+
|
|
429
|
+
# Handle PDF decryption
|
|
430
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
431
|
+
return []
|
|
432
|
+
|
|
433
|
+
# Read and chunk.
|
|
434
|
+
return self._pdf_reader_to_documents(pdf_reader, doc_name, read_images=True, use_uuid_for_id=False)
|
|
435
|
+
|
|
436
|
+
async def async_read(self, pdf: Union[str, Path, IO[Any]], password: Optional[str] = None) -> List[Document]:
|
|
437
|
+
if not pdf:
|
|
438
|
+
raise ValueError("No pdf provided")
|
|
439
|
+
|
|
440
|
+
try:
|
|
441
|
+
if isinstance(pdf, str):
|
|
442
|
+
doc_name = pdf.split("/")[-1].split(".")[0].replace(" ", "_")
|
|
443
|
+
else:
|
|
444
|
+
doc_name = pdf.name.split(".")[0]
|
|
445
|
+
except Exception:
|
|
446
|
+
doc_name = "pdf"
|
|
447
|
+
|
|
448
|
+
log_info(f"Reading: {doc_name}")
|
|
449
|
+
pdf_reader = DocumentReader(pdf)
|
|
450
|
+
|
|
451
|
+
# Handle PDF decryption
|
|
452
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
453
|
+
return []
|
|
454
|
+
|
|
455
|
+
# Read and chunk.
|
|
456
|
+
return await self._async_pdf_reader_to_documents(pdf_reader, doc_name, read_images=True, use_uuid_for_id=False)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
class PDFUrlImageReader(BasePDFReader):
|
|
460
|
+
"""Reader for PDF files from URL with text and images extraction"""
|
|
461
|
+
|
|
462
|
+
def __init__(self, proxy: Optional[str] = None, password: Optional[str] = None, **kwargs):
|
|
463
|
+
super().__init__(password=password, **kwargs)
|
|
464
|
+
self.proxy = proxy
|
|
465
|
+
|
|
466
|
+
def read(self, url: str, password: Optional[str] = None) -> List[Document]:
|
|
467
|
+
if not url:
|
|
468
|
+
raise ValueError("No url provided")
|
|
469
|
+
|
|
470
|
+
from io import BytesIO
|
|
471
|
+
|
|
472
|
+
import httpx
|
|
473
|
+
|
|
474
|
+
# Read the PDF from the URL
|
|
475
|
+
log_info(f"Reading: {url}")
|
|
476
|
+
response = httpx.get(url, proxy=self.proxy) if self.proxy else httpx.get(url)
|
|
477
|
+
|
|
478
|
+
doc_name = url.split("/")[-1].split(".")[0].replace(" ", "_")
|
|
479
|
+
pdf_reader = DocumentReader(BytesIO(response.content))
|
|
480
|
+
|
|
481
|
+
# Handle PDF decryption
|
|
482
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
483
|
+
return []
|
|
484
|
+
|
|
485
|
+
# Read and chunk.
|
|
486
|
+
return self._pdf_reader_to_documents(pdf_reader, doc_name, read_images=True, use_uuid_for_id=False)
|
|
487
|
+
|
|
488
|
+
async def async_read(self, url: str, password: Optional[str] = None) -> List[Document]:
|
|
489
|
+
if not url:
|
|
490
|
+
raise ValueError("No url provided")
|
|
491
|
+
|
|
492
|
+
from io import BytesIO
|
|
493
|
+
|
|
494
|
+
import httpx
|
|
495
|
+
|
|
496
|
+
log_info(f"Reading: {url}")
|
|
497
|
+
|
|
498
|
+
client_args = {"proxy": self.proxy} if self.proxy else {}
|
|
499
|
+
async with httpx.AsyncClient(**client_args) as client: # type: ignore
|
|
500
|
+
response = await client.get(url)
|
|
501
|
+
response.raise_for_status()
|
|
502
|
+
|
|
503
|
+
doc_name = url.split("/")[-1].split(".")[0].replace(" ", "_")
|
|
504
|
+
pdf_reader = DocumentReader(BytesIO(response.content))
|
|
505
|
+
|
|
506
|
+
# Handle PDF decryption
|
|
507
|
+
if not self._decrypt_pdf(pdf_reader, doc_name, password):
|
|
508
|
+
return []
|
|
509
|
+
|
|
510
|
+
# Read and chunk.
|
|
511
|
+
return await self._async_pdf_reader_to_documents(pdf_reader, doc_name, read_images=True, use_uuid_for_id=False)
|