From ea0f1e6694d0d0982788dd38580cf727f3bc39b6 Mon Sep 17 00:00:00 2001 From: Tushar Date: Wed, 8 Apr 2026 13:38:26 +0530 Subject: [PATCH 1/4] feat(config): add currency symbol and conversion rate to rprompt --- crates/forge_config/src/config.rs | 11 +++++++++++ crates/forge_main/src/ui.rs | 16 ++-------------- crates/forge_main/src/zsh/rprompt.rs | 17 +++++++++++++++++ forge.schema.json | 18 ++++++++++++++++++ 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/crates/forge_config/src/config.rs b/crates/forge_config/src/config.rs index 0f189de0e3..d29f31911f 100644 --- a/crates/forge_config/src/config.rs +++ b/crates/forge_config/src/config.rs @@ -265,6 +265,17 @@ pub struct ForgeConfig { /// selection. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub providers: Vec, + + /// Currency symbol displayed in the shell rprompt next to the session cost + /// (e.g. `"$"`, `"€"`, `"₹"`). Defaults to `"$"` when absent. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub currency_symbol: Option, + + /// Conversion rate applied to costs before display in the shell rprompt. + /// The raw USD cost is multiplied by this value, allowing costs to be shown + /// in a local currency. Defaults to `1.0` (no conversion) when absent. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub currency_conversion_rate: Option, } impl ForgeConfig { diff --git a/crates/forge_main/src/ui.rs b/crates/forge_main/src/ui.rs index 08aa510f53..91ae491444 100644 --- a/crates/forge_main/src/ui.rs +++ b/crates/forge_main/src/ui.rs @@ -3821,17 +3821,7 @@ impl A + Send + Sync> UI .map(|val| val == "1") .unwrap_or(true); // Default to true - // Get currency symbol from environment variable, default to "$" - let currency_symbol = - std::env::var("FORGE_CURRENCY_SYMBOL").unwrap_or_else(|_| "$".to_string()); - - // Get conversion ratio from environment variable, default to 1.0 - let conversion_ratio = std::env::var("FORGE_CURRENCY_CONVERSION_RATE") - .ok() - .and_then(|val| val.parse::().ok()) - .unwrap_or(1.0); - - let rprompt = ZshRPrompt::default() + let rprompt = ZshRPrompt::from_config(&self.config) .agent( std::env::var("_FORGE_ACTIVE_AGENT") .ok() @@ -3841,9 +3831,7 @@ impl A + Send + Sync> UI .model(model_id) .token_count(conversation.and_then(|conversation| conversation.token_count())) .cost(cost) - .use_nerd_font(use_nerd_font) - .currency_symbol(currency_symbol) - .conversion_ratio(conversion_ratio); + .use_nerd_font(use_nerd_font); Some(rprompt.to_string()) } diff --git a/crates/forge_main/src/zsh/rprompt.rs b/crates/forge_main/src/zsh/rprompt.rs index 6e01059302..7927d14752 100644 --- a/crates/forge_main/src/zsh/rprompt.rs +++ b/crates/forge_main/src/zsh/rprompt.rs @@ -7,6 +7,7 @@ use std::fmt::{self, Display}; use convert_case::{Case, Casing}; use derive_setters::Setters; +use forge_config::ForgeConfig; use forge_domain::{AgentId, ModelId, TokenCount}; use super::style::{ZshColor, ZshStyle}; @@ -34,6 +35,22 @@ pub struct ZshRPrompt { /// Defaults to 1.0. conversion_ratio: f64, } +impl ZshRPrompt { + /// Constructs a [`ZshRPrompt`] with currency settings populated from the + /// provided [`ForgeConfig`]. Fields absent from the config fall back to + /// the struct's defaults. + pub fn from_config(config: &ForgeConfig) -> Self { + let mut rprompt = Self::default(); + if let Some(ref symbol) = config.currency_symbol { + rprompt = rprompt.currency_symbol(symbol.clone()); + } + if let Some(rate) = config.currency_conversion_rate { + rprompt = rprompt.conversion_ratio(rate.value()); + } + rprompt + } +} + impl Default for ZshRPrompt { fn default() -> Self { Self { diff --git a/forge.schema.json b/forge.schema.json index f925ff6a5f..da4f63bc71 100644 --- a/forge.schema.json +++ b/forge.schema.json @@ -42,6 +42,24 @@ } ] }, + "currency_conversion_rate": { + "description": "Conversion rate applied to costs before display in the shell rprompt.\nThe raw USD cost is multiplied by this value, allowing costs to be shown\nin a local currency. Defaults to `1.0` (no conversion) when absent.", + "anyOf": [ + { + "$ref": "#/$defs/double" + }, + { + "type": "null" + } + ] + }, + "currency_symbol": { + "description": "Currency symbol displayed in the shell rprompt next to the session cost\n(e.g. `\"$\"`, `\"€\"`, `\"₹\"`). Defaults to `\"$\"` when absent.", + "type": [ + "string", + "null" + ] + }, "custom_history_path": { "description": "Path to the conversation history file; defaults to the global history\nlocation when absent.", "type": [ From defbf8394db067015d5c7cae3344b21a79c326b0 Mon Sep 17 00:00:00 2001 From: Tushar Date: Wed, 8 Apr 2026 15:07:14 +0530 Subject: [PATCH 2/4] chore(config): remove forge.default.yaml model defaults --- forge.default.yaml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 forge.default.yaml diff --git a/forge.default.yaml b/forge.default.yaml deleted file mode 100644 index b311bbd4e8..0000000000 --- a/forge.default.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# yaml-language-server: $schema=./forge.schema.json -variables: - operating_agent: Forge - # Define model anchors with simpler, purpose-based names - advanced_model: &advanced_model anthropic/claude-sonnet-4 - -max_requests_per_turn: 100 -max_tool_failure_per_turn: 3 -top_p: 0.8 -top_k: 30 -max_tokens: 20480 -max_walker_depth: 1 -tool_supported: true - -# Global compact configuration applied to all agents -compact: - max_tokens: 2000 - token_threshold: 100000 - retention_window: 6 - message_threshold: 200 - eviction_window: 0.2 - on_turn_end: false - -updates: - frequency: "daily" - auto_update: false -model: *advanced_model From 7e9d313fe65889a78360c7f29e5bd2b6cbf824f7 Mon Sep 17 00:00:00 2001 From: Tushar Date: Wed, 8 Apr 2026 15:08:17 +0530 Subject: [PATCH 3/4] feat(config): add required currency symbol and conversion rate --- crates/forge_config/.forge.toml | 3 +++ crates/forge_config/src/config.rs | 12 ++++++------ crates/forge_main/src/zsh/rprompt.rs | 14 ++++---------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/crates/forge_config/.forge.toml b/crates/forge_config/.forge.toml index f807226064..930fae6bb0 100644 --- a/crates/forge_config/.forge.toml +++ b/crates/forge_config/.forge.toml @@ -64,3 +64,6 @@ frequency = "daily" [reasoning] enabled = true effort = "high" + +currency_symbol = "$" +currency_conversion_rate = 1.0 diff --git a/crates/forge_config/src/config.rs b/crates/forge_config/src/config.rs index d29f31911f..f705d308c3 100644 --- a/crates/forge_config/src/config.rs +++ b/crates/forge_config/src/config.rs @@ -267,15 +267,15 @@ pub struct ForgeConfig { pub providers: Vec, /// Currency symbol displayed in the shell rprompt next to the session cost - /// (e.g. `"$"`, `"€"`, `"₹"`). Defaults to `"$"` when absent. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub currency_symbol: Option, + /// (e.g. `"$"`, `"€"`, `"₹"`). Defaults to `"$"`. + #[serde(default)] + pub currency_symbol: String, /// Conversion rate applied to costs before display in the shell rprompt. /// The raw USD cost is multiplied by this value, allowing costs to be shown - /// in a local currency. Defaults to `1.0` (no conversion) when absent. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub currency_conversion_rate: Option, + /// in a local currency. Defaults to `1.0` (no conversion). + #[serde(default)] + pub currency_conversion_rate: Decimal, } impl ForgeConfig { diff --git a/crates/forge_main/src/zsh/rprompt.rs b/crates/forge_main/src/zsh/rprompt.rs index 7927d14752..58cbfd7813 100644 --- a/crates/forge_main/src/zsh/rprompt.rs +++ b/crates/forge_main/src/zsh/rprompt.rs @@ -37,17 +37,11 @@ pub struct ZshRPrompt { } impl ZshRPrompt { /// Constructs a [`ZshRPrompt`] with currency settings populated from the - /// provided [`ForgeConfig`]. Fields absent from the config fall back to - /// the struct's defaults. + /// provided [`ForgeConfig`]. pub fn from_config(config: &ForgeConfig) -> Self { - let mut rprompt = Self::default(); - if let Some(ref symbol) = config.currency_symbol { - rprompt = rprompt.currency_symbol(symbol.clone()); - } - if let Some(rate) = config.currency_conversion_rate { - rprompt = rprompt.conversion_ratio(rate.value()); - } - rprompt + Self::default() + .currency_symbol(config.currency_symbol.clone()) + .conversion_ratio(config.currency_conversion_rate.value()) } } From 67430293e7924b517d80e2bf8dec74e06a108a6f Mon Sep 17 00:00:00 2001 From: Tushar Date: Wed, 8 Apr 2026 15:13:44 +0530 Subject: [PATCH 4/4] feat(config): set defaults for currency conversion rate and symbol --- forge.schema.json | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/forge.schema.json b/forge.schema.json index da4f63bc71..7420e9f736 100644 --- a/forge.schema.json +++ b/forge.schema.json @@ -43,22 +43,14 @@ ] }, "currency_conversion_rate": { - "description": "Conversion rate applied to costs before display in the shell rprompt.\nThe raw USD cost is multiplied by this value, allowing costs to be shown\nin a local currency. Defaults to `1.0` (no conversion) when absent.", - "anyOf": [ - { - "$ref": "#/$defs/double" - }, - { - "type": "null" - } - ] + "description": "Conversion rate applied to costs before display in the shell rprompt.\nThe raw USD cost is multiplied by this value, allowing costs to be shown\nin a local currency. Defaults to `1.0` (no conversion).", + "$ref": "#/$defs/double", + "default": 0.0 }, "currency_symbol": { - "description": "Currency symbol displayed in the shell rprompt next to the session cost\n(e.g. `\"$\"`, `\"€\"`, `\"₹\"`). Defaults to `\"$\"` when absent.", - "type": [ - "string", - "null" - ] + "description": "Currency symbol displayed in the shell rprompt next to the session cost\n(e.g. `\"$\"`, `\"€\"`, `\"₹\"`). Defaults to `\"$\"`.", + "type": "string", + "default": "" }, "custom_history_path": { "description": "Path to the conversation history file; defaults to the global history\nlocation when absent.",