Files
crewAI/src/crewai/utilities/prompts.py
Greyson LaLonde 3e97393f58 chore: improve typing and consolidate utilities
- add type annotations across utility modules  
- refactor printer system, agent utils, and imports for consistency  
- remove unused modules, constants, and redundant patterns  
- improve runtime type checks, exception handling, and guardrail validation  
- standardize warning suppression and logging utilities  
- fix llm typing, threading/typing edge cases, and test behavior
2025-09-23 11:33:46 -04:00

128 lines
4.2 KiB
Python

from __future__ import annotations
from typing import Any, TypedDict
from pydantic import BaseModel, Field
from crewai.utilities.i18n import I18N
class StandardPromptResult(TypedDict):
"""Result with only prompt field for standard mode."""
prompt: str
class SystemPromptResult(StandardPromptResult):
"""Result with system, user, and prompt fields for system prompt mode."""
system: str
user: str
class Prompts(BaseModel):
"""Manages and generates prompts for a generic agent."""
i18n: I18N = Field(default_factory=I18N)
has_tools: bool = Field(
default=False, description="Indicates if the agent has access to tools"
)
system_template: str | None = Field(
default=None, description="Custom system prompt template"
)
prompt_template: str | None = Field(
default=None, description="Custom user prompt template"
)
response_template: str | None = Field(
default=None, description="Custom response prompt template"
)
use_system_prompt: bool | None = Field(
default=False,
description="Whether to use the system prompt when no custom templates are provided",
)
agent: Any = Field(description="Reference to the agent using these prompts")
def task_execution(self) -> SystemPromptResult | StandardPromptResult:
"""Generate a standard prompt for task execution.
Returns:
A dictionary containing the constructed prompt(s).
"""
slices: list[str] = ["role_playing"]
if self.has_tools:
slices.append("tools")
else:
slices.append("no_tools")
system: str = self._build_prompt(slices)
slices.append("task")
if (
not self.system_template
and not self.prompt_template
and self.use_system_prompt
):
return SystemPromptResult(
system=system,
user=self._build_prompt(["task"]),
prompt=self._build_prompt(slices),
)
return StandardPromptResult(
prompt=self._build_prompt(
slices,
self.system_template,
self.prompt_template,
self.response_template,
)
)
def _build_prompt(
self,
components: list[str],
system_template: str | None = None,
prompt_template: str | None = None,
response_template: str | None = None,
) -> str:
"""Constructs a prompt string from specified components.
Args:
components: List of component names to include in the prompt.
system_template: Optional custom template for the system prompt.
prompt_template: Optional custom template for the user prompt.
response_template: Optional custom template for the response prompt.
Returns:
The constructed prompt string.
"""
prompt: str
if not system_template or not prompt_template:
# If any of the required templates are missing, fall back to the default format
prompt_parts: list[str] = [
self.i18n.slice(component) for component in components
]
prompt = "".join(prompt_parts)
else:
# All templates are provided, use them
template_parts: list[str] = [
self.i18n.slice(component)
for component in components
if component != "task"
]
system: str = system_template.replace(
"{{ .System }}", "".join(template_parts)
)
prompt = prompt_template.replace(
"{{ .Prompt }}", "".join(self.i18n.slice("task"))
)
# Handle missing response_template
if response_template:
response: str = response_template.split("{{ .Response }}")[0]
prompt = f"{system}\n{prompt}\n{response}"
else:
prompt = f"{system}\n{prompt}"
return (
prompt.replace("{goal}", self.agent.goal)
.replace("{role}", self.agent.role)
.replace("{backstory}", self.agent.backstory)
)