708 lines
23 KiB
Python
708 lines
23 KiB
Python
"""
|
|
Test that fact extraction correctly captures all information dimensions.
|
|
|
|
This test suite verifies that the fact extraction system properly preserves:
|
|
1. Emotional/Affective dimension
|
|
2. Sensory/Experiential dimension
|
|
3. Cognitive/Epistemic dimension
|
|
4. Intentional/Motivational dimension
|
|
5. Evaluative/Preferential dimension
|
|
6. Capability/Skill dimension
|
|
7. Attitudinal/Reactive dimension
|
|
8. Comparative/Relative dimension
|
|
9. Temporal dimension (with absolute date conversion)
|
|
"""
|
|
import pytest
|
|
from datetime import datetime
|
|
from memora.fact_extraction import extract_facts_from_text
|
|
from memora.llm_wrapper import LLMConfig
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_emotional_dimension_preservation():
|
|
"""
|
|
Test that emotional states and feelings are preserved, not stripped away.
|
|
|
|
Example: "I was thrilled to receive positive feedback"
|
|
Should NOT become: "I received positive feedback"
|
|
"""
|
|
text = """
|
|
I was absolutely thrilled when I received such positive feedback on my presentation!
|
|
Sarah seemed disappointed when she heard the news about the delay.
|
|
Marcus felt anxious about the upcoming interview.
|
|
"""
|
|
|
|
context = "Personal journal entry"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
# Check that emotional words are preserved
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve emotional intensity and specific emotions
|
|
emotional_indicators = ["thrilled", "disappointed", "anxious", "positive feedback"]
|
|
found_emotions = [word for word in emotional_indicators if word in all_facts_text]
|
|
|
|
assert len(found_emotions) >= 2, (
|
|
f"Should preserve emotional dimension. "
|
|
f"Found: {found_emotions}, Expected at least 2 from: {emotional_indicators}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_temporal_absolute_conversion():
|
|
"""
|
|
Test that relative temporal expressions are converted to absolute dates.
|
|
|
|
Critical: "yesterday" should become "on November 12, 2024", NOT "recently"
|
|
"""
|
|
text = """
|
|
Yesterday I went for a morning jog for the first time in a nearby park.
|
|
Last week I started a new project.
|
|
I'm planning to visit Tokyo next month.
|
|
"""
|
|
|
|
context = "Personal conversation"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
# Event date is November 13, 2024
|
|
event_date = datetime(2024, 11, 13)
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=event_date,
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should NOT contain vague temporal terms
|
|
prohibited_terms = ["recently", "soon", "lately", "a while ago", "some time ago"]
|
|
found_prohibited = [term for term in prohibited_terms if term in all_facts_text]
|
|
|
|
assert len(found_prohibited) == 0, (
|
|
f"Should NOT use vague temporal terms. Found: {found_prohibited}"
|
|
)
|
|
|
|
# Should contain specific date references (either month names or dates)
|
|
# For "yesterday" (Nov 12), "last week" (early Nov), "next month" (December)
|
|
temporal_indicators = ["november", "12", "early november", "week of", "december"]
|
|
found_temporal = [term for term in temporal_indicators if term in all_facts_text]
|
|
|
|
assert len(found_temporal) >= 1, (
|
|
f"Should convert relative dates to absolute. "
|
|
f"Found: {found_temporal}, Expected month/date references"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_sensory_dimension_preservation():
|
|
"""
|
|
Test that sensory details (visual, auditory, etc.) are preserved.
|
|
"""
|
|
text = """
|
|
The coffee tasted bitter and burnt.
|
|
She showed me her bright orange hair, which looked stunning under the lights.
|
|
The music was so loud I could barely hear myself think.
|
|
"""
|
|
|
|
context = "Personal experience"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve sensory descriptors
|
|
sensory_indicators = ["bitter", "burnt", "bright orange", "loud", "stunning"]
|
|
found_sensory = [word for word in sensory_indicators if word in all_facts_text]
|
|
|
|
assert len(found_sensory) >= 2, (
|
|
f"Should preserve sensory details. "
|
|
f"Found: {found_sensory}, Expected at least 2 from: {sensory_indicators}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cognitive_epistemic_dimension():
|
|
"""
|
|
Test that cognitive states and certainty levels are preserved.
|
|
"""
|
|
text = """
|
|
I realized that the approach wasn't working.
|
|
She wasn't sure if the meeting would happen.
|
|
He's convinced that AI will transform healthcare.
|
|
Maybe we should reconsider the timeline.
|
|
"""
|
|
|
|
context = "Team discussion"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve cognitive/epistemic indicators
|
|
cognitive_indicators = ["realized", "wasn't sure", "convinced", "maybe", "reconsider"]
|
|
found_cognitive = [word for word in cognitive_indicators if word in all_facts_text]
|
|
|
|
assert len(found_cognitive) >= 2, (
|
|
f"Should preserve cognitive/epistemic dimension. "
|
|
f"Found: {found_cognitive}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_capability_skill_dimension():
|
|
"""
|
|
Test that capabilities, skills, and limitations are preserved.
|
|
"""
|
|
text = """
|
|
I can speak French fluently.
|
|
Sarah struggles with public speaking.
|
|
He's an expert in machine learning.
|
|
I'm unable to attend the conference due to scheduling conflicts.
|
|
"""
|
|
|
|
context = "Personal profile discussion"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve capability indicators
|
|
capability_indicators = ["can speak", "fluently", "struggles with", "expert in", "unable to"]
|
|
found_capability = [word for word in capability_indicators if word in all_facts_text]
|
|
|
|
assert len(found_capability) >= 2, (
|
|
f"Should preserve capability/skill dimension. "
|
|
f"Found: {found_capability}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_comparative_dimension():
|
|
"""
|
|
Test that comparisons and contrasts are preserved.
|
|
"""
|
|
text = """
|
|
This approach is much better than the previous one.
|
|
The new design is worse than expected.
|
|
Unlike last year, we're ahead of schedule.
|
|
"""
|
|
|
|
context = "Project review"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve comparative indicators
|
|
comparative_indicators = ["better than", "worse than", "unlike", "ahead of"]
|
|
found_comparative = [word for word in comparative_indicators if word in all_facts_text]
|
|
|
|
assert len(found_comparative) >= 1, (
|
|
f"Should preserve comparative dimension. "
|
|
f"Found: {found_comparative}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_attitudinal_reactive_dimension():
|
|
"""
|
|
Test that attitudes and reactions are preserved.
|
|
"""
|
|
text = """
|
|
She's very skeptical about the new technology.
|
|
I was surprised when he announced his resignation.
|
|
Marcus rolled his eyes when the topic came up.
|
|
She's enthusiastic about the opportunity.
|
|
"""
|
|
|
|
context = "Team meeting"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve attitudinal/reactive indicators
|
|
attitudinal_indicators = ["skeptical", "surprised", "rolled his eyes", "enthusiastic"]
|
|
found_attitudinal = [word for word in attitudinal_indicators if word in all_facts_text]
|
|
|
|
assert len(found_attitudinal) >= 2, (
|
|
f"Should preserve attitudinal/reactive dimension. "
|
|
f"Found: {found_attitudinal}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_intentional_motivational_dimension():
|
|
"""
|
|
Test that goals, plans, and motivations are preserved.
|
|
"""
|
|
text = """
|
|
I want to learn Mandarin before my trip to China.
|
|
She aims to complete her PhD within three years.
|
|
His goal is to build a sustainable business.
|
|
I'm planning to switch careers because I'm not fulfilled in my current role.
|
|
"""
|
|
|
|
context = "Personal goals discussion"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve intentional/motivational indicators
|
|
intentional_indicators = ["want to", "aims to", "goal is", "planning to", "because"]
|
|
found_intentional = [word for word in intentional_indicators if word in all_facts_text]
|
|
|
|
assert len(found_intentional) >= 2, (
|
|
f"Should preserve intentional/motivational dimension. "
|
|
f"Found: {found_intentional}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_evaluative_preferential_dimension():
|
|
"""
|
|
Test that preferences and values are preserved.
|
|
"""
|
|
text = """
|
|
I prefer working remotely to being in an office.
|
|
She values honesty above all else.
|
|
He hates being late to meetings.
|
|
Family is the most important thing to her.
|
|
"""
|
|
|
|
context = "Personal values discussion"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve evaluative/preferential indicators
|
|
evaluative_indicators = ["prefer", "values", "hates", "important", "above all"]
|
|
found_evaluative = [word for word in evaluative_indicators if word in all_facts_text]
|
|
|
|
assert len(found_evaluative) >= 2, (
|
|
f"Should preserve evaluative/preferential dimension. "
|
|
f"Found: {found_evaluative}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_comprehensive_multi_dimension():
|
|
"""
|
|
Test a realistic scenario with multiple dimensions in one fact.
|
|
"""
|
|
text = """
|
|
I was thrilled to receive such positive feedback on my presentation yesterday!
|
|
I wasn't sure if my approach would resonate, but the audience seemed enthusiastic.
|
|
I prefer presenting in person rather than virtually because I can read the room better.
|
|
"""
|
|
|
|
context = "Personal reflection"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
event_date = datetime(2024, 11, 13)
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=event_date,
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve multiple dimensions:
|
|
# 1. Emotional: "thrilled"
|
|
# 2. Temporal: "yesterday" → absolute date (not "recently")
|
|
# 3. Cognitive: "wasn't sure"
|
|
# 4. Attitudinal: "enthusiastic"
|
|
# 5. Preferential: "prefer"
|
|
# 6. Comparative: "better"
|
|
|
|
# Check emotional
|
|
assert "thrilled" in all_facts_text or "positive feedback" in all_facts_text, \
|
|
"Should preserve emotional dimension (thrilled)"
|
|
|
|
# Check no vague temporal terms
|
|
prohibited_terms = ["recently", "soon", "lately"]
|
|
found_prohibited = [term for term in prohibited_terms if term in all_facts_text]
|
|
assert len(found_prohibited) == 0, \
|
|
f"Should NOT use vague temporal terms. Found: {found_prohibited}"
|
|
|
|
# Check cognitive uncertainty
|
|
assert "wasn't sure" in all_facts_text or "unsure" in all_facts_text or "uncertain" in all_facts_text, \
|
|
"Should preserve cognitive uncertainty"
|
|
|
|
# Check preference
|
|
assert "prefer" in all_facts_text or "rather than" in all_facts_text, \
|
|
"Should preserve preferential dimension"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_logical_inference_identity_connection():
|
|
"""
|
|
Test that the system makes logical inferences to connect related information.
|
|
|
|
Example: "I lost a friend" + "this photo with Karlie" → "I lost my friend Karlie"
|
|
"""
|
|
text = """
|
|
Deborah: The roses and dahlias bring me peace. I lost a friend last week,
|
|
so I've been spending time in the garden to find some comfort.
|
|
|
|
Jolene: Sorry to hear about your friend, Deb. Losing someone can be really tough.
|
|
How are you holding up?
|
|
|
|
Deborah: Thanks for the kind words. It's been tough, but I'm comforted by
|
|
remembering our time together. It reminds me of how special life is.
|
|
|
|
Jolene: Memories can give us so much comfort and joy.
|
|
|
|
Deborah: Memories keep our loved ones close. This is the last photo with Karlie
|
|
which was taken last summer when we hiked. It was our last one. We had such a
|
|
great time! Every time I see it, I can't help but smile.
|
|
"""
|
|
|
|
context = "Conversation between Deborah and Jolene"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
# Event date is February 23, 2023
|
|
event_date = datetime(2023, 2, 23)
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=event_date,
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="Deborah"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# CRITICAL: Should make the logical connection that Karlie is the lost friend
|
|
# The fact should mention both "lost" (or similar) AND "Karlie" together
|
|
has_karlie = "karlie" in all_facts_text
|
|
has_loss = any(word in all_facts_text for word in ["lost", "death", "passed", "died", "losing"])
|
|
|
|
assert has_karlie, "Should mention Karlie in the extracted facts"
|
|
assert has_loss, "Should mention the loss/death in the extracted facts"
|
|
|
|
# Ideally, they should be in the same fact (connected)
|
|
# Check if any single fact contains both Karlie and loss-related terms
|
|
connected_fact_found = False
|
|
for fact in facts:
|
|
fact_text = fact['fact'].lower()
|
|
if "karlie" in fact_text and any(word in fact_text for word in ["lost", "death", "passed", "died", "losing"]):
|
|
connected_fact_found = True
|
|
print(f"\n✓ Found connected fact: {fact['fact']}")
|
|
break
|
|
|
|
assert connected_fact_found, (
|
|
"Should connect 'lost a friend' with 'Karlie' in the same fact. "
|
|
f"The inference should be: Karlie is the lost friend. "
|
|
f"Facts: {[f['fact'] for f in facts]}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_logical_inference_pronoun_resolution():
|
|
"""
|
|
Test that pronouns are resolved to their referents.
|
|
|
|
Example: "I started a project" + "It's challenging" → "The project is challenging"
|
|
"""
|
|
text = """
|
|
I started a new machine learning project last month.
|
|
It's been really challenging but very rewarding.
|
|
I've learned so much from it.
|
|
"""
|
|
|
|
context = "Personal update"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=datetime(2024, 11, 13),
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. {f['fact']}")
|
|
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should connect the project with its characteristics
|
|
# The fact should mention "project" AND the qualities (challenging, rewarding)
|
|
has_project = "project" in all_facts_text
|
|
has_qualities = any(word in all_facts_text for word in ["challenging", "rewarding", "learned"])
|
|
|
|
assert has_project, "Should mention the project"
|
|
assert has_qualities, "Should mention the qualities/learning"
|
|
|
|
# Check if a single fact connects the project with its characteristics
|
|
connected_fact_found = False
|
|
for fact in facts:
|
|
fact_text = fact['fact'].lower()
|
|
if "project" in fact_text and any(word in fact_text for word in ["challenging", "rewarding"]):
|
|
connected_fact_found = True
|
|
print(f"\n✓ Found connected fact: {fact['fact']}")
|
|
break
|
|
|
|
assert connected_fact_found, (
|
|
"Should resolve 'it' to 'the project' and connect characteristics in the same fact. "
|
|
f"Facts: {[f['fact'] for f in facts]}"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_date_field_calculation_last_night():
|
|
"""
|
|
Test that the date field is calculated correctly for "last night" events.
|
|
|
|
CRITICAL: If conversation is on August 14, 2023 and text says "last night",
|
|
the date field should be August 13, NOT August 14.
|
|
"""
|
|
text = """
|
|
Melanie: Hey Caroline! Last night was amazing! We celebrated my daughter's birthday
|
|
with a concert surrounded by music, joy and the warm summer breeze.
|
|
"""
|
|
|
|
context = "Conversation between Melanie and Caroline"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
# Conversation happened on August 14, 2023
|
|
event_date = datetime(2023, 8, 14, 14, 24) # 2:24 PM on Aug 14
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=event_date,
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="Melanie"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. Date: {f['date']} - {f['fact']}")
|
|
|
|
# Find the fact about the birthday celebration
|
|
birthday_fact = None
|
|
for fact in facts:
|
|
if "birthday" in fact['fact'].lower() or "concert" in fact['fact'].lower():
|
|
birthday_fact = fact
|
|
break
|
|
|
|
assert birthday_fact is not None, "Should extract fact about birthday celebration"
|
|
|
|
# The date field should be August 13, 2023 (last night), NOT August 14
|
|
fact_date_str = birthday_fact['date']
|
|
|
|
# Parse the date
|
|
if 'T' in fact_date_str:
|
|
fact_date = datetime.fromisoformat(fact_date_str.replace('Z', '+00:00'))
|
|
else:
|
|
fact_date = datetime.fromisoformat(fact_date_str)
|
|
|
|
assert fact_date.year == 2023, "Year should be 2023"
|
|
assert fact_date.month == 8, "Month should be August"
|
|
assert fact_date.day == 13, (
|
|
f"Day should be 13 (last night relative to Aug 14), but got {fact_date.day}. "
|
|
f"Date field should be when FACT occurred, not when mentioned!"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_date_field_calculation_yesterday():
|
|
"""
|
|
Test that the date field is calculated correctly for "yesterday" events.
|
|
"""
|
|
text = """
|
|
Yesterday I went for a morning jog for the first time in a nearby park.
|
|
"""
|
|
|
|
context = "Personal diary"
|
|
llm_config = LLMConfig.for_memory()
|
|
|
|
# Conversation on November 13, 2024
|
|
event_date = datetime(2024, 11, 13)
|
|
|
|
facts = await extract_facts_from_text(
|
|
text=text,
|
|
event_date=event_date,
|
|
context=context,
|
|
llm_config=llm_config,
|
|
agent_name="TestUser"
|
|
)
|
|
|
|
assert len(facts) > 0, "Should extract at least one fact"
|
|
|
|
print(f"\nExtracted {len(facts)} facts:")
|
|
for i, f in enumerate(facts):
|
|
print(f"{i+1}. Date: {f['date']} - {f['fact']}")
|
|
|
|
# Get the jogging fact
|
|
jogging_fact = facts[0]
|
|
|
|
# Parse the date
|
|
fact_date_str = jogging_fact['date']
|
|
if 'T' in fact_date_str:
|
|
fact_date = datetime.fromisoformat(fact_date_str.replace('Z', '+00:00'))
|
|
else:
|
|
fact_date = datetime.fromisoformat(fact_date_str)
|
|
|
|
# Should be November 12, 2024 (yesterday)
|
|
assert fact_date.year == 2024, "Year should be 2024"
|
|
assert fact_date.month == 11, "Month should be November"
|
|
assert fact_date.day == 12, (
|
|
f"Day should be 12 (yesterday relative to Nov 13), but got {fact_date.day}. "
|
|
f"Date field: {fact_date_str}"
|
|
)
|
|
|
|
# Check fact text
|
|
all_facts_text = " ".join([f['fact'].lower() for f in facts])
|
|
|
|
# Should preserve "first time"
|
|
assert "first time" in all_facts_text or "first" in all_facts_text, \
|
|
"Should preserve 'first time' qualifier"
|
|
|
|
# Should NOT use "recently"
|
|
assert "recently" not in all_facts_text, \
|
|
"Should NOT convert 'yesterday' to 'recently'"
|
|
|
|
# Should have absolute date in text (November 12 or specific date)
|
|
assert any(term in all_facts_text for term in ["november", "12", "nov"]), \
|
|
"Should convert 'yesterday' to absolute date in fact text"
|