[FEAT][Prompt]

pull/595/head
Your Name 3 months ago
parent 29e03cff24
commit 2f82a92768

@ -142,6 +142,9 @@ nav:
- Swarms CLI: "swarms/cli/main.md"
# - Swarms + Docker:
- Swarms Framework Architecture: "swarms/concept/framework_architecture.md"
- Prelimary:
- 80/20 Rule For Agents: "swarms/prompting/8020.md"
- Managing Prompts in Production: "swarms/prompting/main.md"
- Agents:
# - Overview: "swarms/structs/index.md"
# - Build Custom Agents: "swarms/structs/diy_your_own_agent.md"

@ -0,0 +1,314 @@
# Managing Prompts in Production
The `Prompt` class provides a comprehensive solution for managing prompts, including advanced features like version control, autosaving, and logging. This guide will walk you through how to effectively use this class in a production environment, focusing on its core features, use cases, and best practices.
## Table of Contents
1. **Getting Started**
- Installation and Setup
- Creating a New Prompt
2. **Managing Prompt Content**
- Editing Prompts
- Retrieving Prompt Content
3. **Version Control**
- Tracking Edits and History
- Rolling Back to Previous Versions
4. **Autosaving Prompts**
- Enabling and Configuring Autosave
- Manually Triggering Autosave
5. **Logging and Telemetry**
6. **Handling Errors**
7. **Extending the Prompt Class**
- Customizing the Save Mechanism
- Integrating with Databases
---
## 1. Getting Started
### Installation and Setup
Before diving into how to use the `Prompt` class, ensure that you have the required dependencies installed:
```bash
pip3 install -U swarms
```
### Creating a New Prompt
To create a new instance of a `Prompt`, simply initialize it with the required attributes such as `content`:
```python
from swarms import Prompt
prompt = Prompt(
content="This is my first prompt!",
name="My First Prompt",
description="A simple example prompt."
)
print(prompt)
```
This creates a new prompt with the current timestamp and a unique identifier.
---
## 2. Managing Prompt Content
### Editing Prompts
Once you have initialized a prompt, you can edit its content using the `edit_prompt` method. Each time the content is edited, a new version is stored in the `edit_history`, and the `last_modified_at` timestamp is updated.
```python
new_content = "This is an updated version of my prompt."
prompt.edit_prompt(new_content)
```
**Note**: If the new content is identical to the current content, an error will be raised to prevent unnecessary edits:
```python
try:
prompt.edit_prompt("This is my first prompt!") # Same as initial content
except ValueError as e:
print(e) # Output: New content must be different from the current content.
```
### Retrieving Prompt Content
You can retrieve the current prompt content using the `get_prompt` method:
```python
current_content = prompt.get_prompt()
print(current_content) # Output: This is an updated version of my prompt.
```
This method also logs telemetry data, which includes both system information and prompt metadata.
---
## 3. Version Control
### Tracking Edits and History
The `Prompt` class automatically tracks every change made to the prompt. This is stored in the `edit_history` attribute as a list of previous versions.
```python
print(prompt.edit_history) # Output: ['This is my first prompt!', 'This is an updated version of my prompt.']
```
The number of edits is also tracked using the `edit_count` attribute:
```python
print(prompt.edit_count) # Output: 2
```
### Rolling Back to Previous Versions
If you want to revert a prompt to a previous version, you can use the `rollback` method, passing the version index you want to revert to:
```python
prompt.rollback(0)
print(prompt.get_prompt()) # Output: This is my first prompt!
```
The rollback operation is thread-safe, and any rollback also triggers a telemetry log.
---
## 4. Autosaving Prompts
### Enabling and Configuring Autosave
To automatically save prompts to storage after every change, you can enable the `autosave` feature when initializing the prompt:
```python
prompt = Prompt(
content="This is my first prompt!",
autosave=True,
autosave_folder="my_prompts" # Specify the folder within WORKSPACE_DIR
)
```
This will ensure that every edit or rollback action triggers an autosave to the specified folder.
### Manually Triggering Autosave
You can also manually trigger an autosave by calling the `_autosave` method (which is a private method typically used internally):
```python
prompt._autosave() # Manually triggers autosaving
```
Autosaves are stored as JSON files in the folder specified by `autosave_folder` under the workspace directory (`WORKSPACE_DIR` environment variable).
---
## 5. Logging and Telemetry
The `Prompt` class integrates with the `loguru` logging library to provide detailed logs for every major action, such as editing, rolling back, and saving. The `log_telemetry` method captures and logs system data, including prompt metadata, for each operation.
Here's an example of a log when editing a prompt:
```bash
2024-10-10 10:12:34.567 | INFO | Editing prompt a7b8f9. Current content: 'This is my first prompt!'
2024-10-10 10:12:34.789 | DEBUG | Prompt a7b8f9 updated. Edit count: 1. New content: 'This is an updated version of my prompt.'
```
You can extend logging by integrating the `log_telemetry` method with your own telemetry systems or databases:
```python
prompt.log_telemetry()
```
---
## 6. Handling Errors
Error handling in the `Prompt` class is robust and prevents common mistakes, such as editing with identical content or rolling back to an invalid version. Here's a common scenario:
### Editing with Identical Content
```python
try:
prompt.edit_prompt("This is an updated version of my prompt.")
except ValueError as e:
print(e) # Output: New content must be different from the current content.
```
### Invalid Rollback Version
```python
try:
prompt.rollback(10) # Invalid version index
except IndexError as e:
print(e) # Output: Invalid version number for rollback.
```
Always ensure that version numbers passed to `rollback` are within the valid range of existing versions.
---
## 7. Extending the Prompt Class
### Customizing the Save Mechanism
The `Prompt` class currently includes a placeholder for saving and loading prompts from persistent storage. You can override the `save_to_storage` and `load_from_storage` methods to integrate with databases, cloud storage, or other persistent layers.
Here's how you can implement the save functionality:
```python
def save_to_storage(self):
# Example of saving to a database or cloud storage
data = self.model_dump()
save_to_database(data) # Custom function to save data
```
Similarly, you can implement a `load_from_storage` function to load the prompt from a storage location using its unique identifier (`id`).
## Full Example code with all methods
```python
from swarms.prompts.prompt import Prompt
# Example 1: Initializing a Financial Report Prompt
financial_prompt = Prompt(
content="Q1 2024 Earnings Report: Initial Draft", autosave=True
)
# Output the initial state of the prompt
print("\n--- Example 1: Initializing Prompt ---")
print(f"Prompt ID: {financial_prompt.id}")
print(f"Content: {financial_prompt.content}")
print(f"Created At: {financial_prompt.created_at}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"History: {financial_prompt.edit_history}")
# Example 2: Editing a Financial Report Prompt
financial_prompt.edit_prompt(
"Q1 2024 Earnings Report: Updated Revenue Figures"
)
# Output the updated state of the prompt
print("\n--- Example 2: Editing Prompt ---")
print(f"Content after edit: {financial_prompt.content}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"History: {financial_prompt.edit_history}")
# Example 3: Rolling Back to a Previous Version
financial_prompt.edit_prompt("Q1 2024 Earnings Report: Final Version")
financial_prompt.rollback(
1
) # Roll back to the second version (index 1)
# Output the state after rollback
print("\n--- Example 3: Rolling Back ---")
print(f"Content after rollback: {financial_prompt.content}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"History: {financial_prompt.edit_history}")
# Example 4: Handling Invalid Rollback
print("\n--- Example 4: Invalid Rollback ---")
try:
financial_prompt.rollback(
5
) # Attempt an invalid rollback (out of bounds)
except IndexError as e:
print(f"Error: {e}")
# Example 5: Preventing Duplicate Edits
print("\n--- Example 5: Preventing Duplicate Edits ---")
try:
financial_prompt.edit_prompt(
"Q1 2024 Earnings Report: Updated Revenue Figures"
) # Duplicate content
except ValueError as e:
print(f"Error: {e}")
# Example 6: Retrieving the Prompt Content as a String
print("\n--- Example 6: Retrieving Prompt as String ---")
current_content = financial_prompt.get_prompt()
print(f"Current Prompt Content: {current_content}")
# Example 7: Simulating Financial Report Changes Over Time
print("\n--- Example 7: Simulating Changes Over Time ---")
# Initialize a new prompt representing an initial financial report draft
financial_prompt = Prompt(
content="Q2 2024 Earnings Report: Initial Draft"
)
# Simulate several updates over time
financial_prompt.edit_prompt(
"Q2 2024 Earnings Report: Updated Forecasts"
)
financial_prompt.edit_prompt(
"Q2 2024 Earnings Report: Revenue Adjustments"
)
financial_prompt.edit_prompt("Q2 2024 Earnings Report: Final Review")
# Display full history
print(f"Final Content: {financial_prompt.content}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"Edit History: {financial_prompt.edit_history}")
```
---
## 8. Conclusion
This guide covered how to effectively use the `Prompt` class in production environments, including core features like editing, version control, autosaving, and logging. By following the best practices outlined here, you can ensure that your prompts are managed efficiently, with minimal overhead and maximum flexibility.
The `Prompt` class is designed with scalability and robustness in mind, making it a great choice for managing prompt content in multi-agent architectures or any application where dynamic prompt management is required. Feel free to extend the functionality to suit your needs, whether it's integrating with persistent storage or enhancing logging mechanisms.
By using this architecture, you'll be able to scale your system effortlessly while maintaining detailed version control and history of every interaction with your prompts.

5538
poetry.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,87 @@
from swarms.prompts.prompt import Prompt
# Example 1: Initializing a Financial Report Prompt
financial_prompt = Prompt(
content="Q1 2024 Earnings Report: Initial Draft", autosave=True
)
# Output the initial state of the prompt
print("\n--- Example 1: Initializing Prompt ---")
print(f"Prompt ID: {financial_prompt.id}")
print(f"Content: {financial_prompt.content}")
print(f"Created At: {financial_prompt.created_at}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"History: {financial_prompt.edit_history}")
# Example 2: Editing a Financial Report Prompt
financial_prompt.edit_prompt(
"Q1 2024 Earnings Report: Updated Revenue Figures"
)
# Output the updated state of the prompt
print("\n--- Example 2: Editing Prompt ---")
print(f"Content after edit: {financial_prompt.content}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"History: {financial_prompt.edit_history}")
# Example 3: Rolling Back to a Previous Version
financial_prompt.edit_prompt("Q1 2024 Earnings Report: Final Version")
financial_prompt.rollback(
1
) # Roll back to the second version (index 1)
# Output the state after rollback
print("\n--- Example 3: Rolling Back ---")
print(f"Content after rollback: {financial_prompt.content}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"History: {financial_prompt.edit_history}")
# Example 4: Handling Invalid Rollback
print("\n--- Example 4: Invalid Rollback ---")
try:
financial_prompt.rollback(
5
) # Attempt an invalid rollback (out of bounds)
except IndexError as e:
print(f"Error: {e}")
# Example 5: Preventing Duplicate Edits
print("\n--- Example 5: Preventing Duplicate Edits ---")
try:
financial_prompt.edit_prompt(
"Q1 2024 Earnings Report: Updated Revenue Figures"
) # Duplicate content
except ValueError as e:
print(f"Error: {e}")
# Example 6: Retrieving the Prompt Content as a String
print("\n--- Example 6: Retrieving Prompt as String ---")
current_content = financial_prompt.get_prompt()
print(f"Current Prompt Content: {current_content}")
# Example 7: Simulating Financial Report Changes Over Time
print("\n--- Example 7: Simulating Changes Over Time ---")
# Initialize a new prompt representing an initial financial report draft
financial_prompt = Prompt(
content="Q2 2024 Earnings Report: Initial Draft"
)
# Simulate several updates over time
financial_prompt.edit_prompt(
"Q2 2024 Earnings Report: Updated Forecasts"
)
financial_prompt.edit_prompt(
"Q2 2024 Earnings Report: Revenue Adjustments"
)
financial_prompt.edit_prompt("Q2 2024 Earnings Report: Final Review")
# Display full history
print(f"Final Content: {financial_prompt.content}")
print(f"Edit Count: {financial_prompt.edit_count}")
print(f"Edit History: {financial_prompt.edit_history}")

@ -7,6 +7,7 @@ from swarms.prompts.operations_agent_prompt import (
OPERATIONS_AGENT_PROMPT,
)
from swarms.prompts.product_agent_prompt import PRODUCT_AGENT_PROMPT
from swarms.prompts.prompt import Prompt
__all__ = [
"CODE_INTERPRETER",
@ -16,4 +17,5 @@ __all__ = [
"OPERATIONS_AGENT_PROMPT",
"PRODUCT_AGENT_PROMPT",
"DOCUMENTATION_WRITER_SOP",
"Prompt"
]

@ -0,0 +1,233 @@
import time
import json
import os
from typing import List
import uuid
from loguru import logger
from pydantic import (
BaseModel,
Field,
constr,
)
from pydantic.v1 import validator
from swarms_cloud.utils.log_to_swarms_database import log_agent_data
from swarms_cloud.utils.capture_system_data import capture_system_data
class Prompt(BaseModel):
"""
A class representing a prompt with content, edit history, and version control.
This version is enhanced for production use, with thread-safety, logging, and additional functionality.
Autosaving is now added to save the prompt to a specified folder within the WORKSPACE_DIR.
Attributes:
id (UUID): A unique identifier for the prompt.
content (str): The main content of the prompt.
created_at (datetime): The timestamp when the prompt was created.
last_modified_at (datetime): The timestamp when the prompt was last modified.
edit_count (int): The number of times the prompt has been edited.
edit_history (List[str]): A list of all versions of the prompt, including current and previous versions.
autosave (bool): Flag to enable or disable autosaving.
autosave_folder (str): The folder path within WORKSPACE_DIR where the prompt will be autosaved.
"""
id: str = Field(
default=uuid.uuid4().hex,
description="Unique identifier for the prompt",
)
name: str = Field(
default="prompt", description="Name of your prompt"
)
description: str = Field(
default="Simple Prompt",
description="The description of the prompt",
)
content: constr(min_length=1, strip_whitespace=True) = Field(
..., description="The main content of the prompt"
)
created_at: str = Field(
default_factory=lambda: time.strftime("%Y-%m-%d %H:%M:%S"),
description="Time when the prompt was created",
)
last_modified_at: str = Field(
default_factory=lambda: time.strftime("%Y-%m-%d %H:%M:%S"),
description="Time when the prompt was last modified",
)
edit_count: int = Field(
default=0,
description="The number of times the prompt has been edited",
)
edit_history: List[str] = Field(
default_factory=list,
description="The history of edits, storing all prompt versions",
)
autosave: bool = Field(
default=False,
description="Flag to enable or disable autosaving",
)
autosave_folder: str = Field(
default="prompts",
description="The folder path within WORKSPACE_DIR where the prompt will be autosaved",
)
parent_folder: str = Field(
default=os.getenv("WORKSPACE_DIR"),
description="The folder where the autosave folder is in",
)
@validator("edit_history", pre=True, always=True)
def initialize_history(cls, v, values):
"""
Initializes the edit history by storing the first version of the prompt.
"""
if not v:
return [
values["content"]
] # Store initial version in history
return v
def edit_prompt(self, new_content: str) -> None:
"""
Edits the prompt content and updates the version control.
This method is thread-safe to prevent concurrent access issues.
If autosave is enabled, it saves the prompt to the specified folder.
Args:
new_content (str): The updated content of the prompt.
Raises:
ValueError: If the new content is identical to the current content.
"""
if new_content == self.content:
logger.warning(
f"Edit attempt failed: new content is identical to current content for prompt {self.id}"
)
raise ValueError(
"New content must be different from the current content."
)
logger.info(
f"Editing prompt {self.id}. Current content: '{self.content}'"
)
self.edit_history.append(new_content)
self.content = new_content
self.edit_count += 1
self.last_modified_at = time.strftime("%Y-%m-%d %H:%M:%S")
logger.debug(
f"Prompt {self.id} updated. Edit count: {self.edit_count}. New content: '{self.content}'"
)
if self.autosave:
self._autosave()
def log_telemetry(self):
system_data = capture_system_data()
merged_data = {**system_data, **self.model_dump()}
log_agent_data(merged_data)
def rollback(self, version: int) -> None:
"""
Rolls back the prompt to a previous version based on the version index.
This method is thread-safe to prevent concurrent access issues.
If autosave is enabled, it saves the prompt to the specified folder after rollback.
Args:
version (int): The version index to roll back to (0 is the first version).
Raises:
IndexError: If the version number is out of range.
"""
if version < 0 or version >= len(self.edit_history):
logger.error(
f"Rollback failed: invalid version {version} for prompt {self.id}"
)
raise IndexError("Invalid version number for rollback.")
logger.info(
f"Rolling back prompt {self.id} to version {version}."
)
self.content = self.edit_history[version]
self.edit_count = version
self.last_modified_at = time.strftime("%Y-%m-%d %H:%M:%S")
logger.debug(
f"Prompt {self.id} rolled back to version {version}. Current content: '{self.content}'"
)
self.log_telemetry()
if self.autosave:
self._autosave()
def get_prompt(self) -> str:
"""
Returns the current prompt content as a string.
Returns:
str: The current prompt content.
"""
logger.debug(f"Returning prompt {self.id} as a string.")
self.log_telemetry()
return self.content
def save_to_storage(self) -> None:
"""
Placeholder method for saving the prompt to persistent storage.
In a production environment, this would integrate with a database or file system.
Raises:
NotImplementedError: This method is a placeholder for storage integration.
"""
logger.info(f"Saving prompt {self.id} to persistent storage.")
raise NotImplementedError(
"Persistent storage integration is required."
)
def load_from_storage(
self, prompt_id: str = uuid.uuid4().hex
) -> None:
"""
Placeholder method for loading the prompt from persistent storage by its ID.
In a production environment, this would integrate with a database or file system.
Args:
prompt_id (UUID): The unique identifier of the prompt to load.
Raises:
NotImplementedError: This method is a placeholder for storage integration.
"""
logger.info(
f"Loading prompt {prompt_id} from persistent storage."
)
raise NotImplementedError(
"Persistent storage integration is required."
)
def _autosave(self) -> None:
"""
Autosaves the prompt to a specified folder within WORKSPACE_DIR.
"""
workspace_dir = os.getenv("WORKSPACE_DIR")
if not workspace_dir:
logger.error(
"WORKSPACE_DIR environment variable is not set."
)
return
autosave_path = os.path.join(
workspace_dir, self.autosave_folder
)
if not os.path.exists(autosave_path):
os.makedirs(autosave_path)
file_path = os.path.join(
autosave_path, f"prompt-id-{self.id}.json"
)
with open(file_path, "w") as file:
json.dump(self.model_dump(), file)
logger.info(f"Autosaved prompt {self.id} to {file_path}.")
class Config:
"""Pydantic configuration for better JSON serialization."""
use_enum_values = True
arbitrary_types_allowed = True

@ -11,7 +11,10 @@ def bootup():
"""Bootup swarms"""
logging.disable(logging.CRITICAL)
os.environ["WANDB_SILENT"] = "true"
os.environ["WORKSPACE_DIR"] = "agent_workspace"
# Dynamically set WORKSPACE_DIR based on the current directory
os.environ["WORKSPACE_DIR"] = os.path.join(
os.getcwd(), "agent_workspace"
)
warnings.filterwarnings("ignore", category=DeprecationWarning)
# Use ThreadPoolExecutor to run disable_logging and auto_update concurrently

Loading…
Cancel
Save