seekrai 0.4.2__py3-none-any.whl → 0.5.0__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.
Files changed (48) hide show
  1. seekrai/__init__.py +0 -1
  2. seekrai/abstract/api_requestor.py +108 -251
  3. seekrai/abstract/response_parsing.py +99 -0
  4. seekrai/client.py +12 -0
  5. seekrai/filemanager.py +181 -3
  6. seekrai/resources/__init__.py +10 -0
  7. seekrai/resources/agents/__init__.py +13 -0
  8. seekrai/resources/agents/agent_inference.py +277 -0
  9. seekrai/resources/agents/agents.py +272 -0
  10. seekrai/resources/agents/threads.py +454 -0
  11. seekrai/resources/alignment.py +3 -9
  12. seekrai/resources/completions.py +3 -9
  13. seekrai/resources/deployments.py +4 -9
  14. seekrai/resources/embeddings.py +3 -9
  15. seekrai/resources/files.py +163 -48
  16. seekrai/resources/finetune.py +3 -9
  17. seekrai/resources/images.py +3 -5
  18. seekrai/resources/ingestion.py +173 -0
  19. seekrai/resources/models.py +35 -124
  20. seekrai/resources/projects.py +4 -9
  21. seekrai/resources/resource_base.py +10 -0
  22. seekrai/resources/vectordb.py +482 -0
  23. seekrai/types/__init__.py +87 -0
  24. seekrai/types/agents/__init__.py +89 -0
  25. seekrai/types/agents/agent.py +42 -0
  26. seekrai/types/agents/runs.py +117 -0
  27. seekrai/types/agents/threads.py +265 -0
  28. seekrai/types/agents/tools/__init__.py +16 -0
  29. seekrai/types/agents/tools/env_model_config.py +7 -0
  30. seekrai/types/agents/tools/schemas/__init__.py +8 -0
  31. seekrai/types/agents/tools/schemas/file_search.py +9 -0
  32. seekrai/types/agents/tools/schemas/file_search_env.py +11 -0
  33. seekrai/types/agents/tools/tool.py +14 -0
  34. seekrai/types/agents/tools/tool_env_types.py +4 -0
  35. seekrai/types/agents/tools/tool_types.py +10 -0
  36. seekrai/types/alignment.py +6 -2
  37. seekrai/types/common.py +7 -2
  38. seekrai/types/files.py +5 -0
  39. seekrai/types/finetune.py +1 -0
  40. seekrai/types/ingestion.py +29 -0
  41. seekrai/types/models.py +3 -0
  42. seekrai/types/vectordb.py +78 -0
  43. {seekrai-0.4.2.dist-info → seekrai-0.5.0.dist-info}/METADATA +3 -3
  44. seekrai-0.5.0.dist-info/RECORD +67 -0
  45. {seekrai-0.4.2.dist-info → seekrai-0.5.0.dist-info}/WHEEL +1 -1
  46. seekrai-0.4.2.dist-info/RECORD +0 -46
  47. {seekrai-0.4.2.dist-info → seekrai-0.5.0.dist-info}/LICENSE +0 -0
  48. {seekrai-0.4.2.dist-info → seekrai-0.5.0.dist-info}/entry_points.txt +0 -0
@@ -5,6 +5,7 @@ from typing import Any, Dict
5
5
 
6
6
  from seekrai.abstract import api_requestor
7
7
  from seekrai.filemanager import DownloadManager, UploadManager
8
+ from seekrai.resources.resource_base import ResourceBase
8
9
  from seekrai.seekrflow_response import SeekrFlowResponse
9
10
  from seekrai.types import (
10
11
  FileDeleteResponse,
@@ -12,7 +13,6 @@ from seekrai.types import (
12
13
  FileObject,
13
14
  FilePurpose,
14
15
  FileResponse,
15
- SeekrFlowClient,
16
16
  SeekrFlowRequest,
17
17
  )
18
18
  from seekrai.types.files import (
@@ -22,19 +22,17 @@ from seekrai.types.files import (
22
22
  from seekrai.utils import normalize_key
23
23
 
24
24
 
25
- class Files:
26
- def __init__(self, client: SeekrFlowClient) -> None:
27
- self._client = client
25
+ def _get_local_file_metadata(file_path: Path) -> Dict[str, Any]:
26
+ suffix = file_path.suffix.lstrip(".")
27
+ size_bytes = int(file_path.stat().st_size)
28
+ return {
29
+ "suffix": suffix,
30
+ "size_bytes": size_bytes,
31
+ "filename": file_path.name,
32
+ }
28
33
 
29
- def _get_local_file_metadata(self, file_path: Path) -> Dict[str, Any]:
30
- suffix = file_path.suffix.lstrip(".")
31
- size_bytes = int(file_path.stat().st_size)
32
- return {
33
- "suffix": suffix,
34
- "size_bytes": size_bytes,
35
- "filename": file_path.name,
36
- }
37
34
 
35
+ class Files(ResourceBase):
38
36
  def upload(
39
37
  self, file: Path | str, *, purpose: FilePurpose | str = FilePurpose.FineTune
40
38
  ) -> FileResponse:
@@ -48,7 +46,7 @@ class Files:
48
46
 
49
47
  # Do the metadata validation (fail fast before uploading) for Alignment purpose
50
48
  if purpose == FilePurpose.Alignment:
51
- file_metadata = self._get_local_file_metadata(file)
49
+ file_metadata = _get_local_file_metadata(file)
52
50
  suffix = file_metadata["suffix"]
53
51
  size = file_metadata["size_bytes"]
54
52
  metadata_validation = self.validate_align_file_metadata(
@@ -71,30 +69,55 @@ class Files:
71
69
 
72
70
  return file_response
73
71
 
74
- def list(self) -> FileList:
75
- requestor = api_requestor.APIRequestor(
76
- client=self._client,
77
- )
72
+ def bulk_upload(
73
+ self,
74
+ files: list[Path | str],
75
+ *,
76
+ purpose: FilePurpose | str = FilePurpose.FineTune,
77
+ ) -> list[FileResponse]:
78
+ """
79
+ Upload multiple files in bulk.
80
+
81
+ Args:
82
+ files: List of file paths to upload
83
+ purpose: The purpose of the files (defaults to FineTune)
84
+
85
+ Returns:
86
+ List of FileResponse objects for each uploaded file
87
+ """
88
+ if isinstance(purpose, str):
89
+ purpose = FilePurpose(purpose)
78
90
 
79
- response, _, _ = requestor.request(
80
- options=SeekrFlowRequest(
81
- method="GET",
82
- url="flow/files",
83
- ),
84
- stream=False,
91
+ assert isinstance(purpose, FilePurpose)
92
+
93
+ # Convert string paths to Path objects
94
+ file_paths = [Path(file) if isinstance(file, str) else file for file in files]
95
+
96
+ # Validate all files before uploading (fail fast)
97
+ if purpose == FilePurpose.Alignment:
98
+ for file_path in file_paths:
99
+ file_metadata = _get_local_file_metadata(file_path)
100
+ suffix = file_metadata["suffix"]
101
+ size = file_metadata["size_bytes"]
102
+ metadata_validation = self.validate_align_file_metadata(
103
+ purpose,
104
+ suffix,
105
+ size,
106
+ )
107
+
108
+ if not metadata_validation.is_valid:
109
+ assert metadata_validation.errors is not None # To appease linter
110
+ raise ValueError(
111
+ f"Alignment file metadata validation failed for {file_path.name}: {metadata_validation.errors}"
112
+ )
113
+
114
+ # Upload the files to s3
115
+ upload_manager = UploadManager(self._client)
116
+ file_responses = upload_manager.bulk_upload(
117
+ "flow/bulk_files", file_paths, purpose=purpose, redirect=True
85
118
  )
86
119
 
87
- assert isinstance(response, SeekrFlowResponse)
88
- files = [
89
- FileResponse(
90
- id=file["id"],
91
- filename=file["filename"],
92
- created_at=file["created_at"],
93
- object="file",
94
- )
95
- for file in response.data["data"]
96
- ]
97
- return FileList(object="list", data=files)
120
+ return file_responses
98
121
 
99
122
  def retrieve(self, id: str) -> FileResponse:
100
123
  requestor = api_requestor.APIRequestor(
@@ -167,29 +190,19 @@ class Files:
167
190
  options=SeekrFlowRequest(
168
191
  method="POST",
169
192
  url="flow/files/validate_metadata",
170
- params=request_body.dict(),
193
+ params=request_body.model_dump(),
171
194
  ),
172
195
  stream=False,
173
196
  )
174
197
 
175
198
  return AlignFileMetadataValidationResp(**response.data)
176
199
 
177
-
178
- class AsyncFiles:
179
- def __init__(self, client: SeekrFlowClient) -> None:
180
- self._client = client
181
-
182
- async def upload(
183
- self, file: Path | str, *, purpose: FilePurpose | str = FilePurpose.FineTune
184
- ) -> None:
185
- raise NotImplementedError()
186
-
187
- async def list(self) -> FileList:
200
+ def list(self) -> FileList:
188
201
  requestor = api_requestor.APIRequestor(
189
202
  client=self._client,
190
203
  )
191
204
 
192
- response, _, _ = await requestor.arequest(
205
+ response, _, _ = requestor.request(
193
206
  options=SeekrFlowRequest(
194
207
  method="GET",
195
208
  url="flow/files",
@@ -198,8 +211,43 @@ class AsyncFiles:
198
211
  )
199
212
 
200
213
  assert isinstance(response, SeekrFlowResponse)
214
+ files = [
215
+ FileResponse(
216
+ id=file["id"],
217
+ filename=file["filename"],
218
+ created_at=file["created_at"],
219
+ object="file",
220
+ )
221
+ for file in response.data["data"]
222
+ ]
223
+ return FileList(object="list", data=files)
201
224
 
202
- return FileList(**response.data)
225
+
226
+ class AsyncFiles(ResourceBase):
227
+ async def validate_align_file_metadata(
228
+ self,
229
+ purpose: FilePurpose,
230
+ suffix: str,
231
+ size: int,
232
+ ) -> AlignFileMetadataValidationResp:
233
+ requestor = api_requestor.APIRequestor(client=self._client)
234
+
235
+ request_body = AlignFileMetadataValidationReq(
236
+ purpose=purpose,
237
+ suffix=suffix,
238
+ size=size,
239
+ )
240
+
241
+ response, _, _ = await requestor.arequest(
242
+ options=SeekrFlowRequest(
243
+ method="POST",
244
+ url="flow/files/validate_metadata",
245
+ params=request_body.model_dump(),
246
+ ),
247
+ stream=False,
248
+ )
249
+
250
+ return AlignFileMetadataValidationResp(**response.data)
203
251
 
204
252
  async def retrieve(self, id: str) -> FileResponse:
205
253
  requestor = api_requestor.APIRequestor(
@@ -239,3 +287,70 @@ class AsyncFiles:
239
287
  assert isinstance(response, SeekrFlowResponse)
240
288
 
241
289
  return FileDeleteResponse(**response.data)
290
+
291
+ async def bulk_upload(
292
+ self,
293
+ files: list[Path | str],
294
+ *,
295
+ purpose: FilePurpose | str = FilePurpose.FineTune,
296
+ ) -> list[FileResponse]:
297
+ """
298
+ Upload multiple files in bulk asynchronously.
299
+
300
+ Args:
301
+ files: List of file paths to upload
302
+ purpose: The purpose of the files (defaults to FineTune)
303
+
304
+ Returns:
305
+ List of FileResponse objects for each uploaded file
306
+ """
307
+ if isinstance(purpose, str):
308
+ purpose = FilePurpose(purpose)
309
+
310
+ assert isinstance(purpose, FilePurpose)
311
+
312
+ # Convert string paths to Path objects
313
+ file_paths = [Path(file) if isinstance(file, str) else file for file in files]
314
+
315
+ # Validate all files before uploading (fail fast)
316
+ if purpose == FilePurpose.Alignment:
317
+ for file_path in file_paths:
318
+ file_metadata = _get_local_file_metadata(file_path)
319
+ suffix = file_metadata["suffix"]
320
+ size = file_metadata["size_bytes"]
321
+ metadata_validation = await self.validate_align_file_metadata(
322
+ purpose,
323
+ suffix,
324
+ size,
325
+ )
326
+
327
+ if not metadata_validation.is_valid:
328
+ assert metadata_validation.errors is not None # To appease linter
329
+ raise ValueError(
330
+ f"Alignment file metadata validation failed for {file_path.name}: {metadata_validation.errors}"
331
+ )
332
+
333
+ # Upload the files to s3
334
+ upload_manager = UploadManager(self._client)
335
+ file_responses = await upload_manager.bulk_upload_async(
336
+ "flow/bulk_files", file_paths, purpose=purpose, redirect=True
337
+ )
338
+
339
+ return file_responses
340
+
341
+ async def list(self) -> FileList:
342
+ requestor = api_requestor.APIRequestor(
343
+ client=self._client,
344
+ )
345
+
346
+ response, _, _ = await requestor.arequest(
347
+ options=SeekrFlowRequest(
348
+ method="GET",
349
+ url="flow/files",
350
+ ),
351
+ stream=False,
352
+ )
353
+
354
+ assert isinstance(response, SeekrFlowResponse)
355
+
356
+ return FileList(**response.data)
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from pathlib import Path
4
4
 
5
5
  from seekrai.abstract import api_requestor
6
+ from seekrai.resources.resource_base import ResourceBase
6
7
  from seekrai.seekrflow_response import SeekrFlowResponse
7
8
  from seekrai.types import (
8
9
  FinetuneDownloadResult,
@@ -11,16 +12,12 @@ from seekrai.types import (
11
12
  FinetuneRequest,
12
13
  FinetuneResponse,
13
14
  InfrastructureConfig,
14
- SeekrFlowClient,
15
15
  SeekrFlowRequest,
16
16
  TrainingConfig,
17
17
  )
18
18
 
19
19
 
20
- class FineTuning:
21
- def __init__(self, client: SeekrFlowClient) -> None:
22
- self._client = client
23
-
20
+ class FineTuning(ResourceBase):
24
21
  def create(
25
22
  self,
26
23
  *,
@@ -246,10 +243,7 @@ class FineTuning:
246
243
  return FinetuneListEvents(**response.data)
247
244
 
248
245
 
249
- class AsyncFineTuning:
250
- def __init__(self, client: SeekrFlowClient) -> None:
251
- self._client = client
252
-
246
+ class AsyncFineTuning(ResourceBase):
253
247
  async def create(
254
248
  self,
255
249
  *,
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from seekrai.abstract import api_requestor
4
+ from seekrai.resources.resource_base import ResourceBase
4
5
  from seekrai.seekrflow_response import SeekrFlowResponse
5
6
  from seekrai.types import (
6
7
  ImageRequest,
@@ -10,10 +11,7 @@ from seekrai.types import (
10
11
  )
11
12
 
12
13
 
13
- class Images:
14
- def __init__(self, client: SeekrFlowClient) -> None:
15
- self._client = client
16
-
14
+ class Images(ResourceBase):
17
15
  def generate(
18
16
  self,
19
17
  *,
@@ -83,7 +81,7 @@ class Images:
83
81
  return ImageResponse(**response.data)
84
82
 
85
83
 
86
- class AsyncImages:
84
+ class AsyncImages(ResourceBase):
87
85
  def __init__(self, client: SeekrFlowClient) -> None:
88
86
  self._client = client
89
87
 
@@ -0,0 +1,173 @@
1
+ from typing import List
2
+
3
+ from seekrai.abstract import api_requestor
4
+ from seekrai.resources.resource_base import ResourceBase
5
+ from seekrai.seekrflow_response import SeekrFlowResponse
6
+ from seekrai.types import (
7
+ SeekrFlowRequest,
8
+ )
9
+ from seekrai.types.ingestion import IngestionList, IngestionRequest, IngestionResponse
10
+
11
+
12
+ class Ingestion(ResourceBase):
13
+ def ingest(
14
+ self,
15
+ files: List[str],
16
+ ) -> IngestionResponse:
17
+ """
18
+ Start an ingestion job for the specified files.
19
+
20
+ Args:
21
+ files (List[str]): List of file IDs to ingest.
22
+
23
+ Returns:
24
+ IngestionResponse: Object containing information about the created ingestion job.
25
+ """
26
+ requestor = api_requestor.APIRequestor(
27
+ client=self._client,
28
+ )
29
+
30
+ parameter_payload = IngestionRequest(
31
+ files=files,
32
+ ).model_dump()
33
+
34
+ response, _, _ = requestor.request(
35
+ options=SeekrFlowRequest(
36
+ method="POST",
37
+ url="flow/alignment/ingestion",
38
+ params=parameter_payload,
39
+ ),
40
+ stream=False,
41
+ )
42
+
43
+ assert isinstance(response, SeekrFlowResponse)
44
+ return IngestionResponse(**response.data)
45
+
46
+ def list(self) -> IngestionList:
47
+ """
48
+ Lists ingestion job history
49
+
50
+ Returns:
51
+ IngestionList: Object containing a list of ingestion jobs
52
+ """
53
+ requestor = api_requestor.APIRequestor(
54
+ client=self._client,
55
+ )
56
+
57
+ response, _, _ = requestor.request(
58
+ options=SeekrFlowRequest(
59
+ method="GET",
60
+ url="flow/alignment/ingestion",
61
+ ),
62
+ stream=False,
63
+ )
64
+
65
+ assert isinstance(response, SeekrFlowResponse)
66
+ return IngestionList(**response.data)
67
+
68
+ def retrieve(self, id: str) -> IngestionResponse:
69
+ """
70
+ Retrieves ingestion job details
71
+
72
+ Args:
73
+ id (str): Ingestion job ID to retrieve.
74
+
75
+ Returns:
76
+ IngestionResponse: Object containing information about ingestion job.
77
+ """
78
+ requestor = api_requestor.APIRequestor(
79
+ client=self._client,
80
+ )
81
+
82
+ response, _, _ = requestor.request(
83
+ options=SeekrFlowRequest(
84
+ method="GET",
85
+ url=f"flow/alignment/ingestion/{id}",
86
+ ),
87
+ stream=False,
88
+ )
89
+
90
+ assert isinstance(response, SeekrFlowResponse)
91
+ return IngestionResponse(**response.data)
92
+
93
+
94
+ class AsyncIngestion(ResourceBase):
95
+ async def ingest(
96
+ self,
97
+ files: List[str],
98
+ ) -> IngestionResponse:
99
+ """
100
+ Start an ingestion job for the specified files asynchronously.
101
+
102
+ Args:
103
+ files (List[str]): List of file IDs to ingest.
104
+
105
+ Returns:
106
+ IngestionResponse: Object containing information about the created ingestion job.
107
+ """
108
+ requestor = api_requestor.APIRequestor(
109
+ client=self._client,
110
+ )
111
+
112
+ parameter_payload = IngestionRequest(
113
+ files=files,
114
+ ).model_dump()
115
+
116
+ response, _, _ = await requestor.arequest(
117
+ options=SeekrFlowRequest(
118
+ method="POST",
119
+ url="flow/alignment/ingestion",
120
+ params=parameter_payload,
121
+ ),
122
+ stream=False,
123
+ )
124
+
125
+ assert isinstance(response, SeekrFlowResponse)
126
+ return IngestionResponse(**response.data)
127
+
128
+ async def list(self) -> IngestionList:
129
+ """
130
+ Lists ingestion job history asynchronously
131
+
132
+ Returns:
133
+ IngestionList: Object containing a list of ingestion jobs
134
+ """
135
+ requestor = api_requestor.APIRequestor(
136
+ client=self._client,
137
+ )
138
+
139
+ response, _, _ = await requestor.arequest(
140
+ options=SeekrFlowRequest(
141
+ method="GET",
142
+ url="flow/alignment/ingestion",
143
+ ),
144
+ stream=False,
145
+ )
146
+
147
+ assert isinstance(response, SeekrFlowResponse)
148
+ return IngestionList(**response.data)
149
+
150
+ async def retrieve(self, id: str) -> IngestionResponse:
151
+ """
152
+ Retrieves ingestion job details asynchronously
153
+
154
+ Args:
155
+ id (str): Ingestion job ID to retrieve.
156
+
157
+ Returns:
158
+ IngestionResponse: Object containing information about ingestion job.
159
+ """
160
+ requestor = api_requestor.APIRequestor(
161
+ client=self._client,
162
+ )
163
+
164
+ response, _, _ = await requestor.arequest(
165
+ options=SeekrFlowRequest(
166
+ method="GET",
167
+ url=f"flow/alignment/ingestion/{id}",
168
+ ),
169
+ stream=False,
170
+ )
171
+
172
+ assert isinstance(response, SeekrFlowResponse)
173
+ return IngestionResponse(**response.data)