Virgil split go-ai into standalone modules (go-agentic, go-ml, go-mlx, go-rag). This migrates all CLI imports to the new module paths and fixes API mismatches from the split. Key changes: - go-ai/agentic → go-agentic (cmd/ai, cmd/dev) - go-ai/ml → go-ml (31 files in cmd/ml) - go-ai/rag → go-rag (3 files in cmd/rag) - go-ai/mlx → go-mlx (1 file) - Fix go.work path (../core → ../go) - Add all split repos to go.work and go.mod - Simplify daemon to goroutine-based MCP (remove missing supervisor) - Wire go-agentic SQLiteRegistry into dispatch watch (--agent-id flag) - Add `core ai agent fleet` command for local registry status - Fix rag collections API (PointCount, Status string) - Fix ml live/expand-status to use available go-ml API Co-Authored-By: Charon <charon@lethean.io>
82 lines
2.3 KiB
Go
82 lines
2.3 KiB
Go
package ml
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"forge.lthn.ai/core/go/pkg/cli"
|
|
"forge.lthn.ai/core/go-ml"
|
|
)
|
|
|
|
const targetTotal = 15000
|
|
|
|
var liveCmd = &cli.Command{
|
|
Use: "live",
|
|
Short: "Show live generation progress from InfluxDB",
|
|
Long: "Queries InfluxDB for real-time generation progress, worker breakdown, and domain/voice counts.",
|
|
RunE: runLive,
|
|
}
|
|
|
|
func runLive(cmd *cli.Command, args []string) error {
|
|
influx := ml.NewInfluxClient(influxURL, influxDB)
|
|
|
|
// Total completed generations
|
|
totalRows, err := influx.QuerySQL("SELECT count(DISTINCT i) AS n FROM gold_gen")
|
|
if err != nil {
|
|
return fmt.Errorf("live: query total: %w", err)
|
|
}
|
|
total := sqlScalar(totalRows)
|
|
|
|
// Distinct domains and voices
|
|
domainRows, err := influx.QuerySQL("SELECT count(DISTINCT d) AS n FROM gold_gen")
|
|
if err != nil {
|
|
return fmt.Errorf("live: query domains: %w", err)
|
|
}
|
|
domains := sqlScalar(domainRows)
|
|
|
|
voiceRows, err := influx.QuerySQL("SELECT count(DISTINCT v) AS n FROM gold_gen")
|
|
if err != nil {
|
|
return fmt.Errorf("live: query voices: %w", err)
|
|
}
|
|
voices := sqlScalar(voiceRows)
|
|
|
|
// Per-worker breakdown
|
|
workers, err := influx.QuerySQL("SELECT w, count(DISTINCT i) AS n FROM gold_gen GROUP BY w ORDER BY n DESC")
|
|
if err != nil {
|
|
return fmt.Errorf("live: query workers: %w", err)
|
|
}
|
|
|
|
pct := float64(total) / float64(targetTotal) * 100
|
|
remaining := targetTotal - total
|
|
|
|
fmt.Fprintln(os.Stdout, "Golden Set Live Status (from InfluxDB)")
|
|
fmt.Fprintln(os.Stdout, "─────────────────────────────────────────────")
|
|
fmt.Fprintf(os.Stdout, " Total: %d / %d (%.1f%%)\n", total, targetTotal, pct)
|
|
fmt.Fprintf(os.Stdout, " Remaining: %d\n", remaining)
|
|
fmt.Fprintf(os.Stdout, " Domains: %d\n", domains)
|
|
fmt.Fprintf(os.Stdout, " Voices: %d\n", voices)
|
|
fmt.Fprintln(os.Stdout)
|
|
fmt.Fprintln(os.Stdout, " Workers:")
|
|
for _, w := range workers {
|
|
name := w["w"]
|
|
n := w["n"]
|
|
marker := ""
|
|
if name == "migration" {
|
|
marker = " (seed data)"
|
|
}
|
|
fmt.Fprintf(os.Stdout, " %-20s %6s generations%s\n", name, n, marker)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// sqlScalar extracts the first numeric value from a QuerySQL result.
|
|
func sqlScalar(rows []map[string]interface{}) int {
|
|
if len(rows) == 0 {
|
|
return 0
|
|
}
|
|
for _, v := range rows[0] {
|
|
return toInt(v)
|
|
}
|
|
return 0
|
|
}
|