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

@@ -255,13 +255,29 @@ class StateModifierNode(Runnable):
255
255
  type_of_output = type(state.get(self.output_variables[0])) if self.output_variables else None
256
256
  # Render the template using Jinja
257
257
  import json
258
+ import base64
258
259
  from jinja2 import Environment
259
260
 
260
261
  def from_json(value):
261
- return json.loads(value)
262
+ """Convert JSON string to Python object"""
263
+ try:
264
+ return json.loads(value)
265
+ except (json.JSONDecodeError, TypeError) as e:
266
+ logger.warning(f"Failed to parse JSON value: {e}")
267
+ return value
268
+
269
+ def base64_to_string(value):
270
+ """Convert base64 encoded string to regular string"""
271
+ try:
272
+ return base64.b64decode(value).decode('utf-8')
273
+ except Exception as e:
274
+ logger.warning(f"Failed to decode base64 value: {e}")
275
+ return value
276
+
262
277
 
263
278
  env = Environment()
264
279
  env.filters['from_json'] = from_json
280
+ env.filters['base64ToString'] = base64_to_string
265
281
 
266
282
  template = env.from_string(self.template)
267
283
  rendered_message = template.render(**input_data)
@@ -307,76 +307,110 @@ class FigmaApiWrapper(NonCodeIndexerToolkit):
307
307
  else:
308
308
  raise ValueError("You must provide at least project_id or file_keys_include.")
309
309
 
310
+ def has_image_representation(self, node):
311
+ node_type = node.get('type', '').lower()
312
+ default_images_types = [
313
+ 'image', 'canvas', 'frame', 'vector', 'table', 'slice', 'sticky', 'shape_with_text', 'connector'
314
+ ]
315
+ # filter nodes of type which has image representation
316
+ # or rectangles with image as background
317
+ if (node_type in default_images_types
318
+ or (node_type == 'rectangle' and 'fills' in node and any(
319
+ fill.get('type') == 'IMAGE' for fill in node['fills'] if isinstance(fill, dict)))):
320
+ return True
321
+ return False
322
+
323
+ def get_texts_recursive(self, node):
324
+ texts = []
325
+ node_type = node.get('type', '').lower()
326
+ if node_type == 'text':
327
+ texts.append(node.get('characters', ''))
328
+ if 'children' in node:
329
+ for child in node['children']:
330
+ texts.extend(self.get_texts_recursive(child))
331
+ return texts
332
+
310
333
  def _process_document(self, document: Document) -> Generator[Document, None, None]:
311
334
  file_key = document.metadata.get('id', '')
312
335
  self._log_tool_event(f"Loading details (images) for `{file_key}`")
313
- #
314
336
  figma_pages = self._client.get_file(file_key).document.get('children', [])
315
337
  node_ids_include = document.metadata.pop('figma_pages_include', [])
316
338
  node_ids_exclude = document.metadata.pop('figma_pages_exclude', [])
317
- node_types_include = [t.lower() for t in document.metadata.pop('figma_nodes_include', [])]
318
- node_types_exclude = [t.lower() for t in document.metadata.pop('figma_nodes_exclude', [])]
339
+ node_types_include = [t.strip().lower() for t in document.metadata.pop('figma_nodes_include', [])]
340
+ node_types_exclude = [t.strip().lower() for t in document.metadata.pop('figma_nodes_exclude', [])]
319
341
  self._log_tool_event(f"Included pages: {node_ids_include}. Excluded pages: {node_ids_exclude}.")
320
342
  if node_ids_include:
321
343
  figma_pages = [node for node in figma_pages if ('id' in node and node['id'].replace(':', '-') in node_ids_include)]
322
344
  elif node_ids_exclude:
323
345
  figma_pages = [node for node in figma_pages if ('id' in node and node['id'].replace(':', '-') not in node_ids_exclude)]
324
346
 
