aria-code 4.1.3__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.
- agents/__init__.py +32 -0
- agents/base.py +190 -0
- agents/deep/__init__.py +37 -0
- agents/deep/calibration_loop.py +144 -0
- agents/deep/critic.py +125 -0
- agents/deep/deepen.py +193 -0
- agents/deep/models.py +149 -0
- agents/deep/pipeline.py +164 -0
- agents/deep/quant_fusion.py +192 -0
- agents/deep/themes.py +95 -0
- agents/deep/tiers.py +106 -0
- agents/financial/__init__.py +10 -0
- agents/financial/catalyst.py +279 -0
- agents/financial/debate.py +145 -0
- agents/financial/earnings.py +303 -0
- agents/financial/fundamental.py +159 -0
- agents/financial/macro.py +99 -0
- agents/financial/news.py +207 -0
- agents/financial/risk.py +132 -0
- agents/financial/sector.py +279 -0
- agents/financial/synthesis.py +274 -0
- agents/financial/technical.py +258 -0
- agents/portfolio_agent.py +333 -0
- agents/realty/__init__.py +62 -0
- agents/realty/asset_diagnosis.py +150 -0
- agents/realty/business_match.py +165 -0
- agents/realty/cashflow_verify.py +208 -0
- agents/realty/contract_rules.py +209 -0
- agents/realty/energy_anomaly.py +188 -0
- agents/realty/exit_settlement.py +207 -0
- agents/realty/fulfillment_risk.py +205 -0
- agents/realty/ops_optimize.py +159 -0
- agents/realty/revenue_share.py +214 -0
- agents/registry.py +144 -0
- agents/sports/__init__.py +0 -0
- agents/sports/football_agent.py +169 -0
- agents/team.py +289 -0
- aliyun_data_client.py +660 -0
- apps/README.md +12 -0
- apps/__init__.py +2 -0
- apps/channels/README.md +15 -0
- apps/cli/README.md +13 -0
- apps/cli/__init__.py +2 -0
- apps/cli/bootstrap.py +99 -0
- apps/cli/codegen_paths.py +29 -0
- apps/cli/commands/__init__.py +16 -0
- apps/cli/commands/analysis_cmds.py +288 -0
- apps/cli/commands/backtest_cmds.py +1887 -0
- apps/cli/commands/broker_cmds.py +1154 -0
- apps/cli/commands/business_workflow_cmds.py +289 -0
- apps/cli/commands/catalog.py +84 -0
- apps/cli/commands/data_cmds.py +405 -0
- apps/cli/commands/diagnostic_cmds.py +179 -0
- apps/cli/commands/diagnostic_ops_cmds.py +696 -0
- apps/cli/commands/finance_render.py +12 -0
- apps/cli/commands/market.py +399 -0
- apps/cli/commands/market_cmds.py +1276 -0
- apps/cli/commands/market_context.py +425 -0
- apps/cli/commands/market_render.py +7 -0
- apps/cli/commands/model_cmds.py +1579 -0
- apps/cli/commands/ops_cmds.py +668 -0
- apps/cli/commands/portfolio_cmds.py +962 -0
- apps/cli/commands/report.py +377 -0
- apps/cli/commands/scaffold_templates.py +617 -0
- apps/cli/commands/session_cmds.py +179 -0
- apps/cli/commands/session_ux_cmds.py +280 -0
- apps/cli/commands/team.py +588 -0
- apps/cli/commands/team_render.py +8 -0
- apps/cli/commands/ui_cmds.py +358 -0
- apps/cli/commands/workflow_cmds.py +279 -0
- apps/cli/commands/workspace_cmds.py +1414 -0
- apps/cli/config_paths.py +70 -0
- apps/cli/config_store.py +61 -0
- apps/cli/deterministic.py +122 -0
- apps/cli/direct.py +48 -0
- apps/cli/github_app_auth.py +135 -0
- apps/cli/handlers/__init__.py +11 -0
- apps/cli/handlers/broker_handlers.py +122 -0
- apps/cli/handlers/chart_handlers.py +1309 -0
- apps/cli/handlers/market_handlers.py +2509 -0
- apps/cli/handlers/realty_handlers.py +114 -0
- apps/cli/handlers/strategy_advice.py +82 -0
- apps/cli/hooks.py +180 -0
- apps/cli/i18n.py +284 -0
- apps/cli/intent.py +136 -0
- apps/cli/intent_router.py +217 -0
- apps/cli/lifecycle_hooks.py +48 -0
- apps/cli/main.py +29 -0
- apps/cli/market_metadata.py +135 -0
- apps/cli/market_universe.py +265 -0
- apps/cli/message_processing.py +257 -0
- apps/cli/plan_mode.py +139 -0
- apps/cli/plotly_html.py +15 -0
- apps/cli/prediction_feedback.py +202 -0
- apps/cli/preflight.py +497 -0
- apps/cli/project_aria.py +60 -0
- apps/cli/prompts/__init__.py +0 -0
- apps/cli/prompts/coding.py +658 -0
- apps/cli/prompts/system_prompts.py +531 -0
- apps/cli/prompts/ui.py +434 -0
- apps/cli/providers/__init__.py +1 -0
- apps/cli/providers/base.py +271 -0
- apps/cli/providers/chat_routing.py +80 -0
- apps/cli/providers/llm/__init__.py +1 -0
- apps/cli/providers/llm/ollama_stream.py +1170 -0
- apps/cli/providers/llm/sse_stream.py +216 -0
- apps/cli/providers/runtime_bridge.py +185 -0
- apps/cli/runtime_consumer.py +489 -0
- apps/cli/session_export.py +87 -0
- apps/cli/session_jsonl.py +207 -0
- apps/cli/session_store.py +112 -0
- apps/cli/todo_tracker.py +190 -0
- apps/cli/tools/__init__.py +40 -0
- apps/cli/tools/context.py +46 -0
- apps/cli/tools/file_tools.py +112 -0
- apps/cli/tools/market_tools.py +549 -0
- apps/cli/tools/notebook_tools.py +111 -0
- apps/cli/tools/system_tools.py +669 -0
- apps/cli/tools/write_tools.py +715 -0
- apps/cli/tradingview_bridge.py +434 -0
- apps/cli/update_check.py +152 -0
- apps/cli/utils/__init__.py +0 -0
- apps/cli/utils/market_detect.py +1578 -0
- apps/daemon/README.md +14 -0
- apps/vscode/README.md +115 -0
- apps/vscode/package.json +70 -0
- aria_cli.py +11636 -0
- aria_code-4.1.3.dist-info/METADATA +952 -0
- aria_code-4.1.3.dist-info/RECORD +284 -0
- aria_code-4.1.3.dist-info/WHEEL +5 -0
- aria_code-4.1.3.dist-info/entry_points.txt +2 -0
- aria_code-4.1.3.dist-info/licenses/LICENSE +121 -0
- aria_code-4.1.3.dist-info/top_level.txt +50 -0
- aria_daemon.py +1295 -0
- aria_feishu_bot.py +1359 -0
- aria_relay_client.py +182 -0
- aria_relay_server.py +405 -0
- aria_telegram_bot.py +202 -0
- ariarc.py +328 -0
- artifacts.py +491 -0
- backtest_report.py +472 -0
- brokers/__init__.py +72 -0
- brokers/base.py +207 -0
- brokers/capabilities.py +264 -0
- brokers/cn/__init__.py +10 -0
- brokers/cn/easytrader_broker.py +193 -0
- brokers/cn/futu_broker.py +194 -0
- brokers/cn/longbridge_broker.py +190 -0
- brokers/cn/tiger_broker.py +196 -0
- brokers/cn/xtquant_broker.py +175 -0
- brokers/config.py +364 -0
- brokers/intl/__init__.py +5 -0
- brokers/intl/alpaca_broker.py +183 -0
- brokers/intl/ibkr_broker.py +215 -0
- brokers/intl/webull_broker.py +156 -0
- brokers/paper_broker.py +259 -0
- brokers/planning.py +296 -0
- brokers/registry.py +181 -0
- brokers/trading.py +237 -0
- change_store.py +127 -0
- command_safety.py +19 -0
- computer_use_tools.py +504 -0
- dashboard_generator.py +578 -0
- data_analysis_tools.py +808 -0
- data_cleaner.py +483 -0
- data_service.py +481 -0
- datasources/__init__.py +23 -0
- datasources/base.py +166 -0
- datasources/router.py +221 -0
- datasources/sources/__init__.py +15 -0
- datasources/sources/akshare_source.py +269 -0
- datasources/sources/alpha_vantage_source.py +202 -0
- datasources/sources/edgar_source.py +218 -0
- datasources/sources/finnhub_source.py +197 -0
- datasources/sources/fred_source.py +219 -0
- datasources/sources/tushare_source.py +141 -0
- datasources/sources/web_scraper_source.py +278 -0
- datasources/sources/world_bank_source.py +205 -0
- datasources/sources/yfinance_source.py +152 -0
- demo_player.py +204 -0
- doctor.py +508 -0
- file_analysis_tools.py +734 -0
- finance_formulas.py +389 -0
- football_data_client.py +1670 -0
- intent_classifier.py +358 -0
- local_finance_tools.py +3221 -0
- local_llm_provider.py +552 -0
- macro_tools.py +368 -0
- market_data_client.py +1899 -0
- mcp_client.py +506 -0
- memory_manager.py +245 -0
- model_capability.py +416 -0
- notification_tools.py +248 -0
- packages/__init__.py +23 -0
- packages/aria_agents/__init__.py +5 -0
- packages/aria_agents/manifest.py +69 -0
- packages/aria_core/__init__.py +34 -0
- packages/aria_core/architecture.py +192 -0
- packages/aria_core/export.py +124 -0
- packages/aria_core/manifest.py +65 -0
- packages/aria_infra/__init__.py +15 -0
- packages/aria_infra/arthera.py +52 -0
- packages/aria_infra/doctor.py +246 -0
- packages/aria_infra/product.py +37 -0
- packages/aria_mcp/__init__.py +25 -0
- packages/aria_mcp/bridge.py +38 -0
- packages/aria_mcp/config.py +97 -0
- packages/aria_mcp/tools.py +61 -0
- packages/aria_sdk/__init__.py +19 -0
- packages/aria_sdk/client.py +396 -0
- packages/aria_sdk/providers.py +70 -0
- packages/aria_sdk/streaming.py +73 -0
- packages/aria_sdk/types.py +86 -0
- packages/aria_services/__init__.py +55 -0
- packages/aria_services/context.py +258 -0
- packages/aria_services/data.py +11 -0
- packages/aria_services/provider_health.py +189 -0
- packages/aria_services/registry.py +213 -0
- packages/aria_services/usage.py +138 -0
- packages/aria_skills/__init__.py +5 -0
- packages/aria_skills/registry.py +59 -0
- packages/aria_tools/__init__.py +5 -0
- packages/aria_tools/registry.py +128 -0
- packages/quant_engine/__init__.py +6 -0
- packages/quant_engine/sports/__init__.py +72 -0
- packages/quant_engine/sports/calibrator.py +353 -0
- packages/quant_engine/sports/dixon_coles.py +234 -0
- packages/quant_engine/sports/elo.py +299 -0
- packages/quant_engine/sports/form.py +188 -0
- packages/quant_engine/sports/h2h.py +195 -0
- packages/quant_engine/sports/ml_model.py +354 -0
- packages/quant_engine/sports/predictor.py +311 -0
- packages/quant_engine/sports/tracker.py +664 -0
- packages/quant_engine/stochastic/__init__.py +27 -0
- packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- packages/quant_engine/stochastic/ito_calculus.py +477 -0
- packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- packages/quant_engine/stochastic/options_pricing.py +573 -0
- packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- plan_utils.py +194 -0
- plugin_loader.py +328 -0
- portfolio_ledger.py +262 -0
- privacy/__init__.py +5 -0
- privacy/feedback.py +123 -0
- project_tools.py +525 -0
- providers/__init__.py +30 -0
- providers/llm/__init__.py +19 -0
- providers/llm/anthropic.py +184 -0
- providers/llm/base.py +139 -0
- providers/llm/ollama.py +128 -0
- providers/llm/openai_compat.py +282 -0
- providers/llm/registry.py +358 -0
- realty_data_tools.py +659 -0
- report_generator.py +1314 -0
- runtime/__init__.py +103 -0
- runtime/agent_loop.py +1183 -0
- runtime/approval.py +51 -0
- runtime/events.py +102 -0
- runtime/gateway.py +128 -0
- runtime/lsp.py +346 -0
- runtime/subagent.py +258 -0
- runtime/tool_executor.py +104 -0
- runtime/tool_policy.py +106 -0
- safety/__init__.py +21 -0
- safety/permissions.py +275 -0
- setup_wizard.py +653 -0
- strategy_vault.py +420 -0
- ui/__init__.py +100 -0
- ui/banner.py +310 -0
- ui/completer.py +391 -0
- ui/console.py +271 -0
- ui/image_render.py +243 -0
- ui/input_box.py +376 -0
- ui/picker.py +195 -0
- ui/render/__init__.py +11 -0
- ui/render/finance.py +1480 -0
- ui/render/market.py +225 -0
- ui/render/output.py +681 -0
- ui/render/team.py +346 -0
- ui/robot.py +235 -0
- workspace/__init__.py +6 -0
- workspace/files.py +170 -0
- workspace/verify.py +113 -0
ui/banner.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Startup banner and status-label rendering for Aria Code.
|
|
2
|
+
|
|
3
|
+
All functions accept only primitive values (strings, dicts, ints, bools)
|
|
4
|
+
so aria_cli.py can do data gathering while this module owns all display.
|
|
5
|
+
|
|
6
|
+
Public surface
|
|
7
|
+
--------------
|
|
8
|
+
render_compact_banner(...) — one-line banner (banner=compact)
|
|
9
|
+
render_full_banner(...) — robot-face + grid panel (banner=full)
|
|
10
|
+
render_try_hints(console) — "try analyze AAPL · /help" line below panel
|
|
11
|
+
privacy_status_label(...)
|
|
12
|
+
control_status_label(...)
|
|
13
|
+
ollama_status_label(...)
|
|
14
|
+
bottom_toolbar_parts(...)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import shutil
|
|
21
|
+
from typing import Optional
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _t(key: str, lang: str) -> str:
|
|
25
|
+
"""Thin wrapper around i18n.t() — tolerates import failure."""
|
|
26
|
+
try:
|
|
27
|
+
from apps.cli.i18n import t as _translate
|
|
28
|
+
return _translate(key, lang=lang)
|
|
29
|
+
except Exception:
|
|
30
|
+
_fallback = {
|
|
31
|
+
"sharing_on": "sharing on", "local_only": "local-only",
|
|
32
|
+
"network_on": "network on", "network_off": "network off",
|
|
33
|
+
"privacy": "privacy", "ollama_online": "Ollama online",
|
|
34
|
+
"ollama_offline": "Ollama offline", "cloud": "cloud",
|
|
35
|
+
"local_first_agent": "local-first agent",
|
|
36
|
+
"model": "model", "workspace": "workspace",
|
|
37
|
+
"mode": "mode", "status": "status",
|
|
38
|
+
"tools": "tools", "skills": "skills", "quant": "quant",
|
|
39
|
+
"try": "try", "local": "local", "lite": "lite",
|
|
40
|
+
}
|
|
41
|
+
return _fallback.get(key, key)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ── Status label helpers ───────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
def privacy_status_label(config: dict, rich: bool = False, lang: str = "") -> str:
|
|
47
|
+
sharing = bool(config.get("data_sharing", False))
|
|
48
|
+
upload = bool(config.get("feedback_upload", False))
|
|
49
|
+
_lang = lang or config.get("ui_lang", "en")
|
|
50
|
+
if sharing and upload:
|
|
51
|
+
label = _t("sharing_on", _lang)
|
|
52
|
+
return _mark("accent", label) if rich else label
|
|
53
|
+
return _t("local_only", _lang)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def control_status_label(config: dict, rich: bool = False, lang: str = "") -> str:
|
|
57
|
+
_lang = lang or config.get("ui_lang", "en")
|
|
58
|
+
permission = config.get("permission_mode", "workspace-write")
|
|
59
|
+
net_key = "network_on" if bool(config.get("network_enabled", True)) else "network_off"
|
|
60
|
+
network = _t(net_key, _lang)
|
|
61
|
+
priv_label = _t("privacy", _lang)
|
|
62
|
+
privacy = privacy_status_label(config, rich=rich, lang=_lang)
|
|
63
|
+
return f"{permission} · {network} · {priv_label} {privacy}"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def ollama_status_label(
|
|
67
|
+
ollama_alive: bool,
|
|
68
|
+
installed_models: set,
|
|
69
|
+
config: dict,
|
|
70
|
+
rich: bool = False,
|
|
71
|
+
lang: str = "",
|
|
72
|
+
) -> str:
|
|
73
|
+
_lang = lang or config.get("ui_lang", "en")
|
|
74
|
+
count = len(installed_models)
|
|
75
|
+
has_cloud = bool(
|
|
76
|
+
config.get("auth_token")
|
|
77
|
+
or os.getenv("ANTHROPIC_API_KEY")
|
|
78
|
+
or os.getenv("OPENAI_API_KEY")
|
|
79
|
+
or os.getenv("DEEPSEEK_API_KEY")
|
|
80
|
+
)
|
|
81
|
+
cloud_word = _t("cloud", _lang)
|
|
82
|
+
cloud_rich = _mark("muted", f"· {cloud_word} ✓")
|
|
83
|
+
cloud_tag = (
|
|
84
|
+
f" {cloud_rich}" if rich
|
|
85
|
+
else f" · {cloud_word} ✓"
|
|
86
|
+
) if has_cloud else ""
|
|
87
|
+
model_word = _t("model_singular" if count == 1 else "model_plural", _lang)
|
|
88
|
+
if ollama_alive:
|
|
89
|
+
label = f"{_t('ollama_online', _lang)} · {count} {model_word}"
|
|
90
|
+
return f"{label}{cloud_tag}"
|
|
91
|
+
base = _t("ollama_offline", _lang)
|
|
92
|
+
if has_cloud:
|
|
93
|
+
return (f"{base} {cloud_rich}" if rich else f"{base} · {cloud_word} ✓")
|
|
94
|
+
return base
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def bottom_toolbar_parts(
|
|
98
|
+
conversation: list,
|
|
99
|
+
config: dict,
|
|
100
|
+
actual_model: Optional[str],
|
|
101
|
+
get_model_cfg_fn,
|
|
102
|
+
) -> tuple:
|
|
103
|
+
"""Return (model_label, cwd, privacy, est_tokens, max_ctx)."""
|
|
104
|
+
est_tokens = sum(len(m.get("content", "")) for m in conversation) // 3
|
|
105
|
+
mkey = config.get("model", "qwen2.5:7b")
|
|
106
|
+
max_ctx = get_model_cfg_fn(mkey).get("num_ctx", 16384)
|
|
107
|
+
cwd = os.getcwd()
|
|
108
|
+
home = os.path.expanduser("~")
|
|
109
|
+
if cwd.startswith(home):
|
|
110
|
+
cwd = "~" + cwd[len(home):]
|
|
111
|
+
model_label = actual_model or mkey
|
|
112
|
+
if len(model_label) > 28:
|
|
113
|
+
model_label = "…" + model_label[-27:]
|
|
114
|
+
if len(cwd) > 34:
|
|
115
|
+
cwd = "…" + cwd[-33:]
|
|
116
|
+
privacy = "sharing" if bool(config.get("data_sharing", False)) else "local-only"
|
|
117
|
+
return model_label, cwd, privacy, est_tokens, max_ctx
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# ── Banner renderers ───────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
_MASCOT = "[bold #C08050]◉[/bold #C08050]"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _is_light_theme() -> bool:
|
|
126
|
+
try:
|
|
127
|
+
from .robot import detect_theme
|
|
128
|
+
return detect_theme() == "light"
|
|
129
|
+
except Exception:
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _style_tag(style: str, text: str) -> str:
|
|
134
|
+
if style == "dim":
|
|
135
|
+
return f"[dim]{text}[/dim]"
|
|
136
|
+
return f"[{style}]{text}[/{style}]"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _banner_style(role: str) -> str:
|
|
140
|
+
if _is_light_theme():
|
|
141
|
+
return {
|
|
142
|
+
"primary": "bold #1F2328",
|
|
143
|
+
"muted": "#57606A",
|
|
144
|
+
"subtle": "#6E7781",
|
|
145
|
+
"dim": "#8C959F",
|
|
146
|
+
"accent": "#9A6700",
|
|
147
|
+
}.get(role, "#57606A")
|
|
148
|
+
return {
|
|
149
|
+
"primary": "bold",
|
|
150
|
+
"muted": "dim",
|
|
151
|
+
"subtle": "dim",
|
|
152
|
+
"dim": "dim",
|
|
153
|
+
"accent": "#C08050",
|
|
154
|
+
}.get(role, "dim")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _mark(role: str, text: str) -> str:
|
|
158
|
+
return _style_tag(_banner_style(role), text)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _normalize_dim_markup(markup: str) -> str:
|
|
162
|
+
"""Make caller-supplied [dim] markup readable in light terminals."""
|
|
163
|
+
if not _is_light_theme():
|
|
164
|
+
return markup
|
|
165
|
+
return markup.replace("[dim]", "[#57606A]").replace("[/dim]", "[/#57606A]")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def render_compact_banner(
|
|
169
|
+
*,
|
|
170
|
+
version: str,
|
|
171
|
+
model_label: str,
|
|
172
|
+
runtime: str, # "cloud" | "local"
|
|
173
|
+
cwd: str,
|
|
174
|
+
control_status_rich: str,
|
|
175
|
+
tool_count: int,
|
|
176
|
+
update_notice: Optional[str] = None,
|
|
177
|
+
console,
|
|
178
|
+
has_rich: bool,
|
|
179
|
+
lang: str = "en",
|
|
180
|
+
) -> None:
|
|
181
|
+
if not has_rich:
|
|
182
|
+
print(f" Aria Code v{version} {model_label} {cwd}")
|
|
183
|
+
return
|
|
184
|
+
_rt_word = _t("cloud", lang) if runtime == "cloud" else _t("local", lang)
|
|
185
|
+
_rt = _mark("muted", _rt_word)
|
|
186
|
+
_tools_word = _t("tools", lang)
|
|
187
|
+
_mascot = _style_tag(f"bold {_banner_style('accent')}", "◉")
|
|
188
|
+
console.print(
|
|
189
|
+
f" {_mascot} {_mark('primary', 'Aria Code')} {_mark('subtle', f'v{version}')}"
|
|
190
|
+
f" {_mark('dim', '·')} {model_label} {_rt}"
|
|
191
|
+
f" {_mark('dim', '·')} {_mark('muted', cwd)}"
|
|
192
|
+
)
|
|
193
|
+
console.print(_mark("muted", f" {_normalize_dim_markup(control_status_rich)} · {tool_count} {_tools_word} · /help"))
|
|
194
|
+
if update_notice:
|
|
195
|
+
console.print(f" {update_notice}")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def render_full_banner(
|
|
199
|
+
*,
|
|
200
|
+
version: str,
|
|
201
|
+
rt_label: str, # Rich markup: "GPT-OSS 120B [dim]cloud[/dim]"
|
|
202
|
+
cwd: str,
|
|
203
|
+
control_status_rich: str,
|
|
204
|
+
ollama_status_rich: str,
|
|
205
|
+
tool_count: int,
|
|
206
|
+
skill_count: int,
|
|
207
|
+
auto_healed_from: str = "",
|
|
208
|
+
current_id: str = "",
|
|
209
|
+
badge: str = "",
|
|
210
|
+
installed_models: frozenset = frozenset(),
|
|
211
|
+
best_lite_id: str = "", # model ID to suggest when lite badge + not installed
|
|
212
|
+
update_notice: Optional[str] = None,
|
|
213
|
+
console,
|
|
214
|
+
has_rich: bool,
|
|
215
|
+
rich_box,
|
|
216
|
+
lang: str = "en",
|
|
217
|
+
) -> None:
|
|
218
|
+
_lfa = _t("local_first_agent", lang)
|
|
219
|
+
_model = _t("model", lang)
|
|
220
|
+
_ws = _t("workspace", lang)
|
|
221
|
+
_tools = _t("tools", lang)
|
|
222
|
+
_tip = _t("tip", lang)
|
|
223
|
+
_amatch = _t("auto_matched", lang)
|
|
224
|
+
|
|
225
|
+
if not has_rich:
|
|
226
|
+
print(f"\n Aria Code v{version} {_lfa}")
|
|
227
|
+
print(f" {_model:<10}{rt_label}")
|
|
228
|
+
print(f" {_ws:<10}{cwd}")
|
|
229
|
+
print(f" {control_status_rich}")
|
|
230
|
+
print(f" {ollama_status_rich}")
|
|
231
|
+
print("─" * 60)
|
|
232
|
+
return
|
|
233
|
+
|
|
234
|
+
from rich.table import Table
|
|
235
|
+
from rich.text import Text
|
|
236
|
+
|
|
237
|
+
# Left column: hand-tuned pixel mascot (pure text — works in every terminal,
|
|
238
|
+
# no image deps). Keep it quiet; copper is reserved for state accents.
|
|
239
|
+
from .robot import ROBOT_ROW_COUNT, get_robot_row
|
|
240
|
+
|
|
241
|
+
_face = Text()
|
|
242
|
+
for _idx in range(ROBOT_ROW_COUNT):
|
|
243
|
+
for _style, _text in get_robot_row(2, _idx):
|
|
244
|
+
_face.append(_text, style=_style)
|
|
245
|
+
if _idx < ROBOT_ROW_COUNT - 1:
|
|
246
|
+
_face.append("\n")
|
|
247
|
+
|
|
248
|
+
# Right column: Claude Code-like essentials only. Operational detail is
|
|
249
|
+
# available in the bottom toolbar and slash commands, so startup stays calm.
|
|
250
|
+
_info_lines = [
|
|
251
|
+
f"{_mark('primary', 'Aria Code')} {_mark('subtle', f'v{version} · {_lfa}')}",
|
|
252
|
+
f"{_normalize_dim_markup(rt_label)}",
|
|
253
|
+
f"{_mark('muted', cwd)}",
|
|
254
|
+
]
|
|
255
|
+
if auto_healed_from:
|
|
256
|
+
_info_lines.append(
|
|
257
|
+
f"{_mark('muted', f'⚙ {_amatch}')} "
|
|
258
|
+
f"[yellow]{auto_healed_from}[/yellow]"
|
|
259
|
+
f" {_mark('dim', '→')} [bold]{current_id}[/bold]"
|
|
260
|
+
)
|
|
261
|
+
if badge == "Fast" and best_lite_id and best_lite_id not in installed_models:
|
|
262
|
+
lite_word = _t("lite", lang)
|
|
263
|
+
_info_lines.append(
|
|
264
|
+
f"[yellow]{_tip}[/yellow] {_mark('muted', f'{lite_word} model — ')}"
|
|
265
|
+
f"[bold]ollama pull {best_lite_id}[/bold] {_mark('muted', f'for full {_tools}')}"
|
|
266
|
+
)
|
|
267
|
+
if update_notice:
|
|
268
|
+
_info_lines.append(update_notice)
|
|
269
|
+
|
|
270
|
+
_info = Text.from_markup("\n".join(_info_lines))
|
|
271
|
+
|
|
272
|
+
_grid = Table.grid(padding=(0, 3))
|
|
273
|
+
_grid.add_column(no_wrap=True, vertical="top")
|
|
274
|
+
_grid.add_column(vertical="middle")
|
|
275
|
+
_grid.add_row(_face, _info)
|
|
276
|
+
|
|
277
|
+
console.print(_grid)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def render_try_hints(console, has_rich: bool, lang: str = "en") -> None:
|
|
281
|
+
"""Show natural-language examples that demonstrate LLM-native usage."""
|
|
282
|
+
if not has_rich:
|
|
283
|
+
return
|
|
284
|
+
tcols = shutil.get_terminal_size((80, 24)).columns
|
|
285
|
+
# Hints are natural language sentences — NOT slash commands.
|
|
286
|
+
# The point: users should feel free to just type what they want.
|
|
287
|
+
if lang == "zh":
|
|
288
|
+
hints = [
|
|
289
|
+
(_mark("accent", "宁德时代今天怎么样?"), 19), # 9 CJK×2 + 1
|
|
290
|
+
(_mark("accent", "帮我分析一下持仓风险"), 20), # 10 CJK×2
|
|
291
|
+
(_mark("accent", "生成今日A股晨报看板"), 19), # 9 CJK×2 + "A"×1
|
|
292
|
+
(_mark("subtle", "/help"), 5),
|
|
293
|
+
]
|
|
294
|
+
else:
|
|
295
|
+
hints = [
|
|
296
|
+
(_mark("accent", "How's NVDA this week?"), 18),
|
|
297
|
+
(_mark("accent", "Analyze my portfolio risk"), 24),
|
|
298
|
+
(_mark("accent", "Generate a morning brief HTML"), 30),
|
|
299
|
+
(_mark("subtle", "/help"), 5),
|
|
300
|
+
]
|
|
301
|
+
sep = f" {_mark('dim', '·')} "
|
|
302
|
+
parts = []
|
|
303
|
+
used = 8
|
|
304
|
+
for hint_rich, hint_len in hints:
|
|
305
|
+
cost = hint_len + (5 if parts else 0)
|
|
306
|
+
if used + cost <= tcols - 4:
|
|
307
|
+
parts.append(hint_rich)
|
|
308
|
+
used += cost
|
|
309
|
+
_try_word = _t("try", lang)
|
|
310
|
+
console.print(f" {_mark('subtle', _try_word)} " + sep.join(parts) + "\n")
|