fundamental-client 0.2.3__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,120 @@
1
+ """
2
+ NEXUS Estimator with public API methods.
3
+
4
+ This module contains NEXUSEstimator which extends BaseNEXUSEstimator with public API methods.
5
+ """
6
+
7
+ from abc import ABC
8
+ from typing import Optional
9
+
10
+ import numpy as np
11
+ from sklearn.utils.validation import check_is_fitted
12
+
13
+ from fundamental.estimator.base import BaseNEXUSEstimator
14
+ from fundamental.services import remote_get_feature_importance
15
+ from fundamental.services.feature_importance import (
16
+ poll_feature_importance_result,
17
+ submit_feature_importance_task,
18
+ )
19
+ from fundamental.utils.data import XType, validate_data, validate_inputs_type
20
+
21
+
22
+ class NEXUSEstimator(BaseNEXUSEstimator, ABC):
23
+ """
24
+ NEXUS Estimator with public API methods.
25
+
26
+ Extends BaseNEXUSEstimator with advanced operations.
27
+ """
28
+
29
+ def get_feature_importance(
30
+ self,
31
+ X: XType,
32
+ ) -> np.ndarray:
33
+ """
34
+ Get feature importance for the fitted model.
35
+
36
+ Submits the task and waits for completion.
37
+
38
+ Parameters
39
+ ----------
40
+ X : XType
41
+ Input features for feature importance computation.
42
+
43
+ Returns
44
+ -------
45
+ np.ndarray
46
+ Feature importance values.
47
+
48
+ Raises
49
+ ------
50
+ NotFittedError
51
+ If the model has not been fitted yet.
52
+ """
53
+ validate_inputs_type(X=X)
54
+ validate_data(X=X)
55
+ check_is_fitted(self)
56
+ assert self.trained_model_id_ is not None
57
+ return remote_get_feature_importance(
58
+ X=X,
59
+ trained_model_id=self.trained_model_id_,
60
+ client=self._get_client(),
61
+ )
62
+
63
+ def submit_feature_importance_task(
64
+ self,
65
+ X: XType,
66
+ ) -> str:
67
+ """
68
+ Submit a feature importance computation task without waiting for completion.
69
+
70
+ Parameters
71
+ ----------
72
+ X : XType
73
+ Input features for feature importance computation.
74
+
75
+ Returns
76
+ -------
77
+ str
78
+ The task ID to use with poll_feature_importance_result.
79
+
80
+ Raises
81
+ ------
82
+ NotFittedError
83
+ If the model has not been fitted yet.
84
+ """
85
+ validate_inputs_type(X=X)
86
+ validate_data(X=X)
87
+ check_is_fitted(self)
88
+ assert self.trained_model_id_ is not None
89
+ return submit_feature_importance_task(
90
+ X=X,
91
+ trained_model_id=self.trained_model_id_,
92
+ client=self._get_client(),
93
+ )
94
+
95
+ def poll_feature_importance_result(self, task_id: str) -> Optional[np.ndarray]:
96
+ """
97
+ Check the status of a feature importance task.
98
+
99
+ Parameters
100
+ ----------
101
+ task_id : str
102
+ The task ID returned by submit_feature_importance_task.
103
+
104
+ Returns
105
+ -------
106
+ Optional[np.ndarray]
107
+ Feature importance values if completed, None if still in progress.
108
+
109
+ Raises
110
+ ------
111
+ NotFittedError
112
+ If the model has not been fitted yet.
113
+ """
114
+ check_is_fitted(self)
115
+ assert self.trained_model_id_ is not None
116
+ return poll_feature_importance_result(
117
+ task_id=task_id,
118
+ trained_model_id=self.trained_model_id_,
119
+ client=self._get_client(),
120
+ )
@@ -0,0 +1,22 @@
1
+ """NEXUS Regression estimator."""
2
+
3
+ import logging
4
+ from typing import Literal
5
+
6
+ from sklearn.base import RegressorMixin
7
+
8
+ from fundamental.estimator.nexus_estimator import NEXUSEstimator
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class NEXUSRegressor(RegressorMixin, NEXUSEstimator):
14
+ """NEXUS Model for Regression Tasks."""
15
+
16
+ _task_type = "regression" # type: ignore[assignment]
17
+
18
+ def __init__(
19
+ self,
20
+ mode: Literal["quality", "speed"] = "quality",
21
+ ):
22
+ super().__init__(mode=mode)
@@ -0,0 +1,78 @@
1
+ """Custom exceptions for NEXUS Client SDK."""
2
+
3
+ from typing import Any, Dict, Literal, Optional
4
+
5
+
6
+ class NEXUSError(Exception):
7
+ """Base exception for all NEXUS client errors."""
8
+
9
+ def __init__(
10
+ self,
11
+ message: str,
12
+ details: Optional[Dict[str, Any]] = None,
13
+ trace_id: Optional[str] = None,
14
+ ):
15
+ super().__init__(message)
16
+ self.details = details or {}
17
+ self.trace_id = trace_id
18
+
19
+
20
+ class HTTPError(NEXUSError):
21
+ """Base class for HTTP errors with status codes."""
22
+
23
+ status_code: int
24
+
25
+ def __str__(self) -> str:
26
+ return f"HTTP {self.status_code}: {super().__str__()}"
27
+
28
+
29
+ class ValidationError(HTTPError):
30
+ """Raised when input validation fails."""
31
+
32
+ status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride]
33
+
34
+
35
+ class AuthenticationError(HTTPError):
36
+ """Raised when authentication fails."""
37
+
38
+ status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride]
39
+
40
+
41
+ class AuthorizationError(HTTPError):
42
+ """Raised when authorization fails."""
43
+
44
+ status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride]
45
+
46
+
47
+ class NotFoundError(HTTPError):
48
+ """Raised when resource is not found."""
49
+
50
+ status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride]
51
+
52
+
53
+ class RateLimitError(HTTPError):
54
+ """Raised when API rate limits are exceeded."""
55
+
56
+ status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride]
57
+
58
+
59
+ class ServerError(HTTPError):
60
+ """Raised when server returns 5xx errors."""
61
+
62
+ status_code: int = 500
63
+
64
+
65
+ class NetworkError(HTTPError):
66
+ """Raised when network connectivity issues occur."""
67
+
68
+ status_code: Literal[503] = 503 # pyright: ignore[reportIncompatibleVariableOverride]
69
+
70
+
71
+ class RequestTimeoutError(HTTPError):
72
+ """Raised when requests timeout."""
73
+
74
+ status_code: Literal[504] = 504 # pyright: ignore[reportIncompatibleVariableOverride]
75
+
76
+
77
+ # Deprecated alias for backward compatibility
78
+ FTMError = NEXUSError
@@ -0,0 +1,4 @@
1
+ # Auto-generated Pydantic models from OpenAPI spec
2
+ # Run `scripts/generate-models` to regenerate
3
+
4
+ from fundamental.models.generated import * # noqa: F403
@@ -0,0 +1,431 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: openapi.json
3
+ # timestamp: 2026-01-21T12:25:52+00:00
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+
9
+ from pydantic import AwareDatetime, BaseModel, Field, RootModel
10
+
11
+
12
+ class BYOBSettings(BaseModel):
13
+ enabled: bool = Field(..., description="Whether BYOB is enabled", title="Enabled")
14
+ role_arn: str | None = Field(
15
+ default=None, description="AWS IAM role ARN for assuming role", title="Role Arn"
16
+ )
17
+ external_id: str | None = Field(
18
+ default=None, description="External ID for role assumption", title="External Id"
19
+ )
20
+ data_bucket_name: str | None = Field(
21
+ default=None,
22
+ description="S3 bucket name for temporary data",
23
+ title="Data Bucket Name",
24
+ )
25
+ model_bucket_name: str | None = Field(
26
+ default=None,
27
+ description="S3 bucket name for trained models",
28
+ title="Model Bucket Name",
29
+ )
30
+
31
+
32
+ class BaseModelResultWithEvalMetric(BaseModel):
33
+ name: str = Field(..., description="Name of the model", title="Name")
34
+ type: str = Field(..., description="Type of model (internal or external)", title="Type")
35
+ success: bool = Field(
36
+ ..., description="Whether the model execution was successful", title="Success"
37
+ )
38
+ eval_metric: float | None = Field(
39
+ default=None, description="Model evaluation metric value", title="Eval Metric"
40
+ )
41
+
42
+
43
+ class BodyFitPredictApiV1ModelFitPredictPost(BaseModel):
44
+ task: str = Field(..., description="Task type: 'classification' or 'regression'", title="Task")
45
+ target_column: str = Field(
46
+ ...,
47
+ description="Name of the target column in both train and test datasets",
48
+ title="Target Column",
49
+ )
50
+ train_dataset: bytes = Field(
51
+ ...,
52
+ description="Training dataset CSV file containing features and target",
53
+ title="Train Dataset",
54
+ )
55
+ test_dataset: bytes = Field(
56
+ ...,
57
+ description="Test dataset CSV file containing features and target",
58
+ title="Test Dataset",
59
+ )
60
+
61
+
62
+ class CompleteMultipartUploadPart(BaseModel):
63
+ PartNumber: int = Field(..., description="Part number (1-indexed)", title="Partnumber")
64
+ ETag: str = Field(..., description="ETag from part upload response", title="Etag")
65
+
66
+
67
+ class FileType(Enum):
68
+ X_TRAIN = "x_train"
69
+ Y_TRAIN = "y_train"
70
+ X_TEST = "x_test"
71
+ X_FEATURE_IMPORTANCE = "x_feature_importance"
72
+ Y_FEATURE_IMPORTANCE = "y_feature_importance"
73
+
74
+
75
+ class CompleteMultipartUploadRequest(BaseModel):
76
+ trained_model_id: str = Field(..., description="Trained model ID", title="Trained Model Id")
77
+ file_type: FileType = Field(..., description="Type of file being uploaded", title="File Type")
78
+ upload_id: str = Field(..., description="Multipart upload ID", title="Upload Id")
79
+ parts: list[CompleteMultipartUploadPart] = Field(
80
+ ..., description="List of uploaded parts with their ETags", title="Parts"
81
+ )
82
+ request_id: str | None = Field(
83
+ default=None,
84
+ description="Request ID (required for x_test, x_feature_importance, and y_feature_importance uploads)",
85
+ title="Request Id",
86
+ )
87
+
88
+
89
+ class CompleteMultipartUploadResponse(BaseModel):
90
+ message: str = Field(..., description="Success message", title="Message")
91
+ object_key: str = Field(
92
+ ..., description="S3 object key of the completed upload", title="Object Key"
93
+ )
94
+
95
+
96
+ class CreateAPIKeyRequest(BaseModel):
97
+ key_name: str = Field(
98
+ ...,
99
+ description="Human-readable name for the API key",
100
+ max_length=100,
101
+ min_length=1,
102
+ title="Key Name",
103
+ )
104
+
105
+
106
+ class CreateAPIKeyResponse(BaseModel):
107
+ message: str = Field(..., description="Success message", title="Message")
108
+ api_key: str = Field(..., description="Generated API key", title="Api Key")
109
+ key_name: str = Field(..., description="Name of the API key", title="Key Name")
110
+ organization_id: str = Field(..., description="Organization ID", title="Organization Id")
111
+ expires_at: AwareDatetime | None = Field(
112
+ default=None, description="API key expiration time", title="Expires At"
113
+ )
114
+ created_at: AwareDatetime = Field(..., description="API key creation time", title="Created At")
115
+ creator: str = Field(..., description="User ID who created this API key", title="Creator")
116
+
117
+
118
+ class DailyUsage(BaseModel):
119
+ date: str = Field(..., description="Date in YYYY-MM-DD format", title="Date")
120
+ usage_count: int = Field(
121
+ ...,
122
+ description="Total usage count (predict + fit-predict)",
123
+ title="Usage Count",
124
+ )
125
+
126
+
127
+ class DeleteTrainedModelResponse(BaseModel):
128
+ message: str = Field(..., description="Success message", title="Message")
129
+ trained_model_id: str = Field(
130
+ ..., description="Deleted trained model ID", title="Trained Model Id"
131
+ )
132
+ user_id: str = Field(..., description="User ID", title="User Id")
133
+
134
+
135
+ class FeatureImportanceMultipartMetadataRequest(BaseModel):
136
+ trained_model_id: str = Field(
137
+ ..., description="Trained model ID from training", title="Trained Model Id"
138
+ )
139
+ x_size: int = Field(..., description="Size of X data file in bytes", gt=0, title="X Size")
140
+
141
+
142
+ class FeatureImportanceRequest(BaseModel):
143
+ trained_model_id: str = Field(..., description="Trained model ID", title="Trained Model Id")
144
+ request_id: str = Field(
145
+ ..., description="Request ID from metadata generation", title="Request Id"
146
+ )
147
+
148
+
149
+ class FeatureImportanceResponse(BaseModel):
150
+ task_id: str = Field(
151
+ ..., description="Task ID for the feature importance request", title="Task Id"
152
+ )
153
+
154
+
155
+ class FitMultipartMetadataRequest(BaseModel):
156
+ x_train_size: int = Field(
157
+ ..., description="Size of x_train file in bytes", gt=0, title="X Train Size"
158
+ )
159
+ y_train_size: int = Field(
160
+ ..., description="Size of y_train file in bytes", gt=0, title="Y Train Size"
161
+ )
162
+
163
+
164
+ class FitPredictResponse(BaseModel):
165
+ metric_name: str = Field(
166
+ ..., description="Name of the evaluation metric used", title="Metric Name"
167
+ )
168
+ csv_data: str = Field(
169
+ ..., description="Base64-encoded CSV data with predictions", title="Csv Data"
170
+ )
171
+ csv_filename: str = Field(
172
+ ..., description="Filename for the CSV download", title="Csv Filename"
173
+ )
174
+ models: list[BaseModelResultWithEvalMetric] = Field(
175
+ ..., description="List of model results", title="Models"
176
+ )
177
+
178
+
179
+ class Task(Enum):
180
+ CLASSIFICATION = "classification"
181
+ REGRESSION = "regression"
182
+
183
+
184
+ class Mode(Enum):
185
+ QUALITY = "quality"
186
+ SPEED = "speed"
187
+
188
+
189
+ class Timeout(RootModel[int]):
190
+ root: int = Field(..., description="Time limit in seconds", gt=0, title="Timeout")
191
+
192
+
193
+ class FitRequest(BaseModel):
194
+ trained_model_id: str = Field(
195
+ ...,
196
+ description="Trained model ID from metadata generation",
197
+ title="Trained Model Id",
198
+ )
199
+ task: Task = Field(..., description="Task type for the model", title="Task")
200
+ mode: Mode | None = Field(
201
+ default=None, description="Training mode: 'quality' or 'speed'", title="Mode"
202
+ )
203
+ timeout: Timeout | None = Field(
204
+ default=None, description="Time limit in seconds", title="Timeout"
205
+ )
206
+
207
+
208
+ class FitResponse(BaseModel):
209
+ trained_model_id: str = Field(
210
+ ...,
211
+ description="Trained model ID for this fitted model",
212
+ title="Trained Model Id",
213
+ )
214
+ task_id: str = Field(..., description="task id", title="Task Id")
215
+ status_code: int = Field(..., description="HTTP status code", title="Status Code")
216
+ error_codes: list[str] | None = Field(
217
+ default=[], description="List of error codes if any", title="Error Codes"
218
+ )
219
+
220
+
221
+ class MaskedApiKeyInfo(BaseModel):
222
+ key_name: str = Field(..., description="Human-readable name for the API key", title="Key Name")
223
+ api_key_suffix: str = Field(
224
+ ..., description="Last 4 characters of the API key", title="Api Key Suffix"
225
+ )
226
+ api_key_hash: str = Field(..., description="Hash of the API key", title="Api Key Hash")
227
+ organization_id: str = Field(
228
+ ..., description="Associated organization ID", title="Organization Id"
229
+ )
230
+ created_at: AwareDatetime = Field(..., description="Creation timestamp", title="Created At")
231
+ expires_at: AwareDatetime | None = Field(
232
+ default=None, description="Expiration timestamp", title="Expires At"
233
+ )
234
+ creator: str = Field(..., description="User ID who created this API key", title="Creator")
235
+
236
+
237
+ class MultipartUploadInfo(BaseModel):
238
+ upload_id: str = Field(..., description="S3 multipart upload ID", title="Upload Id")
239
+ upload_urls: list[str] = Field(
240
+ ..., description="List of presigned URLs for each part", title="Upload Urls"
241
+ )
242
+ num_parts: int = Field(..., description="Number of parts to upload", title="Num Parts")
243
+ part_size: int = Field(..., description="Size of each part in bytes", title="Part Size")
244
+
245
+
246
+ class OrganizationSettings(BaseModel):
247
+ bring_your_own_bucket: BYOBSettings | None = Field(
248
+ default=None, description="Bring Your Own Bucket settings"
249
+ )
250
+
251
+
252
+ class PredictMultipartMetadataRequest(BaseModel):
253
+ trained_model_id: str = Field(
254
+ ..., description="Trained model ID from training", title="Trained Model Id"
255
+ )
256
+ x_test_size: int = Field(
257
+ ..., description="Size of x_test file in bytes", gt=0, title="X Test Size"
258
+ )
259
+
260
+
261
+ class PredictMultipartMetadataResponse(BaseModel):
262
+ request_id: str = Field(
263
+ ..., description="Request ID for tracking the upload", title="Request Id"
264
+ )
265
+ part_size: int = Field(..., description="Size of each part in bytes", title="Part Size")
266
+ upload_id: str = Field(..., description="S3 multipart upload ID", title="Upload Id")
267
+ upload_urls: list[str] = Field(
268
+ ..., description="List of presigned URLs for each part", title="Upload Urls"
269
+ )
270
+ num_parts: int = Field(..., description="Number of parts to upload", title="Num Parts")
271
+ trace_id: str = Field(
272
+ ..., description="Root trace ID for the predict operation", title="Trace Id"
273
+ )
274
+ span_id: str = Field(..., description="Span ID for the predict operation", title="Span Id")
275
+
276
+
277
+ class PredictRequest(BaseModel):
278
+ trained_model_id: str = Field(
279
+ ..., description="Trained model ID from training", title="Trained Model Id"
280
+ )
281
+ request_id: str = Field(
282
+ ..., description="Request ID from metadata generation", title="Request Id"
283
+ )
284
+ output_type: str | None = Field(
285
+ default="preds",
286
+ description="Output type: 'preds' or 'probas'",
287
+ title="Output Type",
288
+ )
289
+ timeout: Timeout | None = Field(
290
+ default=None, description="Time limit in seconds", title="Timeout"
291
+ )
292
+
293
+
294
+ class PredictResponse(BaseModel):
295
+ request_id: str = Field(
296
+ ..., description="Request ID for the prediction request", title="Request Id"
297
+ )
298
+ task_id: str = Field(..., description="Task ID for the prediction request", title="Task Id")
299
+
300
+
301
+ class RevokeAPIKeyRequest(BaseModel):
302
+ api_key_hash: str = Field(
303
+ ..., description="Hash of the API key to revoke", title="Api Key Hash"
304
+ )
305
+
306
+
307
+ class RevokeAPIKeyResponse(BaseModel):
308
+ message: str = Field(..., description="Success message", title="Message")
309
+ organization_id: str = Field(..., description="Organization ID", title="Organization Id")
310
+ status: str = Field(..., description="Revocation status", title="Status")
311
+
312
+
313
+ class TaskResult(BaseModel):
314
+ download_url: str = Field(
315
+ ..., description="Presigned URL to download task results", title="Download Url"
316
+ )
317
+
318
+
319
+ class TaskStatus(Enum):
320
+ SUCCESS = "success"
321
+ IN_PROGRESS = "in_progress"
322
+ VALIDATION_ERROR = "validation_error"
323
+
324
+
325
+ class TaskStatusResponse(BaseModel):
326
+ status: TaskStatus = Field(..., description="Task state (in_progress, success)")
327
+ result: TaskResult | None = Field(
328
+ default=None,
329
+ description="Task result with download URL when successful, None otherwise",
330
+ )
331
+
332
+
333
+ class TrainedModelFields(BaseModel):
334
+ estimator_fields: bytes = Field(
335
+ ..., description="Trained model fields file", title="Estimator Fields"
336
+ )
337
+
338
+
339
+ class TrainedModelListResponse(RootModel[list[str]]):
340
+ root: list[str] = Field(
341
+ ...,
342
+ description="Model that returns just a list directly, no wrapper key.",
343
+ examples=[["user_123_model_abc", "user_123_model_def"]],
344
+ title="TrainedModelListResponse",
345
+ )
346
+
347
+
348
+ class TrainedModelMetadata(BaseModel):
349
+ trained_model_id: str = Field(..., description="Trained model ID", title="Trained Model Id")
350
+ attributes: dict[str, str] = Field(
351
+ default_factory=dict,
352
+ description="Structured key/value labels for organization",
353
+ title="Attributes",
354
+ )
355
+
356
+
357
+ class UpdateAttributesRequest(BaseModel):
358
+ attributes: dict[str, str] = Field(
359
+ ...,
360
+ description="Structured key/value labels for organization (max 20 pairs)",
361
+ title="Attributes",
362
+ )
363
+
364
+
365
+ class UpdateAttributesResponse(BaseModel):
366
+ attributes: dict[str, str] = Field(..., description="Updated attributes", title="Attributes")
367
+
368
+
369
+ class UpdateSettingsRequest(BaseModel):
370
+ settings: OrganizationSettings = Field(..., description="Organization settings to update")
371
+
372
+
373
+ class UpdateSettingsResponse(BaseModel):
374
+ message: str = Field(..., description="Success message", title="Message")
375
+ organization_id: str = Field(..., description="Organization ID", title="Organization Id")
376
+
377
+
378
+ class ValidationError(BaseModel):
379
+ loc: list[str | int] = Field(..., title="Location")
380
+ msg: str = Field(..., title="Message")
381
+ type: str = Field(..., title="Error Type")
382
+
383
+
384
+ class AnalyticsResponse(BaseModel):
385
+ week_start: str = Field(
386
+ ..., description="Week start date in YYYY-MM-DD format", title="Week Start"
387
+ )
388
+ daily_usage: list[DailyUsage] = Field(
389
+ ..., description="Daily usage breakdown for 7 days", title="Daily Usage"
390
+ )
391
+
392
+
393
+ class FeatureImportanceMultipartMetadataResponse(BaseModel):
394
+ request_id: str = Field(
395
+ ..., description="Request ID for tracking the upload", title="Request Id"
396
+ )
397
+ x_upload: MultipartUploadInfo = Field(..., description="X data multipart upload info")
398
+ trace_id: str = Field(
399
+ ...,
400
+ description="Root trace ID for the feature importance operation",
401
+ title="Trace Id",
402
+ )
403
+ span_id: str = Field(
404
+ ..., description="Span ID for the feature importance operation", title="Span Id"
405
+ )
406
+
407
+
408
+ class FitMultipartMetadataResponse(BaseModel):
409
+ trained_model_id: str = Field(
410
+ ..., description="Generated trained model ID", title="Trained Model Id"
411
+ )
412
+ x_train_upload: MultipartUploadInfo = Field(..., description="X train multipart upload info")
413
+ y_train_upload: MultipartUploadInfo = Field(..., description="Y train multipart upload info")
414
+ trace_id: str = Field(..., description="Root trace ID for the fit operation", title="Trace Id")
415
+ span_id: str = Field(..., description="Span ID for the fit operation", title="Span Id")
416
+
417
+
418
+ class GetSettingsResponse(BaseModel):
419
+ organization_id: str = Field(..., description="Organization ID", title="Organization Id")
420
+ settings: OrganizationSettings = Field(..., description="Organization settings")
421
+
422
+
423
+ class HTTPValidationError(BaseModel):
424
+ detail: list[ValidationError] | None = Field(default=None, title="Detail")
425
+
426
+
427
+ class ListAPIKeysResponse(BaseModel):
428
+ organization_id: str = Field(..., description="Organization ID", title="Organization Id")
429
+ organization_name: str = Field(..., description="Organization name", title="Organization Name")
430
+ api_keys: list[MaskedApiKeyInfo] = Field(..., description="List of API keys", title="Api Keys")
431
+ total_count: int = Field(..., description="Total number of API keys", title="Total Count")
@@ -0,0 +1,25 @@
1
+ """Services package for NEXUS client."""
2
+
3
+ from fundamental.services.feature_importance import (
4
+ poll_feature_importance_result,
5
+ remote_get_feature_importance,
6
+ submit_feature_importance_task,
7
+ )
8
+ from fundamental.services.inference import (
9
+ poll_fit_result,
10
+ remote_fit,
11
+ remote_predict,
12
+ submit_fit_task,
13
+ )
14
+ from fundamental.services.models import ModelsService
15
+
16
+ __all__ = [
17
+ "ModelsService",
18
+ "poll_feature_importance_result",
19
+ "poll_fit_result",
20
+ "remote_fit",
21
+ "remote_get_feature_importance",
22
+ "remote_predict",
23
+ "submit_feature_importance_task",
24
+ "submit_fit_task",
25
+ ]