mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-27 08:00:17 +00:00
refactor: simplify config resolution and consolidate main.rs init (#287)
* refactor: simplify config resolution and consolidate main.rs init into AppBuilder - Add parse_bool_env() and parse_string_env() helpers to eliminate repetitive 5-line optional_env/parse/map_err/unwrap_or boilerplate across 12 config files - Add EmbeddingsConfig::create_provider() to centralize embeddings construction (fixes hardcoded 1536 dimensions and missing Ollama provider in app.rs) - Extract init_cli_tracing(), setup_wasm_channels(), start_tunnel(), run_memory_command(), run_worker(), run_claude_bridge() from main.rs - Replace ~600 lines of inline init in main.rs with AppBuilder::build_all() - Expose catalog_entries from AppComponents for gateway registry entries - Net reduction: ~738 lines across 15 files Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: propagate dev_loaded_tool_names from AppBuilder and add parse_option_env helper Address PR review feedback: - Capture dev_loaded_tool_names from WASM loading in init_extensions() and expose via AppComponents so bootstrap_hooks receives the actual dev tool names instead of an empty slice (fixes silent hook skip) - Add parse_option_env<T>() helper for Option<T> config fields, simplifying max_cost_per_day_cents and max_actions_per_hour in agent.rs Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: fetch real NEAR AI pricing and unify cost calculation path CostGuard was independently looking up pricing via costs::model_cost(), falling back to GPT-4o default rates when NEAR AI model names didn't match the static table — causing ~3x cost overestimates in logs. - Add pricing map to NearAiChatProvider that fetches real rates from /v1/model/list at startup (background, non-blocking) - Update cost_per_token() to check fetched pricing first, then static table, then default - Add cost_per_token parameter to CostGuard::record_llm_call() so the dispatcher passes provider-sourced rates directly Co-Authored-By: Claude Opus 4.6 <[email protected]> * chore: update default NEAR AI model to GLM-latest Replace fireworks llama4-maverick-instruct-basic with zai-org/GLM-latest as the default model in config and setup wizard. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: align wizard default model name with config Change "zai/GLM-latest" to "zai-org/GLM-latest" in wizard.rs to match the default in config/llm.rs. Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
91b602790a
commit
c3ce26278a
+18
-11
@@ -151,14 +151,19 @@ impl CostGuard {
|
||||
/// Record a completed LLM action: its token costs and the action timestamp.
|
||||
///
|
||||
/// Call this AFTER an LLM call completes so that costs are tracked.
|
||||
///
|
||||
/// When `cost_per_token` is `Some`, those rates are used directly (provider-
|
||||
/// sourced pricing). When `None`, falls back to the static `costs::model_cost`
|
||||
/// lookup table, then `costs::default_cost`.
|
||||
pub async fn record_llm_call(
|
||||
&self,
|
||||
model: &str,
|
||||
input_tokens: u32,
|
||||
output_tokens: u32,
|
||||
cost_per_token: Option<(Decimal, Decimal)>,
|
||||
) -> Decimal {
|
||||
let (input_rate, output_rate) =
|
||||
costs::model_cost(model).unwrap_or_else(costs::default_cost);
|
||||
let (input_rate, output_rate) = cost_per_token
|
||||
.unwrap_or_else(|| costs::model_cost(model).unwrap_or_else(costs::default_cost));
|
||||
let cost =
|
||||
input_rate * Decimal::from(input_tokens) + output_rate * Decimal::from(output_tokens);
|
||||
|
||||
@@ -261,7 +266,9 @@ mod tests {
|
||||
assert!(guard.check_allowed().await.is_ok());
|
||||
|
||||
// Record a big call, still allowed
|
||||
guard.record_llm_call("gpt-4o", 100_000, 100_000).await;
|
||||
guard
|
||||
.record_llm_call("gpt-4o", 100_000, 100_000, None)
|
||||
.await;
|
||||
assert!(guard.check_allowed().await.is_ok());
|
||||
}
|
||||
|
||||
@@ -278,7 +285,7 @@ mod tests {
|
||||
// Record a call that costs more than $0.01
|
||||
// gpt-4o: input=$0.0000025/tok, output=$0.00001/tok
|
||||
// 10000 input + 10000 output = $0.025 + $0.10 = $0.125
|
||||
guard.record_llm_call("gpt-4o", 10_000, 10_000).await;
|
||||
guard.record_llm_call("gpt-4o", 10_000, 10_000, None).await;
|
||||
|
||||
// Now should be blocked
|
||||
let result = guard.check_allowed().await;
|
||||
@@ -301,7 +308,7 @@ mod tests {
|
||||
// First 3 actions allowed
|
||||
for _ in 0..3 {
|
||||
assert!(guard.check_allowed().await.is_ok());
|
||||
guard.record_llm_call("gpt-4o", 10, 10).await;
|
||||
guard.record_llm_call("gpt-4o", 10, 10, None).await;
|
||||
}
|
||||
|
||||
// 4th should be blocked
|
||||
@@ -322,7 +329,7 @@ mod tests {
|
||||
|
||||
assert_eq!(guard.daily_spend().await, Decimal::ZERO);
|
||||
|
||||
let cost = guard.record_llm_call("gpt-4o", 1000, 500).await;
|
||||
let cost = guard.record_llm_call("gpt-4o", 1000, 500, None).await;
|
||||
assert!(cost > Decimal::ZERO);
|
||||
assert_eq!(guard.daily_spend().await, cost);
|
||||
}
|
||||
@@ -333,8 +340,8 @@ mod tests {
|
||||
|
||||
assert_eq!(guard.actions_this_hour().await, 0);
|
||||
|
||||
guard.record_llm_call("gpt-4o", 10, 10).await;
|
||||
guard.record_llm_call("gpt-4o", 10, 10).await;
|
||||
guard.record_llm_call("gpt-4o", 10, 10, None).await;
|
||||
guard.record_llm_call("gpt-4o", 10, 10, None).await;
|
||||
|
||||
assert_eq!(guard.actions_this_hour().await, 2);
|
||||
}
|
||||
@@ -371,10 +378,10 @@ mod tests {
|
||||
assert!(guard.model_usage().await.is_empty());
|
||||
|
||||
// Record calls for two different models
|
||||
guard.record_llm_call("gpt-4o", 1000, 500).await;
|
||||
guard.record_llm_call("gpt-4o", 2000, 1000).await;
|
||||
guard.record_llm_call("gpt-4o", 1000, 500, None).await;
|
||||
guard.record_llm_call("gpt-4o", 2000, 1000, None).await;
|
||||
guard
|
||||
.record_llm_call("claude-3-5-sonnet-20241022", 500, 200)
|
||||
.record_llm_call("claude-3-5-sonnet-20241022", 500, 200, None)
|
||||
.await;
|
||||
|
||||
let usage = guard.model_usage().await;
|
||||
|
||||
@@ -222,6 +222,7 @@ impl Agent {
|
||||
&model_name,
|
||||
output.usage.input_tokens,
|
||||
output.usage.output_tokens,
|
||||
Some(self.llm().cost_per_token()),
|
||||
)
|
||||
.await;
|
||||
tracing::debug!(
|
||||
|
||||
Reference in New Issue
Block a user