-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
89 lines (78 loc) · 2.8 KB
/
Copy pathmain.go
File metadata and controls
89 lines (78 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Command augur is the CLI entrypoint for the Augur cost gate.
//
// Subcommands land one hito at a time (see SPEC.md). Implemented so far:
//
// augur proxy — OpenAI-compatible recording proxy (Hito 1)
// augur run — drive the agent against scenarios.yaml ×N through the proxy (Hito 2)
// augur aggregate — trace + pricing → per-scenario cost distribution (Hito 2)
// augur project — aggregate + traffic → projected unit economics with CIs (Hito 3)
//
// Still to come: gate (Hito 4).
package main
import (
"errors"
"flag"
"fmt"
"os"
)
// command is one augur subcommand: a run function plus the one-line summary
// shown in usage.
type command struct {
run func(args []string) error
summary string
}
// exitErr lets a subcommand request a specific process exit code without main
// printing an "augur <cmd>:" error line. The gate uses it to fail the build
// after it has already written its report — a budget overrun is a normal,
// expected outcome, not an internal error.
type exitErr struct{ code int }
func (e *exitErr) Error() string { return fmt.Sprintf("exit status %d", e.code) }
// commands is the subcommand dispatch table. Adding a hito's command is one
// entry here plus its run<Name> function in its own file.
var commands = map[string]command{
"proxy": {runProxy, "run the OpenAI-compatible recording proxy"},
"run": {runRun, "drive the agent against scenarios.yaml ×N through the proxy"},
"aggregate": {runAggregate, "summarize a cost trace into per-scenario distributions"},
"project": {runProject, "project a trace to production unit economics with CIs"},
"gate": {runGate, "check a projection against budget.yaml (exit 1 if over)"},
"tco": {runTCO, "show effective $/Mtok for self-hosted models (TCO)"},
}
// order fixes the usage listing (maps don't iterate deterministically).
var order = []string{"proxy", "run", "aggregate", "project", "gate", "tco"}
func main() {
if len(os.Args) < 2 {
usage()
os.Exit(2)
}
name, args := os.Args[1], os.Args[2:]
switch name {
case "-h", "--help", "help":
usage()
return
}
cmd, ok := commands[name]
if !ok {
fmt.Fprintf(os.Stderr, "augur: unknown command %q\n\n", name)
usage()
os.Exit(2)
}
if err := cmd.run(args); err != nil {
if errors.Is(err, flag.ErrHelp) {
return // flag already printed usage to stderr
}
var ee *exitErr
if errors.As(err, &ee) {
os.Exit(ee.code) // command already reported; just set the code
}
fmt.Fprintf(os.Stderr, "augur %s: %v\n", name, err)
os.Exit(1)
}
}
func usage() {
fmt.Fprintln(os.Stderr, "augur — cost-first FinOps gate for AI agents")
fmt.Fprintln(os.Stderr, "\nusage:")
for _, name := range order {
fmt.Fprintf(os.Stderr, " augur %-11s %s\n", name, commands[name].summary)
}
fmt.Fprintln(os.Stderr, "\nrun \"augur <command> -h\" for command flags.")
}