langchain-dev-utils 1.4.0__py3-none-any.whl → 1.4.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.
@@ -1 +1 @@
1
- __version__ = "1.4.0"
1
+ __version__ = "1.4.1"
@@ -23,13 +23,15 @@ def _transform_node_to_tuple(
23
23
 
24
24
 
25
25
  def _check_pkg_install(
26
- pkg: Literal["langchain_openai", "json_repair"],
26
+ pkg: Literal["langchain_openai", "json_repair", "jinja2"],
27
27
  ) -> None:
28
28
  if not util.find_spec(pkg):
29
29
  if pkg == "langchain_openai":
30
30
  msg = "Please install langchain_dev_utils[standard],when use 'openai-compatible'"
31
- else:
31
+ elif pkg == "json_repair":
32
32
  msg = "Please install langchain_dev_utils[standard] to use ToolCallRepairMiddleware."
33
+ else:
34
+ msg = "Please install langchain_dev_utils[standard] to use FormatPromptMiddleware."
33
35
  raise ImportError(msg)
34
36
 
35
37
 
@@ -1,10 +1,10 @@
1
- from .format_prompt import format_prompt
1
+ from .format_prompt import FormatPromptMiddleware, format_prompt
2
2
  from .handoffs import HandoffAgentMiddleware
3
3
  from .model_fallback import ModelFallbackMiddleware
4
4
  from .model_router import ModelRouterMiddleware
5
5
  from .plan import PlanMiddleware
6
6
  from .summarization import SummarizationMiddleware
7
- from .tool_call_repair import ToolCallRepairMiddleware
7
+ from .tool_call_repair import ToolCallRepairMiddleware, tool_call_repair
8
8
  from .tool_emulator import LLMToolEmulator
9
9
  from .tool_selection import LLMToolSelectorMiddleware
10
10
 
@@ -16,6 +16,8 @@ __all__ = [
16
16
  "LLMToolEmulator",
17
17
  "ModelRouterMiddleware",
18
18
  "ToolCallRepairMiddleware",
19
- "format_prompt",
19
+ "FormatPromptMiddleware",
20
20
  "HandoffAgentMiddleware",
21
+ "tool_call_repair",
22
+ "format_prompt",
21
23
  ]
@@ -1,66 +1,156 @@
1
- from langchain.agents.middleware import ModelRequest, dynamic_prompt
1
+ from typing import Awaitable, Callable, Literal
2
+
3
+ from langchain.agents.middleware import ModelRequest
4
+ from langchain.agents.middleware.types import (
5
+ AgentMiddleware,
6
+ ModelCallResult,
7
+ ModelResponse,
8
+ )
9
+ from langchain_core.messages import SystemMessage
2
10
  from langchain_core.prompts.string import get_template_variables
3
11
 
12
+ from langchain_dev_utils._utils import _check_pkg_install
13
+
4
14
 
5
- @dynamic_prompt
6
- def format_prompt(request: ModelRequest) -> str:
15
+ class FormatPromptMiddleware(AgentMiddleware):
7
16
  """Format the system prompt with variables from state and context.
8
17
 
9
18
  This middleware function extracts template variables from the system prompt
10
19
  and populates them with values from the agent's state and runtime context.
11
20
  Variables are first resolved from the state, then from the context if not found.
12
21
 
22
+ Args:
23
+ template_format: The format of the template. Defaults to "f-string".
24
+
13
25
  Example:
14
- >>> from langchain_dev_utils.agents.middleware import format_prompt
15
- >>> from langchain.agents import create_agent
16
- >>> from langchain_core.messages import HumanMessage
17
- >>> from dataclasses import dataclass
18
- >>>
19
- >>> @dataclass
20
- ... class Context:
21
- ... name: str
22
- ... user: str
23
- >>>
24
- >>> agent=create_agent(
25
- ... model=model,
26
- ... tools=tools,
27
- ... system_prompt="You are a helpful assistant. Your name is {name}. Your user is {user}.",
28
- ... middleware=[format_prompt],
29
- ... context_schema=Context,
30
- ... )
31
- >>> agent.invoke(
32
- ... {
33
- ... "messages": [HumanMessage(content="Hello")],
34
- ... },
35
- ... context=Context(name="assistant", user="Tom"),
36
- ... )
37
26
 
27
+ # Use format_prompt middleware instance rather than FormatPromptMiddleware class (Recommended)
28
+
29
+ ```python
30
+ from langchain_dev_utils.agents.middleware import format_prompt
31
+ from langchain.agents import create_agent
32
+ from langchain_core.messages import HumanMessage
33
+ from dataclasses import dataclass
34
+
35
+ @dataclass
36
+ class Context:
37
+ name: str
38
+ user: str
39
+
40
+ agent = create_agent(
41
+ model=model,
42
+ tools=tools,
43
+ system_prompt="You are a helpful assistant. Your name is {name}. Your user is {user}.",
44
+ middleware=[format_prompt],
45
+ context_schema=Context,
46
+ )
47
+ agent.invoke(
48
+ {
49
+ "messages": [HumanMessage(content="Hello")],
50
+ },
51
+ context=Context(name="assistant", user="Tom"),
52
+ )
53
+ ```
54
+
55
+ # Use FormatPromptMiddleware class(Use when template_format is jinja2)
56
+
57
+ ```python
58
+ from langchain_dev_utils.agents.middleware import FormatPromptMiddleware
59
+ from langchain.agents import create_agent
60
+ from langchain_core.messages import HumanMessage
61
+ from dataclasses import dataclass
62
+
63
+ @dataclass
64
+ class Context:
65
+ name: str
66
+ user: str
67
+
68
+ agent = create_agent(
69
+ model=model,
70
+ tools=tools,
71
+ system_prompt="You are a helpful assistant. Your name is {{ name }}. Your user is {{ user }}.",
72
+ middleware=[FormatPromptMiddleware(template_format="jinja2")],
73
+ context_schema=Context,
74
+ )
75
+ agent.invoke(
76
+ {
77
+ "messages": [HumanMessage(content="Hello")],
78
+ },
79
+ context=Context(name="assistant", user="Tom"),
80
+ )
81
+ ```
38
82
  """
39
- system_msg = request.system_message
40
- if system_msg is None:
41
- raise ValueError(
42
- "system_message must be provided,while use format_prompt in middleware."
83
+
84
+ def __init__(
85
+ self,
86
+ *,
87
+ template_format: Literal["f-string", "jinja2"] = "f-string",
88
+ ) -> None:
89
+ super().__init__()
90
+
91
+ self.template_format = template_format
92
+
93
+ if template_format == "jinja2":
94
+ _check_pkg_install("jinja2")
95
+
96
+ def _format_prompt(self, request: ModelRequest) -> str:
97
+ """Add the plan system prompt to the system message."""
98
+ system_msg = request.system_message
99
+ if system_msg is None:
100
+ raise ValueError(
101
+ "system_message must be provided,while use format_prompt in middleware."
102
+ )
103
+
104
+ system_prompt = "\n".join(
105
+ [content.get("text", "") for content in system_msg.content_blocks]
43
106
  )
107
+ variables = get_template_variables(system_prompt, self.template_format)
108
+
109
+ format_params = {}
110
+
111
+ state = request.state
112
+ for key in variables:
113
+ if var := state.get(key, None):
114
+ format_params[key] = var
44
115
 
45
- system_prompt = "\n".join(
46
- [content.get("text", "") for content in system_msg.content_blocks]
47
- )
48
- variables = get_template_variables(system_prompt, "f-string")
116
+ other_var_keys = set(variables) - set(format_params.keys())
49
117
 
50
- format_params = {}
118
+ if other_var_keys:
119
+ context = request.runtime.context
120
+ if context is not None:
121
+ for key in other_var_keys:
122
+ if var := getattr(context, key, None):
123
+ format_params[key] = var
51
124
 
52
- state = request.state
53
- for key in variables:
54
- if var := state.get(key, None):
55
- format_params[key] = var
125
+ if self.template_format == "jinja2":
126
+ from jinja2 import Template
56
127
 
57
- other_var_keys = set(variables) - set(format_params.keys())
128
+ template = Template(system_prompt)
129
+ return template.render(**format_params)
130
+ else:
131
+ return system_prompt.format(**format_params)
132
+
133
+ def wrap_model_call(
134
+ self,
135
+ request: ModelRequest,
136
+ handler: Callable[[ModelRequest], ModelResponse],
137
+ ) -> ModelCallResult:
138
+ """Update the system prompt with variables from state and context."""
139
+ prompt = self._format_prompt(request)
140
+ request = request.override(system_message=SystemMessage(content=prompt))
141
+ return handler(request)
142
+
143
+ async def awrap_model_call(
144
+ self,
145
+ request: ModelRequest,
146
+ handler: Callable[[ModelRequest], Awaitable[ModelResponse]],
147
+ ) -> ModelCallResult:
148
+ """Update the system prompt with variables from state and context."""
149
+ prompt = self._format_prompt(request)
150
+ override_request = request.override(
151
+ system_message=SystemMessage(content=prompt)
152
+ )
153
+ return await handler(override_request)
58
154
 
59
- if other_var_keys:
60
- context = request.runtime.context
61
- if context is not None:
62
- for key in other_var_keys:
63
- if var := getattr(context, key, None):
64
- format_params[key] = var
65
155
 
66
- return system_prompt.format(**format_params)
156
+ format_prompt = FormatPromptMiddleware()
@@ -94,3 +94,6 @@ class ToolCallRepairMiddleware(AgentMiddleware):
94
94
  result=results,
95
95
  structured_response=response.structured_response,
96
96
  )
97
+
98
+
99
+ tool_call_repair = ToolCallRepairMiddleware()
@@ -261,6 +261,8 @@ class _BaseChatOpenAICompatible(BaseChatOpenAI):
261
261
  payload_messages.append(_convert_message_to_dict(m))
262
262
 
263
263
  payload["messages"] = payload_messages
264
+ if "tools" in payload and len(payload["tools"]) == 0:
265
+ payload.pop("tools")
264
266
  return payload
265
267
 
266
268
  @model_validator(mode="after")
@@ -302,6 +304,8 @@ class _BaseChatOpenAICompatible(BaseChatOpenAI):
302
304
  ModelProfile,
303
305
  _get_profile_by_provider_and_model(self._provider, self.model_name),
304
306
  )
307
+ if "json_schema" in self.supported_response_format:
308
+ self.profile.update({"structured_output": True})
305
309
  return self
306
310
 
307
311
  def _create_chat_result(
@@ -347,9 +351,9 @@ class _BaseChatOpenAICompatible(BaseChatOpenAI):
347
351
  if isinstance(model_extra, dict) and (
348
352
  reasoning := model_extra.get("reasoning")
349
353
  ):
350
- rtn.generations[0].message.additional_kwargs["reasoning_content"] = (
351
- reasoning
352
- )
354
+ rtn.generations[0].message.additional_kwargs[
355
+ "reasoning_content"
356
+ ] = reasoning
353
357
 
354
358
  return rtn
355
359
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langchain-dev-utils
3
- Version: 1.4.0
3
+ Version: 1.4.1
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
@@ -12,6 +12,7 @@ Requires-Dist: langchain-core>=1.2.5
12
12
  Requires-Dist: langchain>=1.2.0
13
13
  Requires-Dist: langgraph>=1.0.0
14
14
  Provides-Extra: standard
15
+ Requires-Dist: jinja2>=3.1.6; extra == 'standard'
15
16
  Requires-Dist: json-repair>=0.53.1; extra == 'standard'
16
17
  Requires-Dist: langchain-openai; extra == 'standard'
17
18
  Description-Content-Type: text/markdown
@@ -1,17 +1,17 @@
1
- langchain_dev_utils/__init__.py,sha256=-pa9pj_zJgPDZtE3ena4mjuVS3FEWQWYij1shjLYS80,23
2
- langchain_dev_utils/_utils.py,sha256=cWWq0sLA3yNGtcB9YyM60gcUg-hz0mjEa5CYg60cXHE,4663
1
+ langchain_dev_utils/__init__.py,sha256=nxjQ6mMSJJKqkpX2IY-1BmdpErEa1Lx5hYzk9ULB09w,23
2
+ langchain_dev_utils/_utils.py,sha256=EC1mlQggFvso1csYxCrk4XbXkJuK_8zrrjsD19ELzgk,4806
3
3
  langchain_dev_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  langchain_dev_utils/agents/__init__.py,sha256=69_biZzyJvW9OBT1g8TX_77mp9-I_TvWo9QtlvHq83E,177
5
5
  langchain_dev_utils/agents/factory.py,sha256=8XB6y_ddf58vXlTLHBL6KCirFqkD2GjtzsuOt98sS7U,3732
6
6
  langchain_dev_utils/agents/wrap.py,sha256=ufxcOCLDE4Aw2TbgcyFYor0BXXaJDzLTTJJyyD4x7bQ,12011
7
- langchain_dev_utils/agents/middleware/__init__.py,sha256=QVQibaNHvHPyNTZ2UNFfYL153ZboaCHcoioTHK0FsiY,710
8
- langchain_dev_utils/agents/middleware/format_prompt.py,sha256=yIkoSVPp0FemkjezvGsOmtgOkZDyEYQ8yh4YWYYGtVc,2343
7
+ langchain_dev_utils/agents/middleware/__init__.py,sha256=SiTibbzv2QC0FvGKN_1A10yOO62F7wtdScbGARjkyjA,808
8
+ langchain_dev_utils/agents/middleware/format_prompt.py,sha256=HrgHsMCnfHQ-Eh_RY-h56otAJ62-2zJJHbOi2kRyEiw,5303
9
9
  langchain_dev_utils/agents/middleware/handoffs.py,sha256=rSkNXxqtjB8_xT0HUdxnKbchgY76BuTPX-Zc69H-_wI,7687
10
10
  langchain_dev_utils/agents/middleware/model_fallback.py,sha256=8xiNjTJ0yiRkPLCRfAGNnqY1TLstj1Anmiqyv5w2mA8,1633
11
11
  langchain_dev_utils/agents/middleware/model_router.py,sha256=IidYq72tPLa053gEg5IQpPzDzyCxYYEvpgT1K4qBwXw,7862
12
12
  langchain_dev_utils/agents/middleware/plan.py,sha256=Zz0dh1BRbsVgROmhjH2IIqylSsuKHZXJx0iztMBm8EU,14719
13
13
  langchain_dev_utils/agents/middleware/summarization.py,sha256=IoZ2PM1OC3AXwf0DWpfreuPOAipeiYu0KPmAABWXuY0,3087
14
- langchain_dev_utils/agents/middleware/tool_call_repair.py,sha256=oZF0Oejemqs9kSn8xbW79FWyVVarL4IGCz0gpqYBkFM,3529
14
+ langchain_dev_utils/agents/middleware/tool_call_repair.py,sha256=mO21g9nzukdjNcERTg63jS7UOEF47Wx8yd7CqFS_VVQ,3580
15
15
  langchain_dev_utils/agents/middleware/tool_emulator.py,sha256=OgtPhqturaWzF4fRSJ3f_IXvIrYrrAjlpOC5zmLtrkY,2031
16
16
  langchain_dev_utils/agents/middleware/tool_selection.py,sha256=dRH5ejR6N02Djwxt6Gd63MYkg6SV5pySlzaRt53OoZk,3113
17
17
  langchain_dev_utils/chat_models/__init__.py,sha256=YSLUyHrWEEj4y4DtGFCOnDW02VIYZdfAH800m4Klgeg,224
@@ -19,7 +19,7 @@ langchain_dev_utils/chat_models/base.py,sha256=G_SNvd53ogho-LRgD7DCD65xj51J2JxmO
19
19
  langchain_dev_utils/chat_models/types.py,sha256=MD3cv_ZIe9fCdgwisNfuxAOhy-j4YSs1ZOQYyCjlNKs,927
20
20
  langchain_dev_utils/chat_models/adapters/__init__.py,sha256=4tTbhAAQdpX_gWyWeH97hqS5HnaoqQqW6QBh9Qd1SKs,106
21
21
  langchain_dev_utils/chat_models/adapters/create_utils.py,sha256=r8_XWLNF3Yc6sumlBhmgG1QcBa4Dsba7X3f_9YeMeGA,2479
22
- langchain_dev_utils/chat_models/adapters/openai_compatible.py,sha256=Z-AOpMm6MldKpL8EtuZ9pzfOFAjirZUKxw2K7EPk87w,27200
22
+ langchain_dev_utils/chat_models/adapters/openai_compatible.py,sha256=I9MXplglcTSzrRx8Y7sDGliiT7_Wiugv3wdv5y1cpr0,27418
23
23
  langchain_dev_utils/chat_models/adapters/register_profiles.py,sha256=YS9ItCEq2ISoB_bp6QH5NVKOVR9-7la3r7B_xQNxZxE,366
24
24
  langchain_dev_utils/embeddings/__init__.py,sha256=zbEOaV86TUi9Zrg_dH9dpdgacWg31HMJTlTQknA9EKk,244
25
25
  langchain_dev_utils/embeddings/base.py,sha256=GXFKZSAExMtCFUpsd6mY4NxCWCrq7JAatBw3kS9LaKY,8803
@@ -40,7 +40,7 @@ langchain_dev_utils/pipeline/types.py,sha256=T3aROKKXeWvd0jcH5XkgMDQfEkLfPaiOhhV
40
40
  langchain_dev_utils/tool_calling/__init__.py,sha256=mu_WxKMcu6RoTf4vkTPbA1WSBSNc6YIqyBtOQ6iVQj4,322
41
41
  langchain_dev_utils/tool_calling/human_in_the_loop.py,sha256=7Z_QO5OZUR6K8nLoIcafc6osnvX2IYNorOJcbx6bVso,9672
42
42
  langchain_dev_utils/tool_calling/utils.py,sha256=S4-KXQ8jWmpGTXYZitovF8rxKpaSSUkFruM8LDwvcvE,2765
43
- langchain_dev_utils-1.4.0.dist-info/METADATA,sha256=bF2sQIAP0N0yDnBm-_DZDQbFS5sHqrmF7HtRHFQEexY,4758
44
- langchain_dev_utils-1.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
45
- langchain_dev_utils-1.4.0.dist-info/licenses/LICENSE,sha256=AWAOzNEcsvCEzHOF0qby5OKxviVH_eT9Yce1sgJTico,1084
46
- langchain_dev_utils-1.4.0.dist-info/RECORD,,
43
+ langchain_dev_utils-1.4.1.dist-info/METADATA,sha256=QqpJZwTwFUIzwIXZRjfSVGHMrtZG7pJ6salBq_zYEL0,4808
44
+ langchain_dev_utils-1.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
45
+ langchain_dev_utils-1.4.1.dist-info/licenses/LICENSE,sha256=AWAOzNEcsvCEzHOF0qby5OKxviVH_eT9Yce1sgJTico,1084
46
+ langchain_dev_utils-1.4.1.dist-info/RECORD,,