Skip to content

[FEATURE] Expose system_prompt_content as a public property on Agent #1996

@lizradway

Description

@lizradway

Problem Statement

Agent internally maintains two representations of the system prompt:

  • self._system_prompt (string) — exposed publicly via the system_prompt property
  • self._system_prompt_content (list of SystemContentBlock) — private, no public accessor

The content block representation is the richer, more complete one — it preserves cache control markers and non-text content blocks. The string is a lossy flattened projection kept for backwards compatibility.

Despite being private, _system_prompt_content is already accessed from multiple places outside agent.py:

  • event_loop.py passes agent._system_prompt_content to stream_messages()
  • Model tests (test_bedrock.py, test_openai.py, test_litellm.py) test system_prompt_content formatting
  • test_agent_skills.py directly reads/writes agent._system_prompt_content ~12 times to set up test state
  • PR feat(telemetry): emit system prompt on chat spans per GenAI semconv #1818 proposes passing agent._system_prompt_content to telemetry spans

This is a leaky abstraction — the private attribute is effectively part of the public contract already.

Proposed Solution

Add a public system_prompt_content property:

@property
def system_prompt_content(self) -> list[SystemContentBlock] | None:
    """Get the system prompt as content blocks.

    Returns the full content block representation, preserving cache control
    and non-text content. Returns None if no system prompt is set.
    """
    return self._system_prompt_content

Then update internal consumers (event_loop.py, tests) to use the public property instead of the private attribute.

Use Case

The current system_prompt property returns str | None, which was the original API. When content block support was added (for features like prompt caching), _system_prompt_content was introduced as an internal detail. But the string-only public API is now insufficient for consumers that need the full representation — telemetry (#1818), the event loop, and model implementations all need the content blocks.

Alternatives Solutions

No response

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions