diff --git a/Cargo.lock b/Cargo.lock index ca6d607e..9c79d496 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3866,7 +3866,7 @@ dependencies = [ [[package]] name = "openfang-api" -version = "0.3.5" +version = "0.3.6" dependencies = [ "async-trait", "axum", @@ -3902,7 +3902,7 @@ dependencies = [ [[package]] name = "openfang-channels" -version = "0.3.5" +version = "0.3.6" dependencies = [ "async-trait", "axum", @@ -3933,7 +3933,7 @@ dependencies = [ [[package]] name = "openfang-cli" -version = "0.3.5" +version = "0.3.6" dependencies = [ "clap", "clap_complete", @@ -3960,7 +3960,7 @@ dependencies = [ [[package]] name = "openfang-desktop" -version = "0.3.5" +version = "0.3.6" dependencies = [ "axum", "open", @@ -3986,7 +3986,7 @@ dependencies = [ [[package]] name = "openfang-extensions" -version = "0.3.5" +version = "0.3.6" dependencies = [ "aes-gcm", "argon2", @@ -4014,7 +4014,7 @@ dependencies = [ [[package]] name = "openfang-hands" -version = "0.3.5" +version = "0.3.6" dependencies = [ "chrono", "dashmap", @@ -4031,7 +4031,7 @@ dependencies = [ [[package]] name = "openfang-kernel" -version = "0.3.5" +version = "0.3.6" dependencies = [ "async-trait", "chrono", @@ -4067,7 +4067,7 @@ dependencies = [ [[package]] name = "openfang-memory" -version = "0.3.5" +version = "0.3.6" dependencies = [ "async-trait", "chrono", @@ -4086,7 +4086,7 @@ dependencies = [ [[package]] name = "openfang-migrate" -version = "0.3.5" +version = "0.3.6" dependencies = [ "chrono", "dirs 6.0.0", @@ -4105,7 +4105,7 @@ dependencies = [ [[package]] name = "openfang-runtime" -version = "0.3.5" +version = "0.3.6" dependencies = [ "anyhow", "async-trait", @@ -4137,7 +4137,7 @@ dependencies = [ [[package]] name = "openfang-skills" -version = "0.3.5" +version = "0.3.6" dependencies = [ "chrono", "hex", @@ -4160,7 +4160,7 @@ dependencies = [ [[package]] name = "openfang-types" -version = "0.3.5" +version = "0.3.6" dependencies = [ "async-trait", "chrono", @@ -4179,7 +4179,7 @@ dependencies = [ [[package]] name = "openfang-wire" -version = "0.3.5" +version = "0.3.6" dependencies = [ "async-trait", "chrono", @@ -8791,7 +8791,7 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xtask" -version = "0.3.5" +version = "0.3.6" [[package]] name = "yoke" diff --git a/Cargo.toml b/Cargo.toml index 1a9f0475..867d5bb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ members = [ ] [workspace.package] -version = "0.3.6" +version = "0.3.7" edition = "2021" license = "Apache-2.0 OR MIT" repository = "https://github.com/RightNow-AI/openfang" diff --git a/crates/openfang-api/src/routes.rs b/crates/openfang-api/src/routes.rs index 1d92989c..ee7d2521 100644 --- a/crates/openfang-api/src/routes.rs +++ b/crates/openfang-api/src/routes.rs @@ -1959,7 +1959,7 @@ pub async fn configure_channel( let home = openfang_kernel::config::openfang_home(); let secrets_path = home.join("secrets.env"); let config_path = home.join("config.toml"); - let mut config_fields: HashMap = HashMap::new(); + let mut config_fields: HashMap = HashMap::new(); for field_def in meta.fields { let value = fields @@ -1983,8 +1983,8 @@ pub async fn configure_channel( std::env::set_var(env_var, value); } } else { - // Config field — collect for TOML write - config_fields.insert(field_def.key.to_string(), value.to_string()); + // Config field — collect for TOML write with type info + config_fields.insert(field_def.key.to_string(), (value.to_string(), field_def.field_type)); } } @@ -2455,19 +2455,14 @@ pub async fn get_template(Path(name): Path) -> impl IntoResponse { // --------------------------------------------------------------------------- /// GET /api/memory/agents/:id/kv — List KV pairs for an agent. +/// +/// Note: memory_store tool writes to a shared namespace, so we read from that +/// same namespace regardless of which agent ID is in the URL. pub async fn get_agent_kv( State(state): State>, - Path(id): Path, + Path(_id): Path, ) -> impl IntoResponse { - let agent_id: AgentId = match id.parse() { - Ok(id) => id, - Err(_) => { - return ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!({"error": "Invalid agent ID"})), - ); - } - }; + let agent_id = openfang_kernel::kernel::shared_memory_agent_id(); match state.kernel.memory.list_kv(agent_id) { Ok(pairs) => { @@ -2478,7 +2473,7 @@ pub async fn get_agent_kv( (StatusCode::OK, Json(serde_json::json!({"kv_pairs": kv}))) } Err(e) => { - tracing::warn!("Memory list_kv failed for agent {id}: {e}"); + tracing::warn!("Memory list_kv failed: {e}"); ( StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({"error": "Memory operation failed"})), @@ -2490,17 +2485,9 @@ pub async fn get_agent_kv( /// GET /api/memory/agents/:id/kv/:key — Get a specific KV value. pub async fn get_agent_kv_key( State(state): State>, - Path((id, key)): Path<(String, String)>, + Path((_id, key)): Path<(String, String)>, ) -> impl IntoResponse { - let agent_id: AgentId = match id.parse() { - Ok(id) => id, - Err(_) => { - return ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!({"error": "Invalid agent ID"})), - ); - } - }; + let agent_id = openfang_kernel::kernel::shared_memory_agent_id(); match state.kernel.memory.structured_get(agent_id, &key) { Ok(Some(val)) => ( @@ -2512,7 +2499,7 @@ pub async fn get_agent_kv_key( Json(serde_json::json!({"error": "Key not found"})), ), Err(e) => { - tracing::warn!("Memory get failed for agent {id}, key '{key}': {e}"); + tracing::warn!("Memory get failed for key '{key}': {e}"); ( StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({"error": "Memory operation failed"})), @@ -2524,18 +2511,10 @@ pub async fn get_agent_kv_key( /// PUT /api/memory/agents/:id/kv/:key — Set a KV value. pub async fn set_agent_kv_key( State(state): State>, - Path((id, key)): Path<(String, String)>, + Path((_id, key)): Path<(String, String)>, Json(body): Json, ) -> impl IntoResponse { - let agent_id: AgentId = match id.parse() { - Ok(id) => id, - Err(_) => { - return ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!({"error": "Invalid agent ID"})), - ); - } - }; + let agent_id = openfang_kernel::kernel::shared_memory_agent_id(); let value = body.get("value").cloned().unwrap_or(body); @@ -2545,7 +2524,7 @@ pub async fn set_agent_kv_key( Json(serde_json::json!({"status": "stored", "key": key})), ), Err(e) => { - tracing::warn!("Memory set failed for agent {id}, key '{key}': {e}"); + tracing::warn!("Memory set failed for key '{key}': {e}"); ( StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({"error": "Memory operation failed"})), @@ -2557,17 +2536,9 @@ pub async fn set_agent_kv_key( /// DELETE /api/memory/agents/:id/kv/:key — Delete a KV value. pub async fn delete_agent_kv_key( State(state): State>, - Path((id, key)): Path<(String, String)>, + Path((_id, key)): Path<(String, String)>, ) -> impl IntoResponse { - let agent_id: AgentId = match id.parse() { - Ok(id) => id, - Err(_) => { - return ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!({"error": "Invalid agent ID"})), - ); - } - }; + let agent_id = openfang_kernel::kernel::shared_memory_agent_id(); match state.kernel.memory.structured_delete(agent_id, &key) { Ok(()) => ( @@ -2575,7 +2546,7 @@ pub async fn delete_agent_kv_key( Json(serde_json::json!({"status": "deleted", "key": key})), ), Err(e) => { - tracing::warn!("Memory delete failed for agent {id}, key '{key}': {e}"); + tracing::warn!("Memory delete failed for key '{key}': {e}"); ( StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({"error": "Memory operation failed"})), @@ -6788,7 +6759,7 @@ fn remove_secret_env(path: &std::path::Path, key: &str) -> Result<(), std::io::E fn upsert_channel_config( config_path: &std::path::Path, channel_name: &str, - fields: &HashMap, + fields: &HashMap, ) -> Result<(), Box> { let content = if config_path.exists() { std::fs::read_to_string(config_path)? @@ -6816,10 +6787,20 @@ fn upsert_channel_config( .and_then(|v| v.as_table_mut()) .ok_or("channels is not a table")?; - // Build channel sub-table + // Build channel sub-table with correct TOML types let mut ch_table = toml::map::Map::new(); - for (k, v) in fields { - ch_table.insert(k.clone(), toml::Value::String(v.clone())); + for (k, (v, ft)) in fields { + let toml_val = match ft { + FieldType::Number => { + if let Ok(n) = v.parse::() { + toml::Value::Integer(n) + } else { + toml::Value::String(v.clone()) + } + } + _ => toml::Value::String(v.clone()), + }; + ch_table.insert(k.clone(), toml_val); } channels_table.insert(channel_name.to_string(), toml::Value::Table(ch_table)); diff --git a/crates/openfang-api/static/index_body.html b/crates/openfang-api/static/index_body.html index 629e2b2f..76d3e2d1 100644 --- a/crates/openfang-api/static/index_body.html +++ b/crates/openfang-api/static/index_body.html @@ -589,6 +589,14 @@
+ +