Skip to content

refactor: extract _content_fields ClassVar to eliminate duplicate _build_metadata() overrides #155

Description

@Kamilbenkirane

Summary

Five provider/protocol clients implement the exact same 4-line _build_metadata() method, differing only in the content field name ("choices", "output", "message", "content", "candidates").

Current Code (repeated 5 times)

def _build_metadata(self, response_data: dict[str, Any]) -> dict[str, Any]:
    content_fields = {"choices"}  # varies per provider
    filtered_data = {k: v for k, v in response_data.items() if k not in content_fields}
    return super()._build_metadata(filtered_data)

Proposed Change

Add a _content_fields ClassVar to APIMixin and implement the filtering once:

# In APIMixin:
_content_fields: ClassVar[set[str]] = set()

def _build_metadata(self, response_data: dict[str, Any]) -> dict[str, Any]:
    if self._content_fields:
        response_data = {k: v for k, v in response_data.items() if k not in self._content_fields}
    return super()._build_metadata(response_data)

# In each provider (replaces 4-line method override):
_content_fields: ClassVar[set[str]] = {"choices"}

Files to Modify

  • src/celeste/client.py (APIMixin._build_metadata)
  • src/celeste/protocols/chatcompletions/client.py
  • src/celeste/protocols/openresponses/client.py
  • src/celeste/providers/cohere/chat/client.py
  • src/celeste/providers/anthropic/messages/client.py
  • src/celeste/providers/google/generate_content/client.py

Rationale

5 identical method implementations replaced by 5 one-line ClassVar declarations. The ClassVar pattern is already used throughout the codebase (_default_base_url, _default_endpoint, _usage_class, _finish_reason_class), so this is consistent with existing conventions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions