langchain-dev-utils 1.2.5__py3-none-any.whl → 1.2.6__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.
@@ -1 +1 @@
1
- __version__ = "1.2.5"
1
+ __version__ = "1.2.6"
@@ -0,0 +1,39 @@
1
+ from importlib import util
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ def _check_langchain_openai_install() -> None:
7
+ if not util.find_spec("langchain_openai"):
8
+ msg = (
9
+ "Please install langchain_dev_utils[standard],when use 'openai-compatible'"
10
+ )
11
+ raise ImportError(msg)
12
+
13
+
14
+ def _get_base_url_field_name(model_cls: type[BaseModel]) -> str | None:
15
+ """
16
+ Return 'base_url' if the model has a field named or aliased as 'base_url',
17
+ else return 'api_base' if it has a field named or aliased as 'api_base',
18
+ else return None.
19
+ The return value is always either 'base_url', 'api_base', or None.
20
+ """
21
+ model_fields = model_cls.model_fields
22
+
23
+ # try model_fields first
24
+ if "base_url" in model_fields:
25
+ return "base_url"
26
+
27
+ if "api_base" in model_fields:
28
+ return "api_base"
29
+
30
+ # then try aliases
31
+ for field_info in model_fields.values():
32
+ if field_info.alias == "base_url":
33
+ return "base_url"
34
+
35
+ for field_info in model_fields.values():
36
+ if field_info.alias == "api_base":
37
+ return "api_base"
38
+
39
+ return None
@@ -3,7 +3,11 @@ from typing import Any, NotRequired, Optional, TypedDict, cast
3
3
  from langchain.chat_models.base import _SUPPORTED_PROVIDERS, _init_chat_model_helper
4
4
  from langchain_core.language_models.chat_models import BaseChatModel
5
5
  from langchain_core.utils import from_env
6
- from pydantic import BaseModel
6
+
7
+ from langchain_dev_utils._utils import (
8
+ _check_langchain_openai_install,
9
+ _get_base_url_field_name,
10
+ )
7
11
 
8
12
  from .types import ChatModelType, CompatibilityOptions
9
13
 
@@ -18,34 +22,6 @@ class ChatModelProvider(TypedDict):
18
22
  compatibility_options: NotRequired[CompatibilityOptions]
19
23
 
20
24
 
21
- def _get_base_url_field_name(model_cls: type[BaseModel]) -> str | None:
22
- """
23
- Return 'base_url' if the model has a field named or aliased as 'base_url',
24
- else return 'api_base' if it has a field named or aliased as 'api_base',
25
- else return None.
26
- The return value is always either 'base_url', 'api_base', or None.
27
- """
28
- model_fields = model_cls.model_fields
29
-
30
- # try model_fields first
31
- if "base_url" in model_fields:
32
- return "base_url"
33
-
34
- if "api_base" in model_fields:
35
- return "api_base"
36
-
37
- # then try aliases
38
- for field_info in model_fields.values():
39
- if field_info.alias == "base_url":
40
- return "base_url"
41
-
42
- for field_info in model_fields.values():
43
- if field_info.alias == "api_base":
44
- return "api_base"
45
-
46
- return None
47
-
48
-
49
25
  def _parse_model(model: str, model_provider: Optional[str]) -> tuple[str, str]:
50
26
  """Parse model string and provider.
51
27
 
@@ -89,7 +65,7 @@ def _load_chat_model_helper(
89
65
  BaseChatModel: Initialized chat model instance
90
66
  """
91
67
  model, model_provider = _parse_model(model, model_provider)
92
- if model_provider in _MODEL_PROVIDERS_DICT.keys():
68
+ if model_provider in _MODEL_PROVIDERS_DICT:
93
69
  chat_model = _MODEL_PROVIDERS_DICT[model_provider]["chat_model"]
94
70
  if base_url := _MODEL_PROVIDERS_DICT[model_provider].get("base_url"):
95
71
  url_key = _get_base_url_field_name(chat_model)
@@ -98,7 +74,7 @@ def _load_chat_model_helper(
98
74
  if model_profiles := _MODEL_PROVIDERS_DICT[model_provider].get(
99
75
  "model_profiles"
100
76
  ):
101
- if model in model_profiles:
77
+ if model in model_profiles and "profile" not in kwargs:
102
78
  kwargs.update({"profile": model_profiles[model]})
103
79
  return chat_model(model=model, **kwargs)
104
80
 
@@ -145,12 +121,9 @@ def register_model_provider(
145
121
  """
146
122
  base_url = base_url or from_env(f"{provider_name.upper()}_API_BASE", default=None)()
147
123
  if isinstance(chat_model, str):
148
- try:
149
- from .adapters.openai_compatible import _create_openai_compatible_model
150
- except ImportError:
151
- raise ImportError(
152
- "Please install langchain_dev_utils[standard],when chat_model is a 'openai-compatible'"
153
- )
124
+ _check_langchain_openai_install()
125
+ from .adapters.openai_compatible import _create_openai_compatible_model
126
+
154
127
  if base_url is None:
155
128
  raise ValueError(
156
129
  f"base_url must be provided or set {provider_name.upper()}_API_BASE environment variable when chat_model is a string"
@@ -2,7 +2,11 @@ from typing import Any, Literal, NotRequired, Optional, TypedDict, Union
2
2
 
3
3
  from langchain.embeddings.base import Embeddings, _SUPPORTED_PROVIDERS, init_embeddings
4
4
  from langchain_core.utils import from_env, secret_from_env
5
- from pydantic import BaseModel
5
+
6
+ from langchain_dev_utils._utils import (
7
+ _check_langchain_openai_install,
8
+ _get_base_url_field_name,
9
+ )
6
10
 
7
11
  _EMBEDDINGS_PROVIDERS_DICT = {}
8
12
 
@@ -15,34 +19,6 @@ class EmbeddingProvider(TypedDict):
15
19
  base_url: NotRequired[str]
16
20
 
17
21
 
18
- def _get_base_url_field_name(model_cls: type[BaseModel]) -> str | None:
19
- """
20
- Return 'base_url' if the model has a field named or aliased as 'base_url',
21
- else return 'api_base' if it has a field named or aliased as 'api_base',
22
- else return None.
23
- The return value is always either 'base_url', 'api_base', or None.
24
- """
25
- model_fields = model_cls.model_fields
26
-
27
- # try model_fields first
28
- if "base_url" in model_fields:
29
- return "base_url"
30
-
31
- if "api_base" in model_fields:
32
- return "api_base"
33
-
34
- # then try aliases
35
- for field_info in model_fields.values():
36
- if field_info.alias == "base_url":
37
- return "base_url"
38
-
39
- for field_info in model_fields.values():
40
- if field_info.alias == "api_base":
41
- return "api_base"
42
-
43
- return None
44
-
45
-
46
22
  def _parse_model_string(model_name: str) -> tuple[str, str]:
47
23
  """Parse model string into provider and model name.
48
24
 
@@ -119,6 +95,8 @@ def register_embeddings_provider(
119
95
  "when embeddings_model is a string, the value must be 'openai-compatible'"
120
96
  )
121
97
 
98
+ _check_langchain_openai_install()
99
+
122
100
  _EMBEDDINGS_PROVIDERS_DICT.update(
123
101
  {
124
102
  provider_name: {
@@ -238,7 +216,6 @@ def load_embeddings(
238
216
  if embeddings == "openai-compatible":
239
217
  kwargs["check_embedding_ctx_length"] = False
240
218
  embeddings = "openai"
241
-
242
219
  return init_embeddings(
243
220
  model=model,
244
221
  provider=embeddings,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langchain-dev-utils
3
- Version: 1.2.5
3
+ Version: 1.2.6
4
4
  Summary: A practical utility library for LangChain and LangGraph development
5
5
  Project-URL: Source Code, https://github.com/TBice123123/langchain-dev-utils
6
6
  Project-URL: repository, https://github.com/TBice123123/langchain-dev-utils
@@ -157,6 +157,8 @@ For stream responses obtained using `stream()` and `astream()`, you can use `mer
157
157
  | `chunks` | List[AIMessageChunk] | Yes | - | List of AIMessageChunk objects |
158
158
 
159
159
  ```python
160
+ from langchain_dev_utils.message_convert import merge_ai_message_chunk
161
+
160
162
  chunks = list(model.stream("Hello"))
161
163
  merged = merge_ai_message_chunk(chunks)
162
164
  ```
@@ -174,6 +176,7 @@ For a list, you can use `format_sequence` to format it.
174
176
  | `with_num` | bool | No | False | If True, add a numeric prefix to each item (e.g., "1. Hello") |
175
177
 
176
178
  ```python
179
+ from langchain_dev_utils.message_convert import format_sequence
177
180
  text = format_sequence([
178
181
  "str1",
179
182
  "str2",
@@ -205,7 +208,7 @@ Includes the following features:
205
208
  | Parameter | Type | Required | Default | Description |
206
209
  |-----------|------|----------|---------|-------------|
207
210
  | `message` | AIMessage | Yes | - | AIMessage object |
208
- | `first_tool_call_only` | bool | No | False | Whether to only check the first tool call |
211
+ | `first_tool_call_only` | bool | No | False | Whether to only parse the first tool call |
209
212
 
210
213
  ```python
211
214
  import datetime
@@ -234,7 +237,7 @@ if has_tool_calling(response):
234
237
  Both can accept a `handler` parameter for custom breakpoint return and response handling logic.
235
238
 
236
239
  ```python
237
- from langchain_dev_utils import human_in_the_loop
240
+ from langchain_dev_utils.tool_calling import human_in_the_loop
238
241
  from langchain_core.tools import tool
239
242
  import datetime
240
243
 
@@ -262,7 +265,7 @@ In LangChain v1, the officially provided `create_agent` function can be used to
262
265
 
263
266
  | Parameter | Type | Required | Default | Description |
264
267
  |-----------|------|----------|---------|-------------|
265
- | `model` | str \| BaseChatModel | Yes | - | Model name or model instance. Can be a string identifier for a model registered with `register_model_provider` or a BaseChatModel instance. |
268
+ | `model` | str | Yes | - | Model name or model instance. Can be a string identifier for a model registered with `register_model_provider` or a BaseChatModel instance. |
266
269
  | Other parameters | Various | No | - | All other parameters are the same as in `langchain.agents.create_agent` |
267
270
 
268
271
  Usage example:
@@ -317,7 +320,7 @@ Uses `create_sequential_pipeline`, supported parameters:
317
320
 
318
321
  | Parameter | Type | Required | Default | Description |
319
322
  |-----------|------|----------|---------|-------------|
320
- | `sub_graphs` | List[StateGraph] | Yes | - | List of state graphs to combine (must be StateGraph instances) |
323
+ | `sub_graphs` | List[StateGraph\|CompiledStateGraph] | Yes | - | List of state graphs to combine (must be StateGraph instances or CompiledStateGraph instances) |
321
324
  | `state_schema` | type | Yes | - | State Schema for the final generated graph |
322
325
  | `graph_name` | str | No | - | Name of the final generated graph |
323
326
  | `context_schema` | type | No | - | Context Schema for the final generated graph |
@@ -378,7 +381,7 @@ Uses `create_parallel_pipeline`, supported parameters:
378
381
 
379
382
  | Parameter | Type | Required | Default | Description |
380
383
  |-----------|------|----------|---------|-------------|
381
- | `sub_graphs` | List[StateGraph] | Yes | - | List of state graphs to combine |
384
+ | `sub_graphs` | List[StateGraph\|CompiledStateGraph] | Yes | - | List of state graphs to combine (must be StateGraph instances or CompiledStateGraph instances) |
382
385
  | `state_schema` | type | Yes | - | State Schema for the final generated graph |
383
386
  | `branches_fn` | Callable | Yes | - | Parallel branch function, returns a list of Send objects to control parallel execution |
384
387
  | `graph_name` | str | No | - | Name of the final generated graph |
@@ -1,4 +1,5 @@
1
- langchain_dev_utils/__init__.py,sha256=jBmZf3HLbiQlWiolOsAA6J5-BbxXD2bqFqEqDH3lfqo,22
1
+ langchain_dev_utils/__init__.py,sha256=vMQK58X8_YZGKzRm0ThvPAKFtpfyejGmUnDrY9RQ13w,22
2
+ langchain_dev_utils/_utils.py,sha256=5bFs4cf3HvkMNkv35V8Sowu4YSXmfF5VNwmv_eHfkgQ,1151
2
3
  langchain_dev_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
4
  langchain_dev_utils/agents/__init__.py,sha256=e17SMQdJIQngbUCr2N1tY-yw0tD3tEnH7PSvyDmVPeQ,127
4
5
  langchain_dev_utils/agents/factory.py,sha256=JjdJwPTJpQwAlwQlBalbuGej5Jcpy2Fz6lH3EwEaxQo,3979
@@ -13,12 +14,12 @@ langchain_dev_utils/agents/middleware/summarization.py,sha256=BtWPJcQBssGAT0nb1c
13
14
  langchain_dev_utils/agents/middleware/tool_emulator.py,sha256=u9rV24yUB-dyc1uUfUe74B1wOGVI3TZRwxkE1bvGm18,2025
14
15
  langchain_dev_utils/agents/middleware/tool_selection.py,sha256=ZqdyK4Yhp2u3GM6B_D6U7Srca9vy1o7s6N_LrV24-dQ,3107
15
16
  langchain_dev_utils/chat_models/__init__.py,sha256=YSLUyHrWEEj4y4DtGFCOnDW02VIYZdfAH800m4Klgeg,224
16
- langchain_dev_utils/chat_models/base.py,sha256=MeVFt16ytJMTISnW1YbzNvaW_iesxH1nWr8FHG-8CL8,12550
17
+ langchain_dev_utils/chat_models/base.py,sha256=AYRcGViGJYsquqru_www3zt8-ZCkfzPCrw-dFF6HDts,11661
17
18
  langchain_dev_utils/chat_models/types.py,sha256=M0iCGWgXmX1f1vkymH-jNGdFQlsJS5JqpmgHctUS9jw,512
18
19
  langchain_dev_utils/chat_models/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
20
  langchain_dev_utils/chat_models/adapters/openai_compatible.py,sha256=4Q8ySa7jS2_AFo0oxLoqeY_aQyPppvV-DAMLt2rmGoE,20192
20
21
  langchain_dev_utils/embeddings/__init__.py,sha256=zbEOaV86TUi9Zrg_dH9dpdgacWg31HMJTlTQknA9EKk,244
21
- langchain_dev_utils/embeddings/base.py,sha256=25ebUEaf7075h8NARgTHjAvwK6JddhHor5upiucJqu0,9686
22
+ langchain_dev_utils/embeddings/base.py,sha256=lGZWbi6G1M0OcAO_d_k1QAFJm9z9gM0L4UAZ6xFtEoQ,8973
22
23
  langchain_dev_utils/message_convert/__init__.py,sha256=xwjaQ1oJoc80xy70oQI4uW3gAmgV5JymJd5hgnA6s3g,458
23
24
  langchain_dev_utils/message_convert/content.py,sha256=ApmQ7fUUBO3Ihjm2hYSWd4GrU_CvrjbWla-MA7DAFRc,7758
24
25
  langchain_dev_utils/message_convert/format.py,sha256=fh4GyyuZBTMrHeCEwdu9fOh5n8tdli1vDF44jK1i-tI,2373
@@ -29,7 +30,7 @@ langchain_dev_utils/pipeline/types.py,sha256=T3aROKKXeWvd0jcH5XkgMDQfEkLfPaiOhhV
29
30
  langchain_dev_utils/tool_calling/__init__.py,sha256=mu_WxKMcu6RoTf4vkTPbA1WSBSNc6YIqyBtOQ6iVQj4,322
30
31
  langchain_dev_utils/tool_calling/human_in_the_loop.py,sha256=nbaON9806pv5tpMRQUA_Ch3HJA5HBFgzZR7kQRf6PiY,9819
31
32
  langchain_dev_utils/tool_calling/utils.py,sha256=3cNv_Zx32KxdsGn8IkxjWUzxYEEwVJeJgTZTbfSg0pA,2751
32
- langchain_dev_utils-1.2.5.dist-info/METADATA,sha256=LB3TTtW0Hb6vopD23t0wiziRUsSFroD0-wsp1r8ipjg,18822
33
- langchain_dev_utils-1.2.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
34
- langchain_dev_utils-1.2.5.dist-info/licenses/LICENSE,sha256=AWAOzNEcsvCEzHOF0qby5OKxviVH_eT9Yce1sgJTico,1084
35
- langchain_dev_utils-1.2.5.dist-info/RECORD,,
33
+ langchain_dev_utils-1.2.6.dist-info/METADATA,sha256=PhJoxRlERmnMzRumGzLW3kwU58Cg3Tt6MiFibsfIi8U,19090
34
+ langchain_dev_utils-1.2.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
35
+ langchain_dev_utils-1.2.6.dist-info/licenses/LICENSE,sha256=AWAOzNEcsvCEzHOF0qby5OKxviVH_eT9Yce1sgJTico,1084
36
+ langchain_dev_utils-1.2.6.dist-info/RECORD,,