vtcode_core/utils/
session_archive.rs1mod 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;