Compare commits

..

No commits in common. "bb84709f44deeeebe94798941d558a4a1c42b067" and "3fc6b1ab4d1fe2c7f2af06057ef2808a44433fd0" have entirely different histories.

3 changed files with 58 additions and 30 deletions

View File

@ -358,9 +358,8 @@ class Agent(BaseModel, ABC):
size=user.file_watcher.collection.count() size=user.file_watcher.collection.count()
) )
entries += len(rag_metadata.documents)
rag_message.metadata.rag_results.append(rag_metadata) rag_message.metadata.rag_results.append(rag_metadata)
rag_message.content = f"Results from {rag.name} RAG: {len(rag_metadata.documents)} results." rag_message.content = f"Results from {rag.name} RAG: {len(chroma_results['documents'])} results."
yield rag_message yield rag_message
rag_message.content = ( rag_message.content = (
@ -378,7 +377,7 @@ class Agent(BaseModel, ABC):
return return
async def generate( async def generate(
self, llm: Any, model: str, user_message: ChatMessageUser, user: Candidate, temperature=0.7 self, llm: Any, model: str, user_message: ChatMessageUser, user_id: str, temperature=0.7
) -> AsyncGenerator[ChatMessage | ChatMessageBase, None]: ) -> AsyncGenerator[ChatMessage | ChatMessageBase, None]:
logger.info(f"{self.agent_type} - {inspect.stack()[0].function}") logger.info(f"{self.agent_type} - {inspect.stack()[0].function}")
@ -447,7 +446,7 @@ Content: { content }
messages.append( messages.append(
LLMMessage( LLMMessage(
role="user", role="user",
content=f"<|context|>\n{rag_context.strip()}\n</|context|>\n\nPrompt to respond to:\n{user_message.content.strip()}\n" content=f"<|context|>\n{rag_context.strip()}\n</|context|>\n\n{user_message.content.strip()}\n"
) )
) )
else: else:

View File

@ -7,20 +7,44 @@ from .base import Agent, agent_registry
from logger import logger from logger import logger
from .registry import agent_registry from .registry import agent_registry
from models import ( ChatQuery, ChatMessage, Tunables, ChatStatusType, ChatMessageUser, Candidate) from models import ( ChatQuery, ChatMessage, Tunables, ChatStatusType)
system_message = f""" system_message = f"""
Launched on {datetime.now().isoformat()}.
When answering queries, follow these steps: When answering queries, follow these steps:
- When any content from <|context|> is relevant, synthesize information from all sources to provide the most complete answer. - First analyze the query to determine if real-time information from the tools might be helpful
- Always prioritize the most up-to-date, recent, and relevant information first. - Even when <|context|> or <|resume|> is provided, consider whether the tools would provide more current or comprehensive information
- If there is information in the <|context|> section to enhance the answer, incorporate it seamlessly and refer to it as 'the latest information' or 'recent data' instead of mentioning '<|context|>' (etc.) or quoting it directly. - Use the provided tools whenever they would enhance your response, regardless of whether context is also available
- Avoid phrases like 'According to the <|context|>' or similar references to the <|context|>. - When presenting weather forecasts, include relevant emojis immediately before the corresponding text. For example, for a sunny day, say \"☀️ Sunny\" or if the forecast says there will be \"rain showers, say \"🌧️ Rain showers\". Use this mapping for weather emojis: Sunny: ☀️, Cloudy: ☁️, Rainy: 🌧️, Snowy: ❄️
- When any combination of <|context|>, <|resume|> and tool outputs are relevant, synthesize information from all sources to provide the most complete answer
- Always prioritize the most up-to-date and relevant information, whether it comes from <|context|>, <|resume|> or tools
- If <|context|> and tool outputs contain conflicting information, prefer the tool outputs as they likely represent more current data
- If there is information in the <|context|> or <|resume|> sections to enhance the answer, incorporate it seamlessly and refer to it as 'the latest information' or 'recent data' instead of mentioning '<|context|>' (etc.) or quoting it directly.
- Avoid phrases like 'According to the <|context|>' or similar references to the <|context|> or <|resume|>.
Always <|context|> when possible. Be concise, and never make up information. If you do not know the answer, say so. CRITICAL INSTRUCTIONS FOR IMAGE GENERATION:
Before answering, ensure you have spelled the candidate's name correctly. 1. When the user requests to generate an image, inject the following into the response: <GenerateImage prompt="USER-PROMPT"/>. Do this when users request images, drawings, or visual content.
3. MANDATORY: You must respond with EXACTLY this format: <GenerateImage prompt="{{USER-PROMPT}}"/>
4. FORBIDDEN: DO NOT use markdown image syntax ![](url)
5. FORBIDDEN: DO NOT create fake URLs or file paths
6. FORBIDDEN: DO NOT use any other image embedding format
CORRECT EXAMPLE:
User: "Draw a cat"
Your response: "<GenerateImage prompt='Draw a cat'/>"
WRONG EXAMPLES (DO NOT DO THIS):
- ![](https://example.com/...)
- ![Cat image](any_url)
- <img src="...">
The <GenerateImage prompt="{{USER-PROMPT}}"/> format is the ONLY way to display images in this system.
DO NOT make up a URL for an image or provide markdown syntax for embedding an image. Only use <GenerateImage prompt="{{USER-PROMPT}}".
Always use tools, <|resume|>, and <|context|> when possible. Be concise, and never make up information. If you do not know the answer, say so.
""" """
class CandidateChat(Agent): class CandidateChat(Agent):
@ -33,26 +57,31 @@ class CandidateChat(Agent):
system_prompt: str = system_message system_prompt: str = system_message
async def generate( # async def prepare_message(self, message: Message) -> AsyncGenerator[Message, None]:
self, llm: Any, model: str, user_message: ChatMessageUser, user: Candidate, temperature=0.7 # logger.info(f"{self.agent_type} - {inspect.stack()[0].function}")
): # if not self.context:
self.system_prompt = f""" # raise ValueError("Context is not set for this agent.")
You are a helpful expert system representing a {user.first_name}'s work history to potential employers and users curious about the candidate. You want to incorporate as many facts and details about {user.first_name} as possible.
When referencing the candidate, ALWAYS ensure correct spelling. # async for message in super().prepare_message(message):
# if message.status != "done":
# yield message
The candidate's first name is: "{user.first_name}" # if message.preamble:
The candidate's last name is: "{user.last_name}" # excluded = {}
# 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:"
Use that spelling instead of any spelling you may find in the <|context|>.
{system_message}
"""
async for message in super().generate(llm, model, user_message, user, temperature):
yield message
# Register the base agent # Register the base agent
agent_registry.register(CandidateChat._agent_type, CandidateChat) agent_registry.register(CandidateChat._agent_type, CandidateChat)

View File

@ -1994,7 +1994,7 @@ async def post_chat_session_message_stream(
llm=llm_manager.get_llm(), llm=llm_manager.get_llm(),
model=defines.model, model=defines.model,
user_message=user_message, user_message=user_message,
user=current_user, user_id=current_user.id,
): ):
# Store reference to the complete AI message # Store reference to the complete AI message
if generated_message.status == ChatStatusType.DONE: if generated_message.status == ChatStatusType.DONE: