bug fixes

This commit is contained in:
jaberjaber23
2026-03-20 00:33:20 +03:00
parent 93ea832394
commit 93ef98a429
5 changed files with 100 additions and 65 deletions
Generated
+14 -14
View File
@@ -3811,7 +3811,7 @@ dependencies = [
[[package]]
name = "openfang-api"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"async-trait",
"axum",
@@ -3851,7 +3851,7 @@ dependencies = [
[[package]]
name = "openfang-channels"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"aes",
"async-trait",
@@ -3888,7 +3888,7 @@ dependencies = [
[[package]]
name = "openfang-cli"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"clap",
"clap_complete",
@@ -3915,7 +3915,7 @@ dependencies = [
[[package]]
name = "openfang-desktop"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"axum",
"open",
@@ -3941,7 +3941,7 @@ dependencies = [
[[package]]
name = "openfang-extensions"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"aes-gcm",
"argon2",
@@ -3969,7 +3969,7 @@ dependencies = [
[[package]]
name = "openfang-hands"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"chrono",
"dashmap",
@@ -3986,7 +3986,7 @@ dependencies = [
[[package]]
name = "openfang-kernel"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"async-trait",
"chrono",
@@ -4024,7 +4024,7 @@ dependencies = [
[[package]]
name = "openfang-memory"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"async-trait",
"chrono",
@@ -4043,7 +4043,7 @@ dependencies = [
[[package]]
name = "openfang-migrate"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"chrono",
"dirs 6.0.0",
@@ -4062,7 +4062,7 @@ dependencies = [
[[package]]
name = "openfang-runtime"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"anyhow",
"async-trait",
@@ -4096,7 +4096,7 @@ dependencies = [
[[package]]
name = "openfang-skills"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"chrono",
"hex",
@@ -4119,7 +4119,7 @@ dependencies = [
[[package]]
name = "openfang-types"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"async-trait",
"chrono",
@@ -4138,7 +4138,7 @@ dependencies = [
[[package]]
name = "openfang-wire"
version = "0.4.8"
version = "0.4.9"
dependencies = [
"async-trait",
"chrono",
@@ -8814,7 +8814,7 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
[[package]]
name = "xtask"
version = "0.4.8"
version = "0.4.9"
[[package]]
name = "yoke"
+75 -50
View File
@@ -844,7 +844,26 @@ pub async fn create_workflow(
created_at: chrono::Utc::now(),
};
let id = state.kernel.register_workflow(workflow).await;
let id = state.kernel.register_workflow(workflow.clone()).await;
// Persist workflow to disk so it survives daemon restarts (#751)
let wf_dir = state
.kernel
.config
.workflows_dir
.clone()
.unwrap_or_else(|| state.kernel.config.home_dir.join("workflows"));
if let Err(e) = std::fs::create_dir_all(&wf_dir) {
tracing::warn!("Failed to create workflows dir: {e}");
} else {
let wf_path = wf_dir.join(format!("{}.json", id));
if let Ok(json) = serde_json::to_string_pretty(&workflow) {
if let Err(e) = std::fs::write(&wf_path, json) {
tracing::warn!("Failed to persist workflow {id}: {e}");
}
}
}
(
StatusCode::CREATED,
Json(serde_json::json!({"workflow_id": id.to_string()})),
@@ -9713,78 +9732,84 @@ pub async fn config_schema(State(state): State<Arc<AppState>>) -> impl IntoRespo
.collect();
drop(catalog);
// Helper: normalize field definitions to objects with {name, type, label}
// so the frontend template can iterate and render inputs correctly.
let f = |name: &str, ftype: &str, label: &str| -> serde_json::Value {
serde_json::json!({"name": name, "type": ftype, "label": label})
};
Json(serde_json::json!({
"sections": {
"general": {
"root_level": true,
"fields": {
"api_listen": "string",
"api_key": "string",
"log_level": "string"
}
"fields": [
f("api_listen", "string", "API Listen Address"),
f("api_key", "string", "API Key"),
f("log_level", "string", "Log Level")
]
},
"default_model": {
"hot_reloadable": true,
"fields": {
"provider": { "type": "select", "options": provider_options },
"model": { "type": "select", "options": model_options },
"api_key_env": "string",
"base_url": "string"
}
"fields": [
{ "name": "provider", "type": "select", "label": "Provider", "options": provider_options },
{ "name": "model", "type": "select", "label": "Model", "options": model_options },
f("api_key_env", "string", "API Key Env Var"),
f("base_url", "string", "Base URL")
]
},
"memory": {
"fields": {
"decay_rate": "number",
"vector_dims": "number"
}
"fields": [
f("decay_rate", "number", "Decay Rate"),
f("vector_dims", "number", "Vector Dimensions")
]
},
"web": {
"fields": {
"provider": "string",
"timeout_secs": "number",
"max_results": "number"
}
"fields": [
f("provider", "string", "Search Provider"),
f("timeout_secs", "number", "Timeout (seconds)"),
f("max_results", "number", "Max Results")
]
},
"browser": {
"fields": {
"headless": "boolean",
"timeout_secs": "number",
"executable_path": "string"
}
"fields": [
f("headless", "boolean", "Headless Mode"),
f("timeout_secs", "number", "Timeout (seconds)"),
f("executable_path", "string", "Chrome/Chromium Path")
]
},
"network": {
"fields": {
"enabled": "boolean",
"listen_addr": "string",
"shared_secret": "string"
}
"fields": [
f("enabled", "boolean", "Enable OFP Network"),
f("listen_addr", "string", "Listen Address"),
f("shared_secret", "string", "Shared Secret")
]
},
"extensions": {
"fields": {
"auto_connect": "boolean",
"health_check_interval_secs": "number"
}
"fields": [
f("auto_connect", "boolean", "Auto Connect"),
f("health_check_interval_secs", "number", "Health Check Interval (s)")
]
},
"vault": {
"fields": {
"path": "string"
}
"fields": [
f("path", "string", "Vault Path")
]
},
"a2a": {
"fields": {
"enabled": "boolean",
"name": "string",
"description": "string",
"url": "string"
}
"fields": [
f("enabled", "boolean", "Enable A2A"),
f("name", "string", "Agent Name"),
f("description", "string", "Description"),
f("url", "string", "URL")
]
},
"channels": {
"fields": {
"telegram": "object",
"discord": "object",
"slack": "object",
"whatsapp": "object"
}
"fields": [
f("telegram", "object", "Telegram"),
f("discord", "object", "Discord"),
f("slack", "object", "Slack"),
f("whatsapp", "object", "WhatsApp")
]
}
}
}))
+1 -1
View File
@@ -3449,7 +3449,7 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
<div class="card mb-4">
<div class="card-header" style="text-transform:capitalize" x-text="section.replace(/_/g, ' ')"></div>
<div class="detail-grid" style="margin-top:12px">
<template x-for="field in fields" :key="section + '.' + field.name">
<template x-for="field in (fields.fields || [])" :key="section + '.' + field.name">
<div class="detail-row" style="align-items:center">
<span class="detail-label" x-text="field.label || field.name"></span>
<div style="display:flex;align-items:center;gap:8px;flex:1;min-width:0">
@@ -127,6 +127,13 @@ impl CredentialResolver {
}
}
/// Clear a credential from the in-memory dotenv cache.
/// Call this when a key is deleted via the dashboard so the resolver
/// doesn't return a stale value from the boot-time snapshot.
pub fn clear_dotenv_cache(&mut self, key: &str) {
self.dotenv.remove(key);
}
/// Remove a credential from the vault (if available).
pub fn remove_from_vault(&mut self, key: &str) -> ExtensionResult<bool> {
if let Some(ref mut vault) = self.vault {
+3
View File
@@ -4579,6 +4579,9 @@ impl OpenFangKernel {
if let Err(e) = resolver.remove_from_vault(key) {
debug!("Vault remove skipped for {key}: {e}");
}
// Also clear from the in-memory dotenv cache so the resolver
// doesn't return a stale value from the boot-time snapshot (#736).
resolver.clear_dotenv_cache(key);
}
fn lookup_provider_url(&self, provider: &str) -> Option<String> {