forked from retoor/devplacepy
yex
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import sys
|
||||
|
||||
from devplacepy.cli._shared import _audit_cli
|
||||
|
||||
|
||||
def cmd_gateway_quota_list(args):
|
||||
from devplacepy.services.openai_gateway import quota
|
||||
|
||||
rules = quota.quota_rule_store.list()
|
||||
if not rules:
|
||||
print("No quota rules. Every caller is capped by the global defaults on /admin/services/openai.")
|
||||
return
|
||||
for rule in rules:
|
||||
spent = quota.spent_24h(rule["owner_kind"], rule["owner_id"], rule["app_reference"])
|
||||
scope = ", ".join(
|
||||
f"{key}={rule[key]}" for key in ("owner_kind", "owner_id", "app_reference") if rule[key]
|
||||
) or "(no dimensions - invalid)"
|
||||
limit = "unlimited" if rule["limit_usd"] == 0 else f"${rule['limit_usd']:.2f}/24h"
|
||||
active = "active" if rule["is_active"] else "inactive"
|
||||
label = f" - {rule['label']}" if rule["label"] else ""
|
||||
print(f"{rule['uid']} [{scope}] {limit} spent=${spent:.4f} {active}{label}")
|
||||
|
||||
|
||||
def cmd_gateway_quota_set(args):
|
||||
from pydantic import ValidationError
|
||||
from devplacepy.services.openai_gateway import quota
|
||||
|
||||
try:
|
||||
payload = quota.QuotaRuleIn(
|
||||
owner_kind=args.owner_kind,
|
||||
owner_id=args.owner_id,
|
||||
app_reference=args.app_reference,
|
||||
limit_usd=args.limit_usd,
|
||||
is_active=not args.inactive,
|
||||
label=args.label or "",
|
||||
)
|
||||
except ValidationError as exc:
|
||||
print(f"Invalid rule: {exc.errors()[0].get('msg', exc)}")
|
||||
sys.exit(1)
|
||||
saved = quota.quota_rule_store.set(payload, uid=args.uid, created_by="cli")
|
||||
_audit_cli(
|
||||
"gateway.quota_rule.update",
|
||||
f"CLI saved gateway quota rule {saved['uid']}",
|
||||
metadata={
|
||||
"owner_kind": saved["owner_kind"],
|
||||
"owner_id": saved["owner_id"],
|
||||
"app_reference": saved["app_reference"],
|
||||
"limit_usd": saved["limit_usd"],
|
||||
},
|
||||
target_type="gateway_quota_rule",
|
||||
target_uid=saved["uid"],
|
||||
)
|
||||
print(f"Saved quota rule {saved['uid']}")
|
||||
|
||||
|
||||
def cmd_gateway_quota_delete(args):
|
||||
from devplacepy.services.openai_gateway import quota
|
||||
|
||||
if not quota.quota_rule_store.remove(args.uid):
|
||||
print(f"Quota rule '{args.uid}' not found")
|
||||
sys.exit(1)
|
||||
_audit_cli(
|
||||
"gateway.quota_rule.delete",
|
||||
f"CLI deleted gateway quota rule {args.uid}",
|
||||
target_type="gateway_quota_rule",
|
||||
target_uid=args.uid,
|
||||
)
|
||||
print(f"Deleted quota rule {args.uid}")
|
||||
|
||||
|
||||
def register_gateway(subparsers):
|
||||
gateway = subparsers.add_parser("gateway", help="AI gateway management")
|
||||
gateway_sub = gateway.add_subparsers(title="action", dest="action")
|
||||
|
||||
quota = gateway_sub.add_parser("quota", help="Manage rolling-24h AI gateway quota rules")
|
||||
quota_sub = quota.add_subparsers(title="sub-action", dest="sub_action")
|
||||
|
||||
quota_list = quota_sub.add_parser("list", help="List all quota rules and their current 24h spend")
|
||||
quota_list.set_defaults(func=cmd_gateway_quota_list)
|
||||
|
||||
quota_set = quota_sub.add_parser(
|
||||
"set", help="Create or update a quota rule (scope by role/user/app, any combination)"
|
||||
)
|
||||
quota_set.add_argument("--uid", help="Existing rule uid to update; omit to create a new rule")
|
||||
quota_set.add_argument(
|
||||
"--owner-kind",
|
||||
choices=("internal", "key", "user", "admin", "anonymous"),
|
||||
help="Role to scope by. Omit for any role",
|
||||
)
|
||||
quota_set.add_argument("--owner-id", help="Specific user uid to scope by. Omit for any caller")
|
||||
quota_set.add_argument("--app-reference", help="App label to scope by. Omit for any app")
|
||||
quota_set.add_argument(
|
||||
"--limit-usd", type=float, required=True, help="Rolling 24h USD cap (0 = unlimited)"
|
||||
)
|
||||
quota_set.add_argument("--label", help="Optional admin-facing note")
|
||||
quota_set.add_argument("--inactive", action="store_true", help="Create the rule disabled")
|
||||
quota_set.set_defaults(func=cmd_gateway_quota_set)
|
||||
|
||||
quota_delete = quota_sub.add_parser("delete", help="Delete a quota rule by uid")
|
||||
quota_delete.add_argument("uid", help="Quota rule uid")
|
||||
quota_delete.set_defaults(func=cmd_gateway_quota_delete)
|
||||
@@ -13,6 +13,7 @@ from devplacepy.cli.backups import register_backups
|
||||
from devplacepy.cli.containers import register_containers
|
||||
from devplacepy.cli.migrate import register_migrate
|
||||
from devplacepy.cli.game import register_game
|
||||
from devplacepy.cli.gateway import register_gateway
|
||||
|
||||
|
||||
def build_parser():
|
||||
@@ -30,6 +31,7 @@ def build_parser():
|
||||
register_containers(sub)
|
||||
register_migrate(sub)
|
||||
register_game(sub)
|
||||
register_gateway(sub)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
Reference in New Issue
Block a user