mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-13 00:14:02 +00:00
test(v1): align tests with valid-chunk envelope and leak-strip signature
- test_standard_clients_can_ignore_docsgpt: docsgpt-only events now ride
on a valid empty chat.completion.chunk (choices[0].delta == {}) so
strict OpenAI clients accept the frame; assert the envelope plus the
docsgpt extension instead of the absence of choices.
- split continuation persistence into stateful (conversation_id present
-> save) and stateless (no conversation_id -> no save) cases.
- _fake_translate_stream_event mock accepts strip_reasoning_leak kwarg.
This commit is contained in:
1 parent
37417f99c8
commit
b212c5cedd
2 files changed
+37
-8
No files matched your search
@@ -541,7 +541,9 @@ class TestChatCompletionsHappyPath:
|
||||
|
||||
translated_chunks: list = []
|
||||
|
||||
def _fake_translate_stream_event(event_data, completion_id, model_name):
|
||||
def _fake_translate_stream_event(
|
||||
event_data, completion_id, model_name, strip_reasoning_leak=False
|
||||
):
|
||||
translated_chunks.append(event_data)
|
||||
return ['data: x\n\n']
|
||||
|
||||
|
||||
@@ -245,10 +245,12 @@ class TestTranslateRequest:
|
||||
assert len(result["tool_actions"]) == 1
|
||||
assert result["tool_actions"][0]["call_id"] == "c1"
|
||||
|
||||
def test_continuation_persists_by_default(self):
|
||||
"""A continuation implies the first turn was saved, so the resumed turn
|
||||
must persist too (otherwise the final answer + WAL row are lost)."""
|
||||
def test_stateful_continuation_persists_by_default(self):
|
||||
"""A stateful continuation (conversation_id present) implies the first
|
||||
turn was saved, so the resumed turn must persist too (otherwise the
|
||||
final answer + WAL row are lost)."""
|
||||
data = {
|
||||
"conversation_id": "conv-1",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Search for X"},
|
||||
{
|
||||
@@ -261,6 +263,23 @@ class TestTranslateRequest:
|
||||
result = translate_request(data, "key")
|
||||
assert result["save_conversation"] is True
|
||||
|
||||
def test_stateless_continuation_does_not_persist_by_default(self):
|
||||
"""A stateless continuation (no conversation_id, e.g. an OpenAI client
|
||||
such as opencode) never persisted turn 1, so it must NOT default to
|
||||
saving -- otherwise every tool round leaks an orphan conversation."""
|
||||
data = {
|
||||
"messages": [
|
||||
{"role": "user", "content": "Search for X"},
|
||||
{
|
||||
"role": "assistant",
|
||||
"tool_calls": [{"id": "c1", "type": "function", "function": {"name": "search", "arguments": "{}"}}],
|
||||
},
|
||||
{"role": "tool", "tool_call_id": "c1", "content": "done"},
|
||||
],
|
||||
}
|
||||
result = translate_request(data, "key")
|
||||
assert result["save_conversation"] is False
|
||||
|
||||
def test_continuation_honours_explicit_save_conversation_override(self):
|
||||
"""An explicit docsgpt.save_conversation=false on the continuation wins."""
|
||||
data = {
|
||||
@@ -650,15 +669,23 @@ class TestTranslateStreamEvent:
|
||||
assert parsed["docsgpt"]["type"] == "tool_call"
|
||||
|
||||
def test_standard_clients_can_ignore_docsgpt(self):
|
||||
"""Standard clients parse only 'choices' — docsgpt namespace is ignored."""
|
||||
"""The docsgpt namespace rides on a valid empty chat.completion.chunk.
|
||||
|
||||
Standard OpenAI clients validate every streamed frame as a
|
||||
``chat.completion.chunk``; a frame without ``choices`` is rejected.
|
||||
So docsgpt-only events (sources, ids, tool_calls) are emitted as a
|
||||
valid chunk with an empty delta plus a ``docsgpt`` extension that
|
||||
standard parsers simply ignore.
|
||||
"""
|
||||
chunks = translate_stream_event(
|
||||
{"type": "source", "source": [{"title": "t"}]},
|
||||
"chatcmpl-1", "agent",
|
||||
)
|
||||
parsed = json.loads(chunks[0].replace("data: ", "").strip())
|
||||
# No "choices" key — standard parsers skip this chunk entirely
|
||||
assert "choices" not in parsed
|
||||
# docsgpt key is present
|
||||
# Valid chunk envelope: standard parsers read choices[0].delta (empty)
|
||||
assert isinstance(parsed.get("choices"), list)
|
||||
assert parsed["choices"][0]["delta"] == {}
|
||||
# docsgpt extension is present for clients that want it
|
||||
assert "docsgpt" in parsed
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user