Skip to content

refactor(core): consolidate backend raw responses onto mot.raw namespace #1215

Closed

Description

@ajbozarth

Sub-issue of #909. Design discussed in #1197 Area 1.

Summary

Each backend currently writes a different bag of provider-specific keys to mot._meta (chat_response, oai_chat_response, litellm_chat_response, hf_output, etc.). This issue replaces those writes with a typed mot.raw: RawProviderResponse namespace.

Motivation

mot._meta is CBlock surface, but every MOT also stuffs backend-native response objects into it. Consumers reading these values (e.g. chat.py:_parse) have no signal that they're opting into provider-coupled access. A typed sibling of mot.generation — mot.raw — makes the escape hatch explicit while leaving mot._meta for CBlock-level metadata.

Design

@dataclass
class RawProviderResponse:
    """Backend-native response payload. Provider-coupling escape hatch.

    Anyone reading these fields is opting into provider-specific shape. Portable
    consumers should read mot.value, mot.parsed_repr, mot.tool_calls, or
    mot.generation instead.
    """
    provider: str | None = None
    response: Any | None = None              # full SDK response object
    streamed_chunks: list[Any] | None = None # streaming-only
  • mot.raw.response replaces chat_response / oai_chat_response / litellm_chat_response / hf_output.
  • mot.raw.streamed_chunks replaces the parallel *_streamed lists.
  • *_streaming_usage keys disappear — already covered by mot.generation.usage.
  • oai_chat_response_choice is dropped — always equals oai_chat_response["choices"][0].

response is typed Any. The whole point of raw is opt-in provider coupling; portable structured access is on mot.generation.

chat.py:_parse migration

Switches on mot.raw.provider:

  • "ollama" → response.message.role / response.message.content (role can be "assistant" or "tool")
  • "openai" / "watsonx" → response["choices"][0]["message"]…
  • HuggingFace fallback unchanged

The role-recovery branch stays — Ollama can legitimately return role="tool" (SDK docstring), so hardcoding "assistant" would silently change behavior for tool responses. (OQ2 resolution)

Migration

Single PR:

  1. Backends migrate writes from _meta[<key>] to mot.raw.response / mot.raw.streamed_chunks.
  2. Internal readers migrate (chat.py:_parse, tests).
  3. _meta becomes a read-only deprecation shim emitting DeprecationWarning for the old keys, for one minor release.

After one minor cycle: shim removed.

Appendix items folded in

From #1197's Appendix A, all to verify or address during this migration:

  • Item 3 — chat.py:_parse HuggingFace fallback hardcodes role="assistant" and returns raw text without role extraction. Confirm during migration whether this fallback is still desired with mot.raw.response available, or whether a richer shape can be extracted.
  • Item 4 — oai_chat_response_choice is redundant with oai_chat_response["choices"][0]. Drop in this PR (both openai.py and watsonx.py write it).
  • Item 5 — chat.py:_parse HuggingFace tool-call branch returns Message(role="assistant", content=computed.value) without recovering tool-call structure. Decide whether to serialize computed.tool_calls instead during migration.

Out of scope

Acceptance

  • mot.raw populated by all five backends (ollama, openai, watsonx, litellm, huggingface) on chat path
  • mot.raw.streamed_chunks populated on streaming path
  • chat.py:_parse switches on mot.raw.provider
  • _meta[<old key>] reads emit DeprecationWarning
  • oai_chat_response_choice removed
  • Tests updated; existing behavior preserved

Sequencing

Independent of #1181. Can ship after #1181 merges (which closes #909 Area 2) but before or after Area 3 (#1216) / Area 4 (#1217).

Activity

  1. added
    area/backendsProvider-specific work: Ollama, HF, LiteLLM, OpenAI, Bedrock, vLLM
    on Jun 5, 2026
  2. added
    area/stdlibCore abstractions: Context, MOT, SamplingStrategy, formatters, serialization
    on Jun 5, 2026
  3. added
    p2Medium/low: minor bugs, niche features, polish, docs, tests, cleanup. Scoped, lower urgency.
    on Jun 18, 2026
  4. ajbozarth commented on Jun 19, 2026

    @ajbozarth
    MemberAuthor

    Drift / refresh (2026-06-19)

    Path and post-#1264 updates before I pick this up:

    File path drift. Since the design was written, the codebase reorg moved the targets:

    • mellea/stdlib/base.py → mellea/core/base.py
    • chat.py → mellea/stdlib/components/chat.py

    Migration target rename (post-#1264). Backends now implement _generate_from_raw (the public generate_from_raw is a @final wrapper). The chat path's post_processing is unchanged. So the _meta writes to migrate live in:

    • _postprocess_chunk / streaming aggregation (chat path, all backends)
    • post_processing (chat path, all backends)
    • _generate_from_raw (raw path, all backends)

    Key inventory needs one addition. Current grep -rn '_meta\[' mellea/backends/:

    Backend Keys still written
    ollama chat_response
    openai oai_chat_response, oai_chat_response_choice, oai_chat_response_streamed, oai_streaming_usage
    watsonx oai_chat_response, oai_chat_response_choice, oai_chat_response_streamed (uses the openai keys, not watsonx_*)
    litellm litellm_chat_response, litellm_chat_response_streamed, litellm_streaming_usage, litellm_full_response (← not in the issue body's list)
    huggingface hf_output

    Two clarifications worth folding into the PR description when this lands:

    • litellm_full_response exists in the code today and is read internally by litellm's own post_processing for usage extraction. Migrate it alongside litellm_chat_response (or scope it out explicitly).
    • Watsonx writes the oai_* keys, not a watsonx_* namespace. The migration table in the issue's "design" section should make that explicit so reviewers don't expect a per-backend prefix.

    Logits coordination. PR #1261 is now actively implementing the mot.generation.logits path that this issue's "Out of scope" bullet predicted. Confirms the placement decision; no rebase work either way (logits go on generation, not raw).

  5. self-assigned this
    on Jun 19, 2026
  6. added a commit that references this issue on Jun 23, 2026
    e984d19
  7. added a commit that references this issue on Jun 24, 2026
    4403d3e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/backendsProvider-specific work: Ollama, HF, LiteLLM, OpenAI, Bedrock, vLLMarea/stdlibCore abstractions: Context, MOT, SamplingStrategy, formatters, serializationp2Medium/low: minor bugs, niche features, polish, docs, tests, cleanup. Scoped, lower urgency.refactor

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions