Skip to content
Open
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
8 changes: 7 additions & 1 deletion bin/omarchy-agent-usage-agy
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,14 @@ def harness_login(source, data):
}


# omp and pi both move their whole agent tree when PI_CODING_AGENT_DIR is
# set, so both sign-ins are looked for where it points.
def omp_agent_dir():
return Path(os.environ.get("PI_CODING_AGENT_DIR") or (Path.home() / ".omp" / "agent"))


def omp_logins():
database = Path.home() / ".omp" / "agent" / "agent.db"
database = omp_agent_dir() / "agent.db"
if not database.is_file():
return []
try:
Expand Down
2 changes: 1 addition & 1 deletion shell/plugins/agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ The collector asks the client's own key endpoint for the subscription's session

### Antigravity

The record's id is `agy`, the name the default agent knows it by. The plan and limits are asked of Google's Cloud Code API with whichever Antigravity sign-in is on the machine: the one `agy` keeps in the Secret Service keyring (service `gemini`, username `antigravity`) or, without a keyring, in `antigravity-oauth-token` under `AGY_DIR`; omp's `google-antigravity` sign-in in `~/.omp/agent/agent.db`; pi's in `auth.json` (under `PI_CODING_AGENT_DIR` when set); and opencode's `google` sign-in, only when the Antigravity plugin's `antigravity-accounts.json` is there. The token refreshed most recently is asked first, and one Google refuses gives way to the next. Those stores are only ever read. A lapsed token shows the last limits as paused until the harness that owns it runs again; a lapsed omp sign-in is asked through `omp usage`, which renews it. Each Google account keeps its own last answer, so another account's limits never stand in. `CLOUD_CODE_URL` moves the endpoint, over https only.
The record's id is `agy`, the name the default agent knows it by. The plan and limits are asked of Google's Cloud Code API with whichever Antigravity sign-in is on the machine: the one `agy` keeps in the Secret Service keyring (service `gemini`, username `antigravity`) or, without a keyring, in `antigravity-oauth-token` under `AGY_DIR`; omp's `google-antigravity` sign-in in `~/.omp/agent/agent.db`; pi's in `~/.pi/agent/auth.json`, both under `PI_CODING_AGENT_DIR` instead when it is set, since omp and pi each move their agent tree there; and opencode's `google` sign-in, only when the Antigravity plugin's `antigravity-accounts.json` is there. The token refreshed most recently is asked first, and one Google refuses gives way to the next. Those stores are only ever read. A lapsed token shows the last limits as paused until the harness that owns it runs again; a lapsed omp sign-in is asked through `omp usage`, which renews it. Each Google account keeps its own last answer, so another account's limits never stand in. `CLOUD_CODE_URL` moves the endpoint, over https only.

Local stats count `agy`'s history prompts, its conversations (a subagent's conversation counts toward the one that spawned it), and the tokens each transcript step reports, under the model the step or the last Model Selection names. Antigravity answers that pi, omp, OpenClaw (`OPENCLAW_STATE_DIR`), and opencode's plugin recorded count too, a forked copy once. No other collector counts these.

Expand Down
16 changes: 13 additions & 3 deletions test/shell.d/agent-usage-agy-harness-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def machine():
os.environ["PATH"] = f"{stubs}:{REAL_PATH}"


def omp_login(token, expires, email):
database = home() / ".omp" / "agent" / "agent.db"
def omp_login(token, expires, email, directory=None):
database = Path(directory or home() / ".omp" / "agent") / "agent.db"
database.parent.mkdir(parents=True, exist_ok=True)
database.unlink(missing_ok=True)
conn = sqlite3.connect(database)
Expand Down Expand Up @@ -78,7 +78,7 @@ def agy(*accepted):
# Every store the collector reads, so a test can tell none was written.
def stores():
return sorted((str(path), hashlib.md5(path.read_bytes()).hexdigest())
for root in (".omp", ".pi", ".local/share/opencode", ".gemini", "pi-elsewhere")
for root in (".omp", ".pi", ".local/share/opencode", ".gemini", "pi-elsewhere", "omp-elsewhere")
for path in (home() / root).rglob("*") if path.is_file())


Expand Down Expand Up @@ -195,6 +195,16 @@ record, asked = agy("moved-token")
expect("Antigravity collector reads pi's sign-in where PI_CODING_AGENT_DIR puts it", [asked, record["limits"][0]["percent"]], [["moved-token"], 0.25], record)
expect("Antigravity collector never writes pi's store", stores(), before)

# omp reads the same variable for its whole agent tree, so its database moves
# with it.
machine()
omp_login("moved-omp-token", ms_in(3600), "me@example.com", home() / "omp-elsewhere")
os.environ["PI_CODING_AGENT_DIR"] = str(home() / "omp-elsewhere")
before = stores()
record, asked = agy("moved-omp-token")
expect("Antigravity collector reads omp's sign-in where PI_CODING_AGENT_DIR puts it", [asked, record["limits"][0]["percent"]], [["moved-omp-token"], 0.25], record)
expect("Antigravity collector never writes omp's store", stores(), before)

# ---------------------------------------------------------- local stats

# OpenClaw keeps pi's format, one directory per agent; its entries carry no
Expand Down