lm-deluge 0.0.44__tar.gz → 0.0.46__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 lm-deluge might be problematic. Click here for more details.

Files changed (80) hide show
  1. {lm_deluge-0.0.44/src/lm_deluge.egg-info → lm_deluge-0.0.46}/PKG-INFO +1 -1
  2. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/pyproject.toml +1 -1
  3. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/client.py +41 -42
  4. lm_deluge-0.0.46/src/lm_deluge/presets/cerebras.py +17 -0
  5. lm_deluge-0.0.46/src/lm_deluge/presets/meta.py +13 -0
  6. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/prompt.py +19 -2
  7. {lm_deluge-0.0.44 → lm_deluge-0.0.46/src/lm_deluge.egg-info}/PKG-INFO +1 -1
  8. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge.egg-info/SOURCES.txt +2 -0
  9. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/LICENSE +0 -0
  10. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/README.md +0 -0
  11. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/setup.cfg +0 -0
  12. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/__init__.py +0 -0
  13. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/agent.py +0 -0
  14. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/__init__.py +0 -0
  15. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/anthropic.py +0 -0
  16. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/base.py +0 -0
  17. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/bedrock.py +0 -0
  18. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/common.py +0 -0
  19. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/deprecated/bedrock.py +0 -0
  20. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/deprecated/cohere.py +0 -0
  21. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/deprecated/deepseek.py +0 -0
  22. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/deprecated/mistral.py +0 -0
  23. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/deprecated/vertex.py +0 -0
  24. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/gemini.py +0 -0
  25. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/mistral.py +0 -0
  26. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/openai.py +0 -0
  27. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/api_requests/response.py +0 -0
  28. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/batches.py +0 -0
  29. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/built_in_tools/anthropic/__init__.py +0 -0
  30. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/built_in_tools/anthropic/bash.py +0 -0
  31. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/built_in_tools/anthropic/computer_use.py +0 -0
  32. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/built_in_tools/anthropic/editor.py +0 -0
  33. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/built_in_tools/base.py +0 -0
  34. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/built_in_tools/openai.py +0 -0
  35. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/cache.py +0 -0
  36. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/cli.py +0 -0
  37. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/config.py +0 -0
  38. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/embed.py +0 -0
  39. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/errors.py +0 -0
  40. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/file.py +0 -0
  41. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/gemini_limits.py +0 -0
  42. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/image.py +0 -0
  43. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/llm_tools/__init__.py +0 -0
  44. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/llm_tools/classify.py +0 -0
  45. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/llm_tools/extract.py +0 -0
  46. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/llm_tools/locate.py +0 -0
  47. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/llm_tools/ocr.py +0 -0
  48. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/llm_tools/score.py +0 -0
  49. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/llm_tools/translate.py +0 -0
  50. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/__init__.py +0 -0
  51. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/anthropic.py +0 -0
  52. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/bedrock.py +0 -0
  53. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/cerebras.py +0 -0
  54. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/cohere.py +0 -0
  55. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/deepseek.py +0 -0
  56. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/fireworks.py +0 -0
  57. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/google.py +0 -0
  58. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/grok.py +0 -0
  59. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/groq.py +0 -0
  60. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/meta.py +0 -0
  61. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/mistral.py +0 -0
  62. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/openai.py +0 -0
  63. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/openrouter.py +0 -0
  64. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/models/together.py +0 -0
  65. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/request_context.py +0 -0
  66. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/rerank.py +0 -0
  67. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/tool.py +0 -0
  68. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/tracker.py +0 -0
  69. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/usage.py +0 -0
  70. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/util/harmony.py +0 -0
  71. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/util/json.py +0 -0
  72. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/util/logprobs.py +0 -0
  73. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/util/spatial.py +0 -0
  74. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/util/validation.py +0 -0
  75. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge/util/xml.py +0 -0
  76. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge.egg-info/dependency_links.txt +0 -0
  77. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge.egg-info/requires.txt +0 -0
  78. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/src/lm_deluge.egg-info/top_level.txt +0 -0
  79. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/tests/test_builtin_tools.py +0 -0
  80. {lm_deluge-0.0.44 → lm_deluge-0.0.46}/tests/test_native_mcp_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lm_deluge
3
- Version: 0.0.44
3
+ Version: 0.0.46
4
4
  Summary: Python utility for using LLM API models.
5
5
  Author-email: Benjamin Anderson <ben@trytaylor.ai>
6
6
  Requires-Python: >=3.10
@@ -3,7 +3,7 @@ requires = ["setuptools", "wheel"]
3
3
 
4
4
  [project]
5
5
  name = "lm_deluge"
