langchain 1.0.0a7__tar.gz → 1.0.0a8__tar.gz

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 might be problematic. Click here for more details.

Files changed (91) hide show
  1. {langchain-1.0.0a7 → langchain-1.0.0a8}/PKG-INFO +1 -1
  2. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/middleware/__init__.py +0 -2
  3. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/middleware/human_in_the_loop.py +23 -19
  4. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/middleware/prompt_caching.py +22 -5
  5. langchain-1.0.0a8/langchain/agents/middleware/types.py +543 -0
  6. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/middleware_agent.py +26 -22
  7. {langchain-1.0.0a7 → langchain-1.0.0a8}/pyproject.toml +1 -1
  8. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/__snapshots__/test_middleware_agent.ambr +40 -119
  9. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_middleware_agent.py +149 -88
  10. langchain-1.0.0a8/tests/unit_tests/agents/test_middleware_decorators.py +152 -0
  11. langchain-1.0.0a7/langchain/agents/middleware/dynamic_system_prompt.py +0 -105
  12. langchain-1.0.0a7/langchain/agents/middleware/types.py +0 -119
  13. {langchain-1.0.0a7 → langchain-1.0.0a8}/LICENSE +0 -0
  14. {langchain-1.0.0a7 → langchain-1.0.0a8}/README.md +0 -0
  15. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/__init__.py +0 -0
  16. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/_internal/__init__.py +0 -0
  17. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/_internal/_documents.py +0 -0
  18. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/_internal/_lazy_import.py +0 -0
  19. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/_internal/_prompts.py +0 -0
  20. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/_internal/_typing.py +0 -0
  21. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/_internal/_utils.py +0 -0
  22. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/__init__.py +0 -0
  23. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/_internal/__init__.py +0 -0
  24. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/_internal/_typing.py +0 -0
  25. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/middleware/summarization.py +0 -0
  26. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/react_agent.py +0 -0
  27. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/structured_output.py +0 -0
  28. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/agents/tool_node.py +0 -0
  29. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/chat_models/__init__.py +0 -0
  30. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/chat_models/base.py +0 -0
  31. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/documents/__init__.py +0 -0
  32. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/embeddings/__init__.py +0 -0
  33. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/embeddings/base.py +0 -0
  34. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/embeddings/cache.py +0 -0
  35. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/globals.py +0 -0
  36. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/py.typed +0 -0
  37. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/storage/__init__.py +0 -0
  38. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/storage/encoder_backed.py +0 -0
  39. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/storage/exceptions.py +0 -0
  40. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/storage/in_memory.py +0 -0
  41. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/text_splitter.py +0 -0
  42. {langchain-1.0.0a7 → langchain-1.0.0a8}/langchain/tools/__init__.py +0 -0
  43. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/__init__.py +0 -0
  44. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/__init__.py +0 -0
  45. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/agents/__init__.py +0 -0
  46. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/agents/test_response_format.py +0 -0
  47. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/cache/__init__.py +0 -0
  48. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/cache/fake_embeddings.py +0 -0
  49. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/chat_models/__init__.py +0 -0
  50. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/chat_models/test_base.py +0 -0
  51. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/conftest.py +0 -0
  52. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/embeddings/__init__.py +0 -0
  53. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/embeddings/test_base.py +0 -0
  54. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/integration_tests/test_compile.py +0 -0
  55. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/__init__.py +0 -0
  56. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/__init__.py +0 -0
  57. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/__snapshots__/test_react_agent_graph.ambr +0 -0
  58. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/any_str.py +0 -0
  59. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/compose-postgres.yml +0 -0
  60. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/compose-redis.yml +0 -0
  61. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/conftest.py +0 -0
  62. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/conftest_checkpointer.py +0 -0
  63. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/conftest_store.py +0 -0
  64. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/memory_assert.py +0 -0
  65. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/messages.py +0 -0
  66. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/model.py +0 -0
  67. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/specifications/responses.json +0 -0
  68. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/specifications/return_direct.json +0 -0
  69. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_react_agent.py +0 -0
  70. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_react_agent_graph.py +0 -0
  71. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_response_format.py +0 -0
  72. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_responses.py +0 -0
  73. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_responses_spec.py +0 -0
  74. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_return_direct_spec.py +0 -0
  75. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/test_tool_node.py +0 -0
  76. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/agents/utils.py +0 -0
  77. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/chat_models/__init__.py +0 -0
  78. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/chat_models/test_chat_models.py +0 -0
  79. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/conftest.py +0 -0
  80. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/embeddings/__init__.py +0 -0
  81. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/embeddings/test_base.py +0 -0
  82. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/embeddings/test_caching.py +0 -0
  83. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/embeddings/test_imports.py +0 -0
  84. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/storage/__init__.py +0 -0
  85. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/storage/test_imports.py +0 -0
  86. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/stubs.py +0 -0
  87. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/test_dependencies.py +0 -0
  88. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/test_imports.py +0 -0
  89. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/test_pytest_config.py +0 -0
  90. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/tools/__init__.py +0 -0
  91. {langchain-1.0.0a7 → langchain-1.0.0a8}/tests/unit_tests/tools/test_imports.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain
3
- Version: 1.0.0a7
3
+ Version: 1.0.0a8
4
4
  Summary: Building applications with LLMs through composability
5
5
  License: MIT
6
6
  Project-URL: Source Code, https://github.com/langchain-ai/langchain/tree/master/libs/langchain
@@ -1,6 +1,5 @@
1
1
  """Middleware plugins for agents."""
2
2
 
3
- from .dynamic_system_prompt import DynamicSystemPromptMiddleware
4
3
  from .human_in_the_loop import HumanInTheLoopMiddleware
5
4
  from .prompt_caching import AnthropicPromptCachingMiddleware
6
5
  from .summarization import SummarizationMiddleware
@@ -11,7 +10,6 @@ __all__ = [
11
10
  "AgentState",
12
11
  # should move to langchain-anthropic if we decide to keep it
13
12
  "AnthropicPromptCachingMiddleware",
14
- "DynamicSystemPromptMiddleware",
15
13
  "HumanInTheLoopMiddleware",
16
14
  "ModelRequest",
17
15
  "SummarizationMiddleware",
@@ -112,14 +112,14 @@ class HumanInTheLoopMiddleware(AgentMiddleware):
112
112
 
113
113
  def __init__(
114
114
  self,
115
- tool_configs: dict[str, bool | ToolConfig],
115
+ interrupt_on: dict[str, bool | ToolConfig],
116
116
  *,
117
117
  description_prefix: str = "Tool execution requires approval",
118
118
  ) -> None:
119
119
  """Initialize the human in the loop middleware.
120
120
 
121
121
  Args:
122
- tool_configs: Mapping of tool name to allowed actions.
122
+ interrupt_on: Mapping of tool name to allowed actions.
123
123
  If a tool doesn't have an entry, it's auto-approved by default.
124
124
  * `True` indicates all actions are allowed: accept, edit, and respond.
125
125
  * `False` indicates that the tool is auto-approved.
@@ -130,7 +130,7 @@ class HumanInTheLoopMiddleware(AgentMiddleware):
130
130
  """
131
131
  super().__init__()
132
132
  resolved_tool_configs: dict[str, ToolConfig] = {}
133
- for tool_name, tool_config in tool_configs.items():
133
+ for tool_name, tool_config in interrupt_on.items():
134
134
  if isinstance(tool_config, bool):
135
135
  if tool_config is True:
136
136
  resolved_tool_configs[tool_name] = ToolConfig(
@@ -138,13 +138,15 @@ class HumanInTheLoopMiddleware(AgentMiddleware):
138
138
  allow_edit=True,
139
139
  allow_respond=True,
140
140
  )
141
- else:
141
+ elif any(
142
+ tool_config.get(x, False) for x in ["allow_accept", "allow_edit", "allow_respond"]
143
+ ):
142
144
  resolved_tool_configs[tool_name] = tool_config
143
- self.tool_configs = resolved_tool_configs
145
+ self.interrupt_on = resolved_tool_configs
144
146
  self.description_prefix = description_prefix
145
147
 
146
148
  def after_model(self, state: AgentState) -> dict[str, Any] | None: # type: ignore[override]
147
- """Trigger HITL flows for relevant tool calls after an AIMessage."""
149
+ """Trigger interrupt flows for relevant tool calls after an AIMessage."""
148
150
  messages = state["messages"]
149
151
  if not messages:
150
152
  return None
@@ -154,16 +156,16 @@ class HumanInTheLoopMiddleware(AgentMiddleware):
154
156
  return None
155
157
 
156
158
  # Separate tool calls that need interrupts from those that don't
157
- hitl_tool_calls: list[ToolCall] = []
159
+ interrupt_tool_calls: list[ToolCall] = []
158
160
  auto_approved_tool_calls = []
159
161
 
160
162
  for tool_call in last_ai_msg.tool_calls:
161
- hitl_tool_calls.append(tool_call) if tool_call[
163
+ interrupt_tool_calls.append(tool_call) if tool_call[
162
164
  "name"
163
- ] in self.tool_configs else auto_approved_tool_calls.append(tool_call)
165
+ ] in self.interrupt_on else auto_approved_tool_calls.append(tool_call)
164
166
 
165
167
  # If no interrupts needed, return early
166
- if not hitl_tool_calls:
168
+ if not interrupt_tool_calls:
167
169
  return None
168
170
 
169
171
  # Process all tool calls that require interrupts
@@ -171,11 +173,11 @@ class HumanInTheLoopMiddleware(AgentMiddleware):
171
173
  artificial_tool_messages: list[ToolMessage] = []
172
174
 
173
175
  # Create interrupt requests for all tools that need approval
174
- hitl_requests: list[HumanInTheLoopRequest] = []
175
- for tool_call in hitl_tool_calls:
176
+ interrupt_requests: list[HumanInTheLoopRequest] = []
177
+ for tool_call in interrupt_tool_calls:
176
178
  tool_name = tool_call["name"]
177
179
  tool_args = tool_call["args"]
178
- config = self.tool_configs[tool_name]
180
+ config = self.interrupt_on[tool_name]
179
181
  description = (
180
182
  config.get("description")
181
183
  or f"{self.description_prefix}\n\nTool: {tool_name}\nArgs: {tool_args}"
@@ -189,21 +191,23 @@ class HumanInTheLoopMiddleware(AgentMiddleware):
189
191
  "config": config,
190
192
  "description": description,
191
193
  }
192
- hitl_requests.append(request)
194
+ interrupt_requests.append(request)
193
195
 
194
- responses: list[HumanInTheLoopResponse] = interrupt(hitl_requests)
196
+ responses: list[HumanInTheLoopResponse] = interrupt(interrupt_requests)
195
197
 
196
198
  # Validate that the number of responses matches the number of interrupt tool calls
197
- if (responses_len := len(responses)) != (hitl_tool_calls_len := len(hitl_tool_calls)):
199
+ if (responses_len := len(responses)) != (
200
+ interrupt_tool_calls_len := len(interrupt_tool_calls)
201
+ ):
198
202
  msg = (
199
203
  f"Number of human responses ({responses_len}) does not match "
200
- f"number of hanging tool calls ({hitl_tool_calls_len})."
204
+ f"number of hanging tool calls ({interrupt_tool_calls_len})."
201
205
  )
202
206
  raise ValueError(msg)
203
207
 
204
208
  for i, response in enumerate(responses):
205
- tool_call = hitl_tool_calls[i]
206
- config = self.tool_configs[tool_call["name"]]
209
+ tool_call = interrupt_tool_calls[i]
210
+ config = self.interrupt_on[tool_call["name"]]
207
211
 
208
212
  if response["type"] == "accept" and config.get("allow_accept"):
209
213
  approved_tool_calls.append(tool_call)
@@ -1,6 +1,7 @@
1
1
  """Anthropic prompt caching middleware."""
2
2
 
3
3
  from typing import Literal
4
+ from warnings import warn
4
5
 
5
6
  from langchain.agents.middleware.types import AgentMiddleware, ModelRequest
6
7
 
@@ -19,6 +20,7 @@ class AnthropicPromptCachingMiddleware(AgentMiddleware):
19
20
  type: Literal["ephemeral"] = "ephemeral",
20
21
  ttl: Literal["5m", "1h"] = "5m",
21
22
  min_messages_to_cache: int = 0,
23
+ unsupported_model_behavior: Literal["ignore", "warn", "raise"] = "warn",
22
24
  ) -> None:
