loosecanvas / tests /test_response_format.py
Joshua Sundance Bailey
loosecanvas: local AI thought-mapping canvas with a trust-tagged knowledge graph
6d1438c
Raw
History Blame Contribute Delete
2.34 kB
"""Unit tests for M02 — the ``response_format`` payload builder.
These assert the OpenAI-standard ``json_schema`` wrapper shape (the only form
empirically verified to enforce on the current llama.cpp server image; see Q2)
and the fail-closed schema hardening (inline enum, ``additionalProperties: false``,
no surviving ``$defs`` indirection). No live server is required.
"""
from __future__ import annotations
import json
from typing import Any
import pytest
from loosecanvas.contracts import SceneAction, SceneActionType, ScenePlan
from loosecanvas.response_format import SCENEPLAN_RESPONSE_FORMAT
def _nested_schema() -> dict[str, Any]:
return SCENEPLAN_RESPONSE_FORMAT["json_schema"]["schema"]
def test_response_format_is_json_serializable() -> None:
# Must not raise — fed verbatim to the server as JSON.
json.dumps(SCENEPLAN_RESPONSE_FORMAT)
def test_response_format_wrapper_shape() -> None:
assert SCENEPLAN_RESPONSE_FORMAT["type"] == "json_schema"
json_schema = SCENEPLAN_RESPONSE_FORMAT["json_schema"]
assert json_schema["name"] == "scene_plan"
assert json_schema["strict"] is True
# The schema is nested under json_schema["schema"], not at the top level.
assert "schema" in json_schema
def test_nested_schema_forbids_additional_properties() -> None:
schema = _nested_schema()
assert schema["additionalProperties"] is False
action_schema = schema["properties"]["actions"]["items"]
assert action_schema["additionalProperties"] is False
def test_nested_schema_has_no_defs_indirection() -> None:
schema = _nested_schema()
assert "$defs" not in schema
def test_action_type_enum_is_inline_and_complete() -> None:
schema = _nested_schema()
type_schema = schema["properties"]["actions"]["items"]["properties"]["type"]
assert "$ref" not in type_schema
assert set(type_schema["enum"]) == {t.value for t in SceneActionType}
def test_schema_validates_a_real_sceneplan_instance() -> None:
instance = ScenePlan(
actions=[
SceneAction(
type=SceneActionType.explain_no_change, reasoning="nothing to do"
)
],
summary="no change",
).model_dump(mode="json")
jsonschema = pytest.importorskip("jsonschema")
jsonschema.validate(instance=instance, schema=_nested_schema())