Compare commits
2 commits
main
...
fix-respon
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09f470b45b | ||
|
|
85840e7e4d |
2 changed files with 45 additions and 0 deletions
|
|
@ -2797,6 +2797,13 @@ def _normalise_responses_input(payload: ResponsesRequest) -> list[ChatMessage]:
|
||||||
output = item.output
|
output = item.output
|
||||||
if not isinstance(output, str):
|
if not isinstance(output, str):
|
||||||
output = json.dumps(output)
|
output = json.dumps(output)
|
||||||
|
if not output:
|
||||||
|
# An empty/falsy result (e.g. an image-only tool output whose
|
||||||
|
# payload lives outside `output`) would otherwise build a
|
||||||
|
# role="tool" ChatMessage with content="", which the strict
|
||||||
|
# validator rejects with a 500. Emit a placeholder so the turn
|
||||||
|
# normalises gracefully.
|
||||||
|
output = "(no output)"
|
||||||
messages.append(
|
messages.append(
|
||||||
ChatMessage(
|
ChatMessage(
|
||||||
role = "tool",
|
role = "tool",
|
||||||
|
|
|
||||||
|
|
@ -374,6 +374,44 @@ class TestNormaliseResponsesInputWithTools:
|
||||||
# Content is serialised so llama-server sees a string.
|
# Content is serialised so llama-server sees a string.
|
||||||
assert json.loads(msgs[0].content) == [{"type": "output_text", "text": "ok"}]
|
assert json.loads(msgs[0].content) == [{"type": "output_text", "text": "ok"}]
|
||||||
|
|
||||||
|
def test_empty_tool_output_replaced_with_placeholder(self):
|
||||||
|
"""Image-only tool results (Anthropic format) send empty output.
|
||||||
|
Before the fix this crashed the validator with
|
||||||
|
"role=\"tool\" messages require non-empty \"content\"".
|
||||||
|
Now it emits "(no output)" so the turn normalises cleanly."""
|
||||||
|
payload = ResponsesRequest(
|
||||||
|
input = [
|
||||||
|
{
|
||||||
|
"type": "function_call_output",
|
||||||
|
"call_id": "call_1",
|
||||||
|
"output": "",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
msgs = _normalise_responses_input(payload)
|
||||||
|
assert msgs[0].role == "tool"
|
||||||
|
assert msgs[0].tool_call_id == "call_1"
|
||||||
|
assert msgs[0].content == "(no output)"
|
||||||
|
# Round-trip through ChatMessage validator must not raise.
|
||||||
|
ChatMessage(**msgs[0].model_dump(exclude_none = True))
|
||||||
|
|
||||||
|
def test_empty_list_output_serialised_to_json_array(self):
|
||||||
|
"""Empty list output is not falsy after json.dumps (becomes "[]"),
|
||||||
|
so it should not trigger the placeholder."""
|
||||||
|
payload = ResponsesRequest(
|
||||||
|
input = [
|
||||||
|
{
|
||||||
|
"type": "function_call_output",
|
||||||
|
"call_id": "call_1",
|
||||||
|
"output": [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
msgs = _normalise_responses_input(payload)
|
||||||
|
assert msgs[0].role == "tool"
|
||||||
|
assert msgs[0].content == "[]"
|
||||||
|
ChatMessage(**msgs[0].model_dump(exclude_none = True))
|
||||||
|
|
||||||
|
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
# Response mapping — tool_calls → function_call output items
|
# Response mapping — tool_calls → function_call output items
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue