Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 25 additions & 24 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ aionui-cron = { path = "crates/aionui-cron" }
aionui-assistant = { path = "crates/aionui-assistant" }
aionui-app = { path = "crates/aionui-app" }

aion-agent = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.1" }
aion-providers = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.1" }
aion-types = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.1" }
aion-protocol = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.1" }
aion-config = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.1" }
aion-mcp = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.1" }
aion-agent = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.2" }
aion-providers = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.2" }
aion-types = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.2" }
aion-protocol = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.2" }
aion-config = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.2" }
aion-mcp = { git = "https://github.com/iOfficeAI/aionrs.git", tag = "v0.2.2" }

# Core framework
tokio = { version = "1", features = ["full"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/aionui-ai-agent/src/agent_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ mod aionrs_config_option_tests {
model: "claude-sonnet-4-20250514".into(),
base_url: None,
system_prompt: None,
max_tokens: 4096,
max_tokens: Some(4096),
max_turns: None,
max_tool_call_malformed_turns: None,
max_tool_call_failure_turns: None,
Expand Down
6 changes: 4 additions & 2 deletions crates/aionui-ai-agent/src/manager/aionrs/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,15 @@ impl AionrsAgentManager {
api_key: Some(config_extra.api_key.clone()),
base_url: config_extra.base_url.clone(),
model: Some(config_extra.model.clone()),
max_tokens: Some(config_extra.max_tokens),
max_tokens: config_extra.max_tokens,
max_turns: config_extra.max_turns,
max_tool_call_malformed_turns: config_extra.max_tool_call_malformed_turns,
max_tool_call_failure_turns: config_extra.max_tool_call_failure_turns,
system_prompt: config_extra.system_prompt.clone(),
profile: None,
auto_approve: config_extra.session_mode.as_deref() == Some("yolo"),
thinking: None,
thinking_budget: None,
project_dir: Some(PathBuf::from(&workspace)),
};

Expand Down Expand Up @@ -485,7 +487,7 @@ mod tests {
model: "claude-sonnet-4-20250514".into(),
base_url: None,
system_prompt: None,
max_tokens: 4096,
max_tokens: Some(4096),
max_turns: None,
max_tool_call_malformed_turns: None,
max_tool_call_failure_turns: None,
Expand Down
75 changes: 73 additions & 2 deletions crates/aionui-ai-agent/src/services/provider_health.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::factory::aionrs::{map_aionrs_provider, resolve_aionrs_url_and_compat,
use crate::types::AionrsResolvedConfig;

const HEALTH_CHECK_TIMEOUT: Duration = Duration::from_secs(30);
const HEALTH_CHECK_MAX_TOKENS: u32 = 16;
const HEALTH_CHECK_PROMPT: &str = "Reply with exactly OK.";
const HEALTH_CHECK_MSG_ID: &str = "provider-health-check";

Expand Down Expand Up @@ -80,7 +81,7 @@ impl ProviderHealthCheckService {
model: model_id.to_owned(),
base_url,
system_prompt: Some("You are a provider health probe. Reply with exactly OK and do not use tools.".into()),
max_tokens: 16,
max_tokens: Some(HEALTH_CHECK_MAX_TOKENS),
max_turns: Some(1),
max_tool_call_malformed_turns: Some(1),
max_tool_call_failure_turns: Some(1),
Expand Down Expand Up @@ -195,13 +196,15 @@ async fn build_probe_engine(config_extra: AionrsResolvedConfig) -> Result<AgentE
api_key: Some(config_extra.api_key),
base_url: config_extra.base_url,
model: Some(config_extra.model),
max_tokens: Some(config_extra.max_tokens),
max_tokens: config_extra.max_tokens,
max_turns: config_extra.max_turns,
max_tool_call_malformed_turns: config_extra.max_tool_call_malformed_turns,
max_tool_call_failure_turns: config_extra.max_tool_call_failure_turns,
system_prompt: config_extra.system_prompt,
profile: None,
auto_approve: false,
thinking: None,
thinking_budget: None,
project_dir: Some(PathBuf::from(&workspace)),
};
let mut config =
Expand Down Expand Up @@ -311,6 +314,74 @@ pub(crate) fn extract_http_status(message: &str) -> Option<u16> {
#[cfg(test)]
mod tests {
use super::*;
use aionui_common::encrypt_string;
use aionui_db::{CreateProviderParams, DbError, UpdateProviderParams};

const TEST_KEY: [u8; 32] = [0xAB; 32];

struct UnusedProviderRepository;

#[async_trait::async_trait]
impl IProviderRepository for UnusedProviderRepository {
async fn list(&self) -> Result<Vec<Provider>, DbError> {
unreachable!("provider repo is not used by resolve_probe_config")
}

async fn find_by_id(&self, _id: &str) -> Result<Option<Provider>, DbError> {
unreachable!("provider repo is not used by resolve_probe_config")
}

async fn create(&self, _params: CreateProviderParams<'_>) -> Result<Provider, DbError> {
unreachable!("provider repo is not used by resolve_probe_config")
}

async fn update(&self, _id: &str, _params: UpdateProviderParams<'_>) -> Result<Provider, DbError> {
unreachable!("provider repo is not used by resolve_probe_config")
}

async fn delete(&self, _id: &str) -> Result<(), DbError> {
unreachable!("provider repo is not used by resolve_probe_config")
}
}

fn test_service() -> ProviderHealthCheckService {
ProviderHealthCheckService {
provider_repo: Arc::new(UnusedProviderRepository),
encryption_key: TEST_KEY,
data_dir: PathBuf::from("/tmp/aioncore-provider-health-test"),
}
}

fn test_provider() -> Provider {
Provider {
id: "provider-1".to_owned(),
platform: "anthropic".to_owned(),
name: "Test Anthropic".to_owned(),
base_url: "https://api.anthropic.com".to_owned(),
api_key_encrypted: encrypt_string("sk-test", &TEST_KEY).unwrap(),
models: r#"["claude-sonnet-4-20250514"]"#.to_owned(),
enabled: true,
capabilities: "[]".to_owned(),
context_limit: None,
model_protocols: None,
model_enabled: None,
model_health: None,
bedrock_config: None,
is_full_url: false,
created_at: 0,
updated_at: 0,
}
}

#[test]
fn resolve_probe_config_keeps_health_check_token_cap() {
let config = test_service()
.resolve_probe_config(&test_provider(), "claude-sonnet-4-20250514")
.unwrap();

assert_eq!(config.max_tokens, Some(HEALTH_CHECK_MAX_TOKENS));
assert_eq!(config.max_turns, Some(1));
}

#[test]
fn classify_error_detects_quota_message() {
Expand Down
8 changes: 4 additions & 4 deletions crates/aionui-ai-agent/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ pub struct AionrsResolvedConfig {
pub base_url: Option<String>,
/// System prompt override.
pub system_prompt: Option<String>,
/// Max tokens per response.
pub max_tokens: u32,
/// Optional max tokens per response.
pub max_tokens: Option<u32>,
/// Max agentic turns.
pub max_turns: Option<usize>,
/// Max repeated malformed tool-call turns before stopping.
Expand Down Expand Up @@ -341,7 +341,7 @@ mod tests {
let extra: AionrsBuildExtra = serde_json::from_value(json).unwrap();
assert!(extra.system_prompt.is_none());
assert!(extra.preset_rules.is_none());
assert_eq!(extra.max_tokens, 8192);
assert_eq!(extra.max_tokens, None);
assert!(extra.max_turns.is_none());
assert!(extra.max_tool_call_malformed_turns.is_none());
assert!(extra.max_tool_call_failure_turns.is_none());
Expand All @@ -358,7 +358,7 @@ mod tests {
});
let extra: AionrsBuildExtra = serde_json::from_value(json).unwrap();
assert_eq!(extra.system_prompt.unwrap(), "You are a helpful assistant.");
assert_eq!(extra.max_tokens, 4096);
assert_eq!(extra.max_tokens, Some(4096));
assert_eq!(extra.max_turns.unwrap(), 10);
assert_eq!(extra.max_tool_call_malformed_turns.unwrap(), 2);
assert_eq!(extra.max_tool_call_failure_turns.unwrap(), 3);
Expand Down
2 changes: 1 addition & 1 deletion crates/aionui-ai-agent/tests/agent_types_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ fn make_aionrs_config() -> AionrsResolvedConfig {
model: "claude-sonnet-4-20250514".into(),
base_url: None,
system_prompt: None,
max_tokens: 4096,
max_tokens: Some(4096),
max_turns: None,
max_tool_call_malformed_turns: None,
max_tool_call_failure_turns: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ async fn aionrs_factory_resolves_provider_from_db() {
use_model: None,
},
AionrsBuildExtra {
max_tokens: 2048,
max_tokens: Some(2048),
..Default::default()
},
);
Expand Down
8 changes: 2 additions & 6 deletions crates/aionui-api-types/src/agent_build_extra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ pub struct AionrsBuildExtra {
pub preset_rules: Option<String>,
#[serde(default)]
pub skills: Vec<String>,
#[serde(default = "default_aionrs_max_tokens")]
pub max_tokens: u32,
#[serde(default)]
pub max_tokens: Option<u32>,
#[serde(default)]
pub max_turns: Option<usize>,
#[serde(default)]
Expand All @@ -106,10 +106,6 @@ pub struct AionrsBuildExtra {
pub user_id: Option<String>,
}

fn default_aionrs_max_tokens() -> u32 {
8192
}

/// ACP model information returned by the ACP backend.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AcpModelInfo {
Expand Down
Loading