synth-ai 0.2.4.dev6__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 +18 -9
- synth_ai/cli/__init__.py +10 -5
- synth_ai/cli/balance.py +25 -32
- synth_ai/cli/calc.py +2 -3
- synth_ai/cli/demo.py +3 -5
- synth_ai/cli/legacy_root_backup.py +58 -32
- synth_ai/cli/man.py +22 -19
- synth_ai/cli/recent.py +9 -8
- synth_ai/cli/root.py +58 -13
- synth_ai/cli/status.py +13 -6
- synth_ai/cli/traces.py +45 -21
- synth_ai/cli/watch.py +40 -37
- synth_ai/config/base_url.py +47 -2
- synth_ai/core/experiment.py +1 -2
- synth_ai/environments/__init__.py +2 -6
- synth_ai/environments/environment/artifacts/base.py +3 -1
- synth_ai/environments/environment/db/sqlite.py +1 -1
- synth_ai/environments/environment/registry.py +19 -20
- synth_ai/environments/environment/resources/sqlite.py +2 -3
- synth_ai/environments/environment/rewards/core.py +3 -2
- synth_ai/environments/environment/tools/__init__.py +6 -4
- synth_ai/environments/examples/crafter_classic/__init__.py +1 -1
- synth_ai/environments/examples/crafter_classic/engine.py +13 -13
- synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +1 -0
- synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +2 -1
- synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +2 -1
- synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +3 -2
- synth_ai/environments/examples/crafter_classic/environment.py +16 -15
- synth_ai/environments/examples/crafter_classic/taskset.py +2 -2
- synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +2 -3
- synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +2 -1
- synth_ai/environments/examples/crafter_custom/crafter/__init__.py +2 -2
- synth_ai/environments/examples/crafter_custom/crafter/config.py +2 -2
- synth_ai/environments/examples/crafter_custom/crafter/env.py +1 -5
- synth_ai/environments/examples/crafter_custom/crafter/objects.py +1 -2
- synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +1 -2
- synth_ai/environments/examples/crafter_custom/dataset_builder.py +5 -5
- synth_ai/environments/examples/crafter_custom/environment.py +13 -13
- synth_ai/environments/examples/crafter_custom/run_dataset.py +5 -5
- synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +2 -2
- synth_ai/environments/examples/enron/art_helpers/local_email_db.py +5 -4
- synth_ai/environments/examples/enron/art_helpers/types_enron.py +2 -1
- synth_ai/environments/examples/enron/engine.py +18 -14
- synth_ai/environments/examples/enron/environment.py +12 -11
- synth_ai/environments/examples/enron/taskset.py +7 -7
- synth_ai/environments/examples/minigrid/__init__.py +6 -6
- synth_ai/environments/examples/minigrid/engine.py +6 -6
- synth_ai/environments/examples/minigrid/environment.py +6 -6
- synth_ai/environments/examples/minigrid/puzzle_loader.py +3 -2
- synth_ai/environments/examples/minigrid/taskset.py +13 -13
- synth_ai/environments/examples/nethack/achievements.py +1 -1
- synth_ai/environments/examples/nethack/engine.py +8 -7
- synth_ai/environments/examples/nethack/environment.py +10 -9
- synth_ai/environments/examples/nethack/helpers/__init__.py +8 -9
- synth_ai/environments/examples/nethack/helpers/action_mapping.py +1 -1
- synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +2 -1
- synth_ai/environments/examples/nethack/helpers/observation_utils.py +1 -1
- synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +3 -4
- synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +6 -5
- synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +5 -5
- synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +7 -6
- synth_ai/environments/examples/nethack/taskset.py +5 -5
- synth_ai/environments/examples/red/engine.py +9 -8
- synth_ai/environments/examples/red/engine_helpers/reward_components.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +7 -7
- synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +3 -2
- synth_ai/environments/examples/red/engine_helpers/state_extraction.py +2 -1
- synth_ai/environments/examples/red/environment.py +18 -15
- synth_ai/environments/examples/red/taskset.py +5 -3
- synth_ai/environments/examples/sokoban/engine.py +16 -13
- synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +3 -2
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +2 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +1 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +7 -5
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +1 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +2 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +5 -4
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +3 -2
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +2 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +5 -4
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +1 -1
- synth_ai/environments/examples/sokoban/environment.py +15 -14
- synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +5 -3
- synth_ai/environments/examples/sokoban/puzzle_loader.py +3 -2
- synth_ai/environments/examples/sokoban/taskset.py +13 -10
- synth_ai/environments/examples/tictactoe/engine.py +6 -6
- synth_ai/environments/examples/tictactoe/environment.py +8 -7
- synth_ai/environments/examples/tictactoe/taskset.py +6 -5
- synth_ai/environments/examples/verilog/engine.py +4 -3
- synth_ai/environments/examples/verilog/environment.py +11 -10
- synth_ai/environments/examples/verilog/taskset.py +14 -12
- synth_ai/environments/examples/wordle/__init__.py +5 -5
- synth_ai/environments/examples/wordle/engine.py +32 -25
- synth_ai/environments/examples/wordle/environment.py +21 -16
- synth_ai/environments/examples/wordle/helpers/generate_instances_wordfreq.py +6 -6
- synth_ai/environments/examples/wordle/taskset.py +20 -12
- synth_ai/environments/reproducibility/core.py +1 -1
- synth_ai/environments/reproducibility/tree.py +21 -21
- synth_ai/environments/service/app.py +3 -2
- synth_ai/environments/service/core_routes.py +104 -110
- synth_ai/environments/service/external_registry.py +1 -2
- synth_ai/environments/service/registry.py +1 -1
- synth_ai/environments/stateful/core.py +1 -2
- synth_ai/environments/stateful/engine.py +1 -1
- synth_ai/environments/tasks/api.py +4 -4
- synth_ai/environments/tasks/core.py +14 -12
- synth_ai/environments/tasks/filters.py +6 -4
- synth_ai/environments/tasks/utils.py +13 -11
- synth_ai/evals/base.py +2 -3
- synth_ai/experimental/synth_oss.py +4 -4
- 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/gateway.py +1 -3
- synth_ai/learning/health.py +43 -0
- synth_ai/learning/jobs.py +205 -0
- synth_ai/learning/prompts/banking77_injection_eval.py +15 -10
- synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +26 -14
- synth_ai/learning/prompts/mipro.py +61 -52
- synth_ai/learning/prompts/random_search.py +42 -43
- synth_ai/learning/prompts/run_mipro_banking77.py +32 -20
- synth_ai/learning/prompts/run_random_search_banking77.py +71 -52
- 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/__init__.py +5 -5
- synth_ai/lm/caching/ephemeral.py +9 -9
- synth_ai/lm/caching/handler.py +20 -20
- synth_ai/lm/caching/persistent.py +10 -10
- synth_ai/lm/config.py +3 -3
- synth_ai/lm/constants.py +7 -7
- synth_ai/lm/core/all.py +17 -3
- synth_ai/lm/core/exceptions.py +0 -2
- synth_ai/lm/core/main.py +26 -41
- synth_ai/lm/core/main_v3.py +33 -10
- synth_ai/lm/core/synth_models.py +48 -0
- synth_ai/lm/core/vendor_clients.py +26 -22
- synth_ai/lm/injection.py +7 -8
- synth_ai/lm/overrides.py +21 -19
- synth_ai/lm/provider_support/__init__.py +1 -1
- synth_ai/lm/provider_support/anthropic.py +15 -15
- synth_ai/lm/provider_support/openai.py +23 -21
- synth_ai/lm/structured_outputs/handler.py +34 -32
- synth_ai/lm/structured_outputs/inject.py +24 -27
- synth_ai/lm/structured_outputs/rehabilitate.py +19 -15
- synth_ai/lm/tools/base.py +17 -16
- synth_ai/lm/unified_interface.py +17 -18
- synth_ai/lm/vendors/base.py +20 -18
- synth_ai/lm/vendors/core/anthropic_api.py +36 -27
- synth_ai/lm/vendors/core/gemini_api.py +31 -36
- synth_ai/lm/vendors/core/mistral_api.py +19 -19
- synth_ai/lm/vendors/core/openai_api.py +42 -13
- synth_ai/lm/vendors/openai_standard.py +158 -101
- synth_ai/lm/vendors/openai_standard_responses.py +74 -61
- synth_ai/lm/vendors/retries.py +9 -1
- synth_ai/lm/vendors/supported/custom_endpoint.py +38 -28
- synth_ai/lm/vendors/supported/deepseek.py +10 -10
- synth_ai/lm/vendors/supported/grok.py +8 -8
- synth_ai/lm/vendors/supported/ollama.py +2 -1
- synth_ai/lm/vendors/supported/openrouter.py +11 -9
- synth_ai/lm/vendors/synth_client.py +425 -75
- synth_ai/lm/warmup.py +8 -7
- 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/__init__.py +22 -10
- synth_ai/tracing_v1/__init__.py +22 -20
- synth_ai/tracing_v3/__init__.py +7 -7
- synth_ai/tracing_v3/abstractions.py +56 -52
- synth_ai/tracing_v3/config.py +4 -2
- synth_ai/tracing_v3/db_config.py +6 -8
- synth_ai/tracing_v3/decorators.py +29 -30
- synth_ai/tracing_v3/examples/basic_usage.py +12 -12
- synth_ai/tracing_v3/hooks.py +24 -22
- synth_ai/tracing_v3/llm_call_record_helpers.py +85 -98
- synth_ai/tracing_v3/lm_call_record_abstractions.py +2 -4
- synth_ai/tracing_v3/migration_helper.py +3 -5
- synth_ai/tracing_v3/replica_sync.py +30 -32
- synth_ai/tracing_v3/session_tracer.py +158 -31
- synth_ai/tracing_v3/storage/__init__.py +1 -1
- synth_ai/tracing_v3/storage/base.py +8 -7
- synth_ai/tracing_v3/storage/config.py +4 -4
- synth_ai/tracing_v3/storage/factory.py +4 -4
- synth_ai/tracing_v3/storage/utils.py +9 -9
- synth_ai/tracing_v3/turso/__init__.py +3 -3
- synth_ai/tracing_v3/turso/daemon.py +9 -9
- synth_ai/tracing_v3/turso/manager.py +278 -48
- synth_ai/tracing_v3/turso/models.py +77 -19
- synth_ai/tracing_v3/utils.py +5 -5
- synth_ai/v0/tracing/abstractions.py +28 -28
- synth_ai/v0/tracing/base_client.py +9 -9
- synth_ai/v0/tracing/client_manager.py +7 -7
- synth_ai/v0/tracing/config.py +7 -7
- synth_ai/v0/tracing/context.py +6 -6
- synth_ai/v0/tracing/decorators.py +6 -5
- synth_ai/v0/tracing/events/manage.py +1 -1
- synth_ai/v0/tracing/events/store.py +5 -4
- synth_ai/v0/tracing/immediate_client.py +4 -5
- synth_ai/v0/tracing/local.py +3 -3
- synth_ai/v0/tracing/log_client_base.py +4 -5
- synth_ai/v0/tracing/retry_queue.py +5 -6
- synth_ai/v0/tracing/trackers.py +25 -25
- synth_ai/v0/tracing/upload.py +6 -0
- synth_ai/v0/tracing_v1/__init__.py +1 -1
- synth_ai/v0/tracing_v1/abstractions.py +28 -28
- synth_ai/v0/tracing_v1/base_client.py +9 -9
- synth_ai/v0/tracing_v1/client_manager.py +7 -7
- synth_ai/v0/tracing_v1/config.py +7 -7
- synth_ai/v0/tracing_v1/context.py +6 -6
- synth_ai/v0/tracing_v1/decorators.py +7 -6
- synth_ai/v0/tracing_v1/events/manage.py +1 -1
- synth_ai/v0/tracing_v1/events/store.py +5 -4
- synth_ai/v0/tracing_v1/immediate_client.py +4 -5
- synth_ai/v0/tracing_v1/local.py +3 -3
- synth_ai/v0/tracing_v1/log_client_base.py +4 -5
- synth_ai/v0/tracing_v1/retry_queue.py +5 -6
- synth_ai/v0/tracing_v1/trackers.py +25 -25
- synth_ai/v0/tracing_v1/upload.py +25 -24
- synth_ai/zyk/__init__.py +1 -0
- synth_ai-0.2.4.dev8.dist-info/METADATA +635 -0
- synth_ai-0.2.4.dev8.dist-info/RECORD +317 -0
- 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 -165
- synth_ai/tui/cli/query_experiments_v3.py +0 -165
- synth_ai/tui/dashboard.py +0 -329
- synth_ai-0.2.4.dev6.dist-info/METADATA +0 -203
- synth_ai-0.2.4.dev6.dist-info/RECORD +0 -299
- {synth_ai-0.2.4.dev6.dist-info → synth_ai-0.2.4.dev8.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.4.dev6.dist-info → synth_ai-0.2.4.dev8.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.4.dev6.dist-info → synth_ai-0.2.4.dev8.dist-info}/licenses/LICENSE +0 -0
- {synth_ai-0.2.4.dev6.dist-info → synth_ai-0.2.4.dev8.dist-info}/top_level.txt +0 -0
@@ -1,165 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Query experiments and sessions from Turso/sqld using v3 tracing.
|
4
|
-
"""
|
5
|
-
|
6
|
-
import argparse
|
7
|
-
import asyncio
|
8
|
-
from typing import Optional
|
9
|
-
from synth_ai.tracing_v3.turso.manager import AsyncSQLTraceManager
|
10
|
-
import pandas as pd
|
11
|
-
|
12
|
-
|
13
|
-
async def list_experiments(db_url: str):
|
14
|
-
"""List all experiments in the database."""
|
15
|
-
db = AsyncSQLTraceManager(db_url)
|
16
|
-
await db.initialize()
|
17
|
-
|
18
|
-
try:
|
19
|
-
df = await db.query_traces("""
|
20
|
-
SELECT
|
21
|
-
e.experiment_id,
|
22
|
-
e.name,
|
23
|
-
e.description,
|
24
|
-
e.created_at,
|
25
|
-
COUNT(DISTINCT st.session_id) as num_sessions,
|
26
|
-
COUNT(DISTINCT ev.id) as num_events,
|
27
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.cost_usd ELSE 0 END) / 100.0 as total_cost,
|
28
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.total_tokens ELSE 0 END) as total_tokens
|
29
|
-
FROM experiments e
|
30
|
-
LEFT JOIN session_traces st ON e.experiment_id = st.experiment_id
|
31
|
-
LEFT JOIN events ev ON st.session_id = ev.session_id
|
32
|
-
GROUP BY e.experiment_id, e.name, e.description, e.created_at
|
33
|
-
ORDER BY e.created_at DESC
|
34
|
-
""")
|
35
|
-
|
36
|
-
if df.empty:
|
37
|
-
print("No experiments found in database.")
|
38
|
-
return
|
39
|
-
|
40
|
-
print(f"\n{'=' * 100}")
|
41
|
-
print(f"{'Experiments in ' + db_url:^100}")
|
42
|
-
print(f"{'=' * 100}\n")
|
43
|
-
|
44
|
-
for _, row in df.iterrows():
|
45
|
-
print(f"🧪 {row['name']} (id: {row['experiment_id'][:8]}...)")
|
46
|
-
print(f" Created: {row['created_at']}")
|
47
|
-
print(f" Description: {row['description']}")
|
48
|
-
print(f" Sessions: {row['num_sessions']}")
|
49
|
-
print(f" Events: {row['num_events']:,}")
|
50
|
-
if row["total_cost"] and row["total_cost"] > 0:
|
51
|
-
print(f" Cost: ${row['total_cost']:.4f}")
|
52
|
-
if row["total_tokens"] and row["total_tokens"] > 0:
|
53
|
-
print(f" Tokens: {int(row['total_tokens']):,}")
|
54
|
-
print()
|
55
|
-
finally:
|
56
|
-
await db.close()
|
57
|
-
|
58
|
-
|
59
|
-
async def show_experiment_details(db_url: str, experiment_id: str):
|
60
|
-
"""Show detailed information about a specific experiment."""
|
61
|
-
db = AsyncSQLTraceManager(db_url)
|
62
|
-
await db.initialize()
|
63
|
-
|
64
|
-
try:
|
65
|
-
# Get experiment info
|
66
|
-
exp_df = await db.query_traces(
|
67
|
-
"""
|
68
|
-
SELECT * FROM experiments WHERE experiment_id LIKE :exp_id
|
69
|
-
""",
|
70
|
-
{"exp_id": f"{experiment_id}%"},
|
71
|
-
)
|
72
|
-
|
73
|
-
if exp_df.empty:
|
74
|
-
print(f"No experiment found matching ID: {experiment_id}")
|
75
|
-
return
|
76
|
-
|
77
|
-
exp = exp_df.iloc[0]
|
78
|
-
print(f"\n{'=' * 100}")
|
79
|
-
print(f"Experiment: {exp['name']} ({exp['experiment_id']})")
|
80
|
-
print(f"{'=' * 100}\n")
|
81
|
-
|
82
|
-
# Get session statistics
|
83
|
-
sessions_df = await db.get_sessions_by_experiment(exp["experiment_id"])
|
84
|
-
|
85
|
-
if sessions_df:
|
86
|
-
print(f"Sessions: {len(sessions_df)}")
|
87
|
-
|
88
|
-
# Get aggregated stats
|
89
|
-
stats_df = await db.query_traces(
|
90
|
-
"""
|
91
|
-
SELECT
|
92
|
-
COUNT(DISTINCT ev.id) as total_events,
|
93
|
-
COUNT(DISTINCT m.id) as total_messages,
|
94
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.cost_usd ELSE 0 END) / 100.0 as total_cost,
|
95
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.total_tokens ELSE 0 END) as total_tokens
|
96
|
-
FROM session_traces st
|
97
|
-
LEFT JOIN events ev ON st.session_id = ev.session_id
|
98
|
-
LEFT JOIN messages m ON st.session_id = m.session_id
|
99
|
-
WHERE st.experiment_id = :exp_id
|
100
|
-
""",
|
101
|
-
{"exp_id": exp["experiment_id"]},
|
102
|
-
)
|
103
|
-
|
104
|
-
if not stats_df.empty:
|
105
|
-
stats = stats_df.iloc[0]
|
106
|
-
print(f"Total events: {int(stats['total_events']):,}")
|
107
|
-
print(f"Total messages: {int(stats['total_messages']):,}")
|
108
|
-
print(f"Total cost: ${stats['total_cost']:.4f}")
|
109
|
-
print(f"Total tokens: {int(stats['total_tokens']):,}")
|
110
|
-
|
111
|
-
# Show session list
|
112
|
-
print("\nSession list:")
|
113
|
-
for sess in sessions_df:
|
114
|
-
print(f" - {sess['session_id']} ({sess['created_at']})")
|
115
|
-
print(
|
116
|
-
f" Timesteps: {sess['num_timesteps']}, Events: {sess['num_events']}, Messages: {sess['num_messages']}"
|
117
|
-
)
|
118
|
-
finally:
|
119
|
-
await db.close()
|
120
|
-
|
121
|
-
|
122
|
-
async def show_model_usage(db_url: str, model_name: Optional[str] = None):
|
123
|
-
"""Show model usage statistics."""
|
124
|
-
db = AsyncSQLTraceManager(db_url)
|
125
|
-
await db.initialize()
|
126
|
-
|
127
|
-
try:
|
128
|
-
df = await db.get_model_usage(model_name=model_name)
|
129
|
-
|
130
|
-
if df.empty:
|
131
|
-
print("No model usage data found.")
|
132
|
-
return
|
133
|
-
|
134
|
-
print(f"\n{'=' * 100}")
|
135
|
-
print(f"{'Model Usage Statistics':^100}")
|
136
|
-
print(f"{'=' * 100}\n")
|
137
|
-
|
138
|
-
print(df.to_string(index=False))
|
139
|
-
finally:
|
140
|
-
await db.close()
|
141
|
-
|
142
|
-
|
143
|
-
async def main():
|
144
|
-
parser = argparse.ArgumentParser(description="Query experiments from Turso/sqld (v3)")
|
145
|
-
parser.add_argument(
|
146
|
-
"-u", "--url", default="sqlite+libsql://http://127.0.0.1:8080", help="Turso database URL"
|
147
|
-
)
|
148
|
-
parser.add_argument(
|
149
|
-
"-e", "--experiment", help="Show details for specific experiment ID (can be partial)"
|
150
|
-
)
|
151
|
-
parser.add_argument("-m", "--model", help="Show usage for specific model")
|
152
|
-
parser.add_argument("--usage", action="store_true", help="Show model usage statistics")
|
153
|
-
|
154
|
-
args = parser.parse_args()
|
155
|
-
|
156
|
-
if args.usage or args.model:
|
157
|
-
await show_model_usage(args.url, args.model)
|
158
|
-
elif args.experiment:
|
159
|
-
await show_experiment_details(args.url, args.experiment)
|
160
|
-
else:
|
161
|
-
await list_experiments(args.url)
|
162
|
-
|
163
|
-
|
164
|
-
if __name__ == "__main__":
|
165
|
-
asyncio.run(main())
|
synth_ai/tui/dashboard.py
DELETED
@@ -1,329 +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 asyncio
|
9
|
-
import logging
|
10
|
-
from datetime import datetime
|
11
|
-
from typing import List, Optional, Dict, Any
|
12
|
-
from urllib.parse import urlparse
|
13
|
-
|
14
|
-
from textual.app import App, ComposeResult
|
15
|
-
from textual.containers import Container, Horizontal, Vertical
|
16
|
-
from textual.widgets import (
|
17
|
-
Header, Footer, DataTable, Static, Input, Button,
|
18
|
-
TabbedContent, TabPane, Label, ProgressBar
|
19
|
-
)
|
20
|
-
from textual.reactive import reactive
|
21
|
-
from textual.binding import Binding
|
22
|
-
from textual import on
|
23
|
-
from textual.timer import Timer
|
24
|
-
|
25
|
-
from ..tracing_v3.turso.manager import AsyncSQLTraceManager
|
26
|
-
|
27
|
-
class ExperimentRow:
|
28
|
-
"""Data structure for experiment display."""
|
29
|
-
def __init__(self, exp_id: str, name: str, description: str,
|
30
|
-
created_at: datetime, sessions: int, events: int,
|
31
|
-
messages: int, cost: float, tokens: int):
|
32
|
-
self.exp_id = exp_id
|
33
|
-
self.name = name or "Unnamed"
|
34
|
-
self.description = description or ""
|
35
|
-
self.created_at = created_at
|
36
|
-
self.sessions = sessions
|
37
|
-
self.events = events
|
38
|
-
self.messages = messages
|
39
|
-
self.cost = cost
|
40
|
-
self.tokens = tokens
|
41
|
-
|
42
|
-
def to_row(self) -> List[str]:
|
43
|
-
"""Convert to table row format."""
|
44
|
-
return [
|
45
|
-
self.exp_id[:8], # Shortened ID
|
46
|
-
self.name[:20], # Truncated name
|
47
|
-
str(self.sessions),
|
48
|
-
str(self.events),
|
49
|
-
str(self.messages),
|
50
|
-
f"${self.cost:.4f}",
|
51
|
-
f"{self.tokens:,}",
|
52
|
-
self.created_at.strftime("%H:%M")
|
53
|
-
]
|
54
|
-
|
55
|
-
class ExperimentTable(DataTable):
|
56
|
-
"""Custom DataTable for experiments with refresh capability."""
|
57
|
-
|
58
|
-
def __init__(self, **kwargs):
|
59
|
-
super().__init__(**kwargs)
|
60
|
-
self.experiments: List[ExperimentRow] = []
|
61
|
-
self.selected_exp_id: Optional[str] = None
|
62
|
-
|
63
|
-
def setup_table(self):
|
64
|
-
"""Initialize table columns."""
|
65
|
-
self.add_columns(
|
66
|
-
"ID", "Name", "Sessions", "Events",
|
67
|
-
"Messages", "Cost", "Tokens", "Time"
|
68
|
-
)
|
69
|
-
|
70
|
-
async def refresh_data(self, db_manager: AsyncSQLTraceManager):
|
71
|
-
"""Refresh experiment data from database."""
|
72
|
-
try:
|
73
|
-
# Get experiment list with stats using raw query
|
74
|
-
df = await db_manager.query_traces("""
|
75
|
-
SELECT
|
76
|
-
e.experiment_id,
|
77
|
-
e.name,
|
78
|
-
e.description,
|
79
|
-
e.created_at,
|
80
|
-
COUNT(DISTINCT st.session_id) as num_sessions,
|
81
|
-
COUNT(DISTINCT ev.id) as num_events,
|
82
|
-
COUNT(DISTINCT m.id) as num_messages,
|
83
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.cost_usd ELSE 0 END) / 100.0 as total_cost,
|
84
|
-
SUM(CASE WHEN ev.event_type = 'cais' THEN ev.total_tokens ELSE 0 END) as total_tokens
|
85
|
-
FROM experiments e
|
86
|
-
LEFT JOIN session_traces st ON e.experiment_id = st.experiment_id
|
87
|
-
LEFT JOIN events ev ON st.session_id = ev.session_id
|
88
|
-
LEFT JOIN messages m ON st.session_id = m.session_id
|
89
|
-
GROUP BY e.experiment_id, e.name, e.description, e.created_at
|
90
|
-
ORDER BY e.created_at DESC
|
91
|
-
""")
|
92
|
-
|
93
|
-
self.experiments.clear()
|
94
|
-
self.clear()
|
95
|
-
|
96
|
-
if not df.empty:
|
97
|
-
for _, row in df.iterrows():
|
98
|
-
exp_row = ExperimentRow(
|
99
|
-
exp_id=row['experiment_id'],
|
100
|
-
name=row['name'],
|
101
|
-
description=row['description'],
|
102
|
-
created_at=row['created_at'],
|
103
|
-
sessions=int(row['num_sessions'] or 0),
|
104
|
-
events=int(row['num_events'] or 0),
|
105
|
-
messages=int(row['num_messages'] or 0),
|
106
|
-
cost=float(row['total_cost'] or 0.0),
|
107
|
-
tokens=int(row['total_tokens'] or 0)
|
108
|
-
)
|
109
|
-
self.experiments.append(exp_row)
|
110
|
-
self.add_row(*exp_row.to_row(), key=exp_row.exp_id)
|
111
|
-
|
112
|
-
except Exception as e:
|
113
|
-
logging.error(f"Failed to refresh experiments: {e}")
|
114
|
-
|
115
|
-
def get_selected_experiment(self) -> Optional[ExperimentRow]:
|
116
|
-
"""Get currently selected experiment."""
|
117
|
-
if self.cursor_row >= 0 and self.cursor_row < len(self.experiments):
|
118
|
-
return self.experiments[self.cursor_row]
|
119
|
-
return None
|
120
|
-
|
121
|
-
class ExperimentDetail(Static):
|
122
|
-
"""Detailed view of selected experiment."""
|
123
|
-
|
124
|
-
def __init__(self, **kwargs):
|
125
|
-
super().__init__(**kwargs)
|
126
|
-
self.current_experiment: Optional[ExperimentRow] = None
|
127
|
-
|
128
|
-
def update_experiment(self, experiment: Optional[ExperimentRow]):
|
129
|
-
"""Update the displayed experiment details."""
|
130
|
-
self.current_experiment = experiment
|
131
|
-
if experiment:
|
132
|
-
details = f"""
|
133
|
-
🔬 **{experiment.name}**
|
134
|
-
ID: {experiment.exp_id}
|
135
|
-
Description: {experiment.description or 'No description'}
|
136
|
-
|
137
|
-
📊 **Statistics**
|
138
|
-
Sessions: {experiment.sessions}
|
139
|
-
Events: {experiment.events}
|
140
|
-
Messages: {experiment.messages}
|
141
|
-
Cost: ${experiment.cost:.4f}
|
142
|
-
Tokens: {experiment.tokens:,}
|
143
|
-
|
144
|
-
🕒 **Created**: {experiment.created_at.strftime('%Y-%m-%d %H:%M:%S')}
|
145
|
-
""".strip()
|
146
|
-
else:
|
147
|
-
details = "Select an experiment to view details"
|
148
|
-
|
149
|
-
self.update(details)
|
150
|
-
|
151
|
-
class DatabaseStatus(Static):
|
152
|
-
"""Display database connection status."""
|
153
|
-
|
154
|
-
connection_status = reactive("🔴 Disconnected")
|
155
|
-
|
156
|
-
def __init__(self, **kwargs):
|
157
|
-
super().__init__(**kwargs)
|
158
|
-
|
159
|
-
def render(self) -> str:
|
160
|
-
return f"Database: {self.connection_status}"
|
161
|
-
|
162
|
-
def set_connected(self, url: str):
|
163
|
-
parsed = urlparse(url)
|
164
|
-
host_info = f"{parsed.hostname}:{parsed.port}" if parsed.port else str(parsed.hostname)
|
165
|
-
self.connection_status = f"🟢 Connected ({host_info})"
|
166
|
-
|
167
|
-
def set_disconnected(self, error: str = ""):
|
168
|
-
error_text = f" - {error}" if error else ""
|
169
|
-
self.connection_status = f"🔴 Disconnected{error_text}"
|
170
|
-
|
171
|
-
class SynthDashboard(App):
|
172
|
-
"""Main Synth AI TUI Dashboard application."""
|
173
|
-
|
174
|
-
CSS = """
|
175
|
-
Screen {
|
176
|
-
layout: grid;
|
177
|
-
grid-size: 2 3;
|
178
|
-
grid-gutter: 1;
|
179
|
-
}
|
180
|
-
|
181
|
-
#header {
|
182
|
-
column-span: 2;
|
183
|
-
height: 3;
|
184
|
-
}
|
185
|
-
|
186
|
-
#experiments-table {
|
187
|
-
row-span: 2;
|
188
|
-
}
|
189
|
-
|
190
|
-
#experiment-detail {
|
191
|
-
height: 1fr;
|
192
|
-
}
|
193
|
-
|
194
|
-
#status-bar {
|
195
|
-
column-span: 2;
|
196
|
-
height: 3;
|
197
|
-
}
|
198
|
-
|
199
|
-
ExperimentTable {
|
200
|
-
height: 100%;
|
201
|
-
}
|
202
|
-
|
203
|
-
ExperimentDetail {
|
204
|
-
border: solid $primary;
|
205
|
-
padding: 1;
|
206
|
-
height: 100%;
|
207
|
-
}
|
208
|
-
|
209
|
-
DatabaseStatus {
|
210
|
-
height: 1;
|
211
|
-
padding: 0 1;
|
212
|
-
}
|
213
|
-
"""
|
214
|
-
|
215
|
-
BINDINGS = [
|
216
|
-
Binding("q", "quit", "Quit"),
|
217
|
-
Binding("r", "refresh", "Refresh"),
|
218
|
-
Binding("d", "toggle_debug", "Debug"),
|
219
|
-
("ctrl+c", "quit", "Quit"),
|
220
|
-
]
|
221
|
-
|
222
|
-
def __init__(self, db_url: str = "sqlite+aiosqlite:///./synth_ai.db/dbs/default/data"):
|
223
|
-
super().__init__()
|
224
|
-
self.db_url = db_url
|
225
|
-
self.db_manager: Optional[AsyncSQLTraceManager] = None
|
226
|
-
self.refresh_timer: Optional[Timer] = None
|
227
|
-
|
228
|
-
def compose(self) -> ComposeResult:
|
229
|
-
"""Create the UI layout."""
|
230
|
-
yield Header(show_clock=True)
|
231
|
-
|
232
|
-
with Container(id="experiments-table"):
|
233
|
-
yield Static("🧪 Experiments", classes="section-title")
|
234
|
-
yield ExperimentTable(id="experiments")
|
235
|
-
|
236
|
-
with Container(id="experiment-detail"):
|
237
|
-
yield Static("📋 Details", classes="section-title")
|
238
|
-
yield ExperimentDetail(id="detail")
|
239
|
-
|
240
|
-
with Container(id="status-bar"):
|
241
|
-
yield DatabaseStatus(id="db-status")
|
242
|
-
yield Footer()
|
243
|
-
|
244
|
-
async def on_mount(self) -> None:
|
245
|
-
"""Initialize the app when mounted."""
|
246
|
-
# Setup database connection
|
247
|
-
try:
|
248
|
-
self.db_manager = AsyncSQLTraceManager(self.db_url)
|
249
|
-
await self.db_manager.initialize()
|
250
|
-
|
251
|
-
db_status = self.query_one("#db-status", DatabaseStatus)
|
252
|
-
db_status.set_connected(self.db_url)
|
253
|
-
|
254
|
-
except Exception as e:
|
255
|
-
logging.error(f"Failed to connect to database: {e}")
|
256
|
-
db_status = self.query_one("#db-status", DatabaseStatus)
|
257
|
-
db_status.set_disconnected(str(e))
|
258
|
-
|
259
|
-
# Setup experiment table
|
260
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
261
|
-
exp_table.setup_table()
|
262
|
-
|
263
|
-
# Initial data load
|
264
|
-
await self.action_refresh()
|
265
|
-
|
266
|
-
# Start auto-refresh timer (every 5 seconds)
|
267
|
-
self.refresh_timer = self.set_interval(5.0, self._auto_refresh)
|
268
|
-
|
269
|
-
async def _auto_refresh(self) -> None:
|
270
|
-
"""Auto-refresh data periodically."""
|
271
|
-
if self.db_manager:
|
272
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
273
|
-
await exp_table.refresh_data(self.db_manager)
|
274
|
-
|
275
|
-
async def action_refresh(self) -> None:
|
276
|
-
"""Manual refresh action."""
|
277
|
-
if self.db_manager:
|
278
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
279
|
-
await exp_table.refresh_data(self.db_manager)
|
280
|
-
|
281
|
-
async def action_quit(self) -> None:
|
282
|
-
"""Quit the application."""
|
283
|
-
if self.refresh_timer:
|
284
|
-
self.refresh_timer.stop()
|
285
|
-
if self.db_manager:
|
286
|
-
await self.db_manager.close()
|
287
|
-
self.exit()
|
288
|
-
|
289
|
-
def action_toggle_debug(self) -> None:
|
290
|
-
"""Toggle debug mode."""
|
291
|
-
# Could add debug panel or logging level toggle
|
292
|
-
pass
|
293
|
-
|
294
|
-
@on(DataTable.RowHighlighted, "#experiments")
|
295
|
-
def on_experiment_selected(self, event: DataTable.RowHighlighted) -> None:
|
296
|
-
"""Handle experiment selection."""
|
297
|
-
exp_table = self.query_one("#experiments", ExperimentTable)
|
298
|
-
selected_exp = exp_table.get_selected_experiment()
|
299
|
-
|
300
|
-
detail_panel = self.query_one("#detail", ExperimentDetail)
|
301
|
-
detail_panel.update_experiment(selected_exp)
|
302
|
-
|
303
|
-
def main():
|
304
|
-
"""Main entry point for the dashboard."""
|
305
|
-
import argparse
|
306
|
-
|
307
|
-
parser = argparse.ArgumentParser(description="Synth AI Interactive Dashboard")
|
308
|
-
parser.add_argument(
|
309
|
-
"-u", "--url",
|
310
|
-
default="sqlite+libsql://http://127.0.0.1:8080",
|
311
|
-
help="Database URL (default: sqlite+libsql://http://127.0.0.1:8080)"
|
312
|
-
)
|
313
|
-
parser.add_argument(
|
314
|
-
"--debug",
|
315
|
-
action="store_true",
|
316
|
-
help="Enable debug logging"
|
317
|
-
)
|
318
|
-
|
319
|
-
args = parser.parse_args()
|
320
|
-
|
321
|
-
if args.debug:
|
322
|
-
logging.basicConfig(level=logging.DEBUG)
|
323
|
-
|
324
|
-
# Run the dashboard
|
325
|
-
app = SynthDashboard(db_url=args.url)
|
326
|
-
app.run()
|
327
|
-
|
328
|
-
if __name__ == "__main__":
|
329
|
-
main()
|
@@ -1,203 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: synth-ai
|
3
|
-
Version: 0.2.4.dev6
|
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: google
|
64
|
-
Requires-Dist: google-api-core>=2.0.0; extra == "google"
|
65
|
-
Requires-Dist: google-generativeai>=0.8.0; extra == "google"
|
66
|
-
Requires-Dist: google-genai>=1.0.0; extra == "google"
|
67
|
-
Provides-Extra: mistral
|
68
|
-
Requires-Dist: mistralai>=1.0.0; extra == "mistral"
|
69
|
-
Provides-Extra: research
|
70
|
-
Requires-Dist: crafter>=1.8.3; extra == "research"
|
71
|
-
Requires-Dist: datasets>=4.0.0; extra == "research"
|
72
|
-
Provides-Extra: all
|
73
|
-
Requires-Dist: google-api-core>=2.0.0; extra == "all"
|
74
|
-
Requires-Dist: google-generativeai>=0.8.0; extra == "all"
|
75
|
-
Requires-Dist: google-genai>=1.0.0; extra == "all"
|
76
|
-
Requires-Dist: mistralai>=1.0.0; extra == "all"
|
77
|
-
Requires-Dist: crafter>=1.8.3; extra == "all"
|
78
|
-
Requires-Dist: datasets>=4.0.0; extra == "all"
|
79
|
-
Dynamic: license-file
|
80
|
-
|
81
|
-
# Synth AI
|
82
|
-
|
83
|
-
Modern Compound AI System Development
|
84
|
-
|
85
|
-
**Comprehensive AI Framework for Language Models, Environments, and Observability**
|
86
|
-
|
87
|
-
[](https://www.python.org/)
|
88
|
-
[](LICENSE)
|
89
|
-
[](https://pypi.org/project/synth-ai/)
|
90
|
-

|
91
|
-

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