kainguru-sdk 0.2.10.dev0__tar.gz → 0.2.12.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.10.dev0 → kainguru_sdk-0.2.12.dev0}/PKG-INFO +1 -1
  2. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/pyproject.toml +1 -1
  3. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/__init__.py +4 -0
  4. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/async_client.py +2 -1
  5. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/client.py +2 -1
  6. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/models.py +205 -74
  7. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/resources/__init__.py +3 -0
  8. kainguru_sdk-0.2.12.dev0/src/kainguru/resources/_common.py +88 -0
  9. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/resources/executions.py +47 -3
  10. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/resources/finetuning.py +26 -0
  11. kainguru_sdk-0.2.12.dev0/src/kainguru/resources/rag.py +254 -0
  12. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/tests/resources/openapi.json +1226 -375
  13. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/tests/test_executions.py +51 -0
  14. kainguru_sdk-0.2.12.dev0/tests/test_finetuning.py +109 -0
  15. kainguru_sdk-0.2.12.dev0/tests/test_rag.py +218 -0
  16. kainguru_sdk-0.2.10.dev0/src/kainguru/resources/_common.py +0 -35
  17. kainguru_sdk-0.2.10.dev0/tests/test_finetuning.py +0 -53
  18. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/.gitignore +0 -0
  19. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/MAINTAINERS.md +0 -0
  20. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/Makefile +0 -0
  21. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/README.md +0 -0
  22. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/_config.py +0 -0
  23. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/_errors.py +0 -0
  24. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/_polling.py +0 -0
  25. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/_transport.py +0 -0
  26. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/src/kainguru/py.typed +0 -0
  27. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/tests/conftest.py +0 -0
  28. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.dev0}/tests/test_auth.py +0 -0
  29. {kainguru_sdk-0.2.10.dev0 → kainguru_sdk-0.2.12.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.10.dev0
3
+ Version: 0.2.12.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.10.dev0"
7
+ version = "0.2.12.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,25 @@ class ModelExecModelRefDto(BaseModel):
156
243
  version: str | None = None
157
244
 
158
245
 
159
- class ModelExecResponseDto(BaseModel):
246
+ class SourceDto(BaseModel):
247
+ sourceFile: str | None = None
248
+ chunkIndex: int | None = None
249
+
250
+
251
+ class RagKnowledgeBaseDto(BaseModel):
160
252
  id: UUID | None = None
253
+ name: str | None = None
254
+ ragHandle: str | None = None
161
255
  status: ModelStatus | None = None
162
256
  model: ModelExecModelRefDto | None = None
163
- fineTunedModel: ModelExecFineTunedRefDto | None = None
164
- application: ApplicationDto | None = None
165
- execution: ExecutionResultDto | None = None
166
257
  createDate: AwareDatetime | None = None
167
258
  modifiedDate: AwareDatetime | None = None
168
259
 
169
260
 
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
261
+ class RagKnowledgeBaseListApiResponse(BaseModel):
262
+ success: bool | None = None
263
+ code: int | None = None
264
+ data: list[RagKnowledgeBaseDto] | None = None
181
265
 
182
266
 
183
267
  class ModelListDto(BaseModel):
@@ -199,6 +283,18 @@ class ModelListDto(BaseModel):
199
283
  banner: str | None = None
200
284
 
201
285
 
286
+ class RagKnowledgeBaseDetailDto(BaseModel):
287
+ id: UUID | None = None
288
+ name: str | None = None
289
+ ragHandle: str | None = None
290
+ status: ModelStatus | None = None
291
+ model: ModelListDto | None = None
292
+ files: list[FileDto] | None = None
293
+ latestOperation: RagOperationResultDto | None = None
294
+ createDate: AwareDatetime | None = None
295
+ modifiedDate: AwareDatetime | None = None
296
+
297
+
202
298
  class ErrorDto(BaseModel):
203
299
  success: bool | None = None
204
300
  code: int | None = None
@@ -209,12 +305,6 @@ class ErrorDto(BaseModel):
209
305
  errors: list[FieldError] | None = None
210
306
 
211
307
 
212
- class ModelExecApiResponse(BaseModel):
213
- success: bool | None = None
214
- code: int | None = None
215
- data: ModelExecResponseDto | None = None
216
-
217
-
218
308
  class ModelFineTunedDetailDto(BaseModel):
219
309
  id: UUID | None = None
220
310
  name: str | None = None
@@ -230,7 +320,48 @@ class ModelFineTunedDetailDto(BaseModel):
230
320
  modifiedDate: AwareDatetime | None = None
231
321
 
232
322
 
323
+ class ExecutionResultDto(BaseModel):
324
+ id: UUID | None = None
325
+ input: dict[str, Any] | None = None
326
+ output: Any | None = None
327
+ inputFormats: dict[str, str] | None = None
328
+ outputFormat: str | None = None
329
+ step: str | None = None
330
+ percent: float | None = None
331
+ stepsHistory: list[dict[str, Any]] | None = None
332
+ startDate: AwareDatetime | None = None
333
+ endDate: AwareDatetime | None = None
334
+ duration: float | None = None
335
+ mode: str | None = None
336
+ sources: list[SourceDto] | None = None
337
+ loraRunId: str | None = None
338
+ ragHandle: str | None = None
339
+
340
+
341
+ class ModelExecResponseDto(BaseModel):
342
+ id: UUID | None = None
343
+ status: ModelStatus | None = None
344
+ model: ModelExecModelRefDto | None = None
345
+ fineTunedModel: ModelExecFineTunedRefDto | None = None
346
+ application: ApplicationDto | None = None
347
+ execution: ExecutionResultDto | None = None
348
+ createDate: AwareDatetime | None = None
349
+ modifiedDate: AwareDatetime | None = None
350
+
351
+
352
+ class RagKnowledgeBaseApiResponse(BaseModel):
353
+ success: bool | None = None
354
+ code: int | None = None
355
+ data: RagKnowledgeBaseDetailDto | None = None
356
+
357
+
233
358
  class ModelFineTuneApiResponse(BaseModel):
234
359
  success: bool | None = None
235
360
  code: int | None = None
236
361
  data: ModelFineTunedDetailDto | None = None
362
+
363
+
364
+ class ModelExecApiResponse(BaseModel):
365
+ success: bool | None = None
366
+ code: int | None = None
367
+ 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,