mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-08-13 09:48:03 +00:00
* refactor: update date injection functionality in agents - Changed the description of the parameter to clarify that it injects the current date into the agent's prompt instead of tasks. - Removed the method as it was no longer needed. - Implemented a new method in the class to handle date injection directly into the prompt. - Updated tests to ensure the date is correctly injected into the system prompt and user messages based on the flag. * translations * nit
166 lines
5.1 KiB
Python
166 lines
5.1 KiB
Python
"""Tests for the agent ``inject_date`` flag.
|
|
|
|
These assert against the messages the LLM actually receives, so they fail if the
|
|
date stops reaching the wire for either execution entry point: crew/task
|
|
execution via ``execute_task`` and standalone execution via ``kickoff``.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from typing import Any
|
|
from unittest.mock import patch
|
|
|
|
from crewai.agent import Agent
|
|
from crewai.llms.base_llm import BaseLLM
|
|
from crewai.task import Task
|
|
|
|
MOCK_TARGET = "crewai.utilities.prompts.datetime"
|
|
FROZEN_NOW = datetime(2025, 1, 1)
|
|
|
|
|
|
class _RecordingLLM(BaseLLM):
|
|
"""Deterministic LLM that captures every message list it is handed."""
|
|
|
|
def __init__(self, **kwargs: Any) -> None:
|
|
super().__init__(**kwargs)
|
|
self.calls: list[Any] = []
|
|
|
|
def call(self, messages: Any, **kwargs: Any) -> str:
|
|
self.calls.append(messages)
|
|
return "Thought: Done.\nFinal Answer: done"
|
|
|
|
def supports_function_calling(self) -> bool:
|
|
return False
|
|
|
|
def supports_stop_words(self) -> bool:
|
|
return False
|
|
|
|
def get_context_window_size(self) -> int:
|
|
return 8_192
|
|
|
|
def contents_for(self, role: str) -> list[str]:
|
|
"""Every message body sent under ``role`` across all calls."""
|
|
return [
|
|
str(message.get("content", ""))
|
|
for messages in self.calls
|
|
if not isinstance(messages, str)
|
|
for message in messages
|
|
if message.get("role") == role
|
|
]
|
|
|
|
@property
|
|
def everything_sent(self) -> str:
|
|
return "\n".join(
|
|
str(message.get("content", ""))
|
|
for messages in self.calls
|
|
if not isinstance(messages, str)
|
|
for message in messages
|
|
)
|
|
|
|
|
|
def _agent(llm: BaseLLM, **kwargs: Any) -> Agent:
|
|
return Agent(
|
|
role="test_agent",
|
|
goal="test_goal",
|
|
backstory="test_backstory",
|
|
llm=llm,
|
|
max_iter=2,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
def _task(agent: Agent) -> Task:
|
|
return Task(
|
|
description="What is the date today?",
|
|
expected_output="The date.",
|
|
agent=agent,
|
|
)
|
|
|
|
|
|
def test_inject_date_reaches_system_prompt_on_kickoff() -> None:
|
|
"""Standalone ``kickoff`` must put the date in the system message."""
|
|
llm = _RecordingLLM(model="date-test")
|
|
agent = _agent(llm, inject_date=True)
|
|
|
|
with patch(MOCK_TARGET) as mock_datetime:
|
|
mock_datetime.now.return_value = FROZEN_NOW
|
|
agent.kickoff("What is the date today?")
|
|
|
|
system_prompts = llm.contents_for("system")
|
|
assert system_prompts
|
|
assert all("Current Date: 2025-01-01" in prompt for prompt in system_prompts)
|
|
|
|
|
|
def test_inject_date_reaches_system_prompt_on_task_execution() -> None:
|
|
"""Crew/task execution must keep putting the date in front of the model."""
|
|
llm = _RecordingLLM(model="date-test")
|
|
agent = _agent(llm, inject_date=True)
|
|
|
|
with patch(MOCK_TARGET) as mock_datetime:
|
|
mock_datetime.now.return_value = FROZEN_NOW
|
|
agent.execute_task(_task(agent))
|
|
|
|
system_prompts = llm.contents_for("system")
|
|
assert system_prompts
|
|
assert all("Current Date: 2025-01-01" in prompt for prompt in system_prompts)
|
|
|
|
|
|
def test_inject_date_reaches_prompt_without_system_prompt() -> None:
|
|
"""With ``use_system_prompt=False`` the whole prompt is one user message."""
|
|
llm = _RecordingLLM(model="date-test")
|
|
agent = _agent(llm, inject_date=True, use_system_prompt=False)
|
|
|
|
with patch(MOCK_TARGET) as mock_datetime:
|
|
mock_datetime.now.return_value = FROZEN_NOW
|
|
agent.kickoff("What is the date today?")
|
|
|
|
assert not llm.contents_for("system")
|
|
assert "Current Date: 2025-01-01" in llm.contents_for("user")[0]
|
|
|
|
|
|
def test_inject_date_custom_format() -> None:
|
|
llm = _RecordingLLM(model="date-test")
|
|
agent = _agent(llm, inject_date=True, date_format="%d/%m/%Y")
|
|
|
|
with patch(MOCK_TARGET) as mock_datetime:
|
|
mock_datetime.now.return_value = FROZEN_NOW
|
|
agent.kickoff("What is the date today?")
|
|
|
|
assert "Current Date: 01/01/2025" in llm.contents_for("system")[0]
|
|
|
|
|
|
def test_without_inject_date_no_date_is_sent() -> None:
|
|
llm = _RecordingLLM(model="date-test")
|
|
agent = _agent(llm)
|
|
|
|
agent.kickoff("What is the date today?")
|
|
|
|
assert llm.calls
|
|
assert "Current Date:" not in llm.everything_sent
|
|
|
|
|
|
def test_inject_date_invalid_format_is_skipped() -> None:
|
|
"""An unusable format should drop the date, not break execution."""
|
|
llm = _RecordingLLM(model="date-test")
|
|
agent = _agent(llm, inject_date=True, date_format="invalid")
|
|
|
|
output = agent.kickoff("What is the date today?")
|
|
|
|
assert output.raw == "done"
|
|
assert "Current Date:" not in llm.everything_sent
|
|
|
|
|
|
def test_inject_date_does_not_accumulate_across_runs() -> None:
|
|
"""Re-running the same task must not stack up repeated date lines."""
|
|
llm = _RecordingLLM(model="date-test")
|
|
agent = _agent(llm, inject_date=True)
|
|
task = _task(agent)
|
|
|
|
with patch(MOCK_TARGET) as mock_datetime:
|
|
mock_datetime.now.return_value = FROZEN_NOW
|
|
agent.execute_task(task)
|
|
agent.execute_task(task)
|
|
|
|
assert all(
|
|
prompt.count("Current Date:") == 1 for prompt in llm.contents_for("system")
|
|
)
|