langchain-google-genai 2.0.11__py3-none-any.whl → 2.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of langchain-google-genai might be problematic. Click here for more details.

@@ -55,7 +55,7 @@ embeddings.embed_query("hello, world!")
55
55
  ```
56
56
  """ # noqa: E501
57
57
 
58
- from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory
58
+ from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory, Modality
59
59
  from langchain_google_genai.chat_models import ChatGoogleGenerativeAI
60
60
  from langchain_google_genai.embeddings import GoogleGenerativeAIEmbeddings
61
61
  from langchain_google_genai.genai_aqa import (
@@ -80,5 +80,6 @@ __all__ = [
80
80
  "GoogleVectorStore",
81
81
  "HarmBlockThreshold",
82
82
  "HarmCategory",
83
+ "Modality",
83
84
  "DoesNotExistsException",
84
85
  ]
@@ -1,11 +1,11 @@
1
1
  from importlib import metadata
2
- from typing import Any, Dict, Optional, Tuple, TypedDict
2
+ from typing import Any, Dict, List, Optional, Tuple, TypedDict
3
3
 
4
4
  from google.api_core.gapic_v1.client_info import ClientInfo
5
5
  from langchain_core.utils import secret_from_env
6
6
  from pydantic import BaseModel, Field, SecretStr
7
7
 
8
- from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory
8
+ from langchain_google_genai._enums import HarmBlockThreshold, HarmCategory, Modality
9
9
 
10
10
 
11
11
  class GoogleGenerativeAIError(Exception):
@@ -72,6 +72,9 @@ Supported examples:
72
72
  "A key-value dictionary representing additional headers for the model call"
73
73
  ),
74
74
  )
75
+ response_modalities: Optional[List[Modality]] = Field(
76
+ default=None, description=("A list of modalities of the response")
77
+ )
75
78
 
76
79
  safety_settings: Optional[Dict[HarmCategory, HarmBlockThreshold]] = None
77
80
  """The default safety settings to use for all generations.
@@ -2,5 +2,6 @@ import google.ai.generativelanguage_v1beta as genai
2
2
 
3
3
  HarmBlockThreshold = genai.SafetySetting.HarmBlockThreshold
4
4
  HarmCategory = genai.HarmCategory
5
+ Modality = genai.GenerationConfig.Modality
5
6
 
6
- __all__ = ["HarmBlockThreshold", "HarmCategory"]
7
+ __all__ = ["HarmBlockThreshold", "HarmCategory", "Modality"]
@@ -67,7 +67,7 @@ from langchain_core.messages.ai import UsageMetadata
67
67
  from langchain_core.messages.tool import invalid_tool_call, tool_call, tool_call_chunk
68
68
  from langchain_core.output_parsers.base import OutputParserLike
69
69
  from langchain_core.output_parsers.openai_tools import (
70
- JsonOutputToolsParser,
70
+ JsonOutputKeyToolsParser,
71
71
  PydanticToolsParser,
72
72
  parse_tool_calls,
73
73
  )
@@ -89,7 +89,7 @@ from tenacity import (
89
89
  stop_after_attempt,
90
90
  wait_exponential,
91
91
  )
92
- from typing_extensions import Self
92
+ from typing_extensions import Self, is_typeddict
93
93
 
94
94
  from langchain_google_genai._common import (
95
95
  GoogleGenerativeAIError,
@@ -106,10 +106,16 @@ from langchain_google_genai._function_utils import (
106
106
  is_basemodel_subclass_safe,
107
107
  tool_to_dict,
108
108
  )
109
- from langchain_google_genai._image_utils import ImageBytesLoader
109
+ from langchain_google_genai._image_utils import (
110
+ ImageBytesLoader,
111
+ image_bytes_to_b64_string,
112
+ )
110
113
 
111
114
  from . import _genai_extension as genaix
112
115
 
116
+ WARNED_STRUCTURED_OUTPUT_JSON_MODE = False
117
+
118
+
113
119
  logger = logging.getLogger(__name__)
114
120
 
115
121
 
@@ -427,7 +433,7 @@ def _parse_chat_history(
427
433
  def _parse_response_candidate(
428
434
  response_candidate: Candidate, streaming: bool = False
429
435
  ) -> AIMessage:
430
- content: Union[None, str, List[str]] = None
436
+ content: Union[None, str, List[Union[str, dict]]] = None
431
437
  additional_kwargs = {}
432
438
  tool_calls = []
433
439
  invalid_tool_calls = []
@@ -452,6 +458,26 @@ def _parse_response_candidate(
452
458
  elif text:
453
459
  raise Exception("Unexpected content type")
454
460
 
461
+ if part.inline_data.mime_type.startswith("image/"):
462
+ image_format = part.inline_data.mime_type[6:]
463
+ message = {
464
+ "type": "image_url",
465
+ "image_url": {
466
+ "url": image_bytes_to_b64_string(
467
+ part.inline_data.data, image_format=image_format
468
+ )
469
+ },
470
+ }
471
+
472
+ if not content:
473
+ content = [message]
474
+ elif isinstance(content, str) and message:
475
+ content = [content, message]
476
+ elif isinstance(content, list) and message:
477
+ content.append(message)
478
+ elif message:
479
+ raise Exception("Unexpected content type")
480
+
455
481
  if part.function_call:
456
482
  function_call = {"name": part.function_call.name}
457
483
  # dump to match other function calling llm for now
@@ -828,8 +854,8 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
828
854
  @model_validator(mode="after")
829
855
  def validate_environment(self) -> Self:
830
856
  """Validates params and passes them to google-generativeai package."""
831
- if self.temperature is not None and not 0 <= self.temperature <= 1:
832
- raise ValueError("temperature must be in the range [0.0, 1.0]")
857
+ if self.temperature is not None and not 0 <= self.temperature <= 2.0:
858
+ raise ValueError("temperature must be in the range [0.0, 2.0]")
833
859
 
834
860
  if self.top_p is not None and not 0 <= self.top_p <= 1:
835
861
  raise ValueError("top_p must be in the range [0.0, 1.0]")
@@ -892,6 +918,7 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
892
918
  "top_k": self.top_k,
893
919
  "n": self.n,
894
920
  "safety_settings": self.safety_settings,
921
+ "response_modalities": self.response_modalities,
895
922
  }
896
923
 
897
924
  def _get_ls_params(
@@ -925,6 +952,7 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
925
952
  "max_output_tokens": self.max_output_tokens,
926
953
  "top_k": self.top_k,
927
954
  "top_p": self.top_p,
955
+ "response_modalities": self.response_modalities,
928
956
  }.items()
929
957
  if v is not None
930
958
  }
@@ -1177,6 +1205,16 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
1177
1205
  elif functions:
1178
1206
  formatted_tools = [convert_to_genai_function_declarations(functions)]
1179
1207
 
1208
+ filtered_messages = []
1209
+ for message in messages:
1210
+ if isinstance(message, HumanMessage) and not message.content:
1211
+ warnings.warn(
1212
+ "HumanMessage with empty content was removed to prevent API error"
1213
+ )
1214
+ else:
1215
+ filtered_messages.append(message)
1216
+ messages = filtered_messages
1217
+
1180
1218
  system_instruction, history = _parse_chat_history(
1181
1219
  messages,
1182
1220
  convert_system_message_to_human=self.convert_system_message_to_human,
@@ -1243,16 +1281,37 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
1243
1281
  include_raw: bool = False,
1244
1282
  **kwargs: Any,
1245
1283
  ) -> Runnable[LanguageModelInput, Union[Dict, BaseModel]]:
1284
+ _ = kwargs.pop("method", None)
1285
+ _ = kwargs.pop("strict", None)
1246
1286
  if kwargs:
1247
1287
  raise ValueError(f"Received unsupported arguments {kwargs}")
1288
+ tool_name = _get_tool_name(schema) # type: ignore[arg-type]
1248
1289
  if isinstance(schema, type) and is_basemodel_subclass_safe(schema):
1249
1290
  parser: OutputParserLike = PydanticToolsParser(
1250
1291
  tools=[schema], first_tool_only=True
1251
1292
  )
1252
1293
  else:
1253
- parser = JsonOutputToolsParser()
1254
- tool_choice = _get_tool_name(schema) if self._supports_tool_choice else None # type: ignore[arg-type]
1255
- llm = self.bind_tools([schema], tool_choice=tool_choice) # type: ignore[list-item]
1294
+ global WARNED_STRUCTURED_OUTPUT_JSON_MODE
1295
+ warnings.warn(
1296
+ "ChatGoogleGenerativeAI.with_structured_output with dict schema has "
1297
+ "changed recently to align with behavior of other LangChain chat "
1298
+ "models. More context: "
1299
+ "https://github.com/langchain-ai/langchain-google/pull/772"
1300
+ )
1301
+ WARNED_STRUCTURED_OUTPUT_JSON_MODE = True
1302
+ parser = JsonOutputKeyToolsParser(key_name=tool_name, first_tool_only=True)
1303
+ tool_choice = tool_name if self._supports_tool_choice else None
1304
+ try:
1305
+ llm = self.bind_tools(
1306
+ [schema],
1307
+ tool_choice=tool_choice,
1308
+ ls_structured_output_format={
1309
+ "kwargs": {"method": "function_calling"},
1310
+ "schema": convert_to_openai_tool(schema),
1311
+ },
1312
+ )
1313
+ except Exception:
1314
+ llm = self.bind_tools([schema], tool_choice=tool_choice)
1256
1315
  if include_raw:
1257
1316
  parser_with_fallback = RunnablePassthrough.assign(
1258
1317
  parsed=itemgetter("raw") | parser, parsing_error=lambda _: None
@@ -1315,7 +1374,13 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
1315
1374
 
1316
1375
 
1317
1376
  def _get_tool_name(
1318
- tool: Union[_ToolDict, GoogleTool],
1377
+ tool: Union[_ToolDict, GoogleTool, Dict],
1319
1378
  ) -> str:
1320
- genai_tool = tool_to_dict(convert_to_genai_function_declarations([tool]))
1321
- return [f["name"] for f in genai_tool["function_declarations"]][0] # type: ignore[index]
1379
+ try:
1380
+ genai_tool = tool_to_dict(convert_to_genai_function_declarations([tool]))
1381
+ return [f["name"] for f in genai_tool["function_declarations"]][0] # type: ignore[index]
1382
+ except ValueError as e: # other TypedDict
1383
+ if is_typeddict(tool):
1384
+ return convert_to_openai_tool(cast(Dict, tool))["function"]["name"]
1385
+ else:
1386
+ raise e
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain-google-genai
3
- Version: 2.0.11
3
+ Version: 2.1.1
4
4
  Summary: An integration package connecting Google's genai package and LangChain
5
5
  Home-page: https://github.com/langchain-ai/langchain-google
6
6
  License: MIT
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Dist: filetype (>=1.2.0,<2.0.0)
15
15
  Requires-Dist: google-ai-generativelanguage (>=0.6.16,<0.7.0)
16
- Requires-Dist: langchain-core (>=0.3.37,<0.4.0)
16
+ Requires-Dist: langchain-core (>=0.3.47,<0.4.0)
17
17
  Requires-Dist: pydantic (>=2,<3)
18
18
  Project-URL: Repository, https://github.com/langchain-ai/langchain-google
19
19
  Project-URL: Source Code, https://github.com/langchain-ai/langchain-google/tree/main/libs/genai
@@ -77,7 +77,44 @@ The value of `image_url` can be any of the following:
77
77
  - An accessible gcs file (e.g., "gcs://path/to/file.png")
78
78
  - A base64 encoded image (e.g., `data:image/png;base64,abcd124`)
79
79
 
80
+ #### Multimodal outputs
80
81
 
82
+ Gemini 2.0 Flash Experimental model supports text output with inline images
83
+
84
+ ```
85
+ from langchain_google_genai import ChatGoogleGenerativeAI
86
+
87
+ llm = ChatGoogleGenerativeAI(model="models/gemini-2.0-flash-exp-image-generation")
88
+ # example
89
+ response = llm.invoke(
90
+ "Generate an image of a cat and say meow",
91
+ generation_config=dict(response_modalities=["TEXT", "IMAGE"]),
92
+ )
93
+
94
+ # Base64 encoded binary data of the image
95
+ image_base64 = response.content[0].get("image_url").get("url").split(",")[-1]
96
+ meow_str = response.content[1]
97
+ ```
98
+
99
+ #### Multimodal Outputs in Chains
100
+
101
+ '''
102
+ from langchain_core.runnables import RunnablePassthrough
103
+ from langchain_core.prompts import ChatPromptTemplate
104
+
105
+ from langchain_google_genai import ChatGoogleGenerativeAI, Modality
106
+
107
+ llm = ChatGoogleGenerativeAI(
108
+ model="models/gemini-2.0-flash-exp-image-generation",
109
+ response_modalities=[Modality.TEXT, Modality.IMAGE],
110
+ )
111
+
112
+ prompt = ChatPromptTemplate(
113
+ [("human", "Generate an image of {animal} and tell me the sound of the animal")]
114
+ )
115
+ chain = {"animal": RunnablePassthrough()} | prompt | llm
116
+ res = chain.invoke("cat")
117
+ '''
81
118
 
82
119
  ## Embeddings
83
120
 
@@ -1,16 +1,16 @@
1
- langchain_google_genai/__init__.py,sha256=Oji-S2KYWrku1wyQEskY84IOfY8MfRhujjJ4d7hbsk4,2758
2
- langchain_google_genai/_common.py,sha256=KaNewDLkaQtDEgTMc631kjOKqKl1QoUKqD9iOIXNf-0,5275
3
- langchain_google_genai/_enums.py,sha256=KLPmxS1K83K4HjBIXFaXoL_sFEOv8Hq-2B2PDMKyDgo,197
1
+ langchain_google_genai/__init__.py,sha256=IsTvA3UcECLDckt3zWxK6u-n3MEa5KeEQpqsS-Z8shM,2784
2
+ langchain_google_genai/_common.py,sha256=RS_FN1k9BeeSRz8HuPyjh_lfDQPZKY6KdvK5EfVuxDw,5431
3
+ langchain_google_genai/_enums.py,sha256=Zj3BXXLlkm_UybegCi6fLsfFhriJCt_LAJvgatgPWQ0,252
4
4
  langchain_google_genai/_function_utils.py,sha256=FPZ4CxI4iTFco_W6oWNCNV_lgNbCLRbj7Gf-D0zeTCY,17736
5
5
  langchain_google_genai/_genai_extension.py,sha256=81a4ly5ZHlqMf37uJfdB8K41qE6J5ujLnbUypIfFf2o,20775
6
6
  langchain_google_genai/_image_utils.py,sha256=tPrQyMvVmO8xkuow1SvA91omxUEv9ZUy1EMHNGjMAKY,5202
7
- langchain_google_genai/chat_models.py,sha256=hRCxo2eagOnz7suKPiaQO6W1XyBxKr1UCy9AeK71xRs,50920
7
+ langchain_google_genai/chat_models.py,sha256=ZFjhFz3a4t-6CEYGSYujYrTf29QEvKsIHeKZu8nJftI,53404
8
8
  langchain_google_genai/embeddings.py,sha256=jQRWPXD9twXoVBlXJQG7Duz0fb8UC0kgRzzwAmW3Dic,10146
9
9
  langchain_google_genai/genai_aqa.py,sha256=qB6h3-BSXqe0YLR3eeVllYzmNKK6ofI6xJLdBahUVZo,4300
10
10
  langchain_google_genai/google_vector_store.py,sha256=4wvhIiOmc3Fo046FyafPmT9NBCLek-9bgluvuTfrbpQ,16148
11
11
  langchain_google_genai/llms.py,sha256=QNPitkORf86w8WQpTbjuPFCQFkB-qKRMW2phhRBwAEA,4318
12
12
  langchain_google_genai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- langchain_google_genai-2.0.11.dist-info/LICENSE,sha256=DppmdYJVSc1jd0aio6ptnMUn5tIHrdAhQ12SclEBfBg,1072
14
- langchain_google_genai-2.0.11.dist-info/METADATA,sha256=QQSJFXoI4IeDHVyAFT5Xtic6aJ5cd_kY1qCP-B6NX1c,3605
15
- langchain_google_genai-2.0.11.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
16
- langchain_google_genai-2.0.11.dist-info/RECORD,,
13
+ langchain_google_genai-2.1.1.dist-info/LICENSE,sha256=DppmdYJVSc1jd0aio6ptnMUn5tIHrdAhQ12SclEBfBg,1072
14
+ langchain_google_genai-2.1.1.dist-info/METADATA,sha256=600J_hgujuZPiW-FliQBH9SbAeSw5Bb3tAyZzG2NES8,4728
15
+ langchain_google_genai-2.1.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
16
+ langchain_google_genai-2.1.1.dist-info/RECORD,,