langchain-core 0.3.75__py3-none-any.whl → 1.0.0a1__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-core might be problematic. Click here for more details.

Files changed (32) hide show
  1. langchain_core/language_models/_utils.py +233 -68
  2. langchain_core/language_models/base.py +2 -1
  3. langchain_core/language_models/chat_models.py +196 -33
  4. langchain_core/language_models/fake_chat_models.py +22 -6
  5. langchain_core/messages/__init__.py +74 -4
  6. langchain_core/messages/ai.py +191 -26
  7. langchain_core/messages/base.py +164 -25
  8. langchain_core/messages/block_translators/__init__.py +89 -0
  9. langchain_core/messages/block_translators/anthropic.py +451 -0
  10. langchain_core/messages/block_translators/bedrock.py +45 -0
  11. langchain_core/messages/block_translators/bedrock_converse.py +47 -0
  12. langchain_core/messages/block_translators/google_genai.py +45 -0
  13. langchain_core/messages/block_translators/google_vertexai.py +47 -0
  14. langchain_core/messages/block_translators/groq.py +45 -0
  15. langchain_core/messages/block_translators/langchain_v0.py +297 -0
  16. langchain_core/messages/block_translators/ollama.py +45 -0
  17. langchain_core/messages/block_translators/openai.py +586 -0
  18. langchain_core/messages/content.py +1568 -0
  19. langchain_core/messages/human.py +29 -9
  20. langchain_core/messages/system.py +29 -9
  21. langchain_core/messages/tool.py +30 -27
  22. langchain_core/messages/utils.py +12 -5
  23. langchain_core/prompt_values.py +1 -1
  24. langchain_core/runnables/base.py +1 -1
  25. langchain_core/utils/_merge.py +44 -6
  26. langchain_core/utils/utils.py +29 -0
  27. langchain_core/version.py +1 -1
  28. {langchain_core-0.3.75.dist-info → langchain_core-1.0.0a1.dist-info}/METADATA +2 -2
  29. {langchain_core-0.3.75.dist-info → langchain_core-1.0.0a1.dist-info}/RECORD +31 -21
  30. langchain_core/messages/content_blocks.py +0 -155
  31. {langchain_core-0.3.75.dist-info → langchain_core-1.0.0a1.dist-info}/WHEEL +0 -0
  32. {langchain_core-0.3.75.dist-info → langchain_core-1.0.0a1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1568 @@
1
+ """Standard, multimodal content blocks for Large Language Model I/O.
2
+
3
+ .. warning::
4
+ This module is under active development. The API is unstable and subject to
5
+ change in future releases.
6
+
7
+ This module provides standardized data structures for representing inputs to and
8
+ outputs from LLMs. The core abstraction is the **Content Block**, a ``TypedDict``.
9
+
10
+ **Rationale**
11
+
12
+ Different LLM providers use distinct and incompatible API schemas. This module
13
+ provides a unified, provider-agnostic format to facilitate these interactions. A
14
+ message to or from a model is simply a list of content blocks, allowing for the natural
15
+ interleaving of text, images, and other content in a single ordered sequence.
16
+
17
+ An adapter for a specific provider is responsible for translating this standard list of
18
+ blocks into the format required by its API.
19
+
20
+ **Extensibility**
21
+
22
+ Data **not yet mapped** to a standard block may be represented using the
23
+ ``NonStandardContentBlock``, which allows for provider-specific data to be included
24
+ without losing the benefits of type checking and validation.
25
+
26
+ Furthermore, provider-specific fields **within** a standard block are fully supported
27
+ by default in the ``extras`` field of each block. This allows for additional metadata
28
+ to be included without breaking the standard structure.
29
+
30
+ .. warning::
31
+ Do not heavily rely on the ``extras`` field for provider-specific data! This field
32
+ is subject to deprecation in future releases as we move towards PEP 728.
33
+
34
+ .. note::
35
+ Following widespread adoption of `PEP 728 <https://peps.python.org/pep-0728/>`__, we
36
+ will add ``extra_items=Any`` as a param to Content Blocks. This will signify to type
37
+ checkers that additional provider-specific fields are allowed outside of the
38
+ ``extras`` field, and that will become the new standard approach to adding
39
+ provider-specific metadata.
40
+
41
+ .. dropdown::
42
+
43
+ **Example with PEP 728 provider-specific fields:**
44
+
45
+ .. code-block:: python
46
+
47
+ # Content block definition
48
+ # NOTE: `extra_items=Any`
49
+ class TextContentBlock(TypedDict, extra_items=Any):
50
+ type: Literal["text"]
51
+ id: NotRequired[str]
52
+ text: str
53
+ annotations: NotRequired[list[Annotation]]
54
+ index: NotRequired[int]
55
+
56
+ .. code-block:: python
57
+
58
+ from langchain_core.messages.content import TextContentBlock
59
+
60
+ # Create a text content block with provider-specific fields
61
+ my_block: TextContentBlock = {
62
+ # Add required fields
63
+ "type": "text",
64
+ "text": "Hello, world!",
65
+ # Additional fields not specified in the TypedDict
66
+ # These are valid with PEP 728 and are typed as Any
67
+ "openai_metadata": {"model": "gpt-4", "temperature": 0.7},
68
+ "anthropic_usage": {"input_tokens": 10, "output_tokens": 20},
69
+ "custom_field": "any value",
70
+ }
71
+
72
+ # Mutating an existing block to add provider-specific fields
73
+ openai_data = my_block["openai_metadata"] # Type: Any
74
+
75
+ PEP 728 is enabled with ``# type: ignore[call-arg]`` comments to suppress
76
+ warnings from type checkers that don't yet support it. The functionality works
77
+ correctly in Python 3.13+ and will be fully supported as the ecosystem catches
78
+ up.
79
+
80
+ **Key Block Types**
81
+
82
+ The module defines several types of content blocks, including:
83
+
84
+ - ``TextContentBlock``: Standard text output.
85
+ - ``Citation``: For annotations that link text output to a source document.
86
+ - ``ToolCallContentBlock``: For function calling.
87
+ - ``ReasoningContentBlock``: To capture a model's thought process.
88
+ - Multimodal data:
89
+ - ``ImageContentBlock``
90
+ - ``AudioContentBlock``
91
+ - ``VideoContentBlock``
92
+ - ``PlainTextContentBlock`` (e.g. .txt or .md files)
93
+ - ``FileContentBlock`` (e.g. PDFs, etc.)
94
+
95
+ **Example Usage**
96
+
97
+ .. code-block:: python
98
+
99
+ # Direct construction:
100
+ from langchain_core.messages.content import TextContentBlock, ImageContentBlock
101
+
102
+ multimodal_message: AIMessage(content_blocks=
103
+ [
104
+ TextContentBlock(type="text", text="What is shown in this image?"),
105
+ ImageContentBlock(
106
+ type="image",
107
+ url="https://www.langchain.com/images/brand/langchain_logo_text_w_white.png",
108
+ mime_type="image/png",
109
+ ),
110
+ ]
111
+ )
112
+
113
+ # Using factories:
114
+ from langchain_core.messages.content import create_text_block, create_image_block
115
+
116
+ multimodal_message: AIMessage(content=
117
+ [
118
+ create_text_block("What is shown in this image?"),
119
+ create_image_block(
120
+ url="https://www.langchain.com/images/brand/langchain_logo_text_w_white.png",
121
+ mime_type="image/png",
122
+ ),
123
+ ]
124
+ )
125
+
126
+ Factory functions offer benefits such as:
127
+ - Automatic ID generation (when not provided)
128
+ - No need to manually specify the ``type`` field
129
+
130
+ """
131
+
132
+ import warnings
133
+ from typing import Any, Literal, Optional, Union, get_args, get_type_hints
134
+
135
+ from typing_extensions import NotRequired, TypedDict, TypeGuard
136
+
137
+ from langchain_core.utils.utils import ensure_id
138
+
139
+
140
+ class Citation(TypedDict):
141
+ """Annotation for citing data from a document.
142
+
143
+ .. note::
144
+ ``start``/``end`` indices refer to the **response text**,
145
+ not the source text. This means that the indices are relative to the model's
146
+ response, not the original document (as specified in the ``url``).
147
+
148
+ .. note::
149
+ ``create_citation`` may also be used as a factory to create a ``Citation``.
150
+ Benefits include:
151
+
152
+ * Automatic ID generation (when not provided)
153
+ * Required arguments strictly validated at creation time
154
+
155
+ """
156
+
157
+ type: Literal["citation"]
158
+ """Type of the content block. Used for discrimination."""
159
+
160
+ id: NotRequired[str]
161
+ """Content block identifier. Either:
162
+
163
+ - Generated by the provider (e.g., OpenAI's file ID)
164
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
165
+
166
+ """
167
+
168
+ url: NotRequired[str]
169
+ """URL of the document source."""
170
+
171
+ title: NotRequired[str]
172
+ """Source document title.
173
+
174
+ For example, the page title for a web page or the title of a paper.
175
+ """
176
+
177
+ start_index: NotRequired[int]
178
+ """Start index of the **response text** (``TextContentBlock.text``)."""
179
+
180
+ end_index: NotRequired[int]
181
+ """End index of the **response text** (``TextContentBlock.text``)"""
182
+
183
+ cited_text: NotRequired[str]
184
+ """Excerpt of source text being cited."""
185
+
186
+ # NOTE: not including spans for the raw document text (such as `text_start_index`
187
+ # and `text_end_index`) as this is not currently supported by any provider. The
188
+ # thinking is that the `cited_text` should be sufficient for most use cases, and it
189
+ # is difficult to reliably extract spans from the raw document text across file
190
+ # formats or encoding schemes.
191
+
192
+ extras: NotRequired[dict[str, Any]]
193
+ """Provider-specific metadata."""
194
+
195
+
196
+ class NonStandardAnnotation(TypedDict):
197
+ """Provider-specific annotation format."""
198
+
199
+ type: Literal["non_standard_annotation"]
200
+ """Type of the content block. Used for discrimination."""
201
+
202
+ id: NotRequired[str]
203
+ """Content block identifier.
204
+
205
+ Either:
206
+ - Generated by the provider (e.g., OpenAI's file ID)
207
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
208
+
209
+ """
210
+
211
+ value: dict[str, Any]
212
+ """Provider-specific annotation data."""
213
+
214
+
215
+ Annotation = Union[Citation, NonStandardAnnotation]
216
+
217
+
218
+ class TextContentBlock(TypedDict):
219
+ """Text output from a LLM.
220
+
221
+ This typically represents the main text content of a message, such as the response
222
+ from a language model or the text of a user message.
223
+
224
+ .. note::
225
+ ``create_text_block`` may also be used as a factory to create a
226
+ ``TextContentBlock``. Benefits include:
227
+
228
+ * Automatic ID generation (when not provided)
229
+ * Required arguments strictly validated at creation time
230
+
231
+ """
232
+
233
+ type: Literal["text"]
234
+ """Type of the content block. Used for discrimination."""
235
+
236
+ id: NotRequired[str]
237
+ """Content block identifier.
238
+
239
+ Either:
240
+ - Generated by the provider (e.g., OpenAI's file ID)
241
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
242
+
243
+ """
244
+
245
+ text: str
246
+ """Block text."""
247
+
248
+ annotations: NotRequired[list[Annotation]]
249
+ """``Citation``s and other annotations."""
250
+
251
+ index: NotRequired[Union[int, str]]
252
+ """Index of block in aggregate response. Used during streaming."""
253
+
254
+ extras: NotRequired[dict[str, Any]]
255
+ """Provider-specific metadata."""
256
+
257
+
258
+ class ToolCall(TypedDict):
259
+ """Represents a request to call a tool.
260
+
261
+ Example:
262
+
263
+ .. code-block:: python
264
+
265
+ {
266
+ "name": "foo",
267
+ "args": {"a": 1},
268
+ "id": "123"
269
+ }
270
+
271
+ This represents a request to call the tool named "foo" with arguments {"a": 1}
272
+ and an identifier of "123".
273
+
274
+ .. note::
275
+ ``create_tool_call`` may also be used as a factory to create a
276
+ ``ToolCall``. Benefits include:
277
+
278
+ * Automatic ID generation (when not provided)
279
+ * Required arguments strictly validated at creation time
280
+
281
+ """
282
+
283
+ type: Literal["tool_call"]
284
+ """Used for discrimination."""
285
+
286
+ id: Optional[str]
287
+ """An identifier associated with the tool call.
288
+
289
+ An identifier is needed to associate a tool call request with a tool
290
+ call result in events when multiple concurrent tool calls are made.
291
+
292
+ """
293
+ # TODO: Consider making this NotRequired[str] in the future.
294
+
295
+ name: str
296
+ """The name of the tool to be called."""
297
+
298
+ args: dict[str, Any]
299
+ """The arguments to the tool call."""
300
+
301
+ index: NotRequired[Union[int, str]]
302
+ """Index of block in aggregate response. Used during streaming."""
303
+
304
+ extras: NotRequired[dict[str, Any]]
305
+ """Provider-specific metadata."""
306
+
307
+
308
+ class ToolCallChunk(TypedDict):
309
+ """A chunk of a tool call (e.g., as part of a stream).
310
+
311
+ When merging ``ToolCallChunks`` (e.g., via ``AIMessageChunk.__add__``),
312
+ all string attributes are concatenated. Chunks are only merged if their
313
+ values of ``index`` are equal and not ``None``.
314
+
315
+ Example:
316
+
317
+ .. code-block:: python
318
+
319
+ left_chunks = [ToolCallChunk(name="foo", args='{"a":', index=0)]
320
+ right_chunks = [ToolCallChunk(name=None, args='1}', index=0)]
321
+
322
+ (
323
+ AIMessageChunk(content="", tool_call_chunks=left_chunks)
324
+ + AIMessageChunk(content="", tool_call_chunks=right_chunks)
325
+ ).tool_call_chunks == [ToolCallChunk(name='foo', args='{"a":1}', index=0)]
326
+
327
+ """
328
+
329
+ # TODO: Consider making fields NotRequired[str] in the future.
330
+
331
+ type: Literal["tool_call_chunk"]
332
+ """Used for serialization."""
333
+
334
+ id: Optional[str]
335
+ """An identifier associated with the tool call.
336
+
337
+ An identifier is needed to associate a tool call request with a tool
338
+ call result in events when multiple concurrent tool calls are made.
339
+
340
+ """
341
+
342
+ name: Optional[str]
343
+ """The name of the tool to be called."""
344
+
345
+ args: Optional[str]
346
+ """The arguments to the tool call."""
347
+
348
+ index: NotRequired[Union[int, str]]
349
+ """The index of the tool call in a sequence."""
350
+
351
+ extras: NotRequired[dict[str, Any]]
352
+ """Provider-specific metadata."""
353
+
354
+
355
+ class InvalidToolCall(TypedDict):
356
+ """Allowance for errors made by LLM.
357
+
358
+ Here we add an ``error`` key to surface errors made during generation
359
+ (e.g., invalid JSON arguments.)
360
+
361
+ """
362
+
363
+ # TODO: Consider making fields NotRequired[str] in the future.
364
+
365
+ type: Literal["invalid_tool_call"]
366
+ """Used for discrimination."""
367
+
368
+ id: Optional[str]
369
+ """An identifier associated with the tool call.
370
+
371
+ An identifier is needed to associate a tool call request with a tool
372
+ call result in events when multiple concurrent tool calls are made.
373
+
374
+ """
375
+
376
+ name: Optional[str]
377
+ """The name of the tool to be called."""
378
+
379
+ args: Optional[str]
380
+ """The arguments to the tool call."""
381
+
382
+ error: Optional[str]
383
+ """An error message associated with the tool call."""
384
+
385
+ index: NotRequired[Union[int, str]]
386
+ """Index of block in aggregate response. Used during streaming."""
387
+
388
+ extras: NotRequired[dict[str, Any]]
389
+ """Provider-specific metadata."""
390
+
391
+
392
+ class WebSearchCall(TypedDict):
393
+ """Built-in web search tool call."""
394
+
395
+ type: Literal["web_search_call"]
396
+ """Type of the content block. Used for discrimination."""
397
+
398
+ id: NotRequired[str]
399
+ """Content block identifier.
400
+
401
+ Either:
402
+ - Generated by the provider (e.g., OpenAI's file ID)
403
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
404
+
405
+ """
406
+
407
+ query: NotRequired[str]
408
+ """The search query used in the web search tool call."""
409
+
410
+ index: NotRequired[Union[int, str]]
411
+ """Index of block in aggregate response. Used during streaming."""
412
+
413
+ extras: NotRequired[dict[str, Any]]
414
+ """Provider-specific metadata."""
415
+
416
+
417
+ class WebSearchResult(TypedDict):
418
+ """Result of a built-in web search tool call."""
419
+
420
+ type: Literal["web_search_result"]
421
+ """Type of the content block. Used for discrimination."""
422
+
423
+ id: NotRequired[str]
424
+ """Content block identifier.
425
+
426
+ Either:
427
+ - Generated by the provider (e.g., OpenAI's file ID)
428
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
429
+
430
+ """
431
+
432
+ urls: NotRequired[list[str]]
433
+ """List of URLs returned by the web search tool call."""
434
+
435
+ index: NotRequired[Union[int, str]]
436
+ """Index of block in aggregate response. Used during streaming."""
437
+
438
+ extras: NotRequired[dict[str, Any]]
439
+ """Provider-specific metadata."""
440
+
441
+
442
+ class CodeInterpreterCall(TypedDict):
443
+ """Built-in code interpreter tool call."""
444
+
445
+ type: Literal["code_interpreter_call"]
446
+ """Type of the content block. Used for discrimination."""
447
+
448
+ id: NotRequired[str]
449
+ """Content block identifier.
450
+
451
+ Either:
452
+ - Generated by the provider (e.g., OpenAI's file ID)
453
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
454
+
455
+ """
456
+
457
+ language: NotRequired[str]
458
+ """The name of the programming language used in the code interpreter tool call."""
459
+
460
+ code: NotRequired[str]
461
+ """The code to be executed by the code interpreter."""
462
+
463
+ index: NotRequired[Union[int, str]]
464
+ """Index of block in aggregate response. Used during streaming."""
465
+
466
+ extras: NotRequired[dict[str, Any]]
467
+ """Provider-specific metadata."""
468
+
469
+
470
+ class CodeInterpreterOutput(TypedDict):
471
+ """Output of a singular code interpreter tool call.
472
+
473
+ Full output of a code interpreter tool call is represented by
474
+ ``CodeInterpreterResult`` which is a list of these blocks.
475
+
476
+ """
477
+
478
+ type: Literal["code_interpreter_output"]
479
+ """Type of the content block. Used for discrimination."""
480
+
481
+ id: NotRequired[str]
482
+ """Content block identifier.
483
+
484
+ Either:
485
+ - Generated by the provider (e.g., OpenAI's file ID)
486
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
487
+
488
+ """
489
+
490
+ return_code: NotRequired[int]
491
+ """Return code of the executed code.
492
+
493
+ Example: ``0`` for success, non-zero for failure.
494
+
495
+ """
496
+
497
+ stderr: NotRequired[str]
498
+ """Standard error output of the executed code."""
499
+
500
+ stdout: NotRequired[str]
501
+ """Standard output of the executed code."""
502
+
503
+ file_ids: NotRequired[list[str]]
504
+ """List of file IDs generated by the code interpreter."""
505
+
506
+
507
+ class CodeInterpreterResult(TypedDict):
508
+ """Result of a code interpreter tool call."""
509
+
510
+ type: Literal["code_interpreter_result"]
511
+ """Type of the content block. Used for discrimination."""
512
+
513
+ id: NotRequired[str]
514
+ """Content block identifier.
515
+
516
+ Either:
517
+ - Generated by the provider (e.g., OpenAI's file ID)
518
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
519
+
520
+ """
521
+
522
+ output: list[CodeInterpreterOutput]
523
+ """List of outputs from the code interpreter tool call."""
524
+
525
+ index: NotRequired[Union[int, str]]
526
+ """Index of block in aggregate response. Used during streaming."""
527
+
528
+ extras: NotRequired[dict[str, Any]]
529
+ """Provider-specific metadata."""
530
+
531
+
532
+ class ReasoningContentBlock(TypedDict):
533
+ """Reasoning output from a LLM.
534
+
535
+ .. note::
536
+ ``create_reasoning_block`` may also be used as a factory to create a
537
+ ``ReasoningContentBlock``. Benefits include:
538
+
539
+ * Automatic ID generation (when not provided)
540
+ * Required arguments strictly validated at creation time
541
+
542
+ """
543
+
544
+ type: Literal["reasoning"]
545
+ """Type of the content block. Used for discrimination."""
546
+
547
+ id: NotRequired[str]
548
+ """Content block identifier.
549
+
550
+ Either:
551
+ - Generated by the provider (e.g., OpenAI's file ID)
552
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
553
+
554
+ """
555
+
556
+ reasoning: NotRequired[str]
557
+ """Reasoning text.
558
+
559
+ Either the thought summary or the raw reasoning text itself. This is often parsed
560
+ from ``<think>`` tags in the model's response.
561
+
562
+ """
563
+
564
+ index: NotRequired[Union[int, str]]
565
+ """Index of block in aggregate response. Used during streaming."""
566
+
567
+ extras: NotRequired[dict[str, Any]]
568
+ """Provider-specific metadata."""
569
+
570
+
571
+ # Note: `title` and `context` are fields that could be used to provide additional
572
+ # information about the file, such as a description or summary of its content.
573
+ # E.g. with Claude, you can provide a context for a file which is passed to the model.
574
+ class ImageContentBlock(TypedDict):
575
+ """Image data.
576
+
577
+ .. note::
578
+ ``create_image_block`` may also be used as a factory to create a
579
+ ``ImageContentBlock``. Benefits include:
580
+
581
+ * Automatic ID generation (when not provided)
582
+ * Required arguments strictly validated at creation time
583
+
584
+ """
585
+
586
+ type: Literal["image"]
587
+ """Type of the content block. Used for discrimination."""
588
+
589
+ id: NotRequired[str]
590
+ """Content block identifier.
591
+
592
+ Either:
593
+ - Generated by the provider (e.g., OpenAI's file ID)
594
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
595
+
596
+ """
597
+
598
+ file_id: NotRequired[str]
599
+ """ID of the image file, e.g., from a file storage system."""
600
+
601
+ mime_type: NotRequired[str]
602
+ """MIME type of the image. Required for base64.
603
+
604
+ `Examples from IANA <https://www.iana.org/assignments/media-types/media-types.xhtml#image>`__
605
+
606
+ """
607
+
608
+ index: NotRequired[Union[int, str]]
609
+ """Index of block in aggregate response. Used during streaming."""
610
+
611
+ url: NotRequired[str]
612
+ """URL of the image."""
613
+
614
+ base64: NotRequired[str]
615
+ """Data as a base64 string."""
616
+
617
+ extras: NotRequired[dict[str, Any]]
618
+ """Provider-specific metadata. This shouldn't be used for the image data itself."""
619
+
620
+
621
+ class VideoContentBlock(TypedDict):
622
+ """Video data.
623
+
624
+ .. note::
625
+ ``create_video_block`` may also be used as a factory to create a
626
+ ``VideoContentBlock``. Benefits include:
627
+
628
+ * Automatic ID generation (when not provided)
629
+ * Required arguments strictly validated at creation time
630
+
631
+ """
632
+
633
+ type: Literal["video"]
634
+ """Type of the content block. Used for discrimination."""
635
+
636
+ id: NotRequired[str]
637
+ """Content block identifier.
638
+
639
+ Either:
640
+ - Generated by the provider (e.g., OpenAI's file ID)
641
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
642
+
643
+ """
644
+
645
+ file_id: NotRequired[str]
646
+ """ID of the video file, e.g., from a file storage system."""
647
+
648
+ mime_type: NotRequired[str]
649
+ """MIME type of the video. Required for base64.
650
+
651
+ `Examples from IANA <https://www.iana.org/assignments/media-types/media-types.xhtml#video>`__
652
+
653
+ """
654
+
655
+ index: NotRequired[Union[int, str]]
656
+ """Index of block in aggregate response. Used during streaming."""
657
+
658
+ url: NotRequired[str]
659
+ """URL of the video."""
660
+
661
+ base64: NotRequired[str]
662
+ """Data as a base64 string."""
663
+
664
+ extras: NotRequired[dict[str, Any]]
665
+ """Provider-specific metadata. This shouldn't be used for the video data itself."""
666
+
667
+
668
+ class AudioContentBlock(TypedDict):
669
+ """Audio data.
670
+
671
+ .. note::
672
+ ``create_audio_block`` may also be used as a factory to create an
673
+ ``AudioContentBlock``. Benefits include:
674
+ * Automatic ID generation (when not provided)
675
+ * Required arguments strictly validated at creation time
676
+
677
+ """
678
+
679
+ type: Literal["audio"]
680
+ """Type of the content block. Used for discrimination."""
681
+
682
+ id: NotRequired[str]
683
+ """Content block identifier.
684
+
685
+ Either:
686
+ - Generated by the provider (e.g., OpenAI's file ID)
687
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
688
+
689
+ """
690
+
691
+ file_id: NotRequired[str]
692
+ """ID of the audio file, e.g., from a file storage system."""
693
+
694
+ mime_type: NotRequired[str]
695
+ """MIME type of the audio. Required for base64.
696
+
697
+ `Examples from IANA <https://www.iana.org/assignments/media-types/media-types.xhtml#audio>`__
698
+
699
+ """
700
+
701
+ index: NotRequired[Union[int, str]]
702
+ """Index of block in aggregate response. Used during streaming."""
703
+
704
+ url: NotRequired[str]
705
+ """URL of the audio."""
706
+
707
+ base64: NotRequired[str]
708
+ """Data as a base64 string."""
709
+
710
+ extras: NotRequired[dict[str, Any]]
711
+ """Provider-specific metadata. This shouldn't be used for the audio data itself."""
712
+
713
+
714
+ class PlainTextContentBlock(TypedDict):
715
+ """Plaintext data (e.g., from a document).
716
+
717
+ .. note::
718
+ Title and context are optional fields that may be passed to the model. See
719
+ Anthropic `example <https://docs.anthropic.com/en/docs/build-with-claude/citations#citable-vs-non-citable-content>`__.
720
+
721
+ .. note::
722
+ ``create_plaintext_block`` may also be used as a factory to create a
723
+ ``PlainTextContentBlock``. Benefits include:
724
+
725
+ * Automatic ID generation (when not provided)
726
+ * Required arguments strictly validated at creation time
727
+
728
+ """
729
+
730
+ type: Literal["text-plain"]
731
+ """Type of the content block. Used for discrimination."""
732
+
733
+ id: NotRequired[str]
734
+ """Content block identifier.
735
+
736
+ Either:
737
+ - Generated by the provider (e.g., OpenAI's file ID)
738
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
739
+
740
+ """
741
+
742
+ file_id: NotRequired[str]
743
+ """ID of the plaintext file, e.g., from a file storage system."""
744
+
745
+ mime_type: Literal["text/plain"]
746
+ """MIME type of the file. Required for base64."""
747
+
748
+ index: NotRequired[Union[int, str]]
749
+ """Index of block in aggregate response. Used during streaming."""
750
+
751
+ url: NotRequired[str]
752
+ """URL of the plaintext."""
753
+
754
+ base64: NotRequired[str]
755
+ """Data as a base64 string."""
756
+
757
+ text: NotRequired[str]
758
+ """Plaintext content. This is optional if the data is provided as base64."""
759
+
760
+ title: NotRequired[str]
761
+ """Title of the text data, e.g., the title of a document."""
762
+
763
+ context: NotRequired[str]
764
+ """Context for the text, e.g., a description or summary of the text's content."""
765
+
766
+ extras: NotRequired[dict[str, Any]]
767
+ """Provider-specific metadata. This shouldn't be used for the data itself."""
768
+
769
+
770
+ class FileContentBlock(TypedDict):
771
+ """File data that doesn't fit into other multimodal blocks.
772
+
773
+ This block is intended for files that are not images, audio, or plaintext. For
774
+ example, it can be used for PDFs, Word documents, etc.
775
+
776
+ If the file is an image, audio, or plaintext, you should use the corresponding
777
+ content block type (e.g., ``ImageContentBlock``, ``AudioContentBlock``,
778
+ ``PlainTextContentBlock``).
779
+
780
+ .. note::
781
+ ``create_file_block`` may also be used as a factory to create a
782
+ ``FileContentBlock``. Benefits include:
783
+
784
+ * Automatic ID generation (when not provided)
785
+ * Required arguments strictly validated at creation time
786
+
787
+ """
788
+
789
+ type: Literal["file"]
790
+ """Type of the content block. Used for discrimination."""
791
+
792
+ id: NotRequired[str]
793
+ """Content block identifier.
794
+
795
+ Either:
796
+ - Generated by the provider (e.g., OpenAI's file ID)
797
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
798
+
799
+ """
800
+
801
+ file_id: NotRequired[str]
802
+ """ID of the file, e.g., from a file storage system."""
803
+
804
+ mime_type: NotRequired[str]
805
+ """MIME type of the file. Required for base64.
806
+
807
+ `Examples from IANA <https://www.iana.org/assignments/media-types/media-types.xhtml>`__
808
+
809
+ """
810
+
811
+ index: NotRequired[Union[int, str]]
812
+ """Index of block in aggregate response. Used during streaming."""
813
+
814
+ url: NotRequired[str]
815
+ """URL of the file."""
816
+
817
+ base64: NotRequired[str]
818
+ """Data as a base64 string."""
819
+
820
+ extras: NotRequired[dict[str, Any]]
821
+ """Provider-specific metadata. This shouldn't be used for the file data itself."""
822
+
823
+
824
+ # Future modalities to consider:
825
+ # - 3D models
826
+ # - Tabular data
827
+
828
+
829
+ class NonStandardContentBlock(TypedDict):
830
+ """Provider-specific data.
831
+
832
+ This block contains data for which there is not yet a standard type.
833
+
834
+ The purpose of this block should be to simply hold a provider-specific payload.
835
+ If a provider's non-standard output includes reasoning and tool calls, it should be
836
+ the adapter's job to parse that payload and emit the corresponding standard
837
+ ``ReasoningContentBlock`` and ``ToolCallContentBlocks``.
838
+
839
+ Has no ``extras`` field, as provider-specific data should be included in the
840
+ ``value`` field.
841
+
842
+ .. note::
843
+ ``create_non_standard_block`` may also be used as a factory to create a
844
+ ``NonStandardContentBlock``. Benefits include:
845
+
846
+ * Automatic ID generation (when not provided)
847
+ * Required arguments strictly validated at creation time
848
+
849
+ """
850
+
851
+ type: Literal["non_standard"]
852
+ """Type of the content block. Used for discrimination."""
853
+
854
+ id: NotRequired[str]
855
+ """Content block identifier.
856
+
857
+ Either:
858
+ - Generated by the provider (e.g., OpenAI's file ID)
859
+ - Generated by LangChain upon creation (``UUID4`` prefixed with ``'lc_'``))
860
+
861
+ """
862
+
863
+ value: dict[str, Any]
864
+ """Provider-specific data."""
865
+
866
+ index: NotRequired[Union[int, str]]
867
+ """Index of block in aggregate response. Used during streaming."""
868
+
869
+
870
+ # --- Aliases ---
871
+ DataContentBlock = Union[
872
+ ImageContentBlock,
873
+ VideoContentBlock,
874
+ AudioContentBlock,
875
+ PlainTextContentBlock,
876
+ FileContentBlock,
877
+ ]
878
+
879
+ ToolContentBlock = Union[
880
+ ToolCall,
881
+ ToolCallChunk,
882
+ CodeInterpreterCall,
883
+ CodeInterpreterResult,
884
+ WebSearchCall,
885
+ WebSearchResult,
886
+ ]
887
+
888
+ ContentBlock = Union[
889
+ TextContentBlock,
890
+ InvalidToolCall,
891
+ ReasoningContentBlock,
892
+ NonStandardContentBlock,
893
+ DataContentBlock,
894
+ ToolContentBlock,
895
+ ]
896
+
897
+
898
+ KNOWN_BLOCK_TYPES = {
899
+ # Text output
900
+ "text",
901
+ "reasoning",
902
+ # Tools
903
+ "tool_call",
904
+ "invalid_tool_call",
905
+ "tool_call_chunk",
906
+ # Multimodal data
907
+ "image",
908
+ "audio",
909
+ "file",
910
+ "text-plain",
911
+ "video",
912
+ # Server-side tool calls
913
+ "code_interpreter_call",
914
+ "code_interpreter_result",
915
+ "web_search_call",
916
+ "web_search_result",
917
+ # Catch-all
918
+ "non_standard",
919
+ }
920
+
921
+
922
+ def _get_data_content_block_types() -> tuple[str, ...]:
923
+ """Get type literals from DataContentBlock union members dynamically."""
924
+ data_block_types = []
925
+
926
+ for block_type in get_args(DataContentBlock):
927
+ hints = get_type_hints(block_type)
928
+ if "type" in hints:
929
+ type_annotation = hints["type"]
930
+ if hasattr(type_annotation, "__args__"):
931
+ # This is a Literal type, get the literal value
932
+ literal_value = type_annotation.__args__[0]
933
+ data_block_types.append(literal_value)
934
+
935
+ return tuple(data_block_types)
936
+
937
+
938
+ def is_data_content_block(block: dict) -> bool:
939
+ """Check if the provided content block is a standard v1 data content block.
940
+
941
+ Args:
942
+ block: The content block to check.
943
+
944
+ Returns:
945
+ True if the content block is a data content block, False otherwise.
946
+
947
+ """
948
+ if block.get("type") not in _get_data_content_block_types():
949
+ return False
950
+
951
+ if any(key in block for key in ("url", "base64", "file_id", "text")):
952
+ return True
953
+
954
+ # Verify data presence based on source type
955
+ if "source_type" in block:
956
+ source_type = block["source_type"]
957
+ if (source_type == "url" and "url" in block) or (
958
+ source_type == "base64" and "data" in block
959
+ ):
960
+ return True
961
+ if (source_type == "id" and "id" in block) or (
962
+ source_type == "text" and "url" in block
963
+ ):
964
+ return True
965
+
966
+ return False
967
+
968
+
969
+ def is_tool_call_block(block: ContentBlock) -> TypeGuard[ToolCall]:
970
+ """Type guard to check if a content block is a ``ToolCall``."""
971
+ return block.get("type") == "tool_call"
972
+
973
+
974
+ def is_tool_call_chunk(block: ContentBlock) -> TypeGuard[ToolCallChunk]:
975
+ """Type guard to check if a content block is a ``ToolCallChunk``."""
976
+ return block.get("type") == "tool_call_chunk"
977
+
978
+
979
+ def is_text_block(block: ContentBlock) -> TypeGuard[TextContentBlock]:
980
+ """Type guard to check if a content block is a ``TextContentBlock``."""
981
+ return block.get("type") == "text"
982
+
983
+
984
+ def is_reasoning_block(block: ContentBlock) -> TypeGuard[ReasoningContentBlock]:
985
+ """Type guard to check if a content block is a ``ReasoningContentBlock``."""
986
+ return block.get("type") == "reasoning"
987
+
988
+
989
+ def is_invalid_tool_call_block(
990
+ block: ContentBlock,
991
+ ) -> TypeGuard[InvalidToolCall]:
992
+ """Type guard to check if a content block is an ``InvalidToolCall``."""
993
+ return block.get("type") == "invalid_tool_call"
994
+
995
+
996
+ def convert_to_openai_image_block(block: dict[str, Any]) -> dict:
997
+ """Convert ``ImageContentBlock`` to format expected by OpenAI Chat Completions."""
998
+ if "url" in block:
999
+ return {
1000
+ "type": "image_url",
1001
+ "image_url": {
1002
+ "url": block["url"],
1003
+ },
1004
+ }
1005
+ if "base64" in block or block.get("source_type") == "base64":
1006
+ if "mime_type" not in block:
1007
+ error_message = "mime_type key is required for base64 data."
1008
+ raise ValueError(error_message)
1009
+ mime_type = block["mime_type"]
1010
+ base64_data = block["data"] if "data" in block else block["base64"]
1011
+ return {
1012
+ "type": "image_url",
1013
+ "image_url": {
1014
+ "url": f"data:{mime_type};base64,{base64_data}",
1015
+ },
1016
+ }
1017
+ error_message = "Unsupported source type. Only 'url' and 'base64' are supported."
1018
+ raise ValueError(error_message)
1019
+
1020
+
1021
+ def convert_to_openai_data_block(block: dict) -> dict:
1022
+ """Format standard data content block to format expected by OpenAI."""
1023
+ if block["type"] == "image":
1024
+ formatted_block = convert_to_openai_image_block(block)
1025
+
1026
+ elif block["type"] == "file":
1027
+ if "base64" in block or block.get("source_type") == "base64":
1028
+ # Handle v0 format: {"source_type": "base64", "data": "...", ...}
1029
+ # Handle v1 format: {"base64": "...", ...}
1030
+ base64_data = block["data"] if "source_type" in block else block["base64"]
1031
+ file = {"file_data": f"data:{block['mime_type']};base64,{base64_data}"}
1032
+ if filename := block.get("filename"):
1033
+ file["filename"] = filename
1034
+ elif (extras := block.get("extras")) and ("filename" in extras):
1035
+ file["filename"] = extras["filename"]
1036
+ elif (extras := block.get("metadata")) and ("filename" in extras):
1037
+ # Backward compat
1038
+ file["filename"] = extras["filename"]
1039
+ else:
1040
+ warnings.warn(
1041
+ "OpenAI may require a filename for file inputs. Specify a filename "
1042
+ "in the content block: {'type': 'file', 'mime_type': "
1043
+ "'application/pdf', 'base64': '...', 'filename': 'my-pdf'}",
1044
+ stacklevel=1,
1045
+ )
1046
+ formatted_block = {"type": "file", "file": file}
1047
+ elif "file_id" in block or block.get("source_type") == "id":
1048
+ # Handle v0 format: {"source_type": "id", "id": "...", ...}
1049
+ # Handle v1 format: {"file_id": "...", ...}
1050
+ file_id = block["id"] if "source_type" in block else block["file_id"]
1051
+ formatted_block = {"type": "file", "file": {"file_id": file_id}}
1052
+ else:
1053
+ error_msg = "Keys base64 or file_id required for file blocks."
1054
+ raise ValueError(error_msg)
1055
+
1056
+ elif block["type"] == "audio":
1057
+ if "base64" in block or block.get("source_type") == "base64":
1058
+ # Handle v0 format: {"source_type": "base64", "data": "...", ...}
1059
+ # Handle v1 format: {"base64": "...", ...}
1060
+ base64_data = block["data"] if "source_type" in block else block["base64"]
1061
+ audio_format = block["mime_type"].split("/")[-1]
1062
+ formatted_block = {
1063
+ "type": "input_audio",
1064
+ "input_audio": {"data": base64_data, "format": audio_format},
1065
+ }
1066
+ else:
1067
+ error_msg = "Key base64 is required for audio blocks."
1068
+ raise ValueError(error_msg)
1069
+ else:
1070
+ error_msg = f"Block of type {block['type']} is not supported."
1071
+ raise ValueError(error_msg)
1072
+
1073
+ return formatted_block
1074
+
1075
+
1076
+ def create_text_block(
1077
+ text: str,
1078
+ *,
1079
+ id: Optional[str] = None,
1080
+ annotations: Optional[list[Annotation]] = None,
1081
+ index: Optional[Union[int, str]] = None,
1082
+ **kwargs: Any,
1083
+ ) -> TextContentBlock:
1084
+ """Create a ``TextContentBlock``.
1085
+
1086
+ Args:
1087
+ text: The text content of the block.
1088
+ id: Content block identifier. Generated automatically if not provided.
1089
+ annotations: ``Citation``s and other annotations for the text.
1090
+ index: Index of block in aggregate response. Used during streaming.
1091
+
1092
+ Returns:
1093
+ A properly formatted ``TextContentBlock``.
1094
+
1095
+ .. note::
1096
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1097
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1098
+
1099
+ """
1100
+ block = TextContentBlock(
1101
+ type="text",
1102
+ text=text,
1103
+ id=ensure_id(id),
1104
+ )
1105
+ if annotations is not None:
1106
+ block["annotations"] = annotations
1107
+ if index is not None:
1108
+ block["index"] = index
1109
+
1110
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1111
+ if extras:
1112
+ block["extras"] = extras
1113
+
1114
+ return block
1115
+
1116
+
1117
+ def create_image_block(
1118
+ *,
1119
+ url: Optional[str] = None,
1120
+ base64: Optional[str] = None,
1121
+ file_id: Optional[str] = None,
1122
+ mime_type: Optional[str] = None,
1123
+ id: Optional[str] = None,
1124
+ index: Optional[Union[int, str]] = None,
1125
+ **kwargs: Any,
1126
+ ) -> ImageContentBlock:
1127
+ """Create an ``ImageContentBlock``.
1128
+
1129
+ Args:
1130
+ url: URL of the image.
1131
+ base64: Base64-encoded image data.
1132
+ file_id: ID of the image file from a file storage system.
1133
+ mime_type: MIME type of the image. Required for base64 data.
1134
+ id: Content block identifier. Generated automatically if not provided.
1135
+ index: Index of block in aggregate response. Used during streaming.
1136
+
1137
+ Returns:
1138
+ A properly formatted ``ImageContentBlock``.
1139
+
1140
+ Raises:
1141
+ ValueError: If no image source is provided or if ``base64`` is used without
1142
+ ``mime_type``.
1143
+
1144
+ .. note::
1145
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1146
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1147
+
1148
+ """
1149
+ if not any([url, base64, file_id]):
1150
+ msg = "Must provide one of: url, base64, or file_id"
1151
+ raise ValueError(msg)
1152
+
1153
+ block = ImageContentBlock(type="image", id=ensure_id(id))
1154
+
1155
+ if url is not None:
1156
+ block["url"] = url
1157
+ if base64 is not None:
1158
+ block["base64"] = base64
1159
+ if file_id is not None:
1160
+ block["file_id"] = file_id
1161
+ if mime_type is not None:
1162
+ block["mime_type"] = mime_type
1163
+ if index is not None:
1164
+ block["index"] = index
1165
+
1166
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1167
+ if extras:
1168
+ block["extras"] = extras
1169
+
1170
+ return block
1171
+
1172
+
1173
+ def create_video_block(
1174
+ *,
1175
+ url: Optional[str] = None,
1176
+ base64: Optional[str] = None,
1177
+ file_id: Optional[str] = None,
1178
+ mime_type: Optional[str] = None,
1179
+ id: Optional[str] = None,
1180
+ index: Optional[Union[int, str]] = None,
1181
+ **kwargs: Any,
1182
+ ) -> VideoContentBlock:
1183
+ """Create a ``VideoContentBlock``.
1184
+
1185
+ Args:
1186
+ url: URL of the video.
1187
+ base64: Base64-encoded video data.
1188
+ file_id: ID of the video file from a file storage system.
1189
+ mime_type: MIME type of the video. Required for base64 data.
1190
+ id: Content block identifier. Generated automatically if not provided.
1191
+ index: Index of block in aggregate response. Used during streaming.
1192
+
1193
+ Returns:
1194
+ A properly formatted ``VideoContentBlock``.
1195
+
1196
+ Raises:
1197
+ ValueError: If no video source is provided or if ``base64`` is used without
1198
+ ``mime_type``.
1199
+
1200
+ .. note::
1201
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1202
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1203
+
1204
+ """
1205
+ if not any([url, base64, file_id]):
1206
+ msg = "Must provide one of: url, base64, or file_id"
1207
+ raise ValueError(msg)
1208
+
1209
+ if base64 and not mime_type:
1210
+ msg = "mime_type is required when using base64 data"
1211
+ raise ValueError(msg)
1212
+
1213
+ block = VideoContentBlock(type="video", id=ensure_id(id))
1214
+
1215
+ if url is not None:
1216
+ block["url"] = url
1217
+ if base64 is not None:
1218
+ block["base64"] = base64
1219
+ if file_id is not None:
1220
+ block["file_id"] = file_id
1221
+ if mime_type is not None:
1222
+ block["mime_type"] = mime_type
1223
+ if index is not None:
1224
+ block["index"] = index
1225
+
1226
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1227
+ if extras:
1228
+ block["extras"] = extras
1229
+
1230
+ return block
1231
+
1232
+
1233
+ def create_audio_block(
1234
+ *,
1235
+ url: Optional[str] = None,
1236
+ base64: Optional[str] = None,
1237
+ file_id: Optional[str] = None,
1238
+ mime_type: Optional[str] = None,
1239
+ id: Optional[str] = None,
1240
+ index: Optional[Union[int, str]] = None,
1241
+ **kwargs: Any,
1242
+ ) -> AudioContentBlock:
1243
+ """Create an ``AudioContentBlock``.
1244
+
1245
+ Args:
1246
+ url: URL of the audio.
1247
+ base64: Base64-encoded audio data.
1248
+ file_id: ID of the audio file from a file storage system.
1249
+ mime_type: MIME type of the audio. Required for base64 data.
1250
+ id: Content block identifier. Generated automatically if not provided.
1251
+ index: Index of block in aggregate response. Used during streaming.
1252
+
1253
+ Returns:
1254
+ A properly formatted ``AudioContentBlock``.
1255
+
1256
+ Raises:
1257
+ ValueError: If no audio source is provided or if ``base64`` is used without
1258
+ ``mime_type``.
1259
+
1260
+ .. note::
1261
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1262
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1263
+
1264
+ """
1265
+ if not any([url, base64, file_id]):
1266
+ msg = "Must provide one of: url, base64, or file_id"
1267
+ raise ValueError(msg)
1268
+
1269
+ if base64 and not mime_type:
1270
+ msg = "mime_type is required when using base64 data"
1271
+ raise ValueError(msg)
1272
+
1273
+ block = AudioContentBlock(type="audio", id=ensure_id(id))
1274
+
1275
+ if url is not None:
1276
+ block["url"] = url
1277
+ if base64 is not None:
1278
+ block["base64"] = base64
1279
+ if file_id is not None:
1280
+ block["file_id"] = file_id
1281
+ if mime_type is not None:
1282
+ block["mime_type"] = mime_type
1283
+ if index is not None:
1284
+ block["index"] = index
1285
+
1286
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1287
+ if extras:
1288
+ block["extras"] = extras
1289
+
1290
+ return block
1291
+
1292
+
1293
+ def create_file_block(
1294
+ *,
1295
+ url: Optional[str] = None,
1296
+ base64: Optional[str] = None,
1297
+ file_id: Optional[str] = None,
1298
+ mime_type: Optional[str] = None,
1299
+ id: Optional[str] = None,
1300
+ index: Optional[Union[int, str]] = None,
1301
+ **kwargs: Any,
1302
+ ) -> FileContentBlock:
1303
+ """Create a ``FileContentBlock``.
1304
+
1305
+ Args:
1306
+ url: URL of the file.
1307
+ base64: Base64-encoded file data.
1308
+ file_id: ID of the file from a file storage system.
1309
+ mime_type: MIME type of the file. Required for base64 data.
1310
+ id: Content block identifier. Generated automatically if not provided.
1311
+ index: Index of block in aggregate response. Used during streaming.
1312
+
1313
+ Returns:
1314
+ A properly formatted ``FileContentBlock``.
1315
+
1316
+ Raises:
1317
+ ValueError: If no file source is provided or if ``base64`` is used without
1318
+ ``mime_type``.
1319
+
1320
+ .. note::
1321
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1322
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1323
+
1324
+ """
1325
+ if not any([url, base64, file_id]):
1326
+ msg = "Must provide one of: url, base64, or file_id"
1327
+ raise ValueError(msg)
1328
+
1329
+ if base64 and not mime_type:
1330
+ msg = "mime_type is required when using base64 data"
1331
+ raise ValueError(msg)
1332
+
1333
+ block = FileContentBlock(type="file", id=ensure_id(id))
1334
+
1335
+ if url is not None:
1336
+ block["url"] = url
1337
+ if base64 is not None:
1338
+ block["base64"] = base64
1339
+ if file_id is not None:
1340
+ block["file_id"] = file_id
1341
+ if mime_type is not None:
1342
+ block["mime_type"] = mime_type
1343
+ if index is not None:
1344
+ block["index"] = index
1345
+
1346
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1347
+ if extras:
1348
+ block["extras"] = extras
1349
+
1350
+ return block
1351
+
1352
+
1353
+ def create_plaintext_block(
1354
+ text: Optional[str] = None,
1355
+ url: Optional[str] = None,
1356
+ base64: Optional[str] = None,
1357
+ file_id: Optional[str] = None,
1358
+ title: Optional[str] = None,
1359
+ context: Optional[str] = None,
1360
+ id: Optional[str] = None,
1361
+ index: Optional[Union[int, str]] = None,
1362
+ **kwargs: Any,
1363
+ ) -> PlainTextContentBlock:
1364
+ """Create a ``PlainTextContentBlock``.
1365
+
1366
+ Args:
1367
+ text: The plaintext content.
1368
+ url: URL of the plaintext file.
1369
+ base64: Base64-encoded plaintext data.
1370
+ file_id: ID of the plaintext file from a file storage system.
1371
+ title: Title of the text data.
1372
+ context: Context or description of the text content.
1373
+ id: Content block identifier. Generated automatically if not provided.
1374
+ index: Index of block in aggregate response. Used during streaming.
1375
+
1376
+ Returns:
1377
+ A properly formatted ``PlainTextContentBlock``.
1378
+
1379
+ .. note::
1380
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1381
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1382
+
1383
+ """
1384
+ block = PlainTextContentBlock(
1385
+ type="text-plain",
1386
+ mime_type="text/plain",
1387
+ id=ensure_id(id),
1388
+ )
1389
+
1390
+ if text is not None:
1391
+ block["text"] = text
1392
+ if url is not None:
1393
+ block["url"] = url
1394
+ if base64 is not None:
1395
+ block["base64"] = base64
1396
+ if file_id is not None:
1397
+ block["file_id"] = file_id
1398
+ if title is not None:
1399
+ block["title"] = title
1400
+ if context is not None:
1401
+ block["context"] = context
1402
+ if index is not None:
1403
+ block["index"] = index
1404
+
1405
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1406
+ if extras:
1407
+ block["extras"] = extras
1408
+
1409
+ return block
1410
+
1411
+
1412
+ def create_tool_call(
1413
+ name: str,
1414
+ args: dict[str, Any],
1415
+ *,
1416
+ id: Optional[str] = None,
1417
+ index: Optional[Union[int, str]] = None,
1418
+ **kwargs: Any,
1419
+ ) -> ToolCall:
1420
+ """Create a ``ToolCall``.
1421
+
1422
+ Args:
1423
+ name: The name of the tool to be called.
1424
+ args: The arguments to the tool call.
1425
+ id: An identifier for the tool call. Generated automatically if not provided.
1426
+ index: Index of block in aggregate response. Used during streaming.
1427
+
1428
+ Returns:
1429
+ A properly formatted ``ToolCall``.
1430
+
1431
+ .. note::
1432
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1433
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1434
+
1435
+ """
1436
+ block = ToolCall(
1437
+ type="tool_call",
1438
+ name=name,
1439
+ args=args,
1440
+ id=ensure_id(id),
1441
+ )
1442
+
1443
+ if index is not None:
1444
+ block["index"] = index
1445
+
1446
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1447
+ if extras:
1448
+ block["extras"] = extras
1449
+
1450
+ return block
1451
+
1452
+
1453
+ def create_reasoning_block(
1454
+ reasoning: Optional[str] = None,
1455
+ id: Optional[str] = None,
1456
+ index: Optional[Union[int, str]] = None,
1457
+ **kwargs: Any,
1458
+ ) -> ReasoningContentBlock:
1459
+ """Create a ``ReasoningContentBlock``.
1460
+
1461
+ Args:
1462
+ reasoning: The reasoning text or thought summary.
1463
+ id: Content block identifier. Generated automatically if not provided.
1464
+ index: Index of block in aggregate response. Used during streaming.
1465
+
1466
+ Returns:
1467
+ A properly formatted ``ReasoningContentBlock``.
1468
+
1469
+ .. note::
1470
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1471
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1472
+
1473
+ """
1474
+ block = ReasoningContentBlock(
1475
+ type="reasoning",
1476
+ reasoning=reasoning or "",
1477
+ id=ensure_id(id),
1478
+ )
1479
+
1480
+ if index is not None:
1481
+ block["index"] = index
1482
+
1483
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1484
+ if extras:
1485
+ block["extras"] = extras
1486
+
1487
+ return block
1488
+
1489
+
1490
+ def create_citation(
1491
+ *,
1492
+ url: Optional[str] = None,
1493
+ title: Optional[str] = None,
1494
+ start_index: Optional[int] = None,
1495
+ end_index: Optional[int] = None,
1496
+ cited_text: Optional[str] = None,
1497
+ id: Optional[str] = None,
1498
+ **kwargs: Any,
1499
+ ) -> Citation:
1500
+ """Create a ``Citation``.
1501
+
1502
+ Args:
1503
+ url: URL of the document source.
1504
+ title: Source document title.
1505
+ start_index: Start index in the response text where citation applies.
1506
+ end_index: End index in the response text where citation applies.
1507
+ cited_text: Excerpt of source text being cited.
1508
+ id: Content block identifier. Generated automatically if not provided.
1509
+
1510
+ Returns:
1511
+ A properly formatted ``Citation``.
1512
+
1513
+ .. note::
1514
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1515
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1516
+
1517
+ """
1518
+ block = Citation(type="citation", id=ensure_id(id))
1519
+
1520
+ if url is not None:
1521
+ block["url"] = url
1522
+ if title is not None:
1523
+ block["title"] = title
1524
+ if start_index is not None:
1525
+ block["start_index"] = start_index
1526
+ if end_index is not None:
1527
+ block["end_index"] = end_index
1528
+ if cited_text is not None:
1529
+ block["cited_text"] = cited_text
1530
+
1531
+ extras = {k: v for k, v in kwargs.items() if v is not None}
1532
+ if extras:
1533
+ block["extras"] = extras
1534
+
1535
+ return block
1536
+
1537
+
1538
+ def create_non_standard_block(
1539
+ value: dict[str, Any],
1540
+ *,
1541
+ id: Optional[str] = None,
1542
+ index: Optional[Union[int, str]] = None,
1543
+ ) -> NonStandardContentBlock:
1544
+ """Create a ``NonStandardContentBlock``.
1545
+
1546
+ Args:
1547
+ value: Provider-specific data.
1548
+ id: Content block identifier. Generated automatically if not provided.
1549
+ index: Index of block in aggregate response. Used during streaming.
1550
+
1551
+ Returns:
1552
+ A properly formatted ``NonStandardContentBlock``.
1553
+
1554
+ .. note::
1555
+ The ``id`` is generated automatically if not provided, using a UUID4 format
1556
+ prefixed with ``'lc_'`` to indicate it is a LangChain-generated ID.
1557
+
1558
+ """
1559
+ block = NonStandardContentBlock(
1560
+ type="non_standard",
1561
+ value=value,
1562
+ id=ensure_id(id),
1563
+ )
1564
+
1565
+ if index is not None:
1566
+ block["index"] = index
1567
+
1568
+ return block