Skip to content

feat(core): audio file/URL constructors and representation-aware capability guards - #1601

Open
jakelorocco wants to merge 2 commits into
generative-computing:mainfrom
jakelorocco:feat/audio-input
Open

feat(core): audio file/URL constructors and representation-aware capability guards#1601
jakelorocco wants to merge 2 commits into
generative-computing:mainfrom
jakelorocco:feat/audio-input

Conversation

@jakelorocco

Copy link
Copy Markdown
Contributor

Pull Request

Issue

Fixes # N/A

Description

Adds some functionality to make it easier to work with audio and adds a few guards as well. Matches functionality with the images feature.

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.

Assisted-by: Claude Code
Signed-off-by: Jake LoRocco <jake.lorocco@ibm.com>
@github-actions github-actions Bot added the enhancement New feature or request label Sep 1, 2026
Signed-off-by: jakelorocco <59755218+jakelorocco@users.noreply.github.com>
@jakelorocco
jakelorocco marked this pull request as ready for review September 1, 2026 16:57
@jakelorocco
jakelorocco requested a review from a team as a code owner September 1, 2026 16:57
@jakelorocco

Copy link
Copy Markdown
Contributor Author

@markstur, could you please take a look at this PR since it touches / adds some audio feature enhancements in areas you'd previously worked on?

Comment thread mellea/backends/openai.py

@psschwei psschwei Sep 1, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is something that Claude picked up, though it seems fairly minor as I don't think we would hit this very often. Mentioning it as better safe than sorry, but could also see ignoring this:


_generate_from_intrinsic serializes context messages at openai.py:760 without a prefetch, so an AudioUrlBlock there resolves via the blocking resolve_base64() on the event loop.

The cache added here (here being L1013) makes this a hit in almost every real ordering, since any prior generation on the standard path warms it. The one case it misses is an intrinsic called on a context no generation has touched, which is the documented pattern for the intrinsic helpers (check_certainty(context, backend) over a hand-built ChatContext). Worst case is one bounded 30 s download, not wrong output.

Suggest adding this after line 748 for symmetry with the standard path:

messages: list[Message] = self.formatter.to_chat_messages(linearized_context)
await prefetch_audio_urls(messages)

Comment thread mellea/core/base.py
else:
return None
else:
if not hasattr(c, "audio"):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Again, another minor thing that Claude found while reviewing. I think it probably makes sense to just be aware of this but not to fix as that would result in a lot of extra calls.


The fallback fires only when the attribute is absent, but message_from_template_representation (chat.py:354-364) always reads tr.audio / tr.images. So a component exposing audio = None while declaring audio=[...] on its representation passes this guard, then has the clip put on the Message by the formatter and silently dropped by HF's apply_chat_template. Same silent drop this fallback exists to prevent, different shape. test_representation_fallback_not_consulted_when_attribute_present currently pins that as intended.

No built-in can hit it: Instruction.audio and its format_for_llm both read self._audio (instruction.py:204, 229), same for Message. So this is about the extension surface, not a live bug.

Falling back whenever the attribute yields nothing, rather than only when it's missing, would make the guard agree with the payload path. That does cost the optimization the docstring calls out, since every attachment-free Instruction/Message would then pay two extra format_for_llm() calls per generation on the HF path. Fine to keep as-is and just document that a component's attribute must agree with its representation, but worth being a deliberate choice rather than an accident.

@markstur markstur 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.

Good feature. Nice to fix the dead end AudioUrlBlock. See inline comment, however, about how vLLM can support remote URLs. Probably just FYI and no change.

I think Paul's comment should be addressed with an await prefetch.

Otherwise the doc additions, in particular, are a great addition. I had to check to see if I forgot to commit something like that (I didn't. I think I was too focused on m serve examples).

Also some little doc/comment nits inline.

Comment thread mellea/core/base.py
f"Could not read audio file {os.fspath(path)[:120]!r}: expected a path "
f"to an audio file on disk. ({type(e).__name__}: {e}) "
"To load remote audio, fetch the bytes and use AudioBlock.from_bytes(); "
"for base64 data use AudioBlock(value, format=...)."

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.

Instead of fetch, this guidance can now use from_url() e.g.:

To load a remote URL use AudioBlock.from_url() or AudioUrlBlock; for raw bytes use AudioBlock.from_bytes()

Comment thread mellea/core/base.py
self.format = format

def resolve_base64(self) -> str:
"""Return the audio as raw base64, downloading it once per URL.

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.

there is a race condition where the same URL can be downloaded multiple times in parallel and the last one just wins. Not a big concern. I think (if not fixed) a comment somewhere would be good. Maybe here?

carries a `"reasoning_content"` field.

Raises:
ValueError: If the message contains an `AudioUrlBlock`. The OpenAI Chat

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.

outdates docstring. The AudioUrlBlock ValueError was removed


### Remote audio

No provider accepts audio by URL — OpenAI Chat Completions has no audio-by-URL content

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 statement is fine for Mellea/OpenAI, but...

https://docs.vllm.ai/en/v0.6.2/getting_started/examples/openai_audio_api_client.html

So the current AudioUrlBlock was partly just nice symmetry with ImageUrlBlock even though it was a dead end, but was also a potential extension to support vLLM's non-comforming extension of OpenAI API (or maybe anticipating an OpenAI API future change?) which can do the URL download.

I'm OK with ignoring the vLLM extension, keeping this comment as-is and just saying we'll deal with that in the future (or maybe never). Probably not a priority and no need to speculate. Essentially that's why there was no issue to implement the vLLM specific audio_url.

I just want to make sure we agree that we can kick this down the road and if future us wants to add remote audio-by-URL support, we'd probably just add a check similar to is_vllm_server_with_...() to make the prefetch/cache skippable? This and that could co-exist.

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.

3 participants