Skip to content

Conversation

mdrxy
Copy link
Collaborator

@mdrxy mdrxy commented Aug 26, 2025

Q: If output_version is not set, response_metadata won't have an output_version, even though it defaults to 'v0'. Do we want this?

ccurme and others added 30 commits August 11, 2025 14:52
Copy link

codspeed-hq bot commented Aug 26, 2025

CodSpeed Instrumentation Performance Report

Merging #32694 will not alter performance

Comparing mdrxy/call-version (007a3a4) with wip-v1.0 (e4b69db)

Summary

✅ 14 untouched benchmarks

@mdrxy mdrxy changed the title feat(core): output_version on invoke / mode lcall feat(core): output_version on invoke / model call Aug 26, 2025
@mdrxy mdrxy marked this pull request as ready for review August 27, 2025 00:27
Comment on lines -1686 to -1689
from langchain_core.output_parsers.openai_tools import (
JsonOutputKeyToolsParser,
PydanticToolsParser,
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did we dig into why this was here? I'm assuming it was to resolve a circular import.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Possibly, or just an erroneous placement (since we don't enforce placement with ruff). Moving didn't break anything 🙏

Comment on lines +450 to +458
effective_output_version = (
output_version if output_version is not None else self.output_version
)
kwargs["_output_version"] = effective_output_version or "v0"

# Whether the user explicitly set an output_version for either model or call
kwargs["_output_version_explicit"] = (
output_version is not None or self.output_version is not None
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

instead of determining this here, can we just propagate

kwargs["_output_version"] = output_version

and then at call sites, do

output_version = kwargs.pop("_output_version", None) or self.output_version
message = _update_message_content_to_blocks(message, output_version)

then update _update_message_content_to_blocks (maybe rename to process_output_version or similar) to do something like

def _update_message_content_to_blocks(message: T, output_version: str) -> T:
    if output_version is None:
        return message
    elif output_version == "v1":
        return message.model_copy(
            update={
                "content": message.content_blocks,
                "response_metadata": {
                    **message.response_metadata,
                    "output_version": output_version,
                },
            }
        )
    else:
        # v0
        return message.model_copy(
            update={
                "response_metadata": {
                    **message.response_metadata,
                    "output_version": output_version,
                },
            }
        )

Comment on lines +653 to +657
filtered_kwargs = {
k: v
for k, v in kwargs.items()
if k not in ("_output_version", "_output_version_explicit")
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

(nit) see above comment on just popping _output_version from kwargs and processing

"'output_version' should have the same value across "
"all chunks in a generation."
)
raise ValueError(msg)
Copy link
Collaborator

Choose a reason for hiding this comment

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

BaseChatModel is inserting the output version, right? how would we hit this ValueError?

If a user receives this ValueError, are they just stuck? What can they do?

I think in most other cases in the merging logic we just accept the left value.

from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult


class OutputVersionTrackingChatModel(GenericFakeChatModel):
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we not use GenericFakeChatModel on its own?

Comment on lines +219 to +220
"[('_output_version', 'v0'), ('_output_version_explicit', False), ('_type',"
" 'generic-fake-chat-model'), ('stop', None)]",
Copy link
Collaborator

Choose a reason for hiding this comment

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

will this break caches

Comment on lines +1602 to +1603
# Note: output_version accepted for interface consistency; format conversion
# handled by core
Copy link
Collaborator

Choose a reason for hiding this comment

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

are we introducing type errors into all chat models?

could we just add to signature of top-level .invoke, .stream, etc. instead of _generate, _stream and propagate through kwargs?

Comment on lines +4125 to +4127
elif output_version == "v1":
# Use content_blocks property which handles v1 conversion via block_translators
message = message.model_copy(update={"content": message.content_blocks})
Copy link
Collaborator

Choose a reason for hiding this comment

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

isn't this done entirely in core? we went to some lengths so that we wouldn't have to touch the chat model implementations.

Comment on lines +975 to +979
effective_output_version = (
output_version
if output_version is not None
else (self.output_version or "v0")
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

is this logic needed? ideally we should need zero or minimal changes to child chat model classes.

Base automatically changed from cc/1.0/standard_content to wip-v1.0 August 27, 2025 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Related to the package `langchain-core`
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants