airia 0.1.20__tar.gz → 0.1.22__tar.gz

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 (82) hide show
  1. {airia-0.1.20 → airia-0.1.22}/PKG-INFO +1 -1
  2. {airia-0.1.20 → airia-0.1.22}/airia/client/_request_handler/base_request_handler.py +0 -4
  3. {airia-0.1.20 → airia-0.1.22}/airia/client/async_client.py +2 -0
  4. airia-0.1.22/airia/client/attachments/__init__.py +4 -0
  5. airia-0.1.22/airia/client/attachments/async_attachments.py +52 -0
  6. airia-0.1.22/airia/client/attachments/base_attachments.py +54 -0
  7. airia-0.1.22/airia/client/attachments/sync_attachments.py +52 -0
  8. {airia-0.1.20 → airia-0.1.22}/airia/client/pipeline_execution/async_pipeline_execution.py +60 -4
  9. {airia-0.1.20 → airia-0.1.22}/airia/client/pipeline_execution/base_pipeline_execution.py +18 -3
  10. {airia-0.1.20 → airia-0.1.22}/airia/client/pipeline_execution/sync_pipeline_execution.py +60 -4
  11. {airia-0.1.20 → airia-0.1.22}/airia/client/pipelines_config/sync_pipelines_config.py +1 -1
  12. {airia-0.1.20 → airia-0.1.22}/airia/client/sync_client.py +2 -0
  13. airia-0.1.22/airia/types/api/__init__.py +1 -0
  14. airia-0.1.22/airia/types/api/attachments/__init__.py +3 -0
  15. airia-0.1.22/airia/types/api/attachments/upload_file.py +17 -0
  16. {airia-0.1.20 → airia-0.1.22}/airia/types/api/pipeline_execution/_pipeline_execution.py +2 -2
  17. {airia-0.1.20 → airia-0.1.22}/airia/types/api/pipelines_config/export_pipeline_definition.py +28 -3
  18. {airia-0.1.20 → airia-0.1.22}/airia.egg-info/PKG-INFO +1 -1
  19. {airia-0.1.20 → airia-0.1.22}/airia.egg-info/SOURCES.txt +6 -0
  20. {airia-0.1.20 → airia-0.1.22}/pyproject.toml +1 -1
  21. airia-0.1.20/airia/types/api/__init__.py +0 -0
  22. {airia-0.1.20 → airia-0.1.22}/LICENSE +0 -0
  23. {airia-0.1.20 → airia-0.1.22}/README.md +0 -0
  24. {airia-0.1.20 → airia-0.1.22}/airia/__init__.py +0 -0
  25. {airia-0.1.20 → airia-0.1.22}/airia/client/__init__.py +0 -0
  26. {airia-0.1.20 → airia-0.1.22}/airia/client/_request_handler/__init__.py +0 -0
  27. {airia-0.1.20 → airia-0.1.22}/airia/client/_request_handler/async_request_handler.py +0 -0
  28. {airia-0.1.20 → airia-0.1.22}/airia/client/_request_handler/sync_request_handler.py +0 -0
  29. {airia-0.1.20 → airia-0.1.22}/airia/client/base_client.py +0 -0
  30. {airia-0.1.20 → airia-0.1.22}/airia/client/conversations/__init__.py +0 -0
  31. {airia-0.1.20 → airia-0.1.22}/airia/client/conversations/async_conversations.py +0 -0
  32. {airia-0.1.20 → airia-0.1.22}/airia/client/conversations/base_conversations.py +0 -0
  33. {airia-0.1.20 → airia-0.1.22}/airia/client/conversations/sync_conversations.py +0 -0
  34. {airia-0.1.20 → airia-0.1.22}/airia/client/data_vector_search/__init__.py +0 -0
  35. {airia-0.1.20 → airia-0.1.22}/airia/client/data_vector_search/async_data_vector_search.py +0 -0
  36. {airia-0.1.20 → airia-0.1.22}/airia/client/data_vector_search/base_data_vector_search.py +0 -0
  37. {airia-0.1.20 → airia-0.1.22}/airia/client/data_vector_search/sync_data_vector_search.py +0 -0
  38. {airia-0.1.20 → airia-0.1.22}/airia/client/deployments/__init__.py +0 -0
  39. {airia-0.1.20 → airia-0.1.22}/airia/client/deployments/async_deployments.py +0 -0
  40. {airia-0.1.20 → airia-0.1.22}/airia/client/deployments/base_deployments.py +0 -0
  41. {airia-0.1.20 → airia-0.1.22}/airia/client/deployments/sync_deployments.py +0 -0
  42. {airia-0.1.20 → airia-0.1.22}/airia/client/pipeline_execution/__init__.py +0 -0
  43. {airia-0.1.20 → airia-0.1.22}/airia/client/pipelines_config/__init__.py +0 -0
  44. {airia-0.1.20 → airia-0.1.22}/airia/client/pipelines_config/async_pipelines_config.py +0 -0
  45. {airia-0.1.20 → airia-0.1.22}/airia/client/pipelines_config/base_pipelines_config.py +0 -0
  46. {airia-0.1.20 → airia-0.1.22}/airia/client/project/__init__.py +0 -0
  47. {airia-0.1.20 → airia-0.1.22}/airia/client/project/async_project.py +0 -0
  48. {airia-0.1.20 → airia-0.1.22}/airia/client/project/base_project.py +0 -0
  49. {airia-0.1.20 → airia-0.1.22}/airia/client/project/sync_project.py +0 -0
  50. {airia-0.1.20 → airia-0.1.22}/airia/client/store/__init__.py +0 -0
  51. {airia-0.1.20 → airia-0.1.22}/airia/client/store/async_store.py +0 -0
  52. {airia-0.1.20 → airia-0.1.22}/airia/client/store/base_store.py +0 -0
  53. {airia-0.1.20 → airia-0.1.22}/airia/client/store/sync_store.py +0 -0
  54. {airia-0.1.20 → airia-0.1.22}/airia/constants.py +0 -0
  55. {airia-0.1.20 → airia-0.1.22}/airia/exceptions.py +0 -0
  56. {airia-0.1.20 → airia-0.1.22}/airia/logs.py +0 -0
  57. {airia-0.1.20 → airia-0.1.22}/airia/types/__init__.py +0 -0
  58. {airia-0.1.20 → airia-0.1.22}/airia/types/_api_version.py +0 -0
  59. {airia-0.1.20 → airia-0.1.22}/airia/types/_request_data.py +0 -0
  60. {airia-0.1.20 → airia-0.1.22}/airia/types/api/conversations/__init__.py +0 -0
  61. {airia-0.1.20 → airia-0.1.22}/airia/types/api/conversations/_conversations.py +0 -0
  62. {airia-0.1.20 → airia-0.1.22}/airia/types/api/data_vector_search/__init__.py +0 -0
  63. {airia-0.1.20 → airia-0.1.22}/airia/types/api/data_vector_search/get_file_chunks.py +0 -0
  64. {airia-0.1.20 → airia-0.1.22}/airia/types/api/deployments/__init__.py +0 -0
  65. {airia-0.1.20 → airia-0.1.22}/airia/types/api/deployments/get_deployment.py +0 -0
  66. {airia-0.1.20 → airia-0.1.22}/airia/types/api/deployments/get_deployments.py +0 -0
  67. {airia-0.1.20 → airia-0.1.22}/airia/types/api/pipeline_execution/__init__.py +0 -0
  68. {airia-0.1.20 → airia-0.1.22}/airia/types/api/pipelines_config/__init__.py +0 -0
  69. {airia-0.1.20 → airia-0.1.22}/airia/types/api/pipelines_config/get_pipeline_config.py +0 -0
  70. {airia-0.1.20 → airia-0.1.22}/airia/types/api/pipelines_config/get_pipelines_config.py +0 -0
  71. {airia-0.1.20 → airia-0.1.22}/airia/types/api/project/__init__.py +0 -0
  72. {airia-0.1.20 → airia-0.1.22}/airia/types/api/project/get_projects.py +0 -0
  73. {airia-0.1.20 → airia-0.1.22}/airia/types/api/store/__init__.py +0 -0
  74. {airia-0.1.20 → airia-0.1.22}/airia/types/api/store/get_file.py +0 -0
  75. {airia-0.1.20 → airia-0.1.22}/airia/types/api/store/get_files.py +0 -0
  76. {airia-0.1.20 → airia-0.1.22}/airia/types/sse/__init__.py +0 -0
  77. {airia-0.1.20 → airia-0.1.22}/airia/types/sse/sse_messages.py +0 -0
  78. {airia-0.1.20 → airia-0.1.22}/airia/utils/sse_parser.py +0 -0
  79. {airia-0.1.20 → airia-0.1.22}/airia.egg-info/dependency_links.txt +0 -0
  80. {airia-0.1.20 → airia-0.1.22}/airia.egg-info/requires.txt +0 -0
  81. {airia-0.1.20 → airia-0.1.22}/airia.egg-info/top_level.txt +0 -0
  82. {airia-0.1.20 → airia-0.1.22}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: airia
3
- Version: 0.1.20
3
+ Version: 0.1.22
4
4
  Summary: Python SDK for Airia API
5
5
  Author-email: Airia LLC <support@airia.com>
6
6
  License: MIT
@@ -82,10 +82,6 @@ class BaseRequestHandler:
82
82
 
83
83
  # Process payload for logging
84
84
  log_payload = payload.copy() if payload is not None else {}
85
- if "images" in log_payload and log_payload["images"] is not None:
86
- log_payload["images"] = f"{len(log_payload['images'])} images"
87
- if "files" in log_payload and log_payload["files"] is not None:
88
- log_payload["files"] = f"{len(log_payload['files'])} files"
89
85
  log_payload = json.dumps(log_payload)
90
86
 
91
87
  self.logger.info(
@@ -9,6 +9,7 @@ from ..constants import (
9
9
  DEFAULT_TIMEOUT,
10
10
  )
11
11
  from ._request_handler import AsyncRequestHandler
12
+ from .attachments import AsyncAttachments
12
13
  from .base_client import AiriaBaseClient
13
14
  from .conversations import AsyncConversations
14
15
  from .data_vector_search import AsyncDataVectorSearch
@@ -59,6 +60,7 @@ class AiriaAsyncClient(AiriaBaseClient):
59
60
  bearer_token=self.bearer_token,
60
61
  log_requests=self.log_requests,
61
62
  )
63
+ self.attachments = AsyncAttachments(self._request_handler)
62
64
  self.pipeline_execution = AsyncPipelineExecution(self._request_handler)
63
65
  self.pipelines_config = AsyncPipelinesConfig(self._request_handler)
64
66
  self.project = AsyncProject(self._request_handler)
@@ -0,0 +1,4 @@
1
+ from .async_attachments import AsyncAttachments
2
+ from .sync_attachments import Attachments
3
+
4
+ __all__ = ["Attachments", "AsyncAttachments"]
@@ -0,0 +1,52 @@
1
+ from typing import Optional
2
+
3
+ from ...types._api_version import ApiVersion
4
+ from ...types.api.attachments import AttachmentResponse
5
+ from .._request_handler import AsyncRequestHandler
6
+ from .base_attachments import BaseAttachments
7
+
8
+
9
+ class AsyncAttachments(BaseAttachments):
10
+ def __init__(self, request_handler: AsyncRequestHandler):
11
+ super().__init__(request_handler)
12
+
13
+ async def upload_file(
14
+ self,
15
+ file_path: str,
16
+ correlation_id: Optional[str] = None,
17
+ ) -> AttachmentResponse:
18
+ """
19
+ Upload a file and get attachment information.
20
+
21
+ Args:
22
+ file_path: Path to the file on disk
23
+ correlation_id: Optional correlation ID for request tracing. If not provided,
24
+ one will be generated automatically.
25
+
26
+ Returns:
27
+ AttachmentResponse: Response containing the attachment ID and URL.
28
+
29
+ Raises:
30
+ AiriaAPIError: If the API request fails with details about the error.
31
+ aiohttp.ClientError: For other request-related errors.
32
+
33
+ Example:
34
+ ```python
35
+ async_client = AiriaAsyncClient(api_key="your_api_key")
36
+
37
+ # Upload a file
38
+ response = await async_client.attachments.upload_file(
39
+ file_path="example.jpg"
40
+ )
41
+ print(f"Uploaded attachment ID: {response.id}")
42
+ print(f"Attachment URL: {response.image_url}")
43
+ ```
44
+ """
45
+ request_data = self._pre_upload_file(
46
+ file_path=file_path,
47
+ correlation_id=correlation_id,
48
+ api_version=ApiVersion.V1.value,
49
+ )
50
+
51
+ resp = await self._request_handler.make_request_multipart("POST", request_data)
52
+ return AttachmentResponse(**resp)
@@ -0,0 +1,54 @@
1
+ import os
2
+ from mimetypes import guess_type
3
+ from typing import Optional, Union
4
+ from urllib.parse import urljoin
5
+
6
+ from ...types._api_version import ApiVersion
7
+ from .._request_handler import AsyncRequestHandler, RequestHandler
8
+
9
+
10
+ class BaseAttachments:
11
+ def __init__(self, request_handler: Union[RequestHandler, AsyncRequestHandler]):
12
+ self._request_handler = request_handler
13
+
14
+ def _pre_upload_file(
15
+ self,
16
+ file_path: str,
17
+ correlation_id: Optional[str] = None,
18
+ api_version: str = ApiVersion.V1.value,
19
+ ):
20
+ """
21
+ Prepare request data for file upload endpoint.
22
+
23
+ This internal method constructs the URL and files for file upload
24
+ requests, validating the API version and preparing all request components.
25
+
26
+ Args:
27
+ file_path: Path to the file on disk
28
+ correlation_id: Optional correlation ID for tracing
29
+ api_version: API version to use for the request
30
+
31
+ Returns:
32
+ RequestData: Prepared request data for the file upload endpoint
33
+
34
+ Raises:
35
+ ValueError: If an invalid API version is provided
36
+ """
37
+ if api_version not in ApiVersion.as_list():
38
+ raise ValueError(
39
+ f"Invalid API version: {api_version}. Valid versions are: {', '.join(ApiVersion.as_list())}"
40
+ )
41
+
42
+ url = urljoin(
43
+ self._request_handler.base_url,
44
+ f"{api_version}/upload",
45
+ )
46
+
47
+ filename = os.path.basename(file_path)
48
+ files = {"file": (filename, open(file_path, "rb"), guess_type(file_path)[0])}
49
+
50
+ request_data = self._request_handler.prepare_request(
51
+ url=url, payload={}, files=files, correlation_id=correlation_id
52
+ )
53
+
54
+ return request_data
@@ -0,0 +1,52 @@
1
+ from typing import Optional
2
+
3
+ from ...types._api_version import ApiVersion
4
+ from ...types.api.attachments import AttachmentResponse
5
+ from .._request_handler import RequestHandler
6
+ from .base_attachments import BaseAttachments
7
+
8
+
9
+ class Attachments(BaseAttachments):
10
+ def __init__(self, request_handler: RequestHandler):
11
+ super().__init__(request_handler)
12
+
13
+ def upload_file(
14
+ self,
15
+ file_path: str,
16
+ correlation_id: Optional[str] = None,
17
+ ) -> AttachmentResponse:
18
+ """
19
+ Upload a file and get attachment information.
20
+
21
+ Args:
22
+ file_path: Path to the file on disk
23
+ correlation_id: Optional correlation ID for request tracing. If not provided,
24
+ one will be generated automatically.
25
+
26
+ Returns:
27
+ AttachmentResponse: Response containing the attachment ID and URL.
28
+
29
+ Raises:
30
+ AiriaAPIError: If the API request fails with details about the error.
31
+ requests.RequestException: For other request-related errors.
32
+
33
+ Example:
34
+ ```python
35
+ client = AiriaClient(api_key="your_api_key")
36
+
37
+ # Upload a file
38
+ response = client.attachments.upload_file(
39
+ file_path="example.jpg"
40
+ )
41
+ print(f"Uploaded attachment ID: {response.id}")
42
+ print(f"Attachment URL: {response.image_url}")
43
+ ```
44
+ """
45
+ request_data = self._pre_upload_file(
46
+ file_path=file_path,
47
+ correlation_id=correlation_id,
48
+ api_version=ApiVersion.V1.value,
49
+ )
50
+
51
+ resp = self._request_handler.make_request_multipart("POST", request_data)
52
+ return AttachmentResponse(**resp)
@@ -14,6 +14,51 @@ class AsyncPipelineExecution(BasePipelineExecution):
14
14
  def __init__(self, request_handler: AsyncRequestHandler):
15
15
  super().__init__(request_handler)
16
16
 
17
+ async def _upload_files(
18
+ self, files: List[str], images: List[str]
19
+ ) -> tuple[List[str], List[str]]:
20
+ """
21
+ Upload files and images synchronously and return their URLs.
22
+ URLs are passed through directly, local paths are uploaded first.
23
+
24
+ Args:
25
+ files: List of file paths or URLs
26
+ images: List of image file paths or URLs
27
+
28
+ Returns:
29
+ Tuple of (file_urls, image_urls)
30
+ """
31
+ from ..attachments.async_attachments import AsyncAttachments
32
+
33
+ attachments_client = AsyncAttachments(self._request_handler)
34
+ file_urls = None
35
+ image_urls = None
36
+
37
+ if files:
38
+ file_urls = []
39
+ for file_path in files:
40
+ if self._is_local_path(file_path):
41
+ # Local file - upload it
42
+ response = await attachments_client.upload_file(file_path)
43
+ file_urls.append(response.image_url)
44
+ else:
45
+ # URL - use directly
46
+ file_urls.append(file_path)
47
+
48
+ if images:
49
+ image_urls = []
50
+ for image_path in images:
51
+ if self._is_local_path(image_path):
52
+ # Local file - upload it
53
+ response = await attachments_client.upload_file(image_path)
54
+ if response.image_url:
55
+ image_urls.append(response.image_url)
56
+ else:
57
+ # URL - use directly
58
+ image_urls.append(image_path)
59
+
60
+ return file_urls, image_urls
61
+
17
62
  @overload
18
63
  async def execute_pipeline(
19
64
  self,
@@ -119,8 +164,8 @@ class AsyncPipelineExecution(BasePipelineExecution):
119
164
  conversation_id: Optional conversation ID (guid).
120
165
  async_output: Whether to stream the response. Default is False.
121
166
  include_tools_response: Whether to return the initial LLM tool result. Default is False.
122
- images: Optional list of images formatted as base64 strings.
123
- files: Optional list of files formatted as base64 strings.
167
+ images: Optional list of image file paths or URLs.
168
+ files: Optional list of file paths or URLs.
124
169
  data_source_folders: Optional data source folders information.
125
170
  data_source_files: Optional data source files information.
126
171
  in_memory_messages: Optional list of in-memory messages, each with a role and message.
@@ -149,6 +194,17 @@ class AsyncPipelineExecution(BasePipelineExecution):
149
194
  print(response.result)
150
195
  ```
151
196
  """
197
+ # Validate user_input parameter
198
+ if not user_input:
199
+ raise ValueError("user_input cannot be empty")
200
+
201
+ # Handle file and image uploads (local files are uploaded, URLs are passed through)
202
+ image_urls = None
203
+ file_urls = None
204
+
205
+ if images or files:
206
+ file_urls, image_urls = await self._upload_files(files or [], images or [])
207
+
152
208
  request_data = self._pre_execute_pipeline(
153
209
  pipeline_id=pipeline_id,
154
210
  user_input=user_input,
@@ -157,8 +213,8 @@ class AsyncPipelineExecution(BasePipelineExecution):
157
213
  conversation_id=conversation_id,
158
214
  async_output=async_output,
159
215
  include_tools_response=include_tools_response,
160
- images=images,
161
- files=files,
216
+ images=image_urls,
217
+ files=file_urls,
162
218
  data_source_folders=data_source_folders,
163
219
  data_source_files=data_source_files,
164
220
  in_memory_messages=in_memory_messages,
@@ -1,5 +1,5 @@
1
1
  from typing import Any, Dict, List, Optional, Union
2
- from urllib.parse import urljoin
2
+ from urllib.parse import urljoin, urlparse
3
3
 
4
4
  from ...types._api_version import ApiVersion
5
5
  from .._request_handler import AsyncRequestHandler, RequestHandler
@@ -9,6 +9,20 @@ class BasePipelineExecution:
9
9
  def __init__(self, request_handler: Union[RequestHandler, AsyncRequestHandler]):
10
10
  self._request_handler = request_handler
11
11
 
12
+ def _is_local_path(self, path: str) -> bool:
13
+ """
14
+ Check if a given path is a local file path or a URL.
15
+
16
+ Args:
17
+ path: The path to check
18
+
19
+ Returns:
20
+ True if it's a local file path, False if it's a URL
21
+ """
22
+ parsed = urlparse(path)
23
+ # If it has a scheme (http, https, ftp, etc.) and a netloc, it's a URL
24
+ return not (parsed.scheme and parsed.netloc)
25
+
12
26
  def _pre_execute_pipeline(
13
27
  self,
14
28
  pipeline_id: str,
@@ -45,8 +59,8 @@ class BasePipelineExecution:
45
59
  conversation_id: Optional conversation identifier
46
60
  async_output: Whether to enable streaming output
47
61
  include_tools_response: Whether to include tool responses
48
- images: Optional list of base64-encoded images
49
- files: Optional list of base64-encoded files
62
+ images: Optional list of image URLs
63
+ files: Optional list of file URLs
50
64
  data_source_folders: Optional data source folder configuration
51
65
  data_source_files: Optional data source files configuration
52
66
  in_memory_messages: Optional list of in-memory messages
@@ -68,6 +82,7 @@ class BasePipelineExecution:
68
82
  raise ValueError(
69
83
  f"Invalid API version: {api_version}. Valid versions are: {', '.join(ApiVersion.as_list())}"
70
84
  )
85
+
71
86
  url = urljoin(
72
87
  self._request_handler.base_url,
73
88
  f"{api_version}/PipelineExecution/{pipeline_id}",
@@ -13,6 +13,51 @@ from .base_pipeline_execution import BasePipelineExecution
13
13
  class PipelineExecution(BasePipelineExecution):
14
14
  def __init__(self, request_handler: RequestHandler):
15
15
  super().__init__(request_handler)
16
+
17
+ def _upload_files(
18
+ self, files: List[str], images: List[str]
19
+ ) -> tuple[List[str], List[str]]:
20
+ """
21
+ Upload files and images synchronously and return their URLs.
22
+ URLs are passed through directly, local paths are uploaded first.
23
+
24
+ Args:
25
+ files: List of file paths or URLs
26
+ images: List of image file paths or URLs
27
+
28
+ Returns:
29
+ Tuple of (file_urls, image_urls)
30
+ """
31
+ from ..attachments.sync_attachments import Attachments
32
+
33
+ attachments_client = Attachments(self._request_handler)
34
+ file_urls = None
35
+ image_urls = None
36
+
37
+ if files:
38
+ file_urls = []
39
+ for file_path in files:
40
+ if self._is_local_path(file_path):
41
+ # Local file - upload it
42
+ response = attachments_client.upload_file(file_path)
43
+ file_urls.append(response.image_url)
44
+ else:
45
+ # URL - use directly
46
+ file_urls.append(file_path)
47
+
48
+ if images:
49
+ image_urls = []
50
+ for image_path in images:
51
+ if self._is_local_path(image_path):
52
+ # Local file - upload it
53
+ response = attachments_client.upload_file(image_path)
54
+ if response.image_url:
55
+ image_urls.append(response.image_url)
56
+ else:
57
+ # URL - use directly
58
+ image_urls.append(image_path)
59
+
60
+ return file_urls, image_urls
16
61
 
17
62
  @overload
18
63
  def execute_pipeline(
@@ -119,8 +164,8 @@ class PipelineExecution(BasePipelineExecution):
119
164
  conversation_id: Optional conversation ID (guid).
120
165
  async_output: Whether to stream the response. Default is False.
121
166
  include_tools_response: Whether to return the initial LLM tool result. Default is False.
122
- images: Optional list of images formatted as base64 strings.
123
- files: Optional list of files formatted as base64 strings.
167
+ images: Optional list of image file paths or URLs.
168
+ files: Optional list of file paths or URLs.
124
169
  data_source_folders: Optional data source folders information.
125
170
  data_source_files: Optional data source files information.
126
171
  in_memory_messages: Optional list of in-memory messages, each with a role and message.
@@ -149,6 +194,17 @@ class PipelineExecution(BasePipelineExecution):
149
194
  print(response.result)
150
195
  ```
151
196
  """
197
+ # Validate user_input parameter
198
+ if not user_input:
199
+ raise ValueError("user_input cannot be empty")
200
+
201
+ # Handle file and image uploads (local files are uploaded, URLs are passed through)
202
+ image_urls = None
203
+ file_urls = None
204
+
205
+ if images or files:
206
+ file_urls, image_urls = self._upload_files(files or [], images or [])
207
+
152
208
  request_data = self._pre_execute_pipeline(
153
209
  pipeline_id=pipeline_id,
154
210
  user_input=user_input,
@@ -157,8 +213,8 @@ class PipelineExecution(BasePipelineExecution):
157
213
  conversation_id=conversation_id,
158
214
  async_output=async_output,
159
215
  include_tools_response=include_tools_response,
160
- images=images,
161
- files=files,
216
+ images=image_urls,
217
+ files=file_urls,
162
218
  data_source_folders=data_source_folders,
163
219
  data_source_files=data_source_files,
164
220
  in_memory_messages=in_memory_messages,
@@ -133,7 +133,7 @@ class PipelinesConfig(BasePipelinesConfig):
133
133
 
134
134
  This method fetches a list of pipeline configurations including their
135
135
  deployment details, execution statistics, version information, and metadata.
136
- The results can be filtered by project ID to retrieve only pipelines
136
+ The results can be filtered by project ID to retrieve only pipelines
137
137
  belonging to a specific project.
138
138
 
139
139
  Args:
@@ -9,6 +9,7 @@ from ..constants import (
9
9
  DEFAULT_TIMEOUT,
10
10
  )
11
11
  from ._request_handler import RequestHandler
12
+ from .attachments import Attachments
12
13
  from .base_client import AiriaBaseClient
13
14
  from .conversations import Conversations
14
15
  from .data_vector_search import DataVectorSearch
@@ -59,6 +60,7 @@ class AiriaClient(AiriaBaseClient):
59
60
  bearer_token=self.bearer_token,
60
61
  log_requests=self.log_requests,
61
62
  )
63
+ self.attachments = Attachments(self._request_handler)
62
64
  self.pipeline_execution = PipelineExecution(self._request_handler)
63
65
  self.pipelines_config = PipelinesConfig(self._request_handler)
64
66
  self.project = Project(self._request_handler)
@@ -0,0 +1 @@
1
+ from . import attachments as attachments
@@ -0,0 +1,3 @@
1
+ from .upload_file import AttachmentResponse
2
+
3
+ __all__ = ["AttachmentResponse"]
@@ -0,0 +1,17 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class AttachmentResponse(BaseModel):
7
+ """Response model for uploading an attachment file.
8
+
9
+ This class conveys the unique identifier and URL of the uploaded attachment.
10
+
11
+ Attributes:
12
+ id: The unique identifier of the attachment
13
+ image_url: The URL of the attachment
14
+ """
15
+
16
+ id: Optional[str] = None
17
+ image_url: Optional[str] = Field(None, alias="imageUrl")
@@ -5,7 +5,7 @@ This module defines the response models returned by pipeline execution endpoints
5
5
  including both synchronous and streaming response types.
6
6
  """
7
7
 
8
- from typing import Any, AsyncIterator, Dict, Iterator
8
+ from typing import Any, AsyncIterator, Dict, Iterator, Optional
9
9
 
10
10
  from pydantic import BaseModel, ConfigDict, Field
11
11
 
@@ -41,7 +41,7 @@ class PipelineExecutionDebugResponse(BaseModel):
41
41
  is_backup_pipeline: Whether a backup pipeline was used for execution
42
42
  """
43
43
 
44
- result: str
44
+ result: Optional[str]
45
45
  report: Dict[str, Any]
46
46
  is_backup_pipeline: bool = Field(alias="isBackupPipeline")
47
47
 
@@ -20,6 +20,7 @@ class ExportCredentialDataList(BaseModel):
20
20
  key: The key name for the credential data
21
21
  value: The value associated with the key
22
22
  """
23
+
23
24
  key: str = Field(..., description="Gets or sets the key.")
24
25
  value: str = Field(..., description="Gets or sets the value.")
25
26
 
@@ -37,6 +38,7 @@ class ExportCredentials(BaseModel):
37
38
  credential_data_list: List of key-value pairs containing credential data
38
39
  id: The unique identifier for the credential set
39
40
  """
41
+
40
42
  name: str = Field(..., description="Gets or sets the name.")
41
43
  credential_type: str = Field(
42
44
  ..., description="Gets or sets the type.", alias="credentialType"
@@ -62,6 +64,7 @@ class ExportPosition(BaseModel):
62
64
  x: The X-coordinate position
63
65
  y: The Y-coordinate position
64
66
  """
67
+
65
68
  x: str = Field(..., description="Gets or sets the X.")
66
69
  y: str = Field(..., description="Gets or sets the Y.")
67
70
 
@@ -80,6 +83,7 @@ class ExportHandle(BaseModel):
80
83
  x: The X-coordinate position of the handle
81
84
  y: The Y-coordinate position of the handle
82
85
  """
86
+
83
87
  uuid: str = Field(..., description="Gets or sets the UUID of the handle.")
84
88
  type: str = Field(
85
89
  ...,
@@ -113,6 +117,7 @@ class ExportDependency(BaseModel):
113
117
  parent_handle_id: The UUID of the parent's output handle
114
118
  handle_id: The UUID of the child's input handle
115
119
  """
120
+
116
121
  parent_id: str = Field(
117
122
  ...,
118
123
  description="Gets or sets the UUID of the parent pipeline step.",
@@ -160,6 +165,7 @@ class ExportPipelineStep(BaseModel):
160
165
  content: Optional content or configuration data
161
166
  step_title: The human-readable title of the step
162
167
  """
168
+
163
169
  id: str = Field(..., description="Gets or sets the ID.")
164
170
  step_type: str = Field(
165
171
  ..., description="Gets or sets the step type.", alias="stepType"
@@ -240,6 +246,7 @@ class AgentDetailItemDefinition(BaseModel):
240
246
  value: The current value of the parameter
241
247
  options: Optional list of available options for select/multiselect types
242
248
  """
249
+
243
250
  item_type: str = Field(
244
251
  ...,
245
252
  description="Gets or sets the entries for the agent details item input type.",
@@ -277,6 +284,7 @@ class ExportPipeline(BaseModel):
277
284
  agent_icon: Optional base64-encoded icon image
278
285
  steps: List of pipeline steps that make up the workflow
279
286
  """
287
+
280
288
  name: str = Field(..., description="Gets or sets the name.")
281
289
  execution_name: Optional[str] = Field(
282
290
  None, description="Gets or sets the execution name.", alias="executionName"
@@ -312,6 +320,7 @@ class ExportDataSourceFile(BaseModel):
312
320
  file_path: Optional path or location of the file
313
321
  input_token: Optional access token for the file
314
322
  """
323
+
315
324
  data_source_id: str = Field(
316
325
  ...,
317
326
  description="Gets or sets the ID of the associated DataSource.",
@@ -341,6 +350,7 @@ class ExportChunkingConfig(BaseModel):
341
350
  chunk_overlap: The number of characters/tokens that overlap between chunks
342
351
  strategy_type: The chunking strategy used (sentence, paragraph, etc.)
343
352
  """
353
+
344
354
  id: str = Field(
345
355
  ..., description="Gets or sets the chunking configuration identifier."
346
356
  )
@@ -376,6 +386,7 @@ class ExportDataSource(BaseModel):
376
386
  credentials: Optional credential information for access
377
387
  is_image_processing_enabled: Whether image processing is enabled
378
388
  """
389
+
379
390
  id: str = Field(..., description="Gets the id.")
380
391
  name: Optional[str] = Field(None, description="Gets the Name.")
381
392
  execution_name: Optional[str] = Field(
@@ -432,6 +443,7 @@ class ExportPromptMessageList(BaseModel):
432
443
  text: The content of the message
433
444
  order: The order of this message in the prompt sequence
434
445
  """
446
+
435
447
  text: str = Field(..., description="Gets or sets the text.")
436
448
  order: int = Field(..., description="Gets or sets the order.")
437
449
 
@@ -448,6 +460,7 @@ class ExportPrompt(BaseModel):
448
460
  prompt_message_list: List of messages that make up the prompt
449
461
  id: The unique identifier of the prompt
450
462
  """
463
+
451
464
  name: str = Field(..., description="Gets or sets the name.")
452
465
  version_change_description: str = Field(
453
466
  ...,
@@ -472,6 +485,7 @@ class ExportToolHeaders(BaseModel):
472
485
  key: The header name
473
486
  value: The header value
474
487
  """
488
+
475
489
  key: str = Field(..., description="Gets or sets the key of the header.")
476
490
  value: str = Field(..., description="Gets or sets the value of the header.")
477
491
 
@@ -490,6 +504,7 @@ class ExportToolParameters(BaseModel):
490
504
  valid_options: Optional list of valid values for the parameter
491
505
  id: The unique identifier of the parameter
492
506
  """
507
+
493
508
  name: str = Field(..., description="Gets or sets the name.")
494
509
  parameter_type: str = Field(
495
510
  ..., description="Gets or sets the type.", alias="parameterType"
@@ -503,7 +518,7 @@ class ExportToolParameters(BaseModel):
503
518
  description="Gets or sets the list of valid options.",
504
519
  alias="validOptions",
505
520
  )
506
- id: str = Field(..., description="Gets or sets the ID.")
521
+ id: Optional[str] = Field(None, description="Gets or sets the ID.")
507
522
 
508
523
 
509
524
  class ExportTool(BaseModel):
@@ -529,6 +544,7 @@ class ExportTool(BaseModel):
529
544
  use_user_credentials_type: The type of user credentials to use
530
545
  id: The unique identifier of the tool
531
546
  """
547
+
532
548
  tool_type: str = Field(
533
549
  ...,
534
550
  description="Gets or sets a value indicating whether flag that indicates if the tool is native.",
@@ -570,8 +586,8 @@ class ExportTool(BaseModel):
570
586
  description="Gets or sets a value indicating whether the tool should use user based credentials.",
571
587
  alias="useUserCredentials",
572
588
  )
573
- use_user_credentials_type: str = Field(
574
- ...,
589
+ use_user_credentials_type: Optional[str] = Field(
590
+ None,
575
591
  description="Gets or sets a value indicating what the credential type is when the tool use user based credentials.",
576
592
  alias="useUserCredentialsType",
577
593
  )
@@ -612,6 +628,7 @@ class ExportModel(BaseModel):
612
628
  author: Optional author information
613
629
  price_type: The pricing model type
614
630
  """
631
+
615
632
  id: str = Field(..., description="Gets or sets the ID.")
616
633
  display_name: str = Field(
617
634
  ..., description="Gets or sets the display name.", alias="displayName"
@@ -707,6 +724,7 @@ class ExportMemory(BaseModel):
707
724
  name: The name of the memory
708
725
  is_user_specific: Whether the memory is specific to individual users
709
726
  """
727
+
710
728
  id: str = Field(..., description="Gets or sets the memory id.")
711
729
  name: str = Field(..., description="Gets or sets the memory name.")
712
730
  is_user_specific: bool = Field(
@@ -726,6 +744,7 @@ class ExportPythonCodeBlock(BaseModel):
726
744
  id: The unique identifier of the code block
727
745
  code: The Python code content
728
746
  """
747
+
729
748
  id: str = Field(..., description="Gets or sets the memory id.")
730
749
  code: str = Field(..., description="Gets or sets the code.")
731
750
 
@@ -741,6 +760,7 @@ class ExportRouterConfig(BaseModel):
741
760
  prompt: The prompt used for routing decisions
742
761
  is_default: Whether this is the default routing option
743
762
  """
763
+
744
764
  id: str = Field(..., description="Gets or sets the Id.")
745
765
  prompt: str = Field(..., description="Gets or sets the Prompt.")
746
766
  is_default: Optional[bool] = Field(
@@ -762,6 +782,7 @@ class ExportRouter(BaseModel):
762
782
  model: Optional AI model definition for routing
763
783
  router_config: Dictionary of routing configurations
764
784
  """
785
+
765
786
  id: str = Field(..., description="Gets or sets the Router identifier.")
766
787
  model_id: Optional[str] = Field(
767
788
  None, description="Gets or sets the Model identifier.", alias="modelId"
@@ -783,6 +804,7 @@ class ExportUserPrompt(BaseModel):
783
804
  message: The prompt message content
784
805
  prompt_description: Description of the prompt's purpose
785
806
  """
807
+
786
808
  name: str = Field(..., description="Gets or sets the name of the UserPrompt.")
787
809
  message: str = Field(..., description="Gets or sets the UserPrompt Message.")
788
810
  prompt_description: str = Field(
@@ -810,6 +832,7 @@ class ExportDeployment(BaseModel):
810
832
  conversation_type: The type of conversation interface
811
833
  about_json: Optional JSON metadata about the deployment
812
834
  """
835
+
813
836
  name: str = Field(..., description="Gets the Deployment Name.")
814
837
  deployment_icon: Optional[str] = Field(
815
838
  None, description="Gets the Deployment Icon.", alias="deploymentIcon"
@@ -864,6 +887,7 @@ class ExportMetadata(BaseModel):
864
887
  version_information: Information about the pipeline version
865
888
  state: The current state of the agent
866
889
  """
890
+
867
891
  id: str = Field(..., description="Gets or sets the id.")
868
892
  export_version: Optional[str] = Field(
869
893
  None,
@@ -912,6 +936,7 @@ class ExportPipelineDefinitionResponse(BaseModel):
912
936
  routers: Optional list of router configurations used by the pipeline
913
937
  deployment: Optional deployment configuration for the pipeline
914
938
  """
939
+
915
940
  metadata: ExportMetadata = Field(..., description="Gets or sets the Metadata.")
916
941
  agent: ExportPipeline = Field(..., description="Gets or sets the pipeline.")
917
942
  data_sources: Optional[List[ExportDataSource]] = Field(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: airia
3
- Version: 0.1.20
3
+ Version: 0.1.22
4
4
  Summary: Python SDK for Airia API
5
5
  Author-email: Airia LLC <support@airia.com>
6
6
  License: MIT
@@ -18,6 +18,10 @@ airia/client/_request_handler/__init__.py
18
18
  airia/client/_request_handler/async_request_handler.py
19
19
  airia/client/_request_handler/base_request_handler.py
20
20
  airia/client/_request_handler/sync_request_handler.py
21
+ airia/client/attachments/__init__.py
22
+ airia/client/attachments/async_attachments.py
23
+ airia/client/attachments/base_attachments.py
24
+ airia/client/attachments/sync_attachments.py
21
25
  airia/client/conversations/__init__.py
22
26
  airia/client/conversations/async_conversations.py
23
27
  airia/client/conversations/base_conversations.py
@@ -50,6 +54,8 @@ airia/types/__init__.py
50
54
  airia/types/_api_version.py
51
55
  airia/types/_request_data.py
52
56
  airia/types/api/__init__.py
57
+ airia/types/api/attachments/__init__.py
58
+ airia/types/api/attachments/upload_file.py
53
59
  airia/types/api/conversations/__init__.py
54
60
  airia/types/api/conversations/_conversations.py
55
61
  airia/types/api/data_vector_search/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "airia"
7
- version = "0.1.20"
7
+ version = "0.1.22"
8
8
  description = "Python SDK for Airia API"
9
9
  license = { text = "MIT" }
10
10
  authors = [{ name = "Airia LLC", email = "support@airia.com" }]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes