libs/core/langchain_core/messages/block_translators/langchain_v0.py PYTHON 302 lines View on github.com → Search inside
1"""Derivations of standard content blocks from LangChain v0 multimodal content."""23from typing import Any, cast45from langchain_core.messages import content as types678def _convert_v0_multimodal_input_to_v1(9    content: list[types.ContentBlock],10) -> list[types.ContentBlock]:11    """Convert v0 multimodal blocks to v1 format.1213    During the `content_blocks` parsing process, we wrap blocks not recognized as a v114    block as a `'non_standard'` block with the original block stored in the `value`15    field. This function attempts to unpack those blocks and convert any v0 format16    blocks to v1 format.1718    If conversion fails, the block is left as a `'non_standard'` block.1920    Args:21        content: List of content blocks to process.2223    Returns:24        v1 content blocks.25    """26    converted_blocks = []27    unpacked_blocks: list[dict[str, Any]] = [28        cast("dict[str, Any]", block)29        if block.get("type") != "non_standard"30        else block["value"]  # type: ignore[typeddict-item]  # this is only non-standard blocks31        for block in content32    ]33    for block in unpacked_blocks:34        if block.get("type") in {"image", "audio", "file"} and "source_type" in block:35            converted_block = _convert_legacy_v0_content_block_to_v1(block)36            converted_blocks.append(cast("types.ContentBlock", converted_block))37        elif block.get("type") in types.KNOWN_BLOCK_TYPES:38            # Guard in case this function is used outside of the .content_blocks flow39            converted_blocks.append(cast("types.ContentBlock", block))40        else:41            converted_blocks.append({"type": "non_standard", "value": block})4243    return converted_blocks444546def _convert_legacy_v0_content_block_to_v1(47    block: dict,48) -> types.ContentBlock | dict:49    """Convert a LangChain v0 content block to v1 format.5051    Preserves unknown keys as extras to avoid data loss.5253    Returns the original block unchanged if it's not in v0 format.54    """5556    def _extract_v0_extras(block_dict: dict, known_keys: set[str]) -> dict[str, Any]:57        """Extract unknown keys from v0 block to preserve as extras.5859        Args:60            block_dict: The original v0 block dictionary.61            known_keys: Set of keys known to be part of the v0 format for this block.6263        Returns:64            A dictionary of extra keys not part of the known v0 format.65        """66        return {k: v for k, v in block_dict.items() if k not in known_keys}6768    # Check if this is actually a v0 format block69    block_type = block.get("type")70    if block_type not in {"image", "audio", "file"} or "source_type" not in block:71        # Not a v0 format block, return unchanged72        return block7374    if block.get("type") == "image":75        source_type = block.get("source_type")76        if source_type == "url":77            # image-url78            known_keys = {"mime_type", "type", "source_type", "url"}79            extras = _extract_v0_extras(block, known_keys)80            if "id" in block:81                return types.create_image_block(82                    url=block["url"],83                    mime_type=block.get("mime_type"),84                    id=block["id"],85                    **extras,86                )8788            # Don't construct with an ID if not present in original block89            v1_image_url = types.ImageContentBlock(type="image", url=block["url"])90            if block.get("mime_type"):91                v1_image_url["mime_type"] = block["mime_type"]9293            v1_image_url["extras"] = {}94            for key, value in extras.items():95                if value is not None:96                    v1_image_url["extras"][key] = value97            if v1_image_url["extras"] == {}:98                del v1_image_url["extras"]99100            return v1_image_url101        if source_type == "base64":102            # image-base64103            known_keys = {"mime_type", "type", "source_type", "data"}104            extras = _extract_v0_extras(block, known_keys)105            if "id" in block:106                return types.create_image_block(107                    base64=block["data"],108                    mime_type=block.get("mime_type"),109                    id=block["id"],110                    **extras,111                )112113            v1_image_base64 = types.ImageContentBlock(114                type="image", base64=block["data"]115            )116            if block.get("mime_type"):117                v1_image_base64["mime_type"] = block["mime_type"]118119            v1_image_base64["extras"] = {}120            for key, value in extras.items():121                if value is not None:122                    v1_image_base64["extras"][key] = value123            if v1_image_base64["extras"] == {}:124                del v1_image_base64["extras"]125126            return v1_image_base64127        if source_type == "id":128            # image-id129            known_keys = {"type", "source_type", "id"}130            extras = _extract_v0_extras(block, known_keys)131            # For id `source_type`, `id` is the file reference, not block ID132            v1_image_id = types.ImageContentBlock(type="image", file_id=block["id"])133134            v1_image_id["extras"] = {}135            for key, value in extras.items():136                if value is not None:137                    v1_image_id["extras"][key] = value138            if v1_image_id["extras"] == {}:139                del v1_image_id["extras"]140141            return v1_image_id142    elif block.get("type") == "audio":143        source_type = block.get("source_type")144        if source_type == "url":145            # audio-url146            known_keys = {"mime_type", "type", "source_type", "url"}147            extras = _extract_v0_extras(block, known_keys)148            if "id" in block:149                return types.create_audio_block(150                    url=block["url"],151                    mime_type=block.get("mime_type"),152                    id=block["id"],153                    **extras,154                )155156            # Don't construct with an ID if not present in original block157            v1_audio_url: types.AudioContentBlock = types.AudioContentBlock(158                type="audio", url=block["url"]159            )160            if block.get("mime_type"):161                v1_audio_url["mime_type"] = block["mime_type"]162163            v1_audio_url["extras"] = {}164            for key, value in extras.items():165                if value is not None:166                    v1_audio_url["extras"][key] = value167            if v1_audio_url["extras"] == {}:168                del v1_audio_url["extras"]169170            return v1_audio_url171        if source_type == "base64":172            # audio-base64173            known_keys = {"mime_type", "type", "source_type", "data"}174            extras = _extract_v0_extras(block, known_keys)175            if "id" in block:176                return types.create_audio_block(177                    base64=block["data"],178                    mime_type=block.get("mime_type"),179                    id=block["id"],180                    **extras,181                )182183            v1_audio_base64: types.AudioContentBlock = types.AudioContentBlock(184                type="audio", base64=block["data"]185            )186            if block.get("mime_type"):187                v1_audio_base64["mime_type"] = block["mime_type"]188189            v1_audio_base64["extras"] = {}190            for key, value in extras.items():191                if value is not None:192                    v1_audio_base64["extras"][key] = value193            if v1_audio_base64["extras"] == {}:194                del v1_audio_base64["extras"]195196            return v1_audio_base64197        if source_type == "id":198            # audio-id199            known_keys = {"type", "source_type", "id"}200            extras = _extract_v0_extras(block, known_keys)201            v1_audio_id: types.AudioContentBlock = types.AudioContentBlock(202                type="audio", file_id=block["id"]203            )204205            v1_audio_id["extras"] = {}206            for key, value in extras.items():207                if value is not None:208                    v1_audio_id["extras"][key] = value209            if v1_audio_id["extras"] == {}:210                del v1_audio_id["extras"]211212            return v1_audio_id213    elif block.get("type") == "file":214        source_type = block.get("source_type")215        if source_type == "url":216            # file-url217            known_keys = {"mime_type", "type", "source_type", "url"}218            extras = _extract_v0_extras(block, known_keys)219            if "id" in block:220                return types.create_file_block(221                    url=block["url"],222                    mime_type=block.get("mime_type"),223                    id=block["id"],224                    **extras,225                )226227            v1_file_url: types.FileContentBlock = types.FileContentBlock(228                type="file", url=block["url"]229            )230            if block.get("mime_type"):231                v1_file_url["mime_type"] = block["mime_type"]232233            v1_file_url["extras"] = {}234            for key, value in extras.items():235                if value is not None:236                    v1_file_url["extras"][key] = value237            if v1_file_url["extras"] == {}:238                del v1_file_url["extras"]239240            return v1_file_url241        if source_type == "base64":242            # file-base64243            known_keys = {"mime_type", "type", "source_type", "data"}244            extras = _extract_v0_extras(block, known_keys)245            if "id" in block:246                return types.create_file_block(247                    base64=block["data"],248                    mime_type=block.get("mime_type"),249                    id=block["id"],250                    **extras,251                )252253            v1_file_base64: types.FileContentBlock = types.FileContentBlock(254                type="file", base64=block["data"]255            )256            if block.get("mime_type"):257                v1_file_base64["mime_type"] = block["mime_type"]258259            v1_file_base64["extras"] = {}260            for key, value in extras.items():261                if value is not None:262                    v1_file_base64["extras"][key] = value263            if v1_file_base64["extras"] == {}:264                del v1_file_base64["extras"]265266            return v1_file_base64267        if source_type == "id":268            # file-id269            known_keys = {"type", "source_type", "id"}270            extras = _extract_v0_extras(block, known_keys)271            return types.create_file_block(file_id=block["id"], **extras)272        if source_type == "text":273            # file-text274            known_keys = {"mime_type", "type", "source_type", "url"}275            extras = _extract_v0_extras(block, known_keys)276            if "id" in block:277                return types.create_plaintext_block(278                    # In v0, URL points to the text file content279                    # TODO: attribute this claim280                    text=block["url"],281                    id=block["id"],282                    **extras,283                )284285            v1_file_text: types.PlainTextContentBlock = types.PlainTextContentBlock(286                type="text-plain", text=block["url"], mime_type="text/plain"287            )288            if block.get("mime_type"):289                v1_file_text["mime_type"] = block["mime_type"]290291            v1_file_text["extras"] = {}292            for key, value in extras.items():293                if value is not None:294                    v1_file_text["extras"][key] = value295            if v1_file_text["extras"] == {}:296                del v1_file_text["extras"]297298            return v1_file_text299300    # If we can't convert, return the block unchanged301    return block

Code quality findings 9

Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_image_url["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_image_base64["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_image_id["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_audio_url["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_audio_base64["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_audio_id["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_file_url["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_file_base64["extras"]
Avoid unless necessary; Python's garbage collector typically handles object deletion
unnecessary-del
del v1_file_text["extras"]

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.