mirror of
https://github.com/vegu-ai/talemate.git
synced 2026-05-18 05:05:39 +02:00
298 lines
11 KiB
Python
298 lines
11 KiB
Python
|
|
"""
|
||
|
|
Tests for volatile_context_placement() — the function that determines
|
||
|
|
whether volatile content (RAG, internal notes) goes before or after
|
||
|
|
the scene history in prompts.
|
||
|
|
|
||
|
|
Tests the priority chain:
|
||
|
|
1. Per-agent override ("on"/"off") takes precedence
|
||
|
|
2. "auto" defers to client.optimize_prompt_caching
|
||
|
|
3. No agent context → "before_history"
|
||
|
|
"""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from unittest.mock import Mock
|
||
|
|
|
||
|
|
from talemate.agents.base import (
|
||
|
|
AgentAction,
|
||
|
|
AgentActionConfig,
|
||
|
|
optimize_prompt_caching_action,
|
||
|
|
)
|
||
|
|
from talemate.agents.context import ActiveAgentContext, active_agent
|
||
|
|
from talemate.prompts.base import Prompt
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Helpers
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
def _make_agent(
|
||
|
|
agent_type: str, override_value: str = "auto", client_opc: bool = False
|
||
|
|
):
|
||
|
|
"""Build a minimal mock agent with an optimize_prompt_caching config."""
|
||
|
|
agent = Mock()
|
||
|
|
agent.agent_type = agent_type
|
||
|
|
action = optimize_prompt_caching_action()
|
||
|
|
action.config["optimize_prompt_caching"].value = override_value
|
||
|
|
agent.actions = {
|
||
|
|
"prompt_caching": action,
|
||
|
|
}
|
||
|
|
# Client
|
||
|
|
agent.client = Mock()
|
||
|
|
agent.client.optimize_prompt_caching = client_opc
|
||
|
|
return agent
|
||
|
|
|
||
|
|
|
||
|
|
def _make_agent_no_config(agent_type: str, client_opc: bool = False):
|
||
|
|
"""Build a mock agent that has NO optimize_prompt_caching config at all."""
|
||
|
|
agent = Mock()
|
||
|
|
agent.agent_type = agent_type
|
||
|
|
agent.actions = {
|
||
|
|
"some_action": AgentAction(
|
||
|
|
enabled=True,
|
||
|
|
label="Some Action",
|
||
|
|
config={
|
||
|
|
"other_setting": AgentActionConfig(
|
||
|
|
type="bool",
|
||
|
|
label="Other",
|
||
|
|
value=True,
|
||
|
|
),
|
||
|
|
},
|
||
|
|
),
|
||
|
|
}
|
||
|
|
agent.client = Mock()
|
||
|
|
agent.client.optimize_prompt_caching = client_opc
|
||
|
|
return agent
|
||
|
|
|
||
|
|
|
||
|
|
def _set_active_agent(agent):
|
||
|
|
"""Set the active agent context and return the token for cleanup."""
|
||
|
|
ctx = ActiveAgentContext(agent=agent, fn=lambda: None)
|
||
|
|
return active_agent.set(ctx)
|
||
|
|
|
||
|
|
|
||
|
|
def _call_volatile_context_placement():
|
||
|
|
"""Invoke volatile_context_placement via a Prompt instance."""
|
||
|
|
prompt = Prompt.get("conversation.dialogue-movie_script", vars={})
|
||
|
|
return prompt.volatile_context_placement()
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: no agent context
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestNoAgentContext:
|
||
|
|
def test_returns_before_history_when_no_active_agent(self):
|
||
|
|
"""With no active agent, default to before_history."""
|
||
|
|
# Ensure no agent is set
|
||
|
|
token = active_agent.set(None)
|
||
|
|
try:
|
||
|
|
result = _call_volatile_context_placement()
|
||
|
|
assert result == "before_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: agent override = "on"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestAgentOverrideOn:
|
||
|
|
def test_returns_after_history_regardless_of_client(self):
|
||
|
|
"""Agent override 'on' → after_history, even if client is False."""
|
||
|
|
agent = _make_agent("conversation", override_value="on", client_opc=False)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "after_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
def test_returns_after_history_with_client_also_true(self):
|
||
|
|
"""Agent override 'on' + client True → after_history."""
|
||
|
|
agent = _make_agent("narrator", override_value="on", client_opc=True)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "after_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: agent override = "off"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestAgentOverrideOff:
|
||
|
|
def test_returns_before_history_regardless_of_client(self):
|
||
|
|
"""Agent override 'off' → before_history, even if client is True."""
|
||
|
|
agent = _make_agent("director", override_value="off", client_opc=True)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "before_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
def test_returns_before_history_with_client_also_false(self):
|
||
|
|
"""Agent override 'off' + client False → before_history."""
|
||
|
|
agent = _make_agent("editor", override_value="off", client_opc=False)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "before_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: agent override = "auto" (defer to client)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestAgentOverrideAuto:
|
||
|
|
def test_auto_with_client_true(self):
|
||
|
|
"""Agent 'auto' + client optimize_prompt_caching=True → after_history."""
|
||
|
|
agent = _make_agent("conversation", override_value="auto", client_opc=True)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "after_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
def test_auto_with_client_false(self):
|
||
|
|
"""Agent 'auto' + client optimize_prompt_caching=False → before_history."""
|
||
|
|
agent = _make_agent("summarizer", override_value="auto", client_opc=False)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "before_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: agent with no optimize_prompt_caching config (fallback to client)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestAgentWithoutConfig:
|
||
|
|
def test_no_config_client_true(self):
|
||
|
|
"""Agent has no optimize_prompt_caching config + client True → after_history."""
|
||
|
|
agent = _make_agent_no_config("conversation", client_opc=True)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "after_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
def test_no_config_client_false(self):
|
||
|
|
"""Agent has no optimize_prompt_caching config + client False → before_history."""
|
||
|
|
agent = _make_agent_no_config("narrator", client_opc=False)
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "before_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: agent with no client
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestAgentWithNoClient:
|
||
|
|
def test_auto_no_client(self):
|
||
|
|
"""Agent override 'auto' with client=None → before_history."""
|
||
|
|
agent = _make_agent("creator", override_value="auto", client_opc=False)
|
||
|
|
agent.client = None
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "before_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
def test_on_no_client(self):
|
||
|
|
"""Agent override 'on' with client=None → after_history (override wins)."""
|
||
|
|
agent = _make_agent("creator", override_value="on", client_opc=False)
|
||
|
|
agent.client = None
|
||
|
|
token = _set_active_agent(agent)
|
||
|
|
try:
|
||
|
|
assert _call_volatile_context_placement() == "after_history"
|
||
|
|
finally:
|
||
|
|
active_agent.reset(token)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: optimize_prompt_caching_config factory
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestOptimizePromptCachingAction:
|
||
|
|
def test_factory_returns_agent_action(self):
|
||
|
|
action = optimize_prompt_caching_action()
|
||
|
|
assert isinstance(action, AgentAction)
|
||
|
|
|
||
|
|
def test_factory_has_config_with_correct_key(self):
|
||
|
|
action = optimize_prompt_caching_action()
|
||
|
|
assert "optimize_prompt_caching" in action.config
|
||
|
|
assert isinstance(action.config["optimize_prompt_caching"], AgentActionConfig)
|
||
|
|
|
||
|
|
def test_factory_default_value_is_auto(self):
|
||
|
|
action = optimize_prompt_caching_action()
|
||
|
|
assert action.config["optimize_prompt_caching"].value == "auto"
|
||
|
|
|
||
|
|
def test_factory_has_three_choices(self):
|
||
|
|
action = optimize_prompt_caching_action()
|
||
|
|
config = action.config["optimize_prompt_caching"]
|
||
|
|
assert len(config.choices) == 3
|
||
|
|
values = [c["value"] for c in config.choices]
|
||
|
|
assert values == ["auto", "on", "off"]
|
||
|
|
|
||
|
|
def test_factory_returns_independent_instances(self):
|
||
|
|
"""Each call should return a new instance, not a shared reference."""
|
||
|
|
a = optimize_prompt_caching_action()
|
||
|
|
b = optimize_prompt_caching_action()
|
||
|
|
a.config["optimize_prompt_caching"].value = "on"
|
||
|
|
assert b.config["optimize_prompt_caching"].value == "auto"
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Tests: all 6 agents have the config
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
class TestAllAgentsHaveConfig:
|
||
|
|
"""Verify that every agent has the prompt_caching action with
|
||
|
|
optimize_prompt_caching config."""
|
||
|
|
|
||
|
|
@pytest.mark.parametrize(
|
||
|
|
"agent_cls_path",
|
||
|
|
[
|
||
|
|
"talemate.agents.conversation.ConversationAgent",
|
||
|
|
"talemate.agents.narrator.NarratorAgent",
|
||
|
|
"talemate.agents.director.DirectorAgent",
|
||
|
|
"talemate.agents.creator.CreatorAgent",
|
||
|
|
"talemate.agents.editor.EditorAgent",
|
||
|
|
"talemate.agents.summarize.SummarizeAgent",
|
||
|
|
"talemate.agents.world_state.WorldStateAgent",
|
||
|
|
],
|
||
|
|
)
|
||
|
|
def test_agent_has_optimize_prompt_caching(self, agent_cls_path):
|
||
|
|
import importlib
|
||
|
|
|
||
|
|
module_path, class_name = agent_cls_path.rsplit(".", 1)
|
||
|
|
module = importlib.import_module(module_path)
|
||
|
|
cls = getattr(module, class_name)
|
||
|
|
actions = cls.init_actions()
|
||
|
|
assert "prompt_caching" in actions, (
|
||
|
|
f"{class_name} missing 'prompt_caching' action"
|
||
|
|
)
|
||
|
|
action = actions["prompt_caching"]
|
||
|
|
assert isinstance(action, AgentAction)
|
||
|
|
assert action.config is not None, f"{class_name}.prompt_caching has no config"
|
||
|
|
assert "optimize_prompt_caching" in action.config, (
|
||
|
|
f"{class_name}.prompt_caching missing 'optimize_prompt_caching' config"
|
||
|
|
)
|
||
|
|
opc = action.config["optimize_prompt_caching"]
|
||
|
|
assert opc.value == "auto"
|
||
|
|
assert opc.type == "text"
|