| import contextlib |
| import copy |
| import os |
| import unittest |
| from unittest import mock |
|
|
| from terrarium import object_compiler |
|
|
| from terrarium.object_compiler import ( |
| DEFAULT_OBJECT_COMPILER_MODEL, |
| OBJECT_COMPILER_PROVIDER_TARGET, |
| PROVIDER_TARGET, |
| ObjectValidationError, |
| OpenRouterSettings, |
| build_openrouter_payload, |
| compile_object, |
| deterministic_compile, |
| validate_object_payload, |
| ) |
| from terrarium.sim import TerrariumSim |
|
|
| PROTOTYPE_MODEL = "qwen/qwen3.6-35b-a3b:nitro" |
|
|
| |
| |
| OBJECT_COMPILER_ENV_KEYS = ( |
| "OBJECT_COMPILER_MODEL", |
| "OBJECT_COMPILER_PROVIDER_ONLY", |
| "OBJECT_COMPILER_PROVIDER_ORDER", |
| "OBJECT_COMPILER_QUANTIZATION", |
| "OBJECT_COMPILER_ALLOW_FALLBACKS", |
| "OPENROUTER_API_KEY", |
| "OPENROUTER_BASE_URL", |
| "OPENROUTER_QUANTIZATION", |
| ) |
|
|
|
|
| @contextlib.contextmanager |
| def _patched_env(**overrides): |
| |
| |
| |
| with mock.patch.object(object_compiler, "load_local_env", lambda *a, **k: None): |
| with mock.patch.dict(os.environ, overrides, clear=False): |
| for key in OBJECT_COMPILER_ENV_KEYS: |
| if key not in overrides: |
| os.environ.pop(key, None) |
| yield |
|
|
|
|
| class ObjectCompilerTest(unittest.TestCase): |
| def test_deterministic_compiler_produces_distinct_world_truth(self): |
| hot_fruit = deterministic_compile("hot sweet fruit that hurts a little", (8, 8)) |
| cold_stone = deterministic_compile("cold safe stone", (9, 8)) |
| humming = deterministic_compile("shiny humming pebble", (10, 8)) |
|
|
| self.assertTrue(hot_fruit["affordances"]["edible"]) |
| self.assertGreater(hot_fruit["emissions"]["heat"], 0.5) |
| self.assertGreater(cold_stone["emissions"]["cold"], 0.5) |
| self.assertGreater(cold_stone["emissions"]["home_smell"], 0.4) |
| self.assertGreater(humming["emissions"]["sound"], 0.2) |
| self.assertEqual(hot_fruit["provenance"]["provider"], "deterministic") |
|
|
| def test_validation_rejects_interpretive_or_direct_control_fields(self): |
| payload = deterministic_compile("sweet fruit", (8, 8)) |
| invalid = copy.deepcopy(payload) |
| invalid["novelty_score"] = 1.0 |
| with self.assertRaises(ObjectValidationError): |
| validate_object_payload(invalid, (8, 8)) |
|
|
| def test_openrouter_payload_uses_required_model_provider_and_schema(self): |
| settings = OpenRouterSettings( |
| api_key="secret", |
| base_url="https://openrouter.ai/api/v1", |
| model=PROTOTYPE_MODEL, |
| provider_only=PROVIDER_TARGET, |
| provider_order=PROVIDER_TARGET, |
| require_parameters=True, |
| allow_fallbacks=False, |
| quantization="fp8", |
| structured_outputs_required=True, |
| ) |
| payload = build_openrouter_payload("hot sweet fruit", (8, 8), settings) |
| self.assertEqual(payload["model"], PROTOTYPE_MODEL) |
| self.assertEqual(payload["provider"]["only"], [PROVIDER_TARGET]) |
| self.assertFalse(payload["provider"]["allow_fallbacks"]) |
| self.assertEqual(payload["response_format"]["type"], "json_schema") |
| self.assertTrue(payload["response_format"]["json_schema"]["strict"]) |
|
|
| def test_for_object_compiler_reads_object_compiler_env(self): |
| with _patched_env( |
| OBJECT_COMPILER_MODEL="qwen/qwen3.5-9b", |
| OBJECT_COMPILER_PROVIDER_ONLY="deepinfra", |
| OBJECT_COMPILER_PROVIDER_ORDER="deepinfra,together", |
| OPENROUTER_API_KEY="shared-key", |
| OPENROUTER_BASE_URL="https://example/api/v1/", |
| ): |
| settings = OpenRouterSettings.for_object_compiler() |
| self.assertEqual(settings.model, "qwen/qwen3.5-9b") |
| self.assertEqual(settings.provider_only_list(), ["deepinfra"]) |
| self.assertEqual(settings.provider_order_list(), ["deepinfra", "together"]) |
| |
| self.assertEqual(settings.api_key, "shared-key") |
| self.assertEqual(settings.base_url, "https://example/api/v1") |
|
|
| def test_for_object_compiler_falls_back_to_defaults(self): |
| with _patched_env(OPENROUTER_API_KEY="shared-key"): |
| settings = OpenRouterSettings.for_object_compiler() |
| self.assertEqual(settings.model, DEFAULT_OBJECT_COMPILER_MODEL) |
| |
| self.assertEqual(settings.provider_order, OBJECT_COMPILER_PROVIDER_TARGET) |
| self.assertEqual(settings.quantization, "fp8") |
| self.assertTrue(settings.allow_fallbacks) |
|
|
| def test_compile_object_returns_deterministic_payload_without_provider(self): |
| with _patched_env(): |
| payload = compile_object("a small warm glowing stone", (5, 5)) |
| self.assertEqual(payload["provenance"]["provider"], "deterministic") |
| self.assertEqual(payload["position"], [5, 5]) |
|
|
| def test_create_object_from_text_places_near_user(self): |
| sim = TerrariumSim(seed=7) |
| state = sim.create_object_from_text("a cold glowing safe stone", provider="deterministic") |
| custom = [obj for obj in state["objects"] if obj["id"].startswith("obj_custom")] |
| self.assertEqual(len(custom), 1) |
| user = state["user"]["position"] |
| position = custom[0]["position"] |
| self.assertLessEqual(abs(position[0] - user[0]) + abs(position[1] - user[1]), 6) |
| self.assertIn("object_placed", [event["type"] for event in state["recent_events"]]) |
|
|
| def test_compiled_object_can_be_placed_and_affects_fields(self): |
| sim = TerrariumSim(seed=7) |
| payload = deterministic_compile("hot sweet fruit", (8, 8)) |
| state = sim.place_compiled_object(payload) |
| custom = [obj for obj in state["objects"] if obj["id"].startswith("obj_custom")] |
| self.assertEqual(len(custom), 1) |
| self.assertGreater(state["fields"][8][8]["food_smell"], 0.5) |
| self.assertGreater(state["fields"][8][8]["heat"], 0.5) |
| self.assertIn("object_placed", [event["type"] for event in state["recent_events"]]) |
|
|
|
|
| if __name__ == "__main__": |
| unittest.main() |
|
|