knowledge2 0.4.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.
- knowledge2-0.4.0.dist-info/METADATA +556 -0
- knowledge2-0.4.0.dist-info/RECORD +139 -0
- knowledge2-0.4.0.dist-info/WHEEL +5 -0
- knowledge2-0.4.0.dist-info/top_level.txt +1 -0
- sdk/__init__.py +70 -0
- sdk/_async_base.py +525 -0
- sdk/_async_paging.py +57 -0
- sdk/_base.py +541 -0
- sdk/_logging.py +41 -0
- sdk/_paging.py +73 -0
- sdk/_preview.py +70 -0
- sdk/_raw_response.py +25 -0
- sdk/_request_options.py +51 -0
- sdk/_transport.py +144 -0
- sdk/_validation.py +25 -0
- sdk/_validation_response.py +36 -0
- sdk/_version.py +3 -0
- sdk/async_client.py +320 -0
- sdk/async_resources/__init__.py +45 -0
- sdk/async_resources/_mixin_base.py +42 -0
- sdk/async_resources/a2a.py +230 -0
- sdk/async_resources/agents.py +489 -0
- sdk/async_resources/audit.py +145 -0
- sdk/async_resources/auth.py +133 -0
- sdk/async_resources/console.py +409 -0
- sdk/async_resources/corpora.py +276 -0
- sdk/async_resources/deployments.py +106 -0
- sdk/async_resources/documents.py +592 -0
- sdk/async_resources/feeds.py +248 -0
- sdk/async_resources/indexes.py +208 -0
- sdk/async_resources/jobs.py +165 -0
- sdk/async_resources/metadata.py +48 -0
- sdk/async_resources/models.py +102 -0
- sdk/async_resources/onboarding.py +538 -0
- sdk/async_resources/orgs.py +37 -0
- sdk/async_resources/pipelines.py +523 -0
- sdk/async_resources/projects.py +90 -0
- sdk/async_resources/search.py +262 -0
- sdk/async_resources/training.py +357 -0
- sdk/async_resources/usage.py +91 -0
- sdk/client.py +417 -0
- sdk/config.py +182 -0
- sdk/errors.py +178 -0
- sdk/examples/auth_factory.py +34 -0
- sdk/examples/batch_operations.py +57 -0
- sdk/examples/document_upload.py +56 -0
- sdk/examples/e2e_lifecycle.py +213 -0
- sdk/examples/error_handling.py +61 -0
- sdk/examples/pagination.py +64 -0
- sdk/examples/quickstart.py +36 -0
- sdk/examples/request_options.py +44 -0
- sdk/examples/search.py +64 -0
- sdk/integrations/__init__.py +57 -0
- sdk/integrations/_client.py +101 -0
- sdk/integrations/langchain/__init__.py +6 -0
- sdk/integrations/langchain/retriever.py +166 -0
- sdk/integrations/langchain/tools.py +108 -0
- sdk/integrations/llamaindex/__init__.py +11 -0
- sdk/integrations/llamaindex/filters.py +78 -0
- sdk/integrations/llamaindex/retriever.py +162 -0
- sdk/integrations/llamaindex/tools.py +109 -0
- sdk/integrations/llamaindex/vector_store.py +320 -0
- sdk/models/__init__.py +18 -0
- sdk/models/_base.py +24 -0
- sdk/models/_registry.py +457 -0
- sdk/models/a2a.py +92 -0
- sdk/models/agents.py +109 -0
- sdk/models/audit.py +28 -0
- sdk/models/auth.py +49 -0
- sdk/models/chunks.py +20 -0
- sdk/models/common.py +14 -0
- sdk/models/console.py +103 -0
- sdk/models/corpora.py +48 -0
- sdk/models/deployments.py +13 -0
- sdk/models/documents.py +126 -0
- sdk/models/embeddings.py +24 -0
- sdk/models/evaluation.py +17 -0
- sdk/models/feedback.py +9 -0
- sdk/models/feeds.py +57 -0
- sdk/models/indexes.py +36 -0
- sdk/models/jobs.py +52 -0
- sdk/models/models.py +26 -0
- sdk/models/onboarding.py +323 -0
- sdk/models/orgs.py +11 -0
- sdk/models/pipelines.py +147 -0
- sdk/models/projects.py +19 -0
- sdk/models/search.py +149 -0
- sdk/models/training.py +57 -0
- sdk/models/usage.py +39 -0
- sdk/namespaces.py +386 -0
- sdk/py.typed +0 -0
- sdk/resources/__init__.py +45 -0
- sdk/resources/_mixin_base.py +40 -0
- sdk/resources/a2a.py +230 -0
- sdk/resources/agents.py +487 -0
- sdk/resources/audit.py +144 -0
- sdk/resources/auth.py +138 -0
- sdk/resources/console.py +411 -0
- sdk/resources/corpora.py +269 -0
- sdk/resources/deployments.py +105 -0
- sdk/resources/documents.py +597 -0
- sdk/resources/feeds.py +246 -0
- sdk/resources/indexes.py +210 -0
- sdk/resources/jobs.py +164 -0
- sdk/resources/metadata.py +53 -0
- sdk/resources/models.py +99 -0
- sdk/resources/onboarding.py +542 -0
- sdk/resources/orgs.py +35 -0
- sdk/resources/pipeline_builder.py +257 -0
- sdk/resources/pipelines.py +520 -0
- sdk/resources/projects.py +87 -0
- sdk/resources/search.py +277 -0
- sdk/resources/training.py +358 -0
- sdk/resources/usage.py +92 -0
- sdk/types/__init__.py +366 -0
- sdk/types/a2a.py +88 -0
- sdk/types/agents.py +133 -0
- sdk/types/audit.py +26 -0
- sdk/types/auth.py +45 -0
- sdk/types/chunks.py +18 -0
- sdk/types/common.py +10 -0
- sdk/types/console.py +99 -0
- sdk/types/corpora.py +42 -0
- sdk/types/deployments.py +11 -0
- sdk/types/documents.py +104 -0
- sdk/types/embeddings.py +22 -0
- sdk/types/evaluation.py +15 -0
- sdk/types/feedback.py +7 -0
- sdk/types/feeds.py +61 -0
- sdk/types/indexes.py +30 -0
- sdk/types/jobs.py +50 -0
- sdk/types/models.py +22 -0
- sdk/types/onboarding.py +395 -0
- sdk/types/orgs.py +9 -0
- sdk/types/pipelines.py +177 -0
- sdk/types/projects.py +14 -0
- sdk/types/search.py +116 -0
- sdk/types/training.py +55 -0
- sdk/types/usage.py +37 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"""Async feed resource mixin for the Knowledge2 SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from sdk._paging import Page
|
|
8
|
+
from sdk._preview import preview_resource
|
|
9
|
+
from sdk._request_options import RequestOptions
|
|
10
|
+
from sdk._validation import require_str
|
|
11
|
+
from sdk.async_resources._mixin_base import AsyncRequesterMixin
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@preview_resource
|
|
15
|
+
class AsyncFeedsMixin(AsyncRequesterMixin):
|
|
16
|
+
async def create_feed(
|
|
17
|
+
self,
|
|
18
|
+
*,
|
|
19
|
+
project_id: str,
|
|
20
|
+
name: str,
|
|
21
|
+
query: str = "",
|
|
22
|
+
persistent: bool = False,
|
|
23
|
+
target_corpus: dict[str, Any] | None = None,
|
|
24
|
+
reactive: bool = False,
|
|
25
|
+
agent_id: str | None = None,
|
|
26
|
+
schedule_interval: str | None = None,
|
|
27
|
+
schedule_hour: int | None = None,
|
|
28
|
+
start_from: str | None = None,
|
|
29
|
+
top_k: int | None = None,
|
|
30
|
+
metadata_filters: dict[str, Any] | None = None,
|
|
31
|
+
request_options: RequestOptions | None = None,
|
|
32
|
+
) -> dict[str, Any]:
|
|
33
|
+
"""Create a new knowledge feed.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
project_id: ID of the project that will own the feed.
|
|
37
|
+
name: Human-readable name for the feed.
|
|
38
|
+
query: Query string for the feed (defaults to empty string).
|
|
39
|
+
persistent: Whether the feed persists results to storage.
|
|
40
|
+
target_corpus: Optional target corpus configuration dict. Pass
|
|
41
|
+
``{"existing": "<corpus-id>"}`` to write into an existing corpus,
|
|
42
|
+
or ``{"create_new": True}`` to have the API create a new one.
|
|
43
|
+
reactive: Whether the feed triggers on new data automatically.
|
|
44
|
+
agent_id: Optional agent ID to associate with the feed.
|
|
45
|
+
schedule_interval: Optional cron-style schedule interval.
|
|
46
|
+
schedule_hour: UTC hour (0-23) for daily scheduled feeds. Only
|
|
47
|
+
valid when schedule_interval is ``'1d'``.
|
|
48
|
+
start_from: Optional ISO-8601 timestamp to start processing from.
|
|
49
|
+
top_k: Optional number of top results to return per run.
|
|
50
|
+
metadata_filters: Optional metadata filter dictionary.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The newly created feed record.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
Knowledge2Error: If the API request fails.
|
|
57
|
+
"""
|
|
58
|
+
project_id = require_str(project_id, "project_id")
|
|
59
|
+
payload: dict[str, Any] = {
|
|
60
|
+
"project_id": project_id,
|
|
61
|
+
"name": name,
|
|
62
|
+
"query": query,
|
|
63
|
+
"persistent": persistent,
|
|
64
|
+
"reactive": reactive,
|
|
65
|
+
}
|
|
66
|
+
if target_corpus is not None:
|
|
67
|
+
payload["target_corpus"] = target_corpus
|
|
68
|
+
if agent_id is not None:
|
|
69
|
+
payload["agent_id"] = agent_id
|
|
70
|
+
if schedule_interval is not None:
|
|
71
|
+
payload["schedule_interval"] = schedule_interval
|
|
72
|
+
if schedule_hour is not None:
|
|
73
|
+
payload["schedule_hour"] = schedule_hour
|
|
74
|
+
if start_from is not None:
|
|
75
|
+
payload["start_from"] = start_from
|
|
76
|
+
if top_k is not None:
|
|
77
|
+
payload["top_k"] = top_k
|
|
78
|
+
if metadata_filters is not None:
|
|
79
|
+
payload["metadata_filters"] = metadata_filters
|
|
80
|
+
data = await self._request(
|
|
81
|
+
"POST", "/v1/feeds", json=payload, request_options=request_options
|
|
82
|
+
)
|
|
83
|
+
return self._maybe_validate(data, "FeedResponse")
|
|
84
|
+
|
|
85
|
+
async def list_feeds(
|
|
86
|
+
self,
|
|
87
|
+
*,
|
|
88
|
+
project_id: str | None = None,
|
|
89
|
+
limit: int = 100,
|
|
90
|
+
offset: int = 0,
|
|
91
|
+
request_options: RequestOptions | None = None,
|
|
92
|
+
) -> Page[dict[str, Any]]:
|
|
93
|
+
"""List feeds accessible to the current credentials.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
project_id: Optional project ID to filter feeds by.
|
|
97
|
+
limit: Maximum number of feeds to return per page.
|
|
98
|
+
offset: Number of feeds to skip for pagination.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
A Page containing feed records with pagination metadata.
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
Knowledge2Error: If the API request fails.
|
|
105
|
+
"""
|
|
106
|
+
params: dict[str, Any] = {}
|
|
107
|
+
if project_id is not None:
|
|
108
|
+
params["project_id"] = project_id
|
|
109
|
+
return await self._list_page(
|
|
110
|
+
"GET",
|
|
111
|
+
"/v1/feeds",
|
|
112
|
+
items_key="feeds",
|
|
113
|
+
params=params or None,
|
|
114
|
+
limit=limit,
|
|
115
|
+
offset=offset,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
async def get_feed(
|
|
119
|
+
self,
|
|
120
|
+
feed_id: str,
|
|
121
|
+
request_options: RequestOptions | None = None,
|
|
122
|
+
) -> dict[str, Any]:
|
|
123
|
+
"""Retrieve a single feed by ID.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
feed_id: Unique identifier of the feed.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
The feed record.
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
NotFoundError: If the feed does not exist.
|
|
133
|
+
Knowledge2Error: If the API request fails.
|
|
134
|
+
"""
|
|
135
|
+
feed_id = require_str(feed_id, "feed_id")
|
|
136
|
+
data = await self._request("GET", f"/v1/feeds/{feed_id}", request_options=request_options)
|
|
137
|
+
return self._maybe_validate(data, "FeedResponse")
|
|
138
|
+
|
|
139
|
+
async def update_feed(
|
|
140
|
+
self,
|
|
141
|
+
feed_id: str,
|
|
142
|
+
*,
|
|
143
|
+
name: str | None = None,
|
|
144
|
+
query: str | None = None,
|
|
145
|
+
top_k: int | None = None,
|
|
146
|
+
metadata_filters: dict[str, Any] | None = None,
|
|
147
|
+
reactive: bool | None = None,
|
|
148
|
+
schedule_interval: str | None = None,
|
|
149
|
+
schedule_hour: int | None = None,
|
|
150
|
+
request_options: RequestOptions | None = None,
|
|
151
|
+
) -> dict[str, Any]:
|
|
152
|
+
"""Update feed settings.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
feed_id: ID of the feed to update.
|
|
156
|
+
name: New name for the feed.
|
|
157
|
+
query: New query string for the feed.
|
|
158
|
+
top_k: New number of top results to return per run.
|
|
159
|
+
metadata_filters: New metadata filter dictionary.
|
|
160
|
+
reactive: Whether the feed triggers on new data automatically.
|
|
161
|
+
schedule_interval: New cron-style schedule interval.
|
|
162
|
+
schedule_hour: UTC hour (0-23) for daily scheduled feeds. Only
|
|
163
|
+
valid when schedule_interval is ``'1d'``.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Updated feed record.
|
|
167
|
+
|
|
168
|
+
Raises:
|
|
169
|
+
NotFoundError: If the feed does not exist.
|
|
170
|
+
Knowledge2Error: If the API request fails.
|
|
171
|
+
"""
|
|
172
|
+
feed_id = require_str(feed_id, "feed_id")
|
|
173
|
+
payload: dict[str, Any] = {}
|
|
174
|
+
if name is not None:
|
|
175
|
+
payload["name"] = name
|
|
176
|
+
if query is not None:
|
|
177
|
+
payload["query"] = query
|
|
178
|
+
if top_k is not None:
|
|
179
|
+
payload["top_k"] = top_k
|
|
180
|
+
if metadata_filters is not None:
|
|
181
|
+
payload["metadata_filters"] = metadata_filters
|
|
182
|
+
if reactive is not None:
|
|
183
|
+
payload["reactive"] = reactive
|
|
184
|
+
if schedule_interval is not None:
|
|
185
|
+
payload["schedule_interval"] = schedule_interval
|
|
186
|
+
if schedule_hour is not None:
|
|
187
|
+
payload["schedule_hour"] = schedule_hour
|
|
188
|
+
data = await self._request(
|
|
189
|
+
"PATCH", f"/v1/feeds/{feed_id}", json=payload, request_options=request_options
|
|
190
|
+
)
|
|
191
|
+
return self._maybe_validate(data, "FeedResponse")
|
|
192
|
+
|
|
193
|
+
async def delete_feed(
|
|
194
|
+
self,
|
|
195
|
+
feed_id: str,
|
|
196
|
+
request_options: RequestOptions | None = None,
|
|
197
|
+
) -> None:
|
|
198
|
+
"""Delete a feed.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
feed_id: Unique identifier of the feed to delete.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
None (the API returns 204 No Content on success).
|
|
205
|
+
|
|
206
|
+
Raises:
|
|
207
|
+
NotFoundError: If the feed does not exist.
|
|
208
|
+
Knowledge2Error: If the API request fails.
|
|
209
|
+
"""
|
|
210
|
+
feed_id = require_str(feed_id, "feed_id")
|
|
211
|
+
await self._request("DELETE", f"/v1/feeds/{feed_id}", request_options=request_options)
|
|
212
|
+
|
|
213
|
+
async def run_feed(
|
|
214
|
+
self,
|
|
215
|
+
feed_id: str,
|
|
216
|
+
*,
|
|
217
|
+
return_results: bool | None = None,
|
|
218
|
+
dry_run: bool = False,
|
|
219
|
+
request_options: RequestOptions | None = None,
|
|
220
|
+
) -> dict[str, Any]:
|
|
221
|
+
"""Trigger a feed run.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
feed_id: Unique identifier of the feed to run.
|
|
225
|
+
return_results: Whether to include results in the response.
|
|
226
|
+
When ``None`` (default), the API applies a smart default
|
|
227
|
+
based on feed type (``True`` for standard, ``False`` for
|
|
228
|
+
persistent feeds).
|
|
229
|
+
dry_run: If ``True``, simulate the run without persisting results.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
A dict containing the feed run results and metadata.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
NotFoundError: If the feed does not exist.
|
|
236
|
+
Knowledge2Error: If the API request fails.
|
|
237
|
+
"""
|
|
238
|
+
feed_id = require_str(feed_id, "feed_id")
|
|
239
|
+
params: dict[str, Any] = {"dry_run": dry_run}
|
|
240
|
+
if return_results is not None:
|
|
241
|
+
params["return_results"] = return_results
|
|
242
|
+
data = await self._request(
|
|
243
|
+
"POST",
|
|
244
|
+
f"/v1/feeds/{feed_id}/run",
|
|
245
|
+
params=params,
|
|
246
|
+
request_options=request_options,
|
|
247
|
+
)
|
|
248
|
+
return self._maybe_validate(data, "FeedRunResponse")
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Async index management resource mixin for the Knowledge2 SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
from sdk._request_options import RequestOptions
|
|
8
|
+
from sdk._validation import require_str
|
|
9
|
+
from sdk.async_resources._mixin_base import AsyncRequesterMixin
|
|
10
|
+
from sdk.types import IndexBuildResponse, IndexCompactResponse, IndexStatusResponse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AsyncIndexesMixin(AsyncRequesterMixin):
|
|
14
|
+
async def sync_indexes(
|
|
15
|
+
self,
|
|
16
|
+
corpus_id: str,
|
|
17
|
+
*,
|
|
18
|
+
wait: bool = True,
|
|
19
|
+
poll_s: int = 5,
|
|
20
|
+
idempotency_key: str | None = None,
|
|
21
|
+
) -> IndexBuildResponse:
|
|
22
|
+
"""Synchronize the default core retrieval indexes for a corpus.
|
|
23
|
+
|
|
24
|
+
This is the simplest public indexing entrypoint. It queues the platform's
|
|
25
|
+
synchronized core retrieval snapshot using the default automatic
|
|
26
|
+
incremental behavior and does not request GraphRAG artifacts.
|
|
27
|
+
"""
|
|
28
|
+
corpus_id = require_str(corpus_id, "corpus_id")
|
|
29
|
+
headers = self._idempotency_headers(idempotency_key)
|
|
30
|
+
data = await self._request(
|
|
31
|
+
"POST",
|
|
32
|
+
f"/v1/corpora/{corpus_id}/indexes:sync",
|
|
33
|
+
headers=headers,
|
|
34
|
+
)
|
|
35
|
+
if wait:
|
|
36
|
+
job_id = data.get("job_id")
|
|
37
|
+
if job_id:
|
|
38
|
+
await self._wait_for_job(job_id, poll_s=poll_s)
|
|
39
|
+
return cast("IndexBuildResponse", data)
|
|
40
|
+
|
|
41
|
+
async def build_indexes(
|
|
42
|
+
self,
|
|
43
|
+
corpus_id: str,
|
|
44
|
+
dense: bool = True,
|
|
45
|
+
sparse: bool = True,
|
|
46
|
+
sparse_metadata: bool | None = None,
|
|
47
|
+
mode: str = "incremental",
|
|
48
|
+
idempotency_key: str | None = None,
|
|
49
|
+
*,
|
|
50
|
+
sparse_metadata_required: bool = False,
|
|
51
|
+
wait: bool = True,
|
|
52
|
+
poll_s: int = 5,
|
|
53
|
+
request_options: RequestOptions | None = None,
|
|
54
|
+
) -> IndexBuildResponse:
|
|
55
|
+
"""Advanced index build entrypoint for a corpus.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
corpus_id: The corpus to build indexes for.
|
|
59
|
+
dense: Whether to build a dense (vector) index.
|
|
60
|
+
sparse: Whether to build a sparse (BM25) index.
|
|
61
|
+
sparse_metadata: Whether to build the metadata sparse (BM25)
|
|
62
|
+
index. ``None`` uses the server default.
|
|
63
|
+
sparse_metadata_required: Whether metadata sparse is required for
|
|
64
|
+
successful completion. When ``True``, a metadata-sparse skip is
|
|
65
|
+
treated as a build failure.
|
|
66
|
+
mode: Build mode -- ``"incremental"`` is the default synchronized
|
|
67
|
+
snapshot path, while ``"full"`` forces a rebuild from scratch.
|
|
68
|
+
idempotency_key: Optional idempotency key to prevent
|
|
69
|
+
duplicate builds.
|
|
70
|
+
wait: If ``True`` (default), block until the index build
|
|
71
|
+
job completes.
|
|
72
|
+
poll_s: Polling interval in seconds when *wait* is ``True``.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
The index build response, including the background job ID.
|
|
76
|
+
|
|
77
|
+
Raises:
|
|
78
|
+
NotFoundError: If the corpus does not exist.
|
|
79
|
+
ConflictError: If a duplicate idempotency key is detected.
|
|
80
|
+
Knowledge2Error: If the API request fails.
|
|
81
|
+
"""
|
|
82
|
+
corpus_id = require_str(corpus_id, "corpus_id")
|
|
83
|
+
payload = {"dense": dense, "sparse": sparse, "mode": mode}
|
|
84
|
+
if sparse_metadata is not None:
|
|
85
|
+
payload["sparse_metadata"] = bool(sparse_metadata)
|
|
86
|
+
if sparse_metadata_required:
|
|
87
|
+
payload["sparse_metadata_required"] = True
|
|
88
|
+
headers = self._idempotency_headers(idempotency_key)
|
|
89
|
+
data = await self._request(
|
|
90
|
+
"POST",
|
|
91
|
+
f"/v1/corpora/{corpus_id}/indexes:build",
|
|
92
|
+
json=payload,
|
|
93
|
+
headers=headers,
|
|
94
|
+
request_options=request_options,
|
|
95
|
+
)
|
|
96
|
+
if wait:
|
|
97
|
+
job_id = data.get("job_id")
|
|
98
|
+
if job_id:
|
|
99
|
+
await self._wait_for_job(job_id, poll_s=poll_s)
|
|
100
|
+
return cast("IndexBuildResponse", self._maybe_validate(data, "IndexBuildResponse"))
|
|
101
|
+
|
|
102
|
+
async def index_status(
|
|
103
|
+
self,
|
|
104
|
+
corpus_id: str,
|
|
105
|
+
request_options: RequestOptions | None = None,
|
|
106
|
+
) -> IndexStatusResponse:
|
|
107
|
+
"""Retrieve the current index status for a corpus.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
corpus_id: The corpus to check.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Index status including dense/sparse readiness and row counts.
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
NotFoundError: If the corpus does not exist.
|
|
117
|
+
Knowledge2Error: If the API request fails.
|
|
118
|
+
"""
|
|
119
|
+
corpus_id = require_str(corpus_id, "corpus_id")
|
|
120
|
+
data = await self._request(
|
|
121
|
+
"GET", f"/v1/corpora/{corpus_id}/indexes/status", request_options=request_options
|
|
122
|
+
)
|
|
123
|
+
return self._maybe_validate(data, "IndexStatusResponse")
|
|
124
|
+
|
|
125
|
+
async def rebuild_indexes(
|
|
126
|
+
self,
|
|
127
|
+
corpus_id: str,
|
|
128
|
+
dense: bool = True,
|
|
129
|
+
sparse: bool = True,
|
|
130
|
+
sparse_metadata: bool | None = None,
|
|
131
|
+
idempotency_key: str | None = None,
|
|
132
|
+
*,
|
|
133
|
+
sparse_metadata_required: bool = False,
|
|
134
|
+
request_options: RequestOptions | None = None,
|
|
135
|
+
) -> IndexBuildResponse:
|
|
136
|
+
"""Force a full rebuild of indexes for a corpus.
|
|
137
|
+
|
|
138
|
+
Unlike :meth:`build_indexes`, this always performs a full rebuild
|
|
139
|
+
regardless of existing index state.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
corpus_id: The corpus to rebuild indexes for.
|
|
143
|
+
dense: Whether to rebuild the dense (vector) index.
|
|
144
|
+
sparse: Whether to rebuild the sparse (BM25) index.
|
|
145
|
+
sparse_metadata: Whether to rebuild the metadata sparse
|
|
146
|
+
(BM25) index. ``None`` uses the server default.
|
|
147
|
+
sparse_metadata_required: Whether metadata sparse is required for
|
|
148
|
+
successful completion. When ``True``, a metadata-sparse skip is
|
|
149
|
+
treated as a build failure.
|
|
150
|
+
idempotency_key: Optional idempotency key to prevent
|
|
151
|
+
duplicate rebuilds.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
The index build response, including the background job ID.
|
|
155
|
+
|
|
156
|
+
Raises:
|
|
157
|
+
NotFoundError: If the corpus does not exist.
|
|
158
|
+
ConflictError: If a duplicate idempotency key is detected.
|
|
159
|
+
Knowledge2Error: If the API request fails.
|
|
160
|
+
"""
|
|
161
|
+
corpus_id = require_str(corpus_id, "corpus_id")
|
|
162
|
+
payload = {"dense": dense, "sparse": sparse, "mode": "full"}
|
|
163
|
+
if sparse_metadata is not None:
|
|
164
|
+
payload["sparse_metadata"] = bool(sparse_metadata)
|
|
165
|
+
if sparse_metadata_required:
|
|
166
|
+
payload["sparse_metadata_required"] = True
|
|
167
|
+
headers = self._idempotency_headers(idempotency_key)
|
|
168
|
+
data = await self._request(
|
|
169
|
+
"POST",
|
|
170
|
+
f"/v1/corpora/{corpus_id}/indexes:rebuild",
|
|
171
|
+
json=payload,
|
|
172
|
+
headers=headers,
|
|
173
|
+
request_options=request_options,
|
|
174
|
+
)
|
|
175
|
+
return self._maybe_validate(data, "IndexBuildResponse")
|
|
176
|
+
|
|
177
|
+
async def compact_indexes(
|
|
178
|
+
self,
|
|
179
|
+
corpus_id: str,
|
|
180
|
+
*,
|
|
181
|
+
dense: bool = True,
|
|
182
|
+
sparse: bool = True,
|
|
183
|
+
keep: int = 1,
|
|
184
|
+
request_options: RequestOptions | None = None,
|
|
185
|
+
) -> IndexCompactResponse:
|
|
186
|
+
"""Compact index artifacts for a corpus, removing old generations.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
corpus_id: The corpus whose indexes to compact.
|
|
190
|
+
dense: Whether to compact dense index artifacts.
|
|
191
|
+
sparse: Whether to compact sparse index artifacts.
|
|
192
|
+
keep: Number of recent index generations to retain.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
A summary of compacted artifacts.
|
|
196
|
+
|
|
197
|
+
Raises:
|
|
198
|
+
NotFoundError: If the corpus does not exist.
|
|
199
|
+
Knowledge2Error: If the API request fails.
|
|
200
|
+
"""
|
|
201
|
+
corpus_id = require_str(corpus_id, "corpus_id")
|
|
202
|
+
data = await self._request(
|
|
203
|
+
"POST",
|
|
204
|
+
f"/v1/corpora/{corpus_id}/indexes:compact",
|
|
205
|
+
params={"dense": dense, "sparse": sparse, "keep": keep},
|
|
206
|
+
request_options=request_options,
|
|
207
|
+
)
|
|
208
|
+
return self._maybe_validate(data, "IndexCompactResponse")
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Async job management resource mixin for the Knowledge2 SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from sdk._async_paging import AsyncPager
|
|
8
|
+
from sdk._paging import Page
|
|
9
|
+
from sdk._request_options import RequestOptions
|
|
10
|
+
from sdk._validation import require_str
|
|
11
|
+
from sdk.async_resources._mixin_base import AsyncRequesterMixin
|
|
12
|
+
from sdk.types import JobResponse, JobStatusResponse, ReconcileJobsResponse
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AsyncJobsMixin(AsyncRequesterMixin):
|
|
16
|
+
async def get_job(
|
|
17
|
+
self,
|
|
18
|
+
job_id: str,
|
|
19
|
+
request_options: RequestOptions | None = None,
|
|
20
|
+
) -> JobResponse:
|
|
21
|
+
"""Retrieve details of a single job.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
job_id: Unique identifier of the job.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
The job record including type, status, and metadata.
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
NotFoundError: If the job does not exist.
|
|
31
|
+
Knowledge2Error: If the API request fails.
|
|
32
|
+
"""
|
|
33
|
+
job_id = require_str(job_id, "job_id")
|
|
34
|
+
data = await self._request("GET", f"/v1/jobs/{job_id}", request_options=request_options)
|
|
35
|
+
return self._maybe_validate(data, "JobResponse")
|
|
36
|
+
|
|
37
|
+
async def list_jobs(
|
|
38
|
+
self,
|
|
39
|
+
*,
|
|
40
|
+
corpus_id: str | None = None,
|
|
41
|
+
job_type: str | None = None,
|
|
42
|
+
status: str | None = None,
|
|
43
|
+
limit: int = 100,
|
|
44
|
+
offset: int = 0,
|
|
45
|
+
request_options: RequestOptions | None = None,
|
|
46
|
+
) -> Page[dict[str, Any]]:
|
|
47
|
+
"""List jobs with optional filters.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
corpus_id: Filter to jobs belonging to this corpus.
|
|
51
|
+
job_type: Filter by job type.
|
|
52
|
+
status: Filter by job status.
|
|
53
|
+
limit: Maximum number of jobs to return per page.
|
|
54
|
+
offset: Number of jobs to skip for pagination.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
A Page containing job records with pagination metadata.
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
Knowledge2Error: If the API request fails.
|
|
61
|
+
"""
|
|
62
|
+
params: dict[str, Any] = {}
|
|
63
|
+
if corpus_id:
|
|
64
|
+
params["corpus_id"] = corpus_id
|
|
65
|
+
if job_type:
|
|
66
|
+
params["job_type"] = job_type
|
|
67
|
+
if status:
|
|
68
|
+
params["status"] = status
|
|
69
|
+
return await self._list_page(
|
|
70
|
+
"GET", "/v1/jobs", items_key="jobs", params=params or None, limit=limit, offset=offset
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def iter_jobs(
|
|
74
|
+
self,
|
|
75
|
+
*,
|
|
76
|
+
corpus_id: str | None = None,
|
|
77
|
+
job_type: str | None = None,
|
|
78
|
+
status: str | None = None,
|
|
79
|
+
limit: int = 100,
|
|
80
|
+
request_options: RequestOptions | None = None,
|
|
81
|
+
) -> AsyncPager[dict[str, Any]]:
|
|
82
|
+
"""Iterate over jobs, automatically paginating.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
corpus_id: Filter to jobs belonging to this corpus.
|
|
86
|
+
job_type: Filter by job type.
|
|
87
|
+
status: Filter by job status.
|
|
88
|
+
limit: Page size used for each underlying API request.
|
|
89
|
+
|
|
90
|
+
Yields:
|
|
91
|
+
Individual job dicts.
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
Knowledge2Error: If any underlying API request fails.
|
|
95
|
+
"""
|
|
96
|
+
params: dict[str, Any] = {}
|
|
97
|
+
if corpus_id:
|
|
98
|
+
params["corpus_id"] = corpus_id
|
|
99
|
+
if job_type:
|
|
100
|
+
params["job_type"] = job_type
|
|
101
|
+
if status:
|
|
102
|
+
params["status"] = status
|
|
103
|
+
return self._paginate(
|
|
104
|
+
"GET", "/v1/jobs", items_key="jobs", params=params or None, limit=limit
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
async def cancel_job(
|
|
108
|
+
self,
|
|
109
|
+
job_id: str,
|
|
110
|
+
request_options: RequestOptions | None = None,
|
|
111
|
+
) -> JobStatusResponse:
|
|
112
|
+
"""Cancel a running or pending job.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
job_id: Unique identifier of the job to cancel.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The updated job status after cancellation.
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
NotFoundError: If the job does not exist.
|
|
122
|
+
Knowledge2Error: If the API request fails.
|
|
123
|
+
"""
|
|
124
|
+
job_id = require_str(job_id, "job_id")
|
|
125
|
+
data = await self._request(
|
|
126
|
+
"POST", f"/v1/jobs/{job_id}:cancel", request_options=request_options
|
|
127
|
+
)
|
|
128
|
+
return self._maybe_validate(data, "JobStatusResponse")
|
|
129
|
+
|
|
130
|
+
async def retry_job(
|
|
131
|
+
self,
|
|
132
|
+
job_id: str,
|
|
133
|
+
request_options: RequestOptions | None = None,
|
|
134
|
+
) -> JobStatusResponse:
|
|
135
|
+
"""Retry a failed job.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
job_id: Unique identifier of the job to retry.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
The updated job status after scheduling the retry.
|
|
142
|
+
|
|
143
|
+
Raises:
|
|
144
|
+
NotFoundError: If the job does not exist.
|
|
145
|
+
Knowledge2Error: If the API request fails.
|
|
146
|
+
"""
|
|
147
|
+
job_id = require_str(job_id, "job_id")
|
|
148
|
+
data = await self._request(
|
|
149
|
+
"POST", f"/v1/jobs/{job_id}:retry", request_options=request_options
|
|
150
|
+
)
|
|
151
|
+
return self._maybe_validate(data, "JobStatusResponse")
|
|
152
|
+
|
|
153
|
+
async def reconcile_jobs(
|
|
154
|
+
self, *, request_options: RequestOptions | None = None
|
|
155
|
+
) -> ReconcileJobsResponse:
|
|
156
|
+
"""Reconcile stale or stuck jobs across the platform.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
A summary of reconciled jobs.
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
Knowledge2Error: If the API request fails.
|
|
163
|
+
"""
|
|
164
|
+
data = await self._request("POST", "/v1/jobs:reconcile", request_options=request_options)
|
|
165
|
+
return self._maybe_validate(data, "ReconcileJobsResponse")
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Async metadata discovery resource mixin for the Knowledge2 SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from sdk._request_options import RequestOptions
|
|
8
|
+
from sdk._validation import require_str
|
|
9
|
+
from sdk.async_resources._mixin_base import AsyncRequesterMixin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AsyncMetadataMixin(AsyncRequesterMixin):
|
|
13
|
+
"""Async metadata discovery operations."""
|
|
14
|
+
|
|
15
|
+
async def discover_metadata(
|
|
16
|
+
self,
|
|
17
|
+
corpus_id: str,
|
|
18
|
+
*,
|
|
19
|
+
refresh: bool = False,
|
|
20
|
+
request_options: RequestOptions | None = None,
|
|
21
|
+
) -> dict[str, Any]:
|
|
22
|
+
"""Discover metadata fields available in a corpus.
|
|
23
|
+
|
|
24
|
+
Returns distinct metadata keys with inferred types, value
|
|
25
|
+
distributions, and basic statistics.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
corpus_id: Corpus ID to discover metadata for.
|
|
29
|
+
refresh: Force cache refresh (bypass cached results).
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Discovery response with fields, types, and stats.
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
NotFoundError: If the corpus does not exist.
|
|
36
|
+
Knowledge2Error: If the API request fails.
|
|
37
|
+
"""
|
|
38
|
+
corpus_id = require_str(corpus_id, "corpus_id")
|
|
39
|
+
params: dict[str, Any] = {}
|
|
40
|
+
if refresh:
|
|
41
|
+
params["refresh"] = "true"
|
|
42
|
+
data = await self._request(
|
|
43
|
+
"GET",
|
|
44
|
+
f"/v1/corpora/{corpus_id}/metadata/discover",
|
|
45
|
+
params=params,
|
|
46
|
+
request_options=request_options,
|
|
47
|
+
)
|
|
48
|
+
return data
|