Skip to content

Commit 468e60a

Browse files
Pavanmanikanta98pavanDouweM
authored
feat: enforce message history starts with user message (#3440)
Co-authored-by: pavan <[email protected]> Co-authored-by: Douwe Maan <[email protected]>
1 parent 1b576dd commit 468e60a

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

pydantic_ai_slim/pydantic_ai/_agent_graph.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ async def run( # noqa: C901
216216
ctx.state.message_history = messages
217217
ctx.deps.new_message_index = len(messages)
218218

219+
# Validate that message history starts with a user message
220+
if messages and isinstance(messages[0], _messages.ModelResponse):
221+
raise exceptions.UserError(
222+
'Message history cannot start with a `ModelResponse`. Conversations must begin with a user message.'
223+
)
224+
219225
if self.deferred_tool_results is not None:
220226
return await self._handle_deferred_tool_results(self.deferred_tool_results, messages, ctx)
221227

tests/models/test_outlines.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ def test_input_format(transformers_multimodal_model: OutlinesModel, binary_image
573573

574574
# unsupported: tool calls
575575
tool_call_message_history: list[ModelMessage] = [
576+
ModelRequest(parts=[UserPromptPart(content='some user prompt')]),
576577
ModelResponse(parts=[ToolCallPart(tool_call_id='1', tool_name='get_location')]),
577578
ModelRequest(parts=[ToolReturnPart(tool_name='get_location', content='London', tool_call_id='1')]),
578579
]
@@ -588,7 +589,8 @@ def test_input_format(transformers_multimodal_model: OutlinesModel, binary_image
588589

589590
# unsupported: non-image file parts
590591
file_part_message_history: list[ModelMessage] = [
591-
ModelResponse(parts=[FilePart(content=BinaryContent(data=b'test', media_type='text/plain'))])
592+
ModelRequest(parts=[UserPromptPart(content='some user prompt')]),
593+
ModelResponse(parts=[FilePart(content=BinaryContent(data=b'test', media_type='text/plain'))]),
592594
]
593595
with pytest.raises(
594596
UserError, match='File parts other than `BinaryImage` are not supported for Outlines models yet.'

tests/test_agent.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6132,3 +6132,19 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse:
61326132
]
61336133
)
61346134
assert run.all_messages_json().startswith(b'[{"parts":[{"content":"Hello",')
6135+
6136+
6137+
def test_message_history_cannot_start_with_model_response():
6138+
"""Test that message history starting with ModelResponse raises UserError."""
6139+
6140+
agent = Agent('test')
6141+
6142+
invalid_history = [
6143+
ModelResponse(parts=[TextPart(content='ai response')]),
6144+
]
6145+
6146+
with pytest.raises(
6147+
UserError,
6148+
match='Message history cannot start with a `ModelResponse`.',
6149+
):
6150+
agent.run_sync('hello', message_history=invalid_history)

0 commit comments

Comments
 (0)