docent-python 0.1.17a0__py3-none-any.whl → 0.1.18a0__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.
Potentially problematic release.
This version of docent-python might be problematic. Click here for more details.
- docent/sdk/agent_run_writer.py +47 -17
- {docent_python-0.1.17a0.dist-info → docent_python-0.1.18a0.dist-info}/METADATA +1 -1
- {docent_python-0.1.17a0.dist-info → docent_python-0.1.18a0.dist-info}/RECORD +5 -5
- {docent_python-0.1.17a0.dist-info → docent_python-0.1.18a0.dist-info}/WHEEL +0 -0
- {docent_python-0.1.17a0.dist-info → docent_python-0.1.18a0.dist-info}/licenses/LICENSE.md +0 -0
docent/sdk/agent_run_writer.py
CHANGED
|
@@ -19,11 +19,16 @@ logger = get_logger(__name__)
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def _giveup(exc: BaseException) -> bool:
|
|
22
|
-
"""Give up on client errors."""
|
|
22
|
+
"""Give up on timeouts and client errors (4xx except 429). Retry others."""
|
|
23
|
+
|
|
24
|
+
# Give up immediately on any timeout (connect/read/write/pool)
|
|
25
|
+
if isinstance(exc, httpx.TimeoutException):
|
|
26
|
+
return True
|
|
23
27
|
|
|
24
28
|
if isinstance(exc, httpx.HTTPStatusError):
|
|
25
29
|
status = exc.response.status_code
|
|
26
30
|
return status < 500 and status != 429
|
|
31
|
+
|
|
27
32
|
return False
|
|
28
33
|
|
|
29
34
|
|
|
@@ -92,7 +97,6 @@ class AgentRunWriter:
|
|
|
92
97
|
self._thread = threading.Thread(
|
|
93
98
|
target=lambda: anyio.run(self._async_main),
|
|
94
99
|
name="AgentRunWriterThread",
|
|
95
|
-
daemon=True,
|
|
96
100
|
)
|
|
97
101
|
self._thread.start()
|
|
98
102
|
logger.info("AgentRunWriter thread started")
|
|
@@ -179,7 +183,7 @@ class AgentRunWriter:
|
|
|
179
183
|
|
|
180
184
|
def get_post_batch_fcn(
|
|
181
185
|
self, client: httpx.AsyncClient
|
|
182
|
-
) -> Callable[[list[AgentRun]
|
|
186
|
+
) -> Callable[[list[AgentRun]], Coroutine[Any, Any, None]]:
|
|
183
187
|
"""Return a function that will post a batch of agent runs to the API."""
|
|
184
188
|
|
|
185
189
|
@backoff.on_exception(
|
|
@@ -189,34 +193,34 @@ class AgentRunWriter:
|
|
|
189
193
|
max_tries=self._max_retries,
|
|
190
194
|
on_backoff=_print_backoff_message,
|
|
191
195
|
)
|
|
192
|
-
async def _post_batch(batch: list[AgentRun]
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
self._endpoint, json=payload, timeout=self._request_timeout
|
|
197
|
-
)
|
|
198
|
-
resp.raise_for_status()
|
|
196
|
+
async def _post_batch(batch: list[AgentRun]) -> None:
|
|
197
|
+
payload = {"agent_runs": [ar.model_dump(mode="json") for ar in batch]}
|
|
198
|
+
resp = await client.post(self._endpoint, json=payload, timeout=self._request_timeout)
|
|
199
|
+
resp.raise_for_status()
|
|
199
200
|
|
|
200
201
|
return _post_batch
|
|
201
202
|
|
|
202
203
|
async def _async_main(self) -> None:
|
|
203
204
|
"""Main async function for the AgentRunWriter thread."""
|
|
204
205
|
|
|
205
|
-
limiter = anyio.CapacityLimiter(self._num_workers)
|
|
206
|
-
|
|
207
206
|
async with httpx.AsyncClient(base_url=self._base_url, headers=self._headers) as client:
|
|
207
|
+
_post_batch = self.get_post_batch_fcn(client)
|
|
208
208
|
async with anyio.create_task_group() as tg:
|
|
209
|
-
_post_batch = self.get_post_batch_fcn(client)
|
|
210
209
|
|
|
211
|
-
async def
|
|
210
|
+
async def worker():
|
|
212
211
|
while not self._cancel_event.is_set():
|
|
213
212
|
batch = await self._gather_next_batch_from_queue()
|
|
214
213
|
if not batch:
|
|
215
214
|
continue
|
|
215
|
+
try:
|
|
216
|
+
await _post_batch(batch)
|
|
217
|
+
except Exception as e:
|
|
218
|
+
logger.error(
|
|
219
|
+
f"Failed to post batch of {len(batch)} agent runs: {e.__class__.__name__}: {e}"
|
|
220
|
+
)
|
|
216
221
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
tg.start_soon(batch_loop)
|
|
222
|
+
for _ in range(self._num_workers):
|
|
223
|
+
tg.start_soon(worker)
|
|
220
224
|
|
|
221
225
|
async def _gather_next_batch_from_queue(self) -> list[AgentRun]:
|
|
222
226
|
"""Gather a batch of agent runs from the queue.
|
|
@@ -241,6 +245,14 @@ def init(
|
|
|
241
245
|
server_url: str = "https://api.docent.transluce.org",
|
|
242
246
|
web_url: str = "https://docent.transluce.org",
|
|
243
247
|
api_key: str | None = None,
|
|
248
|
+
# Writer arguments
|
|
249
|
+
num_workers: int = 2,
|
|
250
|
+
queue_maxsize: int = 20_000,
|
|
251
|
+
request_timeout: float = 30.0,
|
|
252
|
+
flush_interval: float = 1.0,
|
|
253
|
+
batch_size: int = 1_000,
|
|
254
|
+
max_retries: int = 5,
|
|
255
|
+
shutdown_timeout: int = 60,
|
|
244
256
|
):
|
|
245
257
|
"""Initialize the AgentRunWriter thread.
|
|
246
258
|
|
|
@@ -250,6 +262,16 @@ def init(
|
|
|
250
262
|
server_url (str): URL of the Docent server.
|
|
251
263
|
web_url (str): URL of the Docent web UI.
|
|
252
264
|
api_key (str): API key for the Docent API.
|
|
265
|
+
num_workers (int): Max number of concurrent tasks to run,
|
|
266
|
+
managed by anyio.CapacityLimiter.
|
|
267
|
+
queue_maxsize (int): Maximum size of the queue.
|
|
268
|
+
If maxsize is <= 0, the queue size is infinite.
|
|
269
|
+
request_timeout (float): Timeout for the HTTP request.
|
|
270
|
+
flush_interval (float): Interval to flush the queue.
|
|
271
|
+
batch_size (int): Number of agent runs to batch together.
|
|
272
|
+
max_retries (int): Maximum number of retries for the HTTP request.
|
|
273
|
+
shutdown_timeout (int): Timeout to wait for the background thread to finish
|
|
274
|
+
after the main thread has requested shutdown.
|
|
253
275
|
"""
|
|
254
276
|
api_key = api_key or os.getenv("DOCENT_API_KEY")
|
|
255
277
|
|
|
@@ -271,4 +293,12 @@ def init(
|
|
|
271
293
|
api_key=api_key,
|
|
272
294
|
collection_id=collection_id,
|
|
273
295
|
server_url=server_url,
|
|
296
|
+
# Writer arguments
|
|
297
|
+
num_workers=num_workers,
|
|
298
|
+
queue_maxsize=queue_maxsize,
|
|
299
|
+
request_timeout=request_timeout,
|
|
300
|
+
flush_interval=flush_interval,
|
|
301
|
+
batch_size=batch_size,
|
|
302
|
+
max_retries=max_retries,
|
|
303
|
+
shutdown_timeout=shutdown_timeout,
|
|
274
304
|
)
|
|
@@ -24,9 +24,9 @@ docent/samples/load.py,sha256=ZGE07r83GBNO4A0QBh5aQ18WAu3mTWA1vxUoHd90nrM,207
|
|
|
24
24
|
docent/samples/log.eval,sha256=orrW__9WBfANq7NwKsPSq9oTsQRcG6KohG5tMr_X_XY,397708
|
|
25
25
|
docent/samples/tb_airline.json,sha256=eR2jFFRtOw06xqbEglh6-dPewjifOk-cuxJq67Dtu5I,47028
|
|
26
26
|
docent/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
-
docent/sdk/agent_run_writer.py,sha256=
|
|
27
|
+
docent/sdk/agent_run_writer.py,sha256=nxLBwCjkalDI33XNEUEWdPinio5MN2xGnch5UbvAJtU,10740
|
|
28
28
|
docent/sdk/client.py,sha256=fuJrTF87OtUojULFY7acZuqg5xmE8F-4HgEeEV8_gq0,14781
|
|
29
|
-
docent_python-0.1.
|
|
30
|
-
docent_python-0.1.
|
|
31
|
-
docent_python-0.1.
|
|
32
|
-
docent_python-0.1.
|
|
29
|
+
docent_python-0.1.18a0.dist-info/METADATA,sha256=_PsOAABH2m3ycl1PjRNhdnFNC1o5e_j0O5-OHHh1diA,1110
|
|
30
|
+
docent_python-0.1.18a0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
31
|
+
docent_python-0.1.18a0.dist-info/licenses/LICENSE.md,sha256=QIMv2UiT6MppRasso4ymaA0w7ltkqmlL0HCt8CLD7Rc,580
|
|
32
|
+
docent_python-0.1.18a0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|