mirror of
https://github.com/vegu-ai/talemate.git
synced 2026-09-01 19:48:52 +02:00
use real scene objects
This commit is contained in:
80
tests/_changelog_test_helpers.py
Normal file
80
tests/_changelog_test_helpers.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
Shared helpers for changelog tests (test_changelog.py, test_changelog_extras.py).
|
||||
|
||||
The changelog module reads four scene-shaped attributes — ``filename``,
|
||||
``save_dir``, ``changelog_dir`` (cascades off ``save_dir``) and
|
||||
``serialize`` — and walks the disk under ``save_dir``. The tests need to
|
||||
drive ``serialize`` with arbitrary payloads (not a real scene serialization
|
||||
shape) so a small ``Scene`` subclass overrides ``serialize`` with a settable
|
||||
attribute. This is still a real ``Scene`` with real validation/wiring; if
|
||||
someone renames or removes ``filename``/``save_dir``/``changelog_dir`` on
|
||||
``Scene`` the tests will fail.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from talemate.tale_mate import Scene
|
||||
|
||||
|
||||
class ChangelogScene(Scene):
|
||||
"""Real ``Scene`` subclass exposing ``serialize`` and ``save_dir`` as
|
||||
settable plain attributes for changelog tests.
|
||||
|
||||
The base ``Scene`` exposes both as ``@property`` descriptors.
|
||||
``Scene.serialize`` returns the *real* serialized scene shape (with
|
||||
``character_data``, ``world_state``, etc.); the changelog tests need to
|
||||
drive arbitrary payloads (often ``{"history": ..., "characters": ...}``)
|
||||
to verify changelog logic in isolation. ``Scene.save_dir`` joins the
|
||||
classmethod ``scenes_dir()`` with ``project_name`` and creates the
|
||||
directory; tests instead want a tempdir directly.
|
||||
|
||||
Overriding both with plain class attributes (``None`` here so subclass
|
||||
instances initialize them in ``__init__``) shadows the parent's
|
||||
``@property`` descriptors. ``changelog_dir``/``backups_dir`` are still
|
||||
real ``@property`` on the parent and cascade off ``save_dir`` correctly.
|
||||
"""
|
||||
|
||||
# Shadow the parent's @property descriptors with plain class attrs.
|
||||
# On instance creation these get assigned in __init__. Critical: this
|
||||
# MUST happen at class-body level so the descriptor lookup finds the
|
||||
# plain attribute first.
|
||||
serialize = None # type: ignore[assignment]
|
||||
save_dir = None # type: ignore[assignment]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
save_dir: str,
|
||||
filename: str = "scene.json",
|
||||
initial_serialize: dict | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
self.filename = filename
|
||||
self.save_dir = save_dir
|
||||
self.serialize = (
|
||||
initial_serialize
|
||||
if initial_serialize is not None
|
||||
else {"history": [], "characters": []}
|
||||
)
|
||||
|
||||
|
||||
def make_changelog_scene(
|
||||
tmp_dir: str,
|
||||
*,
|
||||
filename: str = "scene.json",
|
||||
initial_serialize: dict | None = None,
|
||||
) -> ChangelogScene:
|
||||
"""Build a ``ChangelogScene`` whose ``save_dir`` is ``tmp_dir`` directly.
|
||||
|
||||
``changelog_dir`` and ``backups_dir`` cascade off ``save_dir`` via the
|
||||
real properties on ``Scene``.
|
||||
"""
|
||||
scene = ChangelogScene(
|
||||
save_dir=tmp_dir,
|
||||
filename=filename,
|
||||
initial_serialize=initial_serialize,
|
||||
)
|
||||
os.makedirs(tmp_dir, exist_ok=True)
|
||||
return scene
|
||||
43
tests/prompts/_groups_test_helpers.py
Normal file
43
tests/prompts/_groups_test_helpers.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Shared helpers for prompt-groups tests (test_groups.py, test_groups_extras.py).
|
||||
|
||||
The ``talemate.prompts.groups`` module reads exactly one scene-shaped attribute,
|
||||
``scene.template_dir``. The tests need to drive arbitrary values into it
|
||||
(strings, ``Path`` objects, ``None``, or a real path) to exercise the
|
||||
``isinstance(template_dir, str)`` validation branch in
|
||||
``get_scene_template_path``.
|
||||
|
||||
The base ``Scene.template_dir`` is a ``@property`` that always returns a
|
||||
``str`` joined from ``save_dir`` + ``"templates"``. To drive the invalid-type
|
||||
branches, this helper exposes a ``Scene`` subclass that shadows the
|
||||
``@property`` with a plain class attribute. Renames or removals of
|
||||
``template_dir`` on the parent will still surface as test failures (the
|
||||
attribute is still named ``template_dir`` and used in tests via ``scene.template_dir``).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from talemate.tale_mate import Scene
|
||||
|
||||
|
||||
class TemplateDirScene(Scene):
|
||||
"""Real ``Scene`` subclass exposing ``template_dir`` as a settable attribute.
|
||||
|
||||
The shadowed class-level ``template_dir`` (initialized to ``None``) replaces
|
||||
the parent's ``@property`` descriptor on this subclass; ``__init__`` then
|
||||
accepts whatever value the test wants — ``str``, ``Path``, ``None``, or a
|
||||
missing-attribute-equivalent (use ``del scene.template_dir`` to simulate).
|
||||
"""
|
||||
|
||||
template_dir: Any = None # type: ignore[assignment]
|
||||
|
||||
def __init__(self, *, template_dir: Any = None):
|
||||
super().__init__()
|
||||
self.template_dir = template_dir
|
||||
|
||||
|
||||
def make_template_dir_scene(template_dir: Any) -> TemplateDirScene:
|
||||
"""Build a real ``TemplateDirScene`` with ``template_dir`` set to ``value``."""
|
||||
return TemplateDirScene(template_dir=template_dir)
|
||||
@@ -14,6 +14,8 @@ import pytest
|
||||
|
||||
from talemate.prompts import groups
|
||||
|
||||
from ._groups_test_helpers import make_template_dir_scene
|
||||
|
||||
|
||||
class TestGetDefaultTemplatePath:
|
||||
"""Tests for get_default_template_path()."""
|
||||
@@ -73,8 +75,7 @@ class TestGetSceneTemplatePath:
|
||||
|
||||
def test_agent_subdirectory_preferred(self, tmp_path):
|
||||
"""Agent-specific subdirectory is preferred when it exists."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
|
||||
# Create agent subdirectory with template
|
||||
agent_dir = tmp_path / "narrator"
|
||||
@@ -87,8 +88,7 @@ class TestGetSceneTemplatePath:
|
||||
|
||||
def test_falls_back_to_flat_structure(self, tmp_path):
|
||||
"""Falls back to flat structure when agent subdir doesn't exist."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
|
||||
# Create flat template (no agent subdir)
|
||||
flat_template = tmp_path / "test.jinja2"
|
||||
@@ -99,8 +99,7 @@ class TestGetSceneTemplatePath:
|
||||
|
||||
def test_returns_expected_path_even_if_missing(self, tmp_path):
|
||||
"""Returns the expected path even if template doesn't exist."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
|
||||
path = groups.get_scene_template_path(scene, "narrator", "missing")
|
||||
# Should return flat path since no agent subdir exists
|
||||
@@ -121,8 +120,7 @@ class TestResolveTemplate:
|
||||
|
||||
def test_scene_has_highest_priority(self, tmp_path, mock_config):
|
||||
"""Scene templates always take priority over everything else."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
|
||||
# Create scene template
|
||||
scene_template = tmp_path / "test.jinja2"
|
||||
@@ -223,8 +221,7 @@ class TestResolveTemplate:
|
||||
|
||||
def test_scene_override_beats_explicit_source(self, tmp_path, mock_config):
|
||||
"""Scene templates override even explicit template_sources."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path / "scene")
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path / "scene"))
|
||||
|
||||
mock_config.prompts.template_sources = {"narrator.test": "my-group"}
|
||||
|
||||
@@ -307,8 +304,7 @@ class TestListGroups:
|
||||
|
||||
def test_includes_scene_group_when_scene_provided(self, tmp_path, mock_config):
|
||||
"""Scene group is included only when scene is provided."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path / "scene")
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path / "scene"))
|
||||
(tmp_path / "scene").mkdir()
|
||||
|
||||
with patch.object(groups, "_get_config", return_value=mock_config):
|
||||
@@ -398,8 +394,7 @@ class TestGetTemplateContent:
|
||||
|
||||
def test_reads_scene_template(self, tmp_path):
|
||||
"""Reads template from scene when group is 'scene'."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
|
||||
# Create template in agent subdir
|
||||
agent_dir = tmp_path / "narrator"
|
||||
@@ -437,8 +432,7 @@ class TestWriteTemplate:
|
||||
|
||||
def test_writes_to_scene(self, tmp_path):
|
||||
"""Writes template to scene directory."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
|
||||
groups.write_template("scene", "narrator", "test", "scene content", scene)
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ import pytest
|
||||
|
||||
from talemate.prompts import groups
|
||||
|
||||
from ._groups_test_helpers import make_template_dir_scene
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Shared helpers
|
||||
@@ -86,8 +88,7 @@ class TestGetSceneTemplatePathInvalidDir:
|
||||
"""Cover the early-return for a non-string ``template_dir``."""
|
||||
|
||||
def test_returns_none_when_template_dir_is_none(self):
|
||||
scene = Mock()
|
||||
scene.template_dir = None
|
||||
scene = make_template_dir_scene(template_dir=None)
|
||||
|
||||
result = groups.get_scene_template_path(scene, "narrator", "anything")
|
||||
|
||||
@@ -96,8 +97,7 @@ class TestGetSceneTemplatePathInvalidDir:
|
||||
def test_returns_none_when_template_dir_is_path_object(self, tmp_path):
|
||||
# The function specifically checks ``isinstance(template_dir, str)`` —
|
||||
# a Path (which is otherwise valid) hits the early return.
|
||||
scene = Mock()
|
||||
scene.template_dir = tmp_path # Path, not str
|
||||
scene = make_template_dir_scene(template_dir=tmp_path) # Path, not str
|
||||
|
||||
result = groups.get_scene_template_path(scene, "narrator", "anything")
|
||||
|
||||
@@ -304,8 +304,7 @@ class TestListTemplatesScene:
|
||||
scene_dir = isolated_groups_dirs["scene"]
|
||||
_write_template(scene_dir / "narrator" / "scene-only.jinja2")
|
||||
|
||||
scene = Mock()
|
||||
scene.template_dir = str(scene_dir)
|
||||
scene = make_template_dir_scene(template_dir=str(scene_dir))
|
||||
|
||||
result = groups.list_templates(scene=scene)
|
||||
|
||||
@@ -320,8 +319,7 @@ class TestListTemplatesScene:
|
||||
scene_dir = isolated_groups_dirs["scene"]
|
||||
_write_template(scene_dir / "flat-only.jinja2")
|
||||
|
||||
scene = Mock()
|
||||
scene.template_dir = str(scene_dir)
|
||||
scene = make_template_dir_scene(template_dir=str(scene_dir))
|
||||
|
||||
result = groups.list_templates(scene=scene)
|
||||
|
||||
@@ -340,8 +338,7 @@ class TestListTemplatesScene:
|
||||
_write_template(scene_dir / "narrator" / "shared.jinja2")
|
||||
_write_template(scene_dir / "shared.jinja2") # flat
|
||||
|
||||
scene = Mock()
|
||||
scene.template_dir = str(scene_dir)
|
||||
scene = make_template_dir_scene(template_dir=str(scene_dir))
|
||||
|
||||
result = groups.list_templates(scene=scene)
|
||||
|
||||
@@ -440,8 +437,7 @@ class TestListTemplatesScenePriorityForOverrideMtime:
|
||||
_write_template(d / "narrator" / "ovr.jinja2", mtime=1_000_000.0)
|
||||
_write_template(scene_dir / "narrator" / "ovr.jinja2", mtime=3_000_000.0)
|
||||
|
||||
scene = Mock()
|
||||
scene.template_dir = str(scene_dir)
|
||||
scene = make_template_dir_scene(template_dir=str(scene_dir))
|
||||
|
||||
result = groups.list_templates(scene=scene)
|
||||
info = next(t for t in result if t.uid == "narrator.ovr")
|
||||
@@ -463,8 +459,7 @@ class TestDeleteTemplateSceneFlatFallback:
|
||||
|
||||
def test_falls_back_to_flat_scene_path_when_agent_subdir_empty(self, tmp_path):
|
||||
# Only a flat-structure scene template exists; no narrator/ subdir.
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
flat_template = tmp_path / "flat.jinja2"
|
||||
flat_template.write_text("flat content")
|
||||
|
||||
@@ -478,8 +473,7 @@ class TestDeleteTemplateSceneFlatFallback:
|
||||
|
||||
def test_returns_false_when_neither_path_exists(self, tmp_path):
|
||||
"""No agent subdir AND no flat file → returns False, raises nothing."""
|
||||
scene = Mock()
|
||||
scene.template_dir = str(tmp_path)
|
||||
scene = make_template_dir_scene(template_dir=str(tmp_path))
|
||||
|
||||
result = groups.delete_template("scene", "narrator", "missing", scene=scene)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from talemate.server.prompts import (
|
||||
parse_template_uid,
|
||||
validate_jinja2_syntax,
|
||||
)
|
||||
from talemate.tale_mate import Scene
|
||||
|
||||
|
||||
class TestParseTemplateUid:
|
||||
@@ -138,11 +139,14 @@ class TestPromptsPluginListGroups:
|
||||
@pytest.mark.asyncio
|
||||
async def test_lists_groups_with_scene(self, tmp_path):
|
||||
"""Lists groups when scene is loaded."""
|
||||
mock_scene = Mock()
|
||||
mock_scene.name = "test-scene"
|
||||
mock_scene.template_dir = str(tmp_path)
|
||||
# Real ``Scene`` — ``handle_list_groups`` reads ``scene.name`` to decide
|
||||
# whether scene context is loaded (truthy => scene_loaded True), then
|
||||
# delegates to the patched ``list_groups``. ``template_dir`` is never
|
||||
# touched here because ``list_groups`` itself is patched out.
|
||||
scene = Scene()
|
||||
scene.name = "test-scene"
|
||||
|
||||
handler = MockWebsocketHandler(scene=mock_scene)
|
||||
handler = MockWebsocketHandler(scene=scene)
|
||||
plugin = PromptsPlugin(handler)
|
||||
|
||||
# Create mock groups - need to use MagicMock and configure_mock for 'name'
|
||||
|
||||
@@ -3,8 +3,8 @@ import json
|
||||
import tempfile
|
||||
import shutil
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
|
||||
from _changelog_test_helpers import make_changelog_scene
|
||||
from talemate.changelog import (
|
||||
save_changelog,
|
||||
append_scene_delta,
|
||||
@@ -30,6 +30,7 @@ from talemate.changelog import (
|
||||
_get_latest_changelog_file,
|
||||
_get_overall_latest_revision,
|
||||
_get_file_size,
|
||||
_SceneRef,
|
||||
MAX_CHANGELOG_FILE_SIZE,
|
||||
InMemoryChangelog,
|
||||
)
|
||||
@@ -45,16 +46,20 @@ def temp_dir():
|
||||
|
||||
@pytest.fixture
|
||||
def mock_scene(temp_dir):
|
||||
"""Create a mock scene object."""
|
||||
scene = Mock()
|
||||
scene.filename = "test_scene.json"
|
||||
scene.save_dir = temp_dir
|
||||
scene.changelog_dir = os.path.join(temp_dir, "changelog")
|
||||
scene.backups_dir = os.path.join(temp_dir, "backups")
|
||||
scene.serialize = {"characters": [], "entries": [], "metadata": {"version": "1.0"}}
|
||||
scene.rev = 0 # Initialize revision to 0
|
||||
scene._changelog = None # Explicitly set to None to avoid Mock auto-creation
|
||||
return scene
|
||||
# Real ``Scene`` subclass (see _changelog_test_helpers.ChangelogScene) with
|
||||
# ``serialize`` exposed as a settable attribute so tests can drive arbitrary
|
||||
# payloads. ``filename``/``save_dir``/``changelog_dir``/``rev``/``_changelog``
|
||||
# remain the real ``Scene`` fields/properties — renames or removals will
|
||||
# break these tests.
|
||||
return make_changelog_scene(
|
||||
temp_dir,
|
||||
filename="test_scene.json",
|
||||
initial_serialize={
|
||||
"characters": [],
|
||||
"entries": [],
|
||||
"metadata": {"version": "1.0"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_changelog_log_path(mock_scene):
|
||||
@@ -1307,14 +1312,12 @@ async def test_delete_changelog_files_with_wrong_scene_reference(temp_dir):
|
||||
delete_changelog_files(self.scene) is called instead of constructing
|
||||
a proper scene reference from the deleted file path.
|
||||
"""
|
||||
# Create a scene with changelogs
|
||||
scene1 = Mock()
|
||||
scene1.filename = "scene_to_delete.json"
|
||||
scene1.save_dir = os.path.join(temp_dir, "project1")
|
||||
scene1.changelog_dir = os.path.join(scene1.save_dir, "changelog")
|
||||
scene1.serialize = {"characters": [], "data": "scene1"}
|
||||
scene1.rev = 0
|
||||
scene1._changelog = None
|
||||
# Real ``Scene`` (subclass) for the scene whose changelog we'll create.
|
||||
scene1 = make_changelog_scene(
|
||||
os.path.join(temp_dir, "project1"),
|
||||
filename="scene_to_delete.json",
|
||||
initial_serialize={"characters": [], "data": "scene1"},
|
||||
)
|
||||
|
||||
# Initialize changelog for scene1
|
||||
await save_changelog(scene1)
|
||||
@@ -1324,11 +1327,12 @@ async def test_delete_changelog_files_with_wrong_scene_reference(temp_dir):
|
||||
assert os.path.exists(_latest_path(scene1))
|
||||
|
||||
# Now simulate the bug: calling delete_changelog_files with a different scene
|
||||
# (or None, which would be self.scene when no scene is loaded)
|
||||
wrong_scene = Mock()
|
||||
wrong_scene.filename = "different_scene.json" # Wrong filename!
|
||||
wrong_scene.save_dir = os.path.join(temp_dir, "project2") # Wrong directory!
|
||||
wrong_scene.changelog_dir = os.path.join(wrong_scene.save_dir, "changelog")
|
||||
# (or None, which would be self.scene when no scene is loaded). Real Scene
|
||||
# again — wrong filename and wrong save_dir.
|
||||
wrong_scene = make_changelog_scene(
|
||||
os.path.join(temp_dir, "project2"),
|
||||
filename="different_scene.json",
|
||||
)
|
||||
|
||||
# Try to delete with wrong scene reference
|
||||
result = delete_changelog_files(wrong_scene)
|
||||
@@ -1343,19 +1347,15 @@ async def test_delete_changelog_files_with_wrong_scene_reference(temp_dir):
|
||||
"Latest file should still exist due to bug"
|
||||
)
|
||||
|
||||
# Now show the correct way: construct scene reference from the file path
|
||||
scene_path = os.path.join(scene1.save_dir, scene1.filename)
|
||||
scene_dir = os.path.dirname(scene_path)
|
||||
scene_filename = os.path.basename(scene_path)
|
||||
correct_scene_ref = type(
|
||||
"Scene",
|
||||
(),
|
||||
{
|
||||
"save_dir": scene_dir,
|
||||
"filename": scene_filename,
|
||||
"changelog_dir": os.path.join(scene_dir, "changelog"),
|
||||
},
|
||||
)()
|
||||
# Now show the correct way: construct a real ``_SceneRef`` (the type
|
||||
# production code uses for this exact purpose — a lightweight scene
|
||||
# reference for changelog operations). This is the same type
|
||||
# ``ensure_changelogs_for_all_scenes`` builds internally.
|
||||
correct_scene_ref = _SceneRef(
|
||||
filename=scene1.filename,
|
||||
save_dir=scene1.save_dir,
|
||||
data={},
|
||||
)
|
||||
|
||||
# Delete with correct reference
|
||||
result = delete_changelog_files(correct_scene_ref)
|
||||
|
||||
@@ -17,10 +17,10 @@ import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from _changelog_test_helpers import make_changelog_scene
|
||||
from talemate.changelog import (
|
||||
InMemoryChangelog,
|
||||
_apply_delta,
|
||||
@@ -51,21 +51,14 @@ def temp_dir():
|
||||
shutil.rmtree(d, ignore_errors=True)
|
||||
|
||||
|
||||
def _make_mock_scene(temp_dir: str, name: str = "scene.json") -> Mock:
|
||||
scene = Mock()
|
||||
scene.filename = name
|
||||
scene.save_dir = temp_dir
|
||||
scene.changelog_dir = os.path.join(temp_dir, "changelog")
|
||||
scene.backups_dir = os.path.join(temp_dir, "backups")
|
||||
scene.serialize = {"history": [], "characters": []}
|
||||
scene.rev = 0
|
||||
scene._changelog = None
|
||||
return scene
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_scene(temp_dir):
|
||||
return _make_mock_scene(temp_dir)
|
||||
# Real ``Scene`` subclass (see _changelog_test_helpers.ChangelogScene) with
|
||||
# ``serialize`` exposed as a settable attribute so tests can drive arbitrary
|
||||
# payloads. ``filename``/``save_dir``/``changelog_dir``/``rev``/``_changelog``
|
||||
# remain the real ``Scene`` fields/properties — renames or removals will
|
||||
# break these tests.
|
||||
return make_changelog_scene(temp_dir)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -9,8 +9,6 @@ Tests cover:
|
||||
- Chat creation for generate_arc modes
|
||||
"""
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
from talemate.agents.director.plan.expand import (
|
||||
compute_chunks,
|
||||
compute_arc_info,
|
||||
@@ -18,6 +16,7 @@ from talemate.agents.director.plan.expand import (
|
||||
MIN_CHUNK_BEATS,
|
||||
)
|
||||
from talemate.agents.director.plan.schema import Beat
|
||||
from talemate.tale_mate import Scene
|
||||
|
||||
|
||||
def _make_beats(tensions: list[float]) -> list[Beat]:
|
||||
@@ -257,10 +256,11 @@ class TestChatCreateGenerateArc:
|
||||
director.actions = DirectorAgent.init_actions()
|
||||
director._chats = {}
|
||||
director._last_active_chat_id = None
|
||||
# Mock scene with agent_state for chat persistence
|
||||
director.scene = Mock()
|
||||
director.scene.agent_state = {"director": {}}
|
||||
director.scene.agent_persona.return_value = None
|
||||
# Real ``Scene`` — ``chat_create_generate_arc`` reads ``scene.agent_state``
|
||||
# (default ``{}``, persistence target for chats) and calls
|
||||
# ``scene.agent_persona("director")`` (returns ``None`` on a fresh Scene
|
||||
# because ``agent_persona_templates`` is an empty dict by default).
|
||||
director.scene = Scene()
|
||||
return director
|
||||
|
||||
def test_create_generate_arc_default_mode(self):
|
||||
|
||||
Reference in New Issue
Block a user