Name | spof JSON |
Version |
0.1.1
JSON |
| download |
home_page | None |
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 |
upload_time | 2025-09-06 06:58:32 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.9 |
license | None |
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"
}