imbue-mngr-pi-coding-usage 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- imbue/mngr_pi_coding_usage/__init__.py +0 -0
- imbue/mngr_pi_coding_usage/plugin.py +67 -0
- imbue_mngr_pi_coding_usage-0.1.0.dist-info/METADATA +41 -0
- imbue_mngr_pi_coding_usage-0.1.0.dist-info/RECORD +6 -0
- imbue_mngr_pi_coding_usage-0.1.0.dist-info/WHEEL +4 -0
- imbue_mngr_pi_coding_usage-0.1.0.dist-info/entry_points.txt +2 -0
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""pi usage data provider for `mngr usage` (reader + writer gate).
|
|
2
|
+
|
|
3
|
+
pi loads exactly one explicit extension -- mngr_pi_coding's lifecycle extension,
|
|
4
|
+
launched with ``pi -e`` -- so the usage *writer* lives there (it already holds
|
|
5
|
+
each assistant message's cost + tokens). This package owns the two pieces that
|
|
6
|
+
are genuinely usage-specific:
|
|
7
|
+
|
|
8
|
+
1. A gate marker, provisioned per pi agent, that tells the lifecycle extension to
|
|
9
|
+
emit usage events. Without it the writer stays inert -- so usage events are
|
|
10
|
+
only written when *this* package (which ships their reader) is installed.
|
|
11
|
+
Emitting them unread would let ``mngr usage`` fall back to the wrong
|
|
12
|
+
(process-cumulative) strategy and undercount pi's per-message events.
|
|
13
|
+
2. The reader: an ``aggregate_usage_source`` hookimpl claiming the ``pi-coding``
|
|
14
|
+
source, aggregated session-incrementally (pi reports cost per message).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from imbue.mngr import hookimpl
|
|
20
|
+
from imbue.mngr.config.data_types import MngrContext
|
|
21
|
+
from imbue.mngr.hosts.host import get_agent_state_dir_path
|
|
22
|
+
from imbue.mngr.interfaces.agent import AgentInterface
|
|
23
|
+
from imbue.mngr.interfaces.host import OnlineHostInterface
|
|
24
|
+
from imbue.mngr_pi_coding.plugin import PiCodingAgent
|
|
25
|
+
from imbue.mngr_usage.api import aggregate_session_incremental
|
|
26
|
+
from imbue.mngr_usage.data_types import UsageEvent
|
|
27
|
+
from imbue.mngr_usage.data_types import UsageSnapshot
|
|
28
|
+
|
|
29
|
+
# Gate marker the lifecycle extension checks (existsSync) to decide whether to
|
|
30
|
+
# emit usage events. Kept in sync with mngr_pi_lifecycle.ts (literal "pi_emit_usage").
|
|
31
|
+
_USAGE_GATE_FILENAME = "pi_emit_usage"
|
|
32
|
+
|
|
33
|
+
# Source the pi writer emits under ($STATE_DIR/events/pi-coding/usage/...); the
|
|
34
|
+
# reader strips "/usage". A fixed harness id (not the agent subtype), so usage
|
|
35
|
+
# from any pi subtype lumps under one source. Kept in sync with mngr_pi_lifecycle.ts.
|
|
36
|
+
_PI_USAGE_SOURCE_NAME = "pi-coding"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@hookimpl
|
|
40
|
+
def on_after_provisioning(agent: AgentInterface, host: OnlineHostInterface, mngr_ctx: MngrContext) -> None:
|
|
41
|
+
"""Install the usage gate marker for pi agents so the lifecycle extension emits usage events.
|
|
42
|
+
|
|
43
|
+
Skips non-pi agents. Written to the agent state dir, which the extension
|
|
44
|
+
reads (``$MNGR_AGENT_STATE_DIR/pi_emit_usage``) once at startup.
|
|
45
|
+
"""
|
|
46
|
+
if not isinstance(agent, PiCodingAgent):
|
|
47
|
+
return
|
|
48
|
+
state_dir = get_agent_state_dir_path(host.host_dir, agent.id)
|
|
49
|
+
host.write_file(state_dir / _USAGE_GATE_FILENAME, b"1")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@hookimpl
|
|
53
|
+
def aggregate_usage_source(
|
|
54
|
+
source_name: str,
|
|
55
|
+
agents_events: dict[str, list[UsageEvent]],
|
|
56
|
+
since_seconds: int,
|
|
57
|
+
now: int,
|
|
58
|
+
) -> UsageSnapshot | None:
|
|
59
|
+
"""Aggregate the pi usage source; decline every other source.
|
|
60
|
+
|
|
61
|
+
pi reports each assistant message's own cost/tokens (not a cumulative total),
|
|
62
|
+
so this is the session-incremental strategy. Returning None for non-pi sources
|
|
63
|
+
lets the firstresult hook fall through.
|
|
64
|
+
"""
|
|
65
|
+
if source_name != _PI_USAGE_SOURCE_NAME:
|
|
66
|
+
return None
|
|
67
|
+
return aggregate_session_incremental(source_name, agents_events, since_seconds=since_seconds, now=now)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: imbue-mngr-pi-coding-usage
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: pi usage data provider for `mngr usage` (reader + writer gate; the per-message writer lives in mngr_pi_coding's lifecycle extension)
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: imbue-mngr-pi-coding==0.1.13
|
|
7
|
+
Requires-Dist: imbue-mngr-usage==0.1.5
|
|
8
|
+
Requires-Dist: imbue-mngr==0.2.16
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# imbue-mngr-pi-coding-usage
|
|
12
|
+
|
|
13
|
+
pi data provider for `mngr usage`. pi loads a single explicit extension
|
|
14
|
+
(mngr_pi_coding's lifecycle extension, via `pi -e`), so the per-message usage
|
|
15
|
+
**writer** lives there -- it already holds each assistant message's cost and
|
|
16
|
+
tokens. This package owns the two usage-specific pieces:
|
|
17
|
+
|
|
18
|
+
- **The reader**: an `aggregate_usage_source` hookimpl claiming the `pi-coding`
|
|
19
|
+
source, aggregated session-incrementally (pi reports cost per message, summed
|
|
20
|
+
per session).
|
|
21
|
+
- **The writer gate**: `on_after_provisioning` drops a `pi_emit_usage` marker in
|
|
22
|
+
each pi agent's state dir. The lifecycle extension only emits usage events when
|
|
23
|
+
that marker is present -- so the events are written exactly when their reader
|
|
24
|
+
(this package) is installed.
|
|
25
|
+
|
|
26
|
+
## What gets captured
|
|
27
|
+
|
|
28
|
+
pi computes per-message cost client-side (`usage.cost.total`), so cost is
|
|
29
|
+
**REPORTED** (no estimation). Each assistant `message_end` appends one
|
|
30
|
+
`cost_snapshot` to `events/pi-coding/usage/events.jsonl` with the reported cost,
|
|
31
|
+
tokens (`input`/`output`/`cacheRead`/`cacheWrite`), the provider-qualified model
|
|
32
|
+
(`<provider>/<model>`), and the session id (the pi session file's basename).
|
|
33
|
+
`cost_mode` is `API_KEY` (pi bills a real provider key).
|
|
34
|
+
|
|
35
|
+
## Why the writer is in the harness extension
|
|
36
|
+
|
|
37
|
+
Unlike Claude (statusline shim) or OpenCode (auto-loaded `plugin/*.ts`), pi loads
|
|
38
|
+
exactly one explicit extension owned by mngr_pi_coding. A standalone writer would
|
|
39
|
+
require a harness change either way, so the writer is folded into the lifecycle
|
|
40
|
+
extension (which already extracts the message usage), and this package stays the
|
|
41
|
+
reader + gate.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
imbue/mngr_pi_coding_usage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
imbue/mngr_pi_coding_usage/plugin.py,sha256=OIGa6d98BTMpe144EGMGIBD9Z0ymUqbLP57KHuAJS0k,3076
|
|
3
|
+
imbue_mngr_pi_coding_usage-0.1.0.dist-info/METADATA,sha256=p7eI6wKiGWO6FJzceQdrEJPoXkbdLE4FUZc3ZEZSuWY,2012
|
|
4
|
+
imbue_mngr_pi_coding_usage-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
5
|
+
imbue_mngr_pi_coding_usage-0.1.0.dist-info/entry_points.txt,sha256=ED8hJD4M8d07CEJIV-TsJzwGtS_00qf5RGQ2ZFT0Nyc,59
|
|
6
|
+
imbue_mngr_pi_coding_usage-0.1.0.dist-info/RECORD,,
|