Repository: streamlit/streamlit
File: lib/streamlit/elements/widgets/button_group.py (Python)

Code before:
                    indexable_options,
                    default_index,
                    key,
                    options_format_func,
                )
            else:
                # Multi select: filter out invalid values
                current_value, value_needs_reset = (
                    validate_and_sync_multiselect_value_with_options(
                        cast("list[T] | list[T | str]", widget_state.value),
                        indexable_options,
                        key,
                        options_format_func,
                    )
                )

        if value_needs_reset or widget_state.value_changed:
            # Always use string-based raw_values field
            value_for_serialization = (
                current_value if value_needs_reset else widget_state.value
            )
            proto.raw_values[:] = serializer(cast("T", value_for_serialization))
            proto.set_value = True

        if ctx:
            # Save the string format function (not the Option proto creator)
            save_for_app_testing(ctx, element_id, options_format_func or str)

        self.dg._enqueue("button_group", proto, layout_config=layout_config)

        # Return widget_state with possibly updated value
        if value_needs_reset:
            from streamlit.runtime.state.common import RegisterWidgetResult

            return RegisterWidgetResult(
                cast("T", current_value),
                widget_state.value_changed or value_needs_reset,
            )

        return widget_state

    @property
    def dg(self) -> DeltaGenerator:
        """Get our DeltaGenerator."""
        return cast("DeltaGenerator", self)


Review comment (suggestion):
[nit] The agent leaves comments like this that are referring to the change that was made. I think it is better to not reference the change but just the current behaviour and why it is that way since future readers won't be reading the code as a diff. So, e.g. 

> Use options_format_func which returns a string value to stay consistent with app run behavior.

Code after:
                    indexable_options,
                    default_index,
                    key,
                    options_format_func,
                )
            else:
                # Multi select: filter out invalid values
                current_value, value_needs_reset = (
                    validate_and_sync_multiselect_value_with_options(
                        cast("list[T] | list[T | str]", widget_state.value),
                        indexable_options,
                        key,
                        options_format_func,
                    )
                )

        if value_needs_reset or widget_state.value_changed:
            # Always use string-based raw_values field
            value_for_serialization = (
                current_value if value_needs_reset else widget_state.value
            )
            proto.raw_values[:] = serializer(cast("T", value_for_serialization))
            proto.set_value = True

        if ctx:
            # Save format function for AppTest to serialize values as strings
            save_for_app_testing(ctx, element_id, options_format_func or str)

        self.dg._enqueue("button_group", proto, layout_config=layout_config)

        # Return widget_state with possibly updated value
        if value_needs_reset:
            from streamlit.runtime.state.common import RegisterWidgetResult

            return RegisterWidgetResult(
                cast("T", current_value),
                widget_state.value_changed or value_needs_reset,
            )

        return widget_state

    @property
    def dg(self) -> DeltaGenerator:
        """Get our DeltaGenerator."""
        return cast("DeltaGenerator", self)