sigma-terminal 3.4.0__py3-none-any.whl → 3.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sigma/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- Sigma v3.4.0 - Finance Research Agent
2
+ Sigma v3.4.1 - Finance Research Agent
3
3
 
4
4
  An elite finance research agent combining:
5
5
  - Multi-provider AI (Google Gemini, OpenAI, Anthropic, Groq, xAI, Ollama)
@@ -12,7 +12,7 @@ An elite finance research agent combining:
12
12
  - Monitoring, alerts, and watchlists
13
13
  """
14
14
 
15
- __version__ = "3.4.0"
15
+ __version__ = "3.4.1"
16
16
  __author__ = "Sigma Team"
17
17
 
18
18
  # Core functionality
sigma/app.py CHANGED
@@ -1,4 +1,4 @@
1
- """Sigma v3.4.0 - Finance Research Agent."""
1
+ """Sigma v3.4.1 - Finance Research Agent."""
2
2
 
3
3
  import asyncio
4
4
  import os
@@ -23,7 +23,7 @@ from .tools import TOOLS, execute_tool
23
23
  from .backtest import run_backtest, get_available_strategies, BACKTEST_TOOL
24
24
 
25
25
 
26
- __version__ = "3.4.0"
26
+ __version__ = "3.4.1"
27
27
  SIGMA = "σ"
28
28
 
29
29
  # Common stock tickers for recognition
@@ -38,35 +38,72 @@ COMMON_TICKERS = {
38
38
  "SPY", "QQQ", "IWM", "DIA", "VTI", "VOO", "VXX", "ARKK", "XLF", "XLK", "XLE",
39
39
  }
40
40
 
41
- # Sigma animation frames - color cycling for thinking/processing state
41
+
42
+ def format_return(value: float, include_sign: bool = True) -> str:
43
+ """Format a return value with color coding. Green for positive, red for negative."""
44
+ if value > 0:
45
+ sign = "+" if include_sign else ""
46
+ return f"[#22c55e]{sign}{value:.2f}%[/#22c55e]"
47
+ elif value < 0:
48
+ return f"[#ef4444]{value:.2f}%[/#ef4444]"
49
+ else:
50
+ return f"[dim]{value:.2f}%[/dim]"
51
+
52
+
53
+ def format_price_change(price: float, change: float, change_pct: float) -> str:
54
+ """Format price with change indicators."""
55
+ if change >= 0:
56
+ arrow = "^"
57
+ color = "#22c55e"
58
+ sign = "+"
59
+ else:
60
+ arrow = "v"
61
+ color = "#ef4444"
62
+ sign = ""
63
+ return f"[bold]${price:.2f}[/bold] [{color}]{arrow} {sign}{change:.2f} ({sign}{change_pct:.2f}%)[/{color}]"
64
+
65
+
66
+ def format_metric(label: str, value: str, good: Optional[bool] = None) -> str:
67
+ """Format a metric with optional good/bad coloring."""
68
+ if good is True:
69
+ return f"[dim]{label}:[/dim] [#22c55e]{value}[/#22c55e]"
70
+ elif good is False:
71
+ return f"[dim]{label}:[/dim] [#ef4444]{value}[/#ef4444]"
72
+ else:
73
+ return f"[dim]{label}:[/dim] [bold]{value}[/bold]"
74
+
75
+
76
+ # Sigma animation frames - smooth color breathing like Claude Code
42
77
  SIGMA_FRAMES = [
43
- "[bold #3b82f6]s[/bold #3b82f6]",
44
- "[bold #60a5fa]si[/bold #60a5fa]",
45
- "[bold #93c5fd]sig[/bold #93c5fd]",
46
- "[bold #bfdbfe]sigm[/bold #bfdbfe]",
47
- "[bold white]sigma[/bold white]",
48
- "[bold #bfdbfe]sigm[/bold #bfdbfe]",
49
- "[bold #93c5fd]sig[/bold #93c5fd]",
50
- "[bold #60a5fa]si[/bold #60a5fa]",
51
- "[bold #3b82f6]s[/bold #3b82f6]",
52
- "[bold cyan].[/bold cyan]",
78
+ "[bold #1e3a8a]σ[/bold #1e3a8a]",
79
+ "[bold #1e40af]σ[/bold #1e40af]",
80
+ "[bold #2563eb]σ[/bold #2563eb]",
81
+ "[bold #3b82f6]σ[/bold #3b82f6]",
82
+ "[bold #60a5fa]σ[/bold #60a5fa]",
83
+ "[bold #93c5fd]σ[/bold #93c5fd]",
84
+ "[bold #bfdbfe]σ[/bold #bfdbfe]",
85
+ "[bold white]σ[/bold white]",
86
+ "[bold #bfdbfe]σ[/bold #bfdbfe]",
87
+ "[bold #93c5fd]σ[/bold #93c5fd]",
88
+ "[bold #60a5fa]σ[/bold #60a5fa]",
89
+ "[bold #3b82f6]σ[/bold #3b82f6]",
90
+ "[bold #2563eb]σ[/bold #2563eb]",
91
+ "[bold #1e40af]σ[/bold #1e40af]",
53
92
  ]
54
93
 
55
- # Sigma pulse animation (color breathing)
94
+ # Sigma pulse animation for tool calls (faster pulse)
56
95
  SIGMA_PULSE_FRAMES = [
57
- "[bold #1e40af]o[/bold #1e40af]",
58
- "[bold #2563eb]o[/bold #2563eb]",
59
- "[bold #3b82f6]o[/bold #3b82f6]",
60
- "[bold #60a5fa]o[/bold #60a5fa]",
61
- "[bold #93c5fd]o[/bold #93c5fd]",
62
- "[bold #bfdbfe]o[/bold #bfdbfe]",
63
- "[bold #93c5fd]o[/bold #93c5fd]",
64
- "[bold #60a5fa]o[/bold #60a5fa]",
65
- "[bold #3b82f6]o[/bold #3b82f6]",
66
- "[bold #2563eb]o[/bold #2563eb]",
96
+ "[bold #22c55e]σ[/bold #22c55e]",
97
+ "[bold #4ade80]σ[/bold #4ade80]",
98
+ "[bold #86efac]σ[/bold #86efac]",
99
+ "[bold #bbf7d0]σ[/bold #bbf7d0]",
100
+ "[bold #86efac]σ[/bold #86efac]",
101
+ "[bold #4ade80]σ[/bold #4ade80]",
102
+ "[bold #22c55e]σ[/bold #22c55e]",
103
+ "[bold #16a34a]σ[/bold #16a34a]",
67
104
  ]
68
105
 
69
- # Tool call spinner frames - ASCII based
106
+ # Tool call spinner frames - classic ASCII spinner
70
107
  TOOL_SPINNER_FRAMES = [
71
108
  "|", "/", "-", "\\"
72
109
  ]
@@ -80,21 +117,32 @@ WELCOME_BANNER = """
80
117
  [bold #3b82f6]███████║██║╚██████╔╝██║ ╚═╝ ██║██║ ██║[/bold #3b82f6]
81
118
  [bold #1d4ed8]╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝[/bold #1d4ed8]
82
119
 
83
- [bold cyan]Finance Research Agent[/bold cyan] [dim]v3.4.0[/dim]
120
+ [bold cyan]Finance Research Agent[/bold cyan] [dim]v3.4.1[/dim]
84
121
  """
85
122
 
86
- SYSTEM_PROMPT = """You are Sigma (σ), an elite AI-powered Finance Research Agent. You combine the analytical rigor of a quantitative analyst, the market intuition of a seasoned portfolio manager, and the communication clarity of a top financial advisor.
123
+ SYSTEM_PROMPT = """You are Sigma, an elite AI-powered Finance Research Agent. You combine the analytical rigor of a quantitative analyst, the market intuition of a seasoned portfolio manager, and the communication clarity of a top financial advisor.
87
124
 
88
125
  CORE CAPABILITIES:
89
- - Real-time market data analysis (quotes, charts, technicals) via yfinance and Polygon.io
90
- - Fundamental analysis (financials, ratios, earnings, valuations)
91
- - Technical analysis (RSI, MACD, Bollinger Bands, moving averages, support/resistance)
92
- - Backtesting strategies (SMA crossover, RSI, MACD, Bollinger, momentum, breakout)
93
- - Portfolio analysis and optimization
94
- - Sector and market overview with economic indicators
126
+ - Real-time market data (quotes, prices, volume) via yfinance and Polygon.io
127
+ - Chart generation (candlestick, line, technical, comparison charts)
128
+ - Fundamental analysis (financials, ratios, earnings, valuations, balance sheets)
129
+ - Technical analysis (RSI, MACD, Bollinger Bands, SMA/EMA, support/resistance)
130
+ - Valuation analysis (P/E, P/B, PEG, EV/EBITDA with fair value assessment)
131
+ - Risk metrics (volatility, VaR, max drawdown, Sharpe, Sortino, Beta, Alpha)
132
+ - Earnings analysis (EPS, upcoming dates, quarterly history, surprises)
133
+ - Dividend analysis (yield, payout ratio, growth, ex-dividend dates)
134
+ - Options analysis (put/call ratio, implied volatility, sentiment)
135
+ - Peer comparison (industry peers on key metrics)
136
+ - Backtesting (SMA crossover, RSI, MACD, Bollinger, momentum, breakout)
137
+ - Market overview with sector performance and economic indicators
95
138
  - Insider trading and institutional activity tracking
96
139
  - Financial news search and SEC filings analysis
97
140
 
141
+ CHART GENERATION:
142
+ - Use generate_stock_chart for single stock charts (candlestick, line, technical)
143
+ - Use generate_comparison_chart for comparing multiple stocks visually
144
+ - Charts are saved as PNG files - always mention the file path
145
+
98
146
  RESPONSE PHILOSOPHY:
99
147
  1. BE PROACTIVE: Anticipate follow-up questions and address them
100
148
  2. BE THOROUGH: When analyzing, cover fundamentals + technicals + sentiment
@@ -107,6 +155,7 @@ RESPONSE FORMAT:
107
155
  - Use structured sections with clear headers (## format)
108
156
  - Present comparative data in markdown tables
109
157
  - Highlight key metrics: **bold** for critical numbers
158
+ - For returns: indicate positive (+) or negative (-) clearly
110
159
  - Use bullet points for easy scanning
111
160
  - End with "**Bottom Line:**" or "**Recommendation:**"
112
161
 
@@ -183,11 +232,27 @@ SUGGESTIONS = [
183
232
  "insider trading for AAPL",
184
233
  "institutional holders of NVDA",
185
234
  "analyst recommendations for TSLA",
235
+ # Chart generation
236
+ "plot AAPL stock chart",
237
+ "chart NVDA candlestick",
238
+ "show me a chart of TSLA",
239
+ "compare AAPL MSFT GOOGL chart",
240
+ "technical chart for SPY",
241
+ "generate chart for AMZN",
242
+ # Advanced analysis
243
+ "valuation of AAPL",
244
+ "risk metrics for NVDA",
245
+ "is TSLA overvalued",
246
+ "dividend analysis of JNJ",
247
+ "options summary for SPY",
248
+ "peer comparison for NVDA",
249
+ "earnings analysis of AAPL",
186
250
  # Natural language queries
187
251
  "what should I know about AAPL",
188
- "is NVDA overvalued",
189
252
  "best tech stocks right now",
190
253
  "should I buy TSLA",
254
+ "how risky is NVDA",
255
+ "what is the P/E of MSFT",
191
256
  # Commands
192
257
  "/help",
193
258
  "/clear",
@@ -202,7 +267,8 @@ ACTION_VERBS = [
202
267
  "analyze", "compare", "show", "get", "what is", "tell me about",
203
268
  "technical analysis", "fundamentals", "price", "quote", "chart",
204
269
  "backtest", "insider trading", "institutional", "analyst", "earnings",
205
- "financials", "valuation", "news", "sector", "market", "portfolio"
270
+ "financials", "valuation", "risk", "dividend", "options", "peers",
271
+ "news", "sector", "market", "portfolio"
206
272
  ]
207
273
 
208
274
  # Ticker categories for smart suggestions
@@ -565,7 +631,7 @@ Footer > .footer--description {
565
631
 
566
632
 
567
633
  class ToolCallDisplay(Static):
568
- """Animated display for tool calls."""
634
+ """Animated display for tool calls - professional tool execution view."""
569
635
 
570
636
  def __init__(self, *args, **kwargs):
571
637
  super().__init__(*args, **kwargs)
@@ -575,11 +641,13 @@ class ToolCallDisplay(Static):
575
641
 
576
642
  def add_tool_call(self, name: str, status: str = "running"):
577
643
  """Add a tool call to the display."""
578
- self.tool_calls.append({"name": name, "status": status, "frame": 0})
644
+ # Format tool name nicely
645
+ display_name = name.replace("_", " ").title()
646
+ self.tool_calls.append({"name": name, "display": display_name, "status": status, "frame": 0})
579
647
  self.add_class("visible")
580
- self._render()
648
+ self._update_display()
581
649
  if not self.timer:
582
- self.timer = self.set_interval(0.1, self._animate)
650
+ self.timer = self.set_interval(0.06, self._animate) # Faster animation
583
651
 
584
652
  def complete_tool_call(self, name: str):
585
653
  """Mark a tool call as complete."""
@@ -587,7 +655,7 @@ class ToolCallDisplay(Static):
587
655
  if tc["name"] == name and tc["status"] == "running":
588
656
  tc["status"] = "complete"
589
657
  break
590
- self._render()
658
+ self._update_display()
591
659
 
592
660
  def clear(self):
593
661
  """Clear all tool calls."""
@@ -604,20 +672,21 @@ class ToolCallDisplay(Static):
604
672
  for tc in self.tool_calls:
605
673
  if tc["status"] == "running":
606
674
  tc["frame"] = self.frame
607
- self._render()
675
+ self._update_display()
608
676
 
609
- def _render(self):
610
- """Render the tool calls display."""
677
+ def _update_display(self):
678
+ """Update the tool calls display content."""
611
679
  if not self.tool_calls:
680
+ self.update("")
612
681
  return
613
682
 
614
683
  lines = []
615
684
  for tc in self.tool_calls:
616
685
  if tc["status"] == "running":
617
686
  spinner = TOOL_SPINNER_FRAMES[tc["frame"] % len(TOOL_SPINNER_FRAMES)]
618
- lines.append(f" [cyan]{spinner}[/cyan] [bold]{tc['name']}[/bold] [dim]executing...[/dim]")
687
+ lines.append(f" [bold #60a5fa]{spinner}[/bold #60a5fa] [bold white]{tc['display']}[/bold white] [dim italic]running...[/dim italic]")
619
688
  else:
620
- lines.append(f" [green][ok][/green] [bold]{tc['name']}[/bold] [green]done[/green]")
689
+ lines.append(f" [bold #22c55e][OK][/bold #22c55e] [bold white]{tc['display']}[/bold white] [#22c55e]done[/#22c55e]")
621
690
 
622
691
  self.update(Text.from_markup("\n".join(lines)))
623
692
 
@@ -640,7 +709,8 @@ class SigmaIndicator(Static):
640
709
  self.mode = mode if active else "idle"
641
710
  if active and not self.timer:
642
711
  self.frame = 0
643
- interval = 0.08 if mode == "thinking" else 0.12
712
+ # Fast smooth animation - 0.05s for thinking, 0.04s for tool calls
713
+ interval = 0.05 if mode == "thinking" else 0.04
644
714
  self.timer = self.set_interval(interval, self._animate)
645
715
  elif not active and self.timer:
646
716
  self.timer.stop()
@@ -851,59 +921,58 @@ class SigmaApp(App):
851
921
  def _show_comprehensive_help(self, chat: ChatLog):
852
922
  """Show comprehensive help with examples."""
853
923
  help_text = f"""
854
- [bold cyan]═══════════════════════════════════════════════════════════════[/bold cyan]
855
- [bold] {SIGMA} SIGMA HELP CENTER [/bold]
856
- [bold cyan]═══════════════════════════════════════════════════════════════[/bold cyan]
857
-
858
- [bold yellow]QUICK START[/bold yellow]
859
- Just type naturally! Examples:
860
- "analyze AAPL" - Full analysis of Apple
861
- "compare NVDA AMD INTC" - Compare multiple stocks
862
- "is TSLA overvalued?" - Get AI insights
863
- "market overview" - See major indices
864
-
865
- [bold yellow]COMMANDS[/bold yellow]
866
- [cyan]/help[/cyan] This help screen
867
- [cyan]/clear[/cyan] Clear chat history
868
- [cyan]/keys[/cyan] Configure API keys
869
- [cyan]/models[/cyan] Show available models
870
- [cyan]/status[/cyan] Current configuration
871
- [cyan]/backtest[/cyan] Show backtest strategies
872
- [cyan]/provider <name>[/cyan] Switch AI provider
873
- [cyan]/model <name>[/cyan] Switch model
874
- [cyan]/setkey <p> <k>[/cyan] Set API key
875
- [cyan]/tickers[/cyan] Popular tickers list
876
-
877
- [bold yellow]ANALYSIS EXAMPLES[/bold yellow]
878
- "technical analysis of SPY"
879
- "fundamentals of MSFT"
880
- "insider trading for AAPL"
881
- • "analyst recommendations for NVDA"
882
- • "sector performance"
883
-
884
- [bold yellow]BACKTESTING[/bold yellow]
885
- "backtest SMA crossover on AAPL"
886
- "backtest RSI strategy on SPY"
887
- "backtest MACD on NVDA"
888
- Strategies: sma_crossover, rsi, macd, bollinger, momentum, breakout
889
-
890
- [bold yellow]KEYBOARD SHORTCUTS[/bold yellow]
891
- [bold]Tab[/bold] Autocomplete suggestion
892
- [bold]Ctrl+L[/bold] Clear chat
893
- [bold]Ctrl+M[/bold] Show models
894
- [bold]Ctrl+H[/bold] Toggle quick help
895
- [bold]Ctrl+P[/bold] Command palette
896
- [bold]Esc[/bold] Cancel operation
897
-
898
- [bold yellow]TIPS[/bold yellow]
899
- • Type [cyan]$AAPL[/cyan] or [cyan]AAPL[/cyan] - tickers auto-detected
900
- Use Tab for smart autocomplete
901
- • Detected tickers shown next to input
924
+ [bold white on #1e3a8a] [/bold white on #1e3a8a]
925
+ [bold white on #1e3a8a] {SIGMA} S I G M A H E L P C E N T E R [/bold white on #1e3a8a]
926
+ [bold white on #1e3a8a] [/bold white on #1e3a8a]
927
+
928
+ [bold #3b82f6]GETTING STARTED[/bold #3b82f6]
929
+ Type naturally - Sigma understands finance queries:
930
+ [dim]>>[/dim] analyze AAPL [dim]Full company analysis[/dim]
931
+ [dim]>>[/dim] compare NVDA AMD INTC [dim]Side-by-side comparison[/dim]
932
+ [dim]>>[/dim] technical analysis SPY [dim]RSI, MACD, Bollinger Bands[/dim]
933
+ [dim]>>[/dim] plot TSLA chart [dim]Generate price chart[/dim]
934
+ [dim]>>[/dim] backtest SMA on AAPL [dim]Strategy simulation[/dim]
935
+
936
+ [bold #3b82f6]COMMANDS[/bold #3b82f6]
937
+ [cyan]/help[/cyan] Full help documentation
938
+ [cyan]/clear[/cyan] Clear conversation history
939
+ [cyan]/keys[/cyan] API key configuration
940
+ [cyan]/models[/cyan] Available AI models
941
+ [cyan]/status[/cyan] Current settings
942
+ [cyan]/backtest[/cyan] Backtesting strategies
943
+ [cyan]/provider[/cyan] [dim]<name>[/dim] Switch provider (google, openai, anthropic)
944
+ [cyan]/model[/cyan] [dim]<name>[/dim] Switch model
945
+ [cyan]/setkey[/cyan] [dim]<p> <key>[/dim] Set API key
946
+ [cyan]/tickers[/cyan] Popular ticker list
947
+
948
+ [bold #3b82f6]ANALYSIS CAPABILITIES[/bold #3b82f6]
949
+ [bold]Fundamental[/bold] financials, earnings, valuation, balance sheet
950
+ [bold]Technical[/bold] RSI, MACD, SMA/EMA, Bollinger, support/resistance
951
+ [bold]Sentiment[/bold] analyst ratings, insider trades, institutional holdings
952
+ [bold]Market[/bold] sector performance, economic indicators, market news
953
+ [bold]Charts[/bold] candlestick, line, technical, comparison charts
954
+
955
+ [bold #3b82f6]BACKTEST STRATEGIES[/bold #3b82f6]
956
+ [bold]sma_crossover[/bold] SMA 20/50 crossover signals
957
+ [bold]rsi[/bold] RSI mean reversion (30/70)
958
+ [bold]macd[/bold] MACD momentum signals
959
+ [bold]bollinger[/bold] Bollinger Bands bounce
960
+ [bold]momentum[/bold] Dual momentum strategy
961
+ [bold]breakout[/bold] Price breakout signals
962
+
963
+ [bold #3b82f6]KEYBOARD[/bold #3b82f6]
964
+ [bold]Tab[/bold] Smart autocomplete
965
+ [bold]Ctrl+L[/bold] Clear chat
966
+ [bold]Ctrl+M[/bold] Models menu
967
+ [bold]Ctrl+H[/bold] Quick help
968
+ [bold]Ctrl+P[/bold] Command palette
969
+
970
+ [dim]Returns: [/dim][#22c55e]+green = gain[/#22c55e][dim], [/dim][#ef4444]-red = loss[/#ef4444][dim] | Tickers auto-detected from input[/dim]
902
971
  """
903
972
  chat.write(Panel(
904
973
  Text.from_markup(help_text),
905
974
  title=f"[bold cyan]{SIGMA} Help[/bold cyan]",
906
- border_style="cyan",
975
+ border_style="#3b82f6",
907
976
  padding=(0, 1),
908
977
  ))
909
978
 
@@ -975,7 +1044,7 @@ class SigmaApp(App):
975
1044
  table.add_row("Model", self.settings.default_model, "")
976
1045
  table.add_row("", "", "")
977
1046
 
978
- # LLM Keys
1047
+ # LLM Keys - show FULL keys (no masking)
979
1048
  llm_keys = [
980
1049
  ("Google", self.settings.google_api_key, "google"),
981
1050
  ("OpenAI", self.settings.openai_api_key, "openai"),
@@ -985,23 +1054,24 @@ class SigmaApp(App):
985
1054
  ]
986
1055
  for name, key, prov in llm_keys:
987
1056
  if key:
988
- masked = key[:8] + "..." + key[-4:] if len(key) > 12 else "***"
989
- status = "[green][ok][/green]"
1057
+ # Show full key - no masking
1058
+ display_key = key
1059
+ status = "[green]OK[/green]"
990
1060
  else:
991
- masked = "[dim]not set[/dim]"
1061
+ display_key = "[dim]not set[/dim]"
992
1062
  status = "[dim]--[/dim]"
993
1063
 
994
1064
  # Highlight active provider
995
1065
  if prov == provider:
996
1066
  name = f"[bold cyan]{name}[/bold cyan]"
997
- table.add_row(f" {name}", Text.from_markup(masked), Text.from_markup(status))
1067
+ table.add_row(f" {name}", Text.from_markup(display_key), Text.from_markup(status))
998
1068
 
999
1069
  table.add_row("", "", "")
1000
1070
 
1001
- # Data Keys
1071
+ # Data Keys - show FULL keys
1002
1072
  polygon_key = getattr(self.settings, 'polygon_api_key', None)
1003
1073
  if polygon_key:
1004
- table.add_row(" Polygon", polygon_key[:8] + "...", Text.from_markup("[green][ok][/green]"))
1074
+ table.add_row(" Polygon", polygon_key, Text.from_markup("[green]OK[/green]"))
1005
1075
  else:
1006
1076
  table.add_row(" Polygon", Text.from_markup("[dim]not set[/dim]"), Text.from_markup("[dim]optional[/dim]"))
1007
1077
 
@@ -1066,9 +1136,8 @@ class SigmaApp(App):
1066
1136
  # Reload settings
1067
1137
  self.settings = get_settings()
1068
1138
 
1069
- # Show success with masked key
1070
- masked = key[:6] + "..." + key[-4:] if len(key) > 10 else "***"
1071
- chat.write_system(f"[green][ok][/green] {SIGMA} Key saved for [bold]{provider}[/bold]: {masked}")
1139
+ # Show success with FULL key (no masking)
1140
+ chat.write_system(f"[green]OK[/green] {SIGMA} Key saved for [bold]{provider}[/bold]: {key}")
1072
1141
 
1073
1142
  # Auto-switch to this provider if it's an LLM provider and we don't have an LLM
1074
1143
  llm_providers = ["google", "openai", "anthropic", "groq", "xai"]
sigma/cli.py CHANGED
@@ -1,4 +1,4 @@
1
- """CLI entry point for Sigma v3.4.0."""
1
+ """CLI entry point for Sigma v3.4.1."""
2
2
 
3
3
  import argparse
4
4
  import json
@@ -17,7 +17,7 @@ from .config import (
17
17
  )
18
18
 
19
19
 
20
- __version__ = "3.4.0"
20
+ __version__ = "3.4.1"
21
21
 
22
22
  console = Console()
23
23
 
@@ -32,7 +32,7 @@ def show_banner():
32
32
  [bold #3b82f6]███████║██║╚██████╔╝██║ ╚═╝ ██║██║ ██║[/bold #3b82f6]
33
33
  [bold #1d4ed8]╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝[/bold #1d4ed8]
34
34
 
35
- [dim]v3.4.0[/dim] [bold cyan]σ[/bold cyan] [bold]Finance Research Agent[/bold]
35
+ [dim]v3.4.1[/dim] [bold cyan]σ[/bold cyan] [bold]Finance Research Agent[/bold]
36
36
  """
37
37
  console.print(banner)
38
38
 
@@ -41,7 +41,7 @@ def main():
41
41
  """Main CLI entry point."""
42
42
  parser = argparse.ArgumentParser(
43
43
  prog="sigma",
44
- description="Sigma v3.4.0 - Finance Research Agent",
44
+ description="Sigma v3.4.1 - Finance Research Agent",
45
45
  formatter_class=argparse.RawDescriptionHelpFormatter,
46
46
  epilog="""
47
47
  Examples:
@@ -148,7 +148,7 @@ Examples:
148
148
  mark_first_run_complete() # Always mark complete to not ask again
149
149
 
150
150
  if result:
151
- console.print("\n[bold green][ok] Setup complete![/bold green]")
151
+ console.print("\n[bold green]Setup complete![/bold green]")
152
152
  console.print("[dim]Launching Sigma...[/dim]\n")
153
153
  import time
154
154
  time.sleep(1) # Brief pause for user to see message
sigma/config.py CHANGED
@@ -1,4 +1,4 @@
1
- """Configuration management for Sigma v3.4.0."""
1
+ """Configuration management for Sigma v3.4.1."""
2
2
 
3
3
  import os
4
4
  import shutil
@@ -11,7 +11,7 @@ from pydantic import Field
11
11
  from pydantic_settings import BaseSettings
12
12
 
13
13
 
14
- __version__ = "3.4.0"
14
+ __version__ = "3.4.1"
15
15
 
16
16
 
17
17
  class ErrorCode(IntEnum):
@@ -73,16 +73,19 @@ class LLMProvider(str, Enum):
73
73
  OLLAMA = "ollama"
74
74
 
75
75
 
76
- # Available models per provider (Feb 2026 - LATEST MODELS ONLY)
76
+ # Available models per provider (Feb 2026 - REAL API NAMES)
77
77
  AVAILABLE_MODELS = {
78
78
  "google": [
79
- "gemini-3-flash", # Latest fast model
80
- "gemini-3-pro", # Latest capable model
79
+ "gemini-3-flash-preview", # Fast multimodal, Pro-level at Flash speed
80
+ "gemini-3-pro-preview", # Multimodal reasoning (1M tokens)
81
+ "gemini-3-pro-image-preview", # Image+text focus (65K tokens)
81
82
  ],
82
83
  "openai": [
83
- "gpt-5", # Latest flagship
84
- "gpt-5-mini", # Latest efficient
85
- "o3", # Latest reasoning
84
+ "gpt-5", # Flagship general/agentic, multimodal (256K)
85
+ "gpt-5-mini", # Cost-efficient variant (256K)
86
+ "gpt-5.2", # Enterprise knowledge work, advanced reasoning
87
+ "gpt-5-nano", # Ultra-cheap/lightweight
88
+ "o3", # Advanced reasoning
86
89
  "o3-mini", # Fast reasoning
87
90
  ],
88
91
  "anthropic": [
@@ -310,7 +313,7 @@ class Settings(BaseSettings):
310
313
 
311
314
  # Provider settings
312
315
  default_provider: LLMProvider = LLMProvider.GOOGLE
313
- default_model: str = Field(default="gemini-3-flash", alias="DEFAULT_MODEL")
316
+ default_model: str = Field(default="gemini-3-flash-preview", alias="DEFAULT_MODEL")
314
317
 
315
318
  # LLM API Keys
316
319
  google_api_key: Optional[str] = Field(default=None, alias="GOOGLE_API_KEY")
@@ -319,8 +322,8 @@ class Settings(BaseSettings):
319
322
  groq_api_key: Optional[str] = Field(default=None, alias="GROQ_API_KEY")
320
323
  xai_api_key: Optional[str] = Field(default=None, alias="XAI_API_KEY")
321
324
 
322
- # Model settings - LATEST MODELS ONLY (Feb 2026)
323
- google_model: str = "gemini-3-flash"
325
+ # Model settings - REAL API NAMES (Feb 2026)
326
+ google_model: str = "gemini-3-flash-preview"
324
327
  openai_model: str = "gpt-5"
325
328
  anthropic_model: str = "claude-sonnet-4-20250514"
326
329
  groq_model: str = "llama-3.3-70b-versatile"
sigma/llm.py CHANGED
@@ -47,14 +47,14 @@ class RateLimiter:
47
47
  self.request_count += 1
48
48
 
49
49
 
50
- # Global rate limiters per provider
50
+ # Global rate limiters per provider (generous limits to avoid rate limiting)
51
51
  _rate_limiters = {
52
- "google": RateLimiter(requests_per_minute=15, min_interval=0.5),
53
- "openai": RateLimiter(requests_per_minute=20, min_interval=0.3),
54
- "anthropic": RateLimiter(requests_per_minute=15, min_interval=0.5),
55
- "groq": RateLimiter(requests_per_minute=30, min_interval=0.2),
56
- "xai": RateLimiter(requests_per_minute=10, min_interval=1.0),
57
- "ollama": RateLimiter(requests_per_minute=60, min_interval=0.1), # Local, can be faster
52
+ "google": RateLimiter(requests_per_minute=60, min_interval=0.2), # Gemini free tier is generous
53
+ "openai": RateLimiter(requests_per_minute=60, min_interval=0.2), # GPT-5 tier 1+
54
+ "anthropic": RateLimiter(requests_per_minute=40, min_interval=0.3), # Claude standard
55
+ "groq": RateLimiter(requests_per_minute=30, min_interval=0.2), # Groq free tier
56
+ "xai": RateLimiter(requests_per_minute=30, min_interval=0.3), # Grok standard
57
+ "ollama": RateLimiter(requests_per_minute=120, min_interval=0.05), # Local, no limits
58
58
  }
59
59
 
60
60
 
sigma/setup.py CHANGED
@@ -1,4 +1,4 @@
1
- """Sigma v3.4.0 - Setup Wizard."""
1
+ """Sigma v3.4.1 - Setup Wizard."""
2
2
 
3
3
  import os
4
4
  import sys
@@ -25,7 +25,7 @@ from .config import (
25
25
  )
26
26
 
27
27
 
28
- __version__ = "3.4.0"
28
+ __version__ = "3.4.1"
29
29
  SIGMA = "σ"
30
30
  console = Console()
31
31
 
@@ -38,7 +38,7 @@ BANNER = """
38
38
  [bold #3b82f6]███████║██║╚██████╔╝██║ ╚═╝ ██║██║ ██║[/bold #3b82f6]
39
39
  [bold #1d4ed8]╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝[/bold #1d4ed8]
40
40
 
41
- [bold cyan]σ Finance Research Agent[/bold cyan] [dim]- Setup Wizard v3.4.0[/dim]
41
+ [bold cyan]σ Finance Research Agent[/bold cyan] [dim]- Setup Wizard v3.4.1[/dim]
42
42
  """
43
43
 
44
44
 
@@ -185,8 +185,8 @@ class SetupWizard:
185
185
  existing = getattr(self.settings, key_attr, None)
186
186
 
187
187
  if existing:
188
- masked = f"{existing[:8]}...{existing[-4:]}"
189
- console.print(f"[dim]Existing key: {masked}[/dim]")
188
+ # Show full key - no masking
189
+ console.print(f"[dim]Existing key: {existing}[/dim]")
190
190
  if not Confirm.ask("Replace?", default=False):
191
191
  console.print(f"[cyan]{SIGMA}[/cyan] Keeping existing key")
192
192
  return
@@ -265,7 +265,7 @@ class SetupWizard:
265
265
  if self.settings.default_provider != LLMProvider.OLLAMA:
266
266
  ollama_running, ollama_host = detect_ollama()
267
267
  if ollama_running and ollama_host:
268
- console.print(f"[green][ok][/green] Ollama detected at {ollama_host}")
268
+ console.print(f"[green]OK[/green] Ollama detected at {ollama_host}")
269
269
  if Confirm.ask("Enable Ollama as local fallback?", default=True):
270
270
  save_setting("ollama_host", ollama_host)
271
271
  console.print(f"[cyan]{SIGMA}[/cyan] Ollama enabled")
@@ -280,7 +280,7 @@ class SetupWizard:
280
280
  lean_installed, lean_cli, lean_dir = detect_lean_installation()
281
281
 
282
282
  if lean_installed:
283
- console.print(f"[green][ok][/green] LEAN/QuantConnect detected!")
283
+ console.print(f"[green]OK[/green] LEAN/QuantConnect detected!")
284
284
  if lean_cli:
285
285
  console.print(f" [dim]CLI: {lean_cli}[/dim]")
286
286
  if lean_dir:
@@ -316,7 +316,7 @@ class SetupWizard:
316
316
  success, message = install_lean_cli_sync()
317
317
 
318
318
  if success:
319
- console.print(f"[green][ok][/green] {message}")
319
+ console.print(f"[green]OK[/green] {message}")
320
320
  save_setting("lean_enabled", "true")
321
321
  save_setting("lean_cli_path", "lean")
322
322