Skip to content

Commit fac4ad3

Browse files
committed
discord bugfixes
1 parent fe96cd1 commit fac4ad3

10 files changed

Lines changed: 204 additions & 84 deletions

File tree

Cargo.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ members = [
1818
]
1919

2020
[workspace.package]
21-
version = "0.3.7"
21+
version = "0.3.8"
2222
edition = "2021"
2323
license = "Apache-2.0 OR MIT"
2424
repository = "https://github.com/RightNow-AI/openfang"

crates/openfang-api/src/ws.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,12 @@ async fn handle_command(
796796
} else {
797797
match state.kernel.set_agent_model(agent_id, args) {
798798
Ok(()) => {
799-
serde_json::json!({"type": "command_result", "command": cmd, "message": format!("Model switched to: {args}")})
799+
let msg = if let Some(entry) = state.kernel.registry.get(agent_id) {
800+
format!("Model switched to: {} (provider: {})", entry.manifest.model.model, entry.manifest.model.provider)
801+
} else {
802+
format!("Model switched to: {args}")
803+
};
804+
serde_json::json!({"type": "command_result", "command": cmd, "message": msg})
800805
}
801806
Err(e) => {
802807
serde_json::json!({"type": "error", "content": format!("Model switch failed: {e}")})

crates/openfang-api/tests/api_integration_test.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,10 @@ async fn test_status_endpoint() {
222222
assert_eq!(resp.status(), 200);
223223
let body: serde_json::Value = resp.json().await.unwrap();
224224
assert_eq!(body["status"], "running");
225-
assert_eq!(body["agent_count"], 0);
225+
assert_eq!(body["agent_count"], 1); // default assistant auto-spawned
226226
assert!(body["uptime_seconds"].is_number());
227227
assert_eq!(body["default_provider"], "ollama");
228-
assert_eq!(body["agents"].as_array().unwrap().len(), 0);
228+
assert_eq!(body["agents"].as_array().unwrap().len(), 1);
229229
}
230230

231231
#[tokio::test]
@@ -247,18 +247,18 @@ async fn test_spawn_list_kill_agent() {
247247
let agent_id = body["agent_id"].as_str().unwrap().to_string();
248248
assert!(!agent_id.is_empty());
249249

250-
// --- List (1 agent) ---
250+
// --- List (2 agents: default assistant + test-agent) ---
251251
let resp = client
252252
.get(format!("{}/api/agents", server.base_url))
253253
.send()
254254
.await
255255
.unwrap();
256256
assert_eq!(resp.status(), 200);
257257
let agents: Vec<serde_json::Value> = resp.json().await.unwrap();
258-
assert_eq!(agents.len(), 1);
259-
assert_eq!(agents[0]["name"], "test-agent");
260-
assert_eq!(agents[0]["id"], agent_id);
261-
assert_eq!(agents[0]["model_provider"], "ollama");
258+
assert_eq!(agents.len(), 2);
259+
let test_agent = agents.iter().find(|a| a["name"] == "test-agent").unwrap();
260+
assert_eq!(test_agent["id"], agent_id);
261+
assert_eq!(test_agent["model_provider"], "ollama");
262262

263263
// --- Kill ---
264264
let resp = client
@@ -270,15 +270,16 @@ async fn test_spawn_list_kill_agent() {
270270
let body: serde_json::Value = resp.json().await.unwrap();
271271
assert_eq!(body["status"], "killed");
272272

273-
// --- List (empty) ---
273+
// --- List (only default assistant remains) ---
274274
let resp = client
275275
.get(format!("{}/api/agents", server.base_url))
276276
.send()
277277
.await
278278
.unwrap();
279279
assert_eq!(resp.status(), 200);
280280
let agents: Vec<serde_json::Value> = resp.json().await.unwrap();
281-
assert_eq!(agents.len(), 0);
281+
assert_eq!(agents.len(), 1);
282+
assert_eq!(agents[0]["name"], "assistant");
282283
}
283284

284285
#[tokio::test]
@@ -617,14 +618,14 @@ memory_write = ["self.*"]
617618
ids.push(body["agent_id"].as_str().unwrap().to_string());
618619
}
619620

620-
// List should show 3
621+
// List should show 4 (3 spawned + default assistant)
621622
let resp = client
622623
.get(format!("{}/api/agents", server.base_url))
623624
.send()
624625
.await
625626
.unwrap();
626627
let agents: Vec<serde_json::Value> = resp.json().await.unwrap();
627-
assert_eq!(agents.len(), 3);
628+
assert_eq!(agents.len(), 4);
628629

629630
// Status should agree
630631
let resp = client
@@ -633,7 +634,7 @@ memory_write = ["self.*"]
633634
.await
634635
.unwrap();
635636
let status: serde_json::Value = resp.json().await.unwrap();
636-
assert_eq!(status["agent_count"], 3);
637+
assert_eq!(status["agent_count"], 4);
637638

638639
// Kill one
639640
let resp = client
@@ -643,14 +644,14 @@ memory_write = ["self.*"]
643644
.unwrap();
644645
assert_eq!(resp.status(), 200);
645646

646-
// List should show 2
647+
// List should show 3 (2 spawned + default assistant)
647648
let resp = client
648649
.get(format!("{}/api/agents", server.base_url))
649650
.send()
650651
.await
651652
.unwrap();
652653
let agents: Vec<serde_json::Value> = resp.json().await.unwrap();
653-
assert_eq!(agents.len(), 2);
654+
assert_eq!(agents.len(), 3);
654655

655656
// Kill the rest
656657
for id in [&ids[0], &ids[2]] {
@@ -661,14 +662,14 @@ memory_write = ["self.*"]
661662
.unwrap();
662663
}
663664

664-
// List should be empty
665+
// List should have only default assistant
665666
let resp = client
666667
.get(format!("{}/api/agents", server.base_url))
667668
.send()
668669
.await
669670
.unwrap();
670671
let agents: Vec<serde_json::Value> = resp.json().await.unwrap();
671-
assert_eq!(agents.len(), 0);
672+
assert_eq!(agents.len(), 1);
672673
}
673674

674675
// ---------------------------------------------------------------------------

crates/openfang-api/tests/load_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ async fn load_spawn_kill_cycle() {
541541
.await
542542
.unwrap();
543543
let remaining = agents.as_array().map(|a| a.len()).unwrap_or(0);
544-
assert_eq!(remaining, 0, "All agents should be killed");
544+
assert_eq!(remaining, 1, "Only default assistant should remain");
545545
}
546546

547547
/// Test: Prometheus metrics endpoint under sustained load.

crates/openfang-kernel/src/kernel.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,33 @@ impl OpenFangKernel {
10541054
}
10551055
}
10561056

1057+
// If no agents exist (fresh install), spawn a default assistant
1058+
if kernel.registry.list().is_empty() {
1059+
info!("No agents found — spawning default assistant");
1060+
let dm = &kernel.config.default_model;
1061+
let manifest = AgentManifest {
1062+
name: "assistant".to_string(),
1063+
description: "General-purpose assistant".to_string(),
1064+
model: openfang_types::agent::ModelConfig {
1065+
provider: dm.provider.clone(),
1066+
model: dm.model.clone(),
1067+
system_prompt: "You are a helpful AI assistant.".to_string(),
1068+
api_key_env: if dm.api_key_env.is_empty() {
1069+
None
1070+
} else {
1071+
Some(dm.api_key_env.clone())
1072+
},
1073+
base_url: dm.base_url.clone(),
1074+
..Default::default()
1075+
},
1076+
..Default::default()
1077+
};
1078+
match kernel.spawn_agent(manifest) {
1079+
Ok(id) => info!(id = %id, "Default assistant spawned"),
1080+
Err(e) => warn!("Failed to spawn default assistant: {e}"),
1081+
}
1082+
}
1083+
10571084
// Validate routing configs against model catalog
10581085
for entry in kernel.registry.list() {
10591086
if let Some(ref routing_config) = entry.manifest.routing {
@@ -2089,7 +2116,16 @@ impl OpenFangKernel {
20892116
routed_model = %routed_model,
20902117
"Model routing applied"
20912118
);
2092-
manifest.model.model = routed_model;
2119+
manifest.model.model = routed_model.clone();
2120+
// Also update provider if the routed model belongs to a different provider
2121+
if let Ok(cat) = self.model_catalog.read() {
2122+
if let Some(entry) = cat.find_model(&routed_model) {
2123+
if entry.provider != manifest.model.provider {
2124+
info!(old = %manifest.model.provider, new = %entry.provider, "Model routing changed provider");
2125+
manifest.model.provider = entry.provider.clone();
2126+
}
2127+
}
2128+
}
20932129
}
20942130

20952131
let driver = self.resolve_driver(&manifest)?;
@@ -2923,6 +2959,13 @@ impl OpenFangKernel {
29232959
);
29242960
}
29252961

2962+
// If an agent with this hand's name already exists, remove it first
2963+
let existing = self.registry.list().into_iter().find(|e| e.name == def.agent.name);
2964+
if let Some(old) = existing {
2965+
info!(agent = %old.name, id = %old.id, "Removing existing hand agent for reactivation");
2966+
let _ = self.kill_agent(old.id);
2967+
}
2968+
29262969
// Spawn the agent
29272970
let agent_id = self.spawn_agent(manifest)?;
29282971

crates/openfang-kernel/src/metering.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ fn estimate_cost_rates(model: &str) -> (f64, f64) {
429429
}
430430

431431
// ── xAI / Grok ──────────────────────────────────────────────
432-
if model.contains("grok-4.1") {
432+
if model.contains("grok-4-1") {
433433
return (0.20, 0.50);
434434
}
435435
if model.contains("grok-4") {

crates/openfang-kernel/tests/wasm_agent_integration_test.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,9 @@ async fn test_multiple_wasm_agents() {
349349
assert_eq!(hello_result.response, "hello from wasm");
350350
assert!(echo_result.response.contains("test data"));
351351

352-
// Verify agent list shows both
352+
// Verify agent list shows both + default assistant
353353
let agents = kernel.registry.list();
354-
assert_eq!(agents.len(), 2);
354+
assert_eq!(agents.len(), 3);
355355

356356
kernel.shutdown();
357357
}
@@ -391,9 +391,9 @@ memory_write = ["self.*"]
391391
let llm_manifest: AgentManifest = toml::from_str(llm_toml).unwrap();
392392
let llm_id = kernel.spawn_agent(llm_manifest).unwrap();
393393

394-
// Verify both agents exist
394+
// Verify both agents exist + default assistant
395395
let agents = kernel.registry.list();
396-
assert_eq!(agents.len(), 2);
396+
assert_eq!(agents.len(), 3);
397397

398398
// WASM agent should work
399399
let result = kernel.send_message(wasm_id, "hello").await.unwrap();
@@ -404,7 +404,7 @@ memory_write = ["self.*"]
404404

405405
// Kill WASM agent
406406
kernel.kill_agent(wasm_id).unwrap();
407-
assert_eq!(kernel.registry.list().len(), 1);
407+
assert_eq!(kernel.registry.list().len(), 2);
408408

409409
kernel.shutdown();
410410
}

0 commit comments

Comments
 (0)