Added ability to use a tag to insert the current datetime in prompts (#3697)

* Added ability to use a tag to insert the current datetime in prompts

* made tagging logic more robust

* rename

* k

---------

Co-authored-by: Yuhong Sun <yuhongsun96@gmail.com>
This commit is contained in:
hagen-danswer 2025-01-22 08:17:20 -08:00 committed by GitHub
parent b9c29f2a36
commit 3e58cf2667
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 79 additions and 42 deletions

View File

@ -18,8 +18,8 @@ from onyx.llm.utils import message_to_prompt_and_imgs
from onyx.natural_language_processing.utils import get_tokenizer from onyx.natural_language_processing.utils import get_tokenizer
from onyx.prompts.chat_prompts import CHAT_USER_CONTEXT_FREE_PROMPT from onyx.prompts.chat_prompts import CHAT_USER_CONTEXT_FREE_PROMPT
from onyx.prompts.direct_qa_prompts import HISTORY_BLOCK from onyx.prompts.direct_qa_prompts import HISTORY_BLOCK
from onyx.prompts.prompt_utils import add_date_time_to_prompt
from onyx.prompts.prompt_utils import drop_messages_history_overflow from onyx.prompts.prompt_utils import drop_messages_history_overflow
from onyx.prompts.prompt_utils import handle_onyx_date_awareness
from onyx.tools.force import ForceUseTool from onyx.tools.force import ForceUseTool
from onyx.tools.models import ToolCallFinalResult from onyx.tools.models import ToolCallFinalResult
from onyx.tools.models import ToolCallKickoff from onyx.tools.models import ToolCallKickoff
@ -31,15 +31,16 @@ def default_build_system_message(
prompt_config: PromptConfig, prompt_config: PromptConfig,
) -> SystemMessage | None: ) -> SystemMessage | None:
system_prompt = prompt_config.system_prompt.strip() system_prompt = prompt_config.system_prompt.strip()
if prompt_config.datetime_aware: tag_handled_prompt = handle_onyx_date_awareness(
system_prompt = add_date_time_to_prompt(prompt_str=system_prompt) system_prompt,
prompt_config,
add_additional_info_if_no_tag=prompt_config.datetime_aware,
)
if not system_prompt: if not tag_handled_prompt:
return None return None
system_msg = SystemMessage(content=system_prompt) return SystemMessage(content=tag_handled_prompt)
return system_msg
def default_build_user_message( def default_build_user_message(
@ -64,8 +65,11 @@ def default_build_user_message(
else user_query else user_query
) )
user_prompt = user_prompt.strip() user_prompt = user_prompt.strip()
tag_handled_prompt = handle_onyx_date_awareness(user_prompt, prompt_config)
user_msg = HumanMessage( user_msg = HumanMessage(
content=build_content_with_imgs(user_prompt, files) if files else user_prompt content=build_content_with_imgs(tag_handled_prompt, files)
if files
else tag_handled_prompt
) )
return user_msg return user_msg

View File

@ -21,9 +21,9 @@ from onyx.prompts.constants import DEFAULT_IGNORE_STATEMENT
from onyx.prompts.direct_qa_prompts import CITATIONS_PROMPT from onyx.prompts.direct_qa_prompts import CITATIONS_PROMPT
from onyx.prompts.direct_qa_prompts import CITATIONS_PROMPT_FOR_TOOL_CALLING from onyx.prompts.direct_qa_prompts import CITATIONS_PROMPT_FOR_TOOL_CALLING
from onyx.prompts.direct_qa_prompts import HISTORY_BLOCK from onyx.prompts.direct_qa_prompts import HISTORY_BLOCK
from onyx.prompts.prompt_utils import add_date_time_to_prompt
from onyx.prompts.prompt_utils import build_complete_context_str from onyx.prompts.prompt_utils import build_complete_context_str
from onyx.prompts.prompt_utils import build_task_prompt_reminders from onyx.prompts.prompt_utils import build_task_prompt_reminders
from onyx.prompts.prompt_utils import handle_onyx_date_awareness
from onyx.prompts.token_counts import ADDITIONAL_INFO_TOKEN_CNT from onyx.prompts.token_counts import ADDITIONAL_INFO_TOKEN_CNT
from onyx.prompts.token_counts import ( from onyx.prompts.token_counts import (
CHAT_USER_PROMPT_WITH_CONTEXT_OVERHEAD_TOKEN_CNT, CHAT_USER_PROMPT_WITH_CONTEXT_OVERHEAD_TOKEN_CNT,
@ -127,10 +127,11 @@ def build_citations_system_message(
system_prompt = prompt_config.system_prompt.strip() system_prompt = prompt_config.system_prompt.strip()
if prompt_config.include_citations: if prompt_config.include_citations:
system_prompt += REQUIRE_CITATION_STATEMENT system_prompt += REQUIRE_CITATION_STATEMENT
if prompt_config.datetime_aware: tag_handled_prompt = handle_onyx_date_awareness(
system_prompt = add_date_time_to_prompt(prompt_str=system_prompt) system_prompt, prompt_config, add_additional_info_if_no_tag=True
)
return SystemMessage(content=system_prompt) return SystemMessage(content=tag_handled_prompt)
def build_citations_user_message( def build_citations_user_message(

View File

@ -9,8 +9,8 @@ from onyx.llm.utils import message_to_prompt_and_imgs
from onyx.prompts.direct_qa_prompts import CONTEXT_BLOCK from onyx.prompts.direct_qa_prompts import CONTEXT_BLOCK
from onyx.prompts.direct_qa_prompts import HISTORY_BLOCK from onyx.prompts.direct_qa_prompts import HISTORY_BLOCK
from onyx.prompts.direct_qa_prompts import JSON_PROMPT from onyx.prompts.direct_qa_prompts import JSON_PROMPT
from onyx.prompts.prompt_utils import add_date_time_to_prompt
from onyx.prompts.prompt_utils import build_complete_context_str from onyx.prompts.prompt_utils import build_complete_context_str
from onyx.prompts.prompt_utils import handle_onyx_date_awareness
def _build_strong_llm_quotes_prompt( def _build_strong_llm_quotes_prompt(
@ -39,10 +39,11 @@ def _build_strong_llm_quotes_prompt(
language_hint_or_none=LANGUAGE_HINT.strip() if use_language_hint else "", language_hint_or_none=LANGUAGE_HINT.strip() if use_language_hint else "",
).strip() ).strip()
if prompt.datetime_aware: tag_handled_prompt = handle_onyx_date_awareness(
full_prompt = add_date_time_to_prompt(prompt_str=full_prompt) full_prompt, prompt, add_additional_info_if_no_tag=True
)
return HumanMessage(content=full_prompt) return HumanMessage(content=tag_handled_prompt)
def build_quotes_user_message( def build_quotes_user_message(

View File

@ -19,9 +19,8 @@ from onyx.utils.logger import setup_logger
logger = setup_logger() logger = setup_logger()
MOST_BASIC_PROMPT = "You are a helpful AI assistant." _DANSWER_DATETIME_REPLACEMENT_PAT = "[[CURRENT_DATETIME]]"
DANSWER_DATETIME_REPLACEMENT = "DANSWER_DATETIME_REPLACEMENT" _BASIC_TIME_STR = "The current date is {datetime_info}."
BASIC_TIME_STR = "The current date is {datetime_info}."
def get_current_llm_day_time( def get_current_llm_day_time(
@ -38,23 +37,36 @@ def get_current_llm_day_time(
return f"{formatted_datetime}" return f"{formatted_datetime}"
def add_date_time_to_prompt(prompt_str: str) -> str: def build_date_time_string() -> str:
if DANSWER_DATETIME_REPLACEMENT in prompt_str: return ADDITIONAL_INFO.format(
datetime_info=_BASIC_TIME_STR.format(datetime_info=get_current_llm_day_time())
)
def handle_onyx_date_awareness(
prompt_str: str,
prompt_config: PromptConfig,
add_additional_info_if_no_tag: bool = False,
) -> str:
"""
If there is a [[CURRENT_DATETIME]] tag, replace it with the current date and time no matter what.
If the prompt is datetime aware, and there are no [[CURRENT_DATETIME]] tags, add it to the prompt.
do nothing otherwise.
This can later be expanded to support other tags.
"""
if _DANSWER_DATETIME_REPLACEMENT_PAT in prompt_str:
return prompt_str.replace( return prompt_str.replace(
DANSWER_DATETIME_REPLACEMENT, _DANSWER_DATETIME_REPLACEMENT_PAT,
get_current_llm_day_time(full_sentence=False, include_day_of_week=True), get_current_llm_day_time(full_sentence=False, include_day_of_week=True),
) )
any_tag_present = any(
if prompt_str: _DANSWER_DATETIME_REPLACEMENT_PAT in text
return prompt_str + ADDITIONAL_INFO.format( for text in [prompt_str, prompt_config.system_prompt, prompt_config.task_prompt]
datetime_info=get_current_llm_day_time() )
) if add_additional_info_if_no_tag and not any_tag_present:
else: return prompt_str + build_date_time_string()
return ( return prompt_str
MOST_BASIC_PROMPT
+ " "
+ BASIC_TIME_STR.format(datetime_info=get_current_llm_day_time())
)
def build_task_prompt_reminders( def build_task_prompt_reminders(

View File

@ -8,7 +8,7 @@ prompts:
# System Prompt (as shown in UI) # System Prompt (as shown in UI)
system: > system: >
You are a question answering system that is constantly learning and improving. You are a question answering system that is constantly learning and improving.
The current date is DANSWER_DATETIME_REPLACEMENT. The current date is [[CURRENT_DATETIME]].
You can process and comprehend vast amounts of text and utilize this knowledge to provide You can process and comprehend vast amounts of text and utilize this knowledge to provide
grounded, accurate, and concise answers to diverse queries. grounded, accurate, and concise answers to diverse queries.
@ -24,7 +24,7 @@ prompts:
If there are no relevant documents, refer to the chat history and your internal knowledge. If there are no relevant documents, refer to the chat history and your internal knowledge.
# Inject a statement at the end of system prompt to inform the LLM of the current date/time # Inject a statement at the end of system prompt to inform the LLM of the current date/time
# If the DANSWER_DATETIME_REPLACEMENT is set, the date/time is inserted there instead # If the [[CURRENT_DATETIME]] is set, the date/time is inserted there instead
# Format looks like: "October 16, 2023 14:30" # Format looks like: "October 16, 2023 14:30"
datetime_aware: true datetime_aware: true
# Prompts the LLM to include citations in the for [1], [2] etc. # Prompts the LLM to include citations in the for [1], [2] etc.
@ -51,7 +51,7 @@ prompts:
- name: "OnlyLLM" - name: "OnlyLLM"
description: "Chat directly with the LLM!" description: "Chat directly with the LLM!"
system: > system: >
You are a helpful AI assistant. The current date is DANSWER_DATETIME_REPLACEMENT You are a helpful AI assistant. The current date is [[CURRENT_DATETIME]]
You give concise responses to very simple questions, but provide more thorough responses to You give concise responses to very simple questions, but provide more thorough responses to
@ -69,7 +69,7 @@ prompts:
system: > system: >
You are a text summarizing assistant that highlights the most important knowledge from the You are a text summarizing assistant that highlights the most important knowledge from the
context provided, prioritizing the information that relates to the user query. context provided, prioritizing the information that relates to the user query.
The current date is DANSWER_DATETIME_REPLACEMENT. The current date is [[CURRENT_DATETIME]].
You ARE NOT creative and always stick to the provided documents. You ARE NOT creative and always stick to the provided documents.
If there are no documents, refer to the conversation history. If there are no documents, refer to the conversation history.
@ -87,7 +87,7 @@ prompts:
description: "Recites information from retrieved context! Least creative but most safe!" description: "Recites information from retrieved context! Least creative but most safe!"
system: > system: >
Quote and cite relevant information from provided context based on the user query. Quote and cite relevant information from provided context based on the user query.
The current date is DANSWER_DATETIME_REPLACEMENT. The current date is [[CURRENT_DATETIME]].
You only provide quotes that are EXACT substrings from provided documents! You only provide quotes that are EXACT substrings from provided documents!

View File

@ -192,8 +192,7 @@ def create_persona(
name=build_prompt_name_from_persona_name(persona_upsert_request.name), name=build_prompt_name_from_persona_name(persona_upsert_request.name),
system_prompt=persona_upsert_request.system_prompt, system_prompt=persona_upsert_request.system_prompt,
task_prompt=persona_upsert_request.task_prompt, task_prompt=persona_upsert_request.task_prompt,
# TODO: The PersonaUpsertRequest should provide the value for datetime_aware datetime_aware=persona_upsert_request.datetime_aware,
datetime_aware=False,
include_citations=persona_upsert_request.include_citations, include_citations=persona_upsert_request.include_citations,
prompt_id=prompt_id, prompt_id=prompt_id,
) )
@ -237,8 +236,7 @@ def update_persona(
db_session=db_session, db_session=db_session,
user=user, user=user,
name=build_prompt_name_from_persona_name(persona_upsert_request.name), name=build_prompt_name_from_persona_name(persona_upsert_request.name),
# TODO: The PersonaUpsertRequest should provide the value for datetime_aware datetime_aware=persona_upsert_request.datetime_aware,
datetime_aware=False,
system_prompt=persona_upsert_request.system_prompt, system_prompt=persona_upsert_request.system_prompt,
task_prompt=persona_upsert_request.task_prompt, task_prompt=persona_upsert_request.task_prompt,
include_citations=persona_upsert_request.include_citations, include_citations=persona_upsert_request.include_citations,

View File

@ -60,6 +60,7 @@ class PersonaUpsertRequest(BaseModel):
description: str description: str
system_prompt: str system_prompt: str
task_prompt: str task_prompt: str
datetime_aware: bool
document_set_ids: list[int] document_set_ids: list[int]
num_chunks: float num_chunks: float
include_citations: bool include_citations: bool

View File

@ -26,6 +26,7 @@ class PersonaManager:
is_public: bool = True, is_public: bool = True,
llm_filter_extraction: bool = True, llm_filter_extraction: bool = True,
recency_bias: RecencyBiasSetting = RecencyBiasSetting.AUTO, recency_bias: RecencyBiasSetting = RecencyBiasSetting.AUTO,
datetime_aware: bool = False,
prompt_ids: list[int] | None = None, prompt_ids: list[int] | None = None,
document_set_ids: list[int] | None = None, document_set_ids: list[int] | None = None,
tool_ids: list[int] | None = None, tool_ids: list[int] | None = None,
@ -46,6 +47,7 @@ class PersonaManager:
description=description, description=description,
system_prompt=system_prompt, system_prompt=system_prompt,
task_prompt=task_prompt, task_prompt=task_prompt,
datetime_aware=datetime_aware,
include_citations=include_citations, include_citations=include_citations,
num_chunks=num_chunks, num_chunks=num_chunks,
llm_relevance_filter=llm_relevance_filter, llm_relevance_filter=llm_relevance_filter,
@ -104,6 +106,7 @@ class PersonaManager:
is_public: bool | None = None, is_public: bool | None = None,
llm_filter_extraction: bool | None = None, llm_filter_extraction: bool | None = None,
recency_bias: RecencyBiasSetting | None = None, recency_bias: RecencyBiasSetting | None = None,
datetime_aware: bool = False,
prompt_ids: list[int] | None = None, prompt_ids: list[int] | None = None,
document_set_ids: list[int] | None = None, document_set_ids: list[int] | None = None,
tool_ids: list[int] | None = None, tool_ids: list[int] | None = None,
@ -121,6 +124,7 @@ class PersonaManager:
description=description or persona.description, description=description or persona.description,
system_prompt=system_prompt, system_prompt=system_prompt,
task_prompt=task_prompt, task_prompt=task_prompt,
datetime_aware=datetime_aware,
include_citations=include_citations, include_citations=include_citations,
num_chunks=num_chunks or persona.num_chunks, num_chunks=num_chunks or persona.num_chunks,
llm_relevance_filter=llm_relevance_filter or persona.llm_relevance_filter, llm_relevance_filter=llm_relevance_filter or persona.llm_relevance_filter,

View File

@ -221,6 +221,7 @@ export function AssistantEditor({
const initialValues = { const initialValues = {
name: existingPersona?.name ?? "", name: existingPersona?.name ?? "",
description: existingPersona?.description ?? "", description: existingPersona?.description ?? "",
datetime_aware: existingPrompt?.datetime_aware ?? false,
system_prompt: existingPrompt?.system_prompt ?? "", system_prompt: existingPrompt?.system_prompt ?? "",
task_prompt: existingPrompt?.task_prompt ?? "", task_prompt: existingPrompt?.task_prompt ?? "",
is_public: existingPersona?.is_public ?? defaultPublic, is_public: existingPersona?.is_public ?? defaultPublic,
@ -1372,6 +1373,17 @@ export function AssistantEditor({
</div> </div>
<Separator /> <Separator />
<BooleanFormField
small
removeIndent
alignTop
name="datetime_aware"
label="Date and Time Aware"
subtext='Toggle this option to let the assistant know the current date and time (formatted like: "Thursday Jan 1, 1970 00:01"). To inject it in a specific place in the prompt, use the pattern [[CURRENT_DATETIME]]'
/>
<Separator />
<TextFormField <TextFormField
maxWidth="max-w-4xl" maxWidth="max-w-4xl"
name="task_prompt" name="task_prompt"

View File

@ -6,6 +6,7 @@ interface PersonaUpsertRequest {
description: string; description: string;
system_prompt: string; system_prompt: string;
task_prompt: string; task_prompt: string;
datetime_aware: boolean;
document_set_ids: number[]; document_set_ids: number[];
num_chunks: number | null; num_chunks: number | null;
include_citations: boolean; include_citations: boolean;
@ -36,6 +37,7 @@ export interface PersonaUpsertParameters {
system_prompt: string; system_prompt: string;
existing_prompt_id: number | null; existing_prompt_id: number | null;
task_prompt: string; task_prompt: string;
datetime_aware: boolean;
document_set_ids: number[]; document_set_ids: number[];
num_chunks: number | null; num_chunks: number | null;
include_citations: boolean; include_citations: boolean;
@ -105,6 +107,7 @@ function buildPersonaUpsertRequest(
is_public, is_public,
groups, groups,
existing_prompt_id, existing_prompt_id,
datetime_aware,
users, users,
tool_ids, tool_ids,
icon_color, icon_color,
@ -129,6 +132,7 @@ function buildPersonaUpsertRequest(
icon_shape, icon_shape,
remove_image, remove_image,
search_start_date, search_start_date,
datetime_aware,
is_default_persona: creationRequest.is_default_persona ?? false, is_default_persona: creationRequest.is_default_persona ?? false,
recency_bias: "base_decay", recency_bias: "base_decay",
prompt_ids: existing_prompt_id ? [existing_prompt_id] : [], prompt_ids: existing_prompt_id ? [existing_prompt_id] : [],