refactor: split pod metadata store
This commit is contained in:
@@ -13,6 +13,7 @@ async-trait = { workspace = true }
|
||||
clap = { version = "4.6.0", features = ["derive"] }
|
||||
llm-worker = { workspace = true }
|
||||
session-store = { workspace = true }
|
||||
pod-store = { workspace = true }
|
||||
manifest = { workspace = true }
|
||||
protocol = { workspace = true }
|
||||
provider = { workspace = true }
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
//! ```
|
||||
|
||||
use pod::{Pod, PodManifest, PodRunResult};
|
||||
use pod_store::{CombinedStore, FsPodStore};
|
||||
use session_store::FsStore;
|
||||
|
||||
fn manifest_toml(pwd: &std::path::Path) -> String {
|
||||
@@ -48,7 +49,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
// 2. Create a persistent store (temp dir for demo)
|
||||
let tmp = tempfile::tempdir()?;
|
||||
let store = FsStore::new(tmp.path())?;
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(tmp.path().join("sessions"))?,
|
||||
FsPodStore::new(tmp.path().join("pods"))?,
|
||||
);
|
||||
|
||||
// 3. Build the Pod from the single-layer manifest TOML
|
||||
let mut pod = Pod::from_manifest_toml(&toml, store).await?;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//! ```
|
||||
|
||||
use pod::{Event, Method, PodController};
|
||||
use pod_store::{CombinedStore, FsPodStore};
|
||||
use session_store::FsStore;
|
||||
|
||||
fn manifest_toml(pwd: &std::path::Path) -> String {
|
||||
@@ -39,7 +40,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let pwd = std::env::current_dir()?;
|
||||
let toml = manifest_toml(&pwd);
|
||||
let tmp = tempfile::tempdir()?;
|
||||
let store = FsStore::new(tmp.path())?;
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(tmp.path().join("sessions"))?,
|
||||
FsPodStore::new(tmp.path().join("pods"))?,
|
||||
);
|
||||
let pod = pod::Pod::from_manifest_toml(&toml, store).await?;
|
||||
|
||||
let runtime_tmp = tempfile::tempdir()?;
|
||||
|
||||
@@ -4,7 +4,8 @@ use std::sync::atomic::Ordering;
|
||||
|
||||
use llm_worker::WorkerError;
|
||||
use llm_worker::llm_client::client::LlmClient;
|
||||
use session_store::{PodMetadataStore, Store};
|
||||
use pod_store::PodMetadataStore;
|
||||
use session_store::Store;
|
||||
use tokio::sync::{broadcast, mpsc, oneshot};
|
||||
|
||||
use crate::discovery::{
|
||||
|
||||
@@ -15,11 +15,12 @@ use std::time::Duration;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use llm_worker::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
|
||||
use pod_store::{PodActiveSegmentRef, PodMetadata, PodMetadataStore};
|
||||
use protocol::stream::JsonLineReader;
|
||||
use protocol::{Event, PodStatus};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use session_store::{PodActiveSegmentRef, PodMetadata, PodMetadataStore, SegmentId, SessionId};
|
||||
use session_store::{SegmentId, SessionId};
|
||||
use tokio::net::UnixStream;
|
||||
use tokio::process::Command;
|
||||
|
||||
@@ -496,8 +497,10 @@ pub enum PodDiscoveryError {
|
||||
socket_path: PathBuf,
|
||||
pid: u32,
|
||||
},
|
||||
#[error("store error: {0}")]
|
||||
#[error("session store error: {0}")]
|
||||
Store(#[from] session_store::StoreError),
|
||||
#[error("pod store error: {0}")]
|
||||
PodStore(#[from] pod_store::PodStoreError),
|
||||
#[error("scope lock error: {0}")]
|
||||
ScopeLock(#[from] pod_registry::ScopeLockError),
|
||||
#[error("failed to launch restore process: {0}")]
|
||||
@@ -527,7 +530,7 @@ impl VisibilitySet {
|
||||
}
|
||||
|
||||
async fn summarize_spawned_children(
|
||||
children: &[session_store::PodSpawnedChild],
|
||||
children: &[pod_store::PodSpawnedChild],
|
||||
) -> SpawnedChildrenSummary {
|
||||
let mut summary = SpawnedChildrenSummary {
|
||||
count: children.len(),
|
||||
@@ -752,6 +755,7 @@ fn discovery_error_to_tool_error(error: PodDiscoveryError) -> ToolError {
|
||||
| PodDiscoveryError::NotRestorable { .. } => ToolError::InvalidArgument(error.to_string()),
|
||||
PodDiscoveryError::LockConflict { .. }
|
||||
| PodDiscoveryError::Store(_)
|
||||
| PodDiscoveryError::PodStore(_)
|
||||
| PodDiscoveryError::ScopeLock(_)
|
||||
| PodDiscoveryError::RestoreSpawn(_)
|
||||
| PodDiscoveryError::RestoreExited { .. }
|
||||
@@ -765,11 +769,10 @@ mod tests {
|
||||
use std::sync::Mutex;
|
||||
|
||||
use manifest::{Permission, ScopeRule};
|
||||
use pod_store::{FsPodStore, PodSpawnedChild, PodSpawnedScopeRule};
|
||||
use protocol::stream::JsonLineWriter;
|
||||
use protocol::{Alert, AlertLevel, AlertSource, Greeting};
|
||||
use session_store::{
|
||||
FsStore, PodSpawnedChild, PodSpawnedScopeRule, new_segment_id, new_session_id,
|
||||
};
|
||||
use session_store::{new_segment_id, new_session_id};
|
||||
use tempfile::TempDir;
|
||||
use tokio::net::UnixListener;
|
||||
|
||||
@@ -788,7 +791,7 @@ mod tests {
|
||||
std::env::set_var("INSOMNIA_RUNTIME_DIR", &runtime_base);
|
||||
}
|
||||
|
||||
let store = FsStore::new(&store_dir).unwrap();
|
||||
let store = FsPodStore::new(&store_dir).unwrap();
|
||||
let session_id = new_session_id();
|
||||
let active_child_segment = new_segment_id();
|
||||
let pending_session_id = new_session_id();
|
||||
|
||||
+19
-3
@@ -6,7 +6,8 @@ use manifest::{
|
||||
NixProfileResolver, PodManifest, PodManifestConfig, ProfileSelector, ScopeConfig, paths,
|
||||
};
|
||||
use pod::{Pod, PodController, PromptLoader};
|
||||
use session_store::{FsStore, PodMetadataStore, SegmentId, Store};
|
||||
use pod_store::{CombinedStore, FsPodStore, PodMetadataStore};
|
||||
use session_store::{FsStore, SegmentId, Store};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(
|
||||
@@ -229,13 +230,28 @@ async fn main() -> ExitCode {
|
||||
}
|
||||
},
|
||||
};
|
||||
let store = match FsStore::new(&store_dir) {
|
||||
let session_store = match FsStore::new(&store_dir) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("error: failed to initialize store at {store_dir:?}: {e}");
|
||||
eprintln!("error: failed to initialize session store at {store_dir:?}: {e}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
let pod_store_dir = match paths::data_dir() {
|
||||
Some(data_dir) => data_dir.join("pods"),
|
||||
None => store_dir
|
||||
.parent()
|
||||
.map(|parent| parent.join("pods"))
|
||||
.unwrap_or_else(|| PathBuf::from("pods")),
|
||||
};
|
||||
let pod_store = match FsPodStore::new(&pod_store_dir) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("error: failed to initialize pod store at {pod_store_dir:?}: {e}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
let store = CombinedStore::new(session_store, pod_store);
|
||||
|
||||
let pod = if cli.adopt {
|
||||
let callback = match cli.callback.clone() {
|
||||
|
||||
+23
-13
@@ -9,9 +9,10 @@ use llm_worker::llm_client::client::LlmClient;
|
||||
use llm_worker::llm_client::types::Role;
|
||||
use llm_worker::state::Mutable;
|
||||
use llm_worker::{ToolOutputLimits, UsageRecord, Worker, WorkerError, WorkerResult};
|
||||
use pod_store::{PodActiveSegmentRef, PodMetadata, PodMetadataStore, PodStoreError};
|
||||
use session_store::{
|
||||
LogEntry, PodActiveSegmentRef, PodMetadata, PodMetadataStore, PodScopeSnapshot, SegmentId,
|
||||
SessionId, Store, StoreError, SystemItem, segment_log, to_logged,
|
||||
LogEntry, PodScopeSnapshot, SegmentId, SessionId, Store, StoreError, SystemItem, segment_log,
|
||||
to_logged,
|
||||
};
|
||||
use tracing::{info, warn};
|
||||
|
||||
@@ -53,18 +54,21 @@ pub struct SegmentLocation {
|
||||
pub segment_id: SegmentId,
|
||||
}
|
||||
|
||||
type PodMetadataWriter = Arc<dyn Fn(PodMetadata) -> Result<(), StoreError> + Send + Sync>;
|
||||
type PodMetadataWriter = Arc<dyn Fn(PodMetadata) -> Result<(), PodStoreError> + Send + Sync>;
|
||||
|
||||
fn pod_metadata_writer_for_store<St>(store: &St) -> PodMetadataWriter
|
||||
where
|
||||
St: PodMetadataStore + Clone + Send + Sync + 'static,
|
||||
{
|
||||
let store = store.clone();
|
||||
Arc::new(move |mut metadata| {
|
||||
if let Some(existing) = store.read_by_name(&metadata.pod_name)? {
|
||||
metadata.spawned_children = existing.spawned_children;
|
||||
}
|
||||
store.write(&metadata)
|
||||
Arc::new(move |metadata| {
|
||||
store
|
||||
.set_active(
|
||||
&metadata.pod_name,
|
||||
metadata.active,
|
||||
metadata.resolved_manifest_snapshot,
|
||||
)
|
||||
.map(|_| ())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -925,30 +929,32 @@ impl<C: LlmClient, St: Store> Pod<C, St> {
|
||||
metadata
|
||||
}
|
||||
|
||||
fn write_pod_metadata_pending(&self) -> Result<(), StoreError> {
|
||||
fn write_pod_metadata_pending(&self) -> Result<(), PodError> {
|
||||
let Some(writer) = &self.pod_metadata_writer else {
|
||||
return Ok(());
|
||||
};
|
||||
writer(self.pod_metadata(Some(PodActiveSegmentRef::pending_segment(
|
||||
self.session_id(),
|
||||
))))
|
||||
))))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_pod_metadata_active(&self, loc: SegmentLocation) -> Result<(), StoreError> {
|
||||
fn write_pod_metadata_active(&self, loc: SegmentLocation) -> Result<(), PodError> {
|
||||
let Some(writer) = &self.pod_metadata_writer else {
|
||||
return Ok(());
|
||||
};
|
||||
writer(self.pod_metadata(Some(PodActiveSegmentRef::active_segment(
|
||||
loc.session_id,
|
||||
loc.segment_id,
|
||||
))))
|
||||
))))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Enable name-keyed Pod metadata write-through for Pods built through
|
||||
/// the low-level constructor. High-level manifest constructors enable it
|
||||
/// automatically; this hook lets tests and custom embedders opt into the
|
||||
/// same persistence behavior without changing `Pod::new`'s minimal bounds.
|
||||
pub fn enable_pod_metadata_write_through(&mut self) -> Result<(), StoreError>
|
||||
pub fn enable_pod_metadata_write_through(&mut self) -> Result<(), PodError>
|
||||
where
|
||||
St: PodMetadataStore + Clone + Send + Sync + 'static,
|
||||
{
|
||||
@@ -4438,6 +4444,7 @@ fn token_budget_bytes(tokens: u64) -> usize {
|
||||
pub enum RewindError {
|
||||
#[error(transparent)]
|
||||
Store(#[from] StoreError),
|
||||
|
||||
#[error("{0}")]
|
||||
Invalid(String),
|
||||
}
|
||||
@@ -4546,6 +4553,9 @@ pub enum PodError {
|
||||
#[error(transparent)]
|
||||
Store(#[from] StoreError),
|
||||
|
||||
#[error(transparent)]
|
||||
PodStore(#[from] PodStoreError),
|
||||
|
||||
#[error(transparent)]
|
||||
Scope(ScopeError),
|
||||
|
||||
|
||||
@@ -20,10 +20,8 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use manifest::{Permission, ScopeRule, SharedScope};
|
||||
use session_store::{
|
||||
PodMetadata, PodMetadataStore, PodScopeSnapshot, PodSpawnedChild, PodSpawnedScopeRule,
|
||||
StoreError,
|
||||
};
|
||||
use pod_store::{PodMetadataStore, PodSpawnedChild, PodSpawnedScopeRule, PodStoreError};
|
||||
use session_store::PodScopeSnapshot;
|
||||
use tokio::net::UnixStream;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::warn;
|
||||
@@ -304,18 +302,16 @@ fn write_records_to_pod_state<St>(
|
||||
store: &St,
|
||||
pod_name: &str,
|
||||
records: &[SpawnedPodRecord],
|
||||
) -> Result<(), StoreError>
|
||||
) -> Result<(), PodStoreError>
|
||||
where
|
||||
St: PodMetadataStore,
|
||||
{
|
||||
let mut metadata = store
|
||||
.read_by_name(pod_name)?
|
||||
.unwrap_or_else(|| PodMetadata::new(pod_name, None));
|
||||
metadata.spawned_children = records
|
||||
let children = records
|
||||
.iter()
|
||||
.map(record_to_pod_state)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
store.write(&metadata)
|
||||
store.set_spawned_children(pod_name, children)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn record_to_pod_state(record: &SpawnedPodRecord) -> Result<PodSpawnedChild, serde_json::Error> {
|
||||
@@ -366,7 +362,7 @@ fn record_from_pod_state(child: &PodSpawnedChild) -> Result<SpawnedPodRecord, se
|
||||
})
|
||||
}
|
||||
|
||||
fn store_error_to_io(error: StoreError) -> io::Error {
|
||||
fn store_error_to_io(error: PodStoreError) -> io::Error {
|
||||
io::Error::other(error)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,15 @@ use llm_worker::Worker;
|
||||
use llm_worker::llm_client::event::{Event as LlmEvent, ResponseStatus, StatusEvent};
|
||||
use llm_worker::llm_client::types::Item;
|
||||
use llm_worker::llm_client::{ClientError, LlmClient, Request};
|
||||
use pod_store::{CombinedStore, FsPodStore, PodMetadataStore};
|
||||
use protocol::{Event, Method, RunResult};
|
||||
use session_store::{FsStore, LogEntry, PodMetadataStore, Store};
|
||||
use session_store::{FsStore, LogEntry, Store};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
use pod::{Pod, PodController};
|
||||
|
||||
type TestStore = CombinedStore<FsStore, FsPodStore>;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MockClient {
|
||||
responses: Arc<Vec<Vec<LlmEvent>>>,
|
||||
@@ -145,11 +148,14 @@ permission = "write"
|
||||
async fn make_pod_with_manifest(
|
||||
manifest_toml: &str,
|
||||
client: MockClient,
|
||||
) -> Pod<MockClient, FsStore> {
|
||||
) -> Pod<MockClient, TestStore> {
|
||||
let manifest = pod::PodManifest::from_toml(manifest_toml).unwrap();
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
std::mem::forget(store_tmp);
|
||||
|
||||
let pwd_tmp = tempfile::tempdir().unwrap();
|
||||
@@ -163,7 +169,7 @@ async fn make_pod_with_manifest(
|
||||
pod
|
||||
}
|
||||
|
||||
async fn make_pod(client: MockClient) -> Pod<MockClient, FsStore> {
|
||||
async fn make_pod(client: MockClient) -> Pod<MockClient, TestStore> {
|
||||
make_pod_with_manifest(POST_RUN_MANIFEST_TOML, client).await
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@ use llm_worker::llm_client::{ClientError, LlmClient, Request};
|
||||
use memory::WorkspaceLayout;
|
||||
use memory::extract::{ExtractedPayload, write_staging};
|
||||
use memory::schema::SourceRef;
|
||||
use pod_store::{CombinedStore, FsPodStore};
|
||||
use session_store::FsStore;
|
||||
|
||||
type TestStore = CombinedStore<FsStore, FsPodStore>;
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
use pod::{Event, Pod};
|
||||
@@ -155,11 +158,14 @@ async fn make_pod_with(
|
||||
manifest_toml: &str,
|
||||
pwd: std::path::PathBuf,
|
||||
client: MockClient,
|
||||
) -> Pod<MockClient, FsStore> {
|
||||
) -> Pod<MockClient, TestStore> {
|
||||
let manifest = pod::PodManifest::from_toml(manifest_toml).unwrap();
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
std::mem::forget(store_tmp);
|
||||
|
||||
let scope = pod::Scope::writable(&pwd).unwrap();
|
||||
@@ -184,7 +190,7 @@ fn write_n_staging(layout: &WorkspaceLayout, n: usize) -> Vec<uuid::Uuid> {
|
||||
ids
|
||||
}
|
||||
|
||||
fn attach_event_receiver(pod: &mut Pod<MockClient, FsStore>) -> broadcast::Receiver<Event> {
|
||||
fn attach_event_receiver(pod: &mut Pod<MockClient, TestStore>) -> broadcast::Receiver<Event> {
|
||||
let (tx, rx) = broadcast::channel(16);
|
||||
pod.attach_event_tx(tx);
|
||||
rx
|
||||
|
||||
@@ -9,10 +9,13 @@ use llm_worker::llm_client::event::{Event as LlmEvent, ResponseStatus, StatusEve
|
||||
use llm_worker::llm_client::types::Item;
|
||||
use llm_worker::llm_client::{ClientError, LlmClient, Request};
|
||||
use llm_worker::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
|
||||
use pod_store::{CombinedStore, FsPodStore};
|
||||
use session_store::{FsStore, LogEntry};
|
||||
|
||||
use pod::{Event, Method, Pod, PodController, PodHandle, PodManifest, PodStatus};
|
||||
|
||||
type TestStore = CombinedStore<FsStore, FsPodStore>;
|
||||
|
||||
/// Reconstruct a worker-history-like `Vec<Item>` from the live session
|
||||
/// log mirror held by the Pod's broadcast sink. Replaces the previous
|
||||
/// `PodSharedState.history()` test helper now that the mirror lives in
|
||||
@@ -152,21 +155,24 @@ target = "./"
|
||||
permission = "write"
|
||||
"#;
|
||||
|
||||
async fn make_pod(client: MockClient) -> Pod<MockClient, FsStore> {
|
||||
async fn make_pod(client: MockClient) -> Pod<MockClient, TestStore> {
|
||||
make_pod_with_pwd(client).await.0
|
||||
}
|
||||
|
||||
async fn make_pod_with_pwd(client: MockClient) -> (Pod<MockClient, FsStore>, std::path::PathBuf) {
|
||||
async fn make_pod_with_pwd(client: MockClient) -> (Pod<MockClient, TestStore>, std::path::PathBuf) {
|
||||
make_pod_with_pwd_and_manifest(client, MANIFEST_TOML).await
|
||||
}
|
||||
|
||||
async fn make_pod_with_pwd_and_manifest(
|
||||
client: MockClient,
|
||||
manifest_toml: &str,
|
||||
) -> (Pod<MockClient, FsStore>, std::path::PathBuf) {
|
||||
) -> (Pod<MockClient, TestStore>, std::path::PathBuf) {
|
||||
let manifest = PodManifest::from_toml(manifest_toml).unwrap();
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
std::mem::forget(store_tmp);
|
||||
|
||||
// Separate tempdir to serve as the Pod's pwd/scope — these tests
|
||||
@@ -184,7 +190,7 @@ async fn make_pod_with_pwd_and_manifest(
|
||||
(pod, pwd)
|
||||
}
|
||||
|
||||
async fn spawn_controller(pod: Pod<MockClient, FsStore>) -> PodHandle {
|
||||
async fn spawn_controller(pod: Pod<MockClient, TestStore>) -> PodHandle {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let runtime_base = tmp.path().to_owned();
|
||||
std::mem::forget(tmp);
|
||||
|
||||
@@ -20,10 +20,11 @@ use pod::spawn::comm_tools::{
|
||||
list_pods_tool, read_pod_output_tool, send_to_pod_tool, stop_pod_tool,
|
||||
};
|
||||
use pod::spawn::registry::SpawnedPodRegistry;
|
||||
use pod_store::{CombinedStore, FsPodStore, PodMetadataStore};
|
||||
use protocol::stream::{JsonLineReader, JsonLineWriter};
|
||||
use protocol::{ErrorCode, Event, Greeting, Method};
|
||||
use serde_json::json;
|
||||
use session_store::{FsStore, PodMetadataStore};
|
||||
use session_store::FsStore;
|
||||
use tempfile::TempDir;
|
||||
use tokio::net::UnixListener;
|
||||
use tokio::sync::mpsc;
|
||||
@@ -385,7 +386,10 @@ async fn stop_pod_sends_shutdown_and_releases_scope() {
|
||||
let _env = EnvGuard::acquire();
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let store_tmp = TempDir::new().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let rd = Arc::new(RuntimeDir::create(tmp.path(), "spawner").await.unwrap());
|
||||
let parent_scope = SharedScope::new(
|
||||
Scope::writable(tmp.path())
|
||||
@@ -512,7 +516,10 @@ async fn restored_registry_uses_pod_state_without_runtime_file() {
|
||||
let _env = EnvGuard::acquire();
|
||||
let runtime_tmp = TempDir::new().unwrap();
|
||||
let store_tmp = TempDir::new().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
unsafe {
|
||||
std::env::set_var("INSOMNIA_RUNTIME_DIR", runtime_tmp.path());
|
||||
}
|
||||
@@ -582,7 +589,10 @@ async fn restored_registry_uses_pod_state_without_runtime_file() {
|
||||
async fn load_from_pod_state_prunes_runtime_children_but_preserves_durable_state() {
|
||||
let runtime_tmp = TempDir::new().unwrap();
|
||||
let store_tmp = TempDir::new().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let rd = Arc::new(
|
||||
RuntimeDir::create(runtime_tmp.path(), "spawner")
|
||||
.await
|
||||
@@ -635,7 +645,10 @@ async fn load_from_pod_state_reclaims_pruned_child_scope_without_deleting_pod_st
|
||||
let _env = EnvGuard::acquire();
|
||||
let runtime_tmp = TempDir::new().unwrap();
|
||||
let store_tmp = TempDir::new().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
unsafe {
|
||||
std::env::set_var("INSOMNIA_RUNTIME_DIR", runtime_tmp.path());
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
use std::sync::{LazyLock, Mutex};
|
||||
|
||||
use pod::{Pod, PodError};
|
||||
use session_store::{FsStore, PodActiveSegmentRef, PodMetadata, PodMetadataStore, StoreError};
|
||||
use pod_store::{CombinedStore, FsPodStore, PodActiveSegmentRef, PodMetadata, PodMetadataStore};
|
||||
use session_store::{FsStore, StoreError};
|
||||
|
||||
const MINIMAL_MANIFEST_TOML: &str = r#"
|
||||
[pod]
|
||||
@@ -36,7 +37,10 @@ async fn restore_from_pod_metadata_rejects_missing_metadata() {
|
||||
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let manifest = pod::PodManifest::from_toml(MINIMAL_MANIFEST_TOML).unwrap();
|
||||
|
||||
let result = Pod::restore_from_pod_metadata(
|
||||
@@ -59,7 +63,10 @@ async fn restore_from_pod_metadata_rejects_pending_segment() {
|
||||
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let manifest = pod::PodManifest::from_toml(MINIMAL_MANIFEST_TOML).unwrap();
|
||||
let session_id = session_store::new_session_id();
|
||||
store
|
||||
@@ -95,7 +102,10 @@ async fn restore_from_pod_metadata_resolves_active_pointer_through_session_log()
|
||||
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let manifest = pod::PodManifest::from_toml(MINIMAL_MANIFEST_TOML).unwrap();
|
||||
let session_id = session_store::new_session_id();
|
||||
let segment_id = session_store::new_segment_id();
|
||||
@@ -126,7 +136,10 @@ async fn restore_from_manifest_rejects_unknown_segment() {
|
||||
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let manifest = pod::PodManifest::from_toml(MINIMAL_MANIFEST_TOML).unwrap();
|
||||
|
||||
// A freshly-minted id with no jsonl file at all → store returns
|
||||
@@ -155,7 +168,10 @@ async fn restore_from_manifest_rejects_empty_segment_log() {
|
||||
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let manifest = pod::PodManifest::from_toml(MINIMAL_MANIFEST_TOML).unwrap();
|
||||
|
||||
// Pre-create an empty `<sid>/<segid>.jsonl` so `read_all` succeeds
|
||||
@@ -189,7 +205,10 @@ async fn restore_from_manifest_rejects_segment_without_scope_snapshot() {
|
||||
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let manifest = pod::PodManifest::from_toml(MINIMAL_MANIFEST_TOML).unwrap();
|
||||
|
||||
let sid = session_store::new_session_id();
|
||||
|
||||
@@ -25,11 +25,14 @@ use llm_worker::Worker;
|
||||
use llm_worker::llm_client::event::{Event as LlmEvent, ResponseStatus, StatusEvent, UsageEvent};
|
||||
use llm_worker::llm_client::{ClientError, LlmClient, Request};
|
||||
use llm_worker::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
|
||||
use pod_store::{CombinedStore, FsPodStore};
|
||||
use session_metrics::{DOMAIN, Metric, metrics_from_extensions};
|
||||
use session_store::{FsStore, LogEntry, SegmentId, SessionId, Store, StoreError, TraceEntry};
|
||||
|
||||
use pod::{Pod, PodManifest};
|
||||
|
||||
type TestStore = CombinedStore<FsStore, FsPodStore>;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MockClient {
|
||||
responses: Arc<Vec<Vec<LlmEvent>>>,
|
||||
@@ -166,13 +169,16 @@ async fn make_pod(
|
||||
client: MockClient,
|
||||
tool_name: &'static str,
|
||||
) -> (
|
||||
Pod<MockClient, FsStore>,
|
||||
Pod<MockClient, TestStore>,
|
||||
tempfile::TempDir,
|
||||
tempfile::TempDir,
|
||||
) {
|
||||
let manifest = PodManifest::from_toml(&manifest_toml).unwrap();
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let pwd_tmp = tempfile::tempdir().unwrap();
|
||||
let pwd = pwd_tmp.path().to_path_buf();
|
||||
let scope = pod::Scope::writable(&pwd).unwrap();
|
||||
@@ -500,7 +506,10 @@ permission = "write"
|
||||
let client = MockClient::new(vec![text_response_with_cache("hi", 0, 0)]);
|
||||
let manifest = PodManifest::from_toml(manifest_toml).unwrap();
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
let pwd_tmp = tempfile::tempdir().unwrap();
|
||||
let pwd = pwd_tmp.path().to_path_buf();
|
||||
let scope = pod::Scope::writable(&pwd).unwrap();
|
||||
|
||||
@@ -8,10 +8,13 @@ use futures::Stream;
|
||||
use llm_worker::Worker;
|
||||
use llm_worker::llm_client::event::{Event as LlmEvent, ResponseStatus, StatusEvent};
|
||||
use llm_worker::llm_client::{ClientError, LlmClient, Request};
|
||||
use pod_store::{CombinedStore, FsPodStore};
|
||||
use session_store::{FsStore, LogEntry, Store};
|
||||
|
||||
use pod::{Pod, PodError, PromptLoader, SystemPromptTemplate};
|
||||
|
||||
type TestStore = CombinedStore<FsStore, FsPodStore>;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock LLM Client
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -99,11 +102,14 @@ permission = "write"
|
||||
async fn make_pod_with_body(
|
||||
body: &str,
|
||||
client: MockClient,
|
||||
) -> Result<(Pod<MockClient, FsStore>, PathBuf), PodError> {
|
||||
) -> Result<(Pod<MockClient, TestStore>, PathBuf), PodError> {
|
||||
let manifest = pod::PodManifest::from_toml(MINIMAL_MANIFEST_TOML).unwrap();
|
||||
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = FsStore::new(store_tmp.path()).unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
|
||||
);
|
||||
std::mem::forget(store_tmp);
|
||||
|
||||
let pwd_tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user