kainguru-sdk 0.2.11.dev0__tar.gz → 0.2.13.dev0__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 (29) hide show
  1. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/PKG-INFO +1 -1
  2. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/pyproject.toml +1 -1
  3. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/__init__.py +4 -0
  4. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/async_client.py +2 -1
  5. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/client.py +2 -1
  6. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/models.py +213 -74
  7. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/resources/__init__.py +3 -0
  8. kainguru_sdk-0.2.13.dev0/src/kainguru/resources/_common.py +88 -0
  9. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/resources/executions.py +47 -3
  10. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/resources/finetuning.py +26 -0
  11. kainguru_sdk-0.2.13.dev0/src/kainguru/resources/rag.py +254 -0
  12. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/tests/resources/openapi.json +1254 -372
  13. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/tests/test_executions.py +51 -0
  14. kainguru_sdk-0.2.13.dev0/tests/test_finetuning.py +109 -0
  15. kainguru_sdk-0.2.13.dev0/tests/test_rag.py +218 -0
  16. kainguru_sdk-0.2.11.dev0/src/kainguru/resources/_common.py +0 -35
  17. kainguru_sdk-0.2.11.dev0/tests/test_finetuning.py +0 -53
  18. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/.gitignore +0 -0
  19. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/MAINTAINERS.md +0 -0
  20. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/Makefile +0 -0
  21. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/README.md +0 -0
  22. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/_config.py +0 -0
  23. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/_errors.py +0 -0
  24. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/_polling.py +0 -0
  25. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/_transport.py +0 -0
  26. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/src/kainguru/py.typed +0 -0
  27. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/tests/conftest.py +0 -0
  28. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/tests/test_auth.py +0 -0
  29. {kainguru_sdk-0.2.11.dev0 → kainguru_sdk-0.2.13.dev0}/tests/test_polling.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: kainguru-sdk
3
- Version: 0.2.11.dev0
3
+ Version: 0.2.13.dev0
4
4
  Summary: Python SDK for the Kainguru ML platform — run models and fine-tune them.
5
5
  Project-URL: Homepage, https://kainguru.com
6
6
  Project-URL: Repository, https://github.com/kainguru/kainguru
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "kainguru-sdk"
7
- version = "0.2.11.dev0"
7
+ version = "0.2.13.dev0"
8
8
  description = "Python SDK for the Kainguru ML platform — run models and fine-tune them."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -22,6 +22,7 @@ from .models import (
22
22
  ModelFineTunedDetailDto,
23
23
  ModelStatus,
24
24
  )
25
+ from .resources import AsyncRagResource, RagResource
25
26
 
26
27
  __version__ = "0.1.0"
27
28
 
@@ -39,6 +40,9 @@ __all__ = [
39
40
  "KainguruRateLimitError",
40
41
  "KainguruTimeoutError",
41
42
  "KainguruConnectionError",
43
+ # Resources
44
+ "RagResource",
45
+ "AsyncRagResource",
42
46
  # Models
43
47
  "ModelStatus",
44
48
  "ModelExecResponseDto",
@@ -13,7 +13,7 @@ from ._config import (
13
13
  KainguruConfig,
14
14
  )
15
15
  from ._transport import AsyncTransport, enable_debug_logging
16
- from .resources import AsyncExecutionsResource, AsyncFineTuningResource
16
+ from .resources import AsyncExecutionsResource, AsyncFineTuningResource, AsyncRagResource
17
17
 
18
18
 
19
19
  class AsyncKainguruClient:
@@ -58,6 +58,7 @@ class AsyncKainguruClient:
58
58
  self._transport = AsyncTransport(client, self._config)
59
59
  self.executions = AsyncExecutionsResource(self._transport)
60
60
  self.fine_tuning = AsyncFineTuningResource(self._transport)
61
+ self.rag = AsyncRagResource(self._transport)
61
62
 
62
63
  @property
63
64
  def config(self) -> KainguruConfig:
@@ -13,7 +13,7 @@ from ._config import (
13
13
  KainguruConfig,
14
14
  )
15
15
  from ._transport import Transport, enable_debug_logging
16
- from .resources import ExecutionsResource, FineTuningResource
16
+ from .resources import ExecutionsResource, FineTuningResource, RagResource
17
17
 
18
18
 
19
19
  class KainguruClient:
@@ -58,6 +58,7 @@ class KainguruClient:
58
58
  self._transport = Transport(client, self._config)
59
59
  self.executions = ExecutionsResource(self._transport)
60
60
  self.fine_tuning = FineTuningResource(self._transport)
61
+ self.rag = RagResource(self._transport)
61
62
 
62
63
  @property
63
64
  def config(self) -> KainguruConfig:
@@ -7,12 +7,13 @@ from enum import Enum
7
7
  from typing import Any
8
8
  from uuid import UUID
9
9
 
10
- from pydantic import AwareDatetime, BaseModel, constr
10
+ from pydantic import AwareDatetime, BaseModel, Field, constr
11
11
 
12
12
 
13
- class ModelFineTuneRequestDto(BaseModel):
13
+ class RagIngestRequestDto(BaseModel):
14
14
  name: constr(min_length=1)
15
- input: dict[str, Any]
15
+ fileIds: list[UUID] = Field(..., min_length=1)
16
+ params: dict[str, Any] | None = None
16
17
 
17
18
 
18
19
  class CategoryShortDto(BaseModel):
@@ -24,39 +25,54 @@ class CategoryShortDto(BaseModel):
24
25
  modifiedDate: AwareDatetime | None = None
25
26
 
26
27
 
27
- class InputType(Enum):
28
- STRING = 'STRING'
29
- INTEGER = 'INTEGER'
30
- FLOAT = 'FLOAT'
31
- BOOLEAN = 'BOOLEAN'
32
- DICT = 'DICT'
33
- PATH = 'PATH'
34
- PATH_ARRAY = 'PATH_ARRAY'
35
- LABELED_PATH_ARRAY = 'LABELED_PATH_ARRAY'
36
-
37
-
38
- class Scope(Enum):
39
- BASE_ONLY = 'BASE_ONLY'
40
- FINE_TUNED_ONLY = 'FINE_TUNED_ONLY'
41
- BOTH = 'BOTH'
28
+ class FileType(Enum):
29
+ JPEG = 'JPEG'
30
+ PNG = 'PNG'
31
+ WEBP = 'WEBP'
32
+ GIF = 'GIF'
33
+ BMP = 'BMP'
34
+ TIFF = 'TIFF'
35
+ SVG = 'SVG'
36
+ MP3 = 'MP3'
37
+ WAV = 'WAV'
38
+ FLAC = 'FLAC'
39
+ OGG = 'OGG'
40
+ M4A = 'M4A'
41
+ AAC = 'AAC'
42
+ WEBM_AUDIO = 'WEBM_AUDIO'
43
+ MP4 = 'MP4'
44
+ WEBM_VIDEO = 'WEBM_VIDEO'
45
+ MOV = 'MOV'
46
+ AVI = 'AVI'
47
+ MKV = 'MKV'
48
+ JSON = 'JSON'
49
+ JSONL = 'JSONL'
50
+ TXT = 'TXT'
51
+ CSV = 'CSV'
52
+ PDF = 'PDF'
53
+ DOCX = 'DOCX'
54
+ ZIP = 'ZIP'
55
+ PY = 'PY'
56
+ YAML = 'YAML'
57
+ MD = 'MD'
58
+ OBJ = 'OBJ'
59
+ GLB = 'GLB'
60
+ GLTF = 'GLTF'
61
+ PLY = 'PLY'
62
+
63
+
64
+ class AccessLevel(Enum):
65
+ PUBLIC = 'PUBLIC'
66
+ PRIVATE = 'PRIVATE'
42
67
 
43
68
 
44
- class ModelExecInputDto(BaseModel):
69
+ class FileDto(BaseModel):
45
70
  id: UUID | None = None
46
- createDate: AwareDatetime | None = None
47
- modifiedDate: AwareDatetime | None = None
48
71
  name: str | None = None
49
- description: str | None = None
50
- inputType: InputType | None = None
51
- validations: dict[str, Any] | None = None
52
- required: bool | None = None
53
- mediaTypes: list[str] | None = None
54
- scope: Scope | None = None
55
- label: str | None = None
56
- defaultValue: Any | None = None
57
- allowedValues: list[Any] | None = None
58
- requirementGroup: list[str] | None = None
59
- requiredWhen: dict[str, Any] | None = None
72
+ url: str | None = None
73
+ s3Key: str | None = None
74
+ fileType: FileType | None = None
75
+ accessLevel: AccessLevel | None = None
60
76
 
61
77
 
62
78
  class AccessType(Enum):
@@ -90,14 +106,28 @@ class ModelStatus(Enum):
90
106
  DELETED = 'DELETED'
91
107
 
92
108
 
93
- class UserDto(BaseModel):
109
+ class RagOperation(Enum):
110
+ RAG_INGEST = 'RAG_INGEST'
111
+ RAG_APPEND = 'RAG_APPEND'
112
+ RAG_DOC_DELETE = 'RAG_DOC_DELETE'
113
+ RAG_DELETE = 'RAG_DELETE'
114
+
115
+
116
+ class RagOperationResultDto(BaseModel):
94
117
  id: UUID | None = None
95
- username: str | None = None
96
- fullname: str | None = None
97
- email: str | None = None
98
- emailVerified: bool | None = None
99
- createDate: AwareDatetime | None = None
100
- modifiedDate: AwareDatetime | None = None
118
+ operation: RagOperation | None = None
119
+ status: ModelStatus | None = None
120
+ added: list[str] | None = None
121
+ replaced: list[str] | None = None
122
+ skipped: list[str] | None = None
123
+ deleted: list[dict[str, Any]] | None = None
124
+ notFound: list[str] | None = None
125
+ sourceFiles: list[str] | None = None
126
+ numChunks: int | None = None
127
+ verified: bool | None = None
128
+ startDate: AwareDatetime | None = None
129
+ endDate: AwareDatetime | None = None
130
+ duration: float | None = None
101
131
 
102
132
 
103
133
  class CommonApiResponse(BaseModel):
@@ -111,9 +141,80 @@ class FieldError(BaseModel):
111
141
  message: str | None = None
112
142
 
113
143
 
144
+ class RagFileSelectionRequestDto(BaseModel):
145
+ fileIds: list[UUID] = Field(..., min_length=1)
146
+
147
+
148
+ class ModelFineTuneRequestDto(BaseModel):
149
+ name: constr(min_length=1)
150
+ input: dict[str, Any]
151
+
152
+
153
+ class FineTuneResultDto(BaseModel):
154
+ id: UUID | None = None
155
+ status: ModelStatus | None = None
156
+ input: dict[str, Any] | None = None
157
+ output: Any | None = None
158
+ step: str | None = None
159
+ percent: float | None = None
160
+ stepsHistory: list[dict[str, Any]] | None = None
161
+ startDate: AwareDatetime | None = None
162
+ endDate: AwareDatetime | None = None
163
+ duration: float | None = None
164
+
165
+
166
+ class InputType(Enum):
167
+ STRING = 'STRING'
168
+ INTEGER = 'INTEGER'
169
+ FLOAT = 'FLOAT'
170
+ BOOLEAN = 'BOOLEAN'
171
+ DICT = 'DICT'
172
+ PATH = 'PATH'
173
+ PATH_ARRAY = 'PATH_ARRAY'
174
+ LABELED_PATH_ARRAY = 'LABELED_PATH_ARRAY'
175
+
176
+
177
+ class Scope(Enum):
178
+ BASE_ONLY = 'BASE_ONLY'
179
+ FINE_TUNED_ONLY = 'FINE_TUNED_ONLY'
180
+ BOTH = 'BOTH'
181
+
182
+
183
+ class ModelExecInputDto(BaseModel):
184
+ id: UUID | None = None
185
+ createDate: AwareDatetime | None = None
186
+ modifiedDate: AwareDatetime | None = None
187
+ name: str | None = None
188
+ description: str | None = None
189
+ inputType: InputType | None = None
190
+ validations: dict[str, Any] | None = None
191
+ required: bool | None = None
192
+ mediaTypes: list[str] | None = None
193
+ scope: Scope | None = None
194
+ label: str | None = None
195
+ defaultValue: Any | None = None
196
+ allowedValues: list[Any] | None = None
197
+ requirementGroup: list[str] | None = None
198
+ requiredWhen: dict[str, Any] | None = None
199
+
200
+
201
+ class UserDto(BaseModel):
202
+ id: UUID | None = None
203
+ username: str | None = None
204
+ fullname: str | None = None
205
+ email: str | None = None
206
+ emailVerified: bool | None = None
207
+ createDate: AwareDatetime | None = None
208
+ modifiedDate: AwareDatetime | None = None
209
+
210
+
114
211
  class ModelExecRequestDto(BaseModel):
115
212
  input: dict[str, Any]
116
213
  outputFormat: str | None = None
214
+ ragHandle: str | None = None
215
+ ragTopK: int | None = None
216
+ ragMinScore: float | None = None
217
+ ragPromptMode: str | None = None
117
218
 
118
219
 
119
220
  class Status(Enum):
@@ -131,20 +232,6 @@ class ApplicationDto(BaseModel):
131
232
  archived: bool | None = None
132
233
 
133
234
 
134
- class ExecutionResultDto(BaseModel):
135
- id: UUID | None = None
136
- input: dict[str, Any] | None = None
137
- output: Any | None = None
138
- inputFormats: dict[str, str] | None = None
139
- outputFormat: str | None = None
140
- step: str | None = None
141
- percent: float | None = None
142
- stepsHistory: list[dict[str, Any]] | None = None
143
- startDate: AwareDatetime | None = None
144
- endDate: AwareDatetime | None = None
145
- duration: float | None = None
146
-
147
-
148
235
  class ModelExecFineTunedRefDto(BaseModel):
149
236
  id: UUID | None = None
150
237
  mlflowModelId: str | None = None
@@ -156,28 +243,32 @@ class ModelExecModelRefDto(BaseModel):
156
243
  version: str | None = None
157
244
 
158
245
 
159
- class ModelExecResponseDto(BaseModel):
246
+ class RagRequestDto(BaseModel):
247
+ handle: str | None = None
248
+ topK: int | None = None
249
+ minScore: float | None = None
250
+ promptMode: str | None = None
251
+
252
+
253
+ class SourceDto(BaseModel):
254
+ sourceFile: str | None = None
255
+ chunkIndex: int | None = None
256
+
257
+
258
+ class RagKnowledgeBaseDto(BaseModel):
160
259
  id: UUID | None = None
260
+ name: str | None = None
261
+ ragHandle: str | None = None
161
262
  status: ModelStatus | None = None
162
263
  model: ModelExecModelRefDto | None = None
163
- fineTunedModel: ModelExecFineTunedRefDto | None = None
164
- application: ApplicationDto | None = None
165
- execution: ExecutionResultDto | None = None
166
264
  createDate: AwareDatetime | None = None
167
265
  modifiedDate: AwareDatetime | None = None
168
266
 
169
267
 
170
- class FineTuneResultDto(BaseModel):
171
- id: UUID | None = None
172
- status: ModelStatus | None = None
173
- input: dict[str, Any] | None = None
174
- output: Any | None = None
175
- step: str | None = None
176
- percent: float | None = None
177
- stepsHistory: list[dict[str, Any]] | None = None
178
- startDate: AwareDatetime | None = None
179
- endDate: AwareDatetime | None = None
180
- duration: float | None = None
268
+ class RagKnowledgeBaseListApiResponse(BaseModel):
269
+ success: bool | None = None
270
+ code: int | None = None
271
+ data: list[RagKnowledgeBaseDto] | None = None
181
272
 
182
273
 
183
274
  class ModelListDto(BaseModel):
@@ -199,6 +290,18 @@ class ModelListDto(BaseModel):
199
290
  banner: str | None = None
200
291
 
201
292
 
293
+ class RagKnowledgeBaseDetailDto(BaseModel):
294
+ id: UUID | None = None
295
+ name: str | None = None
296
+ ragHandle: str | None = None
297
+ status: ModelStatus | None = None
298
+ model: ModelListDto | None = None
299
+ files: list[FileDto] | None = None
300
+ latestOperation: RagOperationResultDto | None = None
301
+ createDate: AwareDatetime | None = None
302
+ modifiedDate: AwareDatetime | None = None
303
+
304
+
202
305
  class ErrorDto(BaseModel):
203
306
  success: bool | None = None
204
307
  code: int | None = None
@@ -209,12 +312,6 @@ class ErrorDto(BaseModel):
209
312
  errors: list[FieldError] | None = None
210
313
 
211
314
 
212
- class ModelExecApiResponse(BaseModel):
213
- success: bool | None = None
214
- code: int | None = None
215
- data: ModelExecResponseDto | None = None
216
-
217
-
218
315
  class ModelFineTunedDetailDto(BaseModel):
219
316
  id: UUID | None = None
220
317
  name: str | None = None
@@ -230,7 +327,49 @@ class ModelFineTunedDetailDto(BaseModel):
230
327
  modifiedDate: AwareDatetime | None = None
231
328
 
232
329
 
330
+ class ExecutionResultDto(BaseModel):
331
+ id: UUID | None = None
332
+ input: dict[str, Any] | None = None
333
+ output: Any | None = None
334
+ inputFormats: dict[str, str] | None = None
335
+ outputFormat: str | None = None
336
+ step: str | None = None
337
+ percent: float | None = None
338
+ stepsHistory: list[dict[str, Any]] | None = None
339
+ startDate: AwareDatetime | None = None
340
+ endDate: AwareDatetime | None = None
341
+ duration: float | None = None
342
+ mode: str | None = None
343
+ sources: list[SourceDto] | None = None
344
+ loraRunId: str | None = None
345
+ ragHandle: str | None = None
346
+ ragRequest: RagRequestDto | None = None
347
+
348
+
349
+ class ModelExecResponseDto(BaseModel):
350
+ id: UUID | None = None
351
+ status: ModelStatus | None = None
352
+ model: ModelExecModelRefDto | None = None
353
+ fineTunedModel: ModelExecFineTunedRefDto | None = None
354
+ application: ApplicationDto | None = None
355
+ execution: ExecutionResultDto | None = None
356
+ createDate: AwareDatetime | None = None
357
+ modifiedDate: AwareDatetime | None = None
358
+
359
+
360
+ class RagKnowledgeBaseApiResponse(BaseModel):
361
+ success: bool | None = None
362
+ code: int | None = None
363
+ data: RagKnowledgeBaseDetailDto | None = None
364
+
365
+
233
366
  class ModelFineTuneApiResponse(BaseModel):
234
367
  success: bool | None = None
235
368
  code: int | None = None
236
369
  data: ModelFineTunedDetailDto | None = None
370
+
371
+
372
+ class ModelExecApiResponse(BaseModel):
373
+ success: bool | None = None
374
+ code: int | None = None
375
+ data: ModelExecResponseDto | None = None
@@ -1,9 +1,12 @@
1
1
  from .executions import AsyncExecutionsResource, ExecutionsResource
2
2
  from .finetuning import AsyncFineTuningResource, FineTuningResource
3
+ from .rag import AsyncRagResource, RagResource
3
4
 
4
5
  __all__ = [
5
6
  "ExecutionsResource",
6
7
  "AsyncExecutionsResource",
7
8
  "FineTuningResource",
8
9
  "AsyncFineTuningResource",
10
+ "RagResource",
11
+ "AsyncRagResource",
9
12
  ]
@@ -0,0 +1,88 @@
1
+ """Helpers shared across sync and async resources."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ #: A RAG knowledge base's *latest operation* is terminal at these statuses. Unlike
8
+ #: executions/fine-tuning, RAG also treats CANCELLED/DELETED as terminal since
9
+ #: `cancel`/`delete` are themselves operations callers may want to await.
10
+ _RAG_TERMINAL_STATUSES = ("COMPLETED", "FAILED", "CANCELLED", "DELETED")
11
+
12
+
13
+ def is_terminal(dto: object) -> bool:
14
+ """COMPLETED / FAILED are terminal; REGISTERED is not (matches the Java SDK)."""
15
+ status = getattr(dto, "status", None)
16
+ value = getattr(status, "value", status)
17
+ return value in ("COMPLETED", "FAILED")
18
+
19
+
20
+ def is_rag_terminal(dto: object) -> bool:
21
+ """Terminal check for RAG knowledge base polling.
22
+
23
+ Reads ``dto.latestOperation.status`` rather than ``dto.status``: the knowledge
24
+ base's own ``status`` stays ``COMPLETED`` while an append or document-delete
25
+ operation is in flight, so polling it directly would return prematurely (or
26
+ never reflect append/delete completion at all). Terminal values are
27
+ ``COMPLETED``, ``FAILED``, ``CANCELLED``, ``DELETED``.
28
+ """
29
+ latest_operation = getattr(dto, "latestOperation", None)
30
+ if latest_operation is None:
31
+ return False
32
+ status = getattr(latest_operation, "status", None)
33
+ value = getattr(status, "value", status)
34
+ return value in _RAG_TERMINAL_STATUSES
35
+
36
+
37
+ def execute_args(
38
+ ml_flow_id: str,
39
+ input: dict[str, Any],
40
+ output_format: str | None,
41
+ exec_id: str | None,
42
+ rag_handle: str | None = None,
43
+ rag_top_k: int | None = None,
44
+ rag_min_score: float | None = None,
45
+ rag_prompt_mode: str | None = None,
46
+ ) -> tuple[dict[str, Any], dict[str, Any]]:
47
+ params: dict[str, Any] = {"mlFlowId": ml_flow_id}
48
+ if exec_id:
49
+ params["execId"] = exec_id
50
+ body: dict[str, Any] = {"input": input or {}, "outputFormat": output_format}
51
+ if rag_handle is not None:
52
+ body["ragHandle"] = rag_handle
53
+ if rag_top_k is not None:
54
+ body["ragTopK"] = rag_top_k
55
+ if rag_min_score is not None:
56
+ body["ragMinScore"] = rag_min_score
57
+ if rag_prompt_mode is not None:
58
+ body["ragPromptMode"] = rag_prompt_mode
59
+ return params, body
60
+
61
+
62
+ def fine_tune_args(
63
+ model_id: str,
64
+ name: str,
65
+ input: dict[str, Any],
66
+ ) -> tuple[dict[str, Any], dict[str, Any]]:
67
+ params: dict[str, Any] = {"modelId": model_id}
68
+ body: dict[str, Any] = {"name": name, "input": input or {}}
69
+ return params, body
70
+
71
+
72
+ def rag_ingest_args(
73
+ model_id: str,
74
+ name: str,
75
+ file_ids: list[str],
76
+ params: dict[str, Any] | None,
77
+ ) -> tuple[dict[str, Any], dict[str, Any]]:
78
+ """Build the ``(query, body)`` pair for ``POST /v1/rag``."""
79
+ query: dict[str, Any] = {"modelId": model_id}
80
+ body: dict[str, Any] = {"name": name, "fileIds": file_ids}
81
+ if params is not None:
82
+ body["params"] = params
83
+ return query, body
84
+
85
+
86
+ def rag_file_selection_args(file_ids: list[str]) -> dict[str, Any]:
87
+ """Build the request body shared by ``append`` and ``delete_documents``."""
88
+ return {"fileIds": file_ids}
@@ -36,12 +36,30 @@ class ExecutionsResource:
36
36
  output_format: str | None = None,
37
37
  exec_id: str | None = None,
38
38
  *,
39
+ rag_handle: str | None = None,
40
+ rag_top_k: int | None = None,
41
+ rag_min_score: float | None = None,
42
+ rag_prompt_mode: str | None = None,
39
43
  api_key: str | None = None,
40
44
  ) -> ModelExecResponseDto:
41
- """Submit a model run. Returns immediately (typically ``PENDING``)."""
45
+ """Submit a model run. Returns immediately (typically ``PENDING``).
46
+
47
+ The ``rag_*`` kwargs enable retrieval-augmented generation against a
48
+ knowledge base previously created via ``client.rag.ingest`` (identified by
49
+ its ``ragHandle``).
50
+ """
42
51
  if not ml_flow_id:
43
52
  raise KainguruConfigError("ml_flow_id is required")
44
- params, body = execute_args(ml_flow_id, input, output_format, exec_id)
53
+ params, body = execute_args(
54
+ ml_flow_id,
55
+ input,
56
+ output_format,
57
+ exec_id,
58
+ rag_handle=rag_handle,
59
+ rag_top_k=rag_top_k,
60
+ rag_min_score=rag_min_score,
61
+ rag_prompt_mode=rag_prompt_mode,
62
+ )
45
63
  response = self._t.request("POST", _PATH, params=params, json=body, api_key=api_key)
46
64
  return unwrap(response, ModelExecResponseDto)
47
65
 
@@ -52,6 +70,13 @@ class ExecutionsResource:
52
70
  response = self._t.request("GET", f"{_PATH}/{id}", api_key=api_key)
53
71
  return unwrap(response, ModelExecResponseDto)
54
72
 
73
+ def cancel(self, id: str, *, api_key: str | None = None) -> ModelExecResponseDto:
74
+ """Cancel an active execution."""
75
+ if not id:
76
+ raise KainguruConfigError("id is required")
77
+ response = self._t.request("POST", f"{_PATH}/{id}/cancel", api_key=api_key)
78
+ return unwrap(response, ModelExecResponseDto)
79
+
55
80
  def await_completion(
56
81
  self,
57
82
  id: str,
@@ -86,11 +111,24 @@ class AsyncExecutionsResource:
86
111
  output_format: str | None = None,
87
112
  exec_id: str | None = None,
88
113
  *,
114
+ rag_handle: str | None = None,
115
+ rag_top_k: int | None = None,
116
+ rag_min_score: float | None = None,
117
+ rag_prompt_mode: str | None = None,
89
118
  api_key: str | None = None,
90
119
  ) -> ModelExecResponseDto:
91
120
  if not ml_flow_id:
92
121
  raise KainguruConfigError("ml_flow_id is required")
93
- params, body = execute_args(ml_flow_id, input, output_format, exec_id)
122
+ params, body = execute_args(
123
+ ml_flow_id,
124
+ input,
125
+ output_format,
126
+ exec_id,
127
+ rag_handle=rag_handle,
128
+ rag_top_k=rag_top_k,
129
+ rag_min_score=rag_min_score,
130
+ rag_prompt_mode=rag_prompt_mode,
131
+ )
94
132
  response = await self._t.request("POST", _PATH, params=params, json=body, api_key=api_key)
95
133
  return unwrap(response, ModelExecResponseDto)
96
134
 
@@ -100,6 +138,12 @@ class AsyncExecutionsResource:
100
138
  response = await self._t.request("GET", f"{_PATH}/{id}", api_key=api_key)
101
139
  return unwrap(response, ModelExecResponseDto)
102
140
 
141
+ async def cancel(self, id: str, *, api_key: str | None = None) -> ModelExecResponseDto:
142
+ if not id:
143
+ raise KainguruConfigError("id is required")
144
+ response = await self._t.request("POST", f"{_PATH}/{id}/cancel", api_key=api_key)
145
+ return unwrap(response, ModelExecResponseDto)
146
+
103
147
  async def await_completion(
104
148
  self,
105
149
  id: str,
@@ -51,6 +51,20 @@ class FineTuningResource:
51
51
  response = self._t.request("GET", f"{_PATH}/{id}", api_key=api_key)
52
52
  return unwrap(response, ModelFineTunedDetailDto)
53
53
 
54
+ def cancel(self, id: str, *, api_key: str | None = None) -> ModelFineTunedDetailDto:
55
+ """Cancel an active fine-tuning job."""
56
+ if not id:
57
+ raise KainguruConfigError("id is required")
58
+ response = self._t.request("POST", f"{_PATH}/{id}/cancel", api_key=api_key)
59
+ return unwrap(response, ModelFineTunedDetailDto)
60
+
61
+ def delete(self, id: str, *, api_key: str | None = None) -> ModelFineTunedDetailDto:
62
+ """Delete a fine-tuned model and its LoRA artifact."""
63
+ if not id:
64
+ raise KainguruConfigError("id is required")
65
+ response = self._t.request("DELETE", f"{_PATH}/{id}", api_key=api_key)
66
+ return unwrap(response, ModelFineTunedDetailDto)
67
+
54
68
  def await_completion(
55
69
  self,
56
70
  id: str,
@@ -98,6 +112,18 @@ class AsyncFineTuningResource:
98
112
  response = await self._t.request("GET", f"{_PATH}/{id}", api_key=api_key)
99
113
  return unwrap(response, ModelFineTunedDetailDto)
100
114
 
115
+ async def cancel(self, id: str, *, api_key: str | None = None) -> ModelFineTunedDetailDto:
116
+ if not id:
117
+ raise KainguruConfigError("id is required")
118
+ response = await self._t.request("POST", f"{_PATH}/{id}/cancel", api_key=api_key)
119
+ return unwrap(response, ModelFineTunedDetailDto)
120
+
121
+ async def delete(self, id: str, *, api_key: str | None = None) -> ModelFineTunedDetailDto:
122
+ if not id:
123
+ raise KainguruConfigError("id is required")
124
+ response = await self._t.request("DELETE", f"{_PATH}/{id}", api_key=api_key)
125
+ return unwrap(response, ModelFineTunedDetailDto)
126
+
101
127
  async def await_completion(
102
128
  self,
103
129
  id: str,