mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-10-03 18:23:51 +08:00
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:
co-authored by
Cursor
parent
3b37c33607
commit
0ce64e20ba
@@ -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),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user