Skip to content

Commit f3c9770

Browse files
committed
Add basic support for passing error messages from API to UI while streaming
1 parent 3cef0f7 commit f3c9770

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

ragna/deploy/_api/core.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,16 @@ async def answer(
296296
)
297297
core_chat = schema_to_core_chat(session, user=user, chat=chat)
298298

299-
core_answer = await core_chat.answer(prompt, stream=stream)
299+
# smoke test to catch errors unrelated to streaming
300+
# longer-term solution tracked by #409
301+
try:
302+
core_answer = await core_chat.answer(prompt, stream=stream)
303+
_ = await anext(aiter(core_answer))
304+
except Exception as e:
305+
raise HTTPException(
306+
status_code=500,
307+
detail=str(e),
308+
) from e
300309

301310
if stream:
302311

tests/deploy/api/test_streaming.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import io
2+
import json
3+
4+
import pytest
5+
from fastapi.testclient import TestClient
6+
7+
from ragna.core import Assistant, SourceStorage
8+
from ragna.deploy import Config
9+
from ragna.deploy._api import app
10+
11+
from .utils import authenticate
12+
13+
14+
class FakeAssistant(Assistant):
15+
def answer(self, prompt, sources):
16+
if prompt == "Assistant Error":
17+
raise Exception("Assistant Error")
18+
19+
20+
class FakeSourceStorage(SourceStorage):
21+
async def store(self, documents):
22+
pass
23+
24+
async def retrieve(self, documents, prompt):
25+
if prompt == "SourceStorage Error":
26+
raise Exception("SourceStorage Error")
27+
28+
29+
@pytest.mark.parametrize("prompt", ["Assistant Error", "SourceStorage Error"])
30+
def test_internal_server_error_response(tmp_local_root, prompt):
31+
config = Config(
32+
local_root=tmp_local_root,
33+
assistants=[FakeAssistant],
34+
source_storages=[FakeSourceStorage],
35+
)
36+
37+
with TestClient(app(config=config, ignore_unavailable_components=False)) as client:
38+
authenticate(client)
39+
40+
document_upload = (
41+
client.post("/document", json={"name": "fake.txt"})
42+
.raise_for_status()
43+
.json()
44+
)
45+
document = document_upload["document"]
46+
parameters = document_upload["parameters"]
47+
client.request(
48+
parameters["method"],
49+
parameters["url"],
50+
data=parameters["data"],
51+
files={"file": io.BytesIO(b"!")},
52+
)
53+
54+
chat_metadata = {
55+
"name": "test-chat",
56+
"source_storage": "FakeSourceStorage",
57+
"assistant": "FakeAssistant",
58+
"params": {},
59+
"documents": [document],
60+
}
61+
chat = client.post("/chats", json=chat_metadata).raise_for_status().json()
62+
63+
_ = client.post(f"/chats/{chat['id']}/prepare").raise_for_status().json()
64+
65+
with client.stream(
66+
"POST",
67+
f"/chats/{chat['id']}/answer",
68+
json={"prompt": prompt, "stream": True},
69+
) as response:
70+
r = response.read()
71+
72+
assert response.status_code == 500
73+
74+
assert json.loads(r.decode("utf-8"))["detail"] == prompt

0 commit comments

Comments
 (0)