agno 2.0.1__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/agent.py +6015 -2823
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -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/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +594 -186
- agno/knowledge/reader/base.py +9 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +2 -8
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +72 -0
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +999 -519
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +103 -31
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +139 -0
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +59 -5
- agno/models/openai/chat.py +69 -29
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +77 -1
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -178
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -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 +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +248 -94
- agno/run/base.py +44 -5
- agno/run/team.py +238 -97
- agno/run/workflow.py +144 -33
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1610
- agno/tools/dalle.py +2 -4
- agno/tools/decorator.py +4 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +14 -7
- agno/tools/eleven_labs.py +23 -25
- agno/tools/exa.py +21 -16
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +250 -30
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- 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 +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/notion.py +204 -0
- agno/tools/parallel.py +314 -0
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +217 -2
- agno/utils/gemini.py +180 -22
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +92 -2
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +124 -133
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +638 -129
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +61 -23
- agno/workflow/workflow.py +2085 -272
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/METADATA +182 -58
- agno-2.3.0.dist-info/RECORD +577 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.1.dist-info/RECORD +0 -515
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/licenses/LICENSE +0 -0
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/tools/workflow.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from textwrap import dedent
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from agno.tools import Toolkit
|
|
8
|
+
from agno.utils.log import log_debug, log_error
|
|
9
|
+
from agno.workflow.workflow import Workflow, WorkflowRunOutput
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RunWorkflowInput(BaseModel):
|
|
13
|
+
input_data: str = Field(..., description="The input data for the workflow.")
|
|
14
|
+
additional_data: Optional[Dict[str, Any]] = Field(default=None, description="The additional data for the workflow.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WorkflowTools(Toolkit):
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
workflow: Workflow,
|
|
21
|
+
enable_run_workflow: bool = True,
|
|
22
|
+
enable_think: bool = False,
|
|
23
|
+
enable_analyze: bool = False,
|
|
24
|
+
all: bool = False,
|
|
25
|
+
instructions: Optional[str] = None,
|
|
26
|
+
add_instructions: bool = True,
|
|
27
|
+
add_few_shot: bool = False,
|
|
28
|
+
few_shot_examples: Optional[str] = None,
|
|
29
|
+
async_mode: bool = False,
|
|
30
|
+
**kwargs,
|
|
31
|
+
):
|
|
32
|
+
# Add instructions for using this toolkit
|
|
33
|
+
if instructions is None:
|
|
34
|
+
self.instructions = self.DEFAULT_INSTRUCTIONS
|
|
35
|
+
if add_few_shot:
|
|
36
|
+
if few_shot_examples is not None:
|
|
37
|
+
self.instructions += "\n" + few_shot_examples
|
|
38
|
+
else:
|
|
39
|
+
self.instructions = instructions
|
|
40
|
+
|
|
41
|
+
# The workflow to execute
|
|
42
|
+
self.workflow: Workflow = workflow
|
|
43
|
+
|
|
44
|
+
super().__init__(
|
|
45
|
+
name="workflow_tools",
|
|
46
|
+
instructions=self.instructions,
|
|
47
|
+
add_instructions=add_instructions,
|
|
48
|
+
auto_register=False,
|
|
49
|
+
**kwargs,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if enable_think or all:
|
|
53
|
+
if async_mode:
|
|
54
|
+
self.register(self.async_think, name="think")
|
|
55
|
+
else:
|
|
56
|
+
self.register(self.think, name="think")
|
|
57
|
+
if enable_run_workflow or all:
|
|
58
|
+
if async_mode:
|
|
59
|
+
self.register(self.async_run_workflow, name="run_workflow")
|
|
60
|
+
else:
|
|
61
|
+
self.register(self.run_workflow, name="run_workflow")
|
|
62
|
+
if enable_analyze or all:
|
|
63
|
+
if async_mode:
|
|
64
|
+
self.register(self.async_analyze, name="analyze")
|
|
65
|
+
else:
|
|
66
|
+
self.register(self.analyze, name="analyze")
|
|
67
|
+
|
|
68
|
+
def think(self, session_state: Dict[str, Any], thought: str) -> str:
|
|
69
|
+
"""Use this tool as a scratchpad to reason about the workflow execution, refine your approach, brainstorm workflow inputs, or revise your plan.
|
|
70
|
+
Call `Think` whenever you need to figure out what to do next, analyze the user's requirements, plan workflow inputs, or decide on execution strategy.
|
|
71
|
+
You should use this tool as frequently as needed.
|
|
72
|
+
Args:
|
|
73
|
+
thought: Your thought process and reasoning about workflow execution.
|
|
74
|
+
"""
|
|
75
|
+
try:
|
|
76
|
+
log_debug(f"Workflow Thought: {thought}")
|
|
77
|
+
|
|
78
|
+
# Add the thought to the session state
|
|
79
|
+
if session_state is None:
|
|
80
|
+
session_state = {}
|
|
81
|
+
if "workflow_thoughts" not in session_state:
|
|
82
|
+
session_state["workflow_thoughts"] = []
|
|
83
|
+
session_state["workflow_thoughts"].append(thought)
|
|
84
|
+
|
|
85
|
+
# Return the full log of thoughts and the new thought
|
|
86
|
+
thoughts = "\n".join([f"- {t}" for t in session_state["workflow_thoughts"]])
|
|
87
|
+
formatted_thoughts = dedent(
|
|
88
|
+
f"""Workflow Thoughts:
|
|
89
|
+
{thoughts}
|
|
90
|
+
"""
|
|
91
|
+
).strip()
|
|
92
|
+
return formatted_thoughts
|
|
93
|
+
except Exception as e:
|
|
94
|
+
log_error(f"Error recording workflow thought: {e}")
|
|
95
|
+
return f"Error recording workflow thought: {e}"
|
|
96
|
+
|
|
97
|
+
async def async_think(self, session_state: Dict[str, Any], thought: str) -> str:
|
|
98
|
+
"""Use this tool as a scratchpad to reason about the workflow execution, refine your approach, brainstorm workflow inputs, or revise your plan.
|
|
99
|
+
Call `Think` whenever you need to figure out what to do next, analyze the user's requirements, plan workflow inputs, or decide on execution strategy.
|
|
100
|
+
You should use this tool as frequently as needed.
|
|
101
|
+
Args:
|
|
102
|
+
thought: Your thought process and reasoning about workflow execution.
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
log_debug(f"Workflow Thought: {thought}")
|
|
106
|
+
|
|
107
|
+
# Add the thought to the session state
|
|
108
|
+
if session_state is None:
|
|
109
|
+
session_state = {}
|
|
110
|
+
if "workflow_thoughts" not in session_state:
|
|
111
|
+
session_state["workflow_thoughts"] = []
|
|
112
|
+
session_state["workflow_thoughts"].append(thought)
|
|
113
|
+
|
|
114
|
+
# Return the full log of thoughts and the new thought
|
|
115
|
+
thoughts = "\n".join([f"- {t}" for t in session_state["workflow_thoughts"]])
|
|
116
|
+
formatted_thoughts = dedent(
|
|
117
|
+
f"""Workflow Thoughts:
|
|
118
|
+
{thoughts}
|
|
119
|
+
"""
|
|
120
|
+
).strip()
|
|
121
|
+
return formatted_thoughts
|
|
122
|
+
except Exception as e:
|
|
123
|
+
log_error(f"Error recording workflow thought: {e}")
|
|
124
|
+
return f"Error recording workflow thought: {e}"
|
|
125
|
+
|
|
126
|
+
def run_workflow(
|
|
127
|
+
self,
|
|
128
|
+
session_state: Dict[str, Any],
|
|
129
|
+
input: RunWorkflowInput,
|
|
130
|
+
) -> str:
|
|
131
|
+
"""Use this tool to execute the workflow with the specified inputs and parameters.
|
|
132
|
+
After thinking through the requirements, use this tool to run the workflow with appropriate inputs.
|
|
133
|
+
Args:
|
|
134
|
+
input_data: The input data for the workflow.
|
|
135
|
+
"""
|
|
136
|
+
try:
|
|
137
|
+
log_debug(f"Running workflow with input: {input.input_data}")
|
|
138
|
+
|
|
139
|
+
user_id = session_state.get("current_user_id")
|
|
140
|
+
session_id = session_state.get("current_session_id")
|
|
141
|
+
|
|
142
|
+
# Execute the workflow
|
|
143
|
+
result: WorkflowRunOutput = self.workflow.run(
|
|
144
|
+
input=input.input_data,
|
|
145
|
+
user_id=user_id,
|
|
146
|
+
session_id=session_id,
|
|
147
|
+
session_state=session_state,
|
|
148
|
+
additional_data=input.additional_data,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if "workflow_results" not in session_state:
|
|
152
|
+
session_state["workflow_results"] = []
|
|
153
|
+
|
|
154
|
+
session_state["workflow_results"].append(result.to_dict())
|
|
155
|
+
|
|
156
|
+
return json.dumps(result.to_dict(), indent=2)
|
|
157
|
+
|
|
158
|
+
except Exception as e:
|
|
159
|
+
log_error(f"Error running workflow: {e}")
|
|
160
|
+
return f"Error running workflow: {e}"
|
|
161
|
+
|
|
162
|
+
async def async_run_workflow(
|
|
163
|
+
self,
|
|
164
|
+
session_state: Dict[str, Any],
|
|
165
|
+
input: RunWorkflowInput,
|
|
166
|
+
) -> str:
|
|
167
|
+
"""Use this tool to execute the workflow with the specified inputs and parameters.
|
|
168
|
+
After thinking through the requirements, use this tool to run the workflow with appropriate inputs.
|
|
169
|
+
Args:
|
|
170
|
+
input_data: The input data for the workflow (use a `str` for a simple input)
|
|
171
|
+
additional_data: The additional data for the workflow. This is a dictionary of key-value pairs that will be passed to the workflow. E.g. {"topic": "food", "style": "Humour"}
|
|
172
|
+
"""
|
|
173
|
+
try:
|
|
174
|
+
log_debug(f"Running workflow with input: {input.input_data}")
|
|
175
|
+
|
|
176
|
+
user_id = session_state.get("current_user_id")
|
|
177
|
+
session_id = session_state.get("current_session_id")
|
|
178
|
+
|
|
179
|
+
# Execute the workflow
|
|
180
|
+
result: WorkflowRunOutput = await self.workflow.arun(
|
|
181
|
+
input=input.input_data,
|
|
182
|
+
user_id=user_id,
|
|
183
|
+
session_id=session_id,
|
|
184
|
+
session_state=session_state,
|
|
185
|
+
additional_data=input.additional_data,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if "workflow_results" not in session_state:
|
|
189
|
+
session_state["workflow_results"] = []
|
|
190
|
+
|
|
191
|
+
session_state["workflow_results"].append(result.to_dict())
|
|
192
|
+
|
|
193
|
+
return json.dumps(result.to_dict(), indent=2)
|
|
194
|
+
|
|
195
|
+
except Exception as e:
|
|
196
|
+
log_error(f"Error running workflow: {e}")
|
|
197
|
+
return f"Error running workflow: {e}"
|
|
198
|
+
|
|
199
|
+
def analyze(self, session_state: Dict[str, Any], analysis: str) -> str:
|
|
200
|
+
"""Use this tool to evaluate whether the workflow execution results are correct and sufficient.
|
|
201
|
+
If not, go back to "Think" or "Run" with refined inputs or parameters.
|
|
202
|
+
Args:
|
|
203
|
+
analysis: Your analysis of the workflow execution results.
|
|
204
|
+
"""
|
|
205
|
+
try:
|
|
206
|
+
log_debug(f"Workflow Analysis: {analysis}")
|
|
207
|
+
|
|
208
|
+
# Add the analysis to the session state
|
|
209
|
+
if session_state is None:
|
|
210
|
+
session_state = {}
|
|
211
|
+
if "workflow_analysis" not in session_state:
|
|
212
|
+
session_state["workflow_analysis"] = []
|
|
213
|
+
session_state["workflow_analysis"].append(analysis)
|
|
214
|
+
|
|
215
|
+
# Return the full log of analysis and the new analysis
|
|
216
|
+
analysis_log = "\n".join([f"- {a}" for a in session_state["workflow_analysis"]])
|
|
217
|
+
formatted_analysis = dedent(
|
|
218
|
+
f"""Workflow Analysis:
|
|
219
|
+
{analysis_log}
|
|
220
|
+
"""
|
|
221
|
+
).strip()
|
|
222
|
+
return formatted_analysis
|
|
223
|
+
except Exception as e:
|
|
224
|
+
log_error(f"Error recording workflow analysis: {e}")
|
|
225
|
+
return f"Error recording workflow analysis: {e}"
|
|
226
|
+
|
|
227
|
+
async def async_analyze(self, session_state: Dict[str, Any], analysis: str) -> str:
|
|
228
|
+
"""Use this tool to evaluate whether the workflow execution results are correct and sufficient.
|
|
229
|
+
If not, go back to "Think" or "Run" with refined inputs or parameters.
|
|
230
|
+
Args:
|
|
231
|
+
analysis: Your analysis of the workflow execution results.
|
|
232
|
+
"""
|
|
233
|
+
try:
|
|
234
|
+
log_debug(f"Workflow Analysis: {analysis}")
|
|
235
|
+
|
|
236
|
+
# Add the analysis to the session state
|
|
237
|
+
if session_state is None:
|
|
238
|
+
session_state = {}
|
|
239
|
+
if "workflow_analysis" not in session_state:
|
|
240
|
+
session_state["workflow_analysis"] = []
|
|
241
|
+
session_state["workflow_analysis"].append(analysis)
|
|
242
|
+
|
|
243
|
+
# Return the full log of analysis and the new analysis
|
|
244
|
+
analysis_log = "\n".join([f"- {a}" for a in session_state["workflow_analysis"]])
|
|
245
|
+
formatted_analysis = dedent(
|
|
246
|
+
f"""Workflow Analysis:
|
|
247
|
+
{analysis_log}
|
|
248
|
+
"""
|
|
249
|
+
).strip()
|
|
250
|
+
return formatted_analysis
|
|
251
|
+
except Exception as e:
|
|
252
|
+
log_error(f"Error recording workflow analysis: {e}")
|
|
253
|
+
return f"Error recording workflow analysis: {e}"
|
|
254
|
+
|
|
255
|
+
DEFAULT_INSTRUCTIONS = dedent("""\
|
|
256
|
+
You have access to the Think, Run Workflow, and Analyze tools that will help you execute workflows and analyze their results. Use these tools as frequently as needed to successfully complete workflow-based tasks.
|
|
257
|
+
## How to use the Think, Run Workflow, and Analyze tools:
|
|
258
|
+
|
|
259
|
+
1. **Think**
|
|
260
|
+
- Purpose: A scratchpad for planning workflow execution, brainstorming inputs, and refining your approach. You never reveal your "Think" content to the user.
|
|
261
|
+
- Usage: Call `think` whenever you need to figure out what workflow inputs to use, analyze requirements, or decide on execution strategy before (or after) you run the workflow.
|
|
262
|
+
2. **Run Workflow**
|
|
263
|
+
- Purpose: Executes the workflow with specified inputs and parameters.
|
|
264
|
+
- Usage: Call `run_workflow` with appropriate input data whenever you want to execute the workflow.
|
|
265
|
+
- For all workflows, start with simple inputs and gradually increase complexity
|
|
266
|
+
3. **Analyze**
|
|
267
|
+
- Purpose: Evaluate whether the workflow execution results are correct and sufficient. If not, go back to "Think" or "Run Workflow" with refined inputs.
|
|
268
|
+
- Usage: Call `analyze` after getting workflow results to verify the quality and correctness of the execution. Consider:
|
|
269
|
+
- Completeness: Did the workflow complete all expected steps?
|
|
270
|
+
- Quality: Are the results accurate and meet the requirements?
|
|
271
|
+
- Errors: Were there any failures or unexpected behaviors?
|
|
272
|
+
**Important Guidelines**:
|
|
273
|
+
- Do not include your internal chain-of-thought in direct user responses.
|
|
274
|
+
- Use "Think" to reason internally. These notes are never exposed to the user.
|
|
275
|
+
- When you provide a final answer to the user, be clear, concise, and based on the workflow results.
|
|
276
|
+
- If workflow execution fails or produces unexpected results, acknowledge limitations and explain what went wrong.
|
|
277
|
+
- Synthesize information from multiple workflow runs if you execute the workflow several times with different inputs.\
|
|
278
|
+
""")
|
agno/tools/yfinance.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from typing import Any, List
|
|
2
|
+
from typing import Any, List, Optional
|
|
3
3
|
|
|
4
4
|
from agno.tools import Toolkit
|
|
5
5
|
from agno.utils.log import log_debug
|
|
@@ -18,6 +18,7 @@ class YFinanceTools(Toolkit):
|
|
|
18
18
|
|
|
19
19
|
def __init__(
|
|
20
20
|
self,
|
|
21
|
+
session: Optional[Any] = None,
|
|
21
22
|
**kwargs,
|
|
22
23
|
):
|
|
23
24
|
tools: List[Any] = [
|
|
@@ -31,7 +32,7 @@ class YFinanceTools(Toolkit):
|
|
|
31
32
|
self.get_technical_indicators,
|
|
32
33
|
self.get_historical_stock_prices,
|
|
33
34
|
]
|
|
34
|
-
|
|
35
|
+
self.session = session
|
|
35
36
|
super().__init__(name="yfinance_tools", tools=tools, **kwargs)
|
|
36
37
|
|
|
37
38
|
def get_current_stock_price(self, symbol: str) -> str:
|
|
@@ -46,7 +47,7 @@ class YFinanceTools(Toolkit):
|
|
|
46
47
|
"""
|
|
47
48
|
try:
|
|
48
49
|
log_debug(f"Fetching current price for {symbol}")
|
|
49
|
-
stock = yf.Ticker(symbol)
|
|
50
|
+
stock = yf.Ticker(symbol, session=self.session)
|
|
50
51
|
# Use "regularMarketPrice" for regular market hours, or "currentPrice" for pre/post market
|
|
51
52
|
current_price = stock.info.get("regularMarketPrice", stock.info.get("currentPrice"))
|
|
52
53
|
return f"{current_price:.4f}" if current_price else f"Could not fetch current price for {symbol}"
|
|
@@ -63,7 +64,7 @@ class YFinanceTools(Toolkit):
|
|
|
63
64
|
str: JSON containing company profile and overview.
|
|
64
65
|
"""
|
|
65
66
|
try:
|
|
66
|
-
company_info_full = yf.Ticker(symbol).info
|
|
67
|
+
company_info_full = yf.Ticker(symbol, session=self.session).info
|
|
67
68
|
if company_info_full is None:
|
|
68
69
|
return f"Could not fetch company info for {symbol}"
|
|
69
70
|
|
|
@@ -120,7 +121,7 @@ class YFinanceTools(Toolkit):
|
|
|
120
121
|
"""
|
|
121
122
|
try:
|
|
122
123
|
log_debug(f"Fetching historical prices for {symbol}")
|
|
123
|
-
stock = yf.Ticker(symbol)
|
|
124
|
+
stock = yf.Ticker(symbol, session=self.session)
|
|
124
125
|
historical_price = stock.history(period=period, interval=interval)
|
|
125
126
|
return historical_price.to_json(orient="index")
|
|
126
127
|
except Exception as e:
|
|
@@ -150,7 +151,7 @@ class YFinanceTools(Toolkit):
|
|
|
150
151
|
"""
|
|
151
152
|
try:
|
|
152
153
|
log_debug(f"Fetching fundamentals for {symbol}")
|
|
153
|
-
stock = yf.Ticker(symbol)
|
|
154
|
+
stock = yf.Ticker(symbol, session=self.session)
|
|
154
155
|
info = stock.info
|
|
155
156
|
fundamentals = {
|
|
156
157
|
"symbol": symbol,
|
|
@@ -181,7 +182,7 @@ class YFinanceTools(Toolkit):
|
|
|
181
182
|
"""
|
|
182
183
|
try:
|
|
183
184
|
log_debug(f"Fetching income statements for {symbol}")
|
|
184
|
-
stock = yf.Ticker(symbol)
|
|
185
|
+
stock = yf.Ticker(symbol, session=self.session)
|
|
185
186
|
financials = stock.financials
|
|
186
187
|
return financials.to_json(orient="index")
|
|
187
188
|
except Exception as e:
|
|
@@ -198,7 +199,7 @@ class YFinanceTools(Toolkit):
|
|
|
198
199
|
"""
|
|
199
200
|
try:
|
|
200
201
|
log_debug(f"Fetching key financial ratios for {symbol}")
|
|
201
|
-
stock = yf.Ticker(symbol)
|
|
202
|
+
stock = yf.Ticker(symbol, session=self.session)
|
|
202
203
|
key_ratios = stock.info
|
|
203
204
|
return json.dumps(key_ratios, indent=2)
|
|
204
205
|
except Exception as e:
|
|
@@ -215,7 +216,7 @@ class YFinanceTools(Toolkit):
|
|
|
215
216
|
"""
|
|
216
217
|
try:
|
|
217
218
|
log_debug(f"Fetching analyst recommendations for {symbol}")
|
|
218
|
-
stock = yf.Ticker(symbol)
|
|
219
|
+
stock = yf.Ticker(symbol, session=self.session)
|
|
219
220
|
recommendations = stock.recommendations
|
|
220
221
|
return recommendations.to_json(orient="index")
|
|
221
222
|
except Exception as e:
|
|
@@ -233,7 +234,7 @@ class YFinanceTools(Toolkit):
|
|
|
233
234
|
"""
|
|
234
235
|
try:
|
|
235
236
|
log_debug(f"Fetching company news for {symbol}")
|
|
236
|
-
news = yf.Ticker(symbol).news
|
|
237
|
+
news = yf.Ticker(symbol, session=self.session).news
|
|
237
238
|
return json.dumps(news[:num_stories], indent=2)
|
|
238
239
|
except Exception as e:
|
|
239
240
|
return f"Error fetching company news for {symbol}: {e}"
|
|
@@ -251,7 +252,7 @@ class YFinanceTools(Toolkit):
|
|
|
251
252
|
"""
|
|
252
253
|
try:
|
|
253
254
|
log_debug(f"Fetching technical indicators for {symbol}")
|
|
254
|
-
indicators = yf.Ticker(symbol).history(period=period)
|
|
255
|
+
indicators = yf.Ticker(symbol, session=self.session).history(period=period)
|
|
255
256
|
return indicators.to_json(orient="index")
|
|
256
257
|
except Exception as e:
|
|
257
258
|
return f"Error fetching technical indicators for {symbol}: {e}"
|