feat: add Brazilian Portuguese locale and configurable token pricing

Enable Portuguese-speaking users with full pt-BR translations and let users
set per-million token rates so home cost estimates reflect their actual pricing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Usuario Exemplo
2026-09-14 18:47:23 -03:00
co-authored by Cursor
parent 3b37c33607
commit 0ce64e20ba
16 changed files with 1133 additions and 176 deletions
+4
View File
@@ -216,6 +216,10 @@ pub fn api_router(service: ControlService) -> Router {
"/__byok-api__/api/settings/commit",
get(settings::get_commit).put(settings::update_commit),
)
.route(
"/__byok-api__/api/settings/pricing",
get(settings::get_pricing_settings).put(settings::update_pricing_settings),
)
.route(
"/__byok-api__/api/harness/cursor/status",
get(harness::status),
+12 -1
View File
@@ -29,7 +29,7 @@ use crate::{
provider::{is_valid_response_event, ModelEvent, Provider},
store::{
CommitSettings, DesktopSettings, PortSettings, ProxySettings, ProxySettingsInput,
StatisticsStorage, Store, TabSettings,
StatisticsStorage, Store, TabSettings, TokenPricingSettings,
},
Error, Result,
};
@@ -748,6 +748,17 @@ impl ControlService {
pub async fn set_commit_settings(&self, settings: CommitSettings) -> Result<CommitSettings> {
self.store.set_commit_settings(settings).await
}
pub async fn pricing_settings(&self) -> Result<TokenPricingSettings> {
self.store.pricing_settings().await
}
pub async fn set_pricing_settings(
&self,
settings: TokenPricingSettings,
) -> Result<TokenPricingSettings> {
self.store.set_pricing_settings(settings).await
}
}
fn official_call(trace: CursorRunTraceSummary) -> CallSummary {
+14
View File
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
use crate::store::{
CommitPromptLocale, CommitSettings, DesktopSettings, PortSettings, ProxySettings,
ProxySettingsInput, StatisticsStorage, StatisticsStorageScope, TabSettings,
TokenPricingSettings,
};
use super::{ControlService, ObservabilitySettings};
@@ -134,6 +135,19 @@ pub async fn update_commit(
Ok(Json(CommitSettingsView::new(saved, default_locale)))
}
pub async fn get_pricing_settings(
State(service): State<ControlService>,
) -> Result<Json<TokenPricingSettings>> {
Ok(Json(service.pricing_settings().await?))
}
pub async fn update_pricing_settings(
State(service): State<ControlService>,
Json(settings): Json<TokenPricingSettings>,
) -> Result<Json<TokenPricingSettings>> {
Ok(Json(service.set_pricing_settings(settings).await?))
}
fn requested_commit_locale(headers: &HeaderMap) -> CommitPromptLocale {
match headers
.get(header::ACCEPT_LANGUAGE)
+74 -2
View File
@@ -12,6 +12,7 @@ const INSTALLATION_ID_KEY: &str = "installation_id";
const DESKTOP_SETTINGS_KEY: &str = "desktop_lifecycle";
const COMMIT_SETTINGS_KEY: &str = "commit_settings";
const CURSOR_TAKEOVER_ENABLED_KEY: &str = "cursor_takeover_enabled";
const PRICING_SETTINGS_KEY: &str = "token_pricing";
/// Embedded default system prompts for commit message generation.
pub const DEFAULT_COMMIT_PROMPT_ZH_CN: &str = include_str!("../../prompt/cursor/commit/zh-CN.md");
@@ -25,6 +26,25 @@ pub struct PortSettings {
pub service_port: u16,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct TokenPricingSettings {
pub input_per_million: f64,
pub output_per_million: f64,
pub cache_read_per_million: f64,
pub cache_write_per_million: f64,
}
impl Default for TokenPricingSettings {
fn default() -> Self {
Self {
input_per_million: 5.0,
output_per_million: 25.0,
cache_read_per_million: 0.5,
cache_write_per_million: 6.25,
}
}
}
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ProxyMode {
@@ -426,14 +446,43 @@ impl Store {
.await?;
Ok(settings)
}
pub async fn pricing_settings(&self) -> Result<TokenPricingSettings> {
let value = sqlx::query_scalar::<_, String>(
"SELECT value_json FROM service_settings WHERE setting_key = ?",
)
.bind(PRICING_SETTINGS_KEY)
.fetch_optional(&self.pool)
.await?;
value
.map(|value| serde_json::from_str(&value).map_err(Into::into))
.unwrap_or_else(|| Ok(TokenPricingSettings::default()))
}
pub async fn set_pricing_settings(
&self,
settings: TokenPricingSettings,
) -> Result<TokenPricingSettings> {
let value_json = serde_json::to_string(&settings)?;
let _write = self.writes.lock().await;
sqlx::query(
"INSERT INTO service_settings(setting_key, value_json, updated_at_ms) VALUES (?, ?, ?) ON CONFLICT(setting_key) DO UPDATE SET value_json = excluded.value_json, updated_at_ms = excluded.updated_at_ms",
)
.bind(PRICING_SETTINGS_KEY)
.bind(value_json)
.bind(now_ms())
.execute(&self.pool)
.await?;
Ok(settings)
}
}
#[cfg(test)]
mod tests {
use super::{
read_proxy_settings, CommitPromptLocale, CommitSettings, ProxyMode, ProxySettingsInput,
ProxySettingsSecret, Store, DEFAULT_COMMIT_PROMPT_EN_US, DEFAULT_COMMIT_PROMPT_ZH_CN,
PROXY_SETTINGS_KEY,
ProxySettingsSecret, Store, TokenPricingSettings, DEFAULT_COMMIT_PROMPT_EN_US,
DEFAULT_COMMIT_PROMPT_ZH_CN, PROXY_SETTINGS_KEY,
};
/// The `outbound_proxy` row exactly as builds before the `system` -> `default`
@@ -525,4 +574,27 @@ mod tests {
assert_eq!(saved.mode, ProxyMode::Custom);
assert_eq!(saved.address, "http://127.0.0.1:7890");
}
#[tokio::test]
async fn token_pricing_settings_persists_and_reads_back() {
let directory = tempfile::tempdir().unwrap();
let url = format!("sqlite://{}", directory.path().join("test.db").display());
let store = Store::connect(&url).await.unwrap();
assert_eq!(
store.pricing_settings().await.unwrap(),
TokenPricingSettings::default()
);
let custom = TokenPricingSettings {
input_per_million: 3.0,
output_per_million: 15.0,
cache_read_per_million: 0.3,
cache_write_per_million: 3.75,
};
let saved = store.set_pricing_settings(custom).await.unwrap();
assert_eq!(saved, custom);
assert_eq!(store.pricing_settings().await.unwrap(), custom);
}
}