325
- # if node_types_include is not provided, default to 'frame'
326
- # to avoid downloading too many images and nodes which co=annot be rendered as images
327
- if not node_types_include:
328
- node_types_include = ['frame']
329
-
330
- node_ids = [
331
- child['id']
332
- for page in figma_pages
333
- if 'children' in page
334
- for child in page['children']
335
- if 'id' in child
336
- and (
337
- (node_types_include and child.get('type').lower() in node_types_include)
338
- or (node_types_exclude and child.get('type').lower() not in node_types_exclude)
339
- or (not node_types_include and not node_types_exclude)
340
- )
341
- ]
342
-
343
- if not node_ids:
344
- yield from ()
345
- return
346
-
347
- images = self._client.get_file_images(file_key, node_ids).images or {}
348
- total_images = len(images)
349
- if total_images == 0:
350
- logging.info(f"No images found for file {file_key}.")
351
- return
352
- progress_step = max(1, total_images // 10)
353
- for idx, (node_id, image_url) in enumerate(images.items(), 1):
354
- if not image_url:
355
- logging.warning(f"Image URL not found for node_id {node_id} in file {file_key}. Skipping.")
356
- continue
357
- response = requests.get(image_url)
358
- if response.status_code == 200:
359
- content_type = response.headers.get('Content-Type', '')
360
- if 'text/html' not in content_type.lower():
361
- extension = f".{content_type.split('/')[-1]}" if content_type.startswith('image') else '.txt'
362
- page_content = load_content_from_bytes(
363
- file_content=response.content,
364
- extension=extension, llm=self.llm)
347
+ image_nodes = []
348
+ text_nodes = {}
349
+ for page in figma_pages:
350
+ for node in page.get('children', []):
351
+ # filter by node_type if specified any include or exclude
352
+ node_type = node.get('type', '').lower()
353
+ include = node_types_include and node_type in node_types_include
354
+ exclude = node_types_exclude and node_type not in node_types_exclude
355
+ no_filter = not node_types_include and not node_types_exclude
356
+
357
+ if include or exclude or no_filter:
358
+ node_id = node.get('id')
359
+ if node_id:
360
+ if self.has_image_representation(node):
361
+ image_nodes.append(node['id'])
362
+ else:
363
+ text_nodes[node['id']] = self.get_texts_recursive(node)
364
+ # process image nodes
365
+ if image_nodes:
366
+ images = self._client.get_file_images(file_key, image_nodes).images or {}
367
+ total_images = len(images)
368
+ if total_images == 0:
369
+ logging.info(f"No images found for file {file_key}.")
370
+ return
371
+ progress_step = max(1, total_images // 10)
372
+ for idx, (node_id, image_url) in enumerate(images.items(), 1):
373
+ if not image_url:
374
+ logging.warning(f"Image URL not found for node_id {node_id} in file {file_key}. Skipping.")
375
+ continue
376
+ response = requests.get(image_url)
377
+ if response.status_code == 200:
378
+ content_type = response.headers.get('Content-Type', '')
379
+ if 'text/html' not in content_type.lower():
380
+ extension = f".{content_type.split('/')[-1]}" if content_type.startswith('image') else '.txt'
381
+ page_content = load_content_from_bytes(
382
+ file_content=response.content,
383
+ extension=extension, llm=self.llm)
384
+ yield Document(
385
+ page_content=page_content,
386
+ metadata={
387
+ 'id': node_id,
388
+ 'updated_on': document.metadata.get('updated_on', ''),
389
+ 'file_key': file_key,
390
+ 'node_id': node_id,
391
+ 'image_url': image_url,
392
+ 'type': 'image'
393
+ }
394
+ )
395
+ if idx % progress_step == 0 or idx == total_images:
396
+ percent = int((idx / total_images) * 100)
397
+ msg = f"Processed {idx}/{total_images} images ({percent}%) for file {file_key}."
398
+ logging.info(msg)
399
+ self._log_tool_event(msg)
400
+ # process text nodes
401
+ if text_nodes:
402
+ for node_id, texts in text_nodes.items():
403
+ if texts:
365
404
  yield Document(
366
- page_content=page_content,
405
+ page_content="\n".join(texts),
367
406
  metadata={
368
407
  'id': node_id,
369
408
  'updated_on': document.metadata.get('updated_on', ''),
370
409
  'file_key': file_key,
371
410
  'node_id': node_id,
372
- 'image_url': image_url
411
+ 'type': 'text'
373
412
  }
374
413
  )
375
- if idx % progress_step == 0 or idx == total_images:
376
- percent = int((idx / total_images) * 100)
377
- msg = f"Processed {idx}/{total_images} images ({percent}%) for file {file_key}."
378
- logging.info(msg)
379
- self._log_tool_event(msg)
380
414
 
381
415
  def _remove_metadata_keys(self):
382
416
  return super()._remove_metadata_keys() + ['figma_pages_include', 'figma_pages_exclude', 'figma_nodes_include', 'figma_nodes_exclude']
@@ -563,12 +563,14 @@ class JiraApiWrapper(NonCodeIndexerToolkit):
563
563
  Use the appropriate issue link type (e.g., "Test", "Relates", "Blocks").
564
564
  If we use "Test" linktype, the test is inward issue, the story/other issue is outward issue.."""
565
565
 
566
+ comment = "This test is linked to the story."
567
+ comment_body = {"content": [{"content": [{"text": comment,"type": "text"}],"type": "paragraph"}],"type": "doc","version": 1} if self.api_version == "3" else comment
566
568
  link_data = {
567
569
  "type": {"name": f"{linktype}"},
568
570
  "inwardIssue": {"key": f"{inward_issue_key}"},
569
571
  "outwardIssue": {"key": f"{outward_issue_key}"},
570
572
  "comment": {
571
- "body": "This test is linked to the story."
573
+ "body": comment_body
572
574
  }
573
575
  }
574
576
  self._client.create_issue_link(link_data)
@@ -706,6 +708,8 @@ class JiraApiWrapper(NonCodeIndexerToolkit):
706
708
  def add_comments(self, issue_key: str, comment: str):
707
709
  """ Add a comment to a Jira issue."""
708
710
  try:
711
+ if self.api_version == '3':
712
+ comment = {"content": [{"content": [{"text": comment,"type": "text"}],"type": "paragraph"}],"type": "doc","version": 1}
709
713
  self._client.issue_add_comment(issue_key, comment)
710
714
  issue_url = f"{self._client.url}browse/{issue_key}"
711
715
  output = f"Done. Comment is added for issue {issue_key}. You can view it at {issue_url}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alita_sdk
3
- Version: 0.3.327
3
+ Version: 0.3.328
4
4
  Summary: SDK for building langchain agents using resources from Alita
5
5
  Author-email: Artem Rozumenko <artyom.rozumenko@gmail.com>, Mikalai Biazruchka <mikalai_biazruchka@epam.com>, Roman Mitusov <roman_mitusov@epam.com>, Ivan Krakhmaliuk <lifedj27@gmail.com>, Artem Dubrovskiy <ad13box@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -74,8 +74,7 @@ Requires-Dist: paramiko==3.3.1; extra == "tools"
74
74
  Requires-Dist: pygithub==2.3.0; extra == "tools"
75
75
  Requires-Dist: python-gitlab==4.5.0; extra == "tools"
76
76
  Requires-Dist: gitpython==3.1.43; extra == "tools"
77
- Requires-Dist: atlassian-python-api~=3.41; extra == "tools"
78
- Requires-Dist: atlassian_python_api==3.41.16; extra == "tools"
77
+ Requires-Dist: atlassian-python-api~=4.0.7; extra == "tools"
79
78
  Requires-Dist: jira==3.8.0; extra == "tools"
80
79
  Requires-Dist: qtest-swagger-client==0.0.3; extra == "tools"
81
80
  Requires-Dist: testrail-api==1.13.2; extra == "tools"
@@ -44,7 +44,7 @@ alita_sdk/runtime/langchain/assistant.py,sha256=1Eq8BIefp8suhbC9CssoOXtC-plkemoU
44
44
  alita_sdk/runtime/langchain/chat_message_template.py,sha256=kPz8W2BG6IMyITFDA5oeb5BxVRkHEVZhuiGl4MBZKdc,2176
45
45
  alita_sdk/runtime/langchain/constants.py,sha256=eHVJ_beJNTf1WJo4yq7KMK64fxsRvs3lKc34QCXSbpk,3319
46
46
  alita_sdk/runtime/langchain/indexer.py,sha256=0ENHy5EOhThnAiYFc7QAsaTNp9rr8hDV_hTK8ahbatk,37592
47
- alita_sdk/runtime/langchain/langraph_agent.py,sha256=oCUK2f8YdI96AZU0HmETnq78VWUv0weTltCH2q53qEU,46878
47
+ alita_sdk/runtime/langchain/langraph_agent.py,sha256=z_Bontl600nV7ombsomKXtRCuwCJc-5b5P91wapHYo4,47523
48
48
  alita_sdk/runtime/langchain/mixedAgentParser.py,sha256=M256lvtsL3YtYflBCEp-rWKrKtcY1dJIyRGVv7KW9ME,2611
49
49
  alita_sdk/runtime/langchain/mixedAgentRenderes.py,sha256=asBtKqm88QhZRILditjYICwFVKF5KfO38hu2O-WrSWE,5964
50
50
  alita_sdk/runtime/langchain/store_manager.py,sha256=i8Fl11IXJhrBXq1F1ukEVln57B1IBe-tqSUvfUmBV4A,2218
@@ -235,7 +235,7 @@ alita_sdk/tools/custom_open_api/api_wrapper.py,sha256=sDSFpvEqpSvXHGiBISdQQcUecf
235
235
  alita_sdk/tools/elastic/__init__.py,sha256=iwnSRppRpzvJ1da2K3Glu8Uu41MhBDCYbguboLkEbW0,2818
236
236
  alita_sdk/tools/elastic/api_wrapper.py,sha256=pl8CqQxteJAGwyOhMcld-ZgtOTFwwbv42OITQVe8rM0,1948
237
237
  alita_sdk/tools/figma/__init__.py,sha256=W6vIMMkZI2Lmpg6_CRRV3oadaIbVI-qTLmKUh6enqWs,4509
238
- alita_sdk/tools/figma/api_wrapper.py,sha256=SFuvjhxYgey1qGsO9sakFpY1bK1RSzgAH-uJsAp7FnE,27477
238
+ alita_sdk/tools/figma/api_wrapper.py,sha256=-vsIy0Y4UFJBjKumRAOqmgS7pEXVn0UjaNSNN7pFsLs,29351
239
239
  alita_sdk/tools/github/__init__.py,sha256=2rHu0zZyZGnLC5CkHgDIhe14N9yCyaEfrrt7ydH8478,5191
240
240
  alita_sdk/tools/github/api_wrapper.py,sha256=uDwYckdnpYRJtb0uZnDkaz2udvdDLVxuCh1tSwspsiU,8411
241
241
  alita_sdk/tools/github/github_client.py,sha256=nxnSXsDul2PPbWvYZS8TmAFFmR-5ALyakNoV5LN2D4U,86617
@@ -260,7 +260,7 @@ alita_sdk/tools/google/bigquery/tool.py,sha256=Esf9Hsp8I0e7-5EdkFqQ-bid0cfrg-bfS
260
260
  alita_sdk/tools/google_places/__init__.py,sha256=QtmBCI0bHDK79u4hsCSWFcUihu-h4EmPSh9Yll7zz3w,3590
261
261
  alita_sdk/tools/google_places/api_wrapper.py,sha256=7nZly6nk4f4Tm7s2MVdnnwlb-1_WHRrDhyjDiqoyPjA,4674
262
262
  alita_sdk/tools/jira/__init__.py,sha256=G-9qnOYKFWM_adG0QFexh5-2pj_WaxIxxZanB3ARFqI,6339
263
- alita_sdk/tools/jira/api_wrapper.py,sha256=kYd6edldpjaEQNKvJjVaPQt8A22K6f3DMZVJk6Tylsc,80916
263
+ alita_sdk/tools/jira/api_wrapper.py,sha256=-juLuxeOCyDKb_-ZS8eTOeUJWEHKcCiBlXyFY2vbL4Q,81296
264
264
  alita_sdk/tools/keycloak/__init__.py,sha256=0WB9yXMUUAHQRni1ghDEmd7GYa7aJPsTVlZgMCM9cQ0,3050
265
265
  alita_sdk/tools/keycloak/api_wrapper.py,sha256=cOGr0f3S3-c6tRDBWI8wMnetjoNSxiV5rvC_0VHb8uw,3100
266
266
  alita_sdk/tools/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -349,8 +349,8 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
349
349
  alita_sdk/tools/zephyr_squad/__init__.py,sha256=0ne8XLJEQSLOWfzd2HdnqOYmQlUliKHbBED5kW_Vias,2895
350
350
  alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
351
351
  alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
352
- alita_sdk-0.3.327.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
353
- alita_sdk-0.3.327.dist-info/METADATA,sha256=vGd3pwE273hj9w8I4t8YqRph7n5oird_C76aRf_tjNY,18897
354
- alita_sdk-0.3.327.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
355
- alita_sdk-0.3.327.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
356
- alita_sdk-0.3.327.dist-info/RECORD,,
352
+ alita_sdk-0.3.328.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
353
+ alita_sdk-0.3.328.dist-info/METADATA,sha256=jRVOPK8heveuCV9P6VcjO4DE5h6kMdu2TUXKU6VOH7Q,18835
354
+ alita_sdk-0.3.328.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
355
+ alita_sdk-0.3.328.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
356
+ alita_sdk-0.3.328.dist-info/RECORD,,