mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-27 08:00:17 +00:00
fix: add missing JobContext fields and resolve fmt/clippy warnings
Add total_tokens_used and max_tokens fields to JobContext in libsql_backend.rs, apply cargo fmt, and fix clippy warnings. Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
@@ -19,9 +19,9 @@ use crate::channels::{ChannelManager, IncomingMessage, OutgoingResponse, StatusU
|
||||
use crate::config::{AgentConfig, HeartbeatConfig, RoutineConfig};
|
||||
use crate::context::ContextManager;
|
||||
use crate::context::JobContext;
|
||||
use crate::db::Database;
|
||||
use crate::error::Error;
|
||||
use crate::extensions::ExtensionManager;
|
||||
use crate::db::Database;
|
||||
use crate::llm::{ChatMessage, LlmProvider, Reasoning, ReasoningContext, RespondResult};
|
||||
use crate::safety::SafetyLayer;
|
||||
use crate::tools::ToolRegistry;
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::agent::task::{Task, TaskContext, TaskOutput};
|
||||
use crate::agent::worker::{Worker, WorkerDeps};
|
||||
use crate::config::AgentConfig;
|
||||
use crate::context::{ContextManager, JobContext, JobState};
|
||||
use crate::error::{Error, JobError};
|
||||
use crate::db::Database;
|
||||
use crate::error::{Error, JobError};
|
||||
use crate::llm::LlmProvider;
|
||||
use crate::safety::SafetyLayer;
|
||||
use crate::tools::ToolRegistry;
|
||||
|
||||
@@ -8,8 +8,8 @@ use chrono::{DateTime, Utc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::context::{ContextManager, JobState};
|
||||
use crate::error::RepairError;
|
||||
use crate::db::Database;
|
||||
use crate::error::RepairError;
|
||||
use crate::tools::{BuildRequirement, Language, SoftwareBuilder, SoftwareType, ToolRegistry};
|
||||
|
||||
/// A job that has been detected as stuck.
|
||||
|
||||
+1
-1
@@ -10,8 +10,8 @@ use uuid::Uuid;
|
||||
use crate::agent::scheduler::WorkerMessage;
|
||||
use crate::agent::task::TaskOutput;
|
||||
use crate::context::{ContextManager, JobState};
|
||||
use crate::error::Error;
|
||||
use crate::db::Database;
|
||||
use crate::error::Error;
|
||||
use crate::llm::{
|
||||
ActionPlan, ChatMessage, LlmProvider, Reasoning, ReasoningContext, RespondResult, ToolSelection,
|
||||
};
|
||||
|
||||
@@ -32,9 +32,9 @@ use tokio_stream::wrappers::ReceiverStream;
|
||||
use crate::agent::SessionManager;
|
||||
use crate::channels::{Channel, IncomingMessage, MessageStream, OutgoingResponse, StatusUpdate};
|
||||
use crate::config::GatewayConfig;
|
||||
use crate::db::Database;
|
||||
use crate::error::ChannelError;
|
||||
use crate::extensions::ExtensionManager;
|
||||
use crate::db::Database;
|
||||
use crate::orchestrator::job_manager::ContainerJobManager;
|
||||
use crate::tools::ToolRegistry;
|
||||
use crate::workspace::Workspace;
|
||||
|
||||
@@ -30,8 +30,8 @@ use crate::channels::web::auth::{AuthState, auth_middleware};
|
||||
use crate::channels::web::log_layer::LogBroadcaster;
|
||||
use crate::channels::web::sse::SseManager;
|
||||
use crate::channels::web::types::*;
|
||||
use crate::extensions::ExtensionManager;
|
||||
use crate::db::Database;
|
||||
use crate::extensions::ExtensionManager;
|
||||
use crate::orchestrator::job_manager::ContainerJobManager;
|
||||
use crate::tools::ToolRegistry;
|
||||
use crate::workspace::Workspace;
|
||||
|
||||
+3
-1
@@ -74,7 +74,9 @@ pub async fn run_config_command(cmd: ConfigCommand) -> anyhow::Result<()> {
|
||||
|
||||
/// Bootstrap a DB connection for config commands (backend-agnostic).
|
||||
async fn connect_db() -> anyhow::Result<Arc<dyn crate::db::Database>> {
|
||||
let config = crate::config::Config::from_env().await.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
let config = crate::config::Config::from_env()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
crate::db::connect_from_config(&config.database)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))
|
||||
|
||||
+23
-12
@@ -9,9 +9,9 @@ use clap::Subcommand;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::db::Database;
|
||||
use crate::secrets::{SecretsCrypto, SecretsStore};
|
||||
#[cfg(feature = "postgres")]
|
||||
use crate::secrets::PostgresSecretsStore;
|
||||
use crate::secrets::{SecretsCrypto, SecretsStore};
|
||||
use crate::tools::mcp::{
|
||||
McpClient, McpServerConfig, McpSessionManager, OAuthConfig,
|
||||
auth::{authorize_mcp_server, is_authenticated},
|
||||
@@ -510,36 +510,45 @@ async fn get_secrets_store() -> anyhow::Result<Arc<dyn SecretsStore + Send + Syn
|
||||
{
|
||||
let store = crate::history::Store::new(&config.database).await?;
|
||||
store.run_migrations().await?;
|
||||
return Ok(Arc::new(PostgresSecretsStore::new(
|
||||
Ok(Arc::new(PostgresSecretsStore::new(
|
||||
store.pool(),
|
||||
Arc::new(crypto),
|
||||
)));
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "libsql", not(feature = "postgres")))]
|
||||
{
|
||||
use crate::db::libsql_backend::LibSqlBackend;
|
||||
use crate::db::Database as _;
|
||||
use crate::db::libsql_backend::LibSqlBackend;
|
||||
use secrecy::ExposeSecret as _;
|
||||
|
||||
let default_path = crate::config::default_libsql_path();
|
||||
let db_path = config.database.libsql_path.as_deref()
|
||||
let db_path = config
|
||||
.database
|
||||
.libsql_path
|
||||
.as_deref()
|
||||
.unwrap_or(&default_path);
|
||||
|
||||
let backend = if let Some(ref url) = config.database.libsql_url {
|
||||
let token = config.database.libsql_auth_token.as_ref()
|
||||
let token = config
|
||||
.database
|
||||
.libsql_auth_token
|
||||
.as_ref()
|
||||
.expect("LIBSQL_AUTH_TOKEN required when LIBSQL_URL is set");
|
||||
LibSqlBackend::new_remote_replica(db_path, url, token.expose_secret()).await
|
||||
LibSqlBackend::new_remote_replica(db_path, url, token.expose_secret())
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?
|
||||
} else {
|
||||
LibSqlBackend::new_local(db_path).await
|
||||
LibSqlBackend::new_local(db_path)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?
|
||||
};
|
||||
backend.run_migrations().await
|
||||
backend
|
||||
.run_migrations()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
|
||||
let conn = backend.connect()
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
let conn = backend.connect().map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
|
||||
return Ok(Arc::new(crate::secrets::LibSqlSecretsStore::new(
|
||||
conn,
|
||||
@@ -550,7 +559,9 @@ async fn get_secrets_store() -> anyhow::Result<Arc<dyn SecretsStore + Send + Syn
|
||||
#[cfg(not(any(feature = "postgres", feature = "libsql")))]
|
||||
{
|
||||
let _ = crypto;
|
||||
anyhow::bail!("No database backend available for secrets. Enable 'postgres' or 'libsql' feature.");
|
||||
anyhow::bail!(
|
||||
"No database backend available for secrets. Enable 'postgres' or 'libsql' feature."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-11
@@ -13,9 +13,9 @@ use tokio::fs;
|
||||
use crate::config::Config;
|
||||
#[allow(unused_imports)]
|
||||
use crate::db::Database;
|
||||
use crate::secrets::{CreateSecretParams, SecretsCrypto, SecretsStore};
|
||||
#[cfg(feature = "postgres")]
|
||||
use crate::secrets::PostgresSecretsStore;
|
||||
use crate::secrets::{CreateSecretParams, SecretsCrypto, SecretsStore};
|
||||
use crate::tools::wasm::{CapabilitiesFile, compute_binary_hash};
|
||||
|
||||
/// Default tools directory.
|
||||
@@ -736,35 +736,49 @@ async fn auth_tool(name: String, dir: Option<PathBuf>, user_id: String) -> anyho
|
||||
}
|
||||
#[cfg(all(feature = "libsql", not(feature = "postgres")))]
|
||||
{
|
||||
use crate::db::libsql_backend::LibSqlBackend;
|
||||
use crate::db::Database as _;
|
||||
use crate::db::libsql_backend::LibSqlBackend;
|
||||
use secrecy::ExposeSecret as _;
|
||||
|
||||
let default_path = crate::config::default_libsql_path();
|
||||
let db_path = config.database.libsql_path.as_deref()
|
||||
let db_path = config
|
||||
.database
|
||||
.libsql_path
|
||||
.as_deref()
|
||||
.unwrap_or(&default_path);
|
||||
|
||||
let backend = if let Some(ref url) = config.database.libsql_url {
|
||||
let token = config.database.libsql_auth_token.as_ref()
|
||||
let token = config
|
||||
.database
|
||||
.libsql_auth_token
|
||||
.as_ref()
|
||||
.expect("LIBSQL_AUTH_TOKEN required when LIBSQL_URL is set");
|
||||
LibSqlBackend::new_remote_replica(db_path, url, token.expose_secret()).await
|
||||
LibSqlBackend::new_remote_replica(db_path, url, token.expose_secret())
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?
|
||||
} else {
|
||||
LibSqlBackend::new_local(db_path).await
|
||||
LibSqlBackend::new_local(db_path)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?
|
||||
};
|
||||
backend.run_migrations().await
|
||||
backend
|
||||
.run_migrations()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
|
||||
let conn = backend.connect()
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
let conn = backend.connect().map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
|
||||
Arc::new(crate::secrets::LibSqlSecretsStore::new(conn, Arc::new(crypto)))
|
||||
Arc::new(crate::secrets::LibSqlSecretsStore::new(
|
||||
conn,
|
||||
Arc::new(crypto),
|
||||
))
|
||||
}
|
||||
#[cfg(not(any(feature = "postgres", feature = "libsql")))]
|
||||
{
|
||||
let _ = crypto;
|
||||
anyhow::bail!("No database backend available for secrets. Enable 'postgres' or 'libsql' feature.");
|
||||
anyhow::bail!(
|
||||
"No database backend available for secrets. Enable 'postgres' or 'libsql' feature."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+471
-353
File diff suppressed because it is too large
Load Diff
+11
-44
@@ -26,8 +26,8 @@ use chrono::{DateTime, Utc};
|
||||
use rust_decimal::Decimal;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::agent::routine::{Routine, RoutineRun, RunStatus};
|
||||
use crate::agent::BrokenTool;
|
||||
use crate::agent::routine::{Routine, RoutineRun, RunStatus};
|
||||
use crate::context::{ActionRecord, JobContext, JobState};
|
||||
use crate::error::DatabaseError;
|
||||
use crate::error::WorkspaceError;
|
||||
@@ -214,17 +214,10 @@ pub trait Database: Send + Sync {
|
||||
// ==================== Actions ====================
|
||||
|
||||
/// Save a job action.
|
||||
async fn save_action(
|
||||
&self,
|
||||
job_id: Uuid,
|
||||
action: &ActionRecord,
|
||||
) -> Result<(), DatabaseError>;
|
||||
async fn save_action(&self, job_id: Uuid, action: &ActionRecord) -> Result<(), DatabaseError>;
|
||||
|
||||
/// Get actions for a job.
|
||||
async fn get_job_actions(
|
||||
&self,
|
||||
job_id: Uuid,
|
||||
) -> Result<Vec<ActionRecord>, DatabaseError>;
|
||||
async fn get_job_actions(&self, job_id: Uuid) -> Result<Vec<ActionRecord>, DatabaseError>;
|
||||
|
||||
// ==================== LLM Calls ====================
|
||||
|
||||
@@ -259,10 +252,7 @@ pub trait Database: Send + Sync {
|
||||
async fn save_sandbox_job(&self, job: &SandboxJobRecord) -> Result<(), DatabaseError>;
|
||||
|
||||
/// Get a sandbox job by ID.
|
||||
async fn get_sandbox_job(
|
||||
&self,
|
||||
id: Uuid,
|
||||
) -> Result<Option<SandboxJobRecord>, DatabaseError>;
|
||||
async fn get_sandbox_job(&self, id: Uuid) -> Result<Option<SandboxJobRecord>, DatabaseError>;
|
||||
|
||||
/// List all sandbox jobs, most recent first.
|
||||
async fn list_sandbox_jobs(&self) -> Result<Vec<SandboxJobRecord>, DatabaseError>;
|
||||
@@ -304,17 +294,10 @@ pub trait Database: Send + Sync {
|
||||
) -> Result<bool, DatabaseError>;
|
||||
|
||||
/// Update sandbox job mode.
|
||||
async fn update_sandbox_job_mode(
|
||||
&self,
|
||||
id: Uuid,
|
||||
mode: &str,
|
||||
) -> Result<(), DatabaseError>;
|
||||
async fn update_sandbox_job_mode(&self, id: Uuid, mode: &str) -> Result<(), DatabaseError>;
|
||||
|
||||
/// Get sandbox job mode.
|
||||
async fn get_sandbox_job_mode(
|
||||
&self,
|
||||
id: Uuid,
|
||||
) -> Result<Option<String>, DatabaseError>;
|
||||
async fn get_sandbox_job_mode(&self, id: Uuid) -> Result<Option<String>, DatabaseError>;
|
||||
|
||||
// ==================== Job Events ====================
|
||||
|
||||
@@ -327,10 +310,7 @@ pub trait Database: Send + Sync {
|
||||
) -> Result<(), DatabaseError>;
|
||||
|
||||
/// Load all job events.
|
||||
async fn list_job_events(
|
||||
&self,
|
||||
job_id: Uuid,
|
||||
) -> Result<Vec<JobEventRecord>, DatabaseError>;
|
||||
async fn list_job_events(&self, job_id: Uuid) -> Result<Vec<JobEventRecord>, DatabaseError>;
|
||||
|
||||
// ==================== Routines ====================
|
||||
|
||||
@@ -395,10 +375,7 @@ pub trait Database: Send + Sync {
|
||||
) -> Result<Vec<RoutineRun>, DatabaseError>;
|
||||
|
||||
/// Count currently running runs for a routine.
|
||||
async fn count_running_routine_runs(
|
||||
&self,
|
||||
routine_id: Uuid,
|
||||
) -> Result<i64, DatabaseError>;
|
||||
async fn count_running_routine_runs(&self, routine_id: Uuid) -> Result<i64, DatabaseError>;
|
||||
|
||||
// ==================== Tool Failures ====================
|
||||
|
||||
@@ -410,10 +387,7 @@ pub trait Database: Send + Sync {
|
||||
) -> Result<(), DatabaseError>;
|
||||
|
||||
/// Get broken tools exceeding threshold.
|
||||
async fn get_broken_tools(
|
||||
&self,
|
||||
threshold: i32,
|
||||
) -> Result<Vec<BrokenTool>, DatabaseError>;
|
||||
async fn get_broken_tools(&self, threshold: i32) -> Result<Vec<BrokenTool>, DatabaseError>;
|
||||
|
||||
/// Mark a tool as repaired.
|
||||
async fn mark_tool_repaired(&self, tool_name: &str) -> Result<(), DatabaseError>;
|
||||
@@ -446,17 +420,10 @@ pub trait Database: Send + Sync {
|
||||
) -> Result<(), DatabaseError>;
|
||||
|
||||
/// Delete a single setting.
|
||||
async fn delete_setting(
|
||||
&self,
|
||||
user_id: &str,
|
||||
key: &str,
|
||||
) -> Result<bool, DatabaseError>;
|
||||
async fn delete_setting(&self, user_id: &str, key: &str) -> Result<bool, DatabaseError>;
|
||||
|
||||
/// List all settings for a user.
|
||||
async fn list_settings(
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> Result<Vec<SettingRow>, DatabaseError>;
|
||||
async fn list_settings(&self, user_id: &str) -> Result<Vec<SettingRow>, DatabaseError>;
|
||||
|
||||
/// Get all settings as a flat map.
|
||||
async fn get_all_settings(
|
||||
|
||||
+27
-52
@@ -11,8 +11,8 @@ use deadpool_postgres::Pool;
|
||||
use rust_decimal::Decimal;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::agent::routine::{Routine, RoutineRun, RunStatus};
|
||||
use crate::agent::BrokenTool;
|
||||
use crate::agent::routine::{Routine, RoutineRun, RunStatus};
|
||||
use crate::config::DatabaseConfig;
|
||||
use crate::context::{ActionRecord, JobContext, JobState};
|
||||
use crate::db::Database;
|
||||
@@ -65,7 +65,9 @@ impl Database for PgBackend {
|
||||
user_id: &str,
|
||||
thread_id: Option<&str>,
|
||||
) -> Result<Uuid, DatabaseError> {
|
||||
self.store.create_conversation(channel, user_id, thread_id).await
|
||||
self.store
|
||||
.create_conversation(channel, user_id, thread_id)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn touch_conversation(&self, id: Uuid) -> Result<(), DatabaseError> {
|
||||
@@ -160,9 +162,7 @@ impl Database for PgBackend {
|
||||
&self,
|
||||
conversation_id: Uuid,
|
||||
) -> Result<Vec<ConversationMessage>, DatabaseError> {
|
||||
self.store
|
||||
.list_conversation_messages(conversation_id)
|
||||
.await
|
||||
self.store.list_conversation_messages(conversation_id).await
|
||||
}
|
||||
|
||||
async fn conversation_belongs_to_user(
|
||||
@@ -191,7 +191,9 @@ impl Database for PgBackend {
|
||||
status: JobState,
|
||||
failure_reason: Option<&str>,
|
||||
) -> Result<(), DatabaseError> {
|
||||
self.store.update_job_status(id, status, failure_reason).await
|
||||
self.store
|
||||
.update_job_status(id, status, failure_reason)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn mark_job_stuck(&self, id: Uuid) -> Result<(), DatabaseError> {
|
||||
@@ -204,18 +206,11 @@ impl Database for PgBackend {
|
||||
|
||||
// ==================== Actions ====================
|
||||
|
||||
async fn save_action(
|
||||
&self,
|
||||
job_id: Uuid,
|
||||
action: &ActionRecord,
|
||||
) -> Result<(), DatabaseError> {
|
||||
async fn save_action(&self, job_id: Uuid, action: &ActionRecord) -> Result<(), DatabaseError> {
|
||||
self.store.save_action(job_id, action).await
|
||||
}
|
||||
|
||||
async fn get_job_actions(
|
||||
&self,
|
||||
job_id: Uuid,
|
||||
) -> Result<Vec<ActionRecord>, DatabaseError> {
|
||||
async fn get_job_actions(&self, job_id: Uuid) -> Result<Vec<ActionRecord>, DatabaseError> {
|
||||
self.store.get_job_actions(job_id).await
|
||||
}
|
||||
|
||||
@@ -266,10 +261,7 @@ impl Database for PgBackend {
|
||||
self.store.save_sandbox_job(job).await
|
||||
}
|
||||
|
||||
async fn get_sandbox_job(
|
||||
&self,
|
||||
id: Uuid,
|
||||
) -> Result<Option<SandboxJobRecord>, DatabaseError> {
|
||||
async fn get_sandbox_job(&self, id: Uuid) -> Result<Option<SandboxJobRecord>, DatabaseError> {
|
||||
self.store.get_sandbox_job(id).await
|
||||
}
|
||||
|
||||
@@ -318,21 +310,16 @@ impl Database for PgBackend {
|
||||
job_id: Uuid,
|
||||
user_id: &str,
|
||||
) -> Result<bool, DatabaseError> {
|
||||
self.store.sandbox_job_belongs_to_user(job_id, user_id).await
|
||||
self.store
|
||||
.sandbox_job_belongs_to_user(job_id, user_id)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update_sandbox_job_mode(
|
||||
&self,
|
||||
id: Uuid,
|
||||
mode: &str,
|
||||
) -> Result<(), DatabaseError> {
|
||||
async fn update_sandbox_job_mode(&self, id: Uuid, mode: &str) -> Result<(), DatabaseError> {
|
||||
self.store.update_sandbox_job_mode(id, mode).await
|
||||
}
|
||||
|
||||
async fn get_sandbox_job_mode(
|
||||
&self,
|
||||
id: Uuid,
|
||||
) -> Result<Option<String>, DatabaseError> {
|
||||
async fn get_sandbox_job_mode(&self, id: Uuid) -> Result<Option<String>, DatabaseError> {
|
||||
self.store.get_sandbox_job_mode(id).await
|
||||
}
|
||||
|
||||
@@ -347,10 +334,7 @@ impl Database for PgBackend {
|
||||
self.store.save_job_event(job_id, event_type, data).await
|
||||
}
|
||||
|
||||
async fn list_job_events(
|
||||
&self,
|
||||
job_id: Uuid,
|
||||
) -> Result<Vec<JobEventRecord>, DatabaseError> {
|
||||
async fn list_job_events(&self, job_id: Uuid) -> Result<Vec<JobEventRecord>, DatabaseError> {
|
||||
self.store.list_job_events(job_id).await
|
||||
}
|
||||
|
||||
@@ -439,10 +423,7 @@ impl Database for PgBackend {
|
||||
self.store.list_routine_runs(routine_id, limit).await
|
||||
}
|
||||
|
||||
async fn count_running_routine_runs(
|
||||
&self,
|
||||
routine_id: Uuid,
|
||||
) -> Result<i64, DatabaseError> {
|
||||
async fn count_running_routine_runs(&self, routine_id: Uuid) -> Result<i64, DatabaseError> {
|
||||
self.store.count_running_routine_runs(routine_id).await
|
||||
}
|
||||
|
||||
@@ -453,13 +434,12 @@ impl Database for PgBackend {
|
||||
tool_name: &str,
|
||||
error_message: &str,
|
||||
) -> Result<(), DatabaseError> {
|
||||
self.store.record_tool_failure(tool_name, error_message).await
|
||||
self.store
|
||||
.record_tool_failure(tool_name, error_message)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_broken_tools(
|
||||
&self,
|
||||
threshold: i32,
|
||||
) -> Result<Vec<BrokenTool>, DatabaseError> {
|
||||
async fn get_broken_tools(&self, threshold: i32) -> Result<Vec<BrokenTool>, DatabaseError> {
|
||||
self.store.get_broken_tools(threshold).await
|
||||
}
|
||||
|
||||
@@ -498,18 +478,11 @@ impl Database for PgBackend {
|
||||
self.store.set_setting(user_id, key, value).await
|
||||
}
|
||||
|
||||
async fn delete_setting(
|
||||
&self,
|
||||
user_id: &str,
|
||||
key: &str,
|
||||
) -> Result<bool, DatabaseError> {
|
||||
async fn delete_setting(&self, user_id: &str, key: &str) -> Result<bool, DatabaseError> {
|
||||
self.store.delete_setting(user_id, key).await
|
||||
}
|
||||
|
||||
async fn list_settings(
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> Result<Vec<SettingRow>, DatabaseError> {
|
||||
async fn list_settings(&self, user_id: &str) -> Result<Vec<SettingRow>, DatabaseError> {
|
||||
self.store.list_settings(user_id).await
|
||||
}
|
||||
|
||||
@@ -540,7 +513,9 @@ impl Database for PgBackend {
|
||||
agent_id: Option<Uuid>,
|
||||
path: &str,
|
||||
) -> Result<MemoryDocument, WorkspaceError> {
|
||||
self.repo.get_document_by_path(user_id, agent_id, path).await
|
||||
self.repo
|
||||
.get_document_by_path(user_id, agent_id, path)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_document_by_id(&self, id: Uuid) -> Result<MemoryDocument, WorkspaceError> {
|
||||
|
||||
@@ -375,7 +375,8 @@ impl ExtensionManager {
|
||||
) -> Result<(), crate::tools::mcp::config::ConfigError> {
|
||||
config.validate()?;
|
||||
if let Some(ref store) = self.store {
|
||||
crate::tools::mcp::config::add_mcp_server_db(store.as_ref(), &self.user_id, config).await
|
||||
crate::tools::mcp::config::add_mcp_server_db(store.as_ref(), &self.user_id, config)
|
||||
.await
|
||||
} else {
|
||||
crate::tools::mcp::config::add_mcp_server(config).await
|
||||
}
|
||||
@@ -386,7 +387,8 @@ impl ExtensionManager {
|
||||
name: &str,
|
||||
) -> Result<(), crate::tools::mcp::config::ConfigError> {
|
||||
if let Some(ref store) = self.store {
|
||||
crate::tools::mcp::config::remove_mcp_server_db(store.as_ref(), &self.user_id, name).await
|
||||
crate::tools::mcp::config::remove_mcp_server_db(store.as_ref(), &self.user_id, name)
|
||||
.await
|
||||
} else {
|
||||
crate::tools::mcp::config::remove_mcp_server(name).await
|
||||
}
|
||||
|
||||
+2
-2
@@ -11,9 +11,9 @@ mod store;
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
pub use analytics::{JobStats, ToolStats};
|
||||
#[cfg(feature = "postgres")]
|
||||
pub use store::Store;
|
||||
pub use store::{
|
||||
ConversationMessage, ConversationSummary, JobEventRecord, LlmCallRecord, SandboxJobRecord,
|
||||
SandboxJobSummary, SettingRow,
|
||||
};
|
||||
#[cfg(feature = "postgres")]
|
||||
pub use store::Store;
|
||||
|
||||
+1
-1
@@ -43,8 +43,8 @@ pub mod bootstrap;
|
||||
pub mod channels;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod db;
|
||||
pub mod context;
|
||||
pub mod db;
|
||||
pub mod error;
|
||||
pub mod estimation;
|
||||
pub mod evaluation;
|
||||
|
||||
+29
-18
@@ -7,7 +7,6 @@ use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitEx
|
||||
|
||||
use ironclaw::{
|
||||
agent::{Agent, AgentDeps, SessionManager},
|
||||
pairing::PairingStore,
|
||||
channels::{
|
||||
ChannelManager, GatewayChannel, HttpChannel, ReplChannel, WebhookServer,
|
||||
WebhookServerConfig,
|
||||
@@ -18,8 +17,7 @@ use ironclaw::{
|
||||
web::log_layer::{LogBroadcaster, WebLogLayer},
|
||||
},
|
||||
cli::{
|
||||
Cli, Command, run_mcp_command, run_pairing_command, run_status_command,
|
||||
run_tool_command,
|
||||
Cli, Command, run_mcp_command, run_pairing_command, run_status_command, run_tool_command,
|
||||
},
|
||||
config::Config,
|
||||
context::ContextManager,
|
||||
@@ -29,6 +27,7 @@ use ironclaw::{
|
||||
ContainerJobConfig, ContainerJobManager, OrchestratorApi, TokenStore,
|
||||
api::OrchestratorState,
|
||||
},
|
||||
pairing::PairingStore,
|
||||
safety::SafetyLayer,
|
||||
secrets::SecretsStore,
|
||||
tools::{
|
||||
@@ -39,11 +38,9 @@ use ironclaw::{
|
||||
workspace::{EmbeddingProvider, NearAiEmbeddings, OpenAiEmbeddings, Workspace},
|
||||
};
|
||||
|
||||
use ironclaw::secrets::SecretsCrypto;
|
||||
#[cfg(feature = "postgres")]
|
||||
use ironclaw::secrets::PostgresSecretsStore;
|
||||
#[cfg(feature = "libsql")]
|
||||
use ironclaw::secrets::LibSqlSecretsStore;
|
||||
use ironclaw::secrets::SecretsCrypto;
|
||||
#[cfg(any(feature = "postgres", feature = "libsql"))]
|
||||
use ironclaw::setup::{SetupConfig, SetupWizard};
|
||||
|
||||
@@ -92,7 +89,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
// Memory commands need database (and optionally embeddings)
|
||||
let _ = dotenvy::dotenv();
|
||||
let config = Config::from_env().await.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
let config = Config::from_env()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
|
||||
// Set up embeddings if available
|
||||
let session = ironclaw::llm::create_session_manager(ironclaw::llm::SessionConfig {
|
||||
@@ -138,7 +137,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
|
||||
return ironclaw::cli::run_memory_command_with_db(mem_cmd.clone(), db, embeddings).await;
|
||||
return ironclaw::cli::run_memory_command_with_db(mem_cmd.clone(), db, embeddings)
|
||||
.await;
|
||||
}
|
||||
Some(Command::Pairing(pairing_cmd)) => {
|
||||
tracing_subscriber::fmt()
|
||||
@@ -358,16 +358,22 @@ async fn main() -> anyhow::Result<()> {
|
||||
match config.database.backend {
|
||||
#[cfg(feature = "libsql")]
|
||||
ironclaw::config::DatabaseBackend::LibSql => {
|
||||
use ironclaw::db::libsql_backend::LibSqlBackend;
|
||||
use ironclaw::db::Database as _;
|
||||
use ironclaw::db::libsql_backend::LibSqlBackend;
|
||||
use secrecy::ExposeSecret as _;
|
||||
|
||||
let default_path = ironclaw::config::default_libsql_path();
|
||||
let db_path = config.database.libsql_path.as_deref()
|
||||
let db_path = config
|
||||
.database
|
||||
.libsql_path
|
||||
.as_deref()
|
||||
.unwrap_or(&default_path);
|
||||
|
||||
let backend = if let Some(ref url) = config.database.libsql_url {
|
||||
let token = config.database.libsql_auth_token.as_ref()
|
||||
let token = config
|
||||
.database
|
||||
.libsql_auth_token
|
||||
.as_ref()
|
||||
.expect("LIBSQL_AUTH_TOKEN required when LIBSQL_URL is set");
|
||||
LibSqlBackend::new_remote_replica(db_path, url, token.expose_secret()).await?
|
||||
} else {
|
||||
@@ -384,9 +390,12 @@ async fn main() -> anyhow::Result<()> {
|
||||
#[cfg(feature = "postgres")]
|
||||
_ => {
|
||||
use ironclaw::db::Database as _;
|
||||
let pg = ironclaw::db::postgres::PgBackend::new(&config.database).await
|
||||
let pg = ironclaw::db::postgres::PgBackend::new(&config.database)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
pg.run_migrations()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
pg.run_migrations().await.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
tracing::info!("PostgreSQL database connected and migrations applied");
|
||||
|
||||
pg_pool = Some(pg.pool());
|
||||
@@ -394,7 +403,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
#[cfg(not(feature = "postgres"))]
|
||||
_ => {
|
||||
anyhow::bail!("No database backend available. Enable 'postgres' or 'libsql' feature.");
|
||||
anyhow::bail!(
|
||||
"No database backend available. Enable 'postgres' or 'libsql' feature."
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -526,11 +537,11 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
#[cfg(all(feature = "libsql", not(feature = "postgres")))]
|
||||
{
|
||||
if let (Some(conn), Some(master_key)) = (libsql_conn.take(), config.secrets.master_key()) {
|
||||
if let (Some(conn), Some(master_key)) =
|
||||
(libsql_conn.take(), config.secrets.master_key())
|
||||
{
|
||||
match SecretsCrypto::new(master_key.clone()) {
|
||||
Ok(crypto) => Some(Arc::new(
|
||||
LibSqlSecretsStore::new(conn, Arc::new(crypto)),
|
||||
)
|
||||
Ok(crypto) => Some(Arc::new(LibSqlSecretsStore::new(conn, Arc::new(crypto)))
|
||||
as Arc<dyn SecretsStore + Send + Sync>),
|
||||
Err(e) => {
|
||||
tracing::warn!("Failed to initialize secrets crypto: {}", e);
|
||||
|
||||
@@ -340,7 +340,10 @@ impl SecretsStore for LibSqlSecretsStore {
|
||||
.map(|dt| dt.to_rfc3339_opts(chrono::SecondsFormat::Millis, true));
|
||||
|
||||
// Start transaction for atomic upsert + read-back
|
||||
let tx = self.conn.transaction().await
|
||||
let tx = self
|
||||
.conn
|
||||
.transaction()
|
||||
.await
|
||||
.map_err(|e| SecretError::Database(e.to_string()))?;
|
||||
|
||||
tx.execute(
|
||||
@@ -390,7 +393,8 @@ impl SecretsStore for LibSqlSecretsStore {
|
||||
|
||||
let secret = libsql_row_to_secret(&row)?;
|
||||
|
||||
tx.commit().await
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|e| SecretError::Database(e.to_string()))?;
|
||||
|
||||
Ok(secret)
|
||||
|
||||
@@ -12,9 +12,9 @@ use reqwest::Client;
|
||||
use secrecy::{ExposeSecret, SecretString};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::secrets::{CreateSecretParams, SecretsStore};
|
||||
#[cfg(feature = "postgres")]
|
||||
use crate::secrets::SecretsCrypto;
|
||||
use crate::secrets::{CreateSecretParams, SecretsStore};
|
||||
use crate::settings::Settings;
|
||||
use crate::setup::prompts::{
|
||||
confirm, input, optional_input, print_error, print_info, print_success, secret_input,
|
||||
|
||||
+19
-14
@@ -270,12 +270,17 @@ impl SetupWizard {
|
||||
if let Some(ref path) = existing_path {
|
||||
print_info(&format!("Existing database path: {}", path));
|
||||
if confirm("Use this database?", true).map_err(SetupError::Io)? {
|
||||
let turso_url = std::env::var("LIBSQL_URL").ok()
|
||||
let turso_url = std::env::var("LIBSQL_URL")
|
||||
.ok()
|
||||
.or_else(|| self.settings.libsql_url.clone());
|
||||
let turso_token = std::env::var("LIBSQL_AUTH_TOKEN").ok();
|
||||
|
||||
match self
|
||||
.test_database_connection_libsql(path, turso_url.as_deref(), turso_token.as_deref())
|
||||
.test_database_connection_libsql(
|
||||
path,
|
||||
turso_url.as_deref(),
|
||||
turso_token.as_deref(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
@@ -309,8 +314,8 @@ impl SetupWizard {
|
||||
|
||||
// Ask about Turso cloud sync
|
||||
println!();
|
||||
let use_turso = confirm("Enable Turso cloud sync (remote replica)?", false)
|
||||
.map_err(SetupError::Io)?;
|
||||
let use_turso =
|
||||
confirm("Enable Turso cloud sync (remote replica)?", false).map_err(SetupError::Io)?;
|
||||
|
||||
let (turso_url, turso_token) = if use_turso {
|
||||
print_info("Enter your Turso database URL and auth token.");
|
||||
@@ -349,11 +354,9 @@ impl SetupWizard {
|
||||
if let Some(url) = turso_url {
|
||||
self.settings.libsql_url = Some(url);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(SetupError::Database(format!("Connection failed: {}", e)));
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(SetupError::Database(format!("Connection failed: {}", e))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,9 +789,10 @@ impl SetupWizard {
|
||||
}
|
||||
};
|
||||
|
||||
let store: Arc<dyn SecretsStore> = Arc::new(
|
||||
crate::secrets::PostgresSecretsStore::new(pool, Arc::clone(crypto)),
|
||||
);
|
||||
let store: Arc<dyn SecretsStore> = Arc::new(crate::secrets::PostgresSecretsStore::new(
|
||||
pool,
|
||||
Arc::clone(crypto),
|
||||
));
|
||||
Ok(Some(store))
|
||||
}
|
||||
|
||||
@@ -802,9 +806,10 @@ impl SetupWizard {
|
||||
let conn = backend
|
||||
.connect()
|
||||
.map_err(|e| SetupError::Database(format!("Failed to create connection: {}", e)))?;
|
||||
let store: Arc<dyn SecretsStore> = Arc::new(
|
||||
crate::secrets::LibSqlSecretsStore::new(conn, Arc::clone(crypto)),
|
||||
);
|
||||
let store: Arc<dyn SecretsStore> = Arc::new(crate::secrets::LibSqlSecretsStore::new(
|
||||
conn,
|
||||
Arc::clone(crypto),
|
||||
));
|
||||
Ok(Some(store))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
||||
@@ -6,8 +6,8 @@ use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::context::ContextManager;
|
||||
use crate::extensions::ExtensionManager;
|
||||
use crate::db::Database;
|
||||
use crate::extensions::ExtensionManager;
|
||||
use crate::llm::{LlmProvider, ToolDefinition};
|
||||
use crate::orchestrator::job_manager::ContainerJobManager;
|
||||
use crate::safety::SafetyLayer;
|
||||
|
||||
@@ -113,9 +113,8 @@ pub use storage::LibSqlWasmToolStore;
|
||||
#[cfg(feature = "postgres")]
|
||||
pub use storage::PostgresWasmToolStore;
|
||||
pub use storage::{
|
||||
StoreToolParams, StoredCapabilities, StoredWasmTool,
|
||||
StoredWasmToolWithBinary, ToolStatus, TrustLevel, WasmStorageError, WasmToolStore,
|
||||
compute_binary_hash, verify_binary_integrity,
|
||||
StoreToolParams, StoredCapabilities, StoredWasmTool, StoredWasmToolWithBinary, ToolStatus,
|
||||
TrustLevel, WasmStorageError, WasmToolStore, compute_binary_hash, verify_binary_integrity,
|
||||
};
|
||||
|
||||
// Loader
|
||||
|
||||
@@ -643,7 +643,9 @@ impl WasmToolStore for LibSqlWasmToolStore {
|
||||
.next()
|
||||
.await
|
||||
.map_err(|e| WasmStorageError::Database(e.to_string()))?
|
||||
.ok_or_else(|| WasmStorageError::Database("Insert succeeded but row not found".into()))?;
|
||||
.ok_or_else(|| {
|
||||
WasmStorageError::Database("Insert succeeded but row not found".into())
|
||||
})?;
|
||||
|
||||
libsql_row_to_tool(&row)
|
||||
}
|
||||
|
||||
@@ -433,7 +433,9 @@ impl Workspace {
|
||||
|
||||
/// List all files recursively (flat list of all paths).
|
||||
pub async fn list_all(&self) -> Result<Vec<String>, WorkspaceError> {
|
||||
self.storage.list_all_paths(&self.user_id, self.agent_id).await
|
||||
self.storage
|
||||
.list_all_paths(&self.user_id, self.agent_id)
|
||||
.await
|
||||
}
|
||||
|
||||
// ==================== Convenience Methods ====================
|
||||
|
||||
Reference in New Issue
Block a user