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