6
- version = "0.0.44"
6
+ version = "0.0.46"
7
7
  authors = [{ name = "Benjamin Anderson", email = "ben@trytaylor.ai" }]
8
8
  description = "Python utility for using LLM API models."
9
9
  readme = "README.md"
@@ -217,17 +217,19 @@ class _LLMClient(BaseModel):
217
217
  self, num_tokens: int, tracker: StatusTracker, *, retry: bool = False
218
218
  ):
219
219
  while True:
220
+ # Enforce cooldown first, regardless of current capacity.
221
+ cooldown = tracker.seconds_to_pause
222
+ if cooldown > 0:
223
+ print(f"Pausing for {cooldown} seconds to cool down.")
224
+ await asyncio.sleep(cooldown)
225
+ continue
226
+
220
227
  async with self._capacity_lock:
221
228
  if tracker.check_capacity(num_tokens, retry=retry):
222
229
  tracker.set_limiting_factor(None)
223
230
  return
224
- seconds_to_pause = tracker.seconds_to_pause
225
-
226
- if seconds_to_pause > 0:
227
- print(f"Pausing for {seconds_to_pause} seconds to cool down.")
228
- await asyncio.sleep(seconds_to_pause)
229
- else:
230
- await asyncio.sleep(30.0 / self.max_requests_per_minute)
231
+ # Idle wait before next capacity check. Aim for ~RPM spacing.
232
+ await asyncio.sleep(max(60.0 / self.max_requests_per_minute, 0.01))
231
233
 
232
234
  async def _execute_request(self, context: RequestContext) -> APIResponse:
233
235
  """Create and send a single API request using the provided context."""
@@ -363,7 +365,7 @@ class _LLMClient(BaseModel):
363
365
  # Create retry queue for failed requests
364
366
  retry_queue: asyncio.Queue[RequestContext] = asyncio.Queue()
365
367
 
366
- # Calculate sleep time for rate limiting
368
+ # Calculate sleep time for rate limiting (legacy; gating happens in _wait_for_capacity)
367
369
  seconds_to_sleep_each_loop = (60.0 * 0.9) / tracker.max_requests_per_minute
368
370
 
369
371
  # Main dispatch loop - using original pattern but with all prompts
@@ -403,40 +405,37 @@ class _LLMClient(BaseModel):
403
405
  except StopIteration:
404
406
  prompts_not_finished = False
405
407
 
406
- # Update capacity - original logic
407
- tracker.update_capacity()
408
-
409
- # Dispatch if capacity available - original logic
408
+ # Dispatch using shared capacity gate (consistent with start_nowait)
410
409
  if next_context:
411
- if tracker.check_capacity(next_context.num_tokens, retry=next_is_retry):
412
- tracker.set_limiting_factor(None)
410
+ # Wait here until we have capacity to launch this context
411
+ await self._wait_for_capacity(
412
+ next_context.num_tokens, tracker, retry=next_is_retry
413
+ )
414
+
415
+ # Launch simplified request processing
416
+ async def process_and_store(ctx: RequestContext):
417
+ try:
418
+ response = await self.process_single_request(ctx, retry_queue)
419
+ results[ctx.task_id] = response
420
+ except Exception as e:
421
+ # Create an error response for validation errors and other exceptions
422
+ error_response = APIResponse(
423
+ id=ctx.task_id,
424
+ model_internal=ctx.model_name,
425
+ prompt=ctx.prompt,
426
+ sampling_params=ctx.sampling_params,
427
+ status_code=None,
428
+ is_error=True,
429
+ error_message=str(e),
430
+ )
431
+ results[ctx.task_id] = error_response
432
+ # Mark task as completed so the main loop can finish
433
+ if ctx.status_tracker:
434
+ ctx.status_tracker.task_failed(ctx.task_id)
413
435
 
414
- # Launch simplified request processing
415
- async def process_and_store(ctx: RequestContext):
416
- try:
417
- response = await self.process_single_request(
418
- ctx, retry_queue
419
- )
420
- results[ctx.task_id] = response
421
- except Exception as e:
422
- # Create an error response for validation errors and other exceptions
423
- error_response = APIResponse(
424
- id=ctx.task_id,
425
- model_internal=ctx.model_name,
426
- prompt=ctx.prompt,
427
- sampling_params=ctx.sampling_params,
428
- status_code=None,
429
- is_error=True,
430
- error_message=str(e),
431
- )
432
- results[ctx.task_id] = error_response
433
- # Mark task as completed so the main loop can finish
434
- if ctx.status_tracker:
435
- ctx.status_tracker.task_failed(ctx.task_id)
436
-
437
- asyncio.create_task(process_and_store(next_context))
438
- next_context = None # Reset after successful dispatch
439
- next_is_retry = False
436
+ asyncio.create_task(process_and_store(next_context))
437
+ next_context = None # Reset after successful dispatch
438
+ next_is_retry = False
440
439
 
441
440
  # Update progress - original logic
442
441
  tracker.update_pbar()
@@ -448,8 +447,8 @@ class _LLMClient(BaseModel):
448
447
  ) and retry_queue.empty():
449
448
  break
450
449
 
451
- # Sleep - original logic
452
- await asyncio.sleep(seconds_to_sleep_each_loop + tracker.seconds_to_pause)
450
+ # Yield briefly to allow in-flight tasks to progress
451
+ await asyncio.sleep(min(0.01, seconds_to_sleep_each_loop))
453
452
 
454
453
  if not tracker_preopened:
455
454
  self.close()
@@ -0,0 +1,17 @@
1
+ from lm_deluge import LLMClient
2
+
3
+ mixture_of_cerebras = LLMClient(
4
+ [
5
+ "gpt-oss-120b-cerebras",
6
+ "llama-4-scout-cerebras",
7
+ "llama-3.3-70b-cerebras",
8
+ "qwen-3-32b-cerebras",
9
+ "llama-4-maverick-cerebras",
10
+ "qwen-3-235b-instruct-cerebras",
11
+ "qwen-3-235b-thinking-cerebras",
12
+ "qwen-3-coder-cerebras",
13
+ ],
14
+ model_weights=[3, 3, 3, 3, 3, 3, 3, 1],
15
+ max_requests_per_minute=250,
16
+ max_tokens_per_minute=1_000_000,
17
+ )
@@ -0,0 +1,13 @@
1
+ from lm_deluge import LLMClient
2
+
3
+ mixture_of_llamas = LLMClient(
4
+ ["llama-4-scout", "llama-4-maverick", "llama-3.3-70b", "llama-3.3-8b"],
5
+ max_requests_per_minute=12_000,
6
+ max_tokens_per_minute=4_000_000,
7
+ )
8
+
9
+ multimodal_llamas = LLMClient(
10
+ ["llama-4-scout", "llama-4-maverick"],
11
+ max_requests_per_minute=6_000,
12
+ max_tokens_per_minute=2_000_000,
13
+ )
@@ -333,6 +333,23 @@ class Message:
333
333
  """
334
334
  Return a JSON-serialisable dict that fully captures the message.
335
335
  """
336
+ def _json_safe(value):
337
+ if isinstance(value, (str, int, float, bool)) or value is None:
338
+ return value
339
+ if isinstance(value, list):
340
+ return [_json_safe(v) for v in value]
341
+ if isinstance(value, dict):
342
+ return {k: _json_safe(v) for k, v in value.items()}
343
+ if isinstance(value, Text):
344
+ return {"type": "text", "text": value.text}
345
+ if isinstance(value, Image):
346
+ w, h = value.size
347
+ return {"type": "image", "tag": f"<Image ({w}×{h})>"}
348
+ if isinstance(value, File):
349
+ size = value.size
350
+ return {"type": "file", "tag": f"<File ({size} bytes)>"}
351
+ return repr(value)
352
+
336
353
  content_blocks: list[dict] = []
337
354
  for p in self.parts:
338
355
  if isinstance(p, Text):
@@ -349,7 +366,7 @@ class Message:
349
366
  "type": "tool_call",
350
367
  "id": p.id,
351
368
  "name": p.name,
352
- "arguments": p.arguments,
369
+ "arguments": _json_safe(p.arguments),
353
370
  }
354
371
  )
355
372
  elif isinstance(p, ToolResult):
@@ -357,7 +374,7 @@ class Message:
357
374
  {
358
375
  "type": "tool_result",
359
376
  "tool_call_id": p.tool_call_id,
360
- "result": p.result,
377
+ "result": _json_safe(p.result),
361
378
  }
362
379
  )
363
380
  elif isinstance(p, Thinking):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lm_deluge
3
- Version: 0.0.44
3
+ Version: 0.0.46
4
4
  Summary: Python utility for using LLM API models.
5
5
  Author-email: Benjamin Anderson <ben@trytaylor.ai>
6
6
  Requires-Python: >=3.10
@@ -66,6 +66,8 @@ src/lm_deluge/models/mistral.py
66
66
  src/lm_deluge/models/openai.py
67
67
  src/lm_deluge/models/openrouter.py
68
68
  src/lm_deluge/models/together.py
69
+ src/lm_deluge/presets/cerebras.py
70
+ src/lm_deluge/presets/meta.py
69
71
  src/lm_deluge/util/harmony.py
70
72
  src/lm_deluge/util/json.py
71
73
  src/lm_deluge/util/logprobs.py
File without changes
File without changes
File without changes