docent-python 0.1.17a0__tar.gz → 0.1.18a0__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.

Potentially problematic release.


This version of docent-python might be problematic. Click here for more details.

Files changed (34) hide show
  1. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/PKG-INFO +1 -1
  2. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/sdk/agent_run_writer.py +47 -17
  3. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/pyproject.toml +1 -1
  4. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/.gitignore +0 -0
  5. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/LICENSE.md +0 -0
  6. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/README.md +0 -0
  7. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/__init__.py +0 -0
  8. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/_log_util/__init__.py +0 -0
  9. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/_log_util/logger.py +0 -0
  10. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/__init__.py +0 -0
  11. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/_tiktoken_util.py +0 -0
  12. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/agent_run.py +0 -0
  13. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/chat/__init__.py +0 -0
  14. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/chat/content.py +0 -0
  15. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/chat/message.py +0 -0
  16. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/chat/tool.py +0 -0
  17. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/citation.py +0 -0
  18. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/metadata.py +0 -0
  19. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/regex.py +0 -0
  20. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/remove_invalid_citation_ranges.py +0 -0
  21. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/shared_types.py +0 -0
  22. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/transcript.py +0 -0
  23. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/data_models/yaml_util.py +0 -0
  24. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/loaders/load_inspect.py +0 -0
  25. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/py.typed +0 -0
  26. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/samples/__init__.py +0 -0
  27. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/samples/load.py +0 -0
  28. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/samples/log.eval +0 -0
  29. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/samples/tb_airline.json +0 -0
  30. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/sdk/__init__.py +0 -0
  31. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/sdk/client.py +0 -0
  32. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/trace.py +0 -0
  33. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/docent/trace_temp.py +0 -0
  34. {docent_python-0.1.17a0 → docent_python-0.1.18a0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docent-python
3
- Version: 0.1.17a0
3
+ Version: 0.1.18a0
4
4
  Summary: Docent SDK
5
5
  Project-URL: Homepage, https://github.com/TransluceAI/docent
6
6
  Project-URL: Issues, https://github.com/TransluceAI/docent/issues
@@ -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], anyio.CapacityLimiter], Coroutine[Any, Any, None]]:
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], limiter: anyio.CapacityLimiter) -> None:
193
- async with limiter:
194
- payload = {"agent_runs": [ar.model_dump(mode="json") for ar in batch]}
195
- resp = await client.post(
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 batch_loop() -> None:
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
- tg.start_soon(_post_batch, batch, limiter)
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
  )
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "docent-python"
3
3
  description = "Docent SDK"
4
- version = "0.1.17-alpha"
4
+ version = "0.1.18-alpha"
5
5
  authors = [
6
6
  { name="Transluce", email="info@transluce.org" },
7
7
  ]