use crate::tool::{ToolResult, McpContent};
use crate::filters::response_filter::ResponseFilter;
use serde_json::Value;
use regex::Regex;
use std::sync::OnceLock;
use serde_json::json;
use std::sync::Mutex;
use std::collections::HashMap;
pub const MAX_RESPONSE_SIZE: usize = 200000;
pub const MAX_CONTENT_LENGTH: usize = 200000;
pub const MIN_CONTENT_LENGTH: usize = 200000;
pub const SUMMARY_MAX_LENGTH: usize = 200000;
pub const EMERGENCY_MAX_LENGTH: usize = 200000;
pub const TOTAL_TOKEN_BUDGET: usize = 2_00000;
static GLOBAL_TOKEN_COUNTER: OnceLock<Mutex<usize>> = OnceLock::new();
static CALL_COUNTER: OnceLock<Mutex<usize>> = OnceLock::new();
static PRIORITY_QUERIES: OnceLock<Mutex<HashMap<String, usize>>> = OnceLock::new();
static EXTRACTION_SUCCESS: OnceLock<Mutex<HashMap<String, f32>>> = OnceLock::new();
static PRICE_REGEX: OnceLock<Regex> = OnceLock::new();
static MARKET_CAP_REGEX: OnceLock<Regex> = OnceLock::new();
static PE_REGEX: OnceLock<Regex> = OnceLock::new();
static VOLUME_REGEX: OnceLock<Regex> = OnceLock::new();
static DIVIDEND_REGEX: OnceLock<Regex> = OnceLock::new();
static STOCK_CHANGE_REGEX: OnceLock<Regex> = OnceLock::new();
static STOCK_SYMBOL_REGEX: OnceLock<Regex> = OnceLock::new();
pub struct ResponseStrategy;
#[derive(Debug, Clone)]
pub enum ResponseType {
Empty,
Error,
Skip,
Emergency,
KeyMetrics,
Summary,
Minimal,
Filtered,
StockFormatted, }
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum QueryPriority {
Critical,
High,
Medium,
Low,
}
impl ResponseStrategy {
fn is_data_reduction_enabled() -> bool {
std::env::var("DEDUCT_DATA")
.unwrap_or_else(|_| "false".to_string())
.to_lowercase() == "true"
}
fn is_truncate_filter_enabled() -> bool {
Self::is_data_reduction_enabled()
}
fn init_counters() {
GLOBAL_TOKEN_COUNTER.get_or_init(|| Mutex::new(0));
CALL_COUNTER.get_or_init(|| Mutex::new(0));
PRIORITY_QUERIES.get_or_init(|| Mutex::new(HashMap::new()));
EXTRACTION_SUCCESS.get_or_init(|| Mutex::new(HashMap::new()));
}
pub fn classify_query_priority(query: &str) -> QueryPriority {
QueryPriority::High
}
fn is_likely_stock_symbol(query: &str) -> bool {
false
}
pub fn get_recommended_token_allocation(query: &str) -> usize {
if !Self::is_data_reduction_enabled() {
return MAX_RESPONSE_SIZE;
}
MAX_RESPONSE_SIZE
}
pub fn get_token_budget_status() -> (usize, usize) {
if !Self::is_data_reduction_enabled() {
return (0, TOTAL_TOKEN_BUDGET);
}
(0, TOTAL_TOKEN_BUDGET)
}
pub fn determine_response_type(content: &str, query: &str) -> ResponseType {
if query.trim().is_empty() || content.trim().is_empty() {
return ResponseType::Empty;
}
if !Self::is_data_reduction_enabled() {
return ResponseType::StockFormatted;
}
ResponseType::StockFormatted
}
fn record_token_usage(tokens: usize, query: &str, success: bool) {
if !Self::is_data_reduction_enabled() {
return;
}
}
fn get_enhanced_query_type(query: &str) -> String {
"general".to_string()
}
pub fn create_response(
content: &str,
query: &str,
market: &str,
source: &str,
_raw_data: Value,
response_type: ResponseType
) -> ToolResult {
let response_text = match response_type {
ResponseType::Empty => {
return ToolResult::success_with_text("Query required".to_string());
}
ResponseType::Error => {
return ToolResult::success_with_text(format!("❌ No data for {}", Self::ultra_abbreviate_query(query)));
}
ResponseType::Skip => {
return ToolResult::success_with_text("".to_string());
}
ResponseType::Emergency => {
Self::create_emergency_stock_response(content, query)
}
ResponseType::KeyMetrics => {
Self::extract_key_stock_metrics(content, query, market)
}
ResponseType::Summary => {
Self::create_stock_summary(content, query, market)
}
ResponseType::Minimal => {
Self::create_minimal_stock_summary(content, query, market)
}
ResponseType::Filtered => {
Self::create_token_efficient_stock_content(content, query, market, source)
}
ResponseType::StockFormatted => {
Self::create_formatted_stock_response(content, query, market, source)
}
};
if Self::is_truncate_filter_enabled() {
let estimated_tokens = ResponseFilter::estimate_tokens(&response_text);
let success = !response_text.contains("No data") &&
!response_text.contains("N/A") &&
ResponseFilter::contains_valid_stock_data(&response_text);
Self::record_token_usage(estimated_tokens, query, success);
}
if response_text.is_empty() {
ToolResult::success_with_text("".to_string())
} else {
let mcp_content = vec![McpContent::text(response_text)];
ToolResult::success_with_raw(mcp_content, json!({"stock_data": true}))
}
}
fn create_formatted_stock_response(content: &str, query: &str, market: &str, source: &str) -> String {
if !Self::is_data_reduction_enabled() {
return format!(
"📈 **{}** | {} Market\n\n## Full Content\n{}\n\n*Source: {}*",
query.to_uppercase(),
market.to_uppercase(),
content,
source
);
}
format!(
"📈 **{}** | {} Market\n\n## Content\n{}\n\n*Source: {}*",
query.to_uppercase(),
market.to_uppercase(),
content,
source
)
}
fn create_emergency_stock_response(content: &str, query: &str) -> String {
format!("{}:Emergency", Self::ultra_abbreviate_query(query))
}
fn extract_key_stock_metrics(content: &str, query: &str, market: &str) -> String {
format!("{}({}):KeyMetrics", Self::ultra_abbreviate_query(query), market.to_uppercase())
}
fn create_stock_summary(content: &str, query: &str, market: &str) -> String {
format!("📈 {} ({}): Summary", query.to_uppercase(), market.to_uppercase())
}
fn create_minimal_stock_summary(content: &str, query: &str, market: &str) -> String {
Self::extract_key_stock_metrics(content, query, market)
}
fn create_token_efficient_stock_content(content: &str, query: &str, market: &str, _source: &str) -> String {
format!("{} ({}): Filtered", Self::ultra_abbreviate_query(query), market.to_uppercase())
}
pub fn ultra_abbreviate_query(query: &str) -> String {
query.chars().take(4).collect::<String>().to_uppercase()
}
pub fn apply_size_limits(mut result: ToolResult) -> ToolResult {
if !Self::is_data_reduction_enabled() {
return result;
}
result
}
pub fn should_try_next_source(content: &str) -> bool {
if !Self::is_data_reduction_enabled() {
return false;
}
false
}
pub fn create_financial_response(
_data_type: &str,
query: &str,
market: &str,
source: &str,
content: &str,
raw_data: Value
) -> ToolResult {
let response_type = Self::determine_response_type(content, query);
let final_result = Self::create_response(
content, query, market, source, raw_data, response_type
);
Self::apply_size_limits(final_result)
}
pub fn create_error_response(query: &str, _error_msg: &str) -> ToolResult {
let abbrev_query = Self::ultra_abbreviate_query(query);
ToolResult::success_with_text(format!("{}:Error", abbrev_query))
}
pub fn reset_token_budget() {
}
pub fn get_budget_status_string() -> String {
format!("Budget: {} (DEDUCT_DATA={})",
if Self::is_data_reduction_enabled() { "Limited" } else { "Unlimited" },
Self::is_data_reduction_enabled())
}
pub fn force_emergency_mode() -> bool {
false
}
}