code-puppy 0.0.144__py3-none-any.whl → 0.0.145__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.
@@ -255,6 +255,9 @@ class ModelFactory:
255
255
  if not model_names or not isinstance(model_names, list):
256
256
  raise ValueError(f"Round-robin model '{model_name}' requires a 'models' list in its configuration.")
257
257
 
258
+ # Get the rotate_every parameter (default: 1)
259
+ rotate_every = model_config.get("rotate_every", 1)
260
+
258
261
  # Resolve each model name to an actual model instance
259
262
  models = []
260
263
  for name in model_names:
@@ -263,7 +266,7 @@ class ModelFactory:
263
266
  models.append(model)
264
267
 
265
268
  # Create and return the round-robin model
266
- return RoundRobinModel(*models)
269
+ return RoundRobinModel(*models, rotate_every=rotate_every)
267
270
 
268
271
  else:
269
272
  raise ValueError(f"Unsupported model type: {model_type}")
@@ -1,3 +1,4 @@
1
+
1
2
  from contextlib import asynccontextmanager, suppress
2
3
  from dataclasses import dataclass, field
3
4
  from typing import Any, Callable, AsyncIterator, List
@@ -29,26 +30,39 @@ class RoundRobinModel(Model):
29
30
  models: List[Model]
30
31
  _current_index: int = field(default=0, repr=False)
31
32
  _model_name: str = field(repr=False)
33
+ _rotate_every: int = field(default=1, repr=False)
34
+ _request_count: int = field(default=0, repr=False)
32
35
 
33
36
  def __init__(
34
37
  self,
35
- *models: Model | KnownModelName | str,
38
+ *models: Model,
39
+ rotate_every: int = 1,
40
+ settings: ModelSettings | None = None
36
41
  ):
37
42
  """Initialize a round-robin model instance.
38
43
 
39
44
  Args:
40
- models: The names or instances of models to cycle through.
45
+ models: The model instances to cycle through.
46
+ rotate_every: Number of requests before rotating to the next model (default: 1).
47
+ settings: Model settings that will be used as defaults for this model.
41
48
  """
42
- super().__init__()
49
+ super().__init__(settings=settings)
43
50
  if not models:
44
51
  raise ValueError("At least one model must be provided")
45
- self.models = [infer_model(m) for m in models]
52
+ if rotate_every < 1:
53
+ raise ValueError("rotate_every must be at least 1")
54
+ self.models = list(models)
46
55
  self._current_index = 0
56
+ self._request_count = 0
57
+ self._rotate_every = rotate_every
47
58
 
48
59
  @property
49
60
  def model_name(self) -> str:
50
61
  """The model name showing this is a round-robin model with its candidates."""
51
- return f'round_robin:{",".join(model.model_name for model in self.models)}'
62
+ base_name = f'round_robin:{",".join(model.model_name for model in self.models)}'
63
+ if self._rotate_every != 1:
64
+ return f'{base_name}:rotate_every={self._rotate_every}'
65
+ return base_name
52
66
 
53
67
  @property
54
68
  def system(self) -> str:
@@ -63,7 +77,10 @@ class RoundRobinModel(Model):
63
77
  def _get_next_model(self) -> Model:
64
78
  """Get the next model in the round-robin sequence and update the index."""
65
79
  model = self.models[self._current_index]
66
- self._current_index = (self._current_index + 1) % len(self.models)
80
+ self._request_count += 1
81
+ if self._request_count >= self._rotate_every:
82
+ self._current_index = (self._current_index + 1) % len(self.models)
83
+ self._request_count = 0
67
84
  return model
68
85
 
69
86
  async def request(
@@ -74,6 +91,7 @@ class RoundRobinModel(Model):
74
91
  ) -> ModelResponse:
75
92
  """Make a request using the next model in the round-robin sequence."""
76
93
  current_model = self._get_next_model()
94
+ # Use the current model's settings as base, then merge with provided settings
77
95
  merged_settings = merge_model_settings(current_model.settings, model_settings)
78
96
  customized_model_request_parameters = current_model.customize_request_parameters(model_request_parameters)
79
97
 
@@ -96,6 +114,7 @@ class RoundRobinModel(Model):
96
114
  ) -> AsyncIterator[StreamedResponse]:
97
115
  """Make a streaming request using the next model in the round-robin sequence."""
98
116
  current_model = self._get_next_model()
117
+ # Use the current model's settings as base, then merge with provided settings
99
118
  merged_settings = merge_model_settings(current_model.settings, model_settings)
100
119
  customized_model_request_parameters = current_model.customize_request_parameters(model_request_parameters)
101
120
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.144
3
+ Version: 0.0.145
4
4
  Summary: Code generation agent
5
5
  Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
6
6
  Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
@@ -234,13 +234,16 @@ export CEREBRAS_API_KEY3=csk-...
234
234
  },
235
235
  "cerebras_round_robin": {
236
236
  "type": "round_robin",
237
- "models": ["qwen1", "qwen2", "qwen3"]
237
+ "models": ["qwen1", "qwen2", "qwen3"],
238
+ "rotate_every": 5
238
239
  }
239
240
  }
240
241
  ```
241
242
 
242
243
  Then just use /model and tab to select your round-robin model!
243
244
 
245
+ The `rotate_every` parameter controls how many requests are made to each model before rotating to the next one. In this example, the round-robin model will use each Qwen model for 5 consecutive requests before moving to the next model in the sequence.
246
+
244
247
  ### Benefits
245
248
  - **Rate Limit Protection**: Automatically distribute requests across multiple models
246
249
  - **Load Balancing**: Share workload between different model providers
@@ -6,10 +6,10 @@ code_puppy/config.py,sha256=9yWKHKjLJ2Ddl4frrBI9VRIwPvoWpIx1fAd1YpAvOSQ,15330
6
6
  code_puppy/http_utils.py,sha256=BAvt4hed7fVMXglA7eS9gOb08h2YTuOyai6VmQq09fg,3432
7
7
  code_puppy/main.py,sha256=Vv5HSJnkgZhCvvOoXrJ2zqM5P-i47-RcYAU00Z1Pfx0,21733
8
8
  code_puppy/message_history_processor.py,sha256=O2rKp7W6YeIg93W8b0XySTUEQgIZm0f_06--_kzHugM,16145
9
- code_puppy/model_factory.py,sha256=kTVaHNm6S1cLw6vHE6kH0WS6JZLRoZ8qFGKCp_fdDM4,11756
9
+ code_puppy/model_factory.py,sha256=-_0kJ7qYmRTDk0v3mfp-UrYf0IaDLyG8IMBweDECwJg,11917
10
10
  code_puppy/models.json,sha256=dAfpMMI2EEeOMv0ynHSmMuJAYDLcZrs5gCLX3voC4-A,3252
11
11
  code_puppy/reopenable_async_client.py,sha256=4UJRaMp5np8cbef9F0zKQ7TPKOfyf5U-Kv-0zYUWDho,8274
12
- code_puppy/round_robin_model.py,sha256=DmbO1_SIWevdhb9nN1eNVh0dNIF-XzLYX-9gra5xVsY,4670
12
+ code_puppy/round_robin_model.py,sha256=VWGCbK0-0rLpnrdxlmND5JsKXiNZZWFMIjF4_OL3STE,5594
13
13
  code_puppy/state_management.py,sha256=o4mNBCPblRyVrNBH-992-1YqffgH6AKHU7iZRqgP1LI,5925
14
14
  code_puppy/status_display.py,sha256=F6eEAkGePDp4StM2BWj-uLLQTDGtJrf0IufzCeP1rRg,8336
15
15
  code_puppy/summarization_agent.py,sha256=-e6yUGZ22ahSaF0y7QhgVcQBfx5ktNUkPxBIWQfPaA4,3275
@@ -126,9 +126,9 @@ code_puppy/tui/tests/test_sidebar_history_navigation.py,sha256=JGiyua8A2B8dLfwiE
126
126
  code_puppy/tui/tests/test_status_bar.py,sha256=nYT_FZGdmqnnbn6o0ZuOkLtNUtJzLSmtX8P72liQ5Vo,1797
127
127
  code_puppy/tui/tests/test_timestamped_history.py,sha256=nVXt9hExZZ_8MFP-AZj4L4bB_1Eo_mc-ZhVICzTuw3I,1799
128
128
  code_puppy/tui/tests/test_tools.py,sha256=kgzzAkK4r0DPzQwHHD4cePpVNgrHor6cFr05Pg6DBWg,2687
129
- code_puppy-0.0.144.data/data/code_puppy/models.json,sha256=dAfpMMI2EEeOMv0ynHSmMuJAYDLcZrs5gCLX3voC4-A,3252
130
- code_puppy-0.0.144.dist-info/METADATA,sha256=86kIwQ2Vf9hFT7PL6NBbHaMZGBzJ6L-CtXVn3IXULk0,21743
131
- code_puppy-0.0.144.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
132
- code_puppy-0.0.144.dist-info/entry_points.txt,sha256=d8YkBvIUxF-dHNJAj-x4fPEqizbY5d_TwvYpc01U5kw,58
133
- code_puppy-0.0.144.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
134
- code_puppy-0.0.144.dist-info/RECORD,,
129
+ code_puppy-0.0.145.data/data/code_puppy/models.json,sha256=dAfpMMI2EEeOMv0ynHSmMuJAYDLcZrs5gCLX3voC4-A,3252
130
+ code_puppy-0.0.145.dist-info/METADATA,sha256=i8WX2P4dcHB7_rGZGug23IafcwjtNPYsy1rcSbsKm9o,22019
131
+ code_puppy-0.0.145.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
132
+ code_puppy-0.0.145.dist-info/entry_points.txt,sha256=d8YkBvIUxF-dHNJAj-x4fPEqizbY5d_TwvYpc01U5kw,58
133
+ code_puppy-0.0.145.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
134
+ code_puppy-0.0.145.dist-info/RECORD,,