alita-sdk 0.3.497__py3-none-any.whl → 0.3.515__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.

Potentially problematic release.


This version of alita-sdk might be problematic. Click here for more details.

Files changed (108) hide show
  1. alita_sdk/cli/inventory.py +12 -195
  2. alita_sdk/community/inventory/__init__.py +12 -0
  3. alita_sdk/community/inventory/toolkit.py +9 -5
  4. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  5. alita_sdk/configurations/ado.py +144 -0
  6. alita_sdk/configurations/confluence.py +76 -42
  7. alita_sdk/configurations/figma.py +76 -0
  8. alita_sdk/configurations/gitlab.py +2 -0
  9. alita_sdk/configurations/qtest.py +72 -1
  10. alita_sdk/configurations/report_portal.py +96 -0
  11. alita_sdk/configurations/sharepoint.py +148 -0
  12. alita_sdk/configurations/testio.py +83 -0
  13. alita_sdk/runtime/clients/artifact.py +2 -2
  14. alita_sdk/runtime/clients/client.py +24 -19
  15. alita_sdk/runtime/clients/sandbox_client.py +14 -0
  16. alita_sdk/runtime/langchain/assistant.py +48 -2
  17. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  18. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +2 -1
  19. alita_sdk/runtime/langchain/document_loaders/constants.py +2 -1
  20. alita_sdk/runtime/langchain/langraph_agent.py +8 -9
  21. alita_sdk/runtime/langchain/utils.py +6 -1
  22. alita_sdk/runtime/toolkits/artifact.py +14 -5
  23. alita_sdk/runtime/toolkits/datasource.py +13 -6
  24. alita_sdk/runtime/toolkits/mcp.py +26 -157
  25. alita_sdk/runtime/toolkits/planning.py +10 -5
  26. alita_sdk/runtime/toolkits/tools.py +23 -7
  27. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  28. alita_sdk/runtime/tools/artifact.py +139 -6
  29. alita_sdk/runtime/tools/llm.py +20 -10
  30. alita_sdk/runtime/tools/mcp_remote_tool.py +2 -3
  31. alita_sdk/runtime/tools/mcp_server_tool.py +2 -4
  32. alita_sdk/runtime/utils/AlitaCallback.py +30 -1
  33. alita_sdk/runtime/utils/mcp_client.py +33 -6
  34. alita_sdk/runtime/utils/mcp_oauth.py +125 -8
  35. alita_sdk/runtime/utils/mcp_sse_client.py +35 -6
  36. alita_sdk/runtime/utils/utils.py +2 -0
  37. alita_sdk/tools/__init__.py +15 -0
  38. alita_sdk/tools/ado/repos/__init__.py +10 -12
  39. alita_sdk/tools/ado/test_plan/__init__.py +23 -8
  40. alita_sdk/tools/ado/wiki/__init__.py +24 -8
  41. alita_sdk/tools/ado/wiki/ado_wrapper.py +21 -7
  42. alita_sdk/tools/ado/work_item/__init__.py +24 -8
  43. alita_sdk/tools/advanced_jira_mining/__init__.py +10 -8
  44. alita_sdk/tools/aws/delta_lake/__init__.py +12 -9
  45. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  46. alita_sdk/tools/azure_ai/search/__init__.py +9 -7
  47. alita_sdk/tools/base/tool.py +5 -1
  48. alita_sdk/tools/base_indexer_toolkit.py +25 -0
  49. alita_sdk/tools/bitbucket/__init__.py +14 -10
  50. alita_sdk/tools/bitbucket/api_wrapper.py +50 -2
  51. alita_sdk/tools/browser/__init__.py +5 -4
  52. alita_sdk/tools/carrier/__init__.py +5 -6
  53. alita_sdk/tools/cloud/aws/__init__.py +9 -7
  54. alita_sdk/tools/cloud/azure/__init__.py +9 -7
  55. alita_sdk/tools/cloud/gcp/__init__.py +9 -7
  56. alita_sdk/tools/cloud/k8s/__init__.py +9 -7
  57. alita_sdk/tools/code/linter/__init__.py +9 -8
  58. alita_sdk/tools/code/sonar/__init__.py +9 -7
  59. alita_sdk/tools/confluence/__init__.py +15 -10
  60. alita_sdk/tools/custom_open_api/__init__.py +11 -5
  61. alita_sdk/tools/elastic/__init__.py +10 -8
  62. alita_sdk/tools/elitea_base.py +387 -9
  63. alita_sdk/tools/figma/__init__.py +8 -7
  64. alita_sdk/tools/github/__init__.py +12 -14
  65. alita_sdk/tools/github/github_client.py +68 -2
  66. alita_sdk/tools/github/tool.py +5 -1
  67. alita_sdk/tools/gitlab/__init__.py +14 -11
  68. alita_sdk/tools/gitlab/api_wrapper.py +81 -1
  69. alita_sdk/tools/gitlab_org/__init__.py +9 -8
  70. alita_sdk/tools/google/bigquery/__init__.py +12 -12
  71. alita_sdk/tools/google/bigquery/tool.py +5 -1
  72. alita_sdk/tools/google_places/__init__.py +9 -8
  73. alita_sdk/tools/jira/__init__.py +15 -10
  74. alita_sdk/tools/keycloak/__init__.py +10 -8
  75. alita_sdk/tools/localgit/__init__.py +8 -3
  76. alita_sdk/tools/localgit/local_git.py +62 -54
  77. alita_sdk/tools/localgit/tool.py +5 -1
  78. alita_sdk/tools/memory/__init__.py +11 -3
  79. alita_sdk/tools/ocr/__init__.py +10 -8
  80. alita_sdk/tools/openapi/__init__.py +6 -2
  81. alita_sdk/tools/pandas/__init__.py +9 -7
  82. alita_sdk/tools/postman/__init__.py +10 -11
  83. alita_sdk/tools/pptx/__init__.py +9 -9
  84. alita_sdk/tools/qtest/__init__.py +9 -8
  85. alita_sdk/tools/rally/__init__.py +9 -8
  86. alita_sdk/tools/report_portal/__init__.py +11 -9
  87. alita_sdk/tools/salesforce/__init__.py +9 -9
  88. alita_sdk/tools/servicenow/__init__.py +10 -8
  89. alita_sdk/tools/sharepoint/__init__.py +9 -8
  90. alita_sdk/tools/slack/__init__.py +8 -7
  91. alita_sdk/tools/sql/__init__.py +9 -8
  92. alita_sdk/tools/testio/__init__.py +9 -8
  93. alita_sdk/tools/testrail/__init__.py +10 -8
  94. alita_sdk/tools/utils/__init__.py +9 -4
  95. alita_sdk/tools/utils/text_operations.py +254 -0
  96. alita_sdk/tools/xray/__init__.py +10 -8
  97. alita_sdk/tools/yagmail/__init__.py +8 -3
  98. alita_sdk/tools/zephyr/__init__.py +8 -7
  99. alita_sdk/tools/zephyr_enterprise/__init__.py +10 -8
  100. alita_sdk/tools/zephyr_essential/__init__.py +9 -8
  101. alita_sdk/tools/zephyr_scale/__init__.py +9 -8
  102. alita_sdk/tools/zephyr_squad/__init__.py +9 -8
  103. {alita_sdk-0.3.497.dist-info → alita_sdk-0.3.515.dist-info}/METADATA +1 -1
  104. {alita_sdk-0.3.497.dist-info → alita_sdk-0.3.515.dist-info}/RECORD +108 -105
  105. {alita_sdk-0.3.497.dist-info → alita_sdk-0.3.515.dist-info}/WHEEL +0 -0
  106. {alita_sdk-0.3.497.dist-info → alita_sdk-0.3.515.dist-info}/entry_points.txt +0 -0
  107. {alita_sdk-0.3.497.dist-info → alita_sdk-0.3.515.dist-info}/licenses/LICENSE +0 -0
  108. {alita_sdk-0.3.497.dist-info → alita_sdk-0.3.515.dist-info}/top_level.txt +0 -0
@@ -29,6 +29,10 @@ class GitHubAction(BaseTool):
29
29
  ) -> str:
30
30
  """Use the GitHub API to run an operation."""
31
31
  try:
32
- return self.api_wrapper.run(self.mode, *args, **kwargs)
32
+ # Strip numeric suffix added for deduplication (_2, _3, etc.)
33
+ # to get the original tool name that exists in the wrapper
34
+ import re
35
+ mode = re.sub(r'_\d+$', '', self.mode) if self.mode else self.mode
36
+ return self.api_wrapper.run(mode, *args, **kwargs)
33
37
  except Exception as e:
34
38
  return f"Error: {format_exc()}"
@@ -8,14 +8,14 @@ from pydantic.fields import Field
8
8
 
9
9
  from .api_wrapper import GitLabAPIWrapper
10
10
  from ..elitea_base import filter_missconfigured_index_tools
11
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
11
+ from ..utils import clean_string, get_max_toolkit_length
12
12
  from ...configurations.gitlab import GitlabConfiguration
13
13
  from ...configurations.pgvector import PgVectorConfiguration
14
14
 
15
15
  name = "gitlab"
16
16
 
17
17
 
18
- def get_tools(tool):
18
+ def get_toolkit(tool):
19
19
  return AlitaGitlabToolkit().get_toolkit(
20
20
  selected_tools=tool['settings'].get('selected_tools', []),
21
21
  repository=tool['settings']['repository'],
@@ -30,17 +30,18 @@ def get_tools(tool):
30
30
  embedding_model=tool['settings'].get('embedding_model'),
31
31
  vectorstore_type="PGVector",
32
32
  toolkit_name=tool.get('toolkit_name')
33
- ).get_tools()
33
+ )
34
+
35
+ def get_tools(tool):
36
+ return get_toolkit(tool).get_tools()
34
37
 
35
38
  class AlitaGitlabToolkit(BaseToolkit):
36
39
  tools: List[BaseTool] = []
37
- toolkit_max_length: int = 0
38
40
 
39
41
  @staticmethod
40
42
  def toolkit_config_schema() -> BaseModel:
41
43
  selected_tools = {x['name']: x['args_schema'].schema() for x in
42
44
  GitLabAPIWrapper.model_construct().get_available_tools()}
43
- AlitaGitlabToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
44
45
  return create_model(
45
46
  name,
46
47
  repository=(str, Field(description="GitLab repository")),
@@ -57,7 +58,6 @@ class AlitaGitlabToolkit(BaseToolkit):
57
58
  'metadata': {
58
59
  "label": "GitLab",
59
60
  "icon_url": None,
60
- "max_length": AlitaGitlabToolkit.toolkit_max_length,
61
61
  "categories": ["code repositories"],
62
62
  "extra_categories": ["gitlab", "git", "repository", "code", "version control"],
63
63
  }
@@ -77,19 +77,22 @@ class AlitaGitlabToolkit(BaseToolkit):
77
77
  **(kwargs.get('embedding_configuration') or {}),
78
78
  }
79
79
  gitlab_api_wrapper = GitLabAPIWrapper(**wrapper_payload)
80
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
81
80
  available_tools: List[Dict] = gitlab_api_wrapper.get_available_tools()
82
81
  tools = []
83
82
  for tool in available_tools:
84
83
  if selected_tools:
85
84
  if tool["name"] not in selected_tools:
86
85
  continue
87
-
86
+ description = tool["description"] + f"\nrepo: {gitlab_api_wrapper.repository}"
87
+ if toolkit_name:
88
+ description = f"{description}\nToolkit: {toolkit_name}"
89
+ description = description[:1000]
88
90
  tools.append(BaseAction(
89
91
  api_wrapper=gitlab_api_wrapper,
90
- name=prefix + tool["name"],
91
- description=tool["description"] + f"\nrepo: {gitlab_api_wrapper.repository}",
92
- args_schema=tool["args_schema"]
92
+ name=tool["name"],
93
+ description=description,
94
+ args_schema=tool["args_schema"],
95
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
93
96
  ))
94
97
  return cls(tools=tools)
95
98
 
@@ -7,6 +7,7 @@ from pydantic import create_model, Field, model_validator, SecretStr, PrivateAtt
7
7
 
8
8
  from ..code_indexer_toolkit import CodeIndexerToolkit
9
9
  from ..utils.available_tools_decorator import extend_with_parent_available_tools
10
+ from ..elitea_base import extend_with_file_operations, BaseCodeToolApiWrapper
10
11
  from ..utils.content_parser import parse_file_content
11
12
 
12
13
  AppendFileModel = create_model(
@@ -109,6 +110,12 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
109
110
  branch: Optional[str] = 'main'
110
111
  _git: Any = PrivateAttr()
111
112
  _active_branch: Any = PrivateAttr()
113
+
114
+ # Import file operation methods from BaseCodeToolApiWrapper
115
+ read_file_chunk = BaseCodeToolApiWrapper.read_file_chunk
116
+ read_multiple_files = BaseCodeToolApiWrapper.read_multiple_files
117
+ search_file = BaseCodeToolApiWrapper.search_file
118
+ edit_file = BaseCodeToolApiWrapper.edit_file
112
119
 
113
120
  @staticmethod
114
121
  def _sanitize_url(url: str) -> str:
@@ -215,7 +222,19 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
215
222
  except Exception as e:
216
223
  return f"Unable to get commit hash for {file_path} due to error:\n{e}"
217
224
 
218
- def _read_file(self, file_path: str, branch: str):
225
+ def _read_file(self, file_path: str, branch: str, **kwargs):
226
+ """
227
+ Read a file from specified branch with optional partial read support.
228
+
229
+ Parameters:
230
+ file_path: the file path
231
+ branch: the branch to read the file from
232
+ **kwargs: Additional parameters (offset, limit, head, tail) - currently ignored,
233
+ partial read handled client-side by base class methods
234
+
235
+ Returns:
236
+ File content as string
237
+ """
219
238
  return self.read_file(file_path, branch)
220
239
 
221
240
  def create_branch(self, branch_name: str) -> str:
@@ -325,6 +344,66 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
325
344
  return parse_file_content(file_name=file_path,
326
345
  file_content=file.decode(),
327
346
  llm=self.llm)
347
+
348
+ def _write_file(
349
+ self,
350
+ file_path: str,
351
+ content: str,
352
+ branch: str = None,
353
+ commit_message: str = None
354
+ ) -> str:
355
+ """
356
+ Write content to a file (create or update).
357
+
358
+ Parameters:
359
+ file_path: Path to the file
360
+ content: New file content
361
+ branch: Branch name (uses active branch if None)
362
+ commit_message: Commit message
363
+
364
+ Returns:
365
+ Success message
366
+ """
367
+ try:
368
+ branch = branch or self._active_branch
369
+
370
+ if branch == self.branch:
371
+ raise ToolException(
372
+ f"Cannot commit directly to the {self.branch} branch. "
373
+ "Please create a new branch and try again."
374
+ )
375
+
376
+ self.set_active_branch(branch)
377
+
378
+ # Check if file exists
379
+ try:
380
+ self.repo_instance.files.get(file_path, branch)
381
+ # File exists, update it
382
+ commit = {
383
+ "branch": branch,
384
+ "commit_message": commit_message or f"Update {file_path}",
385
+ "actions": [
386
+ {
387
+ "action": "update",
388
+ "file_path": file_path,
389
+ "content": content,
390
+ }
391
+ ],
392
+ }
393
+ self.repo_instance.commits.create(commit)
394
+ return f"Updated file {file_path}"
395
+ except:
396
+ # File doesn't exist, create it
397
+ data = {
398
+ "branch": branch,
399
+ "commit_message": commit_message or f"Create {file_path}",
400
+ "file_path": file_path,
401
+ "content": content,
402
+ }
403
+ self.repo_instance.files.create(data)
404
+ return f"Created file {file_path}"
405
+ except Exception as e:
406
+ raise ToolException(f"Unable to write file {file_path}: {str(e)}")
328
407
 
329
408
  def update_file(self, file_query: str, branch: str) -> str:
330
409
  if branch == self.branch:
@@ -445,6 +524,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
445
524
  ]
446
525
 
447
526
  @extend_with_parent_available_tools
527
+ @extend_with_file_operations
448
528
  def get_available_tools(self):
449
529
  return [
450
530
  {
@@ -6,7 +6,7 @@ from ..base.tool import BaseAction
6
6
  from pydantic import create_model, BaseModel, ConfigDict, Field, SecretStr
7
7
 
8
8
  from ..elitea_base import filter_missconfigured_index_tools
9
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
9
+ from ..utils import clean_string, get_max_toolkit_length
10
10
  from ...configurations.gitlab import GitlabConfiguration
11
11
 
12
12
  name = "gitlab_org"
@@ -22,12 +22,10 @@ def get_tools(tool):
22
22
 
23
23
  class AlitaGitlabSpaceToolkit(BaseToolkit):
24
24
  tools: List[BaseTool] = []
25
- toolkit_max_length: int = 0
26
25
 
27
26
  @staticmethod
28
27
  def toolkit_config_schema() -> BaseModel:
29
28
  selected_tools = {x['name']: x['args_schema'].schema() for x in GitLabWorkspaceAPIWrapper.model_construct().get_available_tools()}
30
- AlitaGitlabSpaceToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
31
29
  return create_model(
32
30
  name,
33
31
  gitlab_configuration=(GitlabConfiguration, Field(description="GitLab configuration",
@@ -44,7 +42,6 @@ class AlitaGitlabSpaceToolkit(BaseToolkit):
44
42
  'metadata': {
45
43
  "label": "GitLab Org",
46
44
  "icon_url": None,
47
- "max_length": AlitaGitlabSpaceToolkit.toolkit_max_length,
48
45
  "categories": ["code repositories"],
49
46
  "extra_categories": ["gitlab", "git", "repository", "code", "version control"],
50
47
  }
@@ -62,18 +59,22 @@ class AlitaGitlabSpaceToolkit(BaseToolkit):
62
59
  **kwargs['gitlab_configuration'],
63
60
  }
64
61
  gitlab_wrapper = GitLabWorkspaceAPIWrapper(**wrapper_payload)
65
- prefix = clean_string(toolkit_name, AlitaGitlabSpaceToolkit.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
66
62
  available_tools = gitlab_wrapper.get_available_tools()
67
63
  tools = []
68
64
  for tool in available_tools:
69
65
  if selected_tools:
70
66
  if tool["name"] not in selected_tools:
71
67
  continue
68
+ description = tool["description"]
69
+ if toolkit_name:
70
+ description = f"Toolkit: {toolkit_name}\n{description}"
71
+ description = description[:1000]
72
72
  tools.append(BaseAction(
73
73
  api_wrapper=gitlab_wrapper,
74
- name=prefix + tool['name'],
75
- description=tool["description"],
76
- args_schema=tool["args_schema"]
74
+ name=tool['name'],
75
+ description=description,
76
+ args_schema=tool["args_schema"],
77
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
77
78
  ))
78
79
  return cls(tools=tools)
79
80
 
@@ -5,7 +5,7 @@ from langchain_core.tools import BaseTool, BaseToolkit
5
5
  from pydantic import BaseModel, Field, computed_field, field_validator
6
6
 
7
7
  from ....configurations.bigquery import BigQueryConfiguration
8
- from ...utils import TOOLKIT_SPLITTER, clean_string, get_max_toolkit_length
8
+ from ...utils import clean_string, get_max_toolkit_length
9
9
  from .api_wrapper import BigQueryApiWrapper
10
10
  from .tool import BigQueryAction
11
11
 
@@ -22,11 +22,6 @@ def get_available_tools() -> dict[str, dict]:
22
22
  return available_tools
23
23
 
24
24
 
25
- toolkit_max_length = lru_cache(maxsize=1)(
26
- lambda: get_max_toolkit_length(get_available_tools())
27
- )
28
-
29
-
30
25
  class BigQueryToolkitConfig(BaseModel):
31
26
  class Config:
32
27
  title = name
@@ -86,9 +81,10 @@ class BigQueryToolkit(BaseToolkit):
86
81
 
87
82
  @computed_field
88
83
  @property
89
- def tool_prefix(self) -> str:
84
+ def toolkit_context(self) -> str:
85
+ """Returns toolkit context for descriptions (max 1000 chars)."""
90
86
  return (
91
- clean_string(self.toolkit_name, toolkit_max_length()) + TOOLKIT_SPLITTER
87
+ f" [Toolkit: {clean_string(self.toolkit_name, 0)}]"
92
88
  if self.toolkit_name
93
89
  else ""
94
90
  )
@@ -122,14 +118,18 @@ class BigQueryToolkit(BaseToolkit):
122
118
  selected_tools = set(selected_tools)
123
119
  for t in instance.available_tools:
124
120
  if t["name"] in selected_tools:
121
+ description = t["description"]
122
+ if toolkit_name:
123
+ description = f"Toolkit: {toolkit_name}\n{description}"
124
+ description = f"Project: {getattr(instance.api_wrapper, 'project', '')}\n{description}"
125
+ description = description[:1000]
125
126
  instance.tools.append(
126
127
  BigQueryAction(
127
128
  api_wrapper=instance.api_wrapper,
128
- name=instance.tool_prefix + t["name"],
129
- # set unique description for declared tools to differentiate the same methods for different toolkits
130
- description=f"Project: {getattr(instance.api_wrapper, 'project', '')}\n"
131
- + t["description"],
129
+ name=t["name"],
130
+ description=description,
132
131
  args_schema=t["args_schema"],
132
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
133
133
  )
134
134
  )
135
135
  return instance
@@ -29,6 +29,10 @@ class BigQueryAction(BaseTool):
29
29
  ) -> str:
30
30
  """Use the GitHub API to run an operation."""
31
31
  try:
32
- return self.api_wrapper.run(self.mode, *args, **kwargs)
32
+ # Strip numeric suffix added for deduplication (_2, _3, etc.)
33
+ # to get the original tool name that exists in the wrapper
34
+ import re
35
+ mode = re.sub(r'_\d+$', '', self.mode) if self.mode else self.mode
36
+ return self.api_wrapper.run(mode, *args, **kwargs)
33
37
  except Exception as e:
34
38
  return f"Error: {format_exc()}"
@@ -6,7 +6,7 @@ from pydantic.fields import Field
6
6
  from .api_wrapper import GooglePlacesAPIWrapper
7
7
  from ..base.tool import BaseAction
8
8
  from ..elitea_base import filter_missconfigured_index_tools
9
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
9
+ from ..utils import clean_string, get_max_toolkit_length
10
10
  from ...configurations.google_places import GooglePlacesConfiguration
11
11
 
12
12
  name = "google_places"
@@ -22,12 +22,10 @@ def get_tools(tool):
22
22
 
23
23
  class GooglePlacesToolkit(BaseToolkit):
24
24
  tools: list[BaseTool] = []
25
- toolkit_max_length: int = 0
26
25
 
27
26
  @staticmethod
28
27
  def toolkit_config_schema() -> BaseModel:
29
28
  selected_tools = {x['name']: x['args_schema'].schema() for x in GooglePlacesAPIWrapper.model_construct().get_available_tools()}
30
- GooglePlacesToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
31
29
  return create_model(
32
30
  name,
33
31
  results_count=(Optional[int], Field(description="Results number to show", default=None)),
@@ -38,7 +36,6 @@ class GooglePlacesToolkit(BaseToolkit):
38
36
  'metadata':
39
37
  {
40
38
  "label": "Google Places", "icon_url": "gplaces-icon.svg",
41
- "max_length": GooglePlacesToolkit.toolkit_max_length,
42
39
  "categories": ["other"],
43
40
  "extra_categories": ["google", "places", "maps", "location",
44
41
  "geolocation"],
@@ -56,17 +53,21 @@ class GooglePlacesToolkit(BaseToolkit):
56
53
  **kwargs.get('google_places_configuration', {}),
57
54
  }
58
55
  google_places_api_wrapper = GooglePlacesAPIWrapper(**wrapper_payload)
59
- prefix = clean_string(toolkit_name, GooglePlacesToolkit.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
60
56
  available_tools = google_places_api_wrapper.get_available_tools()
61
57
  tools = []
62
58
  for tool in available_tools:
63
59
  if selected_tools and tool["name"] not in selected_tools:
64
60
  continue
61
+ description = tool["description"]
62
+ if toolkit_name:
63
+ description = f"Toolkit: {toolkit_name}\n{description}"
64
+ description = description[:1000]
65
65
  tools.append(BaseAction(
66
66
  api_wrapper=google_places_api_wrapper,
67
- name=prefix + tool["name"],
68
- description=tool["description"],
69
- args_schema=tool["args_schema"]
67
+ name=tool["name"],
68
+ description=description,
69
+ args_schema=tool["args_schema"],
70
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
70
71
  ))
71
72
  return cls(tools=tools)
72
73
 
@@ -6,13 +6,13 @@ from pydantic import create_model, BaseModel, ConfigDict, Field
6
6
  import requests
7
7
 
8
8
  from ..elitea_base import filter_missconfigured_index_tools
9
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length, parse_list, check_connection_response
9
+ from ..utils import clean_string, get_max_toolkit_length, parse_list, check_connection_response
10
10
  from ...configurations.jira import JiraConfiguration
11
11
  from ...configurations.pgvector import PgVectorConfiguration
12
12
 
13
13
  name = "jira"
14
14
 
15
- def get_tools(tool):
15
+ def get_toolkit(tool):
16
16
  return JiraToolkit().get_toolkit(
17
17
  selected_tools=tool['settings'].get('selected_tools', []),
18
18
  base_url=tool['settings'].get('base_url'),
@@ -32,17 +32,18 @@ def get_tools(tool):
32
32
  embedding_model=tool['settings'].get('embedding_model'),
33
33
  vectorstore_type="PGVector",
34
34
  toolkit_name=tool.get('toolkit_name')
35
- ).get_tools()
35
+ )
36
+
37
+ def get_tools(tool):
38
+ return get_toolkit(tool).get_tools()
36
39
 
37
40
 
38
41
  class JiraToolkit(BaseToolkit):
39
42
  tools: List[BaseTool] = []
40
- toolkit_max_length: int = 0
41
43
 
42
44
  @staticmethod
43
45
  def toolkit_config_schema() -> BaseModel:
44
46
  selected_tools = {x['name']: x['args_schema'].schema() for x in JiraApiWrapper.model_construct().get_available_tools()}
45
- JiraToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
46
47
 
47
48
  @check_connection_response
48
49
  def check_connection(self):
@@ -89,7 +90,6 @@ class JiraToolkit(BaseToolkit):
89
90
  'metadata': {
90
91
  "label": "Jira",
91
92
  "icon_url": "jira-icon.svg",
92
- "max_length": JiraToolkit.toolkit_max_length,
93
93
  "categories": ["project management"],
94
94
  "extra_categories": ["jira", "atlassian", "issue tracking", "project management", "task management"],
95
95
  }
@@ -110,18 +110,23 @@ class JiraToolkit(BaseToolkit):
110
110
  **(kwargs.get('pgvector_configuration') or {}),
111
111
  }
112
112
  jira_api_wrapper = JiraApiWrapper(**wrapper_payload)
113
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
114
113
  available_tools = jira_api_wrapper.get_available_tools()
115
114
  tools = []
116
115
  for tool in available_tools:
117
116
  if selected_tools:
118
117
  if tool["name"] not in selected_tools:
119
118
  continue
119
+ description = tool["description"]
120
+ if toolkit_name:
121
+ description = f"Toolkit: {toolkit_name}\n{description}"
122
+ description = f"Jira instance: {jira_api_wrapper.base_url}\n{description}"
123
+ description = description[:1000]
120
124
  tools.append(BaseAction(
121
125
  api_wrapper=jira_api_wrapper,
122
- name=prefix + tool["name"],
123
- description=f"Tool for Jira: '{jira_api_wrapper.base_url}'\n{tool['description']}",
124
- args_schema=tool["args_schema"]
126
+ name=tool["name"],
127
+ description=description,
128
+ args_schema=tool["args_schema"],
129
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
125
130
  ))
126
131
  return cls(tools=tools)
127
132
 
@@ -5,7 +5,7 @@ from pydantic import BaseModel, ConfigDict, create_model, Field, SecretStr
5
5
 
6
6
  from .api_wrapper import KeycloakApiWrapper
7
7
  from ..base.tool import BaseAction
8
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
8
+ from ..utils import clean_string, get_max_toolkit_length
9
9
 
10
10
  name = "keycloak"
11
11
 
@@ -21,15 +21,13 @@ def get_tools(tool):
21
21
 
22
22
  class KeycloakToolkit(BaseToolkit):
23
23
  tools: list[BaseTool] = []
24
- toolkit_max_length: int = 0
25
24
 
26
25
  @staticmethod
27
26
  def toolkit_config_schema() -> BaseModel:
28
27
  selected_tools = {x['name']: x['args_schema'].schema() for x in KeycloakApiWrapper.model_construct().get_available_tools()}
29
- KeycloakToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
30
28
  return create_model(
31
29
  name,
32
- base_url=(str, Field(default="", title="Server URL", description="Keycloak server URL", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': KeycloakToolkit.toolkit_max_length})),
30
+ base_url=(str, Field(default="", title="Server URL", description="Keycloak server URL", json_schema_extra={'toolkit_name': True})),
33
31
  realm=(str, Field(default="", title="Realm", description="Keycloak realm")),
34
32
  client_id=(str, Field(default="", title="Client ID", description="Keycloak client ID")),
35
33
  client_secret=(SecretStr, Field(default="", title="Client sercet", description="Keycloak client secret", json_schema_extra={'secret': True})),
@@ -42,17 +40,21 @@ class KeycloakToolkit(BaseToolkit):
42
40
  if selected_tools is None:
43
41
  selected_tools = []
44
42
  keycloak_api_wrapper = KeycloakApiWrapper(**kwargs)
45
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
46
43
  available_tools = keycloak_api_wrapper.get_available_tools()
47
44
  tools = []
48
45
  for tool in available_tools:
49
46
  if selected_tools and tool["name"] not in selected_tools:
50
47
  continue
48
+ description = f"{tool['description']}\nUrl: {keycloak_api_wrapper.base_url}"
49
+ if toolkit_name:
50
+ description = f"{description}\nToolkit: {toolkit_name}"
51
+ description = description[:1000]
51
52
  tools.append(BaseAction(
52
53
  api_wrapper=keycloak_api_wrapper,
53
- name=prefix + tool["name"],
54
- description=f"{tool['description']}\nUrl: {keycloak_api_wrapper.base_url}",
55
- args_schema=tool["args_schema"]
54
+ name=tool["name"],
55
+ description=description,
56
+ args_schema=tool["args_schema"],
57
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
56
58
  ))
57
59
  return cls(tools=tools)
58
60
 
@@ -34,7 +34,7 @@ class AlitaLocalGitToolkit(BaseToolkit):
34
34
  )
35
35
 
36
36
  @classmethod
37
- def get_toolkit(cls, selected_tools: list[str] | None = None, **kwargs):
37
+ def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
38
38
  if selected_tools is None:
39
39
  selected_tools = []
40
40
  local_git_tool = LocalGit(**kwargs)
@@ -45,12 +45,17 @@ class AlitaLocalGitToolkit(BaseToolkit):
45
45
  if selected_tools:
46
46
  if tool["name"] not in selected_tools:
47
47
  continue
48
+ description = tool["description"]
49
+ if toolkit_name:
50
+ description = f"Toolkit: {toolkit_name}\n{description}"
51
+ description = description[:1000]
48
52
  tools.append(LocalGitAction(
49
53
  api_wrapper=local_git_tool,
50
54
  name=repo + "_" + tool["name"],
51
55
  mode=tool["mode"],
52
- description=tool["description"],
53
- args_schema=tool["args_schema"]
56
+ description=description,
57
+ args_schema=tool["args_schema"],
58
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
54
59
  ))
55
60
  return cls(tools=tools)
56
61