Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/markus_ai_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,9 @@ def chat():
model = request.form.get('model', DEFAULT_MODEL)
content = request.form.get('content', '')
llama_mode = request.form.get('llama_mode', 'cli')
system_prompt = request.form.get('system_prompt')
# Accept either field name: callers send 'system_prompt', the ai_feedback
# RemoteModel sends 'system_instructions'. Prefer the former when both exist.
system_prompt = request.form.get('system_prompt') or request.form.get('system_instructions')
image_files = list(request.files.values())
model_options = request.form.get('model_options')
json_schema = request.form.get('json_schema')
Expand Down
48 changes: 31 additions & 17 deletions test/test_system_prompt_api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import json
from unittest.mock import patch

import pytest

TEST_MODEL = 'DeepSeek-V3-0324-UD-IQ2_XXS'
TEST_SYSTEM_PROMPT = "You are a helpful coding assistant."
TEST_USER_CONTENT = "Write a function"
MOCK_MODEL_ANSWER = "def function(): pass"


class TestSystemPromptAPI:
Expand All @@ -25,40 +25,54 @@ def client(self):
with app.test_client() as client:
yield client

@patch('markus_ai_server.server.REDIS_CONNECTION')
@patch('markus_ai_server.server.chat_with_model')
def test_api_with_system_prompt(self, mock_chat, mock_redis, client):
"""Test /chat endpoint receives and passes system_prompt."""
def _post_chat_and_assert_prompt_forwarded(self, client, mock_chat, mock_redis, form_fields, expected_prompt):
"""POST /chat with a valid key and assert the resolved system prompt reaches the model."""
mock_redis.get.return_value = b'test_user'
mock_chat.return_value = "def function(): pass"
mock_chat.return_value = MOCK_MODEL_ANSWER

response = client.post(
'/chat',
headers={'X-API-KEY': 'test-key'},
data={'model': TEST_MODEL, 'content': TEST_USER_CONTENT, 'system_prompt': TEST_SYSTEM_PROMPT},
data={'model': TEST_MODEL, 'content': TEST_USER_CONTENT, **form_fields},
)

assert response.status_code == 200

mock_chat.assert_called_once_with(
TEST_MODEL, TEST_USER_CONTENT, 'cli', TEST_SYSTEM_PROMPT, [], json_schema=None, model_options=None
TEST_MODEL, TEST_USER_CONTENT, 'cli', expected_prompt, [], json_schema=None, model_options=None
)

@patch('markus_ai_server.server.REDIS_CONNECTION')
@patch('markus_ai_server.server.chat_with_model')
def test_api_with_system_prompt(self, mock_chat, mock_redis, client):
"""Test /chat endpoint receives and passes system_prompt."""
self._post_chat_and_assert_prompt_forwarded(
client, mock_chat, mock_redis, {'system_prompt': TEST_SYSTEM_PROMPT}, TEST_SYSTEM_PROMPT
)

@patch('markus_ai_server.server.REDIS_CONNECTION')
@patch('markus_ai_server.server.chat_with_model')
def test_api_without_system_prompt(self, mock_chat, mock_redis, client):
"""Test /chat endpoint works without system_prompt."""
mock_redis.get.return_value = b'test_user'
mock_chat.return_value = "def function(): pass"
self._post_chat_and_assert_prompt_forwarded(client, mock_chat, mock_redis, {}, None)

response = client.post(
'/chat', headers={'X-API-KEY': 'test-key'}, data={'model': TEST_MODEL, 'content': TEST_USER_CONTENT}
@patch('markus_ai_server.server.REDIS_CONNECTION')
@patch('markus_ai_server.server.chat_with_model')
def test_api_accepts_system_instructions_alias(self, mock_chat, mock_redis, client):
"""The ai_feedback RemoteModel sends 'system_instructions'; it must be honored."""
self._post_chat_and_assert_prompt_forwarded(
client, mock_chat, mock_redis, {'system_instructions': TEST_SYSTEM_PROMPT}, TEST_SYSTEM_PROMPT
)

assert response.status_code == 200

mock_chat.assert_called_once_with(
TEST_MODEL, TEST_USER_CONTENT, 'cli', None, [], model_options=None, json_schema=None
@patch('markus_ai_server.server.REDIS_CONNECTION')
@patch('markus_ai_server.server.chat_with_model')
def test_system_prompt_wins_over_alias(self, mock_chat, mock_redis, client):
"""When both fields are sent, 'system_prompt' takes precedence."""
self._post_chat_and_assert_prompt_forwarded(
client,
mock_chat,
mock_redis,
{'system_prompt': TEST_SYSTEM_PROMPT, 'system_instructions': 'ignored alias'},
TEST_SYSTEM_PROMPT,
)

@patch('markus_ai_server.server.REDIS_CONNECTION')
Expand Down