nao-core 0.0.38__py3-none-manylinux2014_aarch64.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.
- nao_core/__init__.py +2 -0
- nao_core/__init__.py.bak +2 -0
- nao_core/bin/build-info.json +5 -0
- nao_core/bin/fastapi/main.py +268 -0
- nao_core/bin/fastapi/test_main.py +156 -0
- nao_core/bin/migrations-postgres/0000_user_auth_and_chat_tables.sql +98 -0
- nao_core/bin/migrations-postgres/0001_message_feedback.sql +9 -0
- nao_core/bin/migrations-postgres/0002_chat_message_stop_reason_and_error_message.sql +2 -0
- nao_core/bin/migrations-postgres/0003_handle_slack_with_thread.sql +2 -0
- nao_core/bin/migrations-postgres/0004_input_and_output_tokens.sql +8 -0
- nao_core/bin/migrations-postgres/0005_add_project_tables.sql +39 -0
- nao_core/bin/migrations-postgres/0006_llm_model_ids.sql +4 -0
- nao_core/bin/migrations-postgres/0007_chat_message_llm_info.sql +2 -0
- nao_core/bin/migrations-postgres/meta/0000_snapshot.json +707 -0
- nao_core/bin/migrations-postgres/meta/0001_snapshot.json +766 -0
- nao_core/bin/migrations-postgres/meta/0002_snapshot.json +778 -0
- nao_core/bin/migrations-postgres/meta/0003_snapshot.json +799 -0
- nao_core/bin/migrations-postgres/meta/0004_snapshot.json +847 -0
- nao_core/bin/migrations-postgres/meta/0005_snapshot.json +1129 -0
- nao_core/bin/migrations-postgres/meta/0006_snapshot.json +1141 -0
- nao_core/bin/migrations-postgres/meta/_journal.json +62 -0
- nao_core/bin/migrations-sqlite/0000_user_auth_and_chat_tables.sql +98 -0
- nao_core/bin/migrations-sqlite/0001_message_feedback.sql +8 -0
- nao_core/bin/migrations-sqlite/0002_chat_message_stop_reason_and_error_message.sql +2 -0
- nao_core/bin/migrations-sqlite/0003_handle_slack_with_thread.sql +2 -0
- nao_core/bin/migrations-sqlite/0004_input_and_output_tokens.sql +8 -0
- nao_core/bin/migrations-sqlite/0005_add_project_tables.sql +38 -0
- nao_core/bin/migrations-sqlite/0006_llm_model_ids.sql +4 -0
- nao_core/bin/migrations-sqlite/0007_chat_message_llm_info.sql +2 -0
- nao_core/bin/migrations-sqlite/meta/0000_snapshot.json +674 -0
- nao_core/bin/migrations-sqlite/meta/0001_snapshot.json +735 -0
- nao_core/bin/migrations-sqlite/meta/0002_snapshot.json +749 -0
- nao_core/bin/migrations-sqlite/meta/0003_snapshot.json +763 -0
- nao_core/bin/migrations-sqlite/meta/0004_snapshot.json +819 -0
- nao_core/bin/migrations-sqlite/meta/0005_snapshot.json +1086 -0
- nao_core/bin/migrations-sqlite/meta/0006_snapshot.json +1100 -0
- nao_core/bin/migrations-sqlite/meta/_journal.json +62 -0
- nao_core/bin/nao-chat-server +0 -0
- nao_core/bin/public/assets/code-block-F6WJLWQG-CV0uOmNJ.js +153 -0
- nao_core/bin/public/assets/index-DcbndLHo.css +1 -0
- nao_core/bin/public/assets/index-t1hZI3nl.js +560 -0
- nao_core/bin/public/favicon.ico +0 -0
- nao_core/bin/public/index.html +18 -0
- nao_core/bin/rg +0 -0
- nao_core/commands/__init__.py +6 -0
- nao_core/commands/chat.py +225 -0
- nao_core/commands/debug.py +158 -0
- nao_core/commands/init.py +358 -0
- nao_core/commands/sync/__init__.py +124 -0
- nao_core/commands/sync/accessors.py +290 -0
- nao_core/commands/sync/cleanup.py +156 -0
- nao_core/commands/sync/providers/__init__.py +32 -0
- nao_core/commands/sync/providers/base.py +113 -0
- nao_core/commands/sync/providers/databases/__init__.py +17 -0
- nao_core/commands/sync/providers/databases/bigquery.py +79 -0
- nao_core/commands/sync/providers/databases/databricks.py +79 -0
- nao_core/commands/sync/providers/databases/duckdb.py +78 -0
- nao_core/commands/sync/providers/databases/postgres.py +79 -0
- nao_core/commands/sync/providers/databases/provider.py +129 -0
- nao_core/commands/sync/providers/databases/snowflake.py +79 -0
- nao_core/commands/sync/providers/notion/__init__.py +5 -0
- nao_core/commands/sync/providers/notion/provider.py +205 -0
- nao_core/commands/sync/providers/repositories/__init__.py +5 -0
- nao_core/commands/sync/providers/repositories/provider.py +134 -0
- nao_core/commands/sync/registry.py +23 -0
- nao_core/config/__init__.py +30 -0
- nao_core/config/base.py +100 -0
- nao_core/config/databases/__init__.py +55 -0
- nao_core/config/databases/base.py +85 -0
- nao_core/config/databases/bigquery.py +99 -0
- nao_core/config/databases/databricks.py +79 -0
- nao_core/config/databases/duckdb.py +41 -0
- nao_core/config/databases/postgres.py +83 -0
- nao_core/config/databases/snowflake.py +125 -0
- nao_core/config/exceptions.py +7 -0
- nao_core/config/llm/__init__.py +19 -0
- nao_core/config/notion/__init__.py +8 -0
- nao_core/config/repos/__init__.py +3 -0
- nao_core/config/repos/base.py +11 -0
- nao_core/config/slack/__init__.py +12 -0
- nao_core/context/__init__.py +54 -0
- nao_core/context/base.py +57 -0
- nao_core/context/git.py +177 -0
- nao_core/context/local.py +59 -0
- nao_core/main.py +13 -0
- nao_core/templates/__init__.py +41 -0
- nao_core/templates/context.py +193 -0
- nao_core/templates/defaults/databases/columns.md.j2 +23 -0
- nao_core/templates/defaults/databases/description.md.j2 +32 -0
- nao_core/templates/defaults/databases/preview.md.j2 +22 -0
- nao_core/templates/defaults/databases/profiling.md.j2 +34 -0
- nao_core/templates/engine.py +133 -0
- nao_core/templates/render.py +196 -0
- nao_core-0.0.38.dist-info/METADATA +150 -0
- nao_core-0.0.38.dist-info/RECORD +98 -0
- nao_core-0.0.38.dist-info/WHEEL +4 -0
- nao_core-0.0.38.dist-info/entry_points.txt +2 -0
- nao_core-0.0.38.dist-info/licenses/LICENSE +22 -0
|
Binary file
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<link rel="icon" href="/favicon.ico" />
|
|
7
|
+
<meta name="theme-color" content="#000000" />
|
|
8
|
+
<meta name="description" content="Web site created using create-tsrouter-app" />
|
|
9
|
+
<link rel="apple-touch-icon" href="/logo192.png" />
|
|
10
|
+
<link rel="manifest" href="/manifest.json" />
|
|
11
|
+
<title>nao — Chat with your data</title>
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-t1hZI3nl.js"></script>
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DcbndLHo.css">
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<div id="app"></div>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
nao_core/bin/rg
ADDED
|
Binary file
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import secrets
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
import webbrowser
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from time import sleep
|
|
8
|
+
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
|
|
11
|
+
from nao_core.config import NaoConfig
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
# Default port for the nao chat server
|
|
16
|
+
SERVER_PORT = 5005
|
|
17
|
+
FASTAPI_PORT = 8005
|
|
18
|
+
SECRET_FILE_NAME = ".nao-secret"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_server_binary_path() -> Path:
|
|
22
|
+
"""Get the path to the bundled nao-chat-server binary."""
|
|
23
|
+
# The binary is in the bin folder relative to this file
|
|
24
|
+
cli_dir = Path(__file__).parent.parent
|
|
25
|
+
bin_dir = cli_dir / "bin"
|
|
26
|
+
binary_path = bin_dir / "nao-chat-server"
|
|
27
|
+
|
|
28
|
+
if not binary_path.exists():
|
|
29
|
+
console.print(f"[bold red]✗[/bold red] Server binary not found at {binary_path}")
|
|
30
|
+
console.print("[dim]Make sure you've built the server with ./scripts/build-server.sh[/dim]")
|
|
31
|
+
sys.exit(1)
|
|
32
|
+
|
|
33
|
+
return binary_path
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_fastapi_main_path() -> Path:
|
|
37
|
+
"""Get the path to the FastAPI main.py file."""
|
|
38
|
+
cli_dir = Path(__file__).parent.parent
|
|
39
|
+
bin_dir = cli_dir / "bin"
|
|
40
|
+
fastapi_path = bin_dir / "fastapi" / "main.py"
|
|
41
|
+
|
|
42
|
+
if not fastapi_path.exists():
|
|
43
|
+
console.print(f"[bold red]✗[/bold red] FastAPI main.py not found at {fastapi_path}")
|
|
44
|
+
sys.exit(1)
|
|
45
|
+
|
|
46
|
+
return fastapi_path
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def wait_for_server(port: int, timeout: int = 30) -> bool:
|
|
50
|
+
"""Wait for the server to be ready."""
|
|
51
|
+
import socket
|
|
52
|
+
|
|
53
|
+
for _ in range(timeout * 10): # Check every 100ms
|
|
54
|
+
try:
|
|
55
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
56
|
+
sock.settimeout(0.1)
|
|
57
|
+
result = sock.connect_ex(("localhost", port))
|
|
58
|
+
if result == 0:
|
|
59
|
+
return True
|
|
60
|
+
except OSError:
|
|
61
|
+
pass
|
|
62
|
+
sleep(0.1)
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def ensure_auth_secret(bin_dir: Path) -> str | None:
|
|
67
|
+
"""Ensure auth secret exists, generating one if needed.
|
|
68
|
+
|
|
69
|
+
Returns the secret value if one was loaded/generated, or None if
|
|
70
|
+
BETTER_AUTH_SECRET is already set in the environment.
|
|
71
|
+
"""
|
|
72
|
+
# If already set via environment, nothing to do
|
|
73
|
+
if os.environ.get("BETTER_AUTH_SECRET"):
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
secret_path = bin_dir / SECRET_FILE_NAME
|
|
77
|
+
|
|
78
|
+
# Try to load existing secret from file
|
|
79
|
+
if secret_path.exists():
|
|
80
|
+
try:
|
|
81
|
+
secret = secret_path.read_text().strip()
|
|
82
|
+
if secret:
|
|
83
|
+
console.print(f"[bold green]✓[/bold green] Loaded auth secret from {secret_path}")
|
|
84
|
+
return secret
|
|
85
|
+
except Exception:
|
|
86
|
+
pass # Fall through to generate new secret
|
|
87
|
+
|
|
88
|
+
# Generate and save new secret
|
|
89
|
+
new_secret = secrets.token_urlsafe(32)
|
|
90
|
+
try:
|
|
91
|
+
secret_path.write_text(new_secret)
|
|
92
|
+
# Set restrictive permissions (owner read/write only)
|
|
93
|
+
secret_path.chmod(0o600)
|
|
94
|
+
console.print(f"[bold green]✓[/bold green] Generated new auth secret and saved to {secret_path}")
|
|
95
|
+
return new_secret
|
|
96
|
+
except Exception as e:
|
|
97
|
+
console.print(f"[bold yellow]⚠[/bold yellow] Could not save auth secret to {secret_path}: {e}")
|
|
98
|
+
console.print("[dim]Sessions will not persist across restarts[/dim]")
|
|
99
|
+
return new_secret
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def chat():
|
|
103
|
+
"""Start the nao chat UI.
|
|
104
|
+
|
|
105
|
+
Launches the nao chat server and opens the web interface in your browser.
|
|
106
|
+
"""
|
|
107
|
+
console.print("\n[bold cyan]💬 Starting nao chat...[/bold cyan]\n")
|
|
108
|
+
|
|
109
|
+
# Try to load nao config from current directory
|
|
110
|
+
config = NaoConfig.try_load()
|
|
111
|
+
if config:
|
|
112
|
+
console.print(f"[bold green]✓[/bold green] Loaded config from {Path.cwd() / 'nao_config.yaml'}")
|
|
113
|
+
else:
|
|
114
|
+
console.print(
|
|
115
|
+
"[bold red]✗No nao_config.yaml found in current directory. Please move to a nao project directory.[/bold red]"
|
|
116
|
+
)
|
|
117
|
+
sys.exit(1)
|
|
118
|
+
|
|
119
|
+
binary_path = get_server_binary_path()
|
|
120
|
+
bin_dir = binary_path.parent
|
|
121
|
+
|
|
122
|
+
console.print(f"[dim]Server binary: {binary_path}[/dim]")
|
|
123
|
+
console.print(f"[dim]Working directory: {bin_dir}[/dim]")
|
|
124
|
+
|
|
125
|
+
# Start the server processes
|
|
126
|
+
chat_process = None
|
|
127
|
+
fastapi_process = None
|
|
128
|
+
|
|
129
|
+
def shutdown_servers():
|
|
130
|
+
"""Gracefully shut down both server processes."""
|
|
131
|
+
for name, proc in [("Chat server", chat_process), ("FastAPI server", fastapi_process)]:
|
|
132
|
+
if proc:
|
|
133
|
+
proc.terminate()
|
|
134
|
+
try:
|
|
135
|
+
proc.wait(timeout=5)
|
|
136
|
+
except subprocess.TimeoutExpired:
|
|
137
|
+
proc.kill()
|
|
138
|
+
proc.wait()
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
# Set up environment - inherit from parent but ensure we're in the bin dir
|
|
142
|
+
# so the server can find the public folder
|
|
143
|
+
env = os.environ.copy()
|
|
144
|
+
|
|
145
|
+
# Ensure auth secret is available
|
|
146
|
+
auth_secret = ensure_auth_secret(bin_dir)
|
|
147
|
+
if auth_secret:
|
|
148
|
+
env["BETTER_AUTH_SECRET"] = auth_secret
|
|
149
|
+
|
|
150
|
+
# Set LLM API key from config if available
|
|
151
|
+
if config and config.llm:
|
|
152
|
+
env_var_name = f"{config.llm.provider.upper()}_API_KEY"
|
|
153
|
+
env[env_var_name] = config.llm.api_key
|
|
154
|
+
console.print(f"[bold green]✓[/bold green] Set {env_var_name} from config")
|
|
155
|
+
|
|
156
|
+
# Set Slack config if available
|
|
157
|
+
if config and config.slack:
|
|
158
|
+
env["SLACK_BOT_TOKEN"] = config.slack.bot_token
|
|
159
|
+
env["SLACK_SIGNING_SECRET"] = config.slack.signing_secret
|
|
160
|
+
console.print("[bold green]✓[/bold green] Set Slack environment variables from config")
|
|
161
|
+
|
|
162
|
+
env["NAO_DEFAULT_PROJECT_PATH"] = str(Path.cwd())
|
|
163
|
+
env["FASTAPI_URL"] = f"http://localhost:{FASTAPI_PORT}"
|
|
164
|
+
|
|
165
|
+
# Start the FastAPI server first
|
|
166
|
+
fastapi_path = get_fastapi_main_path()
|
|
167
|
+
console.print(f"[dim]FastAPI server: {fastapi_path}[/dim]")
|
|
168
|
+
|
|
169
|
+
fastapi_process = subprocess.Popen(
|
|
170
|
+
[sys.executable, str(fastapi_path)],
|
|
171
|
+
env=env,
|
|
172
|
+
stdout=subprocess.DEVNULL,
|
|
173
|
+
stderr=subprocess.DEVNULL,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
console.print("[bold green]✓[/bold green] FastAPI server starting...")
|
|
177
|
+
|
|
178
|
+
# Wait for FastAPI server to be ready
|
|
179
|
+
if wait_for_server(FASTAPI_PORT):
|
|
180
|
+
console.print(f"[bold green]✓[/bold green] FastAPI server ready at http://localhost:{FASTAPI_PORT}")
|
|
181
|
+
else:
|
|
182
|
+
console.print("[bold yellow]⚠[/bold yellow] FastAPI server is taking longer than expected to start...")
|
|
183
|
+
|
|
184
|
+
# Start the chat server
|
|
185
|
+
chat_process = subprocess.Popen(
|
|
186
|
+
[str(binary_path)],
|
|
187
|
+
cwd=str(bin_dir),
|
|
188
|
+
env=env,
|
|
189
|
+
stdout=subprocess.PIPE,
|
|
190
|
+
stderr=subprocess.STDOUT,
|
|
191
|
+
text=True,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
console.print("[bold green]✓[/bold green] Chat server starting...")
|
|
195
|
+
|
|
196
|
+
# Wait for the chat server to be ready
|
|
197
|
+
if wait_for_server(SERVER_PORT):
|
|
198
|
+
url = f"http://localhost:{SERVER_PORT}"
|
|
199
|
+
console.print(f"[bold green]✓[/bold green] Chat server ready at {url}")
|
|
200
|
+
console.print("\n[bold]Opening browser...[/bold]")
|
|
201
|
+
webbrowser.open(url)
|
|
202
|
+
console.print("\n[dim]Press Ctrl+C to stop the servers[/dim]\n")
|
|
203
|
+
else:
|
|
204
|
+
console.print("[bold yellow]⚠[/bold yellow] Chat server is taking longer than expected to start...")
|
|
205
|
+
console.print(f"[dim]Check http://localhost:{SERVER_PORT} manually[/dim]")
|
|
206
|
+
|
|
207
|
+
# Stream chat server output to console
|
|
208
|
+
if chat_process.stdout:
|
|
209
|
+
for line in chat_process.stdout:
|
|
210
|
+
# Filter out some of the verbose logging if needed
|
|
211
|
+
console.print(f"[dim]{line.rstrip()}[/dim]")
|
|
212
|
+
|
|
213
|
+
# Wait for process to complete
|
|
214
|
+
chat_process.wait()
|
|
215
|
+
|
|
216
|
+
except KeyboardInterrupt:
|
|
217
|
+
console.print("\n[bold yellow]Shutting down...[/bold yellow]")
|
|
218
|
+
shutdown_servers()
|
|
219
|
+
console.print("[bold green]✓[/bold green] Servers stopped")
|
|
220
|
+
sys.exit(0)
|
|
221
|
+
|
|
222
|
+
except Exception as e:
|
|
223
|
+
console.print(f"[bold red]✗[/bold red] Failed to start servers: {e}")
|
|
224
|
+
shutdown_servers()
|
|
225
|
+
sys.exit(1)
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.table import Table
|
|
5
|
+
|
|
6
|
+
from nao_core.config import NaoConfig
|
|
7
|
+
from nao_core.config.databases import AnyDatabaseConfig
|
|
8
|
+
|
|
9
|
+
console = Console()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_database_connection(db_config: AnyDatabaseConfig) -> tuple[bool, str]:
|
|
13
|
+
"""Test connectivity to a database.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
Tuple of (success, message)
|
|
17
|
+
"""
|
|
18
|
+
try:
|
|
19
|
+
conn = db_config.connect()
|
|
20
|
+
# Run a simple query to verify the connection works
|
|
21
|
+
if hasattr(db_config, "dataset_id") and db_config.dataset_id:
|
|
22
|
+
# If dataset is specified, list tables in that dataset
|
|
23
|
+
tables = conn.list_tables()
|
|
24
|
+
table_count = len(tables)
|
|
25
|
+
return True, f"Connected successfully ({table_count} tables found)"
|
|
26
|
+
elif list_databases := getattr(conn, "list_databases", None):
|
|
27
|
+
# If no dataset, list schemas in the database instead
|
|
28
|
+
schemas = list_databases()
|
|
29
|
+
schema_count = len(schemas)
|
|
30
|
+
return True, f"Connected successfully ({schema_count} schemas found)"
|
|
31
|
+
else:
|
|
32
|
+
# Fallback for backends that don't support list_tables and list_databases
|
|
33
|
+
return True, "Connected but unable to list neither datasets nor schemas"
|
|
34
|
+
except Exception as e:
|
|
35
|
+
return False, str(e)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_llm_connection(llm_config) -> tuple[bool, str]:
|
|
39
|
+
"""Test connectivity to an LLM provider.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Tuple of (success, message)
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
if llm_config.provider.value == "openai":
|
|
46
|
+
import openai
|
|
47
|
+
|
|
48
|
+
client = openai.OpenAI(api_key=llm_config.api_key)
|
|
49
|
+
# Make a minimal API call to verify the key works
|
|
50
|
+
models = client.models.list()
|
|
51
|
+
# Just check we can iterate (don't need to consume all)
|
|
52
|
+
model_count = sum(1 for _ in models)
|
|
53
|
+
return True, f"Connected successfully ({model_count} models available)"
|
|
54
|
+
elif llm_config.provider.value == "anthropic":
|
|
55
|
+
from anthropic import Anthropic
|
|
56
|
+
|
|
57
|
+
client = Anthropic(api_key=llm_config.api_key)
|
|
58
|
+
|
|
59
|
+
models = client.models.list()
|
|
60
|
+
|
|
61
|
+
model_count = sum(1 for _ in models)
|
|
62
|
+
return True, f"Connected successfully ({model_count} models available)"
|
|
63
|
+
else:
|
|
64
|
+
return False, f"Unknown provider: {llm_config.provider}"
|
|
65
|
+
except Exception as e:
|
|
66
|
+
return False, str(e)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def debug():
|
|
70
|
+
"""Test connectivity to configured databases and LLMs.
|
|
71
|
+
|
|
72
|
+
Loads the nao configuration from the current directory and tests
|
|
73
|
+
connections to all configured databases and LLM providers.
|
|
74
|
+
"""
|
|
75
|
+
console.print("\n[bold cyan]🔍 nao debug - Testing connections...[/bold cyan]\n")
|
|
76
|
+
|
|
77
|
+
# Load config
|
|
78
|
+
config = NaoConfig.try_load()
|
|
79
|
+
if not config:
|
|
80
|
+
console.print("[bold red]✗[/bold red] No nao_config.yaml found in current directory")
|
|
81
|
+
console.print("[dim]Run 'nao init' to create a configuration file[/dim]")
|
|
82
|
+
sys.exit(1)
|
|
83
|
+
assert config is not None # Help type checker after sys.exit
|
|
84
|
+
|
|
85
|
+
console.print(f"[bold green]✓[/bold green] Loaded config: [cyan]{config.project_name}[/cyan]\n")
|
|
86
|
+
|
|
87
|
+
# Test databases
|
|
88
|
+
if config.databases:
|
|
89
|
+
console.print("[bold]Databases:[/bold]")
|
|
90
|
+
db_table = Table(show_header=True, header_style="bold")
|
|
91
|
+
db_table.add_column("Name")
|
|
92
|
+
db_table.add_column("Type")
|
|
93
|
+
db_table.add_column("Status")
|
|
94
|
+
db_table.add_column("Details")
|
|
95
|
+
|
|
96
|
+
for db in config.databases:
|
|
97
|
+
console.print(f" Testing [cyan]{db.name}[/cyan]...", end=" ")
|
|
98
|
+
success, message = test_database_connection(db)
|
|
99
|
+
|
|
100
|
+
if success:
|
|
101
|
+
console.print("[bold green]✓[/bold green]")
|
|
102
|
+
db_table.add_row(
|
|
103
|
+
db.name,
|
|
104
|
+
db.type,
|
|
105
|
+
"[green]Connected[/green]",
|
|
106
|
+
message,
|
|
107
|
+
)
|
|
108
|
+
else:
|
|
109
|
+
console.print("[bold red]✗[/bold red]")
|
|
110
|
+
# Truncate long error messages
|
|
111
|
+
short_msg = message[:80] + "..." if len(message) > 80 else message
|
|
112
|
+
db_table.add_row(
|
|
113
|
+
db.name,
|
|
114
|
+
db.type,
|
|
115
|
+
"[red]Failed[/red]",
|
|
116
|
+
short_msg,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
console.print()
|
|
120
|
+
console.print(db_table)
|
|
121
|
+
else:
|
|
122
|
+
console.print("[dim]No databases configured[/dim]")
|
|
123
|
+
|
|
124
|
+
console.print()
|
|
125
|
+
|
|
126
|
+
# Test LLM
|
|
127
|
+
if config.llm:
|
|
128
|
+
console.print("[bold]LLM Provider:[/bold]")
|
|
129
|
+
llm_table = Table(show_header=True, header_style="bold")
|
|
130
|
+
llm_table.add_column("Provider")
|
|
131
|
+
llm_table.add_column("Status")
|
|
132
|
+
llm_table.add_column("Details")
|
|
133
|
+
|
|
134
|
+
console.print(f" Testing [cyan]{config.llm.provider.value}[/cyan]...", end=" ")
|
|
135
|
+
success, message = test_llm_connection(config.llm)
|
|
136
|
+
|
|
137
|
+
if success:
|
|
138
|
+
console.print("[bold green]✓[/bold green]")
|
|
139
|
+
llm_table.add_row(
|
|
140
|
+
config.llm.provider.value,
|
|
141
|
+
"[green]Connected[/green]",
|
|
142
|
+
message,
|
|
143
|
+
)
|
|
144
|
+
else:
|
|
145
|
+
console.print("[bold red]✗[/bold red]")
|
|
146
|
+
short_msg = message[:80] + "..." if len(message) > 80 else message
|
|
147
|
+
llm_table.add_row(
|
|
148
|
+
config.llm.provider.value,
|
|
149
|
+
"[red]Failed[/red]",
|
|
150
|
+
short_msg,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
console.print()
|
|
154
|
+
console.print(llm_table)
|
|
155
|
+
else:
|
|
156
|
+
console.print("[dim]No LLM configured[/dim]")
|
|
157
|
+
|
|
158
|
+
console.print()
|