feat: build chat identity line from settings instead of a static env var
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V57jSQPqwkGG8BuAXg59X5
This commit is contained in:
parent
a904f2f8e0
commit
9505bc2eb3
|
|
@ -56,11 +56,6 @@ EMAIL_SMTP_HOST = os.getenv("EMAIL_SMTP_HOST")
|
||||||
EMAIL_SMTP_PORT = int(os.getenv("EMAIL_SMTP_PORT", "465"))
|
EMAIL_SMTP_PORT = int(os.getenv("EMAIL_SMTP_PORT", "465"))
|
||||||
EMAIL_USER = os.getenv("EMAIL_USER")
|
EMAIL_USER = os.getenv("EMAIL_USER")
|
||||||
EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD")
|
EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD")
|
||||||
CLAUDE_SYSTEM_PROMPT = os.getenv(
|
|
||||||
"CLAUDE_SYSTEM_PROMPT",
|
|
||||||
"Du bist JARVIS, ein KI-Assistent fuer Business-Automatisierung.",
|
|
||||||
)
|
|
||||||
|
|
||||||
# ============ INITIALIZATION ============
|
# ============ INITIALIZATION ============
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="JARVIS API",
|
title="JARVIS API",
|
||||||
|
|
@ -1070,12 +1065,21 @@ async def execute_tool(name: str, tool_input: dict) -> str:
|
||||||
MAX_TOOL_ROUNDS = 5
|
MAX_TOOL_ROUNDS = 5
|
||||||
|
|
||||||
|
|
||||||
|
async def _identity_system_prompt() -> str:
|
||||||
|
settings = await get_all_settings()
|
||||||
|
return (
|
||||||
|
f"Du bist {settings['assistant_name']}, der KI-Assistent von "
|
||||||
|
f"{settings['company_name']}. Bei Fragen zur Erreichbarkeit kannst "
|
||||||
|
f"du auf {settings['contact_email']} verweisen."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def run_chat_completion(claude_messages: list, conversation_id: int):
|
async def run_chat_completion(claude_messages: list, conversation_id: int):
|
||||||
latest_user_message = claude_messages[-1]["content"]
|
latest_user_message = claude_messages[-1]["content"]
|
||||||
memory_context = await build_memory_context(latest_user_message, conversation_id)
|
memory_context = await build_memory_context(latest_user_message, conversation_id)
|
||||||
|
|
||||||
system_prompt = (
|
system_prompt = (
|
||||||
f"{CLAUDE_SYSTEM_PROMPT}\n\n{_current_datetime_context()}\n\n{CALENDAR_ASSISTANT_INSTRUCTIONS}\n\n"
|
f"{await _identity_system_prompt()}\n\n{_current_datetime_context()}\n\n{CALENDAR_ASSISTANT_INSTRUCTIONS}\n\n"
|
||||||
f"{MEMORY_ASSISTANT_INSTRUCTIONS}\n\n{ORDER_ASSISTANT_INSTRUCTIONS}"
|
f"{MEMORY_ASSISTANT_INSTRUCTIONS}\n\n{ORDER_ASSISTANT_INSTRUCTIONS}"
|
||||||
)
|
)
|
||||||
if memory_context:
|
if memory_context:
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,9 @@ async def test_run_chat_completion_without_tool_use():
|
||||||
main.claude_client = MagicMock()
|
main.claude_client = MagicMock()
|
||||||
main.claude_client.messages.create.return_value = completion
|
main.claude_client.messages.create.return_value = completion
|
||||||
|
|
||||||
with patch.object(main, "build_memory_context", new=AsyncMock(return_value="")):
|
with patch.object(main, "build_memory_context", new=AsyncMock(return_value="")), patch.object(
|
||||||
|
main, "_identity_system_prompt", new=AsyncMock(return_value="Du bist JARVIS.")
|
||||||
|
):
|
||||||
text, output_tokens, total_tokens = await main.run_chat_completion(
|
text, output_tokens, total_tokens = await main.run_chat_completion(
|
||||||
[{"role": "user", "content": "Hi"}], conversation_id=1
|
[{"role": "user", "content": "Hi"}], conversation_id=1
|
||||||
)
|
)
|
||||||
|
|
@ -70,7 +72,7 @@ async def test_run_chat_completion_executes_tool_and_returns_followup():
|
||||||
|
|
||||||
with patch.object(main, "list_upcoming_events", new=AsyncMock(return_value=[])), patch.object(
|
with patch.object(main, "list_upcoming_events", new=AsyncMock(return_value=[])), patch.object(
|
||||||
main, "build_memory_context", new=AsyncMock(return_value="")
|
main, "build_memory_context", new=AsyncMock(return_value="")
|
||||||
):
|
), patch.object(main, "_identity_system_prompt", new=AsyncMock(return_value="Du bist JARVIS.")):
|
||||||
text, output_tokens, total_tokens = await main.run_chat_completion(
|
text, output_tokens, total_tokens = await main.run_chat_completion(
|
||||||
[{"role": "user", "content": "Was steht diese Woche an?"}], conversation_id=1
|
[{"role": "user", "content": "Was steht diese Woche an?"}], conversation_id=1
|
||||||
)
|
)
|
||||||
|
|
@ -108,7 +110,9 @@ async def test_run_chat_completion_handles_two_sequential_tool_calls():
|
||||||
|
|
||||||
with patch.object(main, "list_upcoming_events", new=AsyncMock(return_value=[{"uid": "abc"}])), patch.object(
|
with patch.object(main, "list_upcoming_events", new=AsyncMock(return_value=[{"uid": "abc"}])), patch.object(
|
||||||
main, "update_event", new=AsyncMock(return_value={"uid": "abc"})
|
main, "update_event", new=AsyncMock(return_value={"uid": "abc"})
|
||||||
), patch.object(main, "build_memory_context", new=AsyncMock(return_value="")):
|
), patch.object(main, "build_memory_context", new=AsyncMock(return_value="")), patch.object(
|
||||||
|
main, "_identity_system_prompt", new=AsyncMock(return_value="Du bist JARVIS.")
|
||||||
|
):
|
||||||
text, output_tokens, total_tokens = await main.run_chat_completion(
|
text, output_tokens, total_tokens = await main.run_chat_completion(
|
||||||
[{"role": "user", "content": "Verschiebe den Termin X"}], conversation_id=1
|
[{"role": "user", "content": "Verschiebe den Termin X"}], conversation_id=1
|
||||||
)
|
)
|
||||||
|
|
@ -136,7 +140,7 @@ async def test_run_chat_completion_lists_recent_emails():
|
||||||
|
|
||||||
with patch.object(main, "list_recent_emails", new=AsyncMock(return_value=[])), patch.object(
|
with patch.object(main, "list_recent_emails", new=AsyncMock(return_value=[])), patch.object(
|
||||||
main, "build_memory_context", new=AsyncMock(return_value="")
|
main, "build_memory_context", new=AsyncMock(return_value="")
|
||||||
):
|
), patch.object(main, "_identity_system_prompt", new=AsyncMock(return_value="Du bist JARVIS.")):
|
||||||
text, output_tokens, total_tokens = await main.run_chat_completion(
|
text, output_tokens, total_tokens = await main.run_chat_completion(
|
||||||
[{"role": "user", "content": "Was ist neu im Postfach?"}], conversation_id=1
|
[{"role": "user", "content": "Was ist neu im Postfach?"}], conversation_id=1
|
||||||
)
|
)
|
||||||
|
|
@ -168,7 +172,7 @@ async def test_run_chat_completion_includes_current_datetime_in_system_prompt():
|
||||||
|
|
||||||
with patch.object(main, "build_memory_context", new=AsyncMock(return_value="")), patch.object(
|
with patch.object(main, "build_memory_context", new=AsyncMock(return_value="")), patch.object(
|
||||||
main, "_current_datetime_context", return_value="Aktuelles Datum und Uhrzeit: TESTMARKER"
|
main, "_current_datetime_context", return_value="Aktuelles Datum und Uhrzeit: TESTMARKER"
|
||||||
):
|
), patch.object(main, "_identity_system_prompt", new=AsyncMock(return_value="Du bist JARVIS.")):
|
||||||
await main.run_chat_completion([{"role": "user", "content": "Hi"}], conversation_id=1)
|
await main.run_chat_completion([{"role": "user", "content": "Hi"}], conversation_id=1)
|
||||||
|
|
||||||
_, kwargs = main.claude_client.messages.create.call_args
|
_, kwargs = main.claude_client.messages.create.call_args
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ async def test_run_chat_completion_includes_memory_context_in_system_prompt():
|
||||||
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
main, "build_memory_context", new=AsyncMock(return_value="Bekannte Fakten ueber den Nutzer:\n- Hund heisst Bruno")
|
main, "build_memory_context", new=AsyncMock(return_value="Bekannte Fakten ueber den Nutzer:\n- Hund heisst Bruno")
|
||||||
):
|
), patch.object(main, "_identity_system_prompt", new=AsyncMock(return_value="Du bist JARVIS.")):
|
||||||
await main.run_chat_completion([{"role": "user", "content": "Wie geht es meinem Hund?"}], conversation_id=1)
|
await main.run_chat_completion([{"role": "user", "content": "Wie geht es meinem Hund?"}], conversation_id=1)
|
||||||
|
|
||||||
_, kwargs = main.claude_client.messages.create.call_args
|
_, kwargs = main.claude_client.messages.create.call_args
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,9 @@ async def test_run_chat_completion_includes_order_tools_and_instructions():
|
||||||
main.claude_client = MagicMock()
|
main.claude_client = MagicMock()
|
||||||
main.claude_client.messages.create.return_value = completion
|
main.claude_client.messages.create.return_value = completion
|
||||||
|
|
||||||
with patch.object(main, "build_memory_context", new=AsyncMock(return_value="")):
|
with patch.object(main, "build_memory_context", new=AsyncMock(return_value="")), patch.object(
|
||||||
|
main, "_identity_system_prompt", new=AsyncMock(return_value="Du bist JARVIS.")
|
||||||
|
):
|
||||||
await main.run_chat_completion(
|
await main.run_chat_completion(
|
||||||
[{"role": "user", "content": "Neue Bestellung fuer Feuerwehr Onza"}], conversation_id=1
|
[{"role": "user", "content": "Neue Bestellung fuer Feuerwehr Onza"}], conversation_id=1
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -113,3 +113,14 @@ def test_put_settings_endpoint_rejects_unknown_key(client):
|
||||||
def test_put_settings_endpoint_requires_admin_key(client):
|
def test_put_settings_endpoint_requires_admin_key(client):
|
||||||
response = client.put("/api/v1/settings", json={"assistant_name": "X"})
|
response = client.put("/api/v1/settings", json={"assistant_name": "X"})
|
||||||
assert response.status_code == 401
|
assert response.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_identity_system_prompt_uses_settings():
|
||||||
|
settings = {"assistant_name": "FRIDAY", "company_name": "Stark Industries", "contact_email": "info@stark.example"}
|
||||||
|
with patch.object(main, "get_all_settings", new=AsyncMock(return_value=settings)):
|
||||||
|
prompt = await main._identity_system_prompt()
|
||||||
|
|
||||||
|
assert "FRIDAY" in prompt
|
||||||
|
assert "Stark Industries" in prompt
|
||||||
|
assert "info@stark.example" in prompt
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue