agno 0.1.2__py3-none-any.whl → 2.3.13__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/__init__.py +8 -0
- agno/agent/__init__.py +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- 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/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/tools/reddit.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from os import getenv
|
|
3
|
-
from typing import Dict, List, Optional, Union
|
|
3
|
+
from typing import Callable, Dict, List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from agno.tools import Toolkit
|
|
6
|
-
from agno.utils.log import logger
|
|
6
|
+
from agno.utils.log import log_debug, log_info, logger
|
|
7
7
|
|
|
8
8
|
try:
|
|
9
9
|
import praw # type: ignore
|
|
@@ -20,17 +20,10 @@ class RedditTools(Toolkit):
|
|
|
20
20
|
user_agent: Optional[str] = None,
|
|
21
21
|
username: Optional[str] = None,
|
|
22
22
|
password: Optional[str] = None,
|
|
23
|
-
|
|
24
|
-
get_top_posts: bool = True,
|
|
25
|
-
get_subreddit_info: bool = True,
|
|
26
|
-
get_trending_subreddits: bool = True,
|
|
27
|
-
get_subreddit_stats: bool = True,
|
|
28
|
-
create_post: bool = True,
|
|
23
|
+
**kwargs,
|
|
29
24
|
):
|
|
30
|
-
super().__init__(name="reddit")
|
|
31
|
-
|
|
32
25
|
if reddit_instance is not None:
|
|
33
|
-
|
|
26
|
+
log_info("Using provided Reddit instance")
|
|
34
27
|
self.reddit = reddit_instance
|
|
35
28
|
else:
|
|
36
29
|
# Get credentials from environment variables if not provided
|
|
@@ -45,7 +38,7 @@ class RedditTools(Toolkit):
|
|
|
45
38
|
if all([self.client_id, self.client_secret]):
|
|
46
39
|
# Initialize with read-only access if no user credentials
|
|
47
40
|
if not all([self.username, self.password]):
|
|
48
|
-
|
|
41
|
+
log_info("Initializing Reddit client with read-only access")
|
|
49
42
|
self.reddit = praw.Reddit(
|
|
50
43
|
client_id=self.client_id,
|
|
51
44
|
client_secret=self.client_secret,
|
|
@@ -53,7 +46,7 @@ class RedditTools(Toolkit):
|
|
|
53
46
|
)
|
|
54
47
|
# Initialize with user authentication if credentials provided
|
|
55
48
|
else:
|
|
56
|
-
|
|
49
|
+
log_info(f"Initializing Reddit client with user authentication for u/{self.username}")
|
|
57
50
|
self.reddit = praw.Reddit(
|
|
58
51
|
client_id=self.client_id,
|
|
59
52
|
client_secret=self.client_secret,
|
|
@@ -64,18 +57,18 @@ class RedditTools(Toolkit):
|
|
|
64
57
|
else:
|
|
65
58
|
logger.warning("Missing Reddit API credentials")
|
|
66
59
|
|
|
67
|
-
|
|
68
|
-
self.
|
|
69
|
-
|
|
70
|
-
self.
|
|
71
|
-
|
|
72
|
-
self.
|
|
73
|
-
|
|
74
|
-
self.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
60
|
+
tools: List[Callable] = [
|
|
61
|
+
self.get_user_info,
|
|
62
|
+
self.get_top_posts,
|
|
63
|
+
self.get_subreddit_info,
|
|
64
|
+
self.get_trending_subreddits,
|
|
65
|
+
self.get_subreddit_stats,
|
|
66
|
+
self.create_post,
|
|
67
|
+
self.reply_to_post,
|
|
68
|
+
self.reply_to_comment,
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
super().__init__(name="reddit", tools=tools, **kwargs)
|
|
79
72
|
|
|
80
73
|
def _check_user_auth(self) -> bool:
|
|
81
74
|
"""
|
|
@@ -105,7 +98,7 @@ class RedditTools(Toolkit):
|
|
|
105
98
|
return "Please provide Reddit API credentials"
|
|
106
99
|
|
|
107
100
|
try:
|
|
108
|
-
|
|
101
|
+
log_info(f"Getting info for u/{username}")
|
|
109
102
|
|
|
110
103
|
user = self.reddit.redditor(username)
|
|
111
104
|
info: Dict[str, Union[str, int, bool, float]] = {
|
|
@@ -137,14 +130,20 @@ class RedditTools(Toolkit):
|
|
|
137
130
|
return "Please provide Reddit API credentials"
|
|
138
131
|
|
|
139
132
|
try:
|
|
133
|
+
log_debug(f"Getting top posts from r/{subreddit}")
|
|
140
134
|
posts = self.reddit.subreddit(subreddit).top(time_filter=time_filter, limit=limit)
|
|
141
135
|
top_posts: List[Dict[str, Union[str, int, float]]] = [
|
|
142
136
|
{
|
|
137
|
+
"id": post.id,
|
|
143
138
|
"title": post.title,
|
|
144
139
|
"score": post.score,
|
|
145
140
|
"url": post.url,
|
|
141
|
+
"selftext": post.selftext,
|
|
146
142
|
"author": str(post.author),
|
|
143
|
+
"permalink": post.permalink,
|
|
147
144
|
"created_utc": post.created_utc,
|
|
145
|
+
"subreddit": str(post.subreddit),
|
|
146
|
+
"subreddit_name_prefixed": post.subreddit_name_prefixed,
|
|
148
147
|
}
|
|
149
148
|
for post in posts
|
|
150
149
|
]
|
|
@@ -164,7 +163,7 @@ class RedditTools(Toolkit):
|
|
|
164
163
|
return "Please provide Reddit API credentials"
|
|
165
164
|
|
|
166
165
|
try:
|
|
167
|
-
|
|
166
|
+
log_info(f"Getting info for r/{subreddit_name}")
|
|
168
167
|
|
|
169
168
|
subreddit = self.reddit.subreddit(subreddit_name)
|
|
170
169
|
flairs = [flair["text"] for flair in subreddit.flair.link_templates]
|
|
@@ -191,6 +190,7 @@ class RedditTools(Toolkit):
|
|
|
191
190
|
return "Please provide Reddit API credentials"
|
|
192
191
|
|
|
193
192
|
try:
|
|
193
|
+
log_debug("Getting trending subreddits")
|
|
194
194
|
popular_subreddits = self.reddit.subreddits.popular(limit=5)
|
|
195
195
|
trending: List[str] = [subreddit.display_name for subreddit in popular_subreddits]
|
|
196
196
|
return json.dumps({"trending_subreddits": trending})
|
|
@@ -209,6 +209,7 @@ class RedditTools(Toolkit):
|
|
|
209
209
|
return "Please provide Reddit API credentials"
|
|
210
210
|
|
|
211
211
|
try:
|
|
212
|
+
log_debug(f"Getting stats for r/{subreddit}")
|
|
212
213
|
sub = self.reddit.subreddit(subreddit)
|
|
213
214
|
stats: Dict[str, Union[str, int, bool, float]] = {
|
|
214
215
|
"display_name": sub.display_name,
|
|
@@ -250,7 +251,7 @@ class RedditTools(Toolkit):
|
|
|
250
251
|
return "User authentication required for posting. Please provide username and password."
|
|
251
252
|
|
|
252
253
|
try:
|
|
253
|
-
|
|
254
|
+
log_info(f"Creating post in r/{subreddit}")
|
|
254
255
|
|
|
255
256
|
subreddit_obj = self.reddit.subreddit(subreddit)
|
|
256
257
|
|
|
@@ -271,7 +272,7 @@ class RedditTools(Toolkit):
|
|
|
271
272
|
url=content,
|
|
272
273
|
flair_id=flair,
|
|
273
274
|
)
|
|
274
|
-
|
|
275
|
+
log_info(f"Post created: {submission.permalink}")
|
|
275
276
|
|
|
276
277
|
post_info: Dict[str, Union[str, int, float]] = {
|
|
277
278
|
"id": submission.id,
|
|
@@ -287,3 +288,180 @@ class RedditTools(Toolkit):
|
|
|
287
288
|
|
|
288
289
|
except Exception as e:
|
|
289
290
|
return f"Error creating post: {e}"
|
|
291
|
+
|
|
292
|
+
def reply_to_post(self, post_id: str, content: str, subreddit: Optional[str] = None) -> str:
|
|
293
|
+
"""
|
|
294
|
+
Post a reply to an existing Reddit post or comment.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
post_id (str): The ID of the post or comment to reply to.
|
|
298
|
+
Can be a full URL, permalink, or just the ID.
|
|
299
|
+
content (str): The content of the reply.
|
|
300
|
+
subreddit (Optional[str]): The subreddit name if known.
|
|
301
|
+
This helps with error handling and validation.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
str: JSON string containing information about the created reply.
|
|
305
|
+
"""
|
|
306
|
+
if not self.reddit:
|
|
307
|
+
logger.error("Reddit instance not initialized")
|
|
308
|
+
return "Please provide Reddit API credentials"
|
|
309
|
+
|
|
310
|
+
if not self._check_user_auth():
|
|
311
|
+
logger.error("User authentication failed")
|
|
312
|
+
return "User authentication required for posting replies. Please provide username and password."
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
log_debug(f"Creating reply to post {post_id}")
|
|
316
|
+
|
|
317
|
+
# Clean up the post_id if it's a full URL or permalink
|
|
318
|
+
if "/" in post_id:
|
|
319
|
+
# Extract the actual ID from the URL/permalink
|
|
320
|
+
original_id = post_id
|
|
321
|
+
post_id = post_id.split("/")[-1]
|
|
322
|
+
log_debug(f"Extracted post ID {post_id} from {original_id}")
|
|
323
|
+
|
|
324
|
+
# Verify post exists
|
|
325
|
+
if not self._check_post_exists(post_id):
|
|
326
|
+
error_msg = f"Post with ID {post_id} does not exist or is not accessible"
|
|
327
|
+
logger.error(error_msg)
|
|
328
|
+
return error_msg
|
|
329
|
+
|
|
330
|
+
# Get the submission object
|
|
331
|
+
submission = self.reddit.submission(id=post_id)
|
|
332
|
+
|
|
333
|
+
log_debug(
|
|
334
|
+
f"Post details: Title: {submission.title}, Author: {submission.author}, Subreddit: {submission.subreddit.display_name}"
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
# If subreddit was provided, verify we're in the right place
|
|
338
|
+
if subreddit and submission.subreddit.display_name.lower() != subreddit.lower():
|
|
339
|
+
error_msg = f"Error: Post ID belongs to r/{submission.subreddit.display_name}, not r/{subreddit}"
|
|
340
|
+
logger.error(error_msg)
|
|
341
|
+
return error_msg
|
|
342
|
+
|
|
343
|
+
# Create the reply
|
|
344
|
+
log_debug(f"Attempting to post reply with content length: {len(content)}")
|
|
345
|
+
reply = submission.reply(body=content)
|
|
346
|
+
|
|
347
|
+
# Prepare the response information
|
|
348
|
+
reply_info: Dict[str, Union[str, int, float]] = {
|
|
349
|
+
"id": reply.id,
|
|
350
|
+
"body": reply.body,
|
|
351
|
+
"score": reply.score,
|
|
352
|
+
"permalink": reply.permalink,
|
|
353
|
+
"created_utc": reply.created_utc,
|
|
354
|
+
"author": str(reply.author),
|
|
355
|
+
"parent_id": reply.parent_id,
|
|
356
|
+
"submission_id": submission.id,
|
|
357
|
+
"subreddit": str(reply.subreddit),
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
log_debug(f"Reply created successfully: {reply.permalink}")
|
|
361
|
+
return json.dumps({"reply": reply_info})
|
|
362
|
+
|
|
363
|
+
except praw.exceptions.RedditAPIException as api_error:
|
|
364
|
+
# Handle specific Reddit API errors
|
|
365
|
+
error_messages = [f"{error.error_type}: {error.message}" for error in api_error.items]
|
|
366
|
+
error_msg = f"Reddit API Error: {'; '.join(error_messages)}"
|
|
367
|
+
logger.error(error_msg)
|
|
368
|
+
return error_msg
|
|
369
|
+
|
|
370
|
+
except Exception as e:
|
|
371
|
+
error_msg = f"Error creating reply: {str(e)}"
|
|
372
|
+
logger.error(error_msg)
|
|
373
|
+
return error_msg
|
|
374
|
+
|
|
375
|
+
def reply_to_comment(self, comment_id: str, content: str, subreddit: Optional[str] = None) -> str:
|
|
376
|
+
"""
|
|
377
|
+
Post a reply to an existing Reddit comment.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
comment_id (str): The ID of the comment to reply to.
|
|
381
|
+
Can be a full URL, permalink, or just the ID.
|
|
382
|
+
content (str): The content of the reply.
|
|
383
|
+
subreddit (Optional[str]): The subreddit name if known.
|
|
384
|
+
This helps with error handling and validation.
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
str: JSON string containing information about the created reply.
|
|
388
|
+
"""
|
|
389
|
+
if not self.reddit:
|
|
390
|
+
logger.error("Reddit instance not initialized")
|
|
391
|
+
return "Please provide Reddit API credentials"
|
|
392
|
+
|
|
393
|
+
if not self._check_user_auth():
|
|
394
|
+
logger.error("User authentication failed")
|
|
395
|
+
return "User authentication required for posting replies. Please provide username and password."
|
|
396
|
+
|
|
397
|
+
try:
|
|
398
|
+
log_debug(f"Creating reply to comment {comment_id}")
|
|
399
|
+
|
|
400
|
+
# Clean up the comment_id if it's a full URL or permalink
|
|
401
|
+
if "/" in comment_id:
|
|
402
|
+
original_id = comment_id
|
|
403
|
+
comment_id = comment_id.split("/")[-1]
|
|
404
|
+
log_info(f"Extracted comment ID {comment_id} from {original_id}")
|
|
405
|
+
|
|
406
|
+
# Get the comment object
|
|
407
|
+
comment = self.reddit.comment(id=comment_id)
|
|
408
|
+
|
|
409
|
+
log_debug(f"Comment details: Author: {comment.author}, Subreddit: {comment.subreddit.display_name}")
|
|
410
|
+
|
|
411
|
+
# If subreddit was provided, verify we're in the right place
|
|
412
|
+
if subreddit and comment.subreddit.display_name.lower() != subreddit.lower():
|
|
413
|
+
error_msg = f"Error: Comment ID belongs to r/{comment.subreddit.display_name}, not r/{subreddit}"
|
|
414
|
+
logger.error(error_msg)
|
|
415
|
+
return error_msg
|
|
416
|
+
|
|
417
|
+
# Create the reply
|
|
418
|
+
log_debug(f"Attempting to post reply with content length: {len(content)}")
|
|
419
|
+
reply = comment.reply(body=content)
|
|
420
|
+
|
|
421
|
+
# Prepare the response information
|
|
422
|
+
reply_info: Dict[str, Union[str, int, float]] = {
|
|
423
|
+
"id": reply.id,
|
|
424
|
+
"body": reply.body,
|
|
425
|
+
"score": reply.score,
|
|
426
|
+
"permalink": reply.permalink,
|
|
427
|
+
"created_utc": reply.created_utc,
|
|
428
|
+
"author": str(reply.author),
|
|
429
|
+
"parent_id": reply.parent_id,
|
|
430
|
+
"submission_id": comment.submission.id,
|
|
431
|
+
"subreddit": str(reply.subreddit),
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
log_debug(f"Reply created successfully: {reply.permalink}")
|
|
435
|
+
return json.dumps({"reply": reply_info})
|
|
436
|
+
|
|
437
|
+
except praw.exceptions.RedditAPIException as api_error:
|
|
438
|
+
# Handle specific Reddit API errors
|
|
439
|
+
error_messages = [f"{error.error_type}: {error.message}" for error in api_error.items]
|
|
440
|
+
error_msg = f"Reddit API Error: {'; '.join(error_messages)}"
|
|
441
|
+
logger.error(error_msg)
|
|
442
|
+
return error_msg
|
|
443
|
+
|
|
444
|
+
except Exception as e:
|
|
445
|
+
error_msg = f"Error creating reply: {str(e)}"
|
|
446
|
+
logger.error(error_msg)
|
|
447
|
+
return error_msg
|
|
448
|
+
|
|
449
|
+
def _check_post_exists(self, post_id: str) -> bool:
|
|
450
|
+
"""
|
|
451
|
+
Verify that a post exists and is accessible.
|
|
452
|
+
|
|
453
|
+
Args:
|
|
454
|
+
post_id (str): The ID of the post to check
|
|
455
|
+
|
|
456
|
+
Returns:
|
|
457
|
+
bool: True if post exists and is accessible, False otherwise
|
|
458
|
+
"""
|
|
459
|
+
try:
|
|
460
|
+
submission = self.reddit.submission(id=post_id)
|
|
461
|
+
# Try to access some attributes to verify the post exists
|
|
462
|
+
_ = submission.title
|
|
463
|
+
_ = submission.author
|
|
464
|
+
return True
|
|
465
|
+
except Exception as e:
|
|
466
|
+
logger.error(f"Error checking post existence: {str(e)}")
|
|
467
|
+
return False
|