Skip to main content

vtcode_core/utils/
session_archive.rs

1mod archive;
2mod identifier;
3mod message;
4mod metadata;
5mod query;
6mod retention;
7mod search;
8mod settings;
9mod shrink;
10mod snapshot;
11mod transcript;
12
13pub use self::archive::SessionArchive;
14#[cfg(test)]
15pub(crate) use self::identifier::generate_unique_archive_path;
16pub use self::identifier::{generate_session_archive_identifier, reserve_session_archive_identifier};
17pub(crate) use self::query::resolve_sessions_dir_for_archive_writes;
18pub use self::query::{find_session_by_id_or_name, find_session_by_identifier, list_recent_sessions};
19#[cfg(test)]
20pub(crate) use self::retention::{SessionRetentionLimits, apply_session_retention_with_limits};
21#[cfg(test)]
22pub(crate) use self::shrink::{compact_snapshot_to_max_bytes, truncate_preview};
23#[cfg(test)]
24pub(crate) use self::transcript::clean_transcript_lines;
25
26pub use self::message::SessionMessage;
27pub use self::metadata::{
28    SessionArchiveMetadata, SessionContinuationExhaustionReason, SessionContinuationMetadata,
29    SessionContinuationRecommendedAction, SessionForkMode,
30};
31
32pub use self::search::{SearchResult, search_sessions};
33pub use self::settings::{
34    SESSION_DIR_ENV, SESSION_MAX_AGE_DAYS_ENV, SESSION_MAX_FILES_ENV, SESSION_MAX_SIZE_MB_ENV,
35    apply_session_history_config_from_vtcode, history_persistence_enabled,
36};
37#[cfg(test)]
38pub(crate) use self::settings::{
39    SessionHistorySettings, clear_sessions_dir_override_for_tests, clear_test_env_override,
40    override_sessions_dir_for_tests, session_history_settings, set_test_env_override_path,
41};
42pub use self::snapshot::{
43    SessionListing, SessionProgress, SessionProgressArgs, SessionProgressPersistenceStatus, SessionSnapshot,
44    VerifiedSessionArchiveIdentifier, session_listing_matches_workspace, session_workspace_path,
45};
46
47const SESSION_FILE_PREFIX: &str = "session";
48const SESSION_FILE_EXTENSION: &str = "json";
49const DEFAULT_SESSION_MAX_FILES: usize = 100;
50const DEFAULT_SESSION_MAX_AGE_DAYS: u64 = 14;
51const DEFAULT_SESSION_MAX_SIZE_MB: u64 = 100;
52const BYTES_PER_MB: u64 = 1024 * 1024;
53
54#[cfg(test)]
55mod metadata_compat_tests {
56    use super::{SessionArchive, SessionArchiveMetadata};
57
58    #[test]
59    fn primary_agent_metadata_is_backward_compatible() {
60        let metadata = serde_json::from_value::<SessionArchiveMetadata>(serde_json::json!({
61            "workspace_label": "ws",
62            "workspace_path": "/tmp/ws",
63            "model": "gpt-5.6-sol",
64            "provider": "openai",
65            "theme": "test",
66            "reasoning_effort": "low"
67        }))
68        .expect("deserialize metadata without primary_agent");
69
70        assert_eq!(metadata.primary_agent, None);
71
72        let value = serde_json::to_value(&metadata).expect("serialize metadata");
73        assert!(value.get("primary_agent").is_none());
74    }
75
76    #[test]
77    fn set_primary_agent_records_mode_on_archive() {
78        let metadata = SessionArchiveMetadata::new("ws", "/tmp/ws", "gpt-5.6-sol", "openai", "test", "low");
79        let mut archive = tokio::runtime::Runtime::new()
80            .expect("runtime")
81            .block_on(SessionArchive::new_with_identifier(metadata, "ws-0000".to_string()))
82            .expect("create archive");
83        assert_eq!(archive.metadata().primary_agent, None);
84
85        archive.set_primary_agent("plan");
86        assert_eq!(archive.metadata().primary_agent.as_deref(), Some("plan"));
87    }
88}
89
90#[cfg(test)]
91#[path = "session_archive_tests.rs"]
92mod tests;