spof


Namespof JSON
Version 0.1.1 PyPI version JSON
download
home_pageNone
SummarySPOF (Structured Prompt Output Framework) is an open-source Python framework for designing structured, maintainable, and type-safe prompts for Large Language Models (LLMs
upload_time2025-09-06 06:58:32
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseNone
keywords spof llms ai agents openai pydantic python-dotenv prompts structured prompts
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # SPOF - Structured Prompt Output Framework

**SPOF (Structured Prompt Output Framework)** is an open-source Python framework for designing **structured, maintainable, and type-safe prompts** for Large Language Models (LLMs).

Think of it as **“Pydantic for prompts”** — SPOF lets you model prompts as composable data structures, enforce schema validation, and render them into multiple formats (JSON, XML, Markdown, plain text) without losing intent.

With SPOF, prompts become:

* **Composable** – Build reusable prompt blocks (e.g., personality, safety rules, context) and combine them like Lego pieces.
* **Type-safe** – Leverage Python’s typing and Pydantic validation to guarantee correct structures before sending to an LLM.
* **Multi-format** – Export the same structured prompt to any output format required by different providers or APIs.
* **Maintainable** – Treat prompts as code, versioned and auditable, instead of fragile strings.

SPOF provides the missing **infrastructure layer for prompt engineering at scale**, turning prompts into reliable, testable, and reusable components.


## 🚀 Quick Start

### Installation

```bash
pip install spof
```

### Basic Example

```python
from spof import InstructionBlock, Text, Items

class SimplePrompt(InstructionBlock):
    instruction: Text
    requirements: Items
    
    def __init__(self):
        super().__init__(
            instruction=Text("Analyze the following data carefully"),
            requirements=Items([
                "Be thorough and accurate",
                "Include specific examples", 
                "Provide clear conclusions"
            ])
        )

# Create and render
prompt = SimplePrompt()
print(prompt.to_xml())
```

**Output:**
```xml
<simple_prompt>
  <instruction>Analyze the following data carefully</instruction>
  <requirements>
    - Be thorough and accurate
    - Include specific examples  
    - Provide clear conclusions
  </requirements>
</simple_prompt>
```

## 📋 Core Components

### 1. InstructionBlock
The base class for all prompt components. Inherit from this to create custom blocks.

```python
class MyBlock(InstructionBlock):
    title: str
    content: str
    
    def __init__(self, title: str, content: str):
        super().__init__(title=title, content=content)
```

### 2. Text Block
For simple text content with optional custom block names.

```python
# Simple text
intro = Text("Welcome to our AI assistant")

# With custom block name
intro = Text("Welcome to our AI assistant", block_name="greeting")
```

### 3. Items Block
For lists of items, rendered as bullet points.

```python
rules = Items([
    "Be respectful and helpful",
    "Provide accurate information",
    "Ask for clarification when needed"
], block_name="guidelines")
```

### 4. ModelBlock & wrap_model()
Automatically wrap any Pydantic model to make it renderable.

```python
from pydantic import BaseModel

class UserProfile(BaseModel):
    name: str
    age: int
    role: str

user = UserProfile(name="Alice", age=30, role="Engineer")

# Wrap for rendering
user_block = wrap_model(user, block_name="user_info")
print(user_block.to_xml())
```

**Output:**
```xml
<user_info>
  <name>Alice</name>
  <age>30</age>
  <role>Engineer</role>
</user_info>
```

## 🎨 Rendering Formats

SPOF can render the same prompt structure in three formats:

### XML Format (Default)
Perfect for Claude and other models that work well with structured XML:

```python
prompt.to_xml()
# or
prompt.render(RenderFormat.XML)
```

### Markdown Format
Great for models that prefer markdown structure:

```python
prompt.to_markdown()
# or  
prompt.render(RenderFormat.MARKDOWN)
```

### JSON Format
Useful for API calls and structured data exchange:

```python
prompt.to_json()
# or
prompt.render(RenderFormat.JSON)  
```

## 🏗️ Building Complex Prompts

### Nested Structures
SPOF handles nested blocks automatically:

```python
class AnalysisPrompt(InstructionBlock):
    role: Text
    context: UserContext  # Another InstructionBlock
    instructions: InstructionSet  # Another InstructionBlock
    examples: List[ExampleCase]  # List of Pydantic models
    
    def __init__(self, user_data, examples):
        super().__init__(
            role=Text("You are a data analyst"),
            context=UserContext(user_data),
            instructions=InstructionSet(),
            examples=[wrap_model(ex) for ex in examples]
        )
```

### Working with Pydantic Models
SPOF seamlessly integrates with existing Pydantic models:

```python
from pydantic import BaseModel
from typing import List, Literal

class Message(BaseModel):
    sender: Literal["User", "Assistant"] 
    timestamp: datetime
    content: str

class ConversationContext(InstructionBlock):
    messages: List[Message]
    user_id: str
    
    def __init__(self, messages: List[Message], user_id: str):
        super().__init__(messages=messages, user_id=user_id)

# Messages are automatically wrapped in ModelBlocks when rendered
```

### Custom Block Names
Control how your blocks appear in the output:

```python
# Class-level naming
class UserInstructions(InstructionBlock):
    __block_name__ = "custom_instructions"
    
# Instance-level naming  
intro = Text("Hello", block_name="greeting")
rules = Items(["Rule 1", "Rule 2"], block_name="policies")
```

## 📱 Complete Example: Chatbot Prompt

Here's a full example showing how to build a structured chatbot prompt:

```python
from typing import List, Optional, Literal
from datetime import datetime
from pydantic import BaseModel
from spof import InstructionBlock, Text, Items

class ChatMessage(BaseModel):
    """Individual chat message with sender, timestamp, and content"""
    sender: Literal["User", "Assistant"]
    timestamp: datetime
    content: str

class PersonalityBlock(InstructionBlock):
    """Define the chatbot's personality and behavior"""
    name: str
    traits: List[str]
    communication_style: str

    def __init__(self):
        super().__init__(
            name="Alex",
            traits=[
                "Friendly and approachable",
                "Helpful and proactive", 
                "Curious and engaging",
                "Professional but warm"
            ],
            communication_style="Conversational, clear, and empathetic. Use 'I' naturally when speaking."
        )

class DirectionsBlock(InstructionBlock):
    """Clear instructions for the chatbot"""
    primary_goals: Items
    response_guidelines: Items
    safety_rules: Items

    def __init__(self):
        super().__init__(
            primary_goals=Items([
                "Listen carefully to understand user needs",
                "Provide helpful, accurate information", 
                "Ask clarifying questions when needed",
                "Maintain a friendly, professional tone"
            ], block_name="goals"),
            
            response_guidelines=Items([
                "Keep responses concise but thorough",
                "Use examples when helpful",
                "Acknowledge when you don't know something", 
                "Offer follow-up suggestions"
            ], block_name="guidelines"),
            
            safety_rules=Items([
                "Never provide harmful or dangerous advice",
                "Protect user privacy and data",
                "Be respectful of all individuals and groups",
                "Decline inappropriate requests politely"
            ], block_name="safety")
        )

class ConversationHistoryBlock(InstructionBlock):
    """Recent conversation messages for context"""
    messages: List[ChatMessage]
    total_messages: int

    def __init__(self, messages: List[ChatMessage]):
        super().__init__(
            messages=messages[-10:],  # Keep last 10 messages
            total_messages=len(messages)
        )

class ChatbotPrompt(InstructionBlock):
    """Complete chatbot prompt structure"""
    introduction: Text
    personality: PersonalityBlock
    directions: DirectionsBlock
    conversation_history: Optional[ConversationHistoryBlock]
    current_context: Text
    final_instruction: Text

    def __init__(self, user_message: str, conversation_history: Optional[List[ChatMessage]] = None):
        super().__init__(
            introduction=Text(
                "You are Alex, a helpful AI assistant. Respond naturally and helpfully to user messages.",
                block_name="role"
            ),
            
            personality=PersonalityBlock(),
            directions=DirectionsBlock(), 
            
            conversation_history=(
                ConversationHistoryBlock(conversation_history) 
                if conversation_history else None
            ),
            
            current_context=Text(f"User's current message: {user_message}", block_name="current_request"),
            
            final_instruction=Text(
                "Based on the user's message and conversation context, provide a helpful, "
                "friendly response that follows your personality and guidelines.",
                block_name="task"
            )
        )

# Usage
user_input = "Hi! Can you help me plan a weekend trip to Paris?"

chat_history = [
    ChatMessage(
        sender="User",
        timestamp=datetime(2025, 9, 6, 14, 30, 0),
        content="Hello there!"
    ),
    ChatMessage(
        sender="Assistant", 
        timestamp=datetime(2025, 9, 6, 14, 30, 5),
        content="Hi! I'm Alex, your helpful assistant. How can I help you today?"
    ),
    ChatMessage(
        sender="User",
        timestamp=datetime(2025, 9, 6, 14, 31, 0), 
        content="I'm looking for travel advice"
    ),
    ChatMessage(
        sender="Assistant",
        timestamp=datetime(2025, 9, 6, 14, 31, 3),
        content="I'd love to help with travel planning! What destination are you considering?"
    )
]

prompt = ChatbotPrompt(user_input, chat_history)
```

### Output (XML Format):

```xml
<chatbot_prompt>
  <introduction>You are Alex, a helpful AI assistant. Respond naturally and helpfully to user messages.</introduction>
  <personality_block>
    <name>Alex</name>
    <traits>
      - Friendly and approachable
      - Helpful and proactive
      - Curious and engaging
      - Professional but warm
    </traits>
    <communication_style>Conversational, clear, and empathetic. Use 'I' naturally when speaking.</communication_style>
  </personality_block>
  <directions_block>
    <goals>
      - Listen carefully to understand user needs
      - Provide helpful, accurate information
      - Ask clarifying questions when needed
      - Maintain a friendly, professional tone
    </goals>
    <guidelines>
      - Keep responses concise but thorough
      - Use examples when helpful
      - Acknowledge when you don't know something
      - Offer follow-up suggestions
    </guidelines>
    <safety>
      - Never provide harmful or dangerous advice
      - Protect user privacy and data
      - Be respectful of all individuals and groups
      - Decline inappropriate requests politely
    </safety>
  </directions_block>
  <conversation_history_block>
    <messages>
      <chat_message>
        <sender>User</sender>
        <timestamp>2025-09-06 14:30:00</timestamp>
        <content>Hello there!</content>
      </chat_message>
      <chat_message>
        <sender>Assistant</sender>
        <timestamp>2025-09-06 14:30:05</timestamp>
        <content>Hi! I'm Alex, your helpful assistant. How can I help you today?</content>
      </chat_message>
      <chat_message>
        <sender>User</sender>
        <timestamp>2025-09-06 14:31:00</timestamp>
        <content>I'm looking for travel advice</content>
      </chat_message>
      <chat_message>
        <sender>Assistant</sender>
        <timestamp>datetime(2025, 9, 6, 14, 31, 3)</timestamp>
        <content>I'd love to help with travel planning! What destination are you considering?</content>
      </chat_message>
    </messages>
    <total_messages>4</total_messages>
  </conversation_history_block>
  <current_request>User's current message: Hi! Can you help me plan a weekend trip to Paris?</current_request>
  <task>Based on the user's message and conversation context, provide a helpful, friendly response that follows your personality and guidelines.</task>
</chatbot_prompt>
```

## 🛠️ Advanced Features

### Field Exclusion
Exclude certain fields from rendering:

```python
user_block = wrap_model(user_model, exclude_fields=["password", "internal_id"])
```

### Custom Rendering Logic
Override rendering for specific block types:

```python
class CustomBlock(InstructionBlock):
    def render(self, format: RenderFormat = None, indent_level: int = 0) -> str:
        # Custom rendering logic
        if format == RenderFormat.XML:
            return "<custom>My custom XML</custom>"
        return super().render(format, indent_level)
```

### Runtime Block Names
Change block names at runtime:

```python
dynamic_block = Text("Content", block_name=f"section_{section_id}")
```

## 🔧 Best Practices

1. **Separate Structure from Content**: Define your prompt structure once, reuse everywhere
2. **Use Type Hints**: Leverage Pydantic's validation and IDE support  
3. **Compose Prompts**: Build complex prompts from simple, reusable blocks
4. **Test Different Formats**: Same structure works for XML, Markdown, and JSON
5. **Version Control Friendly**: Prompt changes are clear in diffs

## 📚 API Reference

### Core Classes

- **`InstructionBlock`**: Base class for all prompt blocks
- **`Text`**: Simple text content block
- **`Items`**: List/bullet point block  
- **`ModelBlock`**: Wrapper for Pydantic models
- **`RenderFormat`**: Enum for output formats (XML, MARKDOWN, JSON)

### Key Methods

- **`render(format, indent_level)`**: Render block in specified format
- **`to_xml()`**: Convenience method for XML output
- **`to_markdown()`**: Convenience method for Markdown output  
- **`to_json()`**: Convenience method for JSON output
- **`to_struct()`**: Convert to dictionary structure


## 🤝 Contributing

All contibutions are welcomed.


---

**SPOF** makes building structured prompts as easy as defining Pydantic models, while giving you the flexibility to render them in whatever format your LLM prefers. Build once, render everywhere! 🚀

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "spof",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "spof, llms, AI agents, openai, pydantic, python-dotenv, prompts, structured prompts",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/47/85/d7c4da51ee8011200620b1e77a5424e9e9e2fcc58804fac0bc356dbc0ae8/spof-0.1.1.tar.gz",
    "platform": null,
    "description": "# SPOF - Structured Prompt Output Framework\n\n**SPOF (Structured Prompt Output Framework)** is an open-source Python framework for designing **structured, maintainable, and type-safe prompts** for Large Language Models (LLMs).\n\nThink of it as **\u201cPydantic for prompts\u201d** \u2014 SPOF lets you model prompts as composable data structures, enforce schema validation, and render them into multiple formats (JSON, XML, Markdown, plain text) without losing intent.\n\nWith SPOF, prompts become:\n\n* **Composable** \u2013 Build reusable prompt blocks (e.g., personality, safety rules, context) and combine them like Lego pieces.\n* **Type-safe** \u2013 Leverage Python\u2019s typing and Pydantic validation to guarantee correct structures before sending to an LLM.\n* **Multi-format** \u2013 Export the same structured prompt to any output format required by different providers or APIs.\n* **Maintainable** \u2013 Treat prompts as code, versioned and auditable, instead of fragile strings.\n\nSPOF provides the missing **infrastructure layer for prompt engineering at scale**, turning prompts into reliable, testable, and reusable components.\n\n\n## \ud83d\ude80 Quick Start\n\n### Installation\n\n```bash\npip install spof\n```\n\n### Basic Example\n\n```python\nfrom spof import InstructionBlock, Text, Items\n\nclass SimplePrompt(InstructionBlock):\n    instruction: Text\n    requirements: Items\n    \n    def __init__(self):\n        super().__init__(\n            instruction=Text(\"Analyze the following data carefully\"),\n            requirements=Items([\n                \"Be thorough and accurate\",\n                \"Include specific examples\", \n                \"Provide clear conclusions\"\n            ])\n        )\n\n# Create and render\nprompt = SimplePrompt()\nprint(prompt.to_xml())\n```\n\n**Output:**\n```xml\n<simple_prompt>\n  <instruction>Analyze the following data carefully</instruction>\n  <requirements>\n    - Be thorough and accurate\n    - Include specific examples  \n    - Provide clear conclusions\n  </requirements>\n</simple_prompt>\n```\n\n## \ud83d\udccb Core Components\n\n### 1. InstructionBlock\nThe base class for all prompt components. Inherit from this to create custom blocks.\n\n```python\nclass MyBlock(InstructionBlock):\n    title: str\n    content: str\n    \n    def __init__(self, title: str, content: str):\n        super().__init__(title=title, content=content)\n```\n\n### 2. Text Block\nFor simple text content with optional custom block names.\n\n```python\n# Simple text\nintro = Text(\"Welcome to our AI assistant\")\n\n# With custom block name\nintro = Text(\"Welcome to our AI assistant\", block_name=\"greeting\")\n```\n\n### 3. Items Block\nFor lists of items, rendered as bullet points.\n\n```python\nrules = Items([\n    \"Be respectful and helpful\",\n    \"Provide accurate information\",\n    \"Ask for clarification when needed\"\n], block_name=\"guidelines\")\n```\n\n### 4. ModelBlock & wrap_model()\nAutomatically wrap any Pydantic model to make it renderable.\n\n```python\nfrom pydantic import BaseModel\n\nclass UserProfile(BaseModel):\n    name: str\n    age: int\n    role: str\n\nuser = UserProfile(name=\"Alice\", age=30, role=\"Engineer\")\n\n# Wrap for rendering\nuser_block = wrap_model(user, block_name=\"user_info\")\nprint(user_block.to_xml())\n```\n\n**Output:**\n```xml\n<user_info>\n  <name>Alice</name>\n  <age>30</age>\n  <role>Engineer</role>\n</user_info>\n```\n\n## \ud83c\udfa8 Rendering Formats\n\nSPOF can render the same prompt structure in three formats:\n\n### XML Format (Default)\nPerfect for Claude and other models that work well with structured XML:\n\n```python\nprompt.to_xml()\n# or\nprompt.render(RenderFormat.XML)\n```\n\n### Markdown Format\nGreat for models that prefer markdown structure:\n\n```python\nprompt.to_markdown()\n# or  \nprompt.render(RenderFormat.MARKDOWN)\n```\n\n### JSON Format\nUseful for API calls and structured data exchange:\n\n```python\nprompt.to_json()\n# or\nprompt.render(RenderFormat.JSON)  \n```\n\n## \ud83c\udfd7\ufe0f Building Complex Prompts\n\n### Nested Structures\nSPOF handles nested blocks automatically:\n\n```python\nclass AnalysisPrompt(InstructionBlock):\n    role: Text\n    context: UserContext  # Another InstructionBlock\n    instructions: InstructionSet  # Another InstructionBlock\n    examples: List[ExampleCase]  # List of Pydantic models\n    \n    def __init__(self, user_data, examples):\n        super().__init__(\n            role=Text(\"You are a data analyst\"),\n            context=UserContext(user_data),\n            instructions=InstructionSet(),\n            examples=[wrap_model(ex) for ex in examples]\n        )\n```\n\n### Working with Pydantic Models\nSPOF seamlessly integrates with existing Pydantic models:\n\n```python\nfrom pydantic import BaseModel\nfrom typing import List, Literal\n\nclass Message(BaseModel):\n    sender: Literal[\"User\", \"Assistant\"] \n    timestamp: datetime\n    content: str\n\nclass ConversationContext(InstructionBlock):\n    messages: List[Message]\n    user_id: str\n    \n    def __init__(self, messages: List[Message], user_id: str):\n        super().__init__(messages=messages, user_id=user_id)\n\n# Messages are automatically wrapped in ModelBlocks when rendered\n```\n\n### Custom Block Names\nControl how your blocks appear in the output:\n\n```python\n# Class-level naming\nclass UserInstructions(InstructionBlock):\n    __block_name__ = \"custom_instructions\"\n    \n# Instance-level naming  \nintro = Text(\"Hello\", block_name=\"greeting\")\nrules = Items([\"Rule 1\", \"Rule 2\"], block_name=\"policies\")\n```\n\n## \ud83d\udcf1 Complete Example: Chatbot Prompt\n\nHere's a full example showing how to build a structured chatbot prompt:\n\n```python\nfrom typing import List, Optional, Literal\nfrom datetime import datetime\nfrom pydantic import BaseModel\nfrom spof import InstructionBlock, Text, Items\n\nclass ChatMessage(BaseModel):\n    \"\"\"Individual chat message with sender, timestamp, and content\"\"\"\n    sender: Literal[\"User\", \"Assistant\"]\n    timestamp: datetime\n    content: str\n\nclass PersonalityBlock(InstructionBlock):\n    \"\"\"Define the chatbot's personality and behavior\"\"\"\n    name: str\n    traits: List[str]\n    communication_style: str\n\n    def __init__(self):\n        super().__init__(\n            name=\"Alex\",\n            traits=[\n                \"Friendly and approachable\",\n                \"Helpful and proactive\", \n                \"Curious and engaging\",\n                \"Professional but warm\"\n            ],\n            communication_style=\"Conversational, clear, and empathetic. Use 'I' naturally when speaking.\"\n        )\n\nclass DirectionsBlock(InstructionBlock):\n    \"\"\"Clear instructions for the chatbot\"\"\"\n    primary_goals: Items\n    response_guidelines: Items\n    safety_rules: Items\n\n    def __init__(self):\n        super().__init__(\n            primary_goals=Items([\n                \"Listen carefully to understand user needs\",\n                \"Provide helpful, accurate information\", \n                \"Ask clarifying questions when needed\",\n                \"Maintain a friendly, professional tone\"\n            ], block_name=\"goals\"),\n            \n            response_guidelines=Items([\n                \"Keep responses concise but thorough\",\n                \"Use examples when helpful\",\n                \"Acknowledge when you don't know something\", \n                \"Offer follow-up suggestions\"\n            ], block_name=\"guidelines\"),\n            \n            safety_rules=Items([\n                \"Never provide harmful or dangerous advice\",\n                \"Protect user privacy and data\",\n                \"Be respectful of all individuals and groups\",\n                \"Decline inappropriate requests politely\"\n            ], block_name=\"safety\")\n        )\n\nclass ConversationHistoryBlock(InstructionBlock):\n    \"\"\"Recent conversation messages for context\"\"\"\n    messages: List[ChatMessage]\n    total_messages: int\n\n    def __init__(self, messages: List[ChatMessage]):\n        super().__init__(\n            messages=messages[-10:],  # Keep last 10 messages\n            total_messages=len(messages)\n        )\n\nclass ChatbotPrompt(InstructionBlock):\n    \"\"\"Complete chatbot prompt structure\"\"\"\n    introduction: Text\n    personality: PersonalityBlock\n    directions: DirectionsBlock\n    conversation_history: Optional[ConversationHistoryBlock]\n    current_context: Text\n    final_instruction: Text\n\n    def __init__(self, user_message: str, conversation_history: Optional[List[ChatMessage]] = None):\n        super().__init__(\n            introduction=Text(\n                \"You are Alex, a helpful AI assistant. Respond naturally and helpfully to user messages.\",\n                block_name=\"role\"\n            ),\n            \n            personality=PersonalityBlock(),\n            directions=DirectionsBlock(), \n            \n            conversation_history=(\n                ConversationHistoryBlock(conversation_history) \n                if conversation_history else None\n            ),\n            \n            current_context=Text(f\"User's current message: {user_message}\", block_name=\"current_request\"),\n            \n            final_instruction=Text(\n                \"Based on the user's message and conversation context, provide a helpful, \"\n                \"friendly response that follows your personality and guidelines.\",\n                block_name=\"task\"\n            )\n        )\n\n# Usage\nuser_input = \"Hi! Can you help me plan a weekend trip to Paris?\"\n\nchat_history = [\n    ChatMessage(\n        sender=\"User\",\n        timestamp=datetime(2025, 9, 6, 14, 30, 0),\n        content=\"Hello there!\"\n    ),\n    ChatMessage(\n        sender=\"Assistant\", \n        timestamp=datetime(2025, 9, 6, 14, 30, 5),\n        content=\"Hi! I'm Alex, your helpful assistant. How can I help you today?\"\n    ),\n    ChatMessage(\n        sender=\"User\",\n        timestamp=datetime(2025, 9, 6, 14, 31, 0), \n        content=\"I'm looking for travel advice\"\n    ),\n    ChatMessage(\n        sender=\"Assistant\",\n        timestamp=datetime(2025, 9, 6, 14, 31, 3),\n        content=\"I'd love to help with travel planning! What destination are you considering?\"\n    )\n]\n\nprompt = ChatbotPrompt(user_input, chat_history)\n```\n\n### Output (XML Format):\n\n```xml\n<chatbot_prompt>\n  <introduction>You are Alex, a helpful AI assistant. Respond naturally and helpfully to user messages.</introduction>\n  <personality_block>\n    <name>Alex</name>\n    <traits>\n      - Friendly and approachable\n      - Helpful and proactive\n      - Curious and engaging\n      - Professional but warm\n    </traits>\n    <communication_style>Conversational, clear, and empathetic. Use 'I' naturally when speaking.</communication_style>\n  </personality_block>\n  <directions_block>\n    <goals>\n      - Listen carefully to understand user needs\n      - Provide helpful, accurate information\n      - Ask clarifying questions when needed\n      - Maintain a friendly, professional tone\n    </goals>\n    <guidelines>\n      - Keep responses concise but thorough\n      - Use examples when helpful\n      - Acknowledge when you don't know something\n      - Offer follow-up suggestions\n    </guidelines>\n    <safety>\n      - Never provide harmful or dangerous advice\n      - Protect user privacy and data\n      - Be respectful of all individuals and groups\n      - Decline inappropriate requests politely\n    </safety>\n  </directions_block>\n  <conversation_history_block>\n    <messages>\n      <chat_message>\n        <sender>User</sender>\n        <timestamp>2025-09-06 14:30:00</timestamp>\n        <content>Hello there!</content>\n      </chat_message>\n      <chat_message>\n        <sender>Assistant</sender>\n        <timestamp>2025-09-06 14:30:05</timestamp>\n        <content>Hi! I'm Alex, your helpful assistant. How can I help you today?</content>\n      </chat_message>\n      <chat_message>\n        <sender>User</sender>\n        <timestamp>2025-09-06 14:31:00</timestamp>\n        <content>I'm looking for travel advice</content>\n      </chat_message>\n      <chat_message>\n        <sender>Assistant</sender>\n        <timestamp>datetime(2025, 9, 6, 14, 31, 3)</timestamp>\n        <content>I'd love to help with travel planning! What destination are you considering?</content>\n      </chat_message>\n    </messages>\n    <total_messages>4</total_messages>\n  </conversation_history_block>\n  <current_request>User's current message: Hi! Can you help me plan a weekend trip to Paris?</current_request>\n  <task>Based on the user's message and conversation context, provide a helpful, friendly response that follows your personality and guidelines.</task>\n</chatbot_prompt>\n```\n\n## \ud83d\udee0\ufe0f Advanced Features\n\n### Field Exclusion\nExclude certain fields from rendering:\n\n```python\nuser_block = wrap_model(user_model, exclude_fields=[\"password\", \"internal_id\"])\n```\n\n### Custom Rendering Logic\nOverride rendering for specific block types:\n\n```python\nclass CustomBlock(InstructionBlock):\n    def render(self, format: RenderFormat = None, indent_level: int = 0) -> str:\n        # Custom rendering logic\n        if format == RenderFormat.XML:\n            return \"<custom>My custom XML</custom>\"\n        return super().render(format, indent_level)\n```\n\n### Runtime Block Names\nChange block names at runtime:\n\n```python\ndynamic_block = Text(\"Content\", block_name=f\"section_{section_id}\")\n```\n\n## \ud83d\udd27 Best Practices\n\n1. **Separate Structure from Content**: Define your prompt structure once, reuse everywhere\n2. **Use Type Hints**: Leverage Pydantic's validation and IDE support  \n3. **Compose Prompts**: Build complex prompts from simple, reusable blocks\n4. **Test Different Formats**: Same structure works for XML, Markdown, and JSON\n5. **Version Control Friendly**: Prompt changes are clear in diffs\n\n## \ud83d\udcda API Reference\n\n### Core Classes\n\n- **`InstructionBlock`**: Base class for all prompt blocks\n- **`Text`**: Simple text content block\n- **`Items`**: List/bullet point block  \n- **`ModelBlock`**: Wrapper for Pydantic models\n- **`RenderFormat`**: Enum for output formats (XML, MARKDOWN, JSON)\n\n### Key Methods\n\n- **`render(format, indent_level)`**: Render block in specified format\n- **`to_xml()`**: Convenience method for XML output\n- **`to_markdown()`**: Convenience method for Markdown output  \n- **`to_json()`**: Convenience method for JSON output\n- **`to_struct()`**: Convert to dictionary structure\n\n\n## \ud83e\udd1d Contributing\n\nAll contibutions are welcomed.\n\n\n---\n\n**SPOF** makes building structured prompts as easy as defining Pydantic models, while giving you the flexibility to render them in whatever format your LLM prefers. Build once, render everywhere! \ud83d\ude80\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "SPOF (Structured Prompt Output Framework) is an open-source Python framework for designing structured, maintainable, and type-safe prompts for Large Language Models (LLMs",
    "version": "0.1.1",
    "project_urls": null,
    "split_keywords": [
        "spof",
        " llms",
        " ai agents",
        " openai",
        " pydantic",
        " python-dotenv",
        " prompts",
        " structured prompts"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "83ff54d55f52e919e5d6fa45f58ceeadad835182316c619097f789a7a7643bda",
                "md5": "23e513dda771850bb9809573c7a3b695",
                "sha256": "9de7e5585edcd947e6f413c601344e9792c10fda60efe73ab95d70b7f74e7f8c"
            },
            "downloads": -1,
            "filename": "spof-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "23e513dda771850bb9809573c7a3b695",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 10559,
            "upload_time": "2025-09-06T06:58:31",
            "upload_time_iso_8601": "2025-09-06T06:58:31.163866Z",
            "url": "https://files.pythonhosted.org/packages/83/ff/54d55f52e919e5d6fa45f58ceeadad835182316c619097f789a7a7643bda/spof-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "4785d7c4da51ee8011200620b1e77a5424e9e9e2fcc58804fac0bc356dbc0ae8",
                "md5": "7c98c2bb6ff7e4a267b5617ede29e8a3",
                "sha256": "72b44f766167cf536b170f82dd7506761f0a8ca7624f93508f9da469b899fedf"
            },
            "downloads": -1,
            "filename": "spof-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "7c98c2bb6ff7e4a267b5617ede29e8a3",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 14289,
            "upload_time": "2025-09-06T06:58:32",
            "upload_time_iso_8601": "2025-09-06T06:58:32.424715Z",
            "url": "https://files.pythonhosted.org/packages/47/85/d7c4da51ee8011200620b1e77a5424e9e9e2fcc58804fac0bc356dbc0ae8/spof-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-06 06:58:32",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "spof"
}
        
Elapsed time: 1.73502s