Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/crew/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "crew",
"displayName": "Crew",
"version": "0.4.0",
"version": "0.4.1",
"author": {
"name": "4nrry",
"url": "https://github.com/4nrry"
Expand Down
24 changes: 24 additions & 0 deletions plugins/crew/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,19 @@ Python e `unittest`:
| delegate depois do endurecimento do guard (allowlist de ferramentas, git so leitura, `.git` e redirect negados, `realpath`), com o mesmo `gate_once.py` | `ok`, 71 s, `finish` negado na 1a tentativa e gate verde na 2a. Nenhuma chamada legitima negada: 7 `run_command`, 3 `replace_file_content`, 2 `view_file`, todos permitidos |
| review `--diff HEAD --prompt-file` sobre esse diff | `ok`, 16 s, `approve` sem findings, arvore e `.git` inalterados, so `view_file` |

Na 0.4.1, dois runs com `gemini-4-argon-medium` no agy **1.4.2** (2026-10-18,
repo descartavel com um modulo Python, `unittest` e um checador de formato so
com stdlib no lugar do `ruff`, que nao estava instalado; mesma fatia `slugify`
\+ 3 testes):

| run | resultado |
|---|---|
| sem `.gitignore` no repo | `ok: false`, culpa do lab: o `unittest` do gate escreveu `__pycache__`, que a checagem de escopo pos-run acusou. O diff do worker estava certo. O Argon pediu um caminho absoluto inventado (um segmento do caminho do repo duplicado) e o guard negou |
| com `__pycache__/` no `.gitignore` | `ok`, 66 s, ~55 mil tokens, gate verde na 1a passada. Diff correto e no estilo do arquivo; uma unica negacao: o worker tentou rodar o checador do gate, que fica fora do repo |

O preflight de quota checou o grupo "Gemini 4 Argon", nao o "Gemini Models".
Nenhum desses runs mostra que o Argon acerta o que o Flash erra.

## O que nao foi medido

- **Nenhuma comparacao** com o Claude fazendo a mesma tarefa: nem qualidade,
Expand Down Expand Up @@ -433,6 +446,17 @@ checagem de que o `hooks.json` aponta para um executavel.

## Changelog

**0.4.1** (2026-10-18)

- Preflight de quota do agy: o grupo era achado pela familia do modelo
(`gemini`), que no agy 1.4.2 casa tambem com o grupo novo "Gemini 4 Argon".
Um Argon esgotado recusava todo run do Flash, e vice-versa, embora no plano
Pro as duas quotas sejam separadas. Agora o grupo e achado pela linha do
modelo (`flash`, `argon`, `sonnet`, `oss`), e pela familia so como fallback.
- Escalada do agy: Flash, depois `gemini-4-argon-medium`, depois
`claude-sonnet-5-5-medium`. O Argon tem quota propria e nao gasta a dos
Claude. Dois runs de fumaca, acima.

**0.4.0** (2026-10-13)

- Renomeado de `agy-worker` para `crew`: diretorio, manifesto, comandos
Expand Down
34 changes: 32 additions & 2 deletions plugins/crew/scripts/crew.py
Original file line number Diff line number Diff line change
Expand Up @@ -1179,14 +1179,30 @@ def parse_models(text: str) -> list:
if "\t" in ln and ln.split("\t", 1)[0].strip()]


EFFORT_SUFFIXES = {"low", "medium", "high", "xhigh", "max"}


def quota_groups_for(groups: list, model: str) -> list:
"""The /usage groups that meter `model`. The family alone ("gemini") is too
wide since agy 1.4.2: "Gemini 4 Argon" is its own group next to "Gemini
Models" (Flash, Pro), and on a Pro plan the two are separate quotas, so an
exhausted Argon must not refuse a Flash run nor the reverse. Match on the
model line first (flash, argon, sonnet, oss), the family only as fallback."""
def text(g):
return (str(g.get("name", "")) + " " + str(g.get("description", ""))).lower()
parts = model.lower().split("-")
lines = [p for p in parts[1:] if p not in EFFORT_SUFFIXES and not any(c.isdigit() for c in p)]
hits = [g for g in groups if any(re.search(rf"\b{re.escape(p)}\b", text(g)) for p in lines)]
return hits or [g for g in groups if parts[0] in text(g)]


def evaluate_quota(envelope: dict, model: str, min_quota: float):
"""None when there is headroom, else a refusal message."""
groups = (((envelope or {}).get("command") or {}).get("data") or {}).get("groups")
if not isinstance(groups, list):
return "nao consegui ler os grupos de quota de `agy -p /usage --output-format json`"
family = model.split("-", 1)[0].lower()
hits = [g for g in groups if family in (str(g.get("name", "")) + " "
+ str(g.get("description", ""))).lower()]
hits = quota_groups_for(groups, model)
if not hits:
return f"nenhum grupo de quota menciona {family!r}; formato do /usage mudou?"
for g in hits:
Expand Down Expand Up @@ -3048,6 +3064,20 @@ def cphook(event, payload):
check(msg and "esgotada" in msg and "2026-10-15" in msg, "quota claude esgotada")
check(evaluate_quota(usage, "gpt-oss-120b-medium", 0.05), "gpt no mesmo grupo esgotado")
check(evaluate_quota({}, "gemini-x", 0.05), "usage ilegivel recusa")
# agy 1.4.2 (2026-10-18) adds Argon as its own group; on a Pro plan it is a separate quota
argon = {"name": "Gemini 4 Argon", "description": "For paid Pro plans, Argon quota is separate. Higher "
"Argon quota (included as part of the larger Gemini quota bucket) is available on Ultra plans.",
"buckets": [{"name": "Gemini 4 Argon Weekly Limit", "remaining_fraction": 0.01,
"reset_time": "2026-10-25T01:46:00Z"}]}
groups = usage["command"]["data"]["groups"]
groups.append(argon)
check(evaluate_quota(usage, "gemini-3.8-flash-high", 0.05) is None, "argon esgotado nao barra o flash")
msg = evaluate_quota(usage, "gemini-4-argon-medium", 0.05)
check(msg and "Gemini 4 Argon" in msg, "argon esgotado barra o argon")
argon["buckets"][0]["remaining_fraction"] = 0.9
groups[0]["buckets"][0]["remaining_fraction"] = 0
check(evaluate_quota(usage, "gemini-4-argon-high", 0.05) is None, "flash esgotado nao barra o argon")
check(evaluate_quota(usage, "gemini-3.8-flash-low", 0.05), "flash esgotado barra o flash")
models = parse_models("gemini-3.8-flash-low\tGemini 3.8 Flash (Low)\nFetching available models...\n")
check(models == ["gemini-3.8-flash-low"], "parse de agy models")

Expand Down
15 changes: 12 additions & 3 deletions plugins/crew/skills/agy/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: agy
description: Especificos do backend agy (Antigravity CLI, Gemini) do plugin crew - flags do run, modelo padrao gemini-3.8-flash-high, escalada so para claude-sonnet-5-5-medium e nunca Opus, preflight de quota, hooks em .agents/hooks.json e os comandos que o agy joga para segundo plano. Use quando for delegar uma fatia ou pedir review pelo agy.
description: Especificos do backend agy (Antigravity CLI, Gemini) do plugin crew - flags do run, modelo padrao gemini-3.8-flash-high, escalada para gemini-4-argon-medium e depois claude-sonnet-5-5-medium, nunca Opus, preflight de quota, hooks em .agents/hooks.json e os comandos que o agy joga para segundo plano. Use quando for delegar uma fatia ou pedir review pelo agy.
---

# crew pelo agy
Expand Down Expand Up @@ -28,7 +28,12 @@ nenhuma no lab: nao conte com ele.

- Comece no `gemini-3.8-flash-high` (padrao).
- Se o Flash nao der conta de uma fatia (gate vermelho ate o limite, ou diff
que nao sobrevive a revisao), suba para `claude-sonnet-5-5-medium`.
que nao sobrevive a revisao), suba para `gemini-4-argon-medium`. O Argon
tem quota semanal propria no plano Pro: nao gasta a dos Gemini Flash nem a
dos Claude. `-high` so se o `-medium` tambem falhar.
- Se o Argon tambem nao der conta, `claude-sonnet-5-5-medium`.
- O Argon so passou por fumaca (n=1, fatia trivial; ver "Smoke tests" no README): nada
diz ainda que ele resolve o que o Flash erra. Revise o diff igual.
- **Nunca Opus pelo agy.** Os modelos Claude do agy dividem uma quota semanal,
e o Opus a esgota em poucas fatias.
- O modelo e validado contra `agy models` antes de rodar.
Expand All @@ -37,7 +42,11 @@ nenhuma no lab: nao conte com ele.

O preflight le `agy -p /usage` (responde sem turno de modelo) e recusa, saida
2, se o grupo do modelo tiver menos que `min_quota` (padrao 0.05) restante,
dizendo quando renova. `--no-quota-probe` pula. Com a quota esgotada, o
dizendo quando renova. O grupo e achado pela linha do modelo (`flash`,
`argon`, `sonnet`, `oss`) no nome ou na descricao do grupo, e so pela familia
(`gemini`, `claude`) se nenhum grupo citar a linha: no agy 1.4.2 o Argon tem
grupo proprio ao lado de "Gemini Models", e no plano Pro as duas quotas sao
separadas. `--no-quota-probe` pula. Com a quota esgotada, o
`opencode` e a alternativa gratis (skill `crew:opencode`).

## Antes do primeiro run
Expand Down
Loading