@danypops/jittor 0.16.3 → 0.17.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.
Files changed (94) hide show
  1. package/README.md +38 -13
  2. package/docs/COMPACTION_EFFECTIVENESS.md +34 -0
  3. package/docs/CONTEXT_SNAPSHOTS.md +53 -0
  4. package/docs/MODEL_CATALOG.md +43 -0
  5. package/docs/OTLP_EXPORT.md +63 -0
  6. package/docs/PROVIDER_RESEARCH.md +1 -1
  7. package/docs/TOKEN_MEASUREMENT.md +53 -0
  8. package/docs/USAGE_BACKFILL.md +35 -0
  9. package/package.json +4 -3
  10. package/src/{providers/anthropic-contracts.ts → anthropic/rate-limits.ts} +1 -1
  11. package/src/{adapters/artificial-analysis-direct-source.ts → artificial-analysis/benchmark-source.ts} +3 -3
  12. package/src/cli-commands/backfill.ts +51 -0
  13. package/src/cli-commands/benchmarks.ts +4 -4
  14. package/src/cli-commands/catalog.ts +123 -0
  15. package/src/cli-commands/compaction.ts +1 -1
  16. package/src/cli-commands/context.ts +77 -4
  17. package/src/cli-commands/export.ts +30 -0
  18. package/src/cli-commands/metrics.ts +8 -2
  19. package/src/cli-commands/op.ts +1 -1
  20. package/src/cli-commands/route-args.ts +2 -2
  21. package/src/cli-commands/router.ts +2 -2
  22. package/src/cli-commands/support.ts +2 -2
  23. package/src/cli.ts +54 -21
  24. package/src/{providers/codex-contracts.ts → codex/contracts.ts} +1 -1
  25. package/src/codex/source.ts +53 -0
  26. package/src/{providers/codex.ts → codex/telemetry.ts} +2 -2
  27. package/src/constants.ts +18 -0
  28. package/src/daemon.ts +53 -23
  29. package/src/{providers/google-vertex-budget-contracts.ts → google-vertex/budget-contracts.ts} +3 -3
  30. package/src/{providers/google-vertex-budget.ts → google-vertex/budget-telemetry.ts} +6 -6
  31. package/src/{providers/google-vertex-contracts.ts → google-vertex/failures.ts} +1 -1
  32. package/src/google-vertex/source.ts +35 -0
  33. package/src/index.ts +135 -55
  34. package/src/{adapters/lmarena-hf-source.ts → lmarena/benchmark-source.ts} +3 -3
  35. package/src/observability/budget.ts +14 -0
  36. package/src/observability/context-delta.ts +309 -0
  37. package/src/{domain → observability}/context-hub.ts +19 -2
  38. package/src/observability/context-snapshot-history.ts +281 -0
  39. package/src/{domain → observability}/context-telemetry.ts +232 -4
  40. package/src/observability/model-identity.ts +42 -0
  41. package/src/{domain → observability}/model-observation.ts +26 -11
  42. package/src/{ports/metric-store.ts → observability/store.ts} +2 -2
  43. package/src/{ports → observability}/telemetry-source.ts +2 -2
  44. package/src/observability/token-measurement.ts +194 -0
  45. package/src/observability/usage-import.ts +122 -0
  46. package/src/openai/token-counter.ts +63 -0
  47. package/src/{adapters/openrouter-benchmark-source.ts → openrouter/benchmark-source.ts} +3 -3
  48. package/src/{providers/openrouter-contracts.ts → openrouter/contracts.ts} +1 -1
  49. package/src/{adapters/openrouter-design-arena-source.ts → openrouter/design-arena-source.ts} +4 -4
  50. package/src/openrouter/source.ts +20 -0
  51. package/src/{providers/openrouter.ts → openrouter/telemetry.ts} +2 -2
  52. package/src/{domain → optimization/model-selection}/benchmark.ts +9 -27
  53. package/src/optimization/model-selection/catalog-store.ts +97 -0
  54. package/src/optimization/model-selection/catalog.ts +478 -0
  55. package/src/{ports/benchmark-controller.ts → optimization/model-selection/controller.ts} +1 -1
  56. package/src/{adapters/metric-benchmark-store.ts → optimization/model-selection/observation-store.ts} +5 -5
  57. package/src/{domain/model-ranking-service.ts → optimization/model-selection/ranker.ts} +6 -12
  58. package/src/{domain/model-ranking.ts → optimization/model-selection/ranking.ts} +8 -2
  59. package/src/{ports/benchmark-source.ts → optimization/model-selection/source.ts} +1 -1
  60. package/src/{ports/benchmark-store.ts → optimization/model-selection/store.ts} +1 -1
  61. package/src/{domain/codex-recovery.ts → optimization/recovery/codex.ts} +1 -1
  62. package/src/{ports/router-controller.ts → optimization/routing/controller.ts} +1 -1
  63. package/src/{policy.ts → optimization/routing/policy.ts} +4 -14
  64. package/src/{router.ts → optimization/routing/router.ts} +4 -10
  65. package/src/otlp/exporter.ts +354 -0
  66. package/src/pi/session-usage-source.ts +203 -0
  67. package/src/{session-identity-service.ts → sessions/identity.ts} +2 -2
  68. package/src/{operations/session-scope.ts → sessions/router-authorization.ts} +1 -1
  69. package/src/{db.ts → sqlite/database.ts} +14 -1
  70. package/src/{adapters/sqlite-metric-store.ts → sqlite/metric-store.ts} +4 -4
  71. package/src/{adapters/sqlite-session-identity-store.ts → sqlite/session-store.ts} +1 -1
  72. package/src/sqlite/usage-import-store.ts +133 -0
  73. package/src/telemetry-export/exporter.ts +84 -0
  74. package/src/{operations → vehicle}/benchmark-operations.ts +3 -3
  75. package/src/vehicle/catalog-operations.ts +10 -0
  76. package/src/{client.ts → vehicle/client.ts} +1 -1
  77. package/src/{operations → vehicle}/context-operations.ts +13 -5
  78. package/src/vehicle/export-operations.ts +12 -0
  79. package/src/{operations/metrics-operations.ts → vehicle/metric-operations.ts} +4 -4
  80. package/src/{operations → vehicle}/model-ranking-operations.ts +3 -3
  81. package/src/{vehicle-registration.ts → vehicle/registration.ts} +14 -4
  82. package/src/{operations/router-operations.ts → vehicle/routing-operations.ts} +4 -4
  83. package/src/{service.ts → vehicle/service.ts} +108 -26
  84. package/src/{operations/session-identity-operations.ts → vehicle/session-operations.ts} +3 -3
  85. package/src/vehicle/usage-import-operations.ts +10 -0
  86. package/src/providers/telemetry-sources.ts +0 -108
  87. /package/src/{providers/google-adc-auth.ts → google-vertex/auth.ts} +0 -0
  88. /package/src/{domain → observability}/metric.ts +0 -0
  89. /package/src/{domain → observability}/task-cost.ts +0 -0
  90. /package/src/{domain → observability}/task-focus.ts +0 -0
  91. /package/src/{domain → observability}/usage.ts +0 -0
  92. /package/src/{config.ts → optimization/routing/config.ts} +0 -0
  93. /package/src/{ports/session-identity-store.ts → sessions/store.ts} +0 -0
  94. /package/src/{operations/types.ts → vehicle/operation-types.ts} +0 -0
package/README.md CHANGED
@@ -1,20 +1,28 @@
1
1
  # @danypops/jittor
2
2
 
3
- Supervised Bun daemon, router policy, provider telemetry adapters, and CLI for Jittor. See the [repo root README](../../README.md) for the two-package overview and [`@danypops/pi-jittor`](../pi-jittor) for the Pi extension that talks to this daemon.
3
+ Token and context observability, optimization policies, provider integrations, supervised Bun daemon, and CLI for Jittor. See the [repo root README](../../README.md) for the two-package overview and [`@danypops/pi-jittor`](../pi-jittor) for the Pi extension that talks to this daemon.
4
4
 
5
5
  ## Architecture
6
6
 
7
- - `src/domain/metric.ts` normalized timestamped metric observations
8
- - `src/ports/metric-store.ts` — storage boundary used by the application service
9
- - `src/adapters/sqlite-metric-store.ts` — SQLite time-series adapter
10
- - `src/service.ts` — authenticated operation registry
11
- - `src/client.ts` — operation-typed loopback client
12
- - `src/daemon.ts` — Bun composition root and maintenance loop
13
- - `src/index.ts` — the package's public surface: everything `@danypops/pi-jittor` (or any other consumer) imports
7
+ `src/` is organized by Jittor's domain and concrete integrations:
14
8
 
15
- 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`.
9
+ - `observability/` token, cost, context, task-focus, model-run, and provider-budget observations; its store and source boundaries live beside that model
10
+ - `optimization/routing/` — budget pressure, route decisions, overrides, and enforcement state
11
+ - `optimization/model-selection/` — benchmark evidence, model ranking, and their source/store boundaries
12
+ - `optimization/recovery/` — bounded recovery policies
13
+ - `sessions/` — session identity and mutation authorization
14
+ - `codex/`, `openrouter/`, `anthropic/`, `google-vertex/` — provider-specific translation and telemetry
15
+ - `lmarena/`, `artificial-analysis/` — benchmark-source translation
16
+ - `sqlite/` — observation and session persistence
17
+ - `vehicle/` — authenticated operation transport
18
+ - `daemon.ts` — composition root and maintenance loop
19
+ - `index.ts` — stable public package surface
16
20
 
17
- Operations currently include bounded metric recording/query/pruning, benchmark refresh/status/query, context assessment, routing control, telemetry polling, and service checkpointing. Every operation is exposed through the authenticated typed client; benchmark operations also have CLI parity.
21
+ Dependencies point toward `observability/` and `optimization/`; provider, SQLite, Vehicle, CLI, and Pi models are translated at their boundaries. SQLite runs in WAL mode with versioned migrations, bounded queries, pruning, and checkpoints.
22
+
23
+ Operations currently include bounded metric recording/query/pruning, benchmark and provenance-bearing model-catalog refresh/status/query, context assessment and content-free snapshot deltas, routing control, telemetry polling, and service checkpointing. Every operation is exposed through the authenticated typed client; benchmark operations also have CLI parity.
24
+
25
+ Token counts carry explicit scope and provenance (`provider-reported`, `provider-count-api`, `tokenizer-exact-text`, or `structural-estimate`). Provider aggregates remain authoritative, exact local tokenization is labeled exact for text only, and envelope/media/provider residuals remain explicit instead of being assigned to individual context items. See [`docs/TOKEN_MEASUREMENT.md`](docs/TOKEN_MEASUREMENT.md) for the contract, OpenAI-family adapter, privacy boundary, module benchmark, and E2E test layers.
18
26
 
19
27
  ## Provider telemetry
20
28
 
@@ -25,10 +33,16 @@ Operations currently include bounded metric recording/query/pruning, benchmark r
25
33
 
26
34
  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. Anthropic has no personal-account polling endpoint (its Admin/Rate Limits API is documented as unavailable for individual accounts), so Jittor instead reads the official `anthropic-ratelimit-*` response headers Pi observes on every Messages API call and fails closed on schema drift the same way. Google Vertex AI has neither a personal polling endpoint nor a documented remaining-quota response header, so Jittor never fabricates a Vertex budget bar; it instead classifies Vertex's `google.rpc.Status` failure shape (quota, authentication, invalid-request, overload, transport, unknown) from Pi's bounded, content-free `errorMessage` and records only a bounded failure-count metric.
27
35
 
36
+ If Codex usage becomes `telemetry unavailable`, check `jittor telemetry poll --json`: the active daemon must list `codex-subscription`. A manually started or older npm-installed daemon can own the shared runtime handle while a correctly configured systemd service is inactive; stop that process and restart the configured service. The human status view reports this mismatch without displaying credential paths or values. Jittor never carries an expired percentage across its reset or assumes the reset replenished the subscription—until a fresh provider observation arrives, it reports `reset pending` instead.
37
+
28
38
  The third-party `anthropic-vertex` provider (Anthropic Claude models served through Google Vertex, e.g. via `@twogiants/pi-anthropic-vertex`) is tracked separately from both of the above: it reuses Pi's own Anthropic Messages stream implementation with Anthropic's official `@anthropic-ai/vertex-sdk` client, so its wire shape is Anthropic's, but its quota accounting is Google's. Jittor applies Google Vertex's failure classification to it (real-world reports confirm its 429s still carry GCP's own quota-exceeded shape even through Anthropic's own SDK) and, best-effort, also checks for genuine Anthropic rate-limit response headers on it, since it is unverified whether this specific passthrough ever forwards them. Either way, every metric is tagged `anthropic-vertex`, never blended into direct Anthropic's `anthropic` source or Pi's unrelated native `google-vertex` provider, since each represents a different account/quota pool.
29
39
 
30
40
  Blocking always has a daemon-independent escape hatch: `/jittor off` (in the extension) immediately enters persisted monitor-only mode and never blocks provider requests, regardless of daemon state.
31
41
 
42
+ ## Provenance-bearing model catalog
43
+
44
+ Set `JITTOR_MODELS_DEV_CATALOG=1` to opt into bounded models.dev ingestion. `jittor catalog status|refresh|list [--json]` exposes last-good snapshot state and provider-serving limits, capabilities, modalities, lifecycle, and pricing with per-field authority. Live provider usage/cost remains authoritative; explicit local query overrides win over catalog metadata. See [`docs/MODEL_CATALOG.md`](docs/MODEL_CATALOG.md).
45
+
32
46
  ## Benchmark evidence
33
47
 
34
48
  Jittor can ingest bounded OpenRouter model metadata, p50 latency/throughput ordering, and Design Arena Elo rankings as provenance-bearing evidence without treating OpenRouter as model-scope authority. Enable online ingestion explicitly with `JITTOR_OPENROUTER_BENCHMARKS=1`; it is off by default. OpenRouter model metadata and operational ordering are public; Design Arena ingestion additionally uses `OPENROUTER_API_KEY` from the supervised service environment without retaining it. Snapshots preserve the upstream publisher, normalized model identities, immutable retrieval revisions, source URLs, confidence, license terms, and explicit freshness deadlines. A malformed or oversized refresh leaves the last complete snapshot visible and records only a payload-safe failure state.
@@ -47,15 +61,23 @@ jittor benchmarks list --source openrouter-models [--model provider/model] [--di
47
61
 
48
62
  Only complete snapshots are queryable. Query output reports both completeness and freshness. See [`docs/BENCHMARK_SOURCES.md`](docs/BENCHMARK_SOURCES.md) for source authority, provenance, conflict, and redistribution rules.
49
63
 
50
- The ranking operation (`domain/model-ranking.ts`) accepts an explicit bounded candidate set and never adds identities found only in evidence. It scores quality (a domain-specific dimension, e.g. `quality-coding`, and a type-specific dimension, e.g. `quality-type-planning`, each optional and additive over the universal `quality-general` fallback), cost, latency, context, and local reliability with bounded user weights, budget-pressure adjustment, component confidence, freshness, provenance, and deterministic tie-breaking. Missing evidence remains unknown and lowers confidence.
64
+ The ranking operation (`optimization/model-selection/ranking.ts`) accepts an explicit bounded candidate set and never adds identities found only in evidence. It scores quality (a domain-specific dimension, e.g. `quality-coding`, and a type-specific dimension, e.g. `quality-type-planning`, each optional and additive over the universal `quality-general` fallback), cost, latency, context, and local reliability with bounded user weights, budget-pressure adjustment, component confidence, freshness, provenance, and deterministic tie-breaking. Missing evidence remains unknown and lowers confidence.
51
65
 
52
66
  Jittor separately records content-free local model observations from Pi's public lifecycle: TTFT, wall latency, output throughput, token/cache/cost efficiency, provider retries, tool-loop counts, failures, and two independent classifications derived only from bounded tool names: domain (subject matter, e.g. `coding`) and type (activity, e.g. `research`, `planning`). Prompts, responses, tool arguments/results, credentials, and project paths are never retained. Robust aggregates report sample size, median, p90, median absolute deviation, recency, and confidence without merging local observations into external benchmark facts.
53
67
 
68
+ ## Content-free OTLP export
69
+
70
+ Configure `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` (or the standard generic endpoint) to opt into bounded asynchronous OTLP/HTTP JSON export. `jittor export status|flush [--json]` reports credential-safe health. The mapper pins evolving GenAI conventions and has no content-capture mode. See [`docs/OTLP_EXPORT.md`](docs/OTLP_EXPORT.md).
71
+
72
+ ## Historical Pi usage backfill
73
+
74
+ `jittor backfill status|dry-run|run|cancel [--json]` imports only persisted content-free Pi usage facts into the same charts as live observations. Opaque identities and atomic SQLite claims make reimport, concurrency, moved sessions, and restart safe; scans and progress are bounded and cancelable. See [`docs/USAGE_BACKFILL.md`](docs/USAGE_BACKFILL.md).
75
+
54
76
  ## Context pressure
55
77
 
56
- Papyrus emits content-free prompt-injection observations through Pi's shared extension event bus. Jittor validates and records their exact Rule/Task character sizes, prompt share, fingerprint repetition, and explicitly estimated token size. Jittor also records completed, aborted, and unmatched Pi compactions with duration, reason, retry state, pre-compaction context usage, and bounded turns/injection/provider/cache usage since the previous compaction.
78
+ Papyrus emits content-free prompt-injection observations through Pi's shared extension event bus. Jittor validates and records their exact Rule/Task character sizes, prompt share, fingerprint repetition, and explicitly estimated token size. Jittor also records completed, aborted, and unmatched Pi compactions with duration, reason, retry state, provenance-bearing pre/post context, summary size, reduction, regrowth milestones, mechanism identity, and bounded turns/injection/provider/cache/tool/outcome counters since the previous compaction. See [`docs/COMPACTION_EFFECTIVENESS.md`](docs/COMPACTION_EFFECTIVENESS.md).
57
79
 
58
- `jittor context [--since <epoch-ms>] [--until <epoch-ms>] [--json]` reports bounded average/p95/max injection, Rule/Task mix, unchanged rate, compaction frequency/duration/reasons, and between-compaction provider/cache facts. Repeated prompt content is not labeled billed waste: provider-reported input/cache usage and an injection-disabled control are required before making cost or compaction-causality claims.
80
+ `jittor context [--since <epoch-ms>] [--until <epoch-ms>] [--json]` reports bounded average/p95/max injection, Rule/Task mix, unchanged rate, compaction frequency/duration/reasons, and between-compaction provider/cache facts. `jittor context delta --session-id <opaque-id> [--json]` exposes the latest content-free structural delta; Pi's `/context` view resolves that opaque identity itself. Repeated prompt content is not labeled billed waste: provider-reported input/cache usage and an injection-disabled control are required before making cost or compaction-causality claims. See [`docs/CONTEXT_SNAPSHOTS.md`](docs/CONTEXT_SNAPSHOTS.md) for privacy, lifecycle, truncation, persistence, and stable-prefix semantics.
59
81
 
60
82
  ## CLI operations
61
83
 
@@ -71,6 +93,9 @@ jittor metrics cost-by-task --since <ms> --until <ms> [--json]
71
93
  jittor service checkpoint [--json]
72
94
  jittor telemetry poll [--json]
73
95
  jittor compaction estimate [--json]
96
+ jittor catalog status|refresh|list [--provider <id>] [--model <id>] [--limit <n>] [--json]
97
+ jittor backfill status|dry-run|run|cancel [--json]
98
+ jittor export status|flush [--json]
74
99
  jittor session register --session-id <id> [--json]
75
100
  jittor session release --session-id <id> [--session-secret <secret>] [--json]
76
101
  jittor router status|decide|pause|resume|clear-override [--session-id <id>] [--session-secret <secret>] [--json]
@@ -0,0 +1,34 @@
1
+ # Compaction effectiveness and regrowth
2
+
3
+ Jittor treats compaction as an observed intervention, not as proof that information was lost or that
4
+ provider caching improved. Pi's public compaction lifecycle supplies the mechanism, reason,
5
+ completion/abort/retry state, duration, and pre-compaction token estimate. The first subsequent
6
+ content-free provider snapshot supplies the post-compaction structural token estimate.
7
+
8
+ Every pre/post/summary/regrowth token value carries explicit provenance. Current Pi-native summary
9
+ and provider-payload structure values are `structural-estimate`; provider-reported request totals
10
+ remain separate and authoritative for billing. A completed compaction without a subsequent snapshot
11
+ remains a duration observation and does not fabricate effectiveness.
12
+
13
+ `compaction-effectiveness` records the reduction ratio, pre/post token sizes, mechanism
14
+ (`pi-native`, `provider-side`, or `extension`), provider/model, and summary size. Regrowth emits each
15
+ 50%, 80%, and 100% milestone once with turns and elapsed time. Interval attributes also retain only
16
+ bounded counts for tool classes, retries/failures, cache reads/writes, and explicit accepted/rejected
17
+ outcomes. Tool arguments, results, commands, paths, prompts, responses, and summaries are never
18
+ persisted.
19
+
20
+ `jittor context` and `/jittor context` aggregate these observations by period and mechanism. Missing
21
+ samples remain unknown. Repeated tool-class activity is a content-free proxy only; it is never
22
+ labeled waste or information loss without explicit outcome/control evidence.
23
+
24
+ ## External mechanisms
25
+
26
+ External compactors such as `pi-mega-compact` should emit the same capability inputs through an
27
+ extension boundary: call `begin()` with `mechanism: "extension"`, record completion with summary
28
+ measurement provenance, and pass the first final provider-request snapshot to
29
+ `observeContextSnapshot()`. Provider-side compaction uses `mechanism: "provider-side"`. Core Jittor
30
+ has no dependency on either implementation and does not invoke or control a compactor.
31
+
32
+ Capture and daemon-write failures are isolated from provider delivery. An extension/daemon restart
33
+ may leave a completed duration without a correlated post snapshot; Jittor reports the missing
34
+ sample rather than correlating across an uncertain lifecycle boundary.
@@ -0,0 +1,53 @@
1
+ # Content-free context snapshots and deltas
2
+
3
+ Jittor observes Pi's `before_provider_request` boundary to compare the structure of consecutive
4
+ provider requests. This is observability only: capture never modifies or delays the request, and a
5
+ capture/daemon failure cannot block provider delivery.
6
+
7
+ ## Persisted contract
8
+
9
+ A snapshot contains only:
10
+
11
+ - bounded source categories (`base-prompt`, `tool-definitions`, `rules`, `skills`,
12
+ `project-context`, `conversation-message`, `thinking`, `tool-call`, `tool-result`);
13
+ - non-negative token sizes, request positions, timestamps, and lifecycle state;
14
+ - opaque logical IDs and content fingerprints produced by keyed HMAC;
15
+ - provider/model identity and an honest truncation flag.
16
+
17
+ Snapshots are capped at 512 segments. Values are canonicalized only in memory with depth,
18
+ collection, node, and string bounds. Jittor never persists prompts, responses, tokenizer input,
19
+ tool arguments/results, images, shell commands, paths, credentials, or reversible/plain hashes.
20
+ Images retain structural identity with zero locally attributed tokens because image token cost is
21
+ provider/model-specific.
22
+
23
+ Pi's final payload supplies active request order. Its real `SessionManager` tree additionally marks
24
+ entries omitted by compaction as `compacted` and abandoned branches as `inactive`; historical
25
+ entries have no request position and therefore cannot inflate stable-prefix evidence.
26
+
27
+ ## Delta semantics
28
+
29
+ For each logical segment, a delta reports `added`, `retained`, `changed`, `evicted`, `compacted`, or
30
+ `inactive`, plus source-level token growth. Equal repeated structures remain distinct logical
31
+ segments even when their content fingerprints are equal. A provider, model, or opaque session
32
+ change resets comparison rather than correlating incompatible request shapes.
33
+
34
+ `stablePrefixTokens` is the sum of unchanged leading active request segments, and
35
+ `firstChangedSegment` identifies the first structural divergence. This is correlation evidence for
36
+ request churn. It is **not proof of provider cache behavior, cache eligibility, cache hits, billing,
37
+ or causality**. Provider-reported usage remains authoritative at aggregate request scope.
38
+
39
+ ## Operations
40
+
41
+ ```text
42
+ jittor context delta --session-id <opaque-id> [--json]
43
+ jittor context snapshot --snapshot <content-free-json> [--json]
44
+ ```
45
+
46
+ `context.snapshot` is a single-execution local write and is never transport-retried.
47
+ `context.delta` is a bounded read and may reconnect/retry once. Pi's `/context` view derives the
48
+ opaque session ID internally and displays stable-prefix size, first change, lifecycle counts,
49
+ source growth, truncation, and the cache-evidence caveat alongside its searchable context tree.
50
+
51
+ Snapshots and their deltas are committed atomically through `MetricStore.recordBatch()`. The latest
52
+ snapshot reloads from SQLite after daemon restart. A late stale capture remains queryable as
53
+ history but cannot replace a newer snapshot as the session's latest state.
@@ -0,0 +1,43 @@
1
+ # Provenance-bearing model catalog
2
+
3
+ Jittor can ingest the open-source [models.dev](https://models.dev) provider catalog from
4
+ `https://models.dev/api.json`. Network access is off by default. Set
5
+ `JITTOR_MODELS_DEV_CATALOG=1`, then run `jittor catalog refresh`; an optional
6
+ `JITTOR_MODELS_DEV_CATALOG_URL` is intended for a trusted mirror or loopback integration test.
7
+
8
+ The direct translator preserves provider serving identity, aliases, context/input/output limits,
9
+ modalities, capabilities, lifecycle status, input/output/reasoning/cache prices, over-200k prices,
10
+ and context price tiers. A bounded response is validated as one complete snapshot. Its SHA-256
11
+ content revision, source URL, retrieval time, freshness deadline, and upstream MIT license are
12
+ stored. The complete marker is published last, so malformed, partial, oversized, timed-out, or
13
+ offline refreshes cannot replace the last complete snapshot.
14
+
15
+ Catalog prices are USD per million tokens and remain metadata estimates. Provider-reported usage
16
+ and cost are authoritative for actual billing. Provider serving entries override base-model
17
+ metadata in models.dev itself. Explicit query-time local overrides then win over catalog fields;
18
+ every resolved field reports `models-dev-provider` or `user-override` authority. Aliases are matched
19
+ only inside the selected provider, so a shared model name never merges provider quota pools or
20
+ serving variants.
21
+
22
+ Commands:
23
+
24
+ ```text
25
+ jittor catalog status [--json]
26
+ jittor catalog refresh [--force] [--json]
27
+ jittor catalog list [--provider <id>] [--model <id>] [--limit <n>] [--json]
28
+ ```
29
+
30
+ Local limit/price overrides are available on `catalog list` through `--context-tokens`,
31
+ `--input-tokens`, `--output-tokens`, `--input-price`, and `--output-price`.
32
+
33
+ ## Source and redistribution
34
+
35
+ models.dev is Copyright (c) 2025 models.dev and distributed under the MIT License. Jittor stores only
36
+ translated metadata plus its source/provenance; redistributors must retain the upstream copyright
37
+ and permission notice when the license requires it. See the upstream repository for the complete
38
+ license and contribution history.
39
+
40
+ OpenRouter's model endpoint remains useful operational marketplace metadata for OpenRouter-specific
41
+ availability and pricing. It is not used as a base-model authority and cannot replace models.dev's
42
+ cross-provider serving catalog. Conversely, models.dev metadata does not override live OpenRouter
43
+ account/response telemetry. The two sources retain distinct provenance and authority.
@@ -0,0 +1,63 @@
1
+ # Content-free OTLP export
2
+
3
+ Jittor can asynchronously export observations to any OTLP/HTTP JSON metrics collector. It is off by
4
+ default and has no Phoenix, Langfuse, or other backend dependency.
5
+
6
+ Configure one standard OpenTelemetry endpoint variable:
7
+
8
+ ```text
9
+ OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://collector.example/v1/metrics
10
+ # or OTEL_EXPORTER_OTLP_ENDPOINT=https://collector.example/
11
+ OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer%20...
12
+ ```
13
+
14
+ `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` is exact. The generic endpoint receives `v1/metrics`.
15
+ Endpoints and headers exist only at the concrete transport boundary; status, errors, local metrics,
16
+ and logs never contain them. Plain HTTP is accepted only for loopback collectors.
17
+
18
+ ```text
19
+ jittor export status [--json]
20
+ jittor export flush [--json]
21
+ ```
22
+
23
+ Status reports enabled/disabled state, queue depth, exported/dropped counts, failed batches, last
24
+ success/failure timestamps, and the pinned convention revision. It never reports endpoint or
25
+ credential data.
26
+
27
+ ## Semantic mapping
28
+
29
+ The mapping is pinned to OpenTelemetry GenAI semantic-conventions commit
30
+ `46d43c8949afb53765a202e89f4534eeb75ca3fa` with core semantic conventions `v1.44.0`. GenAI
31
+ conventions are still Development and currently have no schema URL, so Jittor reports this complete
32
+ pin as `genai@46d43...+core-v1.44.0` and isolates names in one mapper.
33
+
34
+ - input/output tokens → `gen_ai.client.token.usage` with `gen_ai.token.type`
35
+ - latency → `gen_ai.client.operation.duration`
36
+ - TTFT → `gen_ai.client.operation.time_to_first_chunk`
37
+ - provider/model/operation/thinking → current `gen_ai.*` attributes
38
+ - readily available opaque session correlation → `gen_ai.conversation.id`
39
+ - cache/reasoning tokens and output throughput → `jittor.gen_ai.*`
40
+ - compaction, context, budget, and routing facts → bounded `jittor.*` metrics/attributes
41
+ - failures → low-cardinality `error.type`; raw provider errors are never exported
42
+
43
+ The standard token metric allows only input/output token types, so cache and reasoning observations
44
+ stay distinct under Jittor's namespace rather than inventing non-standard values for
45
+ `gen_ai.token.type`. Provider-reported values retain their local authority; export does not
46
+ re-tokenize content.
47
+
48
+ ## Privacy and failure isolation
49
+
50
+ The mapper is an allowlist. It has no configuration switch for content and cannot emit
51
+ `gen_ai.input.messages`, `gen_ai.output.messages`, `gen_ai.system_instructions`, prompt variables,
52
+ tool definitions, prompts, responses, tool arguments/results, shell commands, file paths,
53
+ credentials, environment values, or raw provider errors.
54
+
55
+ Local SQLite persistence completes before an observation is enqueued. Export is detached from Pi's
56
+ provider lifecycle. The in-memory queue, batch, interval, timeout, and one-retry policy are bounded;
57
+ backpressure drops and counts the oldest item. Collector failure only increments credential-safe
58
+ health counters and cannot change local persistence or routing. Shutdown performs a bounded final
59
+ flush; a restart intentionally starts with an empty queue while SQLite remains authoritative.
60
+
61
+ Generic OpenTelemetry Collector, Phoenix OTLP ingestion, and Langfuse OTLP ingestion can consume the
62
+ same endpoint shape when configured by their own documentation. Jittor neither detects nor couples
63
+ to those products.
@@ -194,7 +194,7 @@ Two API surfaces matter here, and they answer different questions:
194
194
  - **`billingAccounts.budgets.get`/`.list`** (REST, project-scoped per above) returns only the budget's *policy* — its cap (`amount`), alert `thresholdRules`, and filters. It does **not** return current spend. Resolving which billing account owns a given project first requires `projects.getBillingInfo` (`cloudbilling.googleapis.com`, also just `resourcemanager.projects.get`/Project Viewer).
195
195
  - **Cloud Billing's own programmatic budget notifications**, delivered over Pub/Sub, are the real signal: Google's docs state notifications are "sent to the Pub/Sub topic **multiple times per day** with the current status of your budget" (not only on threshold crossings), each message carrying real dollar figures — `costAmount`, `budgetAmount`, `costIntervalStart`, `currencyCode`, and (only once actually exceeded) `alertThresholdExceeded`/`forecastThresholdExceeded` (schema verified against `docs.cloud.google.com/billing/docs/how-to/budgets-programmatic-notifications#notification-format` and the worked fixture in `.../billing/docs/how-to/listen-to-notifications`, fetched 2026-07-23). Since Jittor is a local, loopback-only daemon with no public inbound endpoint, it **pulls** (never pushes) this topic via a Pub/Sub pull subscription (`pubsub.googleapis.com/v1/{subscription}:pull`), authenticated the same ADC way.
196
196
 
197
- This is still not a fully real-time signal, and the docs are explicit about both caveats Jittor must preserve rather than paper over: (1) "Budgets use estimated Cloud Billing data which is subject to change until your invoice is finalized", and (2) "Pub/Sub only provides at-least-once delivery. You might receive a message multiple times, and messages might arrive out of order." Jittor's `GoogleVertexBudgetTelemetryAdapter` (`src/providers/google-vertex-budget.ts`) selects the freshest pulled message by its own Pub/Sub `publishTime`, fails closed (throws) on any message that doesn't match the documented schema, and reports this signal at a lower confidence (`0.6`, vs. `0.8` for Codex's header-derived windows) than a per-response header would earn. `spend`/`cap` are recorded as real USD metrics and their `spend-fraction` ratio is left unclamped (so a genuine over-cap soft-quota period stays visible); only the policy-facing `BudgetWindow.usedFraction` is clamped to `1.0`, since a known-to-be-≥100% real number floored to the window's documented `[0,1]` invariant is not the same thing as fabricating one from nothing.
197
+ This is still not a fully real-time signal, and the docs are explicit about both caveats Jittor must preserve rather than paper over: (1) "Budgets use estimated Cloud Billing data which is subject to change until your invoice is finalized", and (2) "Pub/Sub only provides at-least-once delivery. You might receive a message multiple times, and messages might arrive out of order." Jittor's `GoogleVertexBudgetTelemetryAdapter` (`src/google-vertex/budget-telemetry.ts`) selects the freshest pulled message by its own Pub/Sub `publishTime`, fails closed (throws) on any message that doesn't match the documented schema, and reports this signal at a lower confidence (`0.6`, vs. `0.8` for Codex's header-derived windows) than a per-response header would earn. `spend`/`cap` are recorded as real USD metrics and their `spend-fraction` ratio is left unclamped (so a genuine over-cap soft-quota period stays visible); only the policy-facing `BudgetWindow.usedFraction` is clamped to `1.0`, since a known-to-be-≥100% real number floored to the window's documented `[0,1]` invariant is not the same thing as fabricating one from nothing.
198
198
 
199
199
  Setting this up requires one-time configuration outside Jittor for each individual project: create a Pub/Sub topic, connect it to the project's budget (Project Owner/Editor role, plus Pub/Sub Admin on whichever project holds the topic), and create a pull subscription on it. Jittor only consumes the subscription; it does not provision any of this GCP-side configuration itself.
200
200
 
@@ -0,0 +1,53 @@
1
+ # Token measurement provenance
2
+
3
+ Jittor treats token counts as measurements with explicit scope and provenance. A number is not enough: provider request usage, a provider count API, exact tokenization of one text value, and `char/4` structural estimates have different authority and must not be blended or relabeled.
4
+
5
+ ## Stable measurement shape
6
+
7
+ `TokenMeasurement` contains only bounded metadata:
8
+
9
+ - `tokens`: a non-negative safe integer.
10
+ - `scope`: `request-context`, `request-input`, `response-output`, `cache-read`, `cache-write`, `context-item`, or `unattributed-residual`.
11
+ - `provenance`: `provider-reported`, `provider-count-api`, `tokenizer-exact-text`, or `structural-estimate`.
12
+ - `method`: a bounded counter identity such as `pi-assistant-usage`, `gpt-tokenizer:o200k_base`, or `char/4`.
13
+ - Optional provider/model identity, present together.
14
+
15
+ Raw text, prompts, responses, tool arguments/results, paths, credentials, and tokenizer input are not valid fields and fail strict validation.
16
+
17
+ ## Authority and reconciliation
18
+
19
+ Provider-reported request totals remain the runtime authority. Exact local tokenization applies only to the supplied text; it does not include provider message envelopes, chat templates, tool schemas, images, cache-control serialization, or provider-side rewrites.
20
+
21
+ `reconcileRequestTokens()` therefore keeps three distinct facts:
22
+
23
+ 1. The unchanged provider aggregate.
24
+ 2. The sum of locally attributed items.
25
+ 3. An explicit unattributed residual, plus any estimate overshoot.
26
+
27
+ The residual is never distributed across individual items. Until a complete request snapshot can be counted safely, an assistant turn's provider aggregate is represented with zero attributed items and the complete request count as its visible residual.
28
+
29
+ ## OpenAI-family local adapter
30
+
31
+ `loadOpenAiTextTokenCounter(provider, model)` conservatively maps known OpenAI-family model identities to `cl100k_base`, `o200k_base`, or `o200k_harmony`. It returns `null` for an unknown provider/model instead of guessing. OpenRouter identities are supported only when the model is explicitly under `openai/`.
32
+
33
+ The BPE tables are dynamically loaded only when `/context` requests exact text attribution. Importing Jittor's public API does not load them or increase daemon startup memory. Pi falls back to a visibly marked `char/4` measurement if loading or mapping fails.
34
+
35
+ ## TypeScript module evaluation
36
+
37
+ Measured under Bun 1.3.14 on 2026-08-09 with a 1,232,000-byte corpus repeated for 20 encodes. The corpus mixed TypeScript, prose, Unicode scripts/emoji, and high-entropy hexadecimal text. Results are environment-specific engineering evidence, not universal performance claims.
38
+
39
+ | Module | Version/license | Representative o200k throughput | Package/cold-load trade-off | Decision |
40
+ |---|---|---:|---|---|
41
+ | `gpt-tokenizer` | 3.4.0, MIT | 27.51 MB/s | About 53.1 MB npm unpacked. Standalone o200k load measured ~0.26 s / 176 MB RSS. Jittor public-index import remains ~0.02 s / 52 MB RSS; lazy GPT-5 counter load measured ~0.37 s / 185 MB RSS. | Selected for the first adapter, dynamically and one encoding at a time. |
42
+ | `js-tiktoken` | 1.0.21, MIT | 4.95 MB/s | About 22.4 MB npm unpacked; measured ~0.02 s / 53 MB RSS cold import. Lower startup/memory, materially slower on this corpus. | Retained as prior art/fallback candidate, not a production dependency. |
43
+ | `@huggingface/tokenizers` | 0.1.3, Apache-2.0 | Not benchmarked without a model tokenizer configuration | About 301 KB npm unpacked, excluding model `tokenizer.json` and `tokenizer_config.json`. Broad open-model support, but configuration provenance/download bounds and regex compatibility must be handled per model. | Deferred to a bounded open-model/catalog integration. |
44
+
45
+ Both tested OpenAI implementations produced 6,160,000 tokens across the 20 corpus iterations. The benchmark used encoding-level APIs, not chat/request encoding, because Jittor labels this capability exact for text only.
46
+
47
+ ## Test layers
48
+
49
+ - Domain tests validate strict serialization, provenance, fallback, residuals, overshoot, Unicode, and model mapping.
50
+ - Adapter tests execute real `gpt-tokenizer` encodings.
51
+ - Context integration tests attach measurements to the real hierarchy while preserving legacy `estimatedTokens` compatibility.
52
+ - `pi-tui-harness` runs the context viewport through a real headless VT implementation.
53
+ - `pi-process-harness` starts a real isolated Pi process, faux provider, and Jittor daemon, then verifies provider-reported token provenance through SQLite and the authenticated CLI without retaining prompt/response content.
@@ -0,0 +1,35 @@
1
+ # Historical Pi usage backfill
2
+
3
+ Jittor can populate usage and cost charts from Pi's supported v1-v3 JSONL session format. The
4
+ import boundary is separate from live extension collection and is local-only: it performs no
5
+ network requests and never writes to Pi sessions.
6
+
7
+ ```text
8
+ jittor backfill status [--json]
9
+ jittor backfill dry-run [--json]
10
+ jittor backfill run [--json]
11
+ jittor backfill cancel [--json]
12
+ ```
13
+
14
+ The source defaults to `$HOME/.pi/agent/sessions`; `JITTOR_PI_SESSIONS_DIR` selects a different
15
+ supported Pi session root. Scans are bounded by file count, per-file and total bytes, entries,
16
+ records, and elapsed time. A truncated or canceled run reports that state and can safely be resumed
17
+ by running it again.
18
+
19
+ Only assistant, compaction, and branch-summary usage objects are translated. Persisted facts are:
20
+ timestamp, provider/model/thinking identity, input/output/cache-read/cache-write tokens,
21
+ provider-reported total cost, and a SHA-256 opaque identity derived from the high-entropy session
22
+ identity plus entry identity. Prompts, responses, summaries, tool arguments/results, commands,
23
+ paths, session names, credentials, and raw session/entry IDs are discarded before the daemon store
24
+ boundary.
25
+
26
+ Each opaque identity is claimed in the same SQLite transaction as its five usage/cost observations.
27
+ Repeated, concurrent, moved-directory, and restart imports are therefore idempotent. A matching
28
+ live observation at the same provider/model/timestamp and values is recognized before insertion,
29
+ so imported history does not double-count live collection. Imported rows retain `imported: true`;
30
+ they otherwise use the same `pi` source, provider/model scope, metric names, and provider-reported
31
+ token provenance as live rows, so existing charts work without a second query path.
32
+
33
+ Import status and the last bounded cursor/progress result survive daemon restart. A stale `running`
34
+ flag is never trusted after restart. Database recreation intentionally loses both metrics and import
35
+ identities; rerunning the import repopulates the new database deterministically.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@danypops/jittor",
3
- "version": "0.16.3",
4
- "description": "Just-in-Time Token Optimizing Router for Pi -- supervised daemon, router policy, and CLI",
3
+ "version": "0.17.0",
4
+ "description": "Just-in-Time Token Optimization Router for Pi -- token and context observability with optimization policies",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
7
7
  "types": "./src/index.ts",
@@ -19,7 +19,8 @@
19
19
  "@danypops/vehicle-core": "^0.12.1",
20
20
  "@danypops/vehicle-server": "^0.17.0",
21
21
  "@danypops/vehicle-client": "^0.5.1",
22
- "google-auth-library": "^10.9.0"
22
+ "google-auth-library": "^10.9.0",
23
+ "gpt-tokenizer": "^3.4.0"
23
24
  },
24
25
  "devDependencies": {
25
26
  "bun-types": "latest"
@@ -1,4 +1,4 @@
1
- import type { MetricObservation } from "../domain/metric.ts";
1
+ import type { MetricObservation } from "../observability/metric.ts";
2
2
 
3
3
  /**
4
4
  * Official Anthropic Messages API rate-limit response headers, verified against
@@ -1,12 +1,12 @@
1
1
  import { BENCHMARK_MAX_MODELS_PER_SOURCE, BENCHMARK_REFRESH_INTERVAL_MS, BENCHMARK_SOURCE_MAX_RESPONSE_BYTES } from "../constants.ts";
2
+ import { contractRecord } from "../openrouter/contracts.ts";
2
3
  import {
3
4
  type BenchmarkObservation,
4
5
  type BenchmarkSourceSnapshot,
5
6
  normalizeModelIdentity,
6
7
  validateBenchmarkObservation,
7
- } from "../domain/benchmark.ts";
8
- import type { BenchmarkSource } from "../ports/benchmark-source.ts";
9
- import { contractRecord } from "../providers/openrouter-contracts.ts";
8
+ } from "../optimization/model-selection/benchmark.ts";
9
+ import type { BenchmarkSource } from "../optimization/model-selection/source.ts";
10
10
 
11
11
  const SOURCE_ID = "artificial-analysis-direct";
12
12
  const ENDPOINT = "https://artificialanalysis.ai/api/v2/data/llms/models";
@@ -0,0 +1,51 @@
1
+ import type { UsageImportResult, UsageImportStatus } from "../observability/usage-import.ts";
2
+ import type { CliDependencies } from "./support.ts";
3
+
4
+ export const BACKFILL_USAGE_LINES = [" backfill <status|dry-run|run|cancel> [--json]"];
5
+
6
+ export function formatUsageImportResult(result: UsageImportResult): string {
7
+ return [
8
+ `Pi usage backfill: ${result.dryRun ? "dry run" : result.canceled ? "canceled" : "complete"}${result.truncated ? " · bounded/truncated" : ""}`,
9
+ `Records: ${result.discovered.toLocaleString()} discovered · ${result.imported.toLocaleString()} imported · ${result.duplicates.toLocaleString()} duplicates`,
10
+ `Scanned: ${result.filesScanned.toLocaleString()} files · ${result.entriesScanned.toLocaleString()} entries · ${result.bytesScanned.toLocaleString()} bytes · ${result.malformedEntries.toLocaleString()} malformed`,
11
+ ].join("\n");
12
+ }
13
+
14
+ export function formatUsageImportStatus(status: UsageImportStatus): string {
15
+ if (!status.lastResult)
16
+ return `Pi usage backfill: ${status.running ? "running" : "not run"}${status.cancelRequested ? " · cancellation requested" : ""}`;
17
+ return `${status.running ? "Running" : "Last run"}${status.cancelRequested ? " · cancellation requested" : ""}\n${formatUsageImportResult(status.lastResult)}`;
18
+ }
19
+
20
+ export async function runBackfillCommand(
21
+ action: string | undefined,
22
+ rest: string[],
23
+ deps: CliDependencies,
24
+ usage: () => number,
25
+ ): Promise<number> {
26
+ if (!action || !["status", "dry-run", "run", "cancel"].includes(action)) return usage();
27
+ let json = false;
28
+ for (const argument of rest) {
29
+ if (argument !== "--json") return usage();
30
+ json = true;
31
+ }
32
+ try {
33
+ const result =
34
+ action === "status"
35
+ ? await deps.client.call("usage.import_status", {})
36
+ : action === "cancel"
37
+ ? await deps.client.call("usage.import_cancel", {})
38
+ : await deps.client.call("usage.import", { dryRun: action === "dry-run" });
39
+ deps.stdout(
40
+ json
41
+ ? JSON.stringify(result)
42
+ : action === "run" || action === "dry-run"
43
+ ? formatUsageImportResult(result as UsageImportResult)
44
+ : formatUsageImportStatus(result as UsageImportStatus),
45
+ );
46
+ return 0;
47
+ } catch (error) {
48
+ deps.stderr(error instanceof Error ? error.message : String(error));
49
+ return 1;
50
+ }
51
+ }
@@ -7,10 +7,10 @@ import {
7
7
  MODEL_RANKING_DEFAULT_RELIABILITY_WEIGHT,
8
8
  MODEL_RANKING_MAX_SOURCES,
9
9
  } from "../constants.ts";
10
- import type { BenchmarkQuery, BenchmarkQueryResult, BenchmarkRefreshResult } from "../domain/benchmark.ts";
11
- import { type ModelTaskDomain, type ModelTaskType, TASK_DOMAINS, TASK_TYPES } from "../domain/model-observation.ts";
12
- import type { ModelCandidate, ModelRankingResult, ScopeAuthority, UtilityWeights } from "../domain/model-ranking.ts";
13
- import type { ModelRecommendationInput } from "../domain/model-ranking-service.ts";
10
+ import { type ModelTaskDomain, type ModelTaskType, TASK_DOMAINS, TASK_TYPES } from "../observability/model-observation.ts";
11
+ import type { BenchmarkQuery, BenchmarkQueryResult, BenchmarkRefreshResult } from "../optimization/model-selection/benchmark.ts";
12
+ import type { ModelRecommendationInput } from "../optimization/model-selection/ranker.ts";
13
+ import type { ModelCandidate, ModelRankingResult, ScopeAuthority, UtilityWeights } from "../optimization/model-selection/ranking.ts";
14
14
  import { parseCandidate } from "./route-args.ts";
15
15
  import { type CliDependencies, humanField } from "./support.ts";
16
16