langchain 1.0.5__py3-none-any.whl → 1.2.4__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.
Files changed (34) hide show
  1. langchain/__init__.py +1 -1
  2. langchain/agents/__init__.py +1 -7
  3. langchain/agents/factory.py +153 -79
  4. langchain/agents/middleware/__init__.py +18 -23
  5. langchain/agents/middleware/_execution.py +29 -32
  6. langchain/agents/middleware/_redaction.py +108 -22
  7. langchain/agents/middleware/_retry.py +123 -0
  8. langchain/agents/middleware/context_editing.py +47 -25
  9. langchain/agents/middleware/file_search.py +19 -14
  10. langchain/agents/middleware/human_in_the_loop.py +87 -57
  11. langchain/agents/middleware/model_call_limit.py +64 -18
  12. langchain/agents/middleware/model_fallback.py +7 -9
  13. langchain/agents/middleware/model_retry.py +307 -0
  14. langchain/agents/middleware/pii.py +82 -29
  15. langchain/agents/middleware/shell_tool.py +254 -107
  16. langchain/agents/middleware/summarization.py +469 -95
  17. langchain/agents/middleware/todo.py +129 -31
  18. langchain/agents/middleware/tool_call_limit.py +105 -71
  19. langchain/agents/middleware/tool_emulator.py +47 -38
  20. langchain/agents/middleware/tool_retry.py +183 -164
  21. langchain/agents/middleware/tool_selection.py +81 -37
  22. langchain/agents/middleware/types.py +856 -427
  23. langchain/agents/structured_output.py +65 -42
  24. langchain/chat_models/__init__.py +1 -7
  25. langchain/chat_models/base.py +253 -196
  26. langchain/embeddings/__init__.py +0 -5
  27. langchain/embeddings/base.py +79 -65
  28. langchain/messages/__init__.py +0 -5
  29. langchain/tools/__init__.py +1 -7
  30. {langchain-1.0.5.dist-info → langchain-1.2.4.dist-info}/METADATA +5 -7
  31. langchain-1.2.4.dist-info/RECORD +36 -0
  32. {langchain-1.0.5.dist-info → langchain-1.2.4.dist-info}/WHEEL +1 -1
  33. langchain-1.0.5.dist-info/RECORD +0 -34
  34. {langchain-1.0.5.dist-info → langchain-1.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json
5
6
  import uuid
6
7
  from dataclasses import dataclass, is_dataclass
7
8
  from types import UnionType
@@ -74,7 +75,7 @@ class StructuredOutputValidationError(StructuredOutputError):
74
75
 
75
76
 
76
77
  def _parse_with_schema(
77
- schema: type[SchemaT] | dict, schema_kind: SchemaKind, data: dict[str, Any]
78
+ schema: type[SchemaT] | dict[str, Any], schema_kind: SchemaKind, data: dict[str, Any]
78
79
  ) -> Any:
79
80
  """Parse data using for any supported schema type.
80
81
 
@@ -105,21 +106,21 @@ def _parse_with_schema(
105
106
  class _SchemaSpec(Generic[SchemaT]):
106
107
  """Describes a structured output schema."""
107
108
 
108
- schema: type[SchemaT]
109
+ schema: type[SchemaT] | dict[str, Any]
109
110
  """The schema for the response, can be a Pydantic model, `dataclass`, `TypedDict`,
110
111
  or JSON schema dict."""
111
112
 
112
113
  name: str
113
114
  """Name of the schema, used for tool calling.
114
115
 
115
- If not provided, the name will be the model name or `"response_format"` if it's a
116
- JSON schema.
116
+ If not provided, the name will be the class name for models/dataclasses/TypedDicts,
117
+ or the `title` field for JSON schemas. Falls back to a generated name if unavailable.
117
118
  """
118
119
 
119
120
  description: str
120
121
  """Custom description of the schema.
121
122
 
122
- If not provided, provided will use the model's docstring.
123
+ If not provided, will use the model's docstring.
123
124
  """
124
125
 
125
126
  schema_kind: SchemaKind
@@ -128,18 +129,28 @@ class _SchemaSpec(Generic[SchemaT]):
128
129
  json_schema: dict[str, Any]
129
130
  """JSON schema associated with the schema."""
130
131
 
131
- strict: bool = False
132
+ strict: bool | None = None
132
133
  """Whether to enforce strict validation of the schema."""
133
134
 
134
135
  def __init__(
135
136
  self,
136
- schema: type[SchemaT],
137
+ schema: type[SchemaT] | dict[str, Any],
137
138
  *,
138
139
  name: str | None = None,
139
140
  description: str | None = None,
140
- strict: bool = False,
141
+ strict: bool | None = None,
141
142
  ) -> None:
142
- """Initialize SchemaSpec with schema and optional parameters."""
143
+ """Initialize `SchemaSpec` with schema and optional parameters.
144
+
145
+ Args:
146
+ schema: Schema to describe.
147
+ name: Optional name for the schema.
148
+ description: Optional description for the schema.
149
+ strict: Whether to enforce strict validation of the schema.
150
+
151
+ Raises:
152
+ ValueError: If the schema type is unsupported.
153
+ """
143
154
  self.schema = schema
144
155
 
145
156
  if name:
@@ -181,10 +192,10 @@ class _SchemaSpec(Generic[SchemaT]):
181
192
  class ToolStrategy(Generic[SchemaT]):
182
193
  """Use a tool calling strategy for model responses."""
183
194
 
184
- schema: type[SchemaT]
195
+ schema: type[SchemaT] | UnionType | dict[str, Any]
185
196
  """Schema for the tool calls."""
186
197
 
187
- schema_specs: list[_SchemaSpec[SchemaT]]
198
+ schema_specs: list[_SchemaSpec[Any]]
188
199
  """Schema specs for the tool calls."""
189
200
 
190
201
  tool_message_content: str | None
@@ -207,7 +218,7 @@ class ToolStrategy(Generic[SchemaT]):
207
218
 
208
219
  def __init__(
209
220
  self,
210
- schema: type[SchemaT],
221
+ schema: type[SchemaT] | UnionType | dict[str, Any],
211
222
  *,
212
223
  tool_message_content: str | None = None,
213
224
  handle_errors: bool
@@ -227,7 +238,7 @@ class ToolStrategy(Generic[SchemaT]):
227
238
 
228
239
  def _iter_variants(schema: Any) -> Iterable[Any]:
229
240
  """Yield leaf variants from Union and JSON Schema oneOf."""
230
- if get_origin(schema) in (UnionType, Union):
241
+ if get_origin(schema) in {UnionType, Union}:
231
242
  for arg in get_args(schema):
232
243
  yield from _iter_variants(arg)
233
244
  return
@@ -246,7 +257,7 @@ class ToolStrategy(Generic[SchemaT]):
246
257
  class ProviderStrategy(Generic[SchemaT]):
247
258
  """Use the model provider's native structured output method."""
248
259
 
249
- schema: type[SchemaT]
260
+ schema: type[SchemaT] | dict[str, Any]
250
261
  """Schema for native mode."""
251
262
 
252
263
  schema_spec: _SchemaSpec[SchemaT]
@@ -254,22 +265,37 @@ class ProviderStrategy(Generic[SchemaT]):
254
265
 
255
266
  def __init__(
256
267
  self,
257
- schema: type[SchemaT],
268
+ schema: type[SchemaT] | dict[str, Any],
269
+ *,
270
+ strict: bool | None = None,
258
271
  ) -> None:
259
- """Initialize ProviderStrategy with schema."""
272
+ """Initialize ProviderStrategy with schema.
273
+
274
+ Args:
275
+ schema: Schema to enforce via the provider's native structured output.
276
+ strict: Whether to request strict provider-side schema enforcement.
277
+ """
260
278
  self.schema = schema
261
- self.schema_spec = _SchemaSpec(schema)
279
+ self.schema_spec = _SchemaSpec(schema, strict=strict)
262
280
 
263
281
  def to_model_kwargs(self) -> dict[str, Any]:
264
- """Convert to kwargs to bind to a model to force structured output."""
282
+ """Convert to kwargs to bind to a model to force structured output.
283
+
284
+ Returns:
285
+ The kwargs to bind to a model.
286
+ """
265
287
  # OpenAI:
266
288
  # - see https://platform.openai.com/docs/guides/structured-outputs
267
- response_format = {
289
+ json_schema: dict[str, Any] = {
290
+ "name": self.schema_spec.name,
291
+ "schema": self.schema_spec.json_schema,
292
+ }
293
+ if self.schema_spec.strict:
294
+ json_schema["strict"] = True
295
+
296
+ response_format: dict[str, Any] = {
268
297
  "type": "json_schema",
269
- "json_schema": {
270
- "name": self.schema_spec.name,
271
- "schema": self.schema_spec.json_schema,
272
- },
298
+ "json_schema": json_schema,
273
299
  }
274
300
  return {"response_format": response_format}
275
301
 
@@ -283,7 +309,7 @@ class OutputToolBinding(Generic[SchemaT]):
283
309
  and the corresponding tool implementation used by the tools strategy.
284
310
  """
285
311
 
286
- schema: type[SchemaT]
312
+ schema: type[SchemaT] | dict[str, Any]
287
313
  """The original schema provided for structured output
288
314
  (Pydantic model, dataclass, TypedDict, or JSON schema dict)."""
289
315
 
@@ -337,7 +363,7 @@ class ProviderStrategyBinding(Generic[SchemaT]):
337
363
  its type classification, and parsing logic for provider-enforced JSON.
338
364
  """
339
365
 
340
- schema: type[SchemaT]
366
+ schema: type[SchemaT] | dict[str, Any]
341
367
  """The original schema provided for structured output
342
368
  (Pydantic model, `dataclass`, `TypedDict`, or JSON schema dict)."""
343
369
 
@@ -374,8 +400,6 @@ class ProviderStrategyBinding(Generic[SchemaT]):
374
400
  # Extract text content from AIMessage and parse as JSON
375
401
  raw_text = self._extract_text_content_from_message(response)
376
402
 
377
- import json
378
-
379
403
  try:
380
404
  data = json.loads(raw_text)
381
405
  except Exception as e:
@@ -389,7 +413,8 @@ class ProviderStrategyBinding(Generic[SchemaT]):
389
413
  # Parse according to schema
390
414
  return _parse_with_schema(self.schema, self.schema_kind, data)
391
415
 
392
- def _extract_text_content_from_message(self, message: AIMessage) -> str:
416
+ @staticmethod
417
+ def _extract_text_content_from_message(message: AIMessage) -> str:
393
418
  """Extract text content from an AIMessage.
394
419
 
395
420
  Args:
@@ -401,29 +426,27 @@ class ProviderStrategyBinding(Generic[SchemaT]):
401
426
  content = message.content
402
427
  if isinstance(content, str):
403
428
  return content
404
- if isinstance(content, list):
405
- parts: list[str] = []
406
- for c in content:
407
- if isinstance(c, dict):
408
- if c.get("type") == "text" and "text" in c:
409
- parts.append(str(c["text"]))
410
- elif "content" in c and isinstance(c["content"], str):
411
- parts.append(c["content"])
412
- else:
413
- parts.append(str(c))
414
- return "".join(parts)
415
- return str(content)
429
+ parts: list[str] = []
430
+ for c in content:
431
+ if isinstance(c, dict):
432
+ if c.get("type") == "text" and "text" in c:
433
+ parts.append(str(c["text"]))
434
+ elif "content" in c and isinstance(c["content"], str):
435
+ parts.append(c["content"])
436
+ else:
437
+ parts.append(str(c))
438
+ return "".join(parts)
416
439
 
417
440
 
418
441
  class AutoStrategy(Generic[SchemaT]):
419
442
  """Automatically select the best strategy for structured output."""
420
443
 
421
- schema: type[SchemaT]
444
+ schema: type[SchemaT] | dict[str, Any]
422
445
  """Schema for automatic mode."""
423
446
 
424
447
  def __init__(
425
448
  self,
426
- schema: type[SchemaT],
449
+ schema: type[SchemaT] | dict[str, Any],
427
450
  ) -> None:
428
451
  """Initialize AutoStrategy with schema."""
429
452
  self.schema = schema
@@ -1,10 +1,4 @@
1
- """Entrypoint to using [chat models](https://docs.langchain.com/oss/python/langchain/models) in LangChain.
2
-
3
- !!! warning "Reference docs"
4
- This page contains **reference documentation** for chat models. See
5
- [the docs](https://docs.langchain.com/oss/python/langchain/models) for conceptual
6
- guides, tutorials, and examples on using chat models.
7
- """ # noqa: E501
1
+ """Entrypoint to using [chat models](https://docs.langchain.com/oss/python/langchain/models) in LangChain.""" # noqa: E501
8
2
 
9
3
  from langchain_core.language_models import BaseChatModel
10
4