@danypops/jittor 0.1.0
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.
- package/README.md +54 -0
- package/docs/CALIBRATION.md +102 -0
- package/docs/PROVIDER_RESEARCH.md +237 -0
- package/docs/USAGE_PRIOR_ART.md +64 -0
- package/extension/src/footer.ts +232 -0
- package/extension/src/index.ts +317 -0
- package/extension/src/service-client.ts +26 -0
- package/extension/src/settings.ts +59 -0
- package/extension/src/tui.ts +180 -0
- package/extension/src/usage.ts +169 -0
- package/package.json +30 -0
- package/src/adapters/sqlite-metric-store.ts +99 -0
- package/src/cli.ts +73 -0
- package/src/client.ts +57 -0
- package/src/config.ts +20 -0
- package/src/constants.ts +26 -0
- package/src/daemon.ts +88 -0
- package/src/db.ts +50 -0
- package/src/domain/metric.ts +54 -0
- package/src/domain/usage.ts +112 -0
- package/src/policy.ts +220 -0
- package/src/ports/metric-store.ts +9 -0
- package/src/ports/router-controller.ts +42 -0
- package/src/ports/telemetry-source.ts +15 -0
- package/src/providers/codex-contracts.ts +307 -0
- package/src/providers/codex.ts +102 -0
- package/src/providers/openrouter-contracts.ts +218 -0
- package/src/providers/openrouter.ts +71 -0
- package/src/providers/telemetry-sources.ts +69 -0
- package/src/router.ts +158 -0
- package/src/service.ts +158 -0
- package/src/state.ts +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Jittor
|
|
2
|
+
|
|
3
|
+
**Just-in-Time Token Optimizing Router** for Pi.
|
|
4
|
+
|
|
5
|
+
Jittor observes provider budgets and per-turn usage, computes whether the current burn rate is sustainable, and applies a deterministic policy before each model request:
|
|
6
|
+
|
|
7
|
+
1. continue
|
|
8
|
+
2. throttle
|
|
9
|
+
3. lower thinking
|
|
10
|
+
4. switch model
|
|
11
|
+
5. switch provider
|
|
12
|
+
6. halt
|
|
13
|
+
|
|
14
|
+
Initial telemetry providers:
|
|
15
|
+
|
|
16
|
+
- ChatGPT-authenticated Codex subscription usage
|
|
17
|
+
- OpenRouter API key usage, response accounting, and model pricing
|
|
18
|
+
|
|
19
|
+
Jittor follows the Papyrus daemon architecture: a supervised Bun service owns SQLite and provider polling; the native Pi extension uses an authenticated loopback client and applies model/thinking decisions.
|
|
20
|
+
|
|
21
|
+
## Architecture
|
|
22
|
+
|
|
23
|
+
The initial service scaffold is split into domain, ports, and adapters:
|
|
24
|
+
|
|
25
|
+
- `src/domain/metric.ts` — normalized timestamped metric observations
|
|
26
|
+
- `src/ports/metric-store.ts` — storage boundary used by the application service
|
|
27
|
+
- `src/adapters/sqlite-metric-store.ts` — SQLite time-series adapter
|
|
28
|
+
- `src/service.ts` — authenticated operation registry
|
|
29
|
+
- `src/client.ts` — operation-typed loopback client
|
|
30
|
+
- `src/daemon.ts` — Bun composition root and maintenance loop
|
|
31
|
+
|
|
32
|
+
SQLite runs in WAL mode with versioned migrations, JSON validation, bounded queries, chronological indexes, pruning, and checkpoints. The database follows `XDG_DATA_HOME`; private authentication state follows `XDG_STATE_HOME`; the daemon handle follows `XDG_RUNTIME_DIR`.
|
|
33
|
+
|
|
34
|
+
Operations currently include `metrics.record`, `metrics.query`, `metrics.prune`, and `service.checkpoint`.
|
|
35
|
+
|
|
36
|
+
Provider adapters currently include official OpenRouter key/usage/model telemetry and an explicitly experimental Codex subscription adapter. The Codex adapter follows the pinned open-source CLI `/wham/usage` payload and `x-codex-*` response-header contracts, accepts additional metered limits, and fails closed on malformed windows or impossible percentages. File credentials must be explicitly configured and private (`0600`); Jittor reads only the access token and account ID, never refreshes credentials, and never logs or persists OAuth secrets.
|
|
37
|
+
|
|
38
|
+
The native Pi extension preflights input and every provider turn, applies model/thinking decisions, records response headers and finalized usage through the daemon, and blocks requests when required telemetry is unsafe. It follows Pi's current authenticated model/provider and synchronizes Pi's available models before every decision, so unavailable catalog routes are never selected. Its responsive Alef-style footer groups repository and AI identity with cumulative usage, a color-coded context-window bar, and current-provider budget telemetry. Codex shows a bounded quota bar for its longest percentage window; OpenRouter remains honest about its unbounded raw spend and does not fabricate a denominator. Unknown and stale telemetry are marked explicitly. Run `/jittor` for detailed burn pressure, freshness, route state, and confirmed emergency-halt/override controls.
|
|
39
|
+
|
|
40
|
+
Blocking always has a daemon-independent escape hatch. `/jittor off` (or `/jittor-off`) immediately enters persisted monitor-only mode and never blocks provider requests. The informational footer is independently controlled with `/jittor footer on` and `/jittor footer off`, so showing status never enables enforcement. `/jittor on` only enables enforcement after telemetry polling and available-route synchronization succeed. Every fail-closed error includes these recovery commands plus the daemon restart command.
|
|
41
|
+
|
|
42
|
+
Run `/usage` for a colored Unicode token histogram with X/Y axes, provider/model series, input/output/cache totals, refresh, and `24h`, `7d`, `30d`, or `90d` ranges. Left/Right changes range and `r` refreshes. Usage is persisted by the daemon from finalized Pi assistant messages.
|
|
43
|
+
|
|
44
|
+
See [`docs/CALIBRATION.md`](docs/CALIBRATION.md) for thresholds and rollback, and [`docs/USAGE_PRIOR_ART.md`](docs/USAGE_PRIOR_ART.md) for the chart design research.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
bun test
|
|
48
|
+
bun x tsc --noEmit
|
|
49
|
+
bun run service:install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The systemd user unit binds only to `127.0.0.1`, discovers a 256-bit token without logging it, restarts on failure, and exposes authenticated health and operation endpoints.
|
|
53
|
+
|
|
54
|
+
See [`docs/PROVIDER_RESEARCH.md`](docs/PROVIDER_RESEARCH.md) for verified API boundaries and caveats.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Jittor routing calibration and rollback
|
|
2
|
+
|
|
3
|
+
Verified locally on 2026-07-19 without logging provider credentials or raw usage values.
|
|
4
|
+
|
|
5
|
+
## Live dogfood result
|
|
6
|
+
|
|
7
|
+
The supervised daemon successfully:
|
|
8
|
+
|
|
9
|
+
- loaded explicitly configured private Codex file credentials;
|
|
10
|
+
- polled the experimental ChatGPT Codex usage contract;
|
|
11
|
+
- polled the official OpenRouter key endpoint;
|
|
12
|
+
- persisted normalized observations through the daemon-owned SQLite store;
|
|
13
|
+
- reported both sources fresh and the router ready;
|
|
14
|
+
- calculated a deterministic policy decision for the active Pi route;
|
|
15
|
+
- exposed status through authenticated operations and the Pi footer/panel.
|
|
16
|
+
|
|
17
|
+
The live Codex response exposed one default window and one additional metered limit. The OpenRouter key exposed spend telemetry but no configured per-key limit, so OpenRouter contributes raw USD status and response cost accounting but does not yet create a resettable pressure window. Jittor does not invent an OpenRouter budget.
|
|
18
|
+
|
|
19
|
+
## Pressure model
|
|
20
|
+
|
|
21
|
+
For each resettable window:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
observed burn = delta(used fraction) / delta(time)
|
|
25
|
+
or average used fraction / elapsed window time
|
|
26
|
+
sustainable burn = remaining fraction / time until reset
|
|
27
|
+
pressure = observed burn / sustainable burn
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The highest-pressure fresh required window binds the decision. Provider percentage and observed Pi token velocity remain separate metrics.
|
|
31
|
+
|
|
32
|
+
## Initial thresholds
|
|
33
|
+
|
|
34
|
+
| Pressure | Decision |
|
|
35
|
+
|---:|---|
|
|
36
|
+
| `<= 1.00` | continue |
|
|
37
|
+
| `> 1.00` | throttle, up to 30 seconds |
|
|
38
|
+
| `> 1.25` | lower thinking |
|
|
39
|
+
| `> 1.50` | switch to a cheaper model on the same provider |
|
|
40
|
+
| `> 2.00` | switch provider |
|
|
41
|
+
| `> 3.00` | halt |
|
|
42
|
+
|
|
43
|
+
A consumed fraction of 99% is an unconditional hard stop. Missing, failed, older-than-120-second, impossible, or low-confidence required telemetry also halts before a provider request.
|
|
44
|
+
|
|
45
|
+
Recovery uses 10% hysteresis and a five-minute cooldown. Escalation is immediate; recovery waits, preventing route oscillation around a threshold.
|
|
46
|
+
|
|
47
|
+
## Dynamic route ladder
|
|
48
|
+
|
|
49
|
+
Jittor contains no model-ID allowlist. Before every decision, the Pi extension rebuilds the route ladder from `ModelRegistry.getAvailable()` and the active Pi model:
|
|
50
|
+
|
|
51
|
+
1. the current model and thinking level;
|
|
52
|
+
2. supported lower thinking levels on that model;
|
|
53
|
+
3. authenticated text models from the same current provider, ordered by advertised input-plus-output cost.
|
|
54
|
+
|
|
55
|
+
Routes from unrelated providers are intentionally excluded. Provider switching therefore halts unless a future explicit cross-provider policy is configured; Jittor does not silently start spending through another configured API. The current route and dynamic ladder are sent to the daemon before policy evaluation. A route that disappears is removed and the policy is evaluated once more instead of aborting with a stale catalog model.
|
|
56
|
+
|
|
57
|
+
## User controls
|
|
58
|
+
|
|
59
|
+
- Footer status: Codex longest-window percentage, raw OpenRouter spend, and current decision.
|
|
60
|
+
- `/jittor`: provider windows, observed/sustainable burn, pressure, current route, next downgrade, freshness, and controls.
|
|
61
|
+
- Pause/resume and route overrides require confirmation.
|
|
62
|
+
- Overrides expire after one hour unless cleared earlier.
|
|
63
|
+
|
|
64
|
+
Pause is a safety halt, not a bypass. It intentionally blocks subsequent provider requests.
|
|
65
|
+
|
|
66
|
+
## Scenario coverage
|
|
67
|
+
|
|
68
|
+
`test/calibration.test.ts` verifies:
|
|
69
|
+
|
|
70
|
+
- sustainable continuation;
|
|
71
|
+
- throttling;
|
|
72
|
+
- thinking downgrade;
|
|
73
|
+
- same-provider model handoff;
|
|
74
|
+
- provider handoff;
|
|
75
|
+
- stale-telemetry fail-closed behavior;
|
|
76
|
+
- pressure and utilization hard halts;
|
|
77
|
+
- cooldown/hysteresis route retention.
|
|
78
|
+
|
|
79
|
+
Extension tests verify pre-request blocking, model/thinking actuation, response-header ingestion, finalized usage recording, and footer formatting.
|
|
80
|
+
|
|
81
|
+
## Rollback
|
|
82
|
+
|
|
83
|
+
To remove enforcement without creating a fail-closed outage:
|
|
84
|
+
|
|
85
|
+
1. Remove or disable the local Jittor Pi package, then reload Pi:
|
|
86
|
+
```bash
|
|
87
|
+
pi remove /home/dpopsuev/Projects/jittor
|
|
88
|
+
```
|
|
89
|
+
2. Stop and disable the daemon only after the extension is unloaded:
|
|
90
|
+
```bash
|
|
91
|
+
systemctl --user disable --now jittor.service
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Stopping the daemon while the extension remains loaded intentionally blocks provider requests. To restore:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
cd /home/dpopsuev/Projects/jittor
|
|
98
|
+
bun src/cli.ts service install
|
|
99
|
+
pi install /home/dpopsuev/Projects/jittor
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Then reload Pi and run `/jittor` to confirm both readiness and provider freshness.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Jittor provider telemetry research
|
|
2
|
+
|
|
3
|
+
Verified 2026-07-18. Contracts marked **official** are documented provider APIs. Contracts marked **experimental** are implemented by an official open-source client but are not published as stable public APIs.
|
|
4
|
+
|
|
5
|
+
## Decision summary
|
|
6
|
+
|
|
7
|
+
| Source | Hot-path telemetry | Budget semantics | Stability |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| Codex subscription | `/backend-api/wham/usage`, Codex response headers, local Pi turn usage | Provider reports used percentage and reset time; absolute token allowance is not exposed | Experimental |
|
|
10
|
+
| OpenAI API key | Standard rate-limit headers and response usage | Exact token rate limits and API billing | Official, separate from subscription |
|
|
11
|
+
| OpenRouter | `/api/v1/key`, response `usage`, `/generation`, `/models` | Exact per-request tokens/cost; key limit when configured; otherwise Jittor budget required | Official |
|
|
12
|
+
| OpenRouter Analytics | `/api/v1/analytics/query` with management key | Historical aggregate spend/tokens | Official beta; not hot path |
|
|
13
|
+
|
|
14
|
+
## Codex subscription
|
|
15
|
+
|
|
16
|
+
### Officially documented behavior
|
|
17
|
+
|
|
18
|
+
OpenAI documents that:
|
|
19
|
+
|
|
20
|
+
- ChatGPT-authenticated Codex uses plan allowance rather than standard API billing.
|
|
21
|
+
- Usage depends on model, context, reasoning, tools, retrieval, and caching; prompt length alone is not a reliable estimate.
|
|
22
|
+
- Local messages and cloud chats can share a five-hour window and additional weekly limits may apply.
|
|
23
|
+
- Users can inspect remaining allowance in the Codex usage dashboard and with `/status` in Codex CLI.
|
|
24
|
+
- Switching to a smaller model is the recommended mitigation near limits.
|
|
25
|
+
- `~/.codex/auth.json` may contain plaintext OAuth credentials and must be treated as a password.
|
|
26
|
+
- The workspace Analytics API is for aggregated Business/Enterprise reporting and is not a personal real-time subscription-quota API.
|
|
27
|
+
|
|
28
|
+
There is no documented personal-plan API contract equivalent to the usage dashboard.
|
|
29
|
+
|
|
30
|
+
### Experimental contract used by official Codex CLI
|
|
31
|
+
|
|
32
|
+
The open-source `openai/codex` client calls:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
GET https://chatgpt.com/backend-api/wham/usage
|
|
36
|
+
Authorization: Bearer <ChatGPT OAuth access token>
|
|
37
|
+
ChatGPT-Account-Id: <account id>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For the alternate Codex API path style, its source constructs `/api/codex/usage`. The ChatGPT path above was live-probed successfully without logging credentials.
|
|
41
|
+
|
|
42
|
+
Observed response fields include:
|
|
43
|
+
|
|
44
|
+
- `plan_type`
|
|
45
|
+
- `rate_limit.primary_window` and `secondary_window`
|
|
46
|
+
- `used_percent`
|
|
47
|
+
- `limit_window_seconds`
|
|
48
|
+
- `reset_at`
|
|
49
|
+
- `credits.{has_credits, unlimited, balance}`
|
|
50
|
+
- `additional_rate_limits[]` with `metered_feature`, `limit_name`, and independent windows
|
|
51
|
+
- spend-control and rate-limit-reached metadata
|
|
52
|
+
|
|
53
|
+
The official CLI also parses rolling response headers:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
x-codex-primary-used-percent
|
|
57
|
+
x-codex-primary-window-minutes
|
|
58
|
+
x-codex-primary-reset-at
|
|
59
|
+
x-codex-secondary-used-percent
|
|
60
|
+
x-codex-secondary-window-minutes
|
|
61
|
+
x-codex-secondary-reset-at
|
|
62
|
+
x-codex-credits-has-credits
|
|
63
|
+
x-codex-credits-unlimited
|
|
64
|
+
x-codex-credits-balance
|
|
65
|
+
x-codex-<limit>-primary-used-percent
|
|
66
|
+
x-codex-<limit>-limit-name
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
It warns at 75%, 90%, and 95%, and offers a smaller-model switch around 90%. Jittor may use different configurable thresholds but should preserve hysteresis.
|
|
70
|
+
|
|
71
|
+
### What Codex does not expose
|
|
72
|
+
|
|
73
|
+
The subscription usage response does **not** expose an absolute token budget. Therefore Jittor must not label provider percentage as tokens. It will maintain two metrics:
|
|
74
|
+
|
|
75
|
+
1. **Provider budget pressure:** percentage consumed versus time remaining.
|
|
76
|
+
2. **Observed token velocity:** Pi assistant usage tokens per elapsed time, grouped by model and thinking level.
|
|
77
|
+
|
|
78
|
+
Over time Jittor can estimate tokens-per-budget-percent with an EWMA, but that estimate must retain confidence and sampling metadata because provider metering includes reasoning, tools, caching, and potentially non-Pi Codex usage.
|
|
79
|
+
|
|
80
|
+
### Credential and reliability rules
|
|
81
|
+
|
|
82
|
+
- Never persist or log OAuth/access/refresh tokens.
|
|
83
|
+
- File-based Codex auth is supported only when explicitly configured; keyring-backed auth needs a separate credential broker.
|
|
84
|
+
- Do not implement OAuth token refresh independently in v1. Codex owns credential refresh.
|
|
85
|
+
- Treat 401, missing fields, unknown schema, stale snapshots, and impossible reset times as telemetry failure.
|
|
86
|
+
- Poll no faster than once per minute unless response headers provide an update.
|
|
87
|
+
- The adapter is version-pinned and explicitly `experimental`; schema drift fails closed according to policy.
|
|
88
|
+
|
|
89
|
+
## OpenAI API-key mode is a separate source
|
|
90
|
+
|
|
91
|
+
Standard OpenAI API requests expose official token/request limit headers such as:
|
|
92
|
+
|
|
93
|
+
- `x-ratelimit-limit-tokens`
|
|
94
|
+
- `x-ratelimit-remaining-tokens`
|
|
95
|
+
- `x-ratelimit-reset-tokens`
|
|
96
|
+
- request and project-token equivalents
|
|
97
|
+
|
|
98
|
+
These are API organization/project limits, not ChatGPT subscription allowance. Jittor must never merge them into one budget window.
|
|
99
|
+
|
|
100
|
+
## OpenRouter
|
|
101
|
+
|
|
102
|
+
### Key and credit telemetry
|
|
103
|
+
|
|
104
|
+
Official endpoint:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
GET https://openrouter.ai/api/v1/key
|
|
108
|
+
Authorization: Bearer <OpenRouter key>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Useful fields:
|
|
112
|
+
|
|
113
|
+
- `limit`, `limit_reset`, `limit_remaining`
|
|
114
|
+
- `usage`, `usage_daily`, `usage_weekly`, `usage_monthly`
|
|
115
|
+
- BYOK usage variants
|
|
116
|
+
- `rate_limit`
|
|
117
|
+
- key capability flags including management/provisioning status
|
|
118
|
+
|
|
119
|
+
A live probe succeeded. The current key has no configured per-key limit, so `limit_remaining` is `null`; Jittor therefore needs user-defined daily/weekly/monthly budgets unless a key cap is configured.
|
|
120
|
+
|
|
121
|
+
Credit exhaustion produces HTTP 402. Rate limits produce 429 and may be OpenRouter-level or upstream-provider-level. Honor `Retry-After`; streaming errors may arrive as SSE error events after HTTP 200.
|
|
122
|
+
|
|
123
|
+
### Per-request accounting
|
|
124
|
+
|
|
125
|
+
Every OpenRouter response includes native-token accounting:
|
|
126
|
+
|
|
127
|
+
- prompt tokens
|
|
128
|
+
- completion tokens
|
|
129
|
+
- reasoning tokens
|
|
130
|
+
- cached read/write tokens when supported
|
|
131
|
+
- total `cost`
|
|
132
|
+
- upstream inference cost details
|
|
133
|
+
|
|
134
|
+
Streaming responses place usage in the last SSE event. A generation ID can later be queried through the `/generation` endpoint for audit/reconciliation.
|
|
135
|
+
|
|
136
|
+
This is Jittor's authoritative OpenRouter hot-path cost signal.
|
|
137
|
+
|
|
138
|
+
### Model catalog
|
|
139
|
+
|
|
140
|
+
Official endpoint:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
GET https://openrouter.ai/api/v1/models
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
A live probe returned 344 models. Model records include canonical ID, context length, pricing, conditional pricing overrides, supported parameters, reasoning support, top-provider details, expiration, and per-request limits.
|
|
147
|
+
|
|
148
|
+
Routing rules:
|
|
149
|
+
|
|
150
|
+
- Prefer canonical model IDs for deterministic budgets; `~...latest` aliases can change.
|
|
151
|
+
- Refresh catalog with TTL and retain the last known-good snapshot.
|
|
152
|
+
- Account for pricing overrides, cache pricing, reasoning, and request/tool surcharges.
|
|
153
|
+
- Filter candidates by required capabilities before sorting by cost.
|
|
154
|
+
- Provider-native fallbacks are useful for availability, but Jittor should record the actual served model/provider and cost.
|
|
155
|
+
|
|
156
|
+
### Analytics API
|
|
157
|
+
|
|
158
|
+
OpenRouter's beta Analytics API accepts management keys and can aggregate `total_usage`, token metrics, cache hit rate, reasoning tokens, model, API key, and generation dimensions. It is useful for calibration and audits, not pre-request routing. The API is beta: discover metadata dynamically, parse count metrics as number or string, and honor truncation metadata.
|
|
159
|
+
|
|
160
|
+
## Normalized Jittor model
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
interface BudgetWindow {
|
|
164
|
+
source: "codex-subscription" | "openai-api" | "openrouter" | "jittor";
|
|
165
|
+
scope: string;
|
|
166
|
+
usedFraction: number | null;
|
|
167
|
+
usedAmount: number | null;
|
|
168
|
+
limitAmount: number | null;
|
|
169
|
+
unit: "provider-percent" | "usd" | "tokens" | "requests";
|
|
170
|
+
windowSeconds: number | null;
|
|
171
|
+
resetsAt: number | null;
|
|
172
|
+
observedAt: number;
|
|
173
|
+
freshness: "fresh" | "stale" | "failed";
|
|
174
|
+
confidence: number;
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
For a resettable window:
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
observed burn = delta(used) / delta(time)
|
|
182
|
+
sustainable burn = remaining / max(reset_at - now, minimum_horizon)
|
|
183
|
+
pressure = observed burn / sustainable burn
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Token velocity and cost velocity are tracked separately per provider/model/thinking route. Decisions must include their input snapshot IDs and a human-readable explanation.
|
|
187
|
+
|
|
188
|
+
## Pi enforcement points
|
|
189
|
+
|
|
190
|
+
Verified Pi APIs support:
|
|
191
|
+
|
|
192
|
+
- `input`: preflight and return `{action: "handled"}` for a hard stop before the agent starts.
|
|
193
|
+
- `turn_start`: re-evaluate before each model/tool loop turn.
|
|
194
|
+
- `pi.setModel(model)`: switch provider/model after resolving it through `ctx.modelRegistry`.
|
|
195
|
+
- `pi.setThinkingLevel(level)`: lower reasoning effort, clamped to model support.
|
|
196
|
+
- `after_provider_response`: observe status and provider headers before streaming.
|
|
197
|
+
- `message_end`: record finalized assistant token/cost usage.
|
|
198
|
+
- `ctx.abort()`: stop an active agent operation if a mid-run hard threshold is crossed.
|
|
199
|
+
|
|
200
|
+
The Pi extension is an actuator and event collector. Policy, provider polling, history, and decisions live in the supervised Jittor daemon.
|
|
201
|
+
|
|
202
|
+
## Initial policy ladder
|
|
203
|
+
|
|
204
|
+
The policy engine is deterministic and configured by route tiers:
|
|
205
|
+
|
|
206
|
+
1. `continue`
|
|
207
|
+
2. `throttle(delayMs)`
|
|
208
|
+
3. `lower-thinking(level)`
|
|
209
|
+
4. `switch-model(provider, model, thinking)`
|
|
210
|
+
5. `switch-provider(provider, model, thinking)`
|
|
211
|
+
6. `halt(reason)`
|
|
212
|
+
|
|
213
|
+
Required safeguards: hysteresis, cooldown, maximum delay, minimum telemetry freshness, explicit capability checks, route availability/auth checks, and no automatic retry of non-idempotent requests.
|
|
214
|
+
|
|
215
|
+
## Sources
|
|
216
|
+
|
|
217
|
+
### OpenAI / Codex
|
|
218
|
+
|
|
219
|
+
- https://learn.chatgpt.com/docs/pricing#what-are-the-usage-limits-for-my-plan
|
|
220
|
+
- https://developers.openai.com/codex/auth
|
|
221
|
+
- https://developers.openai.com/codex/enterprise/analytics-api
|
|
222
|
+
- https://developers.openai.com/api/docs/guides/rate-limits
|
|
223
|
+
- https://github.com/openai/codex/blob/312caf176a8fd3a5897a3d1fd3ed0a283bd1b5ac/codex-rs/backend-client/src/client/rate_limit_resets.rs
|
|
224
|
+
- https://github.com/openai/codex/blob/312caf176a8fd3a5897a3d1fd3ed0a283bd1b5ac/codex-rs/codex-api/src/rate_limits.rs
|
|
225
|
+
- https://github.com/openai/codex/blob/312caf176a8fd3a5897a3d1fd3ed0a283bd1b5ac/codex-rs/tui/src/chatwidget/rate_limits.rs
|
|
226
|
+
|
|
227
|
+
### OpenRouter
|
|
228
|
+
|
|
229
|
+
- https://openrouter.ai/docs/api/reference/limits
|
|
230
|
+
- https://openrouter.ai/docs/cookbook/administration/usage-accounting
|
|
231
|
+
- https://openrouter.ai/docs/cookbook/administration/analytics-cost-control
|
|
232
|
+
- https://openrouter.ai/docs/guides/overview/models
|
|
233
|
+
|
|
234
|
+
### Pi
|
|
235
|
+
|
|
236
|
+
- Pi extension lifecycle and model APIs: local `docs/extensions.md`
|
|
237
|
+
- Pi model/provider configuration: local `docs/models.md`
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Token-usage TUI prior art
|
|
2
|
+
|
|
3
|
+
Research performed before implementing Jittor's `/usage` frontend.
|
|
4
|
+
|
|
5
|
+
## Local agent implementations
|
|
6
|
+
|
|
7
|
+
### Claude Code
|
|
8
|
+
|
|
9
|
+
`~/Repositories/claude/src/components/Stats.tsx` contains the strongest terminal chart precedent:
|
|
10
|
+
|
|
11
|
+
- `generateTokenChart()` renders daily model-token series with an eight-row `asciichart` plot.
|
|
12
|
+
- Width adapts to the terminal and is capped near 52 columns.
|
|
13
|
+
- The top three models receive distinct theme colors.
|
|
14
|
+
- The X axis places three or four date labels at even positions.
|
|
15
|
+
- The Y axis abbreviates values as `k` and `M`.
|
|
16
|
+
|
|
17
|
+
`~/Repositories/claude/src/utils/heatmap.ts` adds a GitHub-style activity view using percentile-derived `░▒▓█` intensity. `src/components/design-system/ProgressBar.tsx` uses eighth-cell Unicode blocks (`▏▎▍▌▋▊▉█`) for fractional precision.
|
|
18
|
+
|
|
19
|
+
Useful decisions: adaptive width, short axes, bounded series count, theme colors, Unicode partial cells. The Jittor requirement is a histogram rather than Claude's line chart, so only the layout and scaling ideas are reused.
|
|
20
|
+
|
|
21
|
+
### OpenCode
|
|
22
|
+
|
|
23
|
+
`~/Repositories/opencode/packages/stats/core/src/domain/home.ts` keeps usage projection in the domain layer. It defines explicit ranges (`1D`, `1W`, `2W`, `1M`, `2M`, `3M`, `YTD`, `ALL`), computes date windows, creates deterministic buckets, and formats range-appropriate labels.
|
|
24
|
+
|
|
25
|
+
Useful decision: range/window/bucket projection is separate from rendering and data access.
|
|
26
|
+
|
|
27
|
+
### Codex
|
|
28
|
+
|
|
29
|
+
`~/Repositories/codex` exposes turn-level `last` and `total` token usage plus account rate-limit snapshots. Its TUI focuses on compact totals and quota state; no reusable historical token histogram was found.
|
|
30
|
+
|
|
31
|
+
Useful decision: finalized turn usage is the durable accounting point. Jittor already records Pi assistant usage on `message_end`.
|
|
32
|
+
|
|
33
|
+
### Cline
|
|
34
|
+
|
|
35
|
+
Cline tracks accumulated input/output/cache/cost values and presents context/cost in its status area. Its local CLI sources did not contain a historical terminal histogram comparable to the requested chart.
|
|
36
|
+
|
|
37
|
+
Useful decision: preserve input, output, cache-read, and cache-write categories rather than collapsing accounting at ingestion.
|
|
38
|
+
|
|
39
|
+
## Pi extensions
|
|
40
|
+
|
|
41
|
+
Registry and package-source review covered:
|
|
42
|
+
|
|
43
|
+
- `@pi-vault/pi-usage@0.6.0`: polished framed/tabbed dashboard, Today/This Week/Last Week/All Time tables, live provider quotas, width-safe theme adapters. It has no historical vertical token histogram.
|
|
44
|
+
- `@sreetej510/pi-usage@0.1.20`: `/usage` provider quota reports, cache, retries, statusline, and 20-cell `█░` quota bars.
|
|
45
|
+
- `@narumitw/pi-codex-usage@0.20.0`: Codex 5-hour/weekly quota bars and compact statusline.
|
|
46
|
+
- `@alexanderfortin/pi-token-usage@0.3.0`: session-file aggregation and table/export overlay, but no chart.
|
|
47
|
+
|
|
48
|
+
Useful decisions: native `registerCommand`, `ctx.ui.custom`, width-bounded rendering, theme-derived colors, keyboard refresh/range navigation, and daemon/cache-backed data rather than synchronous file scans in render.
|
|
49
|
+
|
|
50
|
+
## OpenRouter visual reference
|
|
51
|
+
|
|
52
|
+
OpenRouter's authenticated web dashboard is not distributed as reusable terminal source. Its relevant visual grammar is a compact time-bucket histogram with colored model/provider series, readable axes, totals, and a legend. Jittor reproduces that grammar with Unicode blocks rather than copying web implementation details.
|
|
53
|
+
|
|
54
|
+
## Jittor design
|
|
55
|
+
|
|
56
|
+
Jittor combines the best applicable patterns:
|
|
57
|
+
|
|
58
|
+
1. Pure domain projection in `src/domain/usage.ts`.
|
|
59
|
+
2. Explicit `24h`, `7d`, `30d`, and `90d` windows.
|
|
60
|
+
3. Provider/model-preserving series and input/output/cache totals.
|
|
61
|
+
4. Vertically scaled, colored, stacked Unicode bars with fractional top blocks.
|
|
62
|
+
5. Width-safe X/Y axes and provider/model legend.
|
|
63
|
+
6. Native `/usage` panel with Left/Right range switching and refresh.
|
|
64
|
+
7. Data access only through authenticated daemon `metrics.query`; the extension never opens SQLite or reads provider credentials.
|