Skip to content

feat: add author-pluggable extension point for provider-specific message fields - #1586

Open
AngeloDanducci wants to merge 1 commit into
generative-computing:mainfrom
AngeloDanducci:ad-1565
Open

feat: add author-pluggable extension point for provider-specific message fields#1586
AngeloDanducci wants to merge 1 commit into
generative-computing:mainfrom
AngeloDanducci:ad-1565

Conversation

@AngeloDanducci

Copy link
Copy Markdown
Contributor

Pull Request

Issue

Fixes #1565

Description

Allows author-pluggable fields via provider_fields.

Given the exploration around the original issue, I think this gives us the most extensibility for the least amount of headache.

I chose provider-keyed passthrough instead of widening format_for_llm as this leaks wire shape into component code and doesn't compose well with images/docs (same issue with a global serializer registry). Open to discussion though if anyone can see reasons to alter the design - ie if we think authoring custom serialization logic itself is of greater benefit/immediate need.

Testing

  • Tests added to the respective file if code was changed
  • New code has 100% coverage if code was added
  • Ensure existing tests and github automation passes (a maintainer will kick off the github automation when the rest of the PR is populated)

Attribution

  • AI coding assistants used

Adding a new component, requirement, sampling strategy, or tool?

If your PR adds or modifies one of the types below, check the matching box. A checklist of type-specific review items will be posted as a comment.

  • Component
  • Requirement
  • Sampling Strategy
  • Tool

NOTE: Please ensure you have an issue that has been acknowledged by a core contributor and routed you to open a pull request against this repository. Otherwise, please open an issue before continuing with this pull request.

…age fields

Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
@AngeloDanducci
AngeloDanducci requested a review from a team as a code owner August 25, 2026 19:41
@github-actions github-actions Bot added the enhancement New feature or request label Aug 25, 2026

@jakelorocco jakelorocco left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I like this approach; thank you! A few comments on some of the specifics.


def merge_provider_fields(
base: dict[str, Any],
provider_fields: dict[str, dict[str, Any]] | None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should be creating a copy of this dict (either in this function or at a higher level?) similar to what we do with model options. Editing the dict once it's passed into the function should not edit an existing Message. I believe that's what's happening here in this example / test I wrote:

pf = {"openai": {"prediction": {"type": "content"}}}
msg = Message("user", "hi", provider_fields=pf)

tr = msg.format_for_llm()

print(tr.provider_fields)
print(pf)
print(tr.provider_fields == pf)
# {'openai': {'prediction': {'type': 'content'}}}
# {'openai': {'prediction': {'type': 'content'}}}
# True

pf["openai"]["prediction"]["type"] = "new"

print(tr.provider_fields)
print(pf)
print(tr.provider_fields == pf)
# {'openai': {'prediction': {'type': 'new'}}}
# {'openai': {'prediction': {'type': 'new'}}}
# True

Comment thread mellea/backends/ollama.py
# a mismatched target raises). Must run after the known fields are set.
message_dict = merge_provider_fields(
message_dict, m.provider_fields, self._provider
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ollama apparently auto validates messages and drops extra fields by default. Maybe we should include a note in the docstring that we will only raise errors if the underlying sdk does?

The SDK re-validates every message through a pydantic model:
- ollama/_client.py#L1284 — _copy_messages() does Message.model_validate({k: ... for k, v in dict(message).items() if v})
- Called from _client.py#L371 (sync chat) and #L989 (AsyncClient.chat) — the path mellea/backends/ollama.py uses. Your conversation: list[dict] never reaches the HTTP body as-is; it's rebuilt from validated Message objects.

That model doesn't opt into extras:
- ollama/_types.py#L283 — class Message(SubscriptableBaseModel), no model_config
- _types.py#L19 — SubscriptableBaseModel(BaseModel), also no model_config. Verified at runtime: Message.model_config == {}.

Pydantic's default for unknown keys is to discard them:
- Model config extra — "'ignore' (default): Ignore any extra attributes"
- Models → Extra fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is the same behavior for hugging face's apply_chat_template: an unhandled key will be dropped.

if not _matches(key):
continue
matched_any = True
for field, value in fields.items():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We may want to wrap this section in a larger try-catch block. I'm not sure if there are other places this can fail, but I think if field isn't a dict here, it will raise a generic error.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe lines 74 and 91 can error here as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: author-pluggable message serialization surface

2 participants