import re from app.agents.shell_visual_engine import ShellGrounding, ShellSetupCode, ShellVisualEngine class _FakeClient: def __init__(self, obj): self._obj = obj def structured_complete(self, messages, schema, **kw): return self._obj def test_extract_grounding_3d_happy_path_keeps_anchor(): chunks = [{"source": "paper.pdf", "text": "The hemoglobin molecule forms a tetramer of four globular subunits."}] grounding = ShellGrounding( renderable=True, anchor="forms a tetramer of four globular subunits", scene_brief="Render hemoglobin as four globular subunits arranged as a tetramer.", ) engine = ShellVisualEngine(client=_FakeClient(grounding)) result = engine._extract_grounding("hemoglobin", "3d", chunks, "high_school") assert result.renderable is True assert result.anchor == "forms a tetramer of four globular subunits" assert result.scene_brief == "Render hemoglobin as four globular subunits arranged as a tetramer." def test_extract_grounding_2d_anim_happy_path_keeps_anchor(): chunks = [{"source": "paper.pdf", "text": "During depolarization, sodium ions rush into the cell, flipping the membrane potential."}] grounding = ShellGrounding( renderable=True, anchor="sodium ions rush into the cell, flipping the membrane potential", scene_brief="Animate sodium ions flowing into the cell as the membrane potential flips positive.", ) engine = ShellVisualEngine(client=_FakeClient(grounding)) result = engine._extract_grounding("depolarization", "2d_anim", chunks, "high_school") assert result.renderable is True assert result.anchor == "sodium ions rush into the cell, flipping the membrane potential" assert result.scene_brief == "Animate sodium ions flowing into the cell as the membrane potential flips positive." def test_extract_grounding_decline_path_returned_as_is(): chunks = [{"source": "paper.pdf", "text": "This section discusses abstract policy tradeoffs with no physical form."}] grounding = ShellGrounding( renderable=False, decline_reason="'policy tradeoffs' has no concrete spatial object in the source — better explored in chat.", ) engine = ShellVisualEngine(client=_FakeClient(grounding)) result = engine._extract_grounding("policy tradeoffs", "3d", chunks, "high_school") assert result.renderable is False assert result.anchor == "" assert result.decline_reason == "'policy tradeoffs' has no concrete spatial object in the source — better explored in chat." def test_extract_grounding_discards_hallucinated_anchor(): chunks = [{"source": "paper.pdf", "text": "The heart has four chambers that pump blood through the body."}] grounding = ShellGrounding( renderable=True, anchor="this text was never in the source at all", scene_brief="Render a four-chambered heart pumping blood.", ) engine = ShellVisualEngine(client=_FakeClient(grounding)) result = engine._extract_grounding("heart anatomy", "3d", chunks, "high_school") assert result.renderable is True assert result.anchor == "" assert result.scene_brief == "Render a four-chambered heart pumping blood." def _engine(): return ShellVisualEngine(client=_FakeClient(None)) def test_assemble_shell_replaces_setup_code_token_for_both_kinds(): engine = _engine() for kind in ("3d", "2d_anim"): html = engine._assemble_shell(kind, "group.add(new THREE.Mesh());" + "x" * 30) assert "{SETUP_CODE_JSON}" not in html def test_assemble_shell_escapes_hostile_script_close_tag(): hostile = "group.add(new THREE.Mesh()); /* */" engine = _engine() for kind in ("3d", "2d_anim"): html = engine._assemble_shell(kind, hostile) # The raw closing tag from the hostile string must never survive unescaped. assert "" not in html # It must appear only in its escaped form -- both occurrences from the # hostile string end up as the literal 3-char sequence <\/script>. assert html.count("<\\/script>") == 2 def test_assemble_shell_globals_lockdown_params_present_for_both_kinds(): shadowed_names = ["window", "document", "fetch", "eval", "parent", "top", "self", "Function"] engine = _engine() for kind in ("3d", "2d_anim"): html = engine._assemble_shell(kind, "y" * 40) for name in shadowed_names: assert f'"{name}"' in html def test_assemble_shell_globals_lockdown_param_and_arg_counts_match_for_both_kinds(): """Regression guard for the parity the module docstring calls out: the `new Function("api", , SETUP_CODE_JSON)` parameter list and the real invocation `contentFn(api, undefined, undefined, ...)` must pass exactly the same number of positional arguments -- one real value (`api`) plus exactly one `undefined` per shadowed name. If a future edit added or removed a shadowed name in only one of the two spots, it would either leave a dangerous global un-shadowed (security gap) or throw a runtime arity mismatch -- nothing else in this file catches that today. """ engine = _engine() for kind in ("3d", "2d_anim"): html = engine._assemble_shell(kind, "v" * 40) function_call_match = re.search(r"new Function\(([^)]*)\)", html) assert function_call_match, f"could not find a `new Function(...)` call for kind={kind}" # Every argument to `new Function` here is a quoted string literal -- # the shadowed param names, plus the setup-code body (itself a JSON # string literal) as the trailing argument. Extracting each quoted # token this way (rather than a naive comma split) stays correct even # though the setup-code string could itself contain commas. function_args = re.findall(r'"(?:[^"\\]|\\.)*"', function_call_match.group(1)) # The last quoted argument is the function body (the setup code), not # a shadowed name -- everything before it is a parameter name (api + # the shadowed globals). param_name_count = len(function_args) - 1 invocation_matches = re.findall(r"contentFn\(([^)]*)\)", html) assert len(invocation_matches) == 1, f"expected exactly one contentFn(...) call site for kind={kind}" invocation_args = [arg.strip() for arg in invocation_matches[0].split(",")] arg_count = len(invocation_args) assert param_name_count == arg_count, ( f"kind={kind}: new Function declares {param_name_count} parameter names " f"but contentFn(...) passes {arg_count} arguments -- these must match " "exactly (api's real value + one undefined per shadowed global)" ) def test_assemble_shell_3d_has_pinned_threejs_cdn_2d_does_not(): engine = _engine() html_3d = engine._assemble_shell("3d", "z" * 40) html_2d = engine._assemble_shell("2d_anim", "z" * 40) assert "https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js" in html_3d assert "https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/examples/js/controls/OrbitControls.js" in html_3d assert "three.js/r128" not in html_2d def test_assemble_shell_no_dark_background_uses_cream(): engine = _engine() for kind in ("3d", "2d_anim"): html = engine._assemble_shell(kind, "w" * 40) assert "#0f0f0f" not in html assert "#FAF7F2" in html def test_assemble_shell_has_well_formed_script_block(): engine = _engine() for kind in ("3d", "2d_anim"): html = engine._assemble_shell(kind, "group.add(new THREE.Mesh()); return { update: function(t) {} };") blocks = re.findall(r"]*>(.*?)", html, re.DOTALL) assert len(blocks) >= 1 class _StagedFakeClient: """Fakes the two internal `structured_complete` calls `generate()` makes (grounding, then setup-code) with a single client, dispatching on the schema class passed as the second argument -- and records every call's (schema, messages) for later inspection. If `setup_code_response` is left None, a setup-code-stage call is treated as a test failure (used to prove the decline path never reaches that stage).""" def __init__(self, grounding_response, setup_code_response=None): self._grounding_response = grounding_response self._setup_code_response = setup_code_response self.calls = [] # list of (schema, messages) def structured_complete(self, messages, schema, **kw): self.calls.append((schema, messages)) if schema is ShellGrounding: return self._grounding_response if schema is ShellSetupCode: if self._setup_code_response is None: raise AssertionError("setup-code stage should never have been reached on the decline path") return self._setup_code_response raise AssertionError(f"unexpected schema passed to structured_complete: {schema}") def _setup_code_messages(client): calls = [messages for schema, messages in client.calls if schema is ShellSetupCode] assert len(calls) == 1, "expected exactly one ShellSetupCode structured_complete call" return calls[0] def test_generate_3d_happy_path_returns_assembled_html(): grounding = ShellGrounding(renderable=True, scene_brief="Render a tetrahedron with four triangular faces.") setup = ShellSetupCode( setup_code="const { THREE, scene, camera, group } = api; group.add(new THREE.Mesh());" ) client = _StagedFakeClient(grounding, setup) engine = ShellVisualEngine(client=client) chunks = [{"source": "paper.pdf", "text": "A tetrahedron has four triangular faces."}] result = engine.generate("tetrahedron", "3d", chunks, "high_school") assert result.animation_type == "3d" assert result.html_code assert "