main
py 95 lines 2.71 KB
Raw
1 #!/usr/bin/env python3
2 """Pre-flight cost estimation for the analyze workflow.
3
4 Estimates total input tokens from assembled context files, calculates
5 expected cost, and aborts (exit 1) if the estimate exceeds the hard cap.
6 """
7
8 from __future__ import annotations
9
10 import argparse
11 import sys
12 from pathlib import Path
13
14 from scripts.model_pricing import (
15 MODEL_RATES,
16 estimate_cost_usd,
17 )
18 from scripts.track_token_usage import (
19 estimate_tokens_from_path,
20 )
21
22 DEFAULT_OUTPUT_TOKENS = 2000
23 DEFAULT_MODEL = "copilot-default"
24 HARD_CAP_USD = 1.00
25
26
27 def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
28 parser = argparse.ArgumentParser(
29 description="Pre-flight token cost estimation. Aborts if estimate exceeds hard cap."
30 )
31 parser.add_argument(
32 "--context-files",
33 nargs="+",
34 type=Path,
35 required=True,
36 help="Paths to context files that will be sent as input (raw JSON, prompt, wisdom, etc.).",
37 )
38 parser.add_argument(
39 "--model",
40 default=DEFAULT_MODEL,
41 help="Model or rate profile name for cost lookup (default: copilot-default).",
42 )
43 parser.add_argument(
44 "--output-tokens",
45 type=int,
46 default=DEFAULT_OUTPUT_TOKENS,
47 help=f"Estimated output tokens (default: {DEFAULT_OUTPUT_TOKENS}).",
48 )
49 parser.add_argument(
50 "--hard-cap",
51 type=float,
52 default=HARD_CAP_USD,
53 help=f"Maximum allowed estimated cost in USD (default: {HARD_CAP_USD}).",
54 )
55 return parser.parse_args(argv)
56
57
58 def estimate_input_tokens(context_files: list[Path]) -> int:
59 """Sum estimated tokens across all context files."""
60 return sum(estimate_tokens_from_path(p) for p in context_files)
61
62
63 def main(argv: list[str] | None = None) -> int:
64 args = parse_args(argv)
65
66 input_tokens = estimate_input_tokens(args.context_files)
67 output_tokens = args.output_tokens
68 total_tokens = input_tokens + output_tokens
69 cost = estimate_cost_usd(args.model, input_tokens, output_tokens)
70
71 if cost is None:
72 print(
73 f"::warning::Unknown model '{args.model}' — cannot estimate cost. "
74 f"Known models: {', '.join(sorted(MODEL_RATES.keys()))}",
75 file=sys.stderr,
76 )
77 return 1
78
79 print(
80 f"::notice::Pre-flight estimate: {input_tokens} input + {output_tokens} output "
81 f"= {total_tokens} tokens → ${cost:.4f} (cap: ${args.hard_cap:.2f}, model: {args.model})"
82 )
83
84 if cost > args.hard_cap:
85 print(
86 f"::error::Estimated cost ${cost:.4f} exceeds hard cap ${args.hard_cap:.2f}. Aborting.",
87 file=sys.stderr,
88 )
89 return 1
90
91 return 0
92
93
94 if __name__ == "__main__":
95 raise SystemExit(main())