v2.9.5 (#676)
Co-authored-by: Clément Drouin <clement.drouin@mistral.ai> Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai> Co-authored-by: allansimon-mistral <allan.simon@ext.mistral.ai> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
parent
4972dd5694
commit
b23f49e5f4
74 changed files with 2342 additions and 240 deletions
|
|
@ -5,33 +5,41 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|||
import pytest
|
||||
|
||||
from vibe.core.session.resume_sessions import (
|
||||
SHORT_SESSION_ID_LEN,
|
||||
list_remote_resume_sessions,
|
||||
short_session_id,
|
||||
)
|
||||
from vibe.core.session.session_id import shorten_session_id
|
||||
|
||||
|
||||
class TestShortenSessionId:
|
||||
def test_shortens_to_first_8_chars(self) -> None:
|
||||
sid = "abcdef1234567890"
|
||||
assert shorten_session_id(sid) == "abcdef12"
|
||||
|
||||
def test_from_end_shortens_to_last_8_chars(self) -> None:
|
||||
sid = "abcdef1234567890"
|
||||
assert shorten_session_id(sid, from_end=True) == "34567890"
|
||||
|
||||
def test_returns_full_id_when_shorter_than_limit(self) -> None:
|
||||
sid = "abc"
|
||||
assert shorten_session_id(sid) == "abc"
|
||||
assert shorten_session_id(sid, from_end=True) == "abc"
|
||||
|
||||
|
||||
class TestShortSessionId:
|
||||
def test_local_shortens_to_first_chars(self) -> None:
|
||||
def test_local_delegates_to_shorten(self) -> None:
|
||||
sid = "abcdef1234567890"
|
||||
result = short_session_id(sid)
|
||||
assert result == sid[:SHORT_SESSION_ID_LEN]
|
||||
assert len(result) == SHORT_SESSION_ID_LEN
|
||||
assert short_session_id(sid) == shorten_session_id(sid)
|
||||
|
||||
def test_local_is_default(self) -> None:
|
||||
sid = "abcdef1234567890"
|
||||
assert short_session_id(sid) == short_session_id(sid, source="local")
|
||||
|
||||
def test_remote_shortens_to_last_chars(self) -> None:
|
||||
def test_remote_delegates_to_shorten_from_end(self) -> None:
|
||||
sid = "abcdef1234567890"
|
||||
result = short_session_id(sid, source="remote")
|
||||
assert result == sid[-SHORT_SESSION_ID_LEN:]
|
||||
assert len(result) == SHORT_SESSION_ID_LEN
|
||||
|
||||
def test_returns_full_id_when_shorter_than_limit(self) -> None:
|
||||
sid = "abc"
|
||||
assert short_session_id(sid) == "abc"
|
||||
assert short_session_id(sid, source="remote") == "abc"
|
||||
assert short_session_id(sid, source="remote") == shorten_session_id(
|
||||
sid, from_end=True
|
||||
)
|
||||
|
||||
def test_empty_string(self) -> None:
|
||||
assert short_session_id("") == ""
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import pytest
|
|||
from tests.conftest import build_test_vibe_config
|
||||
from vibe.core.agents.models import AgentProfile, AgentSafety
|
||||
from vibe.core.config import SessionLoggingConfig, VibeConfig
|
||||
from vibe.core.loop import ScheduledLoop
|
||||
from vibe.core.session.session_logger import SessionLogger
|
||||
from vibe.core.tools.manager import ToolManager
|
||||
from vibe.core.types import AgentStats, LLMMessage, Role, SessionMetadata
|
||||
|
|
@ -868,3 +869,136 @@ class TestSessionLoggerCleanupTmpFiles:
|
|||
logger.maybe_cleanup_tmp_files()
|
||||
|
||||
assert cleanup_spy.call_count == 2
|
||||
|
||||
|
||||
class TestPersistLoops:
|
||||
@pytest.mark.asyncio
|
||||
async def test_writes_into_existing_metadata(
|
||||
self,
|
||||
session_config: SessionLoggingConfig,
|
||||
mock_vibe_config: VibeConfig,
|
||||
mock_tool_manager: ToolManager,
|
||||
mock_agent_profile: AgentProfile,
|
||||
) -> None:
|
||||
logger = SessionLogger(session_config, "test-session-loops")
|
||||
await logger.save_interaction(
|
||||
messages=[
|
||||
LLMMessage(role=Role.system, content="System prompt"),
|
||||
LLMMessage(role=Role.user, content="Hello"),
|
||||
LLMMessage(role=Role.assistant, content="Hi there!"),
|
||||
],
|
||||
stats=AgentStats(steps=1),
|
||||
base_config=mock_vibe_config,
|
||||
tool_manager=mock_tool_manager,
|
||||
agent_profile=mock_agent_profile,
|
||||
)
|
||||
|
||||
assert logger.session_metadata is not None
|
||||
logger.session_metadata.loops = [
|
||||
ScheduledLoop(
|
||||
id="aabbccdd",
|
||||
interval_seconds=30,
|
||||
prompt="ping",
|
||||
next_fire_at=12345.0,
|
||||
created_at=12000.0,
|
||||
)
|
||||
]
|
||||
await logger.persist_loops()
|
||||
|
||||
assert logger.session_dir is not None
|
||||
with open(logger.session_dir / "meta.json") as f:
|
||||
metadata = json.load(f)
|
||||
|
||||
assert metadata["session_id"] == "test-session-loops"
|
||||
assert metadata["total_messages"] == 2
|
||||
assert metadata["loops"] == [
|
||||
{
|
||||
"id": "aabbccdd",
|
||||
"interval_seconds": 30,
|
||||
"prompt": "ping",
|
||||
"next_fire_at": 12345.0,
|
||||
"created_at": 12000.0,
|
||||
}
|
||||
]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_noop_when_metadata_file_missing(
|
||||
self, session_config: SessionLoggingConfig
|
||||
) -> None:
|
||||
logger = SessionLogger(session_config, "no-meta-session")
|
||||
assert logger.session_dir is not None
|
||||
# No save_interaction was called -> meta.json does not exist
|
||||
assert not (logger.session_dir / "meta.json").exists()
|
||||
|
||||
assert logger.session_metadata is not None
|
||||
logger.session_metadata.loops = [
|
||||
ScheduledLoop(
|
||||
id="aabbccdd",
|
||||
interval_seconds=30,
|
||||
prompt="ping",
|
||||
next_fire_at=1.0,
|
||||
created_at=0.0,
|
||||
)
|
||||
]
|
||||
await logger.persist_loops()
|
||||
|
||||
assert not (logger.session_dir / "meta.json").exists()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_noop_when_logging_disabled(
|
||||
self, disabled_session_config: SessionLoggingConfig
|
||||
) -> None:
|
||||
logger = SessionLogger(disabled_session_config, "ignored")
|
||||
# Should not raise even though session_metadata is None
|
||||
await logger.persist_loops()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_subsequent_save_interaction_preserves_loops(
|
||||
self,
|
||||
session_config: SessionLoggingConfig,
|
||||
mock_vibe_config: VibeConfig,
|
||||
mock_tool_manager: ToolManager,
|
||||
mock_agent_profile: AgentProfile,
|
||||
) -> None:
|
||||
logger = SessionLogger(session_config, "loops-vs-save")
|
||||
messages = [
|
||||
LLMMessage(role=Role.system, content="System prompt"),
|
||||
LLMMessage(role=Role.user, content="Hello"),
|
||||
LLMMessage(role=Role.assistant, content="Hi there!"),
|
||||
]
|
||||
await logger.save_interaction(
|
||||
messages=messages,
|
||||
stats=AgentStats(steps=1),
|
||||
base_config=mock_vibe_config,
|
||||
tool_manager=mock_tool_manager,
|
||||
agent_profile=mock_agent_profile,
|
||||
)
|
||||
|
||||
assert logger.session_metadata is not None
|
||||
logger.session_metadata.loops = [
|
||||
ScheduledLoop(
|
||||
id="aabbccdd",
|
||||
interval_seconds=30,
|
||||
prompt="ping",
|
||||
next_fire_at=12345.0,
|
||||
created_at=12000.0,
|
||||
)
|
||||
]
|
||||
await logger.persist_loops()
|
||||
|
||||
# A subsequent save (e.g. user sends another message) must not
|
||||
# overwrite the on-disk loops with the stale in-memory value.
|
||||
more_messages = [*messages, LLMMessage(role=Role.user, content="Again")]
|
||||
await logger.save_interaction(
|
||||
messages=more_messages,
|
||||
stats=AgentStats(steps=2),
|
||||
base_config=mock_vibe_config,
|
||||
tool_manager=mock_tool_manager,
|
||||
agent_profile=mock_agent_profile,
|
||||
)
|
||||
|
||||
assert logger.session_dir is not None
|
||||
with open(logger.session_dir / "meta.json") as f:
|
||||
metadata = json.load(f)
|
||||
assert len(metadata["loops"]) == 1
|
||||
assert metadata["loops"][0]["id"] == "aabbccdd"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue