alita-sdk 0.3.532__py3-none-any.whl → 0.3.602__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 (137) hide show
  1. alita_sdk/cli/agent_executor.py +2 -1
  2. alita_sdk/cli/agent_loader.py +34 -4
  3. alita_sdk/cli/agents.py +433 -203
  4. alita_sdk/community/__init__.py +8 -4
  5. alita_sdk/configurations/__init__.py +1 -0
  6. alita_sdk/configurations/openapi.py +323 -0
  7. alita_sdk/runtime/clients/client.py +165 -7
  8. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  9. alita_sdk/runtime/langchain/assistant.py +61 -11
  10. alita_sdk/runtime/langchain/constants.py +419 -171
  11. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +4 -2
  12. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
  13. alita_sdk/runtime/langchain/langraph_agent.py +108 -23
  14. alita_sdk/runtime/langchain/utils.py +76 -14
  15. alita_sdk/runtime/skills/__init__.py +91 -0
  16. alita_sdk/runtime/skills/callbacks.py +498 -0
  17. alita_sdk/runtime/skills/discovery.py +540 -0
  18. alita_sdk/runtime/skills/executor.py +610 -0
  19. alita_sdk/runtime/skills/input_builder.py +371 -0
  20. alita_sdk/runtime/skills/models.py +330 -0
  21. alita_sdk/runtime/skills/registry.py +355 -0
  22. alita_sdk/runtime/skills/skill_runner.py +330 -0
  23. alita_sdk/runtime/toolkits/__init__.py +5 -0
  24. alita_sdk/runtime/toolkits/artifact.py +2 -1
  25. alita_sdk/runtime/toolkits/mcp.py +6 -3
  26. alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
  27. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  28. alita_sdk/runtime/toolkits/tools.py +139 -10
  29. alita_sdk/runtime/toolkits/vectorstore.py +1 -1
  30. alita_sdk/runtime/tools/__init__.py +3 -1
  31. alita_sdk/runtime/tools/artifact.py +15 -0
  32. alita_sdk/runtime/tools/data_analysis.py +183 -0
  33. alita_sdk/runtime/tools/llm.py +260 -73
  34. alita_sdk/runtime/tools/loop.py +3 -1
  35. alita_sdk/runtime/tools/loop_output.py +3 -1
  36. alita_sdk/runtime/tools/mcp_server_tool.py +6 -3
  37. alita_sdk/runtime/tools/router.py +2 -4
  38. alita_sdk/runtime/tools/sandbox.py +9 -6
  39. alita_sdk/runtime/tools/skill_router.py +776 -0
  40. alita_sdk/runtime/tools/tool.py +3 -1
  41. alita_sdk/runtime/tools/vectorstore.py +7 -2
  42. alita_sdk/runtime/tools/vectorstore_base.py +7 -2
  43. alita_sdk/runtime/utils/constants.py +5 -1
  44. alita_sdk/runtime/utils/mcp_client.py +1 -1
  45. alita_sdk/runtime/utils/mcp_sse_client.py +1 -1
  46. alita_sdk/runtime/utils/toolkit_utils.py +2 -0
  47. alita_sdk/tools/__init__.py +44 -2
  48. alita_sdk/tools/ado/repos/__init__.py +26 -8
  49. alita_sdk/tools/ado/repos/repos_wrapper.py +78 -52
  50. alita_sdk/tools/ado/test_plan/__init__.py +3 -2
  51. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
  52. alita_sdk/tools/ado/utils.py +1 -18
  53. alita_sdk/tools/ado/wiki/__init__.py +2 -1
  54. alita_sdk/tools/ado/wiki/ado_wrapper.py +23 -1
  55. alita_sdk/tools/ado/work_item/__init__.py +3 -2
  56. alita_sdk/tools/ado/work_item/ado_wrapper.py +56 -3
  57. alita_sdk/tools/advanced_jira_mining/__init__.py +2 -1
  58. alita_sdk/tools/aws/delta_lake/__init__.py +2 -1
  59. alita_sdk/tools/azure_ai/search/__init__.py +2 -1
  60. alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
  61. alita_sdk/tools/base_indexer_toolkit.py +51 -30
  62. alita_sdk/tools/bitbucket/__init__.py +2 -1
  63. alita_sdk/tools/bitbucket/api_wrapper.py +1 -1
  64. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +3 -3
  65. alita_sdk/tools/browser/__init__.py +1 -1
  66. alita_sdk/tools/carrier/__init__.py +1 -1
  67. alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
  68. alita_sdk/tools/cloud/aws/__init__.py +2 -1
  69. alita_sdk/tools/cloud/azure/__init__.py +2 -1
  70. alita_sdk/tools/cloud/gcp/__init__.py +2 -1
  71. alita_sdk/tools/cloud/k8s/__init__.py +2 -1
  72. alita_sdk/tools/code/linter/__init__.py +2 -1
  73. alita_sdk/tools/code/sonar/__init__.py +2 -1
  74. alita_sdk/tools/code_indexer_toolkit.py +19 -2
  75. alita_sdk/tools/confluence/__init__.py +7 -6
  76. alita_sdk/tools/confluence/api_wrapper.py +7 -8
  77. alita_sdk/tools/confluence/loader.py +4 -2
  78. alita_sdk/tools/custom_open_api/__init__.py +2 -1
  79. alita_sdk/tools/elastic/__init__.py +2 -1
  80. alita_sdk/tools/elitea_base.py +28 -9
  81. alita_sdk/tools/figma/__init__.py +52 -6
  82. alita_sdk/tools/figma/api_wrapper.py +1158 -123
  83. alita_sdk/tools/figma/figma_client.py +73 -0
  84. alita_sdk/tools/figma/toon_tools.py +2748 -0
  85. alita_sdk/tools/github/__init__.py +2 -1
  86. alita_sdk/tools/github/github_client.py +56 -92
  87. alita_sdk/tools/github/schemas.py +4 -4
  88. alita_sdk/tools/gitlab/__init__.py +2 -1
  89. alita_sdk/tools/gitlab/api_wrapper.py +118 -38
  90. alita_sdk/tools/gitlab_org/__init__.py +2 -1
  91. alita_sdk/tools/gitlab_org/api_wrapper.py +60 -62
  92. alita_sdk/tools/google/bigquery/__init__.py +2 -1
  93. alita_sdk/tools/google_places/__init__.py +2 -1
  94. alita_sdk/tools/jira/__init__.py +2 -1
  95. alita_sdk/tools/keycloak/__init__.py +2 -1
  96. alita_sdk/tools/localgit/__init__.py +2 -1
  97. alita_sdk/tools/memory/__init__.py +1 -1
  98. alita_sdk/tools/ocr/__init__.py +2 -1
  99. alita_sdk/tools/openapi/__init__.py +490 -118
  100. alita_sdk/tools/openapi/api_wrapper.py +1368 -0
  101. alita_sdk/tools/openapi/tool.py +20 -0
  102. alita_sdk/tools/pandas/__init__.py +11 -5
  103. alita_sdk/tools/pandas/api_wrapper.py +38 -25
  104. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  105. alita_sdk/tools/postman/__init__.py +2 -1
  106. alita_sdk/tools/pptx/__init__.py +2 -1
  107. alita_sdk/tools/qtest/__init__.py +21 -2
  108. alita_sdk/tools/qtest/api_wrapper.py +430 -13
  109. alita_sdk/tools/rally/__init__.py +2 -1
  110. alita_sdk/tools/rally/api_wrapper.py +1 -1
  111. alita_sdk/tools/report_portal/__init__.py +2 -1
  112. alita_sdk/tools/salesforce/__init__.py +2 -1
  113. alita_sdk/tools/servicenow/__init__.py +11 -10
  114. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  115. alita_sdk/tools/sharepoint/__init__.py +2 -1
  116. alita_sdk/tools/sharepoint/api_wrapper.py +2 -2
  117. alita_sdk/tools/slack/__init__.py +3 -2
  118. alita_sdk/tools/slack/api_wrapper.py +2 -2
  119. alita_sdk/tools/sql/__init__.py +3 -2
  120. alita_sdk/tools/testio/__init__.py +2 -1
  121. alita_sdk/tools/testrail/__init__.py +2 -1
  122. alita_sdk/tools/utils/content_parser.py +77 -3
  123. alita_sdk/tools/utils/text_operations.py +163 -71
  124. alita_sdk/tools/xray/__init__.py +3 -2
  125. alita_sdk/tools/yagmail/__init__.py +2 -1
  126. alita_sdk/tools/zephyr/__init__.py +2 -1
  127. alita_sdk/tools/zephyr_enterprise/__init__.py +2 -1
  128. alita_sdk/tools/zephyr_essential/__init__.py +2 -1
  129. alita_sdk/tools/zephyr_scale/__init__.py +3 -2
  130. alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
  131. alita_sdk/tools/zephyr_squad/__init__.py +2 -1
  132. {alita_sdk-0.3.532.dist-info → alita_sdk-0.3.602.dist-info}/METADATA +7 -6
  133. {alita_sdk-0.3.532.dist-info → alita_sdk-0.3.602.dist-info}/RECORD +137 -119
  134. {alita_sdk-0.3.532.dist-info → alita_sdk-0.3.602.dist-info}/WHEEL +0 -0
  135. {alita_sdk-0.3.532.dist-info → alita_sdk-0.3.602.dist-info}/entry_points.txt +0 -0
  136. {alita_sdk-0.3.532.dist-info → alita_sdk-0.3.602.dist-info}/licenses/LICENSE +0 -0
  137. {alita_sdk-0.3.532.dist-info → alita_sdk-0.3.602.dist-info}/top_level.txt +0 -0
@@ -10,6 +10,7 @@ from ..utils import clean_string, get_max_toolkit_length, parse_list, check_conn
10
10
  from ...configurations.confluence import ConfluenceConfiguration
11
11
  from ...configurations.pgvector import PgVectorConfiguration
12
12
  import requests
13
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
13
14
 
14
15
  name = "confluence"
15
16
 
@@ -70,16 +71,16 @@ class ConfluenceToolkit(BaseToolkit):
70
71
  name,
71
72
  space=(str, Field(description="Space")),
72
73
  cloud=(bool, Field(description="Hosting Option", json_schema_extra={'configuration': True})),
73
- limit=(int, Field(description="Pages limit per request", default=5)),
74
+ limit=(int, Field(description="Pages limit per request", default=5, gt=0)),
74
75
  labels=(Optional[str], Field(
75
76
  description="List of comma separated labels used for labeling of agent's created or updated entities",
76
77
  default=None,
77
78
  examples="alita,elitea;another-label"
78
79
  )),
79
- max_pages=(int, Field(description="Max total pages", default=10)),
80
- number_of_retries=(int, Field(description="Number of retries", default=2)),
81
- min_retry_seconds=(int, Field(description="Min retry, sec", default=10)),
82
- max_retry_seconds=(int, Field(description="Max retry, sec", default=60)),
80
+ max_pages=(int, Field(description="Max total pages", default=10, gt=0)),
81
+ number_of_retries=(int, Field(description="Number of retries", default=2, ge=0)),
82
+ min_retry_seconds=(int, Field(description="Min retry, sec", default=10, ge=0)),
83
+ max_retry_seconds=(int, Field(description="Max retry, sec", default=60, ge=0)),
83
84
  # optional field for custom headers as dictionary
84
85
  custom_headers=(Optional[dict], Field(description="Custom headers for API requests", default={})),
85
86
  confluence_configuration=(ConfluenceConfiguration, Field(description="Confluence Configuration", json_schema_extra={'configuration_types': ['confluence']})),
@@ -131,7 +132,7 @@ class ConfluenceToolkit(BaseToolkit):
131
132
  name=tool["name"],
132
133
  description=description,
133
134
  args_schema=tool["args_schema"],
134
- metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
135
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
135
136
  ))
136
137
  return cls(tools=tools)
137
138
 
@@ -962,6 +962,9 @@ class ConfluenceAPIWrapper(NonCodeIndexerToolkit):
962
962
  created_date = hist.get('createdDate', '') if hist else attachment.get('created', '')
963
963
  last_updated = hist.get('lastUpdated', {}).get('when', '') if hist else ''
964
964
 
965
+ attachment_path = attachment['_links']['download'] if attachment.get(
966
+ '_links', {}).get('download') else ''
967
+ download_url = self.client.url.rstrip('/') + attachment_path
965
968
  metadata = {
966
969
  'name': title,
967
970
  'size': attachment.get('extensions', {}).get('fileSize', None),
@@ -971,14 +974,10 @@ class ConfluenceAPIWrapper(NonCodeIndexerToolkit):
971
974
  'media_type': media_type,
972
975
  'labels': [label['name'] for label in
973
976
  attachment.get('metadata', {}).get('labels', {}).get('results', [])],
974
- 'download_url': self.base_url.rstrip('/') + attachment['_links']['download'] if attachment.get(
975
- '_links', {}).get('download') else None
977
+ 'download_url': download_url
976
978
  }
977
-
978
- download_url = self.base_url.rstrip('/') + attachment['_links']['download']
979
-
980
979
  try:
981
- resp = self.client.request(method="GET", path=download_url[len(self.base_url):], advanced_mode=True)
980
+ resp = self.client.request(method="GET", path=attachment_path, advanced_mode=True)
982
981
  if resp.status_code == 200:
983
982
  content = resp.content
984
983
  else:
@@ -1731,8 +1730,8 @@ class ConfluenceAPIWrapper(NonCodeIndexerToolkit):
1731
1730
  "page_ids": (Optional[List[str]], Field(description="List of page IDs to retrieve.", default=None)),
1732
1731
  "label": (Optional[str], Field(description="Label to filter pages.", default=None)),
1733
1732
  "cql": (Optional[str], Field(description="CQL query to filter pages.", default=None)),
1734
- "limit": (Optional[int], Field(description="Limit the number of results.", default=10)),
1735
- "max_pages": (Optional[int], Field(description="Maximum number of pages to retrieve.", default=1000)),
1733
+ "limit": (Optional[int], Field(description="Limit the number of results.", default=10, gt=0)),
1734
+ "max_pages": (Optional[int], Field(description="Maximum number of pages to retrieve.", default=1000, gt=0)),
1736
1735
  "include_restricted_content": (Optional[bool], Field(description="Include restricted content.", default=False)),
1737
1736
  "include_archived_content": (Optional[bool], Field(description="Include archived content.", default=False)),
1738
1737
  "include_attachments": (Optional[bool], Field(description="Include attachments.", default=False)),
@@ -48,7 +48,8 @@ class AlitaConfluenceLoader(ConfluenceLoader):
48
48
  del kwargs[key]
49
49
  except:
50
50
  pass
51
- self.base_url = kwargs.get('url')
51
+ # utilize adjusted URL from Confluence instance for base_url
52
+ self.base_url = confluence_client.url
52
53
  self.space_key = kwargs.get('space_key')
53
54
  self.page_ids = kwargs.get('page_ids')
54
55
  self.label = kwargs.get('label')
@@ -108,7 +109,8 @@ class AlitaConfluenceLoader(ConfluenceLoader):
108
109
  texts = []
109
110
  for attachment in attachments:
110
111
  media_type = attachment["metadata"]["mediaType"]
111
- absolute_url = self.base_url + attachment["_links"]["download"]
112
+ # utilize adjusted URL from Confluence instance for attachment download URL
113
+ absolute_url = self.confluence.url + attachment["_links"]["download"]
112
114
  title = attachment["title"]
113
115
  try:
114
116
  if media_type == "application/pdf":
@@ -6,6 +6,7 @@ from pydantic import create_model, BaseModel, ConfigDict, Field
6
6
  from .api_wrapper import OpenApiWrapper
7
7
  from ..base.tool import BaseAction
8
8
  from ..utils import clean_string
9
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
9
10
 
10
11
  name = "openapi"
11
12
 
@@ -57,7 +58,7 @@ class OpenApiToolkit(BaseToolkit):
57
58
  name=tool["name"],
58
59
  description=description,
59
60
  args_schema=tool["args_schema"],
60
- metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
61
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
61
62
  ))
62
63
  return cls(tools=tools)
63
64
 
@@ -6,6 +6,7 @@ from pydantic import BaseModel, ConfigDict, create_model, Field, SecretStr
6
6
  from .api_wrapper import ELITEAElasticApiWrapper
7
7
  from ..base.tool import BaseAction
8
8
  from ..utils import clean_string, get_max_toolkit_length
9
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
9
10
 
10
11
  name = "elastic"
11
12
 
@@ -58,7 +59,7 @@ class ElasticToolkit(BaseToolkit):
58
59
  name=tool["name"],
59
60
  description=description,
60
61
  args_schema=tool["args_schema"],
61
- metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
62
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
62
63
  ))
63
64
  return cls(tools=tools)
64
65
 
@@ -842,7 +842,7 @@ class BaseCodeToolApiWrapper(BaseVectorStoreToolApiWrapper):
842
842
  Raises:
843
843
  ToolException: If file is not text-editable or edit fails
844
844
  """
845
- from .utils.text_operations import parse_old_new_markers, is_text_editable
845
+ from .utils.text_operations import parse_old_new_markers, is_text_editable, try_apply_edit
846
846
  from langchain_core.callbacks import dispatch_custom_event
847
847
 
848
848
  # Validate file is text-editable
@@ -863,26 +863,45 @@ class BaseCodeToolApiWrapper(BaseVectorStoreToolApiWrapper):
863
863
  # Read current file content
864
864
  try:
865
865
  current_content = self._read_file(file_path, branch)
866
+ if not isinstance(current_content, str):
867
+ # If current_content is a ToolException or any non-str, raise or return it
868
+ raise current_content if isinstance(current_content, Exception) else ToolException(str(current_content))
866
869
  except Exception as e:
867
870
  raise ToolException(f"Failed to read file {file_path}: {e}")
868
871
 
869
- # Apply all edits
872
+ # Apply all edits (with tolerant fallback)
870
873
  updated_content = current_content
874
+ fallbacks_used = 0
875
+ edits_applied = 0
871
876
  for old_text, new_text in edits:
872
877
  if not old_text.strip():
873
878
  continue
874
879
 
875
- if old_text not in updated_content:
880
+ new_updated, used_fallback = try_apply_edit(
881
+ content=updated_content,
882
+ old_text=old_text,
883
+ new_text=new_text,
884
+ file_path=file_path,
885
+ )
886
+
887
+ if new_updated == updated_content:
888
+ # No change applied for this pair (exact nor fallback)
876
889
  logger.warning(
877
- f"Old content not found in {file_path}. "
878
- f"Looking for: {old_text[:100]}..."
890
+ "Old content not found or could not be safely matched in %s. Snippet: %s...",
891
+ file_path,
892
+ old_text[:100].replace("\n", "\\n"),
879
893
  )
880
894
  continue
881
-
882
- updated_content = updated_content.replace(old_text, new_text)
895
+
896
+ # A replacement was applied
897
+ edits_applied += 1
898
+ if used_fallback:
899
+ fallbacks_used += 1
900
+
901
+ updated_content = new_updated
883
902
 
884
903
  # Check if any changes were made
885
- if current_content == updated_content:
904
+ if current_content == updated_content or edits_applied == 0:
886
905
  return (
887
906
  f"No changes made to {file_path}. "
888
907
  "Old content was not found or is empty. "
@@ -908,7 +927,7 @@ class BaseCodeToolApiWrapper(BaseVectorStoreToolApiWrapper):
908
927
  "tool_name": "edit_file",
909
928
  "toolkit": self.__class__.__name__,
910
929
  "operation_type": "modify",
911
- "edits_applied": len(edits)
930
+ "edits_applied": edits_applied,
912
931
  })
913
932
  except Exception as e:
914
933
  logger.warning(f"Failed to dispatch file_modified event: {e}")
@@ -1,14 +1,20 @@
1
- from typing import List, Literal, Optional
1
+ from typing import Dict, List, Literal, Optional
2
2
 
3
3
  from langchain_core.tools import BaseTool, BaseToolkit
4
4
  from pydantic import BaseModel, ConfigDict, Field, create_model
5
5
 
6
6
  from ..base.tool import BaseAction
7
- from .api_wrapper import FigmaApiWrapper, GLOBAL_LIMIT
7
+ from .api_wrapper import (
8
+ FigmaApiWrapper,
9
+ GLOBAL_LIMIT,
10
+ DEFAULT_FIGMA_IMAGES_PROMPT,
11
+ DEFAULT_FIGMA_SUMMARY_PROMPT,
12
+ DEFAULT_NUMBER_OF_THREADS,
13
+ )
8
14
  from ..elitea_base import filter_missconfigured_index_tools
9
- from ..utils import clean_string, get_max_toolkit_length
10
15
  from ...configurations.figma import FigmaConfiguration
11
16
  from ...configurations.pgvector import PgVectorConfiguration
17
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
12
18
 
13
19
  name = "figma"
14
20
 
@@ -28,7 +34,14 @@ def get_tools(tool):
28
34
  collection_name=str(tool['toolkit_name']),
29
35
  doctype='doc',
30
36
  embedding_model=tool['settings'].get('embedding_model'),
31
- vectorstore_type="PGVector"
37
+ vectorstore_type="PGVector",
38
+ # figma summary/image prompt settings (toolkit-level)
39
+ # TODO disabled until new requirements
40
+ # apply_images_prompt=tool["settings"].get("apply_images_prompt"),
41
+ # images_prompt=tool["settings"].get("images_prompt"),
42
+ # apply_summary_prompt=tool["settings"].get("apply_summary_prompt"),
43
+ # summary_prompt=tool["settings"].get("summary_prompt"),
44
+ # number_of_threads=tool["settings"].get("number_of_threads"),
32
45
  )
33
46
  .get_tools()
34
47
  )
@@ -45,7 +58,40 @@ class FigmaToolkit(BaseToolkit):
45
58
  }
46
59
  return create_model(
47
60
  name,
48
- global_limit=(Optional[int], Field(description="Global limit", default=GLOBAL_LIMIT)),
61
+ # TODO disabled until new requirements
62
+ # apply_images_prompt=(Optional[bool], Field(
63
+ # description="Enable advanced image processing instructions for Figma image nodes.",
64
+ # default=True,
65
+ # )),
66
+ # images_prompt=(Optional[Dict[str, str]], Field(
67
+ # description=(
68
+ # "Instruction for how to analyze image-based nodes "
69
+ # "(screenshots, diagrams, etc.) during Figma file retrieving. "
70
+ # "Must contain a single 'prompt' key with the text."
71
+ # ),
72
+ # default=DEFAULT_FIGMA_IMAGES_PROMPT,
73
+ # )),
74
+ # apply_summary_prompt=(Optional[bool], Field(
75
+ # description="Enable LLM-based summarization over loaded Figma data.",
76
+ # default=True,
77
+ # )),
78
+ # summary_prompt=(Optional[Dict[str, str]], Field(
79
+ # description=(
80
+ # "Instruction for the LLM on how to summarize loaded Figma data. "
81
+ # "Must contain a single 'prompt' key with the text."
82
+ # ),
83
+ # default=DEFAULT_FIGMA_SUMMARY_PROMPT,
84
+ # )),
85
+ number_of_threads=(Optional[int], Field(
86
+ description=(
87
+ "Number of worker threads to use when downloading and processing Figma images. "
88
+ f"Valid values are from 1 to 5. Default is {DEFAULT_NUMBER_OF_THREADS}."
89
+ ),
90
+ default=DEFAULT_NUMBER_OF_THREADS,
91
+ ge=1,
92
+ le=5,
93
+ )),
94
+ global_limit=(Optional[int], Field(description="Global limit", default=GLOBAL_LIMIT, gt=0)),
49
95
  global_regexp=(Optional[str], Field(description="Global regex pattern", default=None)),
50
96
  selected_tools=(
51
97
  List[Literal[tuple(selected_tools)]],
@@ -98,7 +144,7 @@ class FigmaToolkit(BaseToolkit):
98
144
  name=tool["name"],
99
145
  description=description,
100
146
  args_schema=tool["args_schema"],
101
- metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
147
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
102
148
  )
103
149
  )
104
150
  return cls(tools=tools)