synth-ai 0.2.4.dev7__py3-none-any.whl → 0.2.4.dev8__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.
- synth_ai/__init__.py +1 -1
- synth_ai/cli/balance.py +3 -15
- synth_ai/config/base_url.py +47 -0
- synth_ai/http.py +102 -0
- synth_ai/inference/__init__.py +7 -0
- synth_ai/inference/client.py +20 -0
- synth_ai/jobs/client.py +246 -0
- synth_ai/learning/__init__.py +24 -0
- synth_ai/learning/client.py +149 -0
- synth_ai/learning/config.py +43 -0
- synth_ai/learning/constants.py +29 -0
- synth_ai/learning/ft_client.py +59 -0
- synth_ai/learning/health.py +43 -0
- synth_ai/learning/jobs.py +205 -0
- synth_ai/learning/rl_client.py +256 -0
- synth_ai/learning/sse.py +58 -0
- synth_ai/learning/validators.py +48 -0
- synth_ai/lm/core/main_v3.py +13 -0
- synth_ai/lm/core/synth_models.py +48 -0
- synth_ai/lm/core/vendor_clients.py +9 -6
- synth_ai/lm/vendors/core/openai_api.py +31 -3
- synth_ai/lm/vendors/openai_standard.py +45 -14
- synth_ai/lm/vendors/supported/custom_endpoint.py +12 -2
- synth_ai/lm/vendors/synth_client.py +372 -28
- synth_ai/rl/__init__.py +30 -0
- synth_ai/rl/contracts.py +32 -0
- synth_ai/rl/env_keys.py +137 -0
- synth_ai/rl/secrets.py +19 -0
- synth_ai/scripts/verify_rewards.py +100 -0
- synth_ai/task/__init__.py +10 -0
- synth_ai/task/contracts.py +120 -0
- synth_ai/task/health.py +28 -0
- synth_ai/task/validators.py +12 -0
- synth_ai/tracing_v3/hooks.py +3 -1
- synth_ai/tracing_v3/session_tracer.py +123 -2
- synth_ai/tracing_v3/turso/manager.py +218 -0
- synth_ai/tracing_v3/turso/models.py +53 -0
- synth_ai-0.2.4.dev8.dist-info/METADATA +635 -0
- {synth_ai-0.2.4.dev7.dist-info → synth_ai-0.2.4.dev8.dist-info}/RECORD +43 -25
- synth_ai/tui/__init__.py +0 -1
- synth_ai/tui/__main__.py +0 -13
- synth_ai/tui/cli/__init__.py +0 -1
- synth_ai/tui/cli/query_experiments.py +0 -164
- synth_ai/tui/cli/query_experiments_v3.py +0 -164
- synth_ai/tui/dashboard.py +0 -340
- synth_ai-0.2.4.dev7.dist-info/METADATA +0 -193
- {synth_ai-0.2.4.dev7.dist-info → synth_ai-0.2.4.dev8.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.4.dev7.dist-info → synth_ai-0.2.4.dev8.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.4.dev7.dist-info → synth_ai-0.2.4.dev8.dist-info}/licenses/LICENSE +0 -0
- {synth_ai-0.2.4.dev7.dist-info → synth_ai-0.2.4.dev8.dist-info}/top_level.txt +0 -0
synth_ai/tui/dashboard.py
DELETED
@@ -1,340 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Interactive TUI Dashboard for Synth AI experiments.
|
4
|
-
|
5
|
-
Launch with: python -m synth_ai.tui.dashboard
|
6
|
-
"""
|
7
|
-
|
8
|
-
import logging
|
9
|
-
from datetime import datetime
|
10
|
-
from urllib.parse import urlparse
|
11
|
-
|
12
|
-
from textual import on
|
13
|
-
from textual.app import App, ComposeResult
|
14
|
-
from textual.binding import Binding
|
15
|
-
from textual.containers import Container
|
16
|
-
from textual.reactive import reactive
|
17
|
-
from textual.timer import Timer
|
18
|
-
from textual.widgets import (
|
19
|
-
DataTable,
|
20
|
-
Footer,
|
21
|
-
Header,
|
22
|
-
Static,
|
23
|
-
)
|
24
|
-
|
25
|
-
from ..tracing_v3.turso.manager import AsyncSQLTraceManager
|
26
|
-
|
27
|
-
|
28
|
-
class ExperimentRow:
|
29
|
-
"""Data structure for experiment display."""
|
30
|
-
|
31
|
-
def __init__(
|
32
|
-
self,
|
33
|
-
exp_id: str,
|
34
|
-
name: str,
|
35
|
-
description: str,
|
36
|
-
created_at: datetime,
|
37
|
-
sessions: int,
|
38
|
-
events: int,
|
39
|
-
messages: int,
|
40
|
-
cost: float,
|
41
|
-
tokens: int,
|
42
|
-
):
|
43
|
-
self.exp_id = exp_id
|
44
|
-
self.name = name or "Unnamed"
|
45
|
-
self.description = description or ""
|
46
|
-
self.created_at = created_at
|
47
|
-
self.sessions = sessions
|
48
|
-
self.events = events
|
49
|
-
self.messages = messages
|
50
|
-
self.cost = cost
|
51
|
-
self.tokens = tokens
|
52
|
-
|
53
|
-
def to_row(self) -> list[str]:
|
54
|
-
"""Convert to table row format."""
|
55
|
-
return [
|
56
|
-
self.exp_id[:8], # Shortened ID
|
57
|
-
self.name[:20], # Truncated name
|
58
|
-
str(self.sessions),
|
59
|
-
str(self.events),
|
60
|
-
str(self.messages),
|
61
|
-
f"${self.cost:.4f}",
|
62
|
-
f"{self.tokens:,}",
|
63
|
-
self.created_at.strftime("%H:%M"),
|
64
|
-
]
|
65
|
-
|
66
|
-
|
67
|
-
class ExperimentTable(DataTable):
|
68
|
-
"""Custom DataTable for experiments with refresh capability."""
|
69
|
-
|
70
|
-
def __init__(self, **kwargs):
|
71
|
-
super().__init__(**kwargs)
|
72
|
-
self.experiments: list[ExperimentRow] = []
|
73
|
-
self.selected_exp_id: str | None = None
|
74
|
-
|
75
|
-
def setup_table(self):
|
76
|
-
"""Initialize table columns."""
|
77
|
-
self.add_columns("ID", "Name", "Sessions", "Events", "Messages", "Cost", "Tokens", "Time")
|
78
|
-
|
79
|
-
async def refresh_data(self, db_manager: AsyncSQLTraceManager):
|
80
|
-
"""Refresh experiment data from database."""
|
81
|
-
try:
|
82
|
-
# Get experiment list with stats using raw query
|
83
|
-
df = await db_manager.query_traces("""
|
84
|
-
SELECT
|
85
|
-
e.experiment_id,
|
86
|
-
e.name,
|
87
|
-
e.description,
|
88
|
-
e.created_at,
|
89
|
-
COUNT(DISTINCT st.session_id) as num_sessions,
|
90
|
-
COUNT(DISTINCT ev.id) as num_events,
|
91
|
-
COUNT(DISTINCT m.id) as num_messages,
|
92
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.cost_usd ELSE 0 END) / 100.0 as total_cost,
|
93
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.total_tokens ELSE 0 END) as total_tokens
|
94
|
-
FROM experiments e
|
95
|
-
LEFT JOIN session_traces st ON e.experiment_id = st.experiment_id
|
96
|
-
LEFT JOIN events ev ON st.session_id = ev.session_id
|
97
|
-
LEFT JOIN messages m ON st.session_id = m.session_id
|
98
|
-
GROUP BY e.experiment_id, e.name, e.description, e.created_at
|
99
|
-
ORDER BY e.created_at DESC
|
100
|
-
""")
|
101
|
-
|
102
|
-
self.experiments.clear()
|
103
|
-
self.clear()
|
104
|
-
|
105
|
-
if not df.empty:
|
106
|
-
for _, row in df.iterrows():
|
107
|
-
exp_row = ExperimentRow(
|
108
|
-
exp_id=row["experiment_id"],
|
109
|
-
name=row["name"],
|
110
|
-
description=row["description"],
|
111
|
-
created_at=row["created_at"],
|
112
|
-
sessions=int(row["num_sessions"] or 0),
|
113
|
-
events=int(row["num_events"] or 0),
|
114
|
-
messages=int(row["num_messages"] or 0),
|
115
|
-
cost=float(row["total_cost"] or 0.0),
|
116
|
-
tokens=int(row["total_tokens"] or 0),
|
117
|
-
)
|
118
|
-
self.experiments.append(exp_row)
|
119
|
-
self.add_row(*exp_row.to_row(), key=exp_row.exp_id)
|
120
|
-
|
121
|
-
except Exception as e:
|
122
|
-
logging.error(f"Failed to refresh experiments: {e}")
|
123
|
-
|
124
|
-
def get_selected_experiment(self) -> ExperimentRow | None:
|
125
|
-
"""Get currently selected experiment."""
|
126
|
-
if self.cursor_row >= 0 and self.cursor_row < len(self.experiments):
|
127
|
-
return self.experiments[self.cursor_row]
|
128
|
-
return None
|
129
|
-
|
130
|
-
|
131
|
-
class ExperimentDetail(Static):
|
132
|
-
"""Detailed view of selected experiment."""
|
133
|
-
|
134
|
-
def __init__(self, **kwargs):
|
135
|
-
super().__init__(**kwargs)
|
136
|
-
self.current_experiment: ExperimentRow | None = None
|
137
|
-
|
138
|
-
def update_experiment(self, experiment: ExperimentRow | None):
|
139
|
-
"""Update the displayed experiment details."""
|
140
|
-
self.current_experiment = experiment
|
141
|
-
if experiment:
|
142
|
-
details = f"""
|
143
|
-
🔬 **{experiment.name}**
|
144
|
-
ID: {experiment.exp_id}
|
145
|
-
Description: {experiment.description or "No description"}
|
146
|
-
|
147
|
-
📊 **Statistics**
|
148
|
-
Sessions: {experiment.sessions}
|
149
|
-
Events: {experiment.events}
|
150
|
-
Messages: {experiment.messages}
|
151
|
-
Cost: ${experiment.cost:.4f}
|
152
|
-
Tokens: {experiment.tokens:,}
|
153
|
-
|
154
|
-
🕒 **Created**: {experiment.created_at.strftime("%Y-%m-%d %H:%M:%S")}
|
155
|
-
""".strip()
|
156
|
-
else:
|
157
|
-
details = "Select an experiment to view details"
|
158
|
-
|
159
|
-
self.update(details)
|
160
|
-
|
161
|
-
|
162
|
-
class DatabaseStatus(Static):
|
163
|
-
"""Display database connection status."""
|
164
|
-
|
165
|
-
connection_status = reactive("🔴 Disconnected")
|
166
|
-
|
167
|
-
def __init__(self, **kwargs):
|
168
|
-
super().__init__(**kwargs)
|
169
|
-
|
170
|
-
def render(self) -> str:
|
171
|
-
return f"Database: {self.connection_status}"
|
172
|
-
|
173
|
-
def set_connected(self, url: str):
|
174
|
-
parsed = urlparse(url)
|
175
|
-
host_info = f"{parsed.hostname}:{parsed.port}" if parsed.port else str(parsed.hostname)
|
176
|
-
self.connection_status = f"🟢 Connected ({host_info})"
|
177
|
-
|
178
|
-
def set_disconnected(self, error: str = ""):
|
179
|
-
error_text = f" - {error}" if error else ""
|
180
|
-
self.connection_status = f"🔴 Disconnected{error_text}"
|
181
|
-
|
182
|
-
|
183
|
-
class SynthDashboard(App):
|
184
|
-
"""Main Synth AI TUI Dashboard application."""
|
185
|
-
|
186
|
-
CSS = """
|
187
|
-
Screen {
|
188
|
-
layout: grid;
|
189
|
-
grid-size: 2 3;
|
190
|
-
grid-gutter: 1;
|
191
|
-
}
|
192
|
-
|
193
|
-
#header {
|
194
|
-
column-span: 2;
|
195
|
-
height: 3;
|
196
|
-
}
|
197
|
-
|
198
|
-
#experiments-table {
|
199
|
-
row-span: 2;
|
200
|
-
}
|
201
|
-
|
202
|
-
#experiment-detail {
|
203
|
-
height: 1fr;
|
204
|
-
}
|
205
|
-
|
206
|
-
#status-bar {
|
207
|
-
column-span: 2;
|
208
|
-
height: 3;
|
209
|
-
}
|
210
|
-
|
211
|
-
ExperimentTable {
|
212
|
-
height: 100%;
|
213
|
-
}
|
214
|
-
|
215
|
-
ExperimentDetail {
|
216
|
-
border: solid $primary;
|
217
|
-
padding: 1;
|
218
|
-
height: 100%;
|
219
|
-
}
|
220
|
-
|
221
|
-
DatabaseStatus {
|
222
|
-
height: 1;
|
223
|
-
padding: 0 1;
|
224
|
-
}
|
225
|
-
"""
|
226
|
-
|
227
|
-
BINDINGS = [
|
228
|
-
Binding("q", "quit", "Quit"),
|
229
|
-
Binding("r", "refresh", "Refresh"),
|
230
|
-
Binding("d", "toggle_debug", "Debug"),
|
231
|
-
("ctrl+c", "quit", "Quit"),
|
232
|
-
]
|
233
|
-
|
234
|
-
def __init__(self, db_url: str = "sqlite+aiosqlite:///./synth_ai.db/dbs/default/data"):
|
235
|
-
super().__init__()
|
236
|
-
self.db_url = db_url
|
237
|
-
self.db_manager: AsyncSQLTraceManager | None = None
|
238
|
-
self.refresh_timer: Timer | None = None
|
239
|
-
|
240
|
-
def compose(self) -> ComposeResult:
|
241
|
-
"""Create the UI layout."""
|
242
|
-
yield Header(show_clock=True)
|
243
|
-
|
244
|
-
with Container(id="experiments-table"):
|
245
|
-
yield Static("🧪 Experiments", classes="section-title")
|
246
|
-
yield ExperimentTable(id="experiments")
|
247
|
-
|
248
|
-
with Container(id="experiment-detail"):
|
249
|
-
yield Static("📋 Details", classes="section-title")
|
250
|
-
yield ExperimentDetail(id="detail")
|
251
|
-
|
252
|
-
with Container(id="status-bar"):
|
253
|
-
yield DatabaseStatus(id="db-status")
|
254
|
-
yield Footer()
|
255
|
-
|
256
|
-
async def on_mount(self) -> None:
|
257
|
-
"""Initialize the app when mounted."""
|
258
|
-
# Setup database connection
|
259
|
-
try:
|
260
|
-
self.db_manager = AsyncSQLTraceManager(self.db_url)
|
261
|
-
await self.db_manager.initialize()
|
262
|
-
|
263
|
-
db_status = self.query_one("#db-status", DatabaseStatus)
|
264
|
-
db_status.set_connected(self.db_url)
|
265
|
-
|
266
|
-
except Exception as e:
|
267
|
-
logging.error(f"Failed to connect to database: {e}")
|
268
|
-
db_status = self.query_one("#db-status", DatabaseStatus)
|
269
|
-
db_status.set_disconnected(str(e))
|
270
|
-
|
271
|
-
# Setup experiment table
|
272
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
273
|
-
exp_table.setup_table()
|
274
|
-
|
275
|
-
# Initial data load
|
276
|
-
await self.action_refresh()
|
277
|
-
|
278
|
-
# Start auto-refresh timer (every 5 seconds)
|
279
|
-
self.refresh_timer = self.set_interval(5.0, self._auto_refresh)
|
280
|
-
|
281
|
-
async def _auto_refresh(self) -> None:
|
282
|
-
"""Auto-refresh data periodically."""
|
283
|
-
if self.db_manager:
|
284
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
285
|
-
await exp_table.refresh_data(self.db_manager)
|
286
|
-
|
287
|
-
async def action_refresh(self) -> None:
|
288
|
-
"""Manual refresh action."""
|
289
|
-
if self.db_manager:
|
290
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
291
|
-
await exp_table.refresh_data(self.db_manager)
|
292
|
-
|
293
|
-
async def action_quit(self) -> None:
|
294
|
-
"""Quit the application."""
|
295
|
-
if self.refresh_timer:
|
296
|
-
self.refresh_timer.stop()
|
297
|
-
if self.db_manager:
|
298
|
-
await self.db_manager.close()
|
299
|
-
self.exit()
|
300
|
-
|
301
|
-
def action_toggle_debug(self) -> None:
|
302
|
-
"""Toggle debug mode."""
|
303
|
-
# Could add debug panel or logging level toggle
|
304
|
-
pass
|
305
|
-
|
306
|
-
@on(DataTable.RowHighlighted, "#experiments")
|
307
|
-
def on_experiment_selected(self, event: DataTable.RowHighlighted) -> None:
|
308
|
-
"""Handle experiment selection."""
|
309
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
310
|
-
selected_exp = exp_table.get_selected_experiment()
|
311
|
-
|
312
|
-
detail_panel = self.query_one("#detail", ExperimentDetail)
|
313
|
-
detail_panel.update_experiment(selected_exp)
|
314
|
-
|
315
|
-
|
316
|
-
def main():
|
317
|
-
"""Main entry point for the dashboard."""
|
318
|
-
import argparse
|
319
|
-
|
320
|
-
parser = argparse.ArgumentParser(description="Synth AI Interactive Dashboard")
|
321
|
-
parser.add_argument(
|
322
|
-
"-u",
|
323
|
-
"--url",
|
324
|
-
default="sqlite+libsql://http://127.0.0.1:8080",
|
325
|
-
help="Database URL (default: sqlite+libsql://http://127.0.0.1:8080)",
|
326
|
-
)
|
327
|
-
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
|
328
|
-
|
329
|
-
args = parser.parse_args()
|
330
|
-
|
331
|
-
if args.debug:
|
332
|
-
logging.basicConfig(level=logging.DEBUG)
|
333
|
-
|
334
|
-
# Run the dashboard
|
335
|
-
app = SynthDashboard(db_url=args.url)
|
336
|
-
app.run()
|
337
|
-
|
338
|
-
|
339
|
-
if __name__ == "__main__":
|
340
|
-
main()
|
@@ -1,193 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: synth-ai
|
3
|
-
Version: 0.2.4.dev7
|
4
|
-
Summary: Software for aiding the best and multiplying the will - Core AI functionality and tracing
|
5
|
-
Author-email: Synth AI <josh@usesynth.ai>
|
6
|
-
License-Expression: MIT
|
7
|
-
Project-URL: Homepage, https://github.com/synth-laboratories/synth-ai
|
8
|
-
Project-URL: Repository, https://github.com/synth-laboratories/synth-ai
|
9
|
-
Project-URL: Issues, https://github.com/synth-laboratories/synth-ai/issues
|
10
|
-
Requires-Python: >=3.11
|
11
|
-
Description-Content-Type: text/markdown
|
12
|
-
License-File: LICENSE
|
13
|
-
Requires-Dist: pydantic>=2.0.0
|
14
|
-
Requires-Dist: python-dotenv>=1.0.1
|
15
|
-
Requires-Dist: requests>=2.32.3
|
16
|
-
Requires-Dist: urllib3>=2.3.0
|
17
|
-
Requires-Dist: tqdm>=4.66.4
|
18
|
-
Requires-Dist: jsonschema>=4.23.0
|
19
|
-
Requires-Dist: backoff>=2.0.0
|
20
|
-
Requires-Dist: typing_extensions>=4.0.0
|
21
|
-
Requires-Dist: openai>=1.99.0
|
22
|
-
Requires-Dist: anthropic>=0.42.0
|
23
|
-
Requires-Dist: langfuse<3.0.0,>=2.53.9
|
24
|
-
Requires-Dist: opentelemetry-api<1.27.0,>=1.26.0
|
25
|
-
Requires-Dist: opentelemetry-sdk<1.27.0,>=1.26.0
|
26
|
-
Requires-Dist: diskcache>=5.6.3
|
27
|
-
Requires-Dist: groq>=0.30.0
|
28
|
-
Requires-Dist: google-genai>=1.26.0
|
29
|
-
Requires-Dist: together>=1.5.21
|
30
|
-
Requires-Dist: mistralai>=1.9.2
|
31
|
-
Requires-Dist: fastapi>=0.115.12
|
32
|
-
Requires-Dist: uvicorn>=0.34.2
|
33
|
-
Requires-Dist: numpy>=2.2.3
|
34
|
-
Requires-Dist: networkx>=3.4.2
|
35
|
-
Requires-Dist: redis>=6.2.0
|
36
|
-
Requires-Dist: duckdb>=1.0.0
|
37
|
-
Requires-Dist: pandas>=2.2.3
|
38
|
-
Requires-Dist: ty>=0.0.1a5
|
39
|
-
Requires-Dist: toml>=0.10.2
|
40
|
-
Requires-Dist: sqlalchemy>=2.0.42
|
41
|
-
Requires-Dist: aiosqlite>=0.21.0
|
42
|
-
Requires-Dist: greenlet>=3.2.3
|
43
|
-
Requires-Dist: libsql>=0.1.8
|
44
|
-
Requires-Dist: google-api-core>=2.25.1
|
45
|
-
Requires-Dist: google-generativeai>=0.8.5
|
46
|
-
Requires-Dist: crafter>=1.8.3
|
47
|
-
Requires-Dist: click>=8.1.0
|
48
|
-
Requires-Dist: textual>=1.1.0
|
49
|
-
Requires-Dist: openai-harmony>=0.0.1
|
50
|
-
Requires-Dist: asyncpg>=0.30.0
|
51
|
-
Requires-Dist: aiohttp>=3.8.0
|
52
|
-
Requires-Dist: datasets>=4.0.0
|
53
|
-
Provides-Extra: dev
|
54
|
-
Requires-Dist: build>=1.2.2.post1; extra == "dev"
|
55
|
-
Requires-Dist: twine>=4.0.0; extra == "dev"
|
56
|
-
Requires-Dist: keyring>=24.0.0; extra == "dev"
|
57
|
-
Requires-Dist: pytest>=8.3.3; extra == "dev"
|
58
|
-
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
|
59
|
-
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
60
|
-
Requires-Dist: pyright>=1.1.350; extra == "dev"
|
61
|
-
Requires-Dist: coverage[toml]>=7.3.0; extra == "dev"
|
62
|
-
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
63
|
-
Provides-Extra: research
|
64
|
-
Requires-Dist: crafter>=1.8.3; extra == "research"
|
65
|
-
Requires-Dist: datasets>=4.0.0; extra == "research"
|
66
|
-
Provides-Extra: all
|
67
|
-
Requires-Dist: crafter>=1.8.3; extra == "all"
|
68
|
-
Requires-Dist: datasets>=4.0.0; extra == "all"
|
69
|
-
Dynamic: license-file
|
70
|
-
|
71
|
-
# Synth AI
|
72
|
-
|
73
|
-
Modern Compound AI System Development
|
74
|
-
|
75
|
-
**Comprehensive AI Framework for Language Models, Environments, and Observability**
|
76
|
-
|
77
|
-
[](https://www.python.org/)
|
78
|
-
[](LICENSE)
|
79
|
-
[](https://pypi.org/project/synth-ai/)
|
80
|
-

|
81
|
-

|
82
|
-
|
83
|
-
A unified framework combining language model capabilities, synthetic environments, and comprehensive tracing for building and evaluating AI agents.
|
84
|
-
|
85
|
-
## 🚀 Quick Start
|
86
|
-
|
87
|
-
### Installation
|
88
|
-
|
89
|
-
```bash
|
90
|
-
# Basic installation
|
91
|
-
pip install synth-ai
|
92
|
-
|
93
|
-
# With research environments (includes game environments)
|
94
|
-
pip install synth-ai[research]
|
95
|
-
|
96
|
-
# Full installation with all providers
|
97
|
-
pip install synth-ai[all]
|
98
|
-
```
|
99
|
-
|
100
|
-
### Spinning Up
|
101
|
-
|
102
|
-
Start the Synth AI service daemon (includes sqld database + environment service):
|
103
|
-
|
104
|
-
```bash
|
105
|
-
# Start both database daemon (port 8080) and environment service (port 8901)
|
106
|
-
uvx synth-ai serve
|
107
|
-
```
|
108
|
-
|
109
|
-
#### Service Command Options
|
110
|
-
|
111
|
-
```bash
|
112
|
-
uvx synth-ai serve [OPTIONS]
|
113
|
-
```
|
114
|
-
|
115
|
-
**Available Options:**
|
116
|
-
- `--db-file` - Database file path (default: "synth_ai.db")
|
117
|
-
- `--sqld-port` - Port for sqld HTTP interface (default: 8080)
|
118
|
-
- `--env-port` - Port for environment service (default: 8901)
|
119
|
-
- `--no-sqld` - Skip starting sqld database daemon
|
120
|
-
- `--no-env` - Skip starting environment service
|
121
|
-
|
122
|
-
**Examples:**
|
123
|
-
```bash
|
124
|
-
# Start with custom ports
|
125
|
-
uvx synth-ai serve --sqld-port 8081 --env-port 8902
|
126
|
-
|
127
|
-
# Start only the environment service
|
128
|
-
uvx synth-ai serve --no-sqld
|
129
|
-
|
130
|
-
# Start only the database service
|
131
|
-
uvx synth-ai serve --no-env
|
132
|
-
```
|
133
|
-
|
134
|
-
#### What the Serve Command Provides
|
135
|
-
|
136
|
-
**sqld Database Service (port 8080)**
|
137
|
-
- Local SQLite-compatible database server with HTTP API
|
138
|
-
- Automatically downloads and installs sqld binary if needed
|
139
|
-
- Provides persistent storage for agent interactions and traces
|
140
|
-
|
141
|
-
**Environment Service (port 8901)**
|
142
|
-
- FastAPI service for managing AI environments and tasks
|
143
|
-
- Built-in environments: Crafter, Sokoban, MiniGrid, TicTacToe, Verilog, NetHack, Enron
|
144
|
-
- RESTful API for environment initialization, stepping, and termination
|
145
|
-
- Dynamic environment registry for custom environments
|
146
|
-
|
147
|
-
In another terminal, run your first example:
|
148
|
-
|
149
|
-
```bash
|
150
|
-
# Run a Crafter agent demo with Gemini
|
151
|
-
./examples/run_crafter_demo.sh
|
152
|
-
```
|
153
|
-
|
154
|
-
This will:
|
155
|
-
- Start the sqld database daemon with HTTP API on port 8080
|
156
|
-
- Launch the environment service API on port 8901
|
157
|
-
- Run a reactive agent in the Crafter environment using Gemini 1.5 Flash
|
158
|
-
|
159
|
-
#### Demos (Eval + Finetuning)
|
160
|
-
|
161
|
-
You can run interactive demos from the repo without remembering exact commands:
|
162
|
-
|
163
|
-
```bash
|
164
|
-
# Lists all available demos under examples/, then prompts you to choose
|
165
|
-
uvx synth-ai demo
|
166
|
-
```
|
167
|
-
|
168
|
-
Today this includes:
|
169
|
-
- Eval demo: `examples/evals/run_demo.sh`
|
170
|
-
- Prompts for models, episodes, etc.
|
171
|
-
- Runs Crafter rollouts with v3 tracing, then analyzes and filters traces
|
172
|
-
- Writes a JSONL like `ft_data/evals_filtered.jsonl` for downstream use
|
173
|
-
- Finetuning demo: `examples/finetuning/synth_qwen/run_demo.sh`
|
174
|
-
- Guides you through: rollouts → filter v3 traces → prepare SFT JSONL
|
175
|
-
- Pair with `uvpm examples.finetuning.synth_qwen.sft_kickoff` to start an SFT job when ready
|
176
|
-
|
177
|
-
Notes:
|
178
|
-
- Ensure the service is running (`uvx synth-ai serve`) so v3 traces are recorded locally.
|
179
|
-
- Set API configuration for finetuning:
|
180
|
-
- `export LEARNING_V2_BASE_URL="http://localhost:8000/api"` (or your proxy)
|
181
|
-
- `export SYNTH_API_KEY="sk_live_..."`
|
182
|
-
- v3 trace data is stored under `traces/v3/synth_ai.db/` by default. Inspect with `uvx synth-ai traces`.
|
183
|
-
- LM tracing: all model calls (prompts, outputs, tool calls, token usage, latency, cost) are automatically captured via v3 tracing and stored locally; inspect with `uvx synth-ai traces`.
|
184
|
-
|
185
|
-
### One-Command Demos
|
186
|
-
|
187
|
-
Quickly browse and launch interactive demos under `examples/`:
|
188
|
-
|
189
|
-
```bash
|
190
|
-
uvx synth-ai demo
|
191
|
-
```
|
192
|
-
|
193
|
-
This lists all `run_demo.sh` scripts found in the repo (e.g., eval comparisons, finetuning flows) and lets you pick one to run.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|