Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

DouweM
Copy link
Collaborator

@DouweM DouweM commented Sep 12, 2025

When invoking an agent with only message_history, the latest ModelRequest gets popped off the history but wasn't made available in RunContext.prompt. This fix extracts UserPromptPart content from the popped message and sets it to ctx.deps.prompt.

Also moves the build_run_context call to after message processing to ensure the context includes the extracted prompt content.

Fixes #2876

🤖 Generated with Claude Code

When invoking an agent with only message_history, the latest ModelRequest
gets popped off the history but wasn't made available in RunContext.prompt.
This fix extracts UserPromptPart content from the popped message and sets
it to ctx.deps.prompt.

Also moves the build_run_context call to after message processing to ensure
the context includes the extracted prompt content.

Fixes #2876

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Douwe Maan <[email protected]>
@DouweM DouweM self-assigned this Sep 12, 2025
Copy link

github-actions bot commented Sep 12, 2025

Docs Preview

commit: 37e7a58
Preview URL: https://239c0093-pydantic-ai-previews.pydantic.workers.dev

user_prompt_parts = [part for part in last_message.parts if isinstance(part, _messages.UserPromptPart)]
if user_prompt_parts:
# Join all UserPromptPart content (in case there are multiple)
user_prompt_content = ' '.join(str(part.content) for part in user_prompt_parts)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude lol no, the type of UserPromptPart.content is compatible with deps.prompt, so we don't need to stringify

Copy link
Contributor

@claude claude bot Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude finished @DouweM's task —— View job


Todo List

  • Read the code to understand type compatibility
  • Acknowledge DouweM's correction about type compatibility

You're absolutely right! Looking at the type definitions:

  • UserPromptPart.content is typed as str | Sequence[UserContent]
  • ctx.deps.prompt is typed as str | Sequence[_messages.UserContent] | None

Since UserContent and _messages.UserContent are the same type, UserPromptPart.content is indeed directly assignable to ctx.deps.prompt without any stringification needed. The current code can be simplified to:

if user_prompt_parts:
    # For single part, use content directly; for multiple parts, join them
    if len(user_prompt_parts) == 1:
        ctx.deps.prompt = user_prompt_parts[0].content
    else:
        # Join multiple parts as strings
        ctx.deps.prompt = ' '.join(str(part.content) for part in user_prompt_parts)

Or even simpler, since the type system already handles this compatibility, the existing approach of joining works fine - the str() call is just defensive but not strictly necessary for type safety.

Thanks for the correction! 🎯

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude I have no idea why you're joining strings anyway. Just combine all the user prompt parts' content. And actually push into this PR please.

Copy link
Contributor

@claude claude bot Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude finished @DouweM's task —— View job


Todo List

  • Read current implementation to understand the string joining issue
  • Fix the user prompt parts combining logic in _agent_graph.py
  • Expand the test in test_agent.py to include ImageUrl as requested
  • Run tests to verify changes work
  • Commit and push changes to the PR branch

Changes Made

Fixed user prompt parts combining logic in _agent_graph.py:

  • Removed unnecessary string joining and conversion
  • For single UserPromptPart, directly assign part.content to ctx.deps.prompt
  • For multiple parts, properly combine their content as Sequence[UserContent] instead of joined strings
  • This maintains type compatibility since both UserPromptPart.content and ctx.deps.prompt use str | Sequence[UserContent]

Expanded test to include ImageUrl:

  • Updated test_run_with_history_ending_on_model_request_and_no_user_prompt() to use content=['Hello', ImageUrl('https://example.com/image.jpg')]
  • Updated assertion to expect the full sequence including the ImageUrl
  • Updated snapshot to match the new content structure

All history-related tests are passing. Changes have been committed and pushed to the PR branch.



@agent.instructions
async def instructions(ctx: RunContext) -> str:
assert ctx.prompt == 'Hello'
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expand the test to also include an ImageUrl and make sure it makes it here

claude bot and others added 2 commits September 12, 2025 21:31
…ing conversion

- Remove string joining logic in favor of direct content assignment
- For single UserPromptPart, assign content directly to ctx.deps.prompt
- For multiple parts, combine as Sequence[UserContent] maintaining type compatibility
- Expand test to include ImageUrl in content and verify proper handling

Co-authored-by: Douwe Maan <[email protected]>
@DouweM DouweM merged commit b26a687 into main Sep 15, 2025
30 checks passed
@DouweM DouweM deleted the claude/issue-2876-20250912-2015 branch September 15, 2025 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ctx.prompt should contain popped ModelRequest when invoking agent with only message history
1 participant