A scoped window read as "Fable weekly" beside "Session" and "Weekly", so the one row that names a model was also the one row in lowercase. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
104 lines
5.0 KiB
Bash
104 lines
5.0 KiB
Bash
#!/bin/bash
|
|
|
|
source "$(dirname "$0")/base-test.sh"
|
|
|
|
require_command jq
|
|
require_command python3
|
|
|
|
# probe_limits reaches Anthropic, so the reader that interprets its answer is
|
|
# exercised on its own: the collector loads as a module, and a recorded payload
|
|
# stands in for the response.
|
|
read_limits() {
|
|
COLLECTOR="$ROOT/bin/omarchy-agent-usage-claude" PAYLOAD="$1" python3 - <<'PY'
|
|
import importlib.machinery, importlib.util, io, json, os
|
|
|
|
loader = importlib.machinery.SourceFileLoader("collector", os.environ["COLLECTOR"])
|
|
spec = importlib.util.spec_from_loader(loader.name, loader)
|
|
collector = importlib.util.module_from_spec(spec)
|
|
loader.exec_module(collector)
|
|
|
|
collector.urllib.request.urlopen = lambda request, timeout=None: io.BytesIO(os.environ["PAYLOAD"].encode())
|
|
|
|
print(json.dumps(collector.probe_limits("token")))
|
|
PY
|
|
}
|
|
|
|
# The two flat buckets, then every scoped shape that matters: a model's weekly
|
|
# window, a second window for that same model, a model that names only an id,
|
|
# and — dropped — a repeat of a window already read, a blank name, and a
|
|
# percent that will not parse.
|
|
limits=$(read_limits '{
|
|
"five_hour": { "utilization": 78.0 },
|
|
"seven_day": { "utilization": 12.0 },
|
|
"seven_day_opus": null,
|
|
"limits": [
|
|
{ "kind": "session", "percent": 78, "scope": null },
|
|
{ "kind": "weekly_all", "percent": 12, "scope": null },
|
|
{ "kind": "weekly_scoped", "percent": 17, "resets_at": "2026-08-15T03:00:00+00:00",
|
|
"scope": { "model": { "id": "claude-fable-5", "display_name": "Fable" }, "surface": null } },
|
|
{ "kind": "weekly_scoped", "percent": 99, "scope": { "model": { "display_name": "Fable" } } },
|
|
{ "kind": "five_hour_scoped", "percent": 95, "scope": { "model": { "display_name": "Fable" } } },
|
|
{ "kind": "weekly_scoped", "percent": 42, "scope": { "model": { "id": "claude-opus-5", "display_name": null } } },
|
|
{ "kind": "weekly_scoped", "percent": 5, "scope": { "model": { "display_name": " " } } },
|
|
{ "kind": "weekly_scoped", "percent": "unknown", "scope": { "model": { "display_name": "Opus" } } }
|
|
]
|
|
}')
|
|
|
|
expected='[{"label":"Session (5-hour)","percent":0.78,"resetsAt":""},{"label":"Weekly (7-day)","percent":0.12,"resetsAt":""},{"label":"Fable Weekly","title":"Fable Weekly","percent":0.17,"resetsAt":"2026-08-15T03:00:00+00:00"},{"label":"Fable Session","title":"Fable Session","percent":0.95,"resetsAt":""},{"label":"claude-opus-5 Weekly","title":"claude-opus-5 Weekly","percent":0.42,"resetsAt":""}]'
|
|
[[ $(jq -c '.limits' <<<"$limits") == "$expected" ]] ||
|
|
fail "Claude collector reads every model-scoped window once and drops unusable entries" "$limits"
|
|
pass "Claude collector reads every model-scoped window once and drops unusable entries"
|
|
|
|
# A payload that speaks fractions says so in its buckets, and the scoped
|
|
# entries are read on the same scale rather than assuming percentages.
|
|
fractions=$(read_limits '{
|
|
"five_hour": { "utilization": 0.78 },
|
|
"limits": [
|
|
{ "kind": "session", "percent": 0.78, "scope": null },
|
|
{ "kind": "weekly_scoped", "percent": 0.42, "scope": { "model": { "display_name": "Fable" } } }
|
|
]
|
|
}')
|
|
|
|
[[ $(jq -c '[.limits[].percent]' <<<"$fractions") == "[0.78,0.42]" ]] ||
|
|
fail "Claude collector reads scoped percentages on the payload's own scale" "$fractions"
|
|
pass "Claude collector reads scoped percentages on the payload's own scale"
|
|
|
|
# An account with no model-scoped allowance, and an endpoint that never grew
|
|
# the array, both keep the session and weekly windows they always had.
|
|
for payload in '{"five_hour":{"utilization":78.0},"limits":[{"kind":"session","percent":78,"scope":null}]}' \
|
|
'{"five_hour":{"utilization":78.0},"seven_day":{"utilization":12.0}}'; do
|
|
[[ $(jq -c '[.limits[].label]' <<<"$(read_limits "$payload")") != *" Weekly"* ]] ||
|
|
fail "Claude collector adds no limit when the payload scopes none" "$payload"
|
|
done
|
|
pass "Claude collector adds no limit when the payload scopes none"
|
|
|
|
# The panel reads a window out of a label, and that guess cannot survive a
|
|
# model name — "Opus 5 (1M context)" parses as a one-minute window. A collector
|
|
# that states the title outright is taken at its word.
|
|
run_node_test <<'JS'
|
|
const fs = require('fs')
|
|
const source = fs.readFileSync(root + '/shell/plugins/agents/Panel.qml', 'utf8')
|
|
const start = source.indexOf('function windowIsLong')
|
|
const end = source.indexOf('// The window that decides')
|
|
assert(start > 0 && end > start, 'agents panel exposes its limit-window helpers')
|
|
eval(source.slice(start, end))
|
|
|
|
assertDeepEqual(
|
|
limitWindows({ limits: [
|
|
{ label: 'Session (5-hour)', percent: 0.78, resetsAt: '' },
|
|
{ label: 'Opus 5 (1M context) Weekly', title: 'Opus 5 (1M context) Weekly', percent: 0.42, resetsAt: '' }
|
|
] }),
|
|
[
|
|
{ title: 'Session', percent: 0.78, resetAt: '' },
|
|
{ title: 'Opus 5 (1M context) Weekly', percent: 0.42, resetAt: '' }
|
|
],
|
|
'agents panel titles a limit off the collector when it states one'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
limitWindows({ limits: [{ label: 'Weekly (7-day)', percent: 0.12, resetsAt: '' }] }),
|
|
[{ title: 'Weekly', percent: 0.12, resetAt: '' }],
|
|
'agents panel still reads a window out of a label that carries no title'
|
|
)
|
|
JS
|