mirror of
https://github.com/RightNow-AI/openfang.git
synced 2026-07-30 06:32:17 +00:00
default resilience
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
name: Bug Report
|
||||
description: Report a bug or unexpected behavior
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: What happened?
|
||||
placeholder: Describe the bug clearly and concisely.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What did you expect to happen?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: How can we reproduce this?
|
||||
placeholder: |
|
||||
1. Run `openfang start`
|
||||
2. Open dashboard at http://localhost:4200
|
||||
3. Click ...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: OpenFang Version
|
||||
description: Output of `openfang -V`
|
||||
placeholder: "0.3.23"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
options:
|
||||
- Linux (x86_64)
|
||||
- Linux (aarch64/ARM64)
|
||||
- macOS (Apple Silicon)
|
||||
- macOS (Intel)
|
||||
- Windows
|
||||
- Android (Termux)
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs / Screenshots
|
||||
description: Paste relevant logs or attach screenshots.
|
||||
@@ -0,0 +1,24 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature or improvement
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: What feature would you like?
|
||||
placeholder: Describe the feature and why it would be useful.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives Considered
|
||||
description: Have you tried any workarounds?
|
||||
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Any other context, screenshots, or references.
|
||||
@@ -0,0 +1,17 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "cargo"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- "dependencies"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 3
|
||||
labels:
|
||||
- "ci"
|
||||
@@ -0,0 +1,19 @@
|
||||
## Summary
|
||||
|
||||
<!-- What does this PR do? Link related issues with "Fixes #123". -->
|
||||
|
||||
## Changes
|
||||
|
||||
<!-- Brief list of what changed. -->
|
||||
|
||||
## Testing
|
||||
|
||||
- [ ] `cargo clippy --workspace --all-targets -- -D warnings` passes
|
||||
- [ ] `cargo test --workspace` passes
|
||||
- [ ] Live integration tested (if applicable)
|
||||
|
||||
## Security
|
||||
|
||||
- [ ] No new unsafe code
|
||||
- [ ] No secrets or API keys in diff
|
||||
- [ ] User input validated at boundaries
|
||||
Generated
+14
-14
@@ -3866,7 +3866,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-api"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
@@ -3903,7 +3903,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-channels"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
@@ -3934,7 +3934,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-cli"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_complete",
|
||||
@@ -3961,7 +3961,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-desktop"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"open",
|
||||
@@ -3987,7 +3987,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-extensions"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"argon2",
|
||||
@@ -4015,7 +4015,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-hands"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dashmap",
|
||||
@@ -4032,7 +4032,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-kernel"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4068,7 +4068,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-memory"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4087,7 +4087,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-migrate"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dirs 6.0.0",
|
||||
@@ -4106,7 +4106,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-runtime"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4138,7 +4138,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-skills"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
@@ -4161,7 +4161,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-types"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4180,7 +4180,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-wire"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -8802,7 +8802,7 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.3.23"
|
||||
version = "0.3.24"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/RightNow-AI/openfang"
|
||||
|
||||
@@ -2075,20 +2075,23 @@ fn cmd_doctor(json: bool, repair: bool) {
|
||||
}
|
||||
let answer = prompt_input(" Create default config? [Y/n] ");
|
||||
if answer.is_empty() || answer.starts_with('y') || answer.starts_with('Y') {
|
||||
let default_config = r#"# OpenFang Agent OS configuration
|
||||
let (provider, api_key_env, model) = detect_best_provider();
|
||||
let default_config = format!(
|
||||
r#"# OpenFang Agent OS configuration
|
||||
# See https://github.com/RightNow-AI/openfang for documentation
|
||||
|
||||
# For Docker, change to "0.0.0.0:4200" or set OPENFANG_LISTEN env var.
|
||||
api_listen = "127.0.0.1:4200"
|
||||
|
||||
[default_model]
|
||||
provider = "groq"
|
||||
model = "llama-3.3-70b-versatile"
|
||||
api_key_env = "GROQ_API_KEY"
|
||||
provider = "{provider}"
|
||||
model = "{model}"
|
||||
api_key_env = "{api_key_env}"
|
||||
|
||||
[memory]
|
||||
decay_rate = 0.05
|
||||
"#;
|
||||
"#
|
||||
);
|
||||
let _ = std::fs::create_dir_all(&openfang_dir);
|
||||
if std::fs::write(&config_path, default_config).is_ok() {
|
||||
restrict_file_permissions(&config_path);
|
||||
|
||||
@@ -1027,24 +1027,31 @@ impl OpenFangKernel {
|
||||
&mut restored_entry.manifest.resources,
|
||||
);
|
||||
|
||||
// Apply default_model to restored agents (same logic as spawn)
|
||||
// Apply default_model to restored agents.
|
||||
//
|
||||
// Two cases:
|
||||
// 1. Agent has empty/default provider → always apply default_model
|
||||
// 2. Agent named "assistant" (auto-spawned) → update to match
|
||||
// default_model so config.toml changes take effect on restart
|
||||
{
|
||||
let dm = &kernel.config.default_model;
|
||||
let is_default_provider = restored_entry.manifest.model.provider.is_empty()
|
||||
|| restored_entry.manifest.model.provider == "default";
|
||||
let is_default_model = restored_entry.manifest.model.model.is_empty()
|
||||
|| restored_entry.manifest.model.model == "default";
|
||||
if is_default_provider && is_default_model {
|
||||
let dm = &kernel.config.default_model;
|
||||
let is_auto_spawned = restored_entry.name == "assistant"
|
||||
&& restored_entry.manifest.description == "General-purpose assistant";
|
||||
if is_default_provider && is_default_model || is_auto_spawned {
|
||||
if !dm.provider.is_empty() {
|
||||
restored_entry.manifest.model.provider = dm.provider.clone();
|
||||
}
|
||||
if !dm.model.is_empty() {
|
||||
restored_entry.manifest.model.model = dm.model.clone();
|
||||
}
|
||||
if !dm.api_key_env.is_empty() && restored_entry.manifest.model.api_key_env.is_none() {
|
||||
if !dm.api_key_env.is_empty() {
|
||||
restored_entry.manifest.model.api_key_env = Some(dm.api_key_env.clone());
|
||||
}
|
||||
if dm.base_url.is_some() && restored_entry.manifest.model.base_url.is_none() {
|
||||
if dm.base_url.is_some() {
|
||||
restored_entry.manifest.model.base_url.clone_from(&dm.base_url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,10 +54,11 @@ impl SetupWizard {
|
||||
/// model configuration, capabilities, and schedule.
|
||||
pub fn build_plan(intent: AgentIntent) -> SetupPlan {
|
||||
// Map model tier to provider/model
|
||||
// Use "default" so the kernel applies config.toml's [default_model].
|
||||
// Only "complex" tier gets an explicit Anthropic override.
|
||||
let (provider, model) = match intent.model_tier.as_str() {
|
||||
"simple" => ("groq", "llama-3.3-70b-versatile"),
|
||||
"complex" => ("anthropic", "claude-sonnet-4-20250514"),
|
||||
_ => ("groq", "llama-3.3-70b-versatile"), // medium default
|
||||
_ => ("default", "default"),
|
||||
};
|
||||
|
||||
// Build capabilities from intent
|
||||
@@ -285,7 +286,7 @@ mod tests {
|
||||
let plan = SetupWizard::build_plan(intent);
|
||||
|
||||
assert_eq!(plan.manifest.name, "research-bot");
|
||||
assert_eq!(plan.manifest.model.provider, "groq");
|
||||
assert_eq!(plan.manifest.model.provider, "default");
|
||||
assert!(plan
|
||||
.manifest
|
||||
.capabilities
|
||||
|
||||
@@ -26,9 +26,17 @@ impl ModelCatalog {
|
||||
/// Create a new catalog populated with builtin models and providers.
|
||||
pub fn new() -> Self {
|
||||
let models = builtin_models();
|
||||
let aliases = builtin_aliases();
|
||||
let mut aliases = builtin_aliases();
|
||||
let mut providers = builtin_providers();
|
||||
|
||||
// Auto-register aliases defined on model entries
|
||||
for model in &models {
|
||||
for alias in &model.aliases {
|
||||
let lower = alias.to_lowercase();
|
||||
aliases.entry(lower).or_insert_with(|| model.id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Set model counts on providers
|
||||
for provider in &mut providers {
|
||||
provider.model_count = models.iter().filter(|m| m.provider == provider.id).count();
|
||||
@@ -2589,6 +2597,76 @@ fn builtin_models() -> Vec<ModelCatalogEntry> {
|
||||
supports_streaming: true,
|
||||
aliases: vec![],
|
||||
},
|
||||
ModelCatalogEntry {
|
||||
id: "qwen3-235b-a22b".into(),
|
||||
display_name: "Qwen3 235B".into(),
|
||||
provider: "qwen".into(),
|
||||
tier: ModelTier::Frontier,
|
||||
context_window: 131_072,
|
||||
max_output_tokens: 8_192,
|
||||
input_cost_per_m: 4.00,
|
||||
output_cost_per_m: 12.00,
|
||||
supports_tools: true,
|
||||
supports_vision: false,
|
||||
supports_streaming: true,
|
||||
aliases: vec!["qwen3".into()],
|
||||
},
|
||||
ModelCatalogEntry {
|
||||
id: "qwen3-30b-a3b".into(),
|
||||
display_name: "Qwen3 30B".into(),
|
||||
provider: "qwen".into(),
|
||||
tier: ModelTier::Fast,
|
||||
context_window: 131_072,
|
||||
max_output_tokens: 8_192,
|
||||
input_cost_per_m: 0.30,
|
||||
output_cost_per_m: 0.60,
|
||||
supports_tools: true,
|
||||
supports_vision: false,
|
||||
supports_streaming: true,
|
||||
aliases: vec![],
|
||||
},
|
||||
ModelCatalogEntry {
|
||||
id: "qwen-coder-plus-latest".into(),
|
||||
display_name: "Qwen Coder Plus (Latest)".into(),
|
||||
provider: "qwen".into(),
|
||||
tier: ModelTier::Smart,
|
||||
context_window: 131_072,
|
||||
max_output_tokens: 8_192,
|
||||
input_cost_per_m: 0.80,
|
||||
output_cost_per_m: 2.00,
|
||||
supports_tools: true,
|
||||
supports_vision: false,
|
||||
supports_streaming: true,
|
||||
aliases: vec!["qwen-coder".into()],
|
||||
},
|
||||
ModelCatalogEntry {
|
||||
id: "qwen2.5-coder-32b-instruct".into(),
|
||||
display_name: "Qwen 2.5 Coder 32B".into(),
|
||||
provider: "qwen".into(),
|
||||
tier: ModelTier::Balanced,
|
||||
context_window: 131_072,
|
||||
max_output_tokens: 8_192,
|
||||
input_cost_per_m: 0.80,
|
||||
output_cost_per_m: 2.00,
|
||||
supports_tools: true,
|
||||
supports_vision: false,
|
||||
supports_streaming: true,
|
||||
aliases: vec![],
|
||||
},
|
||||
ModelCatalogEntry {
|
||||
id: "qwen-vl-max".into(),
|
||||
display_name: "Qwen VL Max".into(),
|
||||
provider: "qwen".into(),
|
||||
tier: ModelTier::Frontier,
|
||||
context_window: 32_768,
|
||||
max_output_tokens: 8_192,
|
||||
input_cost_per_m: 3.00,
|
||||
output_cost_per_m: 9.00,
|
||||
supports_tools: false,
|
||||
supports_vision: true,
|
||||
supports_streaming: true,
|
||||
aliases: vec![],
|
||||
},
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// MiniMax (4)
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user