This commit is contained in:
jaberjaber23
2026-02-28 04:52:49 +03:00
parent a9124c34f2
commit 1cd47d3905
8 changed files with 66 additions and 30 deletions
Generated
+14 -14
View File
@@ -3866,7 +3866,7 @@ dependencies = [
[[package]]
name = "openfang-api"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"async-trait",
"axum",
@@ -3902,7 +3902,7 @@ dependencies = [
[[package]]
name = "openfang-channels"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"async-trait",
"axum",
@@ -3933,7 +3933,7 @@ dependencies = [
[[package]]
name = "openfang-cli"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"clap",
"clap_complete",
@@ -3960,7 +3960,7 @@ dependencies = [
[[package]]
name = "openfang-desktop"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"axum",
"open",
@@ -3986,7 +3986,7 @@ dependencies = [
[[package]]
name = "openfang-extensions"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"aes-gcm",
"argon2",
@@ -4014,7 +4014,7 @@ dependencies = [
[[package]]
name = "openfang-hands"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"chrono",
"dashmap",
@@ -4031,7 +4031,7 @@ dependencies = [
[[package]]
name = "openfang-kernel"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"async-trait",
"chrono",
@@ -4067,7 +4067,7 @@ dependencies = [
[[package]]
name = "openfang-memory"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"async-trait",
"chrono",
@@ -4086,7 +4086,7 @@ dependencies = [
[[package]]
name = "openfang-migrate"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"chrono",
"dirs 6.0.0",
@@ -4105,7 +4105,7 @@ dependencies = [
[[package]]
name = "openfang-runtime"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"anyhow",
"async-trait",
@@ -4136,7 +4136,7 @@ dependencies = [
[[package]]
name = "openfang-skills"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"chrono",
"hex",
@@ -4158,7 +4158,7 @@ dependencies = [
[[package]]
name = "openfang-types"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"async-trait",
"chrono",
@@ -4177,7 +4177,7 @@ dependencies = [
[[package]]
name = "openfang-wire"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"async-trait",
"chrono",
@@ -8789,7 +8789,7 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
[[package]]
name = "xtask"
version = "0.1.7"
version = "0.1.8"
[[package]]
name = "yoke"
+1 -1
View File
@@ -18,7 +18,7 @@ members = [
]
[workspace.package]
version = "0.1.8"
version = "0.1.9"
edition = "2021"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/RightNow-AI/openfang"
+18
View File
@@ -90,6 +90,24 @@ pub async fn auth(
|| path == "/api/profiles"
|| path == "/api/config"
|| path.starts_with("/api/uploads/")
// Dashboard read endpoints — allow unauthenticated so the SPA can
// render before the user enters their API key.
|| path == "/api/models"
|| path == "/api/models/aliases"
|| path == "/api/providers"
|| path == "/api/budget"
|| path == "/api/budget/agents"
|| path.starts_with("/api/budget/agents/")
|| path == "/api/network/status"
|| path == "/api/a2a/agents"
|| path == "/api/approvals"
|| path == "/api/channels"
|| path == "/api/skills"
|| path == "/api/sessions"
|| path == "/api/integrations"
|| path == "/api/integrations/available"
|| path == "/api/integrations/health"
|| path.starts_with("/api/cron/")
{
return next.run(request).await;
}
+6 -4
View File
@@ -1102,10 +1102,12 @@
</div>
<div class="text-sm text-dim mb-2" x-text="a.description"></div>
<div class="text-xs text-dim">Agent: <span x-text="a.agent_name"></span> &middot; <span x-text="timeAgo(a.created_at)"></span></div>
<div class="approval-actions" x-show="a.status === 'pending'" style="display:flex;gap:8px;margin-top:12px">
<button class="btn btn-success btn-sm" @click="approve(a.id)">Approve</button>
<button class="btn btn-danger btn-sm" @click="reject(a.id)">Reject</button>
</div>
<template x-if="a.status === 'pending'">
<div class="approval-actions" style="display:flex;gap:8px;margin-top:12px">
<button class="btn btn-success btn-sm" @click="approve(a.id)">Approve</button>
<button class="btn btn-danger btn-sm" @click="reject(a.id)">Reject</button>
</div>
</template>
</div>
</template>
</div>
+1 -1
View File
@@ -158,7 +158,7 @@ document.addEventListener('alpine:init', function() {
await OpenFangAPI.get('/api/providers');
this.showAuthPrompt = false;
} catch(e) {
if (e.message && e.message.indexOf('401') >= 0) {
if (e.message && (e.message.indexOf('Not authorized') >= 0 || e.message.indexOf('401') >= 0 || e.message.indexOf('Missing Authorization') >= 0)) {
this.showAuthPrompt = true;
}
}
+8 -2
View File
@@ -953,14 +953,20 @@ pub(crate) fn restrict_dir_permissions(_path: &std::path::Path) {}
pub(crate) fn find_daemon() -> Option<String> {
let home_dir = dirs::home_dir()?.join(".openfang");
let info = read_daemon_info(&home_dir)?;
let url = format!("http://{}/api/health", info.listen_addr);
// Normalize listen address: replace 0.0.0.0 with 127.0.0.1 to avoid
// DNS/connectivity issues on macOS where 0.0.0.0 can hang.
let addr = info.listen_addr.replace("0.0.0.0", "127.0.0.1");
let url = format!("http://{addr}/api/health");
let client = reqwest::blocking::Client::builder()
.connect_timeout(std::time::Duration::from_secs(1))
.timeout(std::time::Duration::from_secs(2))
.build()
.ok()?;
let resp = client.get(&url).send().ok()?;
if resp.status().is_success() {
Some(format!("http://{}", info.listen_addr))
Some(format!("http://{addr}"))
} else {
None
}
+16 -8
View File
@@ -222,16 +222,24 @@ impl CronScheduler {
}
/// Return jobs whose `next_run` is at or before `now` and are enabled.
///
/// **Important**: This also pre-advances each due job's `next_run` to the
/// next scheduled time. This prevents the same job from being returned as
/// "due" on subsequent tick iterations while it's still executing.
pub fn due_jobs(&self) -> Vec<CronJob> {
let now = Utc::now();
self.jobs
.iter()
.filter(|r| {
let meta = r.value();
meta.job.enabled && meta.job.next_run.map(|t| t <= now).unwrap_or(false)
})
.map(|r| r.value().job.clone())
.collect()
let mut due = Vec::new();
for mut entry in self.jobs.iter_mut() {
let meta = entry.value_mut();
if meta.job.enabled && meta.job.next_run.map(|t| t <= now).unwrap_or(false) {
due.push(meta.job.clone());
// Pre-advance next_run so the job won't fire again on the next
// tick while it's still executing. record_success/record_failure
// will recompute it again after execution completes.
meta.job.next_run = Some(compute_next_run(&meta.job.schedule));
}
}
due
}
// -- Outcome recording --------------------------------------------------
+2
View File
@@ -3095,6 +3095,8 @@ impl OpenFangKernel {
let kernel = Arc::clone(self);
tokio::spawn(async move {
let mut interval = tokio::time::interval(std::time::Duration::from_secs(15));
// Use Skip to avoid burst-firing after a long job blocks the loop.
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
let mut persist_counter = 0u32;
interval.tick().await; // Skip first immediate tick
loop {