Skip to content

pydantic_ai.messages

The structure of ModelMessage can be shown as a graph:

graph RL
    SystemPromptPart(SystemPromptPart) --- ModelRequestPart
    UserPromptPart(UserPromptPart) --- ModelRequestPart
    ToolReturnPart(ToolReturnPart) --- ModelRequestPart
    RetryPromptPart(RetryPromptPart) --- ModelRequestPart
    TextPart(TextPart) --- ModelResponsePart
    ToolCallPart(ToolCallPart) --- ModelResponsePart
    ModelRequestPart("ModelRequestPart<br>(Union)") --- ModelRequest
    ModelRequest("ModelRequest(parts=list[...])") --- ModelMessage
    ModelResponsePart("ModelResponsePart<br>(Union)") --- ModelResponse
    ModelResponse("ModelResponse(parts=list[...])") --- ModelMessage("ModelMessage<br>(Union)")

SystemPromptPart dataclass

A system prompt, generally written by the application developer.

This gives the model context and guidance on how to respond.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
14
15
16
17
18
19
20
21
22
23
24
25
@dataclass
class SystemPromptPart:
    """A system prompt, generally written by the application developer.

    This gives the model context and guidance on how to respond.
    """

    content: str
    """The content of the prompt."""

    part_kind: Literal['system-prompt'] = 'system-prompt'
    """Part type identifier, this is available on all parts as a discriminator."""

content instance-attribute

content: str

The content of the prompt.

part_kind class-attribute instance-attribute

part_kind: Literal['system-prompt'] = 'system-prompt'

Part type identifier, this is available on all parts as a discriminator.

UserPromptPart dataclass

A user prompt, generally written by the end user.

Content comes from the user_prompt parameter of Agent.run, Agent.run_sync, and Agent.run_stream.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@dataclass
class UserPromptPart:
    """A user prompt, generally written by the end user.

    Content comes from the `user_prompt` parameter of [`Agent.run`][pydantic_ai.Agent.run],
    [`Agent.run_sync`][pydantic_ai.Agent.run_sync], and [`Agent.run_stream`][pydantic_ai.Agent.run_stream].
    """

    content: str
    """The content of the prompt."""

    timestamp: datetime = field(default_factory=_now_utc)
    """The timestamp of the prompt."""

    part_kind: Literal['user-prompt'] = 'user-prompt'
    """Part type identifier, this is available on all parts as a discriminator."""

content instance-attribute

content: str

The content of the prompt.

timestamp class-attribute instance-attribute

timestamp: datetime = field(default_factory=now_utc)

The timestamp of the prompt.

part_kind class-attribute instance-attribute

part_kind: Literal['user-prompt'] = 'user-prompt'

Part type identifier, this is available on all parts as a discriminator.

ToolReturnPart dataclass

A tool return message, this encodes the result of running a tool.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
@dataclass
class ToolReturnPart:
    """A tool return message, this encodes the result of running a tool."""

    tool_name: str
    """The name of the "tool" was called."""

    content: Any
    """The return value."""

    tool_call_id: str | None = None
    """Optional tool call identifier, this is used by some models including OpenAI."""

    timestamp: datetime = field(default_factory=_now_utc)
    """The timestamp, when the tool returned."""

    part_kind: Literal['tool-return'] = 'tool-return'
    """Part type identifier, this is available on all parts as a discriminator."""

    def model_response_str(self) -> str:
        if isinstance(self.content, str):
            return self.content
        else:
            return tool_return_ta.dump_json(self.content).decode()

    def model_response_object(self) -> dict[str, Any]:
        # gemini supports JSON dict return values, but no other JSON types, hence we wrap anything else in a dict
        if isinstance(self.content, dict):
            return tool_return_ta.dump_python(self.content, mode='json')  # pyright: ignore[reportUnknownMemberType]
        else:
            return {'return_value': tool_return_ta.dump_python(self.content, mode='json')}

tool_name instance-attribute

tool_name: str

The name of the "tool" was called.

content instance-attribute

content: Any

The return value.

tool_call_id class-attribute instance-attribute

tool_call_id: str | None = None

Optional tool call identifier, this is used by some models including OpenAI.

timestamp class-attribute instance-attribute

timestamp: datetime = field(default_factory=now_utc)

The timestamp, when the tool returned.

part_kind class-attribute instance-attribute

part_kind: Literal['tool-return'] = 'tool-return'

Part type identifier, this is available on all parts as a discriminator.

RetryPromptPart dataclass

A message back to a model asking it to try again.

This can be sent for a number of reasons:

  • Pydantic validation of tool arguments failed, here content is derived from a Pydantic ValidationError
  • a tool raised a ModelRetry exception
  • no tool was found for the tool name
  • the model returned plain text when a structured response was expected
  • Pydantic validation of a structured response failed, here content is derived from a Pydantic ValidationError
  • a result validator raised a ModelRetry exception
Source code in pydantic_ai_slim/pydantic_ai/messages.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
@dataclass
class RetryPromptPart:
    """A message back to a model asking it to try again.

    This can be sent for a number of reasons:

    * Pydantic validation of tool arguments failed, here content is derived from a Pydantic
      [`ValidationError`][pydantic_core.ValidationError]
    * a tool raised a [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] exception
    * no tool was found for the tool name
    * the model returned plain text when a structured response was expected
    * Pydantic validation of a structured response failed, here content is derived from a Pydantic
      [`ValidationError`][pydantic_core.ValidationError]
    * a result validator raised a [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] exception
    """

    content: list[pydantic_core.ErrorDetails] | str
    """Details of why and how the model should retry.

    If the retry was triggered by a [`ValidationError`][pydantic_core.ValidationError], this will be a list of
    error details.
    """

    tool_name: str | None = None
    """The name of the tool that was called, if any."""

    tool_call_id: str | None = None
    """Optional tool call identifier, this is used by some models including OpenAI."""

    timestamp: datetime = field(default_factory=_now_utc)
    """The timestamp, when the retry was triggered."""

    part_kind: Literal['retry-prompt'] = 'retry-prompt'
    """Part type identifier, this is available on all parts as a discriminator."""

    def model_response(self) -> str:
        if isinstance(self.content, str):
            description = self.content
        else:
            json_errors = error_details_ta.dump_json(self.content, exclude={'__all__': {'ctx'}}, indent=2)
            description = f'{len(self.content)} validation errors: {json_errors.decode()}'
        return f'{description}\n\nFix the errors and try again.'

content instance-attribute

content: list[ErrorDetails] | str

Details of why and how the model should retry.

If the retry was triggered by a ValidationError, this will be a list of error details.

tool_name class-attribute instance-attribute

tool_name: str | None = None

The name of the tool that was called, if any.

tool_call_id class-attribute instance-attribute

tool_call_id: str | None = None

Optional tool call identifier, this is used by some models including OpenAI.

timestamp class-attribute instance-attribute

timestamp: datetime = field(default_factory=now_utc)

The timestamp, when the retry was triggered.

part_kind class-attribute instance-attribute

part_kind: Literal['retry-prompt'] = 'retry-prompt'

Part type identifier, this is available on all parts as a discriminator.

ModelRequestPart module-attribute

A message part sent by PydanticAI to a model.

ModelRequest dataclass

A request generated by PydanticAI and sent to a model, e.g. a message from the PydanticAI app to the model.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
135
136
137
138
139
140
141
142
143
@dataclass
class ModelRequest:
    """A request generated by PydanticAI and sent to a model, e.g. a message from the PydanticAI app to the model."""

    parts: list[ModelRequestPart]
    """The parts of the user message."""

    kind: Literal['request'] = 'request'
    """Message type identifier, this is available on all parts as a discriminator."""

parts instance-attribute

The parts of the user message.

kind class-attribute instance-attribute

kind: Literal['request'] = 'request'

Message type identifier, this is available on all parts as a discriminator.

TextPart dataclass

A plain text response from a model.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
146
147
148
149
150
151
152
153
154
@dataclass
class TextPart:
    """A plain text response from a model."""

    content: str
    """The text content of the response."""

    part_kind: Literal['text'] = 'text'
    """Part type identifier, this is available on all parts as a discriminator."""

content instance-attribute

content: str

The text content of the response.

part_kind class-attribute instance-attribute

part_kind: Literal['text'] = 'text'

Part type identifier, this is available on all parts as a discriminator.

ArgsJson dataclass

Tool arguments as a JSON string.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
157
158
159
160
161
162
@dataclass
class ArgsJson:
    """Tool arguments as a JSON string."""

    args_json: str
    """A JSON string of arguments."""

args_json instance-attribute

args_json: str

A JSON string of arguments.

ArgsDict dataclass

Tool arguments as a Python dictionary.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
165
166
167
168
169
170
@dataclass
class ArgsDict:
    """Tool arguments as a Python dictionary."""

    args_dict: dict[str, Any]
    """A python dictionary of arguments."""

args_dict instance-attribute

args_dict: dict[str, Any]

A python dictionary of arguments.

ToolCallPart dataclass

A tool call from a model.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
@dataclass
class ToolCallPart:
    """A tool call from a model."""

    tool_name: str
    """The name of the tool to call."""

    args: ArgsJson | ArgsDict
    """The arguments to pass to the tool.

    Either as JSON or a Python dictionary depending on how data was returned.
    """

    tool_call_id: str | None = None
    """Optional tool call identifier, this is used by some models including OpenAI."""

    part_kind: Literal['tool-call'] = 'tool-call'
    """Part type identifier, this is available on all parts as a discriminator."""

    @classmethod
    def from_json(cls, tool_name: str, args_json: str, tool_call_id: str | None = None) -> Self:
        return cls(tool_name, ArgsJson(args_json), tool_call_id)

    @classmethod
    def from_dict(cls, tool_name: str, args_dict: dict[str, Any], tool_call_id: str | None = None) -> Self:
        return cls(tool_name, ArgsDict(args_dict), tool_call_id)

    def has_content(self) -> bool:
        if isinstance(self.args, ArgsDict):
            return any(self.args.args_dict.values())
        else:
            return bool(self.args.args_json)

tool_name instance-attribute

tool_name: str

The name of the tool to call.

args instance-attribute

The arguments to pass to the tool.

Either as JSON or a Python dictionary depending on how data was returned.

tool_call_id class-attribute instance-attribute

tool_call_id: str | None = None

Optional tool call identifier, this is used by some models including OpenAI.

part_kind class-attribute instance-attribute

part_kind: Literal['tool-call'] = 'tool-call'

Part type identifier, this is available on all parts as a discriminator.

ModelResponsePart module-attribute

ModelResponsePart = Annotated[
    Union[TextPart, ToolCallPart],
    Discriminator("part_kind"),
]

A message part returned by a model.

ModelResponse dataclass

A response from a model, e.g. a message from the model to the PydanticAI app.

Source code in pydantic_ai_slim/pydantic_ai/messages.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
@dataclass
class ModelResponse:
    """A response from a model, e.g. a message from the model to the PydanticAI app."""

    parts: list[ModelResponsePart]
    """The parts of the model message."""

    timestamp: datetime = field(default_factory=_now_utc)
    """The timestamp of the response.

    If the model provides a timestamp in the response (as OpenAI does) that will be used.
    """

    kind: Literal['response'] = 'response'
    """Message type identifier, this is available on all parts as a discriminator."""

    @classmethod
    def from_text(cls, content: str, timestamp: datetime | None = None) -> Self:
        return cls([TextPart(content)], timestamp=timestamp or _now_utc())

    @classmethod
    def from_tool_call(cls, tool_call: ToolCallPart) -> Self:
        return cls([tool_call])

parts instance-attribute

The parts of the model message.

timestamp class-attribute instance-attribute

timestamp: datetime = field(default_factory=now_utc)

The timestamp of the response.

If the model provides a timestamp in the response (as OpenAI does) that will be used.

kind class-attribute instance-attribute

kind: Literal['response'] = 'response'

Message type identifier, this is available on all parts as a discriminator.

ModelMessage module-attribute

ModelMessage = Union[ModelRequest, ModelResponse]

Any message send to or returned by a model.

ModelMessagesTypeAdapter module-attribute

ModelMessagesTypeAdapter = TypeAdapter(
    list[Annotated[ModelMessage, Discriminator("kind")]],
    config=ConfigDict(defer_build=True),
)

Pydantic TypeAdapter for (de)serializing messages.