mpfaffenberger / mpfaffenberger/code_puppy
RoundRobinModel: _set_span_attributes calls nonexistent Model.model_attributes (always fails, silently suppressed); factory can insert None sub-models causing intermittent AttributeError every Nth request
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 814
- Forks
- 278
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 76
Description
Problem
RoundRobinModel (code_puppy/round_robin_model.py) has three issues:
1. _set_span_attributes calls a method that doesn't exist on pydantic-ai Model
Line ~148:
span.set_attributes(model.model_attributes(model))
pydantic_ai.models.Model has no model_attributes method (verified against the installed version: 'model_attributes' in dir(Model) is False). This would raise AttributeError on every call — it's only invisible because the whole body is wrapped in with suppress(Exception). So the observability feature this method exists for silently never works: errors passing silently, and dead code in disguise.
2. model_factory can insert None into the rotation
model_factory.py round_robin branch (lines ~960-972):
for name in model_names:
model = ModelFactory.get_model(name, config)
models.append(model)
ModelFactory.get_model() returns None for many failure modes (missing API key, plugin failure). A None lands in the rotation and only blows up later with an opaque AttributeError: 'NoneType' object has no attribute 'prepare_request' mid-conversation — on a schedule (every Nth request), which makes for a maddening intermittent bug. Validate at construction: skip-and-warn or raise immediately if any sub-model is None.
3. system / base_url properties read _current_index without the lock
Minor race: rotation mutates _current_index under _lock, but the properties read it unlocked. Worst case is reporting the wrong sub-model's metadata; worth a comment or a lock for consistency.
Also: the bare try/except Exception: raise around current_model.request(...) (lines ~108-117) is a no-op wrapper — delete it.
Suggested fix
- Fix or delete
_set_span_attributes; if keeping it, use real pydantic-ai attributes (e.g.{\"gen_ai.request.model\": model.model_name}) and stop suppressing all exceptions. - In
model_factory, raiseValueError(f\"Round-robin sub-model {name!r} failed to initialize\")whenget_modelreturns None.
Filed by Zen Reviewer A (code-puppy-60635a)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in code_puppy/round_robin_model.py, especially _set_span_attributes, request(), and the system/base_url properties, then inspect the round_robin branch in model_factory.py. Trace how ModelFactory.get_model() failures enter the rotation and review the lock usage around _current_index. Done means failed sub-models are handled at construction, span metadata uses supported model attributes or is removed, and the no-op exception wrapper is gone.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- ai, backend, observability
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100