refactor: make rollout and app protocol wasm-tolerant

This commit is contained in:
Jeremy lewi
2026-04-14 14:21:15 -07:00
parent 54d765635a
commit e8cdf68bdd
6 changed files with 659 additions and 69 deletions

View File

@@ -25,16 +25,18 @@ serde_with = { workspace = true }
shlex = { workspace = true }
strum_macros = { workspace = true }
thiserror = { workspace = true }
ts-rs = { workspace = true }
inventory = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true, features = ["serde", "v7"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
rmcp = { workspace = true, default-features = false, features = [
"base64",
"macros",
"schemars",
"server",
] }
ts-rs = { workspace = true }
inventory = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true, features = ["serde", "v7"] }
[dev-dependencies]
anyhow = { workspace = true }

View File

@@ -5295,6 +5295,7 @@ impl McpServerElicitationAction {
}
}
#[cfg(not(target_arch = "wasm32"))]
impl From<McpServerElicitationAction> for rmcp::model::ElicitationAction {
fn from(value: McpServerElicitationAction) -> Self {
match value {
@@ -5305,6 +5306,7 @@ impl From<McpServerElicitationAction> for rmcp::model::ElicitationAction {
}
}
#[cfg(not(target_arch = "wasm32"))]
impl From<rmcp::model::ElicitationAction> for McpServerElicitationAction {
fn from(value: rmcp::model::ElicitationAction) -> Self {
match value {
@@ -5722,6 +5724,7 @@ pub struct McpServerElicitationRequestResponse {
pub meta: Option<JsonValue>,
}
#[cfg(not(target_arch = "wasm32"))]
impl From<McpServerElicitationRequestResponse> for rmcp::model::CreateElicitationResult {
fn from(value: McpServerElicitationRequestResponse) -> Self {
Self {
@@ -5731,6 +5734,7 @@ impl From<McpServerElicitationRequestResponse> for rmcp::model::CreateElicitatio
}
}
#[cfg(not(target_arch = "wasm32"))]
impl From<rmcp::model::CreateElicitationResult> for McpServerElicitationRequestResponse {
fn from(value: rmcp::model::CreateElicitationResult) -> Self {
Self {
@@ -7186,6 +7190,7 @@ mod tests {
assert_eq!(reason, Some("askForApproval.granular"));
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn mcp_server_elicitation_response_round_trips_rmcp_result() {
let rmcp_result = rmcp::model::CreateElicitationResult {

View File

@@ -47,10 +47,8 @@ codex-network-proxy = { workspace = true }
codex-otel = { workspace = true }
codex-plugin = { workspace = true }
codex-protocol = { workspace = true }
codex-rollout = { workspace = true }
codex-rmcp-client = { workspace = true }
codex-sandboxing = { workspace = true }
codex-state = { workspace = true }
codex-terminal-detection = { workspace = true }
codex-tools = { workspace = true }
codex-utils-absolute-path = { workspace = true }
@@ -124,6 +122,8 @@ seccompiler = { workspace = true }
core-foundation = "0.9"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
codex-rollout = { workspace = true }
codex-state = { workspace = true }
tokio-tungstenite = { workspace = true }
# Build OpenSSL from source for musl builds.

View File

@@ -153,7 +153,9 @@ pub mod shell;
pub mod shell_snapshot;
pub mod spawn;
pub mod state_db_bridge;
pub use codex_rollout::state_db;
pub mod state_db {
pub use crate::state_db_bridge::*;
}
mod thread_rollout_truncation;
mod tools;
pub mod turn_diff_tracker;

View File

@@ -1,63 +1,476 @@
use crate::config::Config;
pub use codex_rollout::ARCHIVED_SESSIONS_SUBDIR;
pub use codex_rollout::INTERACTIVE_SESSION_SOURCES;
pub use codex_rollout::RolloutRecorder;
pub use codex_rollout::RolloutRecorderParams;
pub use codex_rollout::SESSIONS_SUBDIR;
pub use codex_rollout::SessionMeta;
pub use codex_rollout::append_thread_name;
pub use codex_rollout::find_archived_thread_path_by_id_str;
#[deprecated(note = "use find_thread_path_by_id_str")]
pub use codex_rollout::find_conversation_path_by_id_str;
pub use codex_rollout::find_thread_name_by_id;
pub use codex_rollout::find_thread_path_by_id_str;
pub use codex_rollout::find_thread_path_by_name_str;
pub use codex_rollout::rollout_date_parts;
#[cfg(not(target_arch = "wasm32"))]
mod native {
use crate::config::Config;
impl codex_rollout::RolloutConfigView for Config {
fn codex_home(&self) -> &std::path::Path {
self.codex_home.as_path()
pub use codex_rollout::ARCHIVED_SESSIONS_SUBDIR;
pub use codex_rollout::INTERACTIVE_SESSION_SOURCES;
pub use codex_rollout::RolloutRecorder;
pub use codex_rollout::RolloutRecorderParams;
pub use codex_rollout::SESSIONS_SUBDIR;
pub use codex_rollout::SessionMeta;
pub use codex_rollout::append_thread_name;
pub use codex_rollout::find_archived_thread_path_by_id_str;
#[deprecated(note = "use find_thread_path_by_id_str")]
pub use codex_rollout::find_conversation_path_by_id_str;
pub use codex_rollout::find_thread_name_by_id;
pub use codex_rollout::find_thread_path_by_id_str;
pub use codex_rollout::find_thread_path_by_name_str;
pub use codex_rollout::rollout_date_parts;
impl codex_rollout::RolloutConfigView for Config {
fn codex_home(&self) -> &std::path::Path {
self.codex_home.as_path()
}
fn sqlite_home(&self) -> &std::path::Path {
self.sqlite_home.as_path()
}
fn cwd(&self) -> &std::path::Path {
self.cwd.as_path()
}
fn model_provider_id(&self) -> &str {
self.model_provider_id.as_str()
}
fn generate_memories(&self) -> bool {
self.memories.generate_memories
}
}
fn sqlite_home(&self) -> &std::path::Path {
self.sqlite_home.as_path()
pub mod list {
pub use codex_rollout::list::*;
}
fn cwd(&self) -> &std::path::Path {
self.cwd.as_path()
pub(crate) mod metadata {
pub(crate) use codex_rollout::metadata::builder_from_items;
}
fn model_provider_id(&self) -> &str {
self.model_provider_id.as_str()
pub mod policy {
pub use codex_rollout::policy::*;
}
fn generate_memories(&self) -> bool {
self.memories.generate_memories
pub mod recorder {
pub use codex_rollout::recorder::*;
}
pub mod session_index {
pub use codex_rollout::session_index::*;
}
pub(crate) use crate::session_rollout_init_error::map_session_init_error;
pub(crate) mod truncation {
pub(crate) use crate::thread_rollout_truncation::*;
}
}
pub mod list {
pub use codex_rollout::list::*;
#[cfg(target_arch = "wasm32")]
mod wasm {
use std::collections::HashMap;
use std::collections::HashSet;
use std::ffi::OsStr;
use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::sync::LazyLock;
use codex_protocol::ThreadId;
use codex_protocol::dynamic_tools::DynamicToolSpec;
use codex_protocol::models::BaseInstructions;
use codex_protocol::protocol::InitialHistory;
use codex_protocol::protocol::RolloutItem;
use codex_protocol::protocol::SessionMeta;
use codex_protocol::protocol::SessionMetaLine;
use codex_protocol::protocol::SessionSource;
use crate::config::Config;
use crate::state_db::StateDbHandle;
pub const SESSIONS_SUBDIR: &str = "sessions";
pub const ARCHIVED_SESSIONS_SUBDIR: &str = "archived_sessions";
pub static INTERACTIVE_SESSION_SOURCES: LazyLock<Vec<SessionSource>> = LazyLock::new(|| {
vec![
SessionSource::Cli,
SessionSource::VSCode,
SessionSource::Custom("atlas".to_string()),
SessionSource::Custom("chatgpt".to_string()),
]
});
pub use session_index::append_thread_name;
pub use session_index::find_thread_name_by_id;
pub use session_index::find_thread_path_by_name_str;
#[deprecated(note = "use find_thread_path_by_id_str")]
pub async fn find_conversation_path_by_id_str(
codex_home: &Path,
id_str: &str,
) -> io::Result<Option<PathBuf>> {
find_thread_path_by_id_str(codex_home, id_str).await
}
pub async fn find_thread_path_by_id_str(
_codex_home: &Path,
_id_str: &str,
) -> io::Result<Option<PathBuf>> {
Ok(None)
}
pub async fn find_archived_thread_path_by_id_str(
_codex_home: &Path,
_id_str: &str,
) -> io::Result<Option<PathBuf>> {
Ok(None)
}
pub fn rollout_date_parts(_file_name: &OsStr) -> Option<(String, String, String)> {
None
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum EventPersistenceMode {
#[default]
Limited,
Extended,
}
pub mod policy {
pub use super::EventPersistenceMode;
}
#[derive(Clone)]
pub struct RolloutRecorder {
rollout_path: PathBuf,
state_db: Option<StateDbHandle>,
_event_persistence_mode: EventPersistenceMode,
}
#[derive(Clone)]
pub enum RolloutRecorderParams {
Create {
conversation_id: ThreadId,
forked_from_id: Option<ThreadId>,
source: SessionSource,
base_instructions: BaseInstructions,
dynamic_tools: Vec<DynamicToolSpec>,
event_persistence_mode: EventPersistenceMode,
},
Resume {
path: PathBuf,
event_persistence_mode: EventPersistenceMode,
},
}
impl RolloutRecorderParams {
pub fn new(
conversation_id: ThreadId,
forked_from_id: Option<ThreadId>,
source: SessionSource,
base_instructions: BaseInstructions,
dynamic_tools: Vec<DynamicToolSpec>,
event_persistence_mode: EventPersistenceMode,
) -> Self {
Self::Create {
conversation_id,
forked_from_id,
source,
base_instructions,
dynamic_tools,
event_persistence_mode,
}
}
pub fn resume(path: PathBuf, event_persistence_mode: EventPersistenceMode) -> Self {
Self::Resume {
path,
event_persistence_mode,
}
}
}
impl RolloutRecorder {
#[allow(clippy::too_many_arguments)]
pub async fn list_threads(
_config: &Config,
_page_size: usize,
_cursor: Option<&list::Cursor>,
_sort_key: list::ThreadSortKey,
_allowed_sources: &[SessionSource],
_model_providers: Option<&[String]>,
_default_provider: &str,
_search_term: Option<&str>,
) -> io::Result<list::ThreadsPage> {
Ok(list::ThreadsPage::default())
}
#[allow(clippy::too_many_arguments)]
pub async fn list_archived_threads(
_config: &Config,
_page_size: usize,
_cursor: Option<&list::Cursor>,
_sort_key: list::ThreadSortKey,
_allowed_sources: &[SessionSource],
_model_providers: Option<&[String]>,
_default_provider: &str,
_search_term: Option<&str>,
) -> io::Result<list::ThreadsPage> {
Ok(list::ThreadsPage::default())
}
pub async fn new(
config: &Config,
params: RolloutRecorderParams,
state_db: Option<StateDbHandle>,
_state_builder: Option<metadata::ThreadMetadataBuilder>,
) -> io::Result<Self> {
let rollout_path = match params {
RolloutRecorderParams::Create {
conversation_id, ..
} => config
.codex_home
.join(SESSIONS_SUBDIR)
.join(format!("browser-{}.jsonl", conversation_id)),
RolloutRecorderParams::Resume { path, .. } => path,
};
Ok(Self {
rollout_path,
state_db,
_event_persistence_mode: EventPersistenceMode::Limited,
})
}
pub fn rollout_path(&self) -> &Path {
self.rollout_path.as_path()
}
pub fn state_db(&self) -> Option<StateDbHandle> {
self.state_db.clone()
}
pub async fn record_items(&self, _items: &[RolloutItem]) -> io::Result<()> {
Ok(())
}
pub async fn persist(&self) -> io::Result<()> {
Ok(())
}
pub async fn flush(&self) -> io::Result<()> {
Ok(())
}
pub async fn load_rollout_items(
_path: &Path,
) -> io::Result<(Vec<RolloutItem>, Option<ThreadId>, usize)> {
Err(io::Error::other(
"rollout loading is unavailable on wasm32 without a browser persistence backend",
))
}
pub async fn get_rollout_history(_path: &Path) -> io::Result<InitialHistory> {
Err(io::Error::other(
"rollout history is unavailable on wasm32 without a browser persistence backend",
))
}
pub async fn shutdown(&self) -> io::Result<()> {
Ok(())
}
}
pub mod recorder {
pub use super::RolloutRecorder;
pub use super::RolloutRecorderParams;
}
pub mod metadata {
use std::path::Path;
use codex_protocol::protocol::RolloutItem;
#[derive(Clone, Debug)]
pub struct ThreadMetadataBuilder;
pub fn builder_from_items(
_items: &[RolloutItem],
_rollout_path: &Path,
) -> Option<ThreadMetadataBuilder> {
None
}
}
pub mod list {
use std::io;
use std::path::Path;
use std::path::PathBuf;
use codex_protocol::ThreadId;
use codex_protocol::protocol::SessionMetaLine;
use codex_protocol::protocol::SessionSource;
#[derive(Debug, Default, PartialEq)]
pub struct ThreadsPage {
pub items: Vec<ThreadItem>,
pub next_cursor: Option<Cursor>,
pub num_scanned_files: usize,
pub reached_scan_cap: bool,
}
#[derive(Debug, PartialEq, Default)]
pub struct ThreadItem {
pub path: PathBuf,
pub thread_id: Option<ThreadId>,
pub first_user_message: Option<String>,
pub cwd: Option<PathBuf>,
pub git_branch: Option<String>,
pub git_sha: Option<String>,
pub git_origin_url: Option<String>,
pub source: Option<SessionSource>,
pub agent_nickname: Option<String>,
pub agent_role: Option<String>,
pub model_provider: Option<String>,
pub cli_version: Option<String>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThreadSortKey {
CreatedAt,
UpdatedAt,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThreadListLayout {
NestedByDate,
Flat,
}
pub struct ThreadListConfig<'a> {
pub allowed_sources: &'a [SessionSource],
pub model_providers: Option<&'a [String]>,
pub default_provider: &'a str,
pub layout: ThreadListLayout,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Cursor(String);
pub fn parse_cursor(cursor: &str) -> Option<Cursor> {
if cursor.is_empty() {
None
} else {
Some(Cursor(cursor.to_string()))
}
}
pub async fn get_threads(
_codex_home: &Path,
_page_size: usize,
_cursor: Option<&Cursor>,
_sort_key: ThreadSortKey,
_allowed_sources: &[SessionSource],
_model_providers: Option<&[String]>,
_default_provider: &str,
) -> io::Result<ThreadsPage> {
Ok(ThreadsPage::default())
}
pub async fn get_threads_in_root(
_root: PathBuf,
_page_size: usize,
_cursor: Option<&Cursor>,
_sort_key: ThreadSortKey,
_config: ThreadListConfig<'_>,
) -> io::Result<ThreadsPage> {
Ok(ThreadsPage::default())
}
pub async fn read_head_for_summary(_path: &Path) -> io::Result<Vec<serde_json::Value>> {
Ok(Vec::new())
}
pub async fn read_session_meta_line(_path: &Path) -> io::Result<SessionMetaLine> {
Ok(SessionMetaLine {
meta: Default::default(),
git: None,
})
}
pub async fn find_thread_path_by_id_str(
_codex_home: &Path,
_id_str: &str,
) -> io::Result<Option<PathBuf>> {
Ok(None)
}
pub async fn find_archived_thread_path_by_id_str(
_codex_home: &Path,
_id_str: &str,
) -> io::Result<Option<PathBuf>> {
Ok(None)
}
pub fn rollout_date_parts(
_file_name: &std::ffi::OsStr,
) -> Option<(String, String, String)> {
None
}
}
pub mod session_index {
use std::collections::HashMap;
use std::collections::HashSet;
use std::io;
use std::path::Path;
use std::path::PathBuf;
use codex_protocol::ThreadId;
pub async fn append_thread_name(
_codex_home: &Path,
_thread_id: ThreadId,
_name: &str,
) -> io::Result<()> {
Ok(())
}
pub async fn find_thread_name_by_id(
_codex_home: &Path,
_thread_id: &ThreadId,
) -> io::Result<Option<String>> {
Ok(None)
}
pub async fn find_thread_names_by_ids(
_codex_home: &Path,
_thread_ids: &HashSet<ThreadId>,
) -> io::Result<HashMap<ThreadId, String>> {
Ok(HashMap::new())
}
pub async fn find_thread_path_by_name_str(
_codex_home: &Path,
_name: &str,
) -> io::Result<Option<PathBuf>> {
Ok(None)
}
}
pub(crate) fn map_session_init_error(
err: &anyhow::Error,
_codex_home: &Path,
) -> crate::error::CodexErr {
crate::error::CodexErr::Fatal(err.to_string())
}
pub(crate) mod truncation {}
}
pub(crate) mod metadata {
pub(crate) use codex_rollout::metadata::builder_from_items;
}
#[cfg(not(target_arch = "wasm32"))]
pub use native::*;
pub mod policy {
pub use codex_rollout::policy::*;
}
pub mod recorder {
pub use codex_rollout::recorder::*;
}
pub mod session_index {
pub use codex_rollout::session_index::*;
}
pub(crate) use crate::session_rollout_init_error::map_session_init_error;
pub(crate) mod truncation {
pub(crate) use crate::thread_rollout_truncation::*;
}
#[cfg(target_arch = "wasm32")]
pub use wasm::*;

View File

@@ -1,21 +1,189 @@
#[cfg(not(target_arch = "wasm32"))]
use codex_rollout::state_db as rollout_state_db;
pub use codex_rollout::state_db::StateDbHandle;
pub use codex_rollout::state_db::apply_rollout_items;
pub use codex_rollout::state_db::find_rollout_path_by_id;
pub use codex_rollout::state_db::get_dynamic_tools;
pub use codex_rollout::state_db::list_thread_ids_db;
pub use codex_rollout::state_db::list_threads_db;
pub use codex_rollout::state_db::mark_thread_memory_mode_polluted;
pub use codex_rollout::state_db::normalize_cwd_for_state_db;
pub use codex_rollout::state_db::open_if_present;
pub use codex_rollout::state_db::persist_dynamic_tools;
pub use codex_rollout::state_db::read_repair_rollout_path;
pub use codex_rollout::state_db::reconcile_rollout;
pub use codex_rollout::state_db::touch_thread_updated_at;
pub use codex_state::LogEntry;
use crate::config::Config;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::StateDbHandle;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::apply_rollout_items;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::find_rollout_path_by_id;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::get_dynamic_tools;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::init;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::list_thread_ids_db;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::list_threads_db;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::mark_thread_memory_mode_polluted;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::normalize_cwd_for_state_db;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::open_if_present;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::persist_dynamic_tools;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::read_repair_rollout_path;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::reconcile_rollout;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_rollout::state_db::touch_thread_updated_at;
#[cfg(not(target_arch = "wasm32"))]
pub use codex_state::LogEntry;
#[cfg(not(target_arch = "wasm32"))]
pub async fn get_state_db(config: &Config) -> Option<StateDbHandle> {
rollout_state_db::get_state_db(config).await
}
#[cfg(target_arch = "wasm32")]
pub mod wasm {
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use chrono::DateTime;
use chrono::Utc;
use codex_protocol::ThreadId;
use codex_protocol::dynamic_tools::DynamicToolSpec;
use codex_protocol::protocol::RolloutItem;
use codex_protocol::protocol::SessionSource;
use crate::config::Config;
use crate::rollout::list::Cursor;
use crate::rollout::list::ThreadSortKey;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StateRuntimeStub;
pub type StateDbHandle = Arc<StateRuntimeStub>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogEntry;
pub async fn init(_config: &Config) -> Option<StateDbHandle> {
None
}
pub async fn get_state_db(_config: &Config) -> Option<StateDbHandle> {
None
}
pub async fn open_if_present(
_codex_home: &Path,
_default_provider: &str,
) -> Option<StateDbHandle> {
None
}
pub async fn find_rollout_path_by_id(
_context: Option<&StateRuntimeStub>,
_thread_id: ThreadId,
_archived_only: Option<bool>,
_stage: &str,
) -> Option<PathBuf> {
None
}
pub async fn get_dynamic_tools(
_context: Option<&StateRuntimeStub>,
_thread_id: ThreadId,
_stage: &str,
) -> Option<Vec<DynamicToolSpec>> {
None
}
pub async fn list_thread_ids_db(
_context: Option<&StateRuntimeStub>,
_codex_home: &Path,
_page_size: usize,
_cursor: Option<&Cursor>,
_sort_key: ThreadSortKey,
_allowed_sources: &[SessionSource],
_model_providers: Option<&[String]>,
_archived_only: bool,
_stage: &str,
) -> Option<Vec<ThreadId>> {
None
}
pub async fn list_threads_db(
_context: Option<&StateRuntimeStub>,
_codex_home: &Path,
_page_size: usize,
_cursor: Option<&Cursor>,
_sort_key: ThreadSortKey,
_allowed_sources: &[SessionSource],
_model_providers: Option<&[String]>,
_archived: bool,
_search_term: Option<&str>,
) -> Option<crate::rollout::list::ThreadsPage> {
None
}
pub fn normalize_cwd_for_state_db(cwd: &Path) -> PathBuf {
cwd.to_path_buf()
}
pub async fn persist_dynamic_tools(
_context: Option<&StateRuntimeStub>,
_thread_id: ThreadId,
_tools: Option<&[DynamicToolSpec]>,
_stage: &str,
) {
}
pub async fn mark_thread_memory_mode_polluted(
_context: Option<&StateRuntimeStub>,
_thread_id: ThreadId,
_stage: &str,
) {
}
pub async fn reconcile_rollout(
_context: Option<&StateRuntimeStub>,
_rollout_path: &Path,
_default_provider: &str,
_builder: Option<&()>,
_items: &[RolloutItem],
_archived_only: Option<bool>,
_new_thread_memory_mode: Option<&str>,
) {
}
pub async fn read_repair_rollout_path(
_context: Option<&StateRuntimeStub>,
_thread_id: Option<ThreadId>,
_archived_only: Option<bool>,
_rollout_path: &Path,
) {
}
#[allow(clippy::too_many_arguments)]
pub async fn apply_rollout_items(
_context: Option<&StateRuntimeStub>,
_rollout_path: &Path,
_default_provider: &str,
_builder: Option<&()>,
_items: &[RolloutItem],
_stage: &str,
_new_thread_memory_mode: Option<&str>,
_updated_at_override: Option<DateTime<Utc>>,
) {
}
pub async fn touch_thread_updated_at(
_context: Option<&StateRuntimeStub>,
_thread_id: Option<ThreadId>,
_updated_at: DateTime<Utc>,
_stage: &str,
) -> bool {
false
}
}
#[cfg(target_arch = "wasm32")]
pub use wasm::*;