23
25
  """Initialize the middleware with cache control settings.
24
26
 
@@ -27,10 +29,15 @@ class AnthropicPromptCachingMiddleware(AgentMiddleware):
27
29
  ttl: The time to live for the cache, only "5m" and "1h" are supported.
28
30
  min_messages_to_cache: The minimum number of messages until the cache is used,
29
31
  default is 0.
32
+ unsupported_model_behavior: The behavior to take when an unsupported model is used.
33
+ "ignore" will ignore the unsupported model and continue without caching.
34
+ "warn" will warn the user and continue without caching.
35
+ "raise" will raise an error and stop the agent.
30
36
  """
31
37
  self.type = type
32
38
  self.ttl = ttl
33
39
  self.min_messages_to_cache = min_messages_to_cache
40
+ self.unsupported_model_behavior = unsupported_model_behavior
34
41
 
35
42
  def modify_model_request( # type: ignore[override]
36
43
  self,
@@ -40,19 +47,29 @@ class AnthropicPromptCachingMiddleware(AgentMiddleware):
40
47
  try:
41
48
  from langchain_anthropic import ChatAnthropic
42
49
  except ImportError:
50
+ ChatAnthropic = None # noqa: N806
51
+
52
+ msg: str | None = None
53
+
54
+ if ChatAnthropic is None:
43
55
  msg = (
44
56
  "AnthropicPromptCachingMiddleware caching middleware only supports "
45
- "Anthropic models."
57
+ "Anthropic models. "
46
58
  "Please install langchain-anthropic."
47
59
  )
48
- raise ValueError(msg)
49
-
50
- if not isinstance(request.model, ChatAnthropic):
60
+ elif not isinstance(request.model, ChatAnthropic):
51
61
  msg = (
52
62
  "AnthropicPromptCachingMiddleware caching middleware only supports "
53
63
  f"Anthropic models, not instances of {type(request.model)}"
54
64
  )
55
- raise ValueError(msg)
65
+
66
+ if msg is not None:
67
+ if self.unsupported_model_behavior == "raise":
68
+ raise ValueError(msg)
69
+ if self.unsupported_model_behavior == "warn":
70
+ warn(msg, stacklevel=3)
71
+ else:
72
+ return request
56
73
 
57
74
  messages_count = (
58
75
  len(request.messages) + 1 if request.system_prompt else len(request.messages)