agno 1.7.5__py3-none-any.whl → 1.7.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. agno/agent/agent.py +5 -24
  2. agno/app/agui/async_router.py +5 -5
  3. agno/app/agui/sync_router.py +5 -5
  4. agno/app/agui/utils.py +84 -14
  5. agno/app/playground/app.py +3 -2
  6. agno/document/chunking/row.py +39 -0
  7. agno/document/reader/base.py +0 -7
  8. agno/embedder/jina.py +73 -0
  9. agno/embedder/openai.py +5 -1
  10. agno/memory/agent.py +2 -2
  11. agno/memory/team.py +2 -2
  12. agno/models/anthropic/claude.py +9 -1
  13. agno/models/aws/bedrock.py +311 -15
  14. agno/models/google/gemini.py +26 -6
  15. agno/models/litellm/chat.py +38 -7
  16. agno/models/message.py +1 -0
  17. agno/models/openai/chat.py +1 -22
  18. agno/models/openai/responses.py +5 -5
  19. agno/models/portkey/__init__.py +3 -0
  20. agno/models/portkey/portkey.py +88 -0
  21. agno/models/xai/xai.py +54 -0
  22. agno/run/v2/workflow.py +4 -0
  23. agno/storage/mysql.py +2 -0
  24. agno/storage/postgres.py +5 -3
  25. agno/storage/session/v2/workflow.py +29 -5
  26. agno/storage/singlestore.py +4 -1
  27. agno/storage/sqlite.py +0 -1
  28. agno/team/team.py +38 -36
  29. agno/tools/bitbucket.py +292 -0
  30. agno/tools/daytona.py +411 -63
  31. agno/tools/evm.py +123 -0
  32. agno/tools/jina.py +13 -6
  33. agno/tools/linkup.py +54 -0
  34. agno/tools/mcp.py +170 -26
  35. agno/tools/mem0.py +15 -2
  36. agno/tools/models/morph.py +186 -0
  37. agno/tools/postgres.py +186 -168
  38. agno/tools/zep.py +21 -32
  39. agno/utils/log.py +16 -0
  40. agno/utils/models/claude.py +1 -0
  41. agno/utils/string.py +14 -0
  42. agno/vectordb/pgvector/pgvector.py +4 -5
  43. agno/workflow/v2/workflow.py +152 -25
  44. agno/workflow/workflow.py +90 -63
  45. {agno-1.7.5.dist-info → agno-1.7.7.dist-info}/METADATA +20 -3
  46. {agno-1.7.5.dist-info → agno-1.7.7.dist-info}/RECORD +50 -42
  47. {agno-1.7.5.dist-info → agno-1.7.7.dist-info}/WHEEL +0 -0
  48. {agno-1.7.5.dist-info → agno-1.7.7.dist-info}/entry_points.txt +0 -0
  49. {agno-1.7.5.dist-info → agno-1.7.7.dist-info}/licenses/LICENSE +0 -0
  50. {agno-1.7.5.dist-info → agno-1.7.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,292 @@
1
+ import base64
2
+ import json
3
+ import os
4
+ from typing import Any, Dict, Optional, Union
5
+
6
+ import requests
7
+
8
+ from agno.tools import Toolkit
9
+ from agno.utils.log import logger
10
+
11
+
12
+ class BitbucketTools(Toolkit):
13
+ def __init__(
14
+ self,
15
+ server_url: str = "api.bitbucket.org",
16
+ username: Optional[str] = None,
17
+ password: Optional[str] = None,
18
+ token: Optional[str] = None,
19
+ workspace: Optional[str] = None,
20
+ repo_slug: Optional[str] = None,
21
+ api_version: str = "2.0",
22
+ **kwargs,
23
+ ):
24
+ self.username = username or os.getenv("BITBUCKET_USERNAME")
25
+ self.password = password or os.getenv("BITBUCKET_PASSWORD")
26
+ self.token = token or os.getenv("BITBUCKET_TOKEN")
27
+ self.auth_password = self.token or self.password
28
+ self.server_url = server_url or "api.bitbucket.org"
29
+ self.api_version = api_version or "2.0"
30
+ self.base_url = (
31
+ f"https://{self.server_url}/{api_version}"
32
+ if not self.server_url.startswith(("http://", "https://"))
33
+ else f"{self.server_url}/{api_version}"
34
+ )
35
+ self.workspace = workspace
36
+ self.repo_slug = repo_slug
37
+
38
+ if not (self.username and self.auth_password):
39
+ raise ValueError("Username and password or token are required")
40
+
41
+ if not self.workspace:
42
+ raise ValueError("Workspace is required")
43
+ if not self.repo_slug:
44
+ raise ValueError("Repo slug is required")
45
+
46
+ self.headers = {"Accept": "application/json", "Authorization": f"Basic {self._generate_access_token()}"}
47
+
48
+ super().__init__(
49
+ name="bitbucket",
50
+ tools=[
51
+ self.list_repositories,
52
+ self.get_repository_details,
53
+ self.create_repository,
54
+ self.list_repository_commits,
55
+ self.list_all_pull_requests,
56
+ self.get_pull_request_details,
57
+ self.get_pull_request_changes,
58
+ self.list_issues,
59
+ ],
60
+ **kwargs,
61
+ )
62
+
63
+ def _generate_access_token(self) -> str:
64
+ auth_str = f"{self.username}:{self.auth_password}"
65
+ auth_bytes = auth_str.encode("ascii")
66
+ auth_base64 = base64.b64encode(auth_bytes).decode("ascii")
67
+ return auth_base64
68
+
69
+ def _make_request(
70
+ self,
71
+ method: str,
72
+ endpoint: str,
73
+ params: Optional[Dict[str, Any]] = None,
74
+ data: Optional[Dict[str, Any]] = None,
75
+ ) -> Union[str, Dict[str, Any]]:
76
+ url = f"{self.base_url}{endpoint}"
77
+ response = requests.request(method, url, headers=self.headers, json=data, params=params)
78
+ response.raise_for_status()
79
+ encoding_type = response.headers.get("Content-Type", "application/json")
80
+ if encoding_type.startswith("application/json"):
81
+ return response.json() if response.text else {}
82
+ elif encoding_type == "text/plain":
83
+ return response.text
84
+
85
+ logger.warning(f"Unsupported content type: {encoding_type}")
86
+ return {}
87
+
88
+ def list_repositories(self, count: int = 10) -> str:
89
+ """
90
+ Get all repositories in the workspace.
91
+ Args:
92
+ count (int, optional): The number of repositories to retrieve
93
+
94
+ Returns:
95
+ str: A JSON string containing repository list.
96
+ """
97
+ try:
98
+ # Limit count to maximum of 50
99
+ count = min(count, 50)
100
+
101
+ # Use count directly as pagelen for simplicity, max out at 50 per our limit
102
+ pagelen = min(count, 50)
103
+ params = {"page": 1, "pagelen": pagelen}
104
+
105
+ repo = self._make_request("GET", f"/repositories/{self.workspace}", params=params)
106
+
107
+ return json.dumps(repo, indent=2)
108
+ except Exception as e:
109
+ logger.error(f"Error retrieving repository list for workspace {self.workspace}: {str(e)}")
110
+ return json.dumps({"error": str(e)})
111
+
112
+ def get_repository_details(self) -> str:
113
+ """
114
+ Retrieves repository information.
115
+ API Docs: https://developer.atlassian.com/cloud/bitbucket/rest/api-group-repositories/#api-repositories-workspace-repo-slug-get
116
+
117
+ Returns:
118
+ str: A JSON string containing repository information.
119
+ """
120
+ try:
121
+ repo = self._make_request("GET", f"/repositories/{self.workspace}/{self.repo_slug}")
122
+ return json.dumps(repo, indent=2)
123
+ except Exception as e:
124
+ logger.error(f"Error retrieving repository information for {self.repo_slug}: {str(e)}")
125
+ return json.dumps({"error": str(e)})
126
+
127
+ def create_repository(
128
+ self,
129
+ name: str,
130
+ project: Optional[str] = None,
131
+ is_private: bool = False,
132
+ description: Optional[str] = None,
133
+ language: Optional[str] = None,
134
+ has_issues: bool = False,
135
+ has_wiki: bool = False,
136
+ ) -> str:
137
+ """
138
+ Creates a new repository in Bitbucket for the given workspace.
139
+
140
+ Args:
141
+ name (str): The name of the new repository.
142
+ project (str, optional): The key of the project to create the repository in.
143
+ is_private (bool, optional): Whether the repository is private.
144
+ description (str, optional): A short description of the repository.
145
+ language (str, optional): The primary language of the repository
146
+ has_issues (bool, optional): Whether the repository has issues enabled.
147
+ has_wiki (bool, optional): Whether the repository has a wiki enabled.
148
+
149
+ Returns:
150
+ str: A JSON string containing repository information.
151
+ """
152
+ try:
153
+ payload: Dict[str, Any] = {
154
+ "name": name,
155
+ "scm": "git",
156
+ "is_private": is_private,
157
+ "description": description,
158
+ "language": language,
159
+ "has_issues": has_issues,
160
+ "has_wiki": has_wiki,
161
+ }
162
+ if project:
163
+ payload["project"] = {"key": project}
164
+ repo = self._make_request("POST", f"/repositories/{self.workspace}/{self.repo_slug}", data=payload)
165
+ return json.dumps(repo, indent=2)
166
+ except Exception as e:
167
+ logger.error(f"Error creating repository {self.repo_slug} for {self.workspace}: {str(e)}")
168
+ return json.dumps({"error": str(e)})
169
+
170
+ def list_repository_commits(self, count: int = 10) -> str:
171
+ """
172
+ Retrieves all commits in a repository.
173
+
174
+ Args:
175
+ count (int, optional): The number of commits to retrieve. Defaults to 10. Maximum 50.
176
+
177
+ Returns:
178
+ str: A JSON string containing all commits.
179
+ """
180
+ try:
181
+ count = min(count, 50)
182
+ params = {"pagelen": count}
183
+
184
+ commits = self._make_request(
185
+ "GET", f"/repositories/{self.workspace}/{self.repo_slug}/commits", params=params
186
+ )
187
+
188
+ if isinstance(commits, dict) and commits.get("next"):
189
+ collected_commits = commits.get("values", [])
190
+
191
+ while len(collected_commits) < count and isinstance(commits, dict) and commits.get("next"):
192
+ next_url = commits["next"] # type: ignore
193
+ query_param = next_url.split("?")[1] if "?" in next_url else ""
194
+ commits = self._make_request(
195
+ "GET", f"/repositories/{self.workspace}/{self.repo_slug}/commits?{query_param}"
196
+ )
197
+ if isinstance(commits, dict):
198
+ collected_commits.extend(commits.get("values", []))
199
+
200
+ if isinstance(commits, dict):
201
+ commits["values"] = collected_commits[:count]
202
+
203
+ return json.dumps(commits, indent=2)
204
+ except Exception as e:
205
+ logger.error(f"Error retrieving commits for {self.repo_slug}: {str(e)}")
206
+ return json.dumps({"error": str(e)})
207
+
208
+ def list_all_pull_requests(self, state: str = "OPEN") -> str:
209
+ """
210
+ Retrieves all pull requests for a repository.
211
+
212
+ Args:
213
+ state (str, optional): The state of the pull requests to retrieve.
214
+
215
+ Returns:
216
+ str: A JSON string containing all pull requests.
217
+ """
218
+ try:
219
+ if state not in ["OPEN", "MERGED", "DECLINED", "SUPERSEDED"]:
220
+ logger.debug(f"Invalid pull request state: {state}. Defaulting to OPEN")
221
+ state = "OPEN"
222
+
223
+ params = {"state": state}
224
+
225
+ pull_requests = self._make_request(
226
+ "GET", f"/repositories/{self.workspace}/{self.repo_slug}/pullrequests", params=params
227
+ )
228
+
229
+ return json.dumps(pull_requests, indent=2)
230
+ except Exception as e:
231
+ logger.error(f"Error retrieving pull requests for {self.repo_slug}: {str(e)}")
232
+ return json.dumps({"error": str(e)})
233
+
234
+ def get_pull_request_details(self, pull_request_id: int) -> str:
235
+ """
236
+ Retrieves a pull request for a repository.
237
+ Args:
238
+ pull_request_id (int): The ID of the pull request to retrieve.
239
+
240
+ Returns:
241
+ str: A JSON string containing the pull request.
242
+ """
243
+ try:
244
+ pull_request = self._make_request(
245
+ "GET", f"/repositories/{self.workspace}/{self.repo_slug}/pullrequests/{pull_request_id}"
246
+ )
247
+ return json.dumps(pull_request, indent=2)
248
+ except Exception as e:
249
+ logger.error(f"Error retrieving pull requests for {self.repo_slug}: {str(e)}")
250
+ return json.dumps({"error": str(e)})
251
+
252
+ def get_pull_request_changes(self, pull_request_id: int) -> str:
253
+ """
254
+ Retrieves changes for a pull request in a repository.
255
+
256
+ Args:
257
+ pull_request_id (int): The ID of the pull request to retrieve.
258
+
259
+ Returns:
260
+ str: A markdown string containing the pull request diff.
261
+ """
262
+ try:
263
+ diff = self._make_request(
264
+ "GET", f"/repositories/{self.workspace}/{self.repo_slug}/pullrequests/{pull_request_id}/diff"
265
+ )
266
+ if isinstance(diff, dict):
267
+ return json.dumps(diff, indent=2)
268
+ return diff
269
+ except Exception as e:
270
+ logger.error(f"Error retrieving changes for pull request {pull_request_id} in {self.repo_slug}: {str(e)}")
271
+ return json.dumps({"error": str(e)})
272
+
273
+ def list_issues(self, count: int = 10) -> str:
274
+ """
275
+ Retrieves all issues for a repository.
276
+
277
+ Args:
278
+ count (int, optional): The number of issues to retrieve. Defaults to 10. Maximum 50.
279
+
280
+ Returns:
281
+ str: A JSON string containing all issues.
282
+ """
283
+ try:
284
+ count = min(count, 50)
285
+ params = {"pagelen": count}
286
+
287
+ issues = self._make_request("GET", f"/repositories/{self.workspace}/{self.repo_slug}/issues", params=params)
288
+
289
+ return json.dumps(issues, indent=2)
290
+ except Exception as e:
291
+ logger.error(f"Error retrieving issues for {self.repo_slug}: {str(e)}")
292
+ return json.dumps({"error": str(e)})