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
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Manifest export helpers for Aria package facades."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, Iterable, List, Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _manifest_dicts(items: Iterable[Any]) -> List[Dict[str, Any]]:
|
|
12
|
+
out: List[Dict[str, Any]] = []
|
|
13
|
+
for item in items:
|
|
14
|
+
if hasattr(item, "manifest"):
|
|
15
|
+
item = item.manifest()
|
|
16
|
+
if hasattr(item, "to_dict"):
|
|
17
|
+
out.append(item.to_dict())
|
|
18
|
+
elif isinstance(item, dict):
|
|
19
|
+
out.append(dict(item))
|
|
20
|
+
return out
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def build_package_manifest(
|
|
24
|
+
*,
|
|
25
|
+
identity: Any,
|
|
26
|
+
tools: Iterable[Any],
|
|
27
|
+
agents: Iterable[Any],
|
|
28
|
+
skills: Iterable[Any],
|
|
29
|
+
mcp_exposures: Iterable[Any],
|
|
30
|
+
services: Iterable[Any] = (),
|
|
31
|
+
arthera_packages: Any = None,
|
|
32
|
+
arthera_mcp_tools: Iterable[Any] = (),
|
|
33
|
+
) -> Dict[str, Any]:
|
|
34
|
+
"""Build one JSON-serializable package manifest."""
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
"schema_version": "aria.package-manifest.v1",
|
|
38
|
+
"generated_at": datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z"),
|
|
39
|
+
"product": identity.to_dict() if hasattr(identity, "to_dict") else identity,
|
|
40
|
+
"capabilities": {
|
|
41
|
+
"services": _manifest_dicts(services),
|
|
42
|
+
"tools": _manifest_dicts(tools),
|
|
43
|
+
"agents": _manifest_dicts(agents),
|
|
44
|
+
"skills": _manifest_dicts(skills),
|
|
45
|
+
"mcp_exposures": [
|
|
46
|
+
item.to_tool_descriptor() if hasattr(item, "to_tool_descriptor") else dict(item)
|
|
47
|
+
for item in mcp_exposures
|
|
48
|
+
],
|
|
49
|
+
"arthera_mcp_tools": _manifest_dicts(arthera_mcp_tools),
|
|
50
|
+
},
|
|
51
|
+
"arthera_packages": (
|
|
52
|
+
arthera_packages.to_dict()
|
|
53
|
+
if hasattr(arthera_packages, "to_dict")
|
|
54
|
+
else arthera_packages
|
|
55
|
+
),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def build_session_diagnostic_bundle(
|
|
60
|
+
*,
|
|
61
|
+
session_id: str,
|
|
62
|
+
conversation: list,
|
|
63
|
+
config: Optional[dict] = None,
|
|
64
|
+
paths: Optional[dict] = None,
|
|
65
|
+
trace: Any = None,
|
|
66
|
+
provider_health: Optional[list] = None,
|
|
67
|
+
artifact_summary: Optional[dict] = None,
|
|
68
|
+
) -> Dict[str, Any]:
|
|
69
|
+
"""Build a stable export bundle for debugging and replay."""
|
|
70
|
+
config = dict(config or {})
|
|
71
|
+
redacted_config: Dict[str, Any] = {}
|
|
72
|
+
for key, value in config.items():
|
|
73
|
+
if any(token in key.lower() for token in ("key", "token", "secret", "password")):
|
|
74
|
+
if value:
|
|
75
|
+
redacted_config[key] = "***"
|
|
76
|
+
else:
|
|
77
|
+
redacted_config[key] = value
|
|
78
|
+
|
|
79
|
+
bundle: Dict[str, Any] = {
|
|
80
|
+
"schema": "aria.session_diagnostic_bundle.v1",
|
|
81
|
+
"generated_at": datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z"),
|
|
82
|
+
"session_id": session_id,
|
|
83
|
+
"conversation": list(conversation),
|
|
84
|
+
"conversation_count": len(conversation),
|
|
85
|
+
"config": redacted_config,
|
|
86
|
+
}
|
|
87
|
+
if paths:
|
|
88
|
+
bundle["paths"] = dict(paths)
|
|
89
|
+
if trace is not None:
|
|
90
|
+
try:
|
|
91
|
+
bundle["runtime_trace"] = trace.to_dict()
|
|
92
|
+
except Exception:
|
|
93
|
+
bundle["runtime_trace"] = {}
|
|
94
|
+
if provider_health is not None:
|
|
95
|
+
provider_rows = list(provider_health)
|
|
96
|
+
bundle["provider_health"] = provider_rows
|
|
97
|
+
try:
|
|
98
|
+
from packages.aria_services.provider_health import summarize_provider_health
|
|
99
|
+
|
|
100
|
+
bundle["provider_health_summary"] = summarize_provider_health(provider_rows).to_dict()
|
|
101
|
+
except Exception:
|
|
102
|
+
pass
|
|
103
|
+
if artifact_summary is not None:
|
|
104
|
+
bundle["artifact_summary"] = dict(artifact_summary)
|
|
105
|
+
else:
|
|
106
|
+
try:
|
|
107
|
+
from artifacts import artifact_summary as _artifact_summary
|
|
108
|
+
|
|
109
|
+
bundle["artifact_summary"] = _artifact_summary()
|
|
110
|
+
except Exception:
|
|
111
|
+
pass
|
|
112
|
+
try:
|
|
113
|
+
from packages.aria_core.architecture import architecture_contract
|
|
114
|
+
|
|
115
|
+
bundle["architecture"] = architecture_contract()
|
|
116
|
+
except Exception:
|
|
117
|
+
pass
|
|
118
|
+
return bundle
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def write_package_manifest(path: Path, manifest: Dict[str, Any]) -> Path:
|
|
122
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
123
|
+
path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2, default=str), encoding="utf-8")
|
|
124
|
+
return path
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Shared manifest types for agents, tools, skills, and package bridges."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass, field
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PermissionLevel(str, Enum):
|
|
11
|
+
READ_ONLY = "read_only"
|
|
12
|
+
WORKSPACE_WRITE = "workspace_write"
|
|
13
|
+
NETWORK = "network"
|
|
14
|
+
BROKER_READ = "broker_read"
|
|
15
|
+
BROKER_TRADE = "broker_trade"
|
|
16
|
+
FULL_ACCESS = "full_access"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ServiceKind(str, Enum):
|
|
20
|
+
AGENT = "agent"
|
|
21
|
+
TOOL = "tool"
|
|
22
|
+
SKILL = "skill"
|
|
23
|
+
MCP = "mcp"
|
|
24
|
+
SERVICE = "service"
|
|
25
|
+
DATA = "data"
|
|
26
|
+
INFRA = "infra"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class PackageLink:
|
|
31
|
+
"""Optional link to an implementation package or external service."""
|
|
32
|
+
|
|
33
|
+
package: str
|
|
34
|
+
module: str = ""
|
|
35
|
+
object_name: str = ""
|
|
36
|
+
transport: str = "python"
|
|
37
|
+
optional: bool = True
|
|
38
|
+
notes: str = ""
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
41
|
+
return asdict(self)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class CapabilityManifest:
|
|
46
|
+
"""Stable capability description used by registries and MCP exposure."""
|
|
47
|
+
|
|
48
|
+
name: str
|
|
49
|
+
kind: ServiceKind
|
|
50
|
+
description: str
|
|
51
|
+
capabilities: List[str] = field(default_factory=list)
|
|
52
|
+
permissions: List[PermissionLevel] = field(default_factory=list)
|
|
53
|
+
required_services: List[str] = field(default_factory=list)
|
|
54
|
+
input_schema: Dict[str, Any] = field(default_factory=dict)
|
|
55
|
+
output_schema: Dict[str, Any] = field(default_factory=dict)
|
|
56
|
+
package_link: Optional[PackageLink] = None
|
|
57
|
+
tags: List[str] = field(default_factory=list)
|
|
58
|
+
|
|
59
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
60
|
+
data = asdict(self)
|
|
61
|
+
data["kind"] = self.kind.value
|
|
62
|
+
data["permissions"] = [p.value for p in self.permissions]
|
|
63
|
+
if self.package_link:
|
|
64
|
+
data["package_link"] = self.package_link.to_dict()
|
|
65
|
+
return data
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Infrastructure helpers and external package discovery."""
|
|
2
|
+
|
|
3
|
+
from .arthera import ArtheraPackageMap, discover_arthera_packages
|
|
4
|
+
from .doctor import CheckResult, PackageDoctorReport, build_package_doctor_report
|
|
5
|
+
from .product import ProductIdentity, aria_code_identity
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"ArtheraPackageMap",
|
|
9
|
+
"CheckResult",
|
|
10
|
+
"PackageDoctorReport",
|
|
11
|
+
"ProductIdentity",
|
|
12
|
+
"aria_code_identity",
|
|
13
|
+
"build_package_doctor_report",
|
|
14
|
+
"discover_arthera_packages",
|
|
15
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Optional discovery for the sibling Arthera monorepo packages."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class ArtheraPackageMap:
|
|
12
|
+
root: Path
|
|
13
|
+
available: bool
|
|
14
|
+
packages: Dict[str, Path] = field(default_factory=dict)
|
|
15
|
+
mcp_servers: List[Path] = field(default_factory=list)
|
|
16
|
+
tool_dirs: List[Path] = field(default_factory=list)
|
|
17
|
+
|
|
18
|
+
def to_dict(self) -> dict:
|
|
19
|
+
return {
|
|
20
|
+
"root": str(self.root),
|
|
21
|
+
"available": self.available,
|
|
22
|
+
"packages": {name: str(path) for name, path in self.packages.items()},
|
|
23
|
+
"mcp_servers": [str(path) for path in self.mcp_servers],
|
|
24
|
+
"tool_dirs": [str(path) for path in self.tool_dirs],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def discover_arthera_packages(root: Optional[Path] = None) -> ArtheraPackageMap:
|
|
29
|
+
"""Discover useful Arthera package entrypoints without importing them."""
|
|
30
|
+
|
|
31
|
+
root = (root or Path.home() / "Desktop" / "Arthera" / "packages").expanduser()
|
|
32
|
+
if not root.exists():
|
|
33
|
+
return ArtheraPackageMap(root=root, available=False)
|
|
34
|
+
|
|
35
|
+
names = ["contracts", "data", "ml", "monitoring", "quant_engine", "reporting"]
|
|
36
|
+
packages = {name: root / name for name in names if (root / name).exists()}
|
|
37
|
+
mcp_servers = sorted(root.glob("**/mcp_server.py"))
|
|
38
|
+
tool_dirs = [
|
|
39
|
+
path for path in [
|
|
40
|
+
root / "quant_engine" / "tools",
|
|
41
|
+
root / "ml" / "llm" / "tools",
|
|
42
|
+
root / "ml" / "llm" / "skills",
|
|
43
|
+
]
|
|
44
|
+
if path.exists()
|
|
45
|
+
]
|
|
46
|
+
return ArtheraPackageMap(
|
|
47
|
+
root=root,
|
|
48
|
+
available=True,
|
|
49
|
+
packages=packages,
|
|
50
|
+
mcp_servers=mcp_servers,
|
|
51
|
+
tool_dirs=tool_dirs,
|
|
52
|
+
)
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""Health checks for Aria Code package bridges."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Dict, Iterable, List
|
|
8
|
+
|
|
9
|
+
from packages.aria_infra.arthera import ArtheraPackageMap
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class CheckResult:
|
|
14
|
+
name: str
|
|
15
|
+
status: str
|
|
16
|
+
detail: str = ""
|
|
17
|
+
remediation: str = ""
|
|
18
|
+
|
|
19
|
+
def to_dict(self) -> Dict[str, str]:
|
|
20
|
+
return {
|
|
21
|
+
"name": self.name,
|
|
22
|
+
"status": self.status,
|
|
23
|
+
"detail": self.detail,
|
|
24
|
+
"remediation": self.remediation,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class PackageDoctorReport:
|
|
30
|
+
status: str
|
|
31
|
+
checks: List[CheckResult] = field(default_factory=list)
|
|
32
|
+
|
|
33
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
34
|
+
return {
|
|
35
|
+
"status": self.status,
|
|
36
|
+
"checks": [check.to_dict() for check in self.checks],
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _overall_status(checks: List[CheckResult]) -> str:
|
|
41
|
+
if any(check.status == "fail" for check in checks):
|
|
42
|
+
return "fail"
|
|
43
|
+
if any(check.status == "warn" for check in checks):
|
|
44
|
+
return "warn"
|
|
45
|
+
return "ok"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _status_value(value: Any) -> str:
|
|
49
|
+
if hasattr(value, "value"):
|
|
50
|
+
return str(value.value)
|
|
51
|
+
return str(value)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def build_package_doctor_report(
|
|
55
|
+
*,
|
|
56
|
+
arthera: ArtheraPackageMap,
|
|
57
|
+
mcp_status: Dict[str, Any],
|
|
58
|
+
tool_count: int,
|
|
59
|
+
manifest_can_export: bool,
|
|
60
|
+
manifest_path: Path,
|
|
61
|
+
services: Iterable[Any] = (),
|
|
62
|
+
required_services: Iterable[str] = (),
|
|
63
|
+
architecture_layers: Iterable[Any] = (),
|
|
64
|
+
required_architecture_layers: Iterable[str] = (),
|
|
65
|
+
provider_health: Iterable[Dict[str, Any]] = (),
|
|
66
|
+
) -> PackageDoctorReport:
|
|
67
|
+
"""Build package bridge health checks without doing I/O."""
|
|
68
|
+
|
|
69
|
+
checks: List[CheckResult] = []
|
|
70
|
+
checks.append(CheckResult(
|
|
71
|
+
"product_identity",
|
|
72
|
+
"ok",
|
|
73
|
+
"Aria Code is registered as an Arthera product.",
|
|
74
|
+
))
|
|
75
|
+
|
|
76
|
+
service_names = {
|
|
77
|
+
getattr(service, "name", "")
|
|
78
|
+
for service in services
|
|
79
|
+
if getattr(service, "name", "")
|
|
80
|
+
}
|
|
81
|
+
missing_required = sorted(set(required_services) - service_names)
|
|
82
|
+
if service_names and not missing_required:
|
|
83
|
+
checks.append(CheckResult(
|
|
84
|
+
"service_boundaries",
|
|
85
|
+
"ok",
|
|
86
|
+
f"{len(service_names)} service manifests registered.",
|
|
87
|
+
))
|
|
88
|
+
elif missing_required:
|
|
89
|
+
checks.append(CheckResult(
|
|
90
|
+
"service_boundaries",
|
|
91
|
+
"fail",
|
|
92
|
+
f"Missing required services: {', '.join(missing_required)}.",
|
|
93
|
+
"Register service specs in packages.aria_services.",
|
|
94
|
+
))
|
|
95
|
+
else:
|
|
96
|
+
checks.append(CheckResult(
|
|
97
|
+
"service_boundaries",
|
|
98
|
+
"warn",
|
|
99
|
+
"No service manifests registered yet.",
|
|
100
|
+
"Add Gateway/Data/Reports/Brokers service specs.",
|
|
101
|
+
))
|
|
102
|
+
|
|
103
|
+
architecture_rows = list(architecture_layers or [])
|
|
104
|
+
required_layer_names = set(required_architecture_layers or [])
|
|
105
|
+
if architecture_rows or required_layer_names:
|
|
106
|
+
layer_names = {
|
|
107
|
+
getattr(layer, "name", "")
|
|
108
|
+
for layer in architecture_rows
|
|
109
|
+
if getattr(layer, "name", "")
|
|
110
|
+
}
|
|
111
|
+
missing_layers = sorted(required_layer_names - layer_names)
|
|
112
|
+
if missing_layers:
|
|
113
|
+
checks.append(CheckResult(
|
|
114
|
+
"architecture_layers",
|
|
115
|
+
"fail",
|
|
116
|
+
f"Missing architecture layers: {', '.join(missing_layers)}.",
|
|
117
|
+
"Update packages.aria_core.architecture.",
|
|
118
|
+
))
|
|
119
|
+
else:
|
|
120
|
+
incomplete = [
|
|
121
|
+
getattr(layer, "name", "")
|
|
122
|
+
for layer in architecture_rows
|
|
123
|
+
if _status_value(getattr(layer, "status", "")).lower() != "done"
|
|
124
|
+
]
|
|
125
|
+
if incomplete:
|
|
126
|
+
checks.append(CheckResult(
|
|
127
|
+
"architecture_layers",
|
|
128
|
+
"warn",
|
|
129
|
+
f"{len(layer_names)} layers registered; incomplete: {', '.join(incomplete[:6])}.",
|
|
130
|
+
"Prioritize context, settings, runtime, safety, and channel extraction.",
|
|
131
|
+
))
|
|
132
|
+
else:
|
|
133
|
+
checks.append(CheckResult(
|
|
134
|
+
"architecture_layers",
|
|
135
|
+
"ok",
|
|
136
|
+
f"{len(layer_names)} architecture layers complete.",
|
|
137
|
+
))
|
|
138
|
+
|
|
139
|
+
provider_rows = list(provider_health or [])
|
|
140
|
+
if not provider_rows:
|
|
141
|
+
checks.append(CheckResult(
|
|
142
|
+
"data_provider_health",
|
|
143
|
+
"warn",
|
|
144
|
+
"No provider calls recorded in this session.",
|
|
145
|
+
"Run /quote, /ta, /analyze, or /report first.",
|
|
146
|
+
))
|
|
147
|
+
else:
|
|
148
|
+
unhealthy = [
|
|
149
|
+
row for row in provider_rows
|
|
150
|
+
if row.get("status") not in ("ok", "", None)
|
|
151
|
+
]
|
|
152
|
+
if unhealthy:
|
|
153
|
+
checks.append(CheckResult(
|
|
154
|
+
"data_provider_health",
|
|
155
|
+
"warn",
|
|
156
|
+
"; ".join(
|
|
157
|
+
f"{row.get('provider')}={row.get('status')}"
|
|
158
|
+
for row in unhealthy[:5]
|
|
159
|
+
),
|
|
160
|
+
"Wait for cooldown, retry later, or switch provider/API key.",
|
|
161
|
+
))
|
|
162
|
+
else:
|
|
163
|
+
checks.append(CheckResult(
|
|
164
|
+
"data_provider_health",
|
|
165
|
+
"ok",
|
|
166
|
+
f"{len(provider_rows)} providers healthy.",
|
|
167
|
+
))
|
|
168
|
+
|
|
169
|
+
if arthera.available:
|
|
170
|
+
checks.append(CheckResult(
|
|
171
|
+
"arthera_packages",
|
|
172
|
+
"ok",
|
|
173
|
+
f"Found {len(arthera.packages)} package groups at {arthera.root}.",
|
|
174
|
+
))
|
|
175
|
+
else:
|
|
176
|
+
checks.append(CheckResult(
|
|
177
|
+
"arthera_packages",
|
|
178
|
+
"warn",
|
|
179
|
+
f"Not found at {arthera.root}.",
|
|
180
|
+
"Place Arthera at ~/Desktop/Arthera or configure the MCP server manually.",
|
|
181
|
+
))
|
|
182
|
+
|
|
183
|
+
if mcp_status.get("configured"):
|
|
184
|
+
checks.append(CheckResult(
|
|
185
|
+
"mcp_config",
|
|
186
|
+
"ok",
|
|
187
|
+
f"Configured in {mcp_status.get('config_path')}.",
|
|
188
|
+
))
|
|
189
|
+
else:
|
|
190
|
+
checks.append(CheckResult(
|
|
191
|
+
"mcp_config",
|
|
192
|
+
"warn",
|
|
193
|
+
f"No arthera_quant_engine server in {mcp_status.get('config_path')}.",
|
|
194
|
+
"Run /packages connect arthera.",
|
|
195
|
+
))
|
|
196
|
+
|
|
197
|
+
if mcp_status.get("server_file_exists"):
|
|
198
|
+
checks.append(CheckResult(
|
|
199
|
+
"mcp_server_file",
|
|
200
|
+
"ok",
|
|
201
|
+
str(mcp_status.get("server_path") or ""),
|
|
202
|
+
))
|
|
203
|
+
else:
|
|
204
|
+
checks.append(CheckResult(
|
|
205
|
+
"mcp_server_file",
|
|
206
|
+
"warn",
|
|
207
|
+
str(mcp_status.get("server_path") or "server path unavailable"),
|
|
208
|
+
"Verify <ARTHERA_ROOT>/packages/quant_engine/mcp_server.py exists (set ARTHERA_ROOT env var).",
|
|
209
|
+
))
|
|
210
|
+
|
|
211
|
+
if mcp_status.get("running"):
|
|
212
|
+
checks.append(CheckResult(
|
|
213
|
+
"mcp_runtime",
|
|
214
|
+
"ok",
|
|
215
|
+
f"Running with {mcp_status.get('tool_count', 0)} tools.",
|
|
216
|
+
))
|
|
217
|
+
else:
|
|
218
|
+
checks.append(CheckResult(
|
|
219
|
+
"mcp_runtime",
|
|
220
|
+
"warn",
|
|
221
|
+
"Arthera MCP server is not running.",
|
|
222
|
+
"Run /mcp reload or /packages connect arthera --reload.",
|
|
223
|
+
))
|
|
224
|
+
|
|
225
|
+
if tool_count > 0:
|
|
226
|
+
checks.append(CheckResult(
|
|
227
|
+
"mcp_tool_manifests",
|
|
228
|
+
"ok",
|
|
229
|
+
f"{tool_count} Arthera MCP tools mapped to Aria manifests.",
|
|
230
|
+
))
|
|
231
|
+
else:
|
|
232
|
+
checks.append(CheckResult(
|
|
233
|
+
"mcp_tool_manifests",
|
|
234
|
+
"warn",
|
|
235
|
+
"No Arthera MCP tools mapped yet.",
|
|
236
|
+
"Start the MCP server, then run /packages tools arthera.",
|
|
237
|
+
))
|
|
238
|
+
|
|
239
|
+
checks.append(CheckResult(
|
|
240
|
+
"manifest_export",
|
|
241
|
+
"ok" if manifest_can_export else "fail",
|
|
242
|
+
str(manifest_path),
|
|
243
|
+
"" if manifest_can_export else "Check artifact directory permissions.",
|
|
244
|
+
))
|
|
245
|
+
|
|
246
|
+
return PackageDoctorReport(status=_overall_status(checks), checks=checks)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Product identity for Aria Code inside the Arthera product line."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass
|
|
6
|
+
from typing import Dict, List
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class ProductIdentity:
|
|
11
|
+
company: str
|
|
12
|
+
product: str
|
|
13
|
+
package_name: str
|
|
14
|
+
version: str
|
|
15
|
+
description: str
|
|
16
|
+
product_family: List[str]
|
|
17
|
+
|
|
18
|
+
def to_dict(self) -> Dict[str, object]:
|
|
19
|
+
return asdict(self)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def aria_code_identity(version: str = "3.0.0") -> ProductIdentity:
|
|
23
|
+
return ProductIdentity(
|
|
24
|
+
company="Arthera",
|
|
25
|
+
product="Aria Code",
|
|
26
|
+
package_name="aria-code",
|
|
27
|
+
version=version,
|
|
28
|
+
description="Local-first coding and quantitative research agent by Arthera.",
|
|
29
|
+
product_family=[
|
|
30
|
+
"Aria Code",
|
|
31
|
+
"Aria Gateway",
|
|
32
|
+
"Arthera Quant Engine",
|
|
33
|
+
"Arthera Broker Bridge",
|
|
34
|
+
"Arthera ML/LLM",
|
|
35
|
+
"Arthera Reporting",
|
|
36
|
+
],
|
|
37
|
+
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""MCP bridge facade."""
|
|
2
|
+
|
|
3
|
+
from .bridge import MCPExposure, default_exposures
|
|
4
|
+
from .config import (
|
|
5
|
+
arthera_quant_engine_server_config,
|
|
6
|
+
find_server_config,
|
|
7
|
+
load_mcp_config,
|
|
8
|
+
merge_server_config,
|
|
9
|
+
mcp_server_status,
|
|
10
|
+
write_mcp_config,
|
|
11
|
+
)
|
|
12
|
+
from .tools import mcp_tool_to_spec, mcp_tools_to_specs
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"MCPExposure",
|
|
16
|
+
"arthera_quant_engine_server_config",
|
|
17
|
+
"default_exposures",
|
|
18
|
+
"find_server_config",
|
|
19
|
+
"load_mcp_config",
|
|
20
|
+
"merge_server_config",
|
|
21
|
+
"mcp_server_status",
|
|
22
|
+
"mcp_tool_to_spec",
|
|
23
|
+
"mcp_tools_to_specs",
|
|
24
|
+
"write_mcp_config",
|
|
25
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Describe how Aria packages should be exposed over MCP."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Dict, List
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class MCPExposure:
|
|
11
|
+
name: str
|
|
12
|
+
target: str
|
|
13
|
+
description: str
|
|
14
|
+
read_only: bool = True
|
|
15
|
+
|
|
16
|
+
def to_tool_descriptor(self) -> Dict[str, object]:
|
|
17
|
+
return {
|
|
18
|
+
"name": self.name,
|
|
19
|
+
"description": self.description,
|
|
20
|
+
"target": self.target,
|
|
21
|
+
"read_only": self.read_only,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def default_exposures() -> List[MCPExposure]:
|
|
26
|
+
"""Initial MCP server surface for Aria Code.
|
|
27
|
+
|
|
28
|
+
These names are stable contracts. The server implementation can bind them
|
|
29
|
+
to ToolRegistry/AgentRegistry without changing client-facing tool names.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
return [
|
|
33
|
+
MCPExposure("aria.market.quote", "tool:get_market_data", "Fetch quote and technical market snapshot."),
|
|
34
|
+
MCPExposure("aria.agent.team", "agent:team", "Run multi-agent financial research."),
|
|
35
|
+
MCPExposure("aria.report.generate", "skill:financial-research", "Generate a local research artifact.", read_only=False),
|
|
36
|
+
MCPExposure("aria.backtest.run", "skill:strategy-backtest", "Run a historical strategy simulation.", read_only=False),
|
|
37
|
+
MCPExposure("aria.artifacts.list", "infra:artifacts", "List local generated artifacts."),
|
|
38
|
+
]
|