85 lines
3.2 KiB
Python
85 lines
3.2 KiB
Python
from __future__ import annotations
|
|
from pydantic import model_validator
|
|
from typing import (
|
|
Literal,
|
|
ClassVar,
|
|
Optional,
|
|
Any,
|
|
AsyncGenerator,
|
|
List,
|
|
) # NOTE: You must import Optional for late binding to work
|
|
from datetime import datetime
|
|
import inspect
|
|
|
|
from .base import Agent, agent_registry
|
|
from ..conversation import Conversation
|
|
from ..message import Message
|
|
from ..setup_logging import setup_logging
|
|
|
|
logger = setup_logging()
|
|
|
|
system_fact_check = f"""
|
|
Launched on {datetime.now().isoformat()}.
|
|
|
|
You are a professional resume fact checker. Your task is answer any questions about items identified in the <|discrepancies|>.
|
|
The <|discrepancies|> indicate inaccuracies or unsupported claims in the <|generated-resume|> based on content from the <|resume|> and <|context|>.
|
|
|
|
When answering queries, follow these steps:
|
|
- If there is information in the <|context|> or <|resume|> sections to enhance the answer, incorporate it seamlessly and refer to it using natural language instead of mentioning '<|context|>' (etc.) or quoting it directly.
|
|
- Avoid phrases like 'According to the <|context|>' or similar references to the <|context|>, <|generated-resume|>, or <|resume|> tags.
|
|
""".strip()
|
|
|
|
|
|
class FactCheck(Agent):
|
|
agent_type: Literal["fact_check"] = "fact_check"
|
|
_agent_type: ClassVar[str] = agent_type # Add this for registration
|
|
|
|
system_prompt: str = system_fact_check
|
|
facts: str
|
|
|
|
@model_validator(mode="after")
|
|
def validate_facts(self):
|
|
if not self.facts.strip():
|
|
raise ValueError("Facts cannot be empty")
|
|
return self
|
|
|
|
async def prepare_message(self, message: Message) -> AsyncGenerator[Message, None]:
|
|
logger.info(f"{self.agent_type} - {inspect.stack()[0].function}")
|
|
if not self.context:
|
|
raise ValueError("Context is not set for this agent.")
|
|
|
|
resume_agent = self.context.get_agent("resume")
|
|
if not resume_agent:
|
|
raise ValueError("resume agent does not exist")
|
|
|
|
message.tunables.enable_tools = False
|
|
|
|
async for message in super().prepare_message(message):
|
|
if message.status != "done":
|
|
yield message
|
|
|
|
message.preamble["generated-resume"] = resume_agent.resume
|
|
message.preamble["discrepancies"] = self.facts
|
|
|
|
excluded = {"job_description"}
|
|
preamble_types = [
|
|
f"<|{p}|>" for p in message.preamble.keys() if p not in excluded
|
|
]
|
|
preamble_types_AND = " and ".join(preamble_types)
|
|
preamble_types_OR = " or ".join(preamble_types)
|
|
message.preamble[
|
|
"rules"
|
|
] = f"""\
|
|
- Answer the question based on the information provided in the {preamble_types_AND} sections by incorporate it seamlessly and refer to it using natural language instead of mentioning {preamble_types_OR} or quoting it directly.
|
|
- If there is no information in these sections, answer based on your knowledge, or use any available tools.
|
|
- Avoid phrases like 'According to the {preamble_types[0]}' or similar references to the {preamble_types_OR}.
|
|
"""
|
|
message.preamble["question"] = "Respond to:"
|
|
|
|
yield message
|
|
return
|
|
|
|
|
|
# Register the base agent
|
|
agent_registry.register(FactCheck._agent_type, FactCheck)
|