Skip to content

Conversation

@davesh0812
Copy link
Contributor

@davesh0812 davesh0812 commented Dec 24, 2025

๐Ÿ“ Description

Add user ability to select the outlets after the model execution - relevant to agents (tool selection).


๐Ÿ› ๏ธ Changes Made

  1. ModelRunnerSelector - new user interface that have 2 method one for models selection and one for outlets selection.
  2. ModelRunnerErrorRaiser is a separate branch that comes after the MRS step and not pull in to the graph.
  3. Deprecated ModelSelector class and model_selector and model_selector_parameters params of MRS.__init__

โœ… Checklist

  • I updated the documentation (if applicable)
  • I have tested the changes in this PR
  • I confirmed whether my changes are covered by system tests
    • If yes, I ran all relevant system tests and ensured they passed before submitting this PR
    • I updated existing system tests and/or added new ones if needed to cover my changes
  • If I introduced a deprecation:

๐Ÿงช Testing

Add unit tests include mm tests


๐Ÿ”— References


๐Ÿšจ Breaking Changes?

  • Yes (explain below)
  • No

๐Ÿ”๏ธ Additional Notes

@davesh0812 davesh0812 marked this pull request as ready for review December 24, 2025 08:53
@davesh0812 davesh0812 requested review from a team and liranbg as code owners December 24, 2025 08:53
if isinstance(event, dict):
return event.get("error") is not None
else:
for model in event:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The return statement is inside the loop, so it returns on the first model checked regardless of result.

Example: If first model has no error but second model has error โ†’ returns False incorrectly.

Suggested fix:

else:
    for model in event:
        body_by_model = event.get(model)
        if isinstance(body_by_model, dict) and "error" in body_by_model:
            return True
    return False

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the way I need it to be :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe then something like this?

def _is_error(self, event: dict) -> bool:
    if len(self.runnables) == 1:
        return isinstance(event, dict) and event.get("error") is not None
    
    if not event:
        return False
    body_by_model = next(iter(event.values()))
    return isinstance(body_by_model, dict) and "error" in body_by_model

The 'for' loop is really confusing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alxtkr77 the error can come from a single model in the end of the list, we want the error raiser step will handle it and 1 is enough

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you never get to the end of the list - you unconditionally return on the first iteration

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"error" field is in the body only if error was raised. else the body is the user model answer, there might be an issue if a user adding "error" to his body first layer

Copy link
Contributor Author

@davesh0812 davesh0812 Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alxtkr77 sorry missed this one.. will fix in follow up pr

@alxtkr77
Copy link
Member

Test Coverage Gaps

The happy path is well covered, but error handling and edge cases are missing:

Missing Test Risk
_is_error() with multiple models Would catch the early-return bug
Error routing to {name}_error_raise outlet Error flow untested
select_models() with new ModelRunnerSelector Only select_outlets() is tested via MySelector
select_outlets() returning None Default routing behavior untested
model_runner_selector_parameters dict Only string class name is tested
Deprecation warning assertion Warning emitted but not verified with pytest.warns()

Suggested additions:

def test_model_runner_error_routing():
    """Test that errors route to error_raise outlet"""
    ...

def test_model_runner_selector_select_models():
    """Test select_models() method of new ModelRunnerSelector"""
    class MyModelsSelector(ModelRunnerSelector):
        def select_models(self, event, available_models):
            return [m for m in available_models if m.name in event.get("models", [])]
    ...

def test_is_error_multiple_models():
    """Test _is_error detects error in any model, not just first"""
    ...

Copy link
Contributor

@royischoss royischoss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM small comment and what we discussed

@liranbg liranbg changed the title [Serving] Add ModelRunnerSelector to route models and outlets. [Serving] Add ModelRunnerSelector to route models and outlets Dec 24, 2025
Copy link
Contributor

@royischoss royischoss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ๐Ÿ‘

@davesh0812 davesh0812 merged commit a9075b8 into mlrun:development Dec 24, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants