airia 0.1.3__py3-none-any.whl → 0.1.5__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.
@@ -0,0 +1,4 @@
1
+ from .async_client import AiriaAsyncClient
2
+ from .sync_client import AiriaClient
3
+
4
+ __all__ = ["AiriaClient", "AiriaAsyncClient"]
@@ -0,0 +1,464 @@
1
+ from typing import Any, AsyncIterator, Dict, List, Literal, Optional, overload
2
+ from urllib.parse import urljoin
3
+
4
+ import aiohttp
5
+ import loguru
6
+
7
+ from ..exceptions import AiriaAPIError
8
+ from ..types import (
9
+ ApiVersion,
10
+ PipelineExecutionDebugResponse,
11
+ PipelineExecutionResponse,
12
+ PipelineExecutionV1StreamedResponse,
13
+ PipelineExecutionV2AsyncStreamedResponse,
14
+ RequestData,
15
+ )
16
+ from .base_client import AiriaBaseClient
17
+
18
+
19
+ class AiriaAsyncClient(AiriaBaseClient):
20
+ """Asynchronous client for interacting with the Airia API."""
21
+
22
+ def __init__(
23
+ self,
24
+ base_url: str = "https://api.airia.ai/",
25
+ api_key: Optional[str] = None,
26
+ timeout: float = 30.0,
27
+ log_requests: bool = False,
28
+ custom_logger: Optional["loguru.Logger"] = None,
29
+ ):
30
+ """
31
+ Initialize the asynchronous Airia API client.
32
+
33
+ Args:
34
+ base_url: Base URL of the Airia API.
35
+ api_key: API key for authentication. If not provided, will attempt to use AIRIA_API_KEY environment variable.
36
+ timeout: Request timeout in seconds.
37
+ log_requests: Whether to log API requests and responses. Default is False.
38
+ custom_logger: Optional custom logger object to use for logging. If not provided, will use a default logger when `log_requests` is True.
39
+ """
40
+ super().__init__(
41
+ base_url=base_url,
42
+ api_key=api_key,
43
+ timeout=timeout,
44
+ log_requests=log_requests,
45
+ custom_logger=custom_logger,
46
+ )
47
+
48
+ # Session will be initialized in __aenter__
49
+ self.session = None
50
+ self.headers = {"Content-Type": "application/json"}
51
+
52
+ @classmethod
53
+ def with_openai_gateway(
54
+ cls,
55
+ base_url: str = "https://api.airia.ai/",
56
+ gateway_url: str = "https://gateway.airia.ai/openai/v1",
57
+ api_key: Optional[str] = None,
58
+ timeout: float = 30.0,
59
+ log_requests: bool = False,
60
+ custom_logger: Optional["loguru.Logger"] = None,
61
+ **kwargs,
62
+ ):
63
+ """
64
+ Initialize the asynchronous Airia API client with AsyncOpenAI gateway capabilities.
65
+
66
+ Args:
67
+ base_url: Base URL of the Airia API.
68
+ gateway_url: Base URL of the Airia Gateway API.
69
+ api_key: API key for authentication. If not provided, will attempt to use AIRIA_API_KEY environment variable.
70
+ timeout: Request timeout in seconds.
71
+ log_requests: Whether to log API requests and responses. Default is False.
72
+ custom_logger: Optional custom logger object to use for logging. If not provided, will use a default logger when `log_requests` is True.
73
+ **kwargs: Additional keyword arguments to pass to the AsyncOpenAI client initialization.
74
+ """
75
+ from openai import AsyncOpenAI
76
+
77
+ api_key = cls._get_api_key(api_key)
78
+ cls.openai = AsyncOpenAI(
79
+ api_key=api_key,
80
+ base_url=gateway_url,
81
+ **kwargs,
82
+ )
83
+
84
+ return cls(base_url, api_key, timeout, log_requests, custom_logger)
85
+
86
+ @classmethod
87
+ def with_anthropic_gateway(
88
+ cls,
89
+ base_url: str = "https://api.airia.ai/",
90
+ gateway_url: str = "https://gateway.airia.ai/anthropic",
91
+ api_key: Optional[str] = None,
92
+ timeout: float = 30.0,
93
+ log_requests: bool = False,
94
+ custom_logger: Optional["loguru.Logger"] = None,
95
+ **kwargs,
96
+ ):
97
+ """
98
+ Initialize the asynchronous Airia API client with AsyncAnthropic gateway capabilities.
99
+
100
+ Args:
101
+ base_url: Base URL of the Airia API.
102
+ gateway_url: Base URL of the Airia Gateway API.
103
+ api_key: API key for authentication. If not provided, will attempt to use AIRIA_API_KEY environment variable.
104
+ timeout: Request timeout in seconds.
105
+ log_requests: Whether to log API requests and responses. Default is False.
106
+ custom_logger: Optional custom logger object to use for logging. If not provided, will use a default logger when `log_requests` is True.
107
+ **kwargs: Additional keyword arguments to pass to the AsyncAnthropic client initialization.
108
+ """
109
+ from anthropic import AsyncAnthropic
110
+
111
+ api_key = cls._get_api_key(api_key)
112
+ cls.anthropic = AsyncAnthropic(
113
+ api_key=api_key,
114
+ base_url=gateway_url,
115
+ **kwargs,
116
+ )
117
+
118
+ return cls(base_url, api_key, timeout, log_requests, custom_logger)
119
+
120
+ async def __aenter__(self):
121
+ """Async context manager entry point."""
122
+ self.session = aiohttp.ClientSession(headers=self.headers)
123
+ return self
124
+
125
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
126
+ """Async context manager exit point."""
127
+ if self.session:
128
+ await self.session.close()
129
+ self.session = None
130
+
131
+ def _check_session(self):
132
+ """Check if the client session is initialized."""
133
+ if not self.session:
134
+ raise RuntimeError(
135
+ "Client session not initialized. Use async with AiriaAsyncClient() as client: ..."
136
+ )
137
+
138
+ def _handle_exception(
139
+ self, e: aiohttp.ClientResponseError, url: str, correlation_id: str
140
+ ):
141
+ # Log the error response if enabled
142
+ if self.log_requests:
143
+ self.logger.error(
144
+ f"API Error: {e.status} {e.message}\n"
145
+ f"URL: {url}\n"
146
+ f"Correlation ID: {correlation_id}"
147
+ )
148
+
149
+ # Extract error details from response
150
+ error_message = e.message
151
+
152
+ # Make sure API key is not included in error messages
153
+ sanitized_message = (
154
+ error_message.replace(self.api_key, "[REDACTED]")
155
+ if self.api_key in error_message
156
+ else error_message
157
+ )
158
+
159
+ # Raise custom exception with status code and sanitized message
160
+ raise AiriaAPIError(status_code=e.status, message=sanitized_message) from e
161
+
162
+ async def _make_request(
163
+ self, method: str, request_data: RequestData
164
+ ) -> Dict[str, Any]:
165
+ """
166
+ Makes an asynchronous HTTP request to the Airia API.
167
+
168
+ Args:
169
+ method (str): The HTTP method (e.g., 'GET', 'POST')
170
+ request_data: A dictionary containing the following request information:
171
+ - url: The endpoint URL for the request
172
+ - headers: HTTP headers to include in the request
173
+ - payload: The JSON payload/body for the request
174
+ - correlation_id: Unique identifier for request tracing
175
+
176
+ Returns:
177
+ resp ([Dict[str, Any]): The JSON response from the API as a dictionary.
178
+
179
+ Raises:
180
+ AiriaAPIError: If the API returns an error response, with details about the error
181
+ aiohttp.ClientResponseError: For HTTP-related errors
182
+
183
+ Note:
184
+ This is an internal method used by other client methods to make API requests.
185
+ It handles logging, error handling, and API key redaction in error messages.
186
+ """
187
+ try:
188
+ # Make the request
189
+ async with self.session.request(
190
+ method=method,
191
+ url=request_data.url,
192
+ json=request_data.payload,
193
+ headers=request_data.headers,
194
+ timeout=self.timeout,
195
+ ) as response:
196
+ # Log the response if enabled
197
+ if self.log_requests:
198
+ self.logger.info(
199
+ f"API Response: {response.status} {response.reason}\n"
200
+ f"URL: {request_data.url}\n"
201
+ f"Correlation ID: {request_data.correlation_id}"
202
+ )
203
+
204
+ # Check for HTTP errors
205
+ response.raise_for_status()
206
+
207
+ # Return the response as a dictionary
208
+ return await response.json()
209
+
210
+ except aiohttp.ClientResponseError as e:
211
+ self._handle_exception(e, request_data.url, request_data.correlation_id)
212
+
213
+ async def _make_request_stream(
214
+ self, method: str, request_data: RequestData
215
+ ) -> AsyncIterator[str]:
216
+ """
217
+ Makes an asynchronous HTTP request to the Airia API.
218
+
219
+ Args:
220
+ method (str): The HTTP method (e.g., 'GET', 'POST')
221
+ request_data: A dictionary containing the following request information:
222
+ - url: The endpoint URL for the request
223
+ - headers: HTTP headers to include in the request
224
+ - payload: The JSON payload/body for the request
225
+ - correlation_id: Unique identifier for request tracing
226
+
227
+ Yields:
228
+ resp AsyncIterator[str]]: yields chunks of the response as they are received.
229
+
230
+ Raises:
231
+ AiriaAPIError: If the API returns an error response, with details about the error
232
+ aiohttp.ClientResponseError: For HTTP-related errors
233
+
234
+ Note:
235
+ This is an internal method used by other client methods to make API requests.
236
+ It handles logging, error handling, and API key redaction in error messages.
237
+ """
238
+ try:
239
+ # Make the request
240
+ async with self.session.request(
241
+ method=method,
242
+ url=request_data.url,
243
+ json=request_data.payload,
244
+ headers=request_data.headers,
245
+ timeout=self.timeout,
246
+ chunked=True,
247
+ ) as response:
248
+ # Log the response if enabled
249
+ if self.log_requests:
250
+ self.logger.info(
251
+ f"API Response: {response.status} {response.reason}\n"
252
+ f"URL: {request_data.url}\n"
253
+ f"Correlation ID: {request_data.correlation_id}"
254
+ )
255
+
256
+ # Check for HTTP errors
257
+ response.raise_for_status()
258
+
259
+ # Yields the response content as a stream if streaming
260
+ async for chunk in response.content.iter_any():
261
+ yield chunk.decode("utf-8")
262
+
263
+ except aiohttp.ClientResponseError as e:
264
+ self._handle_exception(e, request_data.url, request_data.correlation_id)
265
+
266
+ @overload
267
+ async def execute_pipeline(
268
+ self,
269
+ pipeline_id: str,
270
+ user_input: str,
271
+ debug: Literal[False] = False,
272
+ user_id: Optional[str] = None,
273
+ conversation_id: Optional[str] = None,
274
+ async_output: Literal[False] = False,
275
+ include_tools_response: bool = False,
276
+ images: Optional[List[str]] = None,
277
+ files: Optional[List[str]] = None,
278
+ data_source_folders: Optional[Dict[str, Any]] = None,
279
+ data_source_files: Optional[Dict[str, Any]] = None,
280
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
281
+ current_date_time: Optional[str] = None,
282
+ save_history: bool = True,
283
+ additional_info: Optional[List[Any]] = None,
284
+ prompt_variables: Optional[Dict[str, Any]] = None,
285
+ correlation_id: Optional[str] = None,
286
+ api_version: str = ApiVersion.V2.value,
287
+ ) -> PipelineExecutionResponse: ...
288
+
289
+ @overload
290
+ async def execute_pipeline(
291
+ self,
292
+ pipeline_id: str,
293
+ user_input: str,
294
+ debug: Literal[True] = True,
295
+ user_id: Optional[str] = None,
296
+ conversation_id: Optional[str] = None,
297
+ async_output: Literal[False] = False,
298
+ include_tools_response: bool = False,
299
+ images: Optional[List[str]] = None,
300
+ files: Optional[List[str]] = None,
301
+ data_source_folders: Optional[Dict[str, Any]] = None,
302
+ data_source_files: Optional[Dict[str, Any]] = None,
303
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
304
+ current_date_time: Optional[str] = None,
305
+ save_history: bool = True,
306
+ additional_info: Optional[List[Any]] = None,
307
+ prompt_variables: Optional[Dict[str, Any]] = None,
308
+ correlation_id: Optional[str] = None,
309
+ api_version: str = ApiVersion.V2.value,
310
+ ) -> PipelineExecutionDebugResponse: ...
311
+
312
+ @overload
313
+ async def execute_pipeline(
314
+ self,
315
+ pipeline_id: str,
316
+ user_input: str,
317
+ debug: bool = False,
318
+ user_id: Optional[str] = None,
319
+ conversation_id: Optional[str] = None,
320
+ async_output: Literal[True] = True,
321
+ include_tools_response: bool = False,
322
+ images: Optional[List[str]] = None,
323
+ files: Optional[List[str]] = None,
324
+ data_source_folders: Optional[Dict[str, Any]] = None,
325
+ data_source_files: Optional[Dict[str, Any]] = None,
326
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
327
+ current_date_time: Optional[str] = None,
328
+ save_history: bool = True,
329
+ additional_info: Optional[List[Any]] = None,
330
+ prompt_variables: Optional[Dict[str, Any]] = None,
331
+ correlation_id: Optional[str] = None,
332
+ api_version: Literal["v2"] = ApiVersion.V2.value,
333
+ ) -> PipelineExecutionV2AsyncStreamedResponse: ...
334
+
335
+ @overload
336
+ async def execute_pipeline(
337
+ self,
338
+ pipeline_id: str,
339
+ user_input: str,
340
+ debug: bool = False,
341
+ user_id: Optional[str] = None,
342
+ conversation_id: Optional[str] = None,
343
+ async_output: Literal[True] = True,
344
+ include_tools_response: bool = False,
345
+ images: Optional[List[str]] = None,
346
+ files: Optional[List[str]] = None,
347
+ data_source_folders: Optional[Dict[str, Any]] = None,
348
+ data_source_files: Optional[Dict[str, Any]] = None,
349
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
350
+ current_date_time: Optional[str] = None,
351
+ save_history: bool = True,
352
+ additional_info: Optional[List[Any]] = None,
353
+ prompt_variables: Optional[Dict[str, Any]] = None,
354
+ correlation_id: Optional[str] = None,
355
+ api_version: Literal["v1"] = ApiVersion.V1.value,
356
+ ) -> PipelineExecutionV1StreamedResponse: ...
357
+
358
+ async def execute_pipeline(
359
+ self,
360
+ pipeline_id: str,
361
+ user_input: str,
362
+ debug: bool = False,
363
+ user_id: Optional[str] = None,
364
+ conversation_id: Optional[str] = None,
365
+ async_output: bool = False,
366
+ include_tools_response: bool = False,
367
+ images: Optional[List[str]] = None,
368
+ files: Optional[List[str]] = None,
369
+ data_source_folders: Optional[Dict[str, Any]] = None,
370
+ data_source_files: Optional[Dict[str, Any]] = None,
371
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
372
+ current_date_time: Optional[str] = None,
373
+ save_history: bool = True,
374
+ additional_info: Optional[List[Any]] = None,
375
+ prompt_variables: Optional[Dict[str, Any]] = None,
376
+ correlation_id: Optional[str] = None,
377
+ api_version: str = ApiVersion.V2.value,
378
+ ) -> Dict[str, Any]:
379
+ """
380
+ Execute a pipeline with the provided input asynchronously.
381
+
382
+ Args:
383
+ pipeline_id: The ID of the pipeline to execute.
384
+ user_input: input text to process.
385
+ debug: Whether debug mode execution is enabled. Default is False.
386
+ user_id: Optional ID of the user making the request (guid).
387
+ conversation_id: Optional conversation ID (guid).
388
+ async_output: Whether to stream the response. Default is False.
389
+ include_tools_response: Whether to return the initial LLM tool result. Default is False.
390
+ images: Optional list of images formatted as base64 strings.
391
+ files: Optional list of files formatted as base64 strings.
392
+ data_source_folders: Optional data source folders information.
393
+ data_source_files: Optional data source files information.
394
+ in_memory_messages: Optional list of in-memory messages, each with a role and message.
395
+ current_date_time: Optional current date and time in ISO format.
396
+ save_history: Whether to save the userInput and output to conversation history. Default is True.
397
+ additional_info: Optional additional information.
398
+ prompt_variables: Optional variables to be used in the prompt.
399
+ correlation_id: Optional correlation ID for request tracing. If not provided,
400
+ one will be generated automatically.
401
+ api_version: API version to use. Default is `v2`
402
+
403
+ Returns:
404
+ The API response as a dictionary.
405
+
406
+ Raises:
407
+ AiriaAPIError: If the API request fails with details about the error.
408
+ aiohttp.ClientError: For other request-related errors.
409
+
410
+ Example:
411
+ >>> async with AiriaAsyncClient(api_key="your_api_key") as client:
412
+ ... response = await client.execute_pipeline(
413
+ ... pipeline_id="pipeline_123",
414
+ ... user_input="Tell me about quantum computing"
415
+ ... )
416
+ >>> print(response.result)
417
+ """
418
+ self._check_session()
419
+
420
+ request_data = self._pre_execute_pipeline(
421
+ pipeline_id=pipeline_id,
422
+ user_input=user_input,
423
+ debug=debug,
424
+ user_id=user_id,
425
+ conversation_id=conversation_id,
426
+ async_output=async_output,
427
+ include_tools_response=include_tools_response,
428
+ images=images,
429
+ files=files,
430
+ data_source_folders=data_source_folders,
431
+ data_source_files=data_source_files,
432
+ in_memory_messages=in_memory_messages,
433
+ current_date_time=current_date_time,
434
+ save_history=save_history,
435
+ additional_info=additional_info,
436
+ prompt_variables=prompt_variables,
437
+ correlation_id=correlation_id,
438
+ api_version=api_version,
439
+ )
440
+ stream = async_output and api_version == ApiVersion.V2.value
441
+ if stream:
442
+ resp = self._make_request_stream(method="POST", request_data=request_data)
443
+ else:
444
+ resp = await self._make_request("POST", request_data)
445
+
446
+ if not async_output:
447
+ if not debug:
448
+ return PipelineExecutionResponse(**resp)
449
+ return PipelineExecutionDebugResponse(**resp)
450
+
451
+ if api_version == ApiVersion.V1.value:
452
+ url = urljoin(
453
+ self.base_url, f"{api_version}/StreamSocketConfig/GenerateUrl"
454
+ )
455
+ request_data = self._prepare_request(
456
+ url,
457
+ {"socketIdentifier": resp},
458
+ request_data.headers["X-Correlation-ID"],
459
+ )
460
+ resp = await self._make_request("POST", request_data)
461
+
462
+ return PipelineExecutionV1StreamedResponse(**resp)
463
+
464
+ return PipelineExecutionV2AsyncStreamedResponse(stream=resp)
@@ -0,0 +1,188 @@
1
+ import json
2
+ import os
3
+ from typing import Any, Dict, List, Optional
4
+ from urllib.parse import urljoin
5
+
6
+ import loguru
7
+
8
+ from ..logs import configure_logging, set_correlation_id
9
+ from ..types import ApiVersion, RequestData
10
+
11
+
12
+ class AiriaBaseClient:
13
+ """Base client containing shared functionality for Airia API clients."""
14
+ openai = None
15
+ anthropic = None
16
+
17
+ def __init__(
18
+ self,
19
+ base_url: str = "https://api.airia.ai/",
20
+ api_key: Optional[str] = None,
21
+ timeout: float = 30.0,
22
+ log_requests: bool = False,
23
+ custom_logger: Optional["loguru.Logger"] = None,
24
+ ):
25
+ """
26
+ Initialize the Airia API client base class.
27
+
28
+ Args:
29
+ api_key: API key for authentication. If not provided, will attempt to use AIRIA_API_KEY environment variable.
30
+ timeout: Request timeout in seconds.
31
+ log_requests: Whether to log API requests and responses. Default is False.
32
+ custom_logger: Optional custom logger object to use for logging. If not provided, will use a default logger when `log_requests` is True.
33
+ """
34
+ # Resolve API key: parameter takes precedence over environment variable
35
+ self.api_key = self.__class__._get_api_key(api_key)
36
+
37
+ # Store configuration
38
+ self.base_url = base_url
39
+ self.timeout = timeout
40
+ self.log_requests = log_requests
41
+
42
+ # Initialize logger
43
+ self.logger = configure_logging() if custom_logger is None else custom_logger
44
+
45
+ @staticmethod
46
+ def _get_api_key(api_key: Optional[str] = None):
47
+ """
48
+ Get the API key from either the provided parameter or environment variable.
49
+
50
+ Args:
51
+ api_key (Optional[str]): The API key provided as a parameter. Defaults to None.
52
+
53
+ Returns:
54
+ str: The resolved API key.
55
+
56
+ Raises:
57
+ ValueError: If no API key is provided through either method.
58
+ """
59
+ api_key = api_key or os.environ.get("AIRIA_API_KEY")
60
+
61
+ if not api_key:
62
+ raise ValueError(
63
+ "API key must be provided either as a parameter or through the AIRIA_API_KEY environment variable."
64
+ )
65
+
66
+ return api_key
67
+
68
+ def _prepare_request(
69
+ self,
70
+ url: str,
71
+ payload: Optional[Dict[str, Any]] = None,
72
+ correlation_id: Optional[str] = None,
73
+ ):
74
+ """
75
+ Prepare the request parameters for an API call.
76
+
77
+ Args:
78
+ url (str): The endpoint URL for the API request.
79
+ payload (Optional[Dict[str, Any]]): The request payload/body to be sent.
80
+ correlation_id (Optional[str]): A unique identifier for tracing the request. If None, one will be generated.
81
+
82
+ Returns:
83
+ dict: A dictionary containing the prepared request parameters with the following keys:
84
+ - url: The request URL
85
+ - payload: The request payload
86
+ - headers: Request headers including API key and correlation ID
87
+ - correlation_id: The correlation ID used for the request
88
+
89
+ Note:
90
+ This method handles:
91
+ - Setting/generating correlation IDs
92
+ - Adding authentication headers
93
+ - Logging requests (if enabled) with sensitive information redacted
94
+ """
95
+ # Set correlation ID if provided or generate a new one
96
+ correlation_id = set_correlation_id(correlation_id)
97
+
98
+ # Add the X-API-KEY header and correlation ID
99
+ headers = {
100
+ "X-API-KEY": self.api_key,
101
+ "X-Correlation-ID": correlation_id,
102
+ "Content-Type": "application/json",
103
+ }
104
+
105
+ # Log the request if enabled
106
+ if self.log_requests:
107
+ # Create a sanitized copy of headers for logging
108
+ log_headers = headers.copy()
109
+
110
+ # Filter out sensitive headers
111
+ if "X-API-KEY" in log_headers:
112
+ log_headers["X-API-KEY"] = "[REDACTED]"
113
+
114
+ # Process payload for logging
115
+ log_payload = None
116
+ if payload is not None:
117
+ log_payload = payload.copy()
118
+
119
+ if "images" in log_payload and log_payload["images"] is not None:
120
+ log_payload["images"] = f"{len(log_payload['images'])} images"
121
+ if "files" in log_payload and log_payload["files"] is not None:
122
+ log_payload["files"] = f"{len(log_payload['files'])} files"
123
+
124
+ log_payload = json.dumps(log_payload)
125
+
126
+ self.logger.info(
127
+ f"API Request: POST {url}\n"
128
+ f"Headers: {json.dumps(log_headers)}\n"
129
+ f"Payload: {log_payload}"
130
+ )
131
+
132
+ return RequestData(
133
+ **{
134
+ "url": url,
135
+ "payload": payload,
136
+ "headers": headers,
137
+ "correlation_id": correlation_id,
138
+ }
139
+ )
140
+
141
+ def _pre_execute_pipeline(
142
+ self,
143
+ pipeline_id: str,
144
+ user_input: str,
145
+ debug: bool = False,
146
+ user_id: Optional[str] = None,
147
+ conversation_id: Optional[str] = None,
148
+ async_output: bool = False,
149
+ include_tools_response: bool = False,
150
+ images: Optional[List[str]] = None,
151
+ files: Optional[List[str]] = None,
152
+ data_source_folders: Optional[Dict[str, Any]] = None,
153
+ data_source_files: Optional[Dict[str, Any]] = None,
154
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
155
+ current_date_time: Optional[str] = None,
156
+ save_history: bool = True,
157
+ additional_info: Optional[List[Any]] = None,
158
+ prompt_variables: Optional[Dict[str, Any]] = None,
159
+ correlation_id: Optional[str] = None,
160
+ api_version: str = ApiVersion.V2.value,
161
+ ):
162
+ if api_version not in ApiVersion.as_list():
163
+ raise ValueError(
164
+ f"Invalid API version: {api_version}. Valid versions are: {', '.join(ApiVersion.as_list())}"
165
+ )
166
+ url = urljoin(self.base_url, f"{api_version}/PipelineExecution/{pipeline_id}")
167
+
168
+ payload = {
169
+ "userInput": user_input,
170
+ "debug": debug,
171
+ "userId": user_id,
172
+ "conversationId": conversation_id,
173
+ "asyncOutput": async_output,
174
+ "includeToolsResponse": include_tools_response,
175
+ "images": images,
176
+ "files": files,
177
+ "dataSourceFolders": data_source_folders,
178
+ "dataSourceFiles": data_source_files,
179
+ "inMemoryMessages": in_memory_messages,
180
+ "currentDateTime": current_date_time,
181
+ "saveHistory": save_history,
182
+ "additionalInfo": additional_info,
183
+ "promptVariables": prompt_variables,
184
+ }
185
+
186
+ request_data = self._prepare_request(url, payload, correlation_id)
187
+
188
+ return request_data
@@ -0,0 +1,452 @@
1
+ from typing import Any, Dict, List, Literal, Optional, overload
2
+ from urllib.parse import urljoin
3
+
4
+ import loguru
5
+ import requests
6
+
7
+ from ..exceptions import AiriaAPIError
8
+ from ..types import (
9
+ ApiVersion,
10
+ PipelineExecutionDebugResponse,
11
+ PipelineExecutionResponse,
12
+ PipelineExecutionV1StreamedResponse,
13
+ PipelineExecutionV2StreamedResponse,
14
+ RequestData,
15
+ )
16
+ from .base_client import AiriaBaseClient
17
+
18
+
19
+ class AiriaClient(AiriaBaseClient):
20
+ """Synchronous client for interacting with the Airia API."""
21
+
22
+ def __init__(
23
+ self,
24
+ base_url: str = "https://api.airia.ai/",
25
+ api_key: Optional[str] = None,
26
+ timeout: float = 30.0,
27
+ log_requests: bool = False,
28
+ custom_logger: Optional["loguru.Logger"] = None,
29
+ ):
30
+ """
31
+ Initialize the synchronous Airia API client.
32
+
33
+ Args:
34
+ base_url: Base URL of the Airia API.
35
+ api_key: API key for authentication. If not provided, will attempt to use AIRIA_API_KEY environment variable.
36
+ timeout: Request timeout in seconds.
37
+ log_requests: Whether to log API requests and responses. Default is False.
38
+ custom_logger: Optional custom logger object to use for logging. If not provided, will use a default logger when `log_requests` is True.
39
+ """
40
+ super().__init__(
41
+ base_url=base_url,
42
+ api_key=api_key,
43
+ timeout=timeout,
44
+ log_requests=log_requests,
45
+ custom_logger=custom_logger,
46
+ )
47
+
48
+ # Initialize session for synchronous requests
49
+ self.session = requests.Session()
50
+ self.session.headers.update({"Content-Type": "application/json"})
51
+
52
+ @classmethod
53
+ def with_openai_gateway(
54
+ cls,
55
+ base_url: str = "https://api.airia.ai/",
56
+ gateway_url: str = "https://gateway.airia.ai/openai/v1",
57
+ api_key: Optional[str] = None,
58
+ timeout: float = 30.0,
59
+ log_requests: bool = False,
60
+ custom_logger: Optional["loguru.Logger"] = None,
61
+ **kwargs,
62
+ ):
63
+ """
64
+ Initialize the synchronous Airia API client with OpenAI gateway capabilities.
65
+
66
+ Args:
67
+ base_url: Base URL of the Airia API.
68
+ gateway_url: Base URL of the Airia Gateway API.
69
+ api_key: API key for authentication. If not provided, will attempt to use AIRIA_API_KEY environment variable.
70
+ timeout: Request timeout in seconds.
71
+ log_requests: Whether to log API requests and responses. Default is False.
72
+ custom_logger: Optional custom logger object to use for logging. If not provided, will use a default logger when `log_requests` is True.
73
+ **kwargs: Additional keyword arguments to pass to the OpenAI client initialization.
74
+ """
75
+ from openai import OpenAI
76
+
77
+ api_key = cls._get_api_key(api_key)
78
+ cls.openai = OpenAI(
79
+ api_key=api_key,
80
+ base_url=gateway_url,
81
+ **kwargs,
82
+ )
83
+
84
+ return cls(base_url, api_key, timeout, log_requests, custom_logger)
85
+
86
+ @classmethod
87
+ def with_anthropic_gateway(
88
+ cls,
89
+ base_url: str = "https://api.airia.ai/",
90
+ gateway_url: str = "https://gateway.airia.ai/anthropic",
91
+ api_key: Optional[str] = None,
92
+ timeout: float = 30.0,
93
+ log_requests: bool = False,
94
+ custom_logger: Optional["loguru.Logger"] = None,
95
+ **kwargs,
96
+ ):
97
+ """
98
+ Initialize the synchronous Airia API client with Anthropic gateway capabilities.
99
+
100
+ Args:
101
+ base_url: Base URL of the Airia API.
102
+ gateway_url: Base URL of the Airia Gateway API.
103
+ api_key: API key for authentication. If not provided, will attempt to use AIRIA_API_KEY environment variable.
104
+ timeout: Request timeout in seconds.
105
+ log_requests: Whether to log API requests and responses. Default is False.
106
+ custom_logger: Optional custom logger object to use for logging. If not provided, will use a default logger when `log_requests` is True.
107
+ **kwargs: Additional keyword arguments to pass to the Anthropic client initialization.
108
+ """
109
+ from anthropic import Anthropic
110
+
111
+ api_key = cls._get_api_key(api_key)
112
+ cls.anthropic = Anthropic(
113
+ api_key=api_key,
114
+ base_url=gateway_url,
115
+ **kwargs,
116
+ )
117
+
118
+ return cls(base_url, api_key, timeout, log_requests, custom_logger)
119
+
120
+ def _handle_exception(self, e: requests.HTTPError, url: str, correlation_id: str):
121
+ # Log the error response if enabled
122
+ if self.log_requests:
123
+ self.logger.error(
124
+ f"API Error: {e.response.status_code} {e.response.reason}\n"
125
+ f"URL: {url}\n"
126
+ f"Correlation ID: {correlation_id}"
127
+ )
128
+
129
+ # Extract error details from response if possible
130
+ error_message = "API request failed"
131
+ try:
132
+ error_data = e.response.json()
133
+ if isinstance(error_data, dict) and "message" in error_data:
134
+ error_message = error_data["message"]
135
+ elif isinstance(error_data, dict) and "error" in error_data:
136
+ error_message = error_data["error"]
137
+ except (ValueError, KeyError):
138
+ # If JSON parsing fails or expected keys are missing
139
+ error_message = f"API request failed: {str(e)}"
140
+
141
+ # Make sure API key is not included in error messages
142
+ sanitized_message = (
143
+ error_message.replace(self.api_key, "[REDACTED]")
144
+ if self.api_key in error_message
145
+ else error_message
146
+ )
147
+
148
+ # Raise custom exception with status code and sanitized message
149
+ raise AiriaAPIError(
150
+ status_code=e.response.status_code, message=sanitized_message
151
+ ) from e
152
+
153
+ def _make_request(self, method: str, request_data: RequestData):
154
+ """
155
+ Makes a synchronous HTTP request to the Airia API.
156
+
157
+ Args:
158
+ method (str): The HTTP method (e.g., 'GET', 'POST')
159
+ request_data: A dictionary containing the following request information:
160
+ - url: The endpoint URL for the request
161
+ - headers: HTTP headers to include in the request
162
+ - payload: The JSON payload/body for the request
163
+ - correlation_id: Unique identifier for request tracing
164
+
165
+ Returns:
166
+ resp (Dict[str, Any]): The JSON response from the API as a dictionary.
167
+
168
+ Raises:
169
+ AiriaAPIError: If the API returns an error response, with details about the error
170
+ requests.HTTPError: For HTTP-related errors
171
+
172
+ Note:
173
+ This is an internal method used by other client methods to make API requests.
174
+ It handles logging, error handling, and API key redaction in error messages.
175
+ """
176
+ try:
177
+ # Make the request
178
+ response = self.session.request(
179
+ method=method,
180
+ url=request_data.url,
181
+ json=request_data.payload,
182
+ headers=request_data.headers,
183
+ timeout=self.timeout,
184
+ )
185
+
186
+ # Log the response if enabled
187
+ if self.log_requests:
188
+ self.logger.info(
189
+ f"API Response: {response.status_code} {response.reason}\n"
190
+ f"URL: {request_data.url}\n"
191
+ f"Correlation ID: {request_data.correlation_id}\n"
192
+ )
193
+
194
+ # Check for HTTP errors
195
+ response.raise_for_status()
196
+
197
+ # Returns the JSON response
198
+ return response.json()
199
+
200
+ except requests.HTTPError as e:
201
+ self._handle_exception(e, request_data.url, request_data.correlation_id)
202
+
203
+ def _make_request_stream(self, method: str, request_data: RequestData):
204
+ """
205
+ Makes a synchronous HTTP request to the Airia API.
206
+
207
+ Args:
208
+ method (str): The HTTP method (e.g., 'GET', 'POST')
209
+ request_data: A dictionary containing the following request information:
210
+ - url: The endpoint URL for the request
211
+ - headers: HTTP headers to include in the request
212
+ - payload: The JSON payload/body for the request
213
+ - correlation_id: Unique identifier for request tracing
214
+ stream (bool): If True, the response will be streamed instead of downloaded all at once
215
+
216
+ Yields:
217
+ resp (Iterator[str]): Yields chunks of the response as they are received.
218
+
219
+ Raises:
220
+ AiriaAPIError: If the API returns an error response, with details about the error
221
+ requests.HTTPError: For HTTP-related errors
222
+
223
+ Note:
224
+ This is an internal method used by other client methods to make API requests.
225
+ It handles logging, error handling, and API key redaction in error messages.
226
+ """
227
+ try:
228
+ # Make the request
229
+ response = self.session.request(
230
+ method=method,
231
+ url=request_data.url,
232
+ json=request_data.payload,
233
+ headers=request_data.headers,
234
+ timeout=self.timeout,
235
+ stream=True,
236
+ )
237
+
238
+ # Log the response if enabled
239
+ if self.log_requests:
240
+ self.logger.info(
241
+ f"API Response: {response.status_code} {response.reason}\n"
242
+ f"URL: {request_data.url}\n"
243
+ f"Correlation ID: {request_data.correlation_id}\n"
244
+ )
245
+
246
+ # Check for HTTP errors
247
+ response.raise_for_status()
248
+
249
+ # Yields the response content as a stream
250
+ for chunk in response.iter_content():
251
+ yield chunk.decode("utf-8")
252
+
253
+ except requests.HTTPError as e:
254
+ self._handle_exception(e, request_data.url, request_data.correlation_id)
255
+
256
+ @overload
257
+ def execute_pipeline(
258
+ self,
259
+ pipeline_id: str,
260
+ user_input: str,
261
+ debug: Literal[False] = False,
262
+ user_id: Optional[str] = None,
263
+ conversation_id: Optional[str] = None,
264
+ async_output: Literal[False] = False,
265
+ include_tools_response: bool = False,
266
+ images: Optional[List[str]] = None,
267
+ files: Optional[List[str]] = None,
268
+ data_source_folders: Optional[Dict[str, Any]] = None,
269
+ data_source_files: Optional[Dict[str, Any]] = None,
270
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
271
+ current_date_time: Optional[str] = None,
272
+ save_history: bool = True,
273
+ additional_info: Optional[List[Any]] = None,
274
+ prompt_variables: Optional[Dict[str, Any]] = None,
275
+ correlation_id: Optional[str] = None,
276
+ api_version: str = ApiVersion.V2.value,
277
+ ) -> PipelineExecutionResponse: ...
278
+
279
+ @overload
280
+ def execute_pipeline(
281
+ self,
282
+ pipeline_id: str,
283
+ user_input: str,
284
+ debug: Literal[True] = True,
285
+ user_id: Optional[str] = None,
286
+ conversation_id: Optional[str] = None,
287
+ async_output: Literal[False] = False,
288
+ include_tools_response: bool = False,
289
+ images: Optional[List[str]] = None,
290
+ files: Optional[List[str]] = None,
291
+ data_source_folders: Optional[Dict[str, Any]] = None,
292
+ data_source_files: Optional[Dict[str, Any]] = None,
293
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
294
+ current_date_time: Optional[str] = None,
295
+ save_history: bool = True,
296
+ additional_info: Optional[List[Any]] = None,
297
+ prompt_variables: Optional[Dict[str, Any]] = None,
298
+ correlation_id: Optional[str] = None,
299
+ api_version: str = ApiVersion.V2.value,
300
+ ) -> PipelineExecutionDebugResponse: ...
301
+
302
+ @overload
303
+ def execute_pipeline(
304
+ self,
305
+ pipeline_id: str,
306
+ user_input: str,
307
+ debug: bool = False,
308
+ user_id: Optional[str] = None,
309
+ conversation_id: Optional[str] = None,
310
+ async_output: Literal[True] = True,
311
+ include_tools_response: bool = False,
312
+ images: Optional[List[str]] = None,
313
+ files: Optional[List[str]] = None,
314
+ data_source_folders: Optional[Dict[str, Any]] = None,
315
+ data_source_files: Optional[Dict[str, Any]] = None,
316
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
317
+ current_date_time: Optional[str] = None,
318
+ save_history: bool = True,
319
+ additional_info: Optional[List[Any]] = None,
320
+ prompt_variables: Optional[Dict[str, Any]] = None,
321
+ correlation_id: Optional[str] = None,
322
+ api_version: Literal["v2"] = ApiVersion.V2.value,
323
+ ) -> PipelineExecutionV2StreamedResponse: ...
324
+
325
+ @overload
326
+ def execute_pipeline(
327
+ self,
328
+ pipeline_id: str,
329
+ user_input: str,
330
+ debug: bool = False,
331
+ user_id: Optional[str] = None,
332
+ conversation_id: Optional[str] = None,
333
+ async_output: Literal[True] = True,
334
+ include_tools_response: bool = False,
335
+ images: Optional[List[str]] = None,
336
+ files: Optional[List[str]] = None,
337
+ data_source_folders: Optional[Dict[str, Any]] = None,
338
+ data_source_files: Optional[Dict[str, Any]] = None,
339
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
340
+ current_date_time: Optional[str] = None,
341
+ save_history: bool = True,
342
+ additional_info: Optional[List[Any]] = None,
343
+ prompt_variables: Optional[Dict[str, Any]] = None,
344
+ correlation_id: Optional[str] = None,
345
+ api_version: Literal["v1"] = ApiVersion.V1.value,
346
+ ) -> PipelineExecutionV1StreamedResponse: ...
347
+
348
+ def execute_pipeline(
349
+ self,
350
+ pipeline_id: str,
351
+ user_input: str,
352
+ debug: bool = False,
353
+ user_id: Optional[str] = None,
354
+ conversation_id: Optional[str] = None,
355
+ async_output: bool = False,
356
+ include_tools_response: bool = False,
357
+ images: Optional[List[str]] = None,
358
+ files: Optional[List[str]] = None,
359
+ data_source_folders: Optional[Dict[str, Any]] = None,
360
+ data_source_files: Optional[Dict[str, Any]] = None,
361
+ in_memory_messages: Optional[List[Dict[str, str]]] = None,
362
+ current_date_time: Optional[str] = None,
363
+ save_history: bool = True,
364
+ additional_info: Optional[List[Any]] = None,
365
+ prompt_variables: Optional[Dict[str, Any]] = None,
366
+ correlation_id: Optional[str] = None,
367
+ api_version: str = ApiVersion.V2.value,
368
+ ):
369
+ """
370
+ Execute a pipeline with the provided input.
371
+
372
+ Args:
373
+ pipeline_id: The ID of the pipeline to execute.
374
+ user_input: input text to process.
375
+ debug: Whether debug mode execution is enabled. Default is False.
376
+ user_id: Optional ID of the user making the request (guid).
377
+ conversation_id: Optional conversation ID (guid).
378
+ async_output: Whether to stream the response. Default is False.
379
+ include_tools_response: Whether to return the initial LLM tool result. Default is False.
380
+ images: Optional list of images formatted as base64 strings.
381
+ files: Optional list of files formatted as base64 strings.
382
+ data_source_folders: Optional data source folders information.
383
+ data_source_files: Optional data source files information.
384
+ in_memory_messages: Optional list of in-memory messages, each with a role and message.
385
+ current_date_time: Optional current date and time in ISO format.
386
+ save_history: Whether to save the userInput and output to conversation history. Default is True.
387
+ additional_info: Optional additional information.
388
+ prompt_variables: Optional variables to be used in the prompt.
389
+ correlation_id: Optional correlation ID for request tracing. If not provided,
390
+ one will be generated automatically.
391
+ api_version: API version to use. Default is `v2`
392
+
393
+ Returns:
394
+ The API response as a dictionary.
395
+
396
+ Raises:
397
+ AiriaAPIError: If the API request fails with details about the error.
398
+ requests.RequestException: For other request-related errors.
399
+
400
+ Example:
401
+ >>> client = AiriaClient(api_key="your_api_key")
402
+ >>> response = client.execute_pipeline(
403
+ ... pipeline_id="pipeline_123",
404
+ ... user_input="Tell me about quantum computing"
405
+ ... )
406
+ >>> print(response.result)
407
+ """
408
+ request_data = self._pre_execute_pipeline(
409
+ pipeline_id=pipeline_id,
410
+ user_input=user_input,
411
+ debug=debug,
412
+ user_id=user_id,
413
+ conversation_id=conversation_id,
414
+ async_output=async_output,
415
+ include_tools_response=include_tools_response,
416
+ images=images,
417
+ files=files,
418
+ data_source_folders=data_source_folders,
419
+ data_source_files=data_source_files,
420
+ in_memory_messages=in_memory_messages,
421
+ current_date_time=current_date_time,
422
+ save_history=save_history,
423
+ additional_info=additional_info,
424
+ prompt_variables=prompt_variables,
425
+ correlation_id=correlation_id,
426
+ api_version=api_version,
427
+ )
428
+ stream = async_output and api_version == ApiVersion.V2.value
429
+ if stream:
430
+ resp = self._make_request_stream("POST", request_data)
431
+ else:
432
+ resp = self._make_request("POST", request_data)
433
+
434
+ if not async_output:
435
+ if not debug:
436
+ return PipelineExecutionResponse(**resp)
437
+ return PipelineExecutionDebugResponse(**resp)
438
+
439
+ if api_version == ApiVersion.V1.value:
440
+ url = urljoin(
441
+ self.base_url, f"{api_version}/StreamSocketConfig/GenerateUrl"
442
+ )
443
+ request_data = self._prepare_request(
444
+ url,
445
+ {"socketIdentifier": resp},
446
+ request_data.headers["X-Correlation-ID"],
447
+ )
448
+ resp = self._make_request("POST", request_data)
449
+
450
+ return PipelineExecutionV1StreamedResponse(**resp)
451
+
452
+ return PipelineExecutionV2StreamedResponse(stream=resp)
@@ -0,0 +1,19 @@
1
+ from .api_version import ApiVersion
2
+ from .pipeline_execution import (
3
+ PipelineExecutionDebugResponse,
4
+ PipelineExecutionResponse,
5
+ PipelineExecutionV1StreamedResponse,
6
+ PipelineExecutionV2AsyncStreamedResponse,
7
+ PipelineExecutionV2StreamedResponse,
8
+ )
9
+ from .request_data import RequestData
10
+
11
+ __all__ = [
12
+ "ApiVersion",
13
+ "PipelineExecutionDebugResponse",
14
+ "PipelineExecutionResponse",
15
+ "PipelineExecutionV1StreamedResponse",
16
+ "PipelineExecutionV2AsyncStreamedResponse",
17
+ "PipelineExecutionV2StreamedResponse",
18
+ "RequestData",
19
+ ]
@@ -0,0 +1,13 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ApiVersion(Enum):
5
+ """Enum for API Versions."""
6
+
7
+ V1 = "v1"
8
+ V2 = "v2"
9
+
10
+ @classmethod
11
+ def as_list(cls):
12
+ """Return a list of all API Version values."""
13
+ return [version.value for version in cls]
@@ -0,0 +1,31 @@
1
+ from typing import Any, AsyncIterator, Dict, Iterator
2
+
3
+ from pydantic import BaseModel, ConfigDict
4
+
5
+
6
+ class PipelineExecutionResponse(BaseModel):
7
+ result: str
8
+ report: None
9
+ isBackupPipeline: bool
10
+
11
+
12
+ class PipelineExecutionDebugResponse(BaseModel):
13
+ result: str
14
+ report: Dict[str, Any]
15
+ isBackupPipeline: bool
16
+
17
+
18
+ class PipelineExecutionV1StreamedResponse(BaseModel):
19
+ webSocketUrl: str
20
+
21
+
22
+ class PipelineExecutionV2StreamedResponse(BaseModel):
23
+ model_config = ConfigDict(arbitrary_types_allowed=True)
24
+
25
+ stream: Iterator[str]
26
+
27
+
28
+ class PipelineExecutionV2AsyncStreamedResponse(BaseModel):
29
+ model_config = ConfigDict(arbitrary_types_allowed=True)
30
+
31
+ stream: AsyncIterator[str]
@@ -0,0 +1,10 @@
1
+ from typing import Any, Dict
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class RequestData(BaseModel):
7
+ url: str
8
+ payload: Dict[str, Any]
9
+ headers: Dict[str, Any]
10
+ correlation_id: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: airia
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Python SDK for Airia API
5
5
  Author-email: Airia LLC <support@airia.com>
6
6
  License: MIT
@@ -176,6 +176,20 @@ This will create both wheel and source distribution in the `dist/` directory.
176
176
 
177
177
  ## Quick Start
178
178
 
179
+ ### Client Instantiation
180
+
181
+ ```python
182
+ from airia import AiriaClient
183
+
184
+ client = AiriaClient(
185
+ base_url="https://api.airia.com", # Default: "https://api.airia.com"
186
+ api_key=None, # Or set AIRIA_API_KEY environment variable
187
+ timeout=30.0, # Request timeout in seconds (default: 30.0)
188
+ log_requests=False, # Enable request/response logging (default: False)
189
+ custom_logger=None # Use custom logger (default: None - uses built-in)
190
+ )
191
+ ```
192
+
179
193
  ### Synchronous Usage
180
194
 
181
195
  ```python
@@ -208,7 +222,7 @@ response = client.execute_pipeline(
208
222
  async_output=True
209
223
  )
210
224
 
211
- for c in resp.stream:
225
+ for c in response.stream:
212
226
  print(c, end="")
213
227
  ```
214
228
 
@@ -244,7 +258,7 @@ async def main():
244
258
  user_input="Tell me about quantum computing",
245
259
  async_output=True
246
260
  )
247
- async for c in resp.stream:
261
+ async for c in response.stream:
248
262
  print(c, end="")
249
263
 
250
264
  asyncio.run(main())
@@ -292,6 +306,8 @@ response = client.anthropic.messages.create(
292
306
  print(response.content[0].text)
293
307
  ```
294
308
 
309
+ You can set the Gateway URL by passing the `gateway_url` parameter when using the gateway constructors. The default values are `https://gateway.airia.ai/openai/v1` for OpenAI and `https://gateway.airia.ai/anthropic` for Anthropic.
310
+
295
311
  ### Asynchronous Gateway Usage
296
312
 
297
313
  Both gateways also support asynchronous usage:
@@ -0,0 +1,16 @@
1
+ airia/__init__.py,sha256=T39gO8E5T5zxlw-JP78ruxOu7-LeKOJCJzz6t40kdQo,231
2
+ airia/exceptions.py,sha256=4Z55n-cRJrtTa5-pZBIK2oZD4-Z99aUtKx_kfTFYY5o,1146
3
+ airia/logs.py,sha256=17YZ4IuzOF0m5bgofj9-QYlJ2BYR2kRZbBVQfFSLFEk,5441
4
+ airia/client/__init__.py,sha256=6gSQ9bl7j79q1HPE0o5py3IRdkwWWuU_7J4h05Dd2o8,127
5
+ airia/client/async_client.py,sha256=4JU6RePXjznulnQXkfo9ZVX3zLeUyclOgxwlaM7-5Js,18816
6
+ airia/client/base_client.py,sha256=IEVsskGpiEL3jw7YLc96YWUZ5rpUZula52IZHe2D8mE,6844
7
+ airia/client/sync_client.py,sha256=mCLViWkW-z8QhCy8CmlEsT8dssBb1g6V2B3fAYgYU1A,18336
8
+ airia/types/__init__.py,sha256=OOFtJ0VIbO98px89u7cq645iL7CYDOel43g85IAjRRw,562
9
+ airia/types/api_version.py,sha256=Uzom6O2ZG92HN_Z2h-lTydmO2XYX9RVs4Yi4DJmXytE,255
10
+ airia/types/pipeline_execution.py,sha256=obp8KOz-ShNxEciF1YQCSpHXPoJUyEa_9uPv-VHf6YA,699
11
+ airia/types/request_data.py,sha256=RbVPWPRIYuT7FaolJKn19IVzuQKbLM4VhXM5r7UXTUY,186
12
+ airia-0.1.5.dist-info/licenses/LICENSE,sha256=R3ClUMMKPRItIcZ0svzyj2taZZnFYw568YDNzN9KQ1Q,1066
13
+ airia-0.1.5.dist-info/METADATA,sha256=WIPLholUrToVlvO4K269qOSYHT4fD7XHpVSrjowOF6A,10745
14
+ airia-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ airia-0.1.5.dist-info/top_level.txt,sha256=qUQEKfs_hdOYTwjKj1JZbRhS5YeXDNaKQaVTrzabS6w,6
16
+ airia-0.1.5.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- airia/__init__.py,sha256=T39gO8E5T5zxlw-JP78ruxOu7-LeKOJCJzz6t40kdQo,231
2
- airia/exceptions.py,sha256=4Z55n-cRJrtTa5-pZBIK2oZD4-Z99aUtKx_kfTFYY5o,1146
3
- airia/logs.py,sha256=17YZ4IuzOF0m5bgofj9-QYlJ2BYR2kRZbBVQfFSLFEk,5441
4
- airia-0.1.3.dist-info/licenses/LICENSE,sha256=R3ClUMMKPRItIcZ0svzyj2taZZnFYw568YDNzN9KQ1Q,1066
5
- airia-0.1.3.dist-info/METADATA,sha256=9LEQFb6HGNqoTfhn6aX8elSCa5Eaogk43cj2j_pcx4o,9966
6
- airia-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- airia-0.1.3.dist-info/top_level.txt,sha256=qUQEKfs_hdOYTwjKj1JZbRhS5YeXDNaKQaVTrzabS6w,6
8
- airia-0.1.3.dist-info/RECORD,,
File without changes