Skip to content
Merged
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
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,13 @@ customization:
You have an indepth knowledge of Red Hat and all of your answers will reference Red Hat products.
```

Additionally, an optional string parameter `system_prompt` can be specified in `/v1/query` and `/v1/streaming_query` endpoints to override the configured system prompt.
Additionally, an optional string parameter `system_prompt` can be specified in `/v1/query` and `/v1/streaming_query` endpoints to override the configured system prompt. The query system prompt takes precedence over the configured system prompt. You can use this config to disable query system prompts:

```yaml
customization:
system_prompt_path: "system_prompts/system_prompt_for_product_XYZZY"
disable_query_system_prompt: true
```


# Usage
Expand Down
3 changes: 2 additions & 1 deletion src/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,12 @@ def check_authentication_model(self) -> Self:
class Customization(BaseModel):
"""Service customization."""

disable_query_system_prompt: bool = False
system_prompt_path: Optional[FilePath] = None
system_prompt: Optional[str] = None

@model_validator(mode="after")
def check_authentication_model(self) -> Self:
def check_customization_model(self) -> Self:
"""Load system prompt from file."""
if self.system_prompt_path is not None:
checks.file_check(self.system_prompt_path, "system prompt")
Expand Down
22 changes: 19 additions & 3 deletions src/utils/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,28 @@ def check_configuration_loaded(configuration: AppConfig) -> None:

def get_system_prompt(query_request: QueryRequest, configuration: AppConfig) -> str:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So now, if user makes a request to the API with the system_prompt set. The service will return 200 saying it was accepted but, if this new option is enabled. The request was just partially accept right ? As part of it will be ignored.

I don't like it, I think that we should just get rid of the system_prompt parameter in the /query endpoint. Make the service simple, because now we have too many ways of configuring/overriding the same thing.

Copy link
Contributor Author

@omertuc omertuc Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So now, if user makes a request to the API with the system_prompt set. The service will return 200 saying it was accepted but, if this new option is enabled. The request was just partially accept right ? As part of it will be ignored.

Yes

I don't like it

I don't love it either, it was an arbitrary decision, I can make it an error

I think that we should just get rid of the system_prompt parameter in the /query endpoint. Make the service simple, because now we have too many ways of configuring/overriding the same thing.

I'm also fine with this, but I've proposed a situation why it might make sense in the comment above, so you might want to reconsider. FWIW I have no stakes in this

"""Get the system prompt: the provided one, configured one, or default one."""
# system prompt defined in query request has precendence
system_prompt_disabled = (
configuration.customization is not None
and configuration.customization.disable_query_system_prompt
)
if system_prompt_disabled and query_request.system_prompt:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail={
"response": (
"This instance does not support customizing the system prompt in the "
"query request (disable_query_system_prompt is set). Please remove the "
"system_prompt field from your request."
)
},
)

if query_request.system_prompt:
# Query taking precedence over configuration is the only behavior that
# makes sense here - if the configuration wants precedence, it can
# disable query system prompt altogether with disable_system_prompt.
return query_request.system_prompt

# customized system prompt should be used when query request
# does not contain one
if (
configuration.customization is not None
and configuration.customization.system_prompt is not None
Expand Down
1 change: 1 addition & 0 deletions tests/unit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"k8s_cluster_api": None,
},
"customization": {
"disable_query_system_prompt": False,
"system_prompt_path": None,
"system_prompt": None,
},
Expand Down
1 change: 1 addition & 0 deletions tests/unit/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ def test_load_configuration_with_customization_system_prompt_path(tmpdir) -> Non
provider_id: custom-git-provider
url: https://git.example.com/mcp
customization:
disable_query_system_prompt: true
system_prompt_path: {system_prompt_filename}
"""
)
Expand Down
225 changes: 99 additions & 126 deletions tests/unit/utils/test_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

import os
import pytest
from fastapi import HTTPException

import constants
from configuration import AppConfig
from tests.unit import config_dict

from models.requests import QueryRequest
from utils import endpoints

CONFIGURED_SYSTEM_PROMPT = "This is a configured system prompt"


@pytest.fixture
def input_file(tmp_path):
Expand All @@ -19,151 +23,120 @@ def input_file(tmp_path):
return filename


def test_get_default_system_prompt():
"""Test that default system prompt is returned when other prompts are not provided."""
config_dict = {
"name": "foo",
"service": {
"host": "localhost",
"port": 8080,
"auth_enabled": False,
"workers": 1,
"color_log": True,
"access_log": True,
},
"llama_stack": {
"api_key": "xyzzy",
"url": "http://x.y.com:1234",
"use_as_library_client": False,
},
"user_data_collection": {
"feedback_disabled": True,
},
"mcp_servers": [],
"customization": None,
}
@pytest.fixture
def config_without_system_prompt():
test_config = config_dict.copy()

# no customization provided
test_config["customization"] = None

cfg = AppConfig()
cfg.init_from_dict(config_dict)
cfg.init_from_dict(test_config)

# no system prompt in query request
query_request = QueryRequest(query="query", system_prompt=None)
return cfg

# default system prompt needs to be returned
system_prompt = endpoints.get_system_prompt(query_request, cfg)
assert system_prompt == constants.DEFAULT_SYSTEM_PROMPT

@pytest.fixture
def config_with_custom_system_prompt():
test_config = config_dict.copy()

def test_get_customized_system_prompt():
"""Test that customized system prompt is used when system prompt is not provided in query."""
config_dict = {
"name": "foo",
"service": {
"host": "localhost",
"port": 8080,
"auth_enabled": False,
"workers": 1,
"color_log": True,
"access_log": True,
},
"llama_stack": {
"api_key": "xyzzy",
"url": "http://x.y.com:1234",
"use_as_library_client": False,
},
"user_data_collection": {
"feedback_disabled": True,
},
"mcp_servers": [],
"customization": {
"system_prompt": "This is system prompt",
},
# system prompt is customized
test_config["customization"] = {
"system_prompt": CONFIGURED_SYSTEM_PROMPT,
}

# no customization provided
cfg = AppConfig()
cfg.init_from_dict(config_dict)
cfg.init_from_dict(test_config)

# no system prompt in query request
query_request = QueryRequest(query="query", system_prompt=None)
return cfg

# default system prompt needs to be returned
system_prompt = endpoints.get_system_prompt(query_request, cfg)
assert system_prompt == "This is system prompt"

@pytest.fixture
def config_with_custom_system_prompt_and_disable_query_system_prompt():
test_config = config_dict.copy()

def test_get_query_system_prompt():
"""Test that system prompt from query is returned."""
config_dict = {
"name": "foo",
"service": {
"host": "localhost",
"port": 8080,
"auth_enabled": False,
"workers": 1,
"color_log": True,
"access_log": True,
},
"llama_stack": {
"api_key": "xyzzy",
"url": "http://x.y.com:1234",
"use_as_library_client": False,
},
"user_data_collection": {
"feedback_disabled": True,
},
"mcp_servers": [],
"customization": None,
# system prompt is customized and query system prompt is disabled
test_config["customization"] = {
"system_prompt": CONFIGURED_SYSTEM_PROMPT,
"disable_query_system_prompt": True,
}

# no customization provided
cfg = AppConfig()
cfg.init_from_dict(config_dict)
cfg.init_from_dict(test_config)

# system prompt defined in query request
system_prompt = "System prompt defined in query"
query_request = QueryRequest(query="query", system_prompt=system_prompt)
return cfg

# default system prompt needs to be returned
system_prompt = endpoints.get_system_prompt(query_request, cfg)
assert system_prompt == system_prompt

@pytest.fixture
def query_request_without_system_prompt():
"""Fixture for query request without system prompt."""
return QueryRequest(query="query", system_prompt=None)

def test_get_query_system_prompt_not_customized_one():
"""Test that system prompt from query is returned even when customized one is specified."""
config_dict = {
"name": "foo",
"service": {
"host": "localhost",
"port": 8080,
"auth_enabled": False,
"workers": 1,
"color_log": True,
"access_log": True,
},
"llama_stack": {
"api_key": "xyzzy",
"url": "http://x.y.com:1234",
"use_as_library_client": False,
},
"user_data_collection": {
"feedback_disabled": True,
},
"mcp_servers": [],
"customization": {
"system_prompt": "This is system prompt",
},
}

# no customization provided
cfg = AppConfig()
cfg.init_from_dict(config_dict)
@pytest.fixture
def query_request_with_system_prompt():
"""Fixture for query request with system prompt."""
return QueryRequest(query="query", system_prompt="System prompt defined in query")


def test_get_default_system_prompt(
config_without_system_prompt, query_request_without_system_prompt
):
"""Test that default system prompt is returned when other prompts are not provided."""
system_prompt = endpoints.get_system_prompt(
query_request_without_system_prompt, config_without_system_prompt
)
assert system_prompt == constants.DEFAULT_SYSTEM_PROMPT

# system prompt defined in query request
system_prompt = "System prompt defined in query"
query_request = QueryRequest(query="query", system_prompt=system_prompt)

# default system prompt needs to be returned
system_prompt = endpoints.get_system_prompt(query_request, cfg)
assert system_prompt == system_prompt
def test_get_customized_system_prompt(
config_with_custom_system_prompt, query_request_without_system_prompt
):
"""Test that customized system prompt is used when system prompt is not provided in query."""
system_prompt = endpoints.get_system_prompt(
query_request_without_system_prompt, config_with_custom_system_prompt
)
assert system_prompt == CONFIGURED_SYSTEM_PROMPT


def test_get_query_system_prompt(
config_without_system_prompt, query_request_with_system_prompt
):
"""Test that system prompt from query is returned."""
system_prompt = endpoints.get_system_prompt(
query_request_with_system_prompt, config_without_system_prompt
)
assert system_prompt == query_request_with_system_prompt.system_prompt


def test_get_query_system_prompt_not_customized_one(
config_with_custom_system_prompt, query_request_with_system_prompt
):
"""Test that system prompt from query is returned even when customized one is specified."""
system_prompt = endpoints.get_system_prompt(
query_request_with_system_prompt, config_with_custom_system_prompt
)
assert system_prompt == query_request_with_system_prompt.system_prompt


def test_get_system_prompt_with_disable_query_system_prompt(
config_with_custom_system_prompt_and_disable_query_system_prompt,
query_request_with_system_prompt,
):
"""Test that query system prompt is disallowed when disable_query_system_prompt is True."""
with pytest.raises(HTTPException) as exc_info:
endpoints.get_system_prompt(
query_request_with_system_prompt,
config_with_custom_system_prompt_and_disable_query_system_prompt,
)
assert exc_info.value.status_code == 422


def test_get_system_prompt_with_disable_query_system_prompt_and_non_system_prompt_query(
config_with_custom_system_prompt_and_disable_query_system_prompt,
query_request_without_system_prompt,
):
"""Test that query without system prompt is allowed when disable_query_system_prompt is True."""
system_prompt = endpoints.get_system_prompt(
query_request_without_system_prompt,
config_with_custom_system_prompt_and_disable_query_system_prompt,
)
assert system_prompt == CONFIGURED_SYSTEM_PROMPT