@danypops/jittor 0.16.3 → 0.18.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 (97) 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 +5 -4
  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/cache.ts +120 -0
  15. package/src/cli-commands/catalog.ts +123 -0
  16. package/src/cli-commands/compaction.ts +1 -1
  17. package/src/cli-commands/context.ts +77 -4
  18. package/src/cli-commands/export.ts +30 -0
  19. package/src/cli-commands/metrics.ts +8 -2
  20. package/src/cli-commands/op.ts +1 -1
  21. package/src/cli-commands/route-args.ts +2 -2
  22. package/src/cli-commands/router.ts +2 -2
  23. package/src/cli-commands/support.ts +2 -2
  24. package/src/cli.ts +59 -21
  25. package/src/{providers/codex-contracts.ts → codex/contracts.ts} +1 -1
  26. package/src/codex/source.ts +53 -0
  27. package/src/{providers/codex.ts → codex/telemetry.ts} +2 -2
  28. package/src/constants.ts +31 -0
  29. package/src/daemon.ts +53 -23
  30. package/src/{providers/google-vertex-budget-contracts.ts → google-vertex/budget-contracts.ts} +3 -3
  31. package/src/{providers/google-vertex-budget.ts → google-vertex/budget-telemetry.ts} +6 -6
  32. package/src/{providers/google-vertex-contracts.ts → google-vertex/failures.ts} +1 -1
  33. package/src/google-vertex/source.ts +35 -0
  34. package/src/index.ts +149 -55
  35. package/src/{adapters/lmarena-hf-source.ts → lmarena/benchmark-source.ts} +3 -3
  36. package/src/observability/budget.ts +14 -0
  37. package/src/observability/cache-economics.ts +623 -0
  38. package/src/observability/context-delta.ts +309 -0
  39. package/src/{domain → observability}/context-hub.ts +19 -2
  40. package/src/observability/context-snapshot-history.ts +281 -0
  41. package/src/{domain → observability}/context-telemetry.ts +232 -4
  42. package/src/observability/model-identity.ts +42 -0
  43. package/src/{domain → observability}/model-observation.ts +26 -11
  44. package/src/{ports/metric-store.ts → observability/store.ts} +2 -2
  45. package/src/{ports → observability}/telemetry-source.ts +2 -2
  46. package/src/observability/token-measurement.ts +194 -0
  47. package/src/observability/usage-import.ts +122 -0
  48. package/src/openai/token-counter.ts +63 -0
  49. package/src/{adapters/openrouter-benchmark-source.ts → openrouter/benchmark-source.ts} +3 -3
  50. package/src/{providers/openrouter-contracts.ts → openrouter/contracts.ts} +1 -1
  51. package/src/{adapters/openrouter-design-arena-source.ts → openrouter/design-arena-source.ts} +4 -4
  52. package/src/openrouter/source.ts +20 -0
  53. package/src/{providers/openrouter.ts → openrouter/telemetry.ts} +2 -2
  54. package/src/{domain → optimization/model-selection}/benchmark.ts +9 -27
  55. package/src/optimization/model-selection/catalog-store.ts +97 -0
  56. package/src/optimization/model-selection/catalog.ts +478 -0
  57. package/src/{ports/benchmark-controller.ts → optimization/model-selection/controller.ts} +1 -1
  58. package/src/{adapters/metric-benchmark-store.ts → optimization/model-selection/observation-store.ts} +5 -5
  59. package/src/{domain/model-ranking-service.ts → optimization/model-selection/ranker.ts} +6 -12
  60. package/src/{domain/model-ranking.ts → optimization/model-selection/ranking.ts} +8 -2
  61. package/src/{ports/benchmark-source.ts → optimization/model-selection/source.ts} +1 -1
  62. package/src/{ports/benchmark-store.ts → optimization/model-selection/store.ts} +1 -1
  63. package/src/{domain/codex-recovery.ts → optimization/recovery/codex.ts} +1 -1
  64. package/src/{ports/router-controller.ts → optimization/routing/controller.ts} +1 -1
  65. package/src/{policy.ts → optimization/routing/policy.ts} +4 -14
  66. package/src/{router.ts → optimization/routing/router.ts} +4 -10
  67. package/src/otlp/exporter.ts +354 -0
  68. package/src/pi/session-usage-source.ts +203 -0
  69. package/src/{session-identity-service.ts → sessions/identity.ts} +2 -2
  70. package/src/{operations/session-scope.ts → sessions/router-authorization.ts} +1 -1
  71. package/src/{db.ts → sqlite/database.ts} +14 -1
  72. package/src/{adapters/sqlite-metric-store.ts → sqlite/metric-store.ts} +4 -4
  73. package/src/{adapters/sqlite-session-identity-store.ts → sqlite/session-store.ts} +1 -1
  74. package/src/sqlite/usage-import-store.ts +133 -0
  75. package/src/telemetry-export/exporter.ts +84 -0
  76. package/src/{operations → vehicle}/benchmark-operations.ts +3 -3
  77. package/src/vehicle/cache-operations.ts +95 -0
  78. package/src/vehicle/catalog-operations.ts +10 -0
  79. package/src/{client.ts → vehicle/client.ts} +1 -1
  80. package/src/{operations → vehicle}/context-operations.ts +13 -5
  81. package/src/vehicle/export-operations.ts +12 -0
  82. package/src/{operations/metrics-operations.ts → vehicle/metric-operations.ts} +4 -4
  83. package/src/{operations → vehicle}/model-ranking-operations.ts +3 -3
  84. package/src/{vehicle-registration.ts → vehicle/registration.ts} +21 -4
  85. package/src/{operations/router-operations.ts → vehicle/routing-operations.ts} +4 -4
  86. package/src/{service.ts → vehicle/service.ts} +114 -26
  87. package/src/{operations/session-identity-operations.ts → vehicle/session-operations.ts} +3 -3
  88. package/src/vehicle/usage-import-operations.ts +10 -0
  89. package/src/providers/telemetry-sources.ts +0 -108
  90. /package/src/{providers/google-adc-auth.ts → google-vertex/auth.ts} +0 -0
  91. /package/src/{domain → observability}/metric.ts +0 -0
  92. /package/src/{domain → observability}/task-cost.ts +0 -0
  93. /package/src/{domain → observability}/task-focus.ts +0 -0
  94. /package/src/{domain → observability}/usage.ts +0 -0
  95. /package/src/{config.ts → optimization/routing/config.ts} +0 -0
  96. /package/src/{ports/session-identity-store.ts → sessions/store.ts} +0 -0
  97. /package/src/{operations/types.ts → vehicle/operation-types.ts} +0 -0
@@ -0,0 +1,120 @@
1
+ import type {
2
+ CacheEconomicsAggregateTotals,
3
+ CacheEconomicsModelSummary,
4
+ CacheEconomicsStablePrefixPoint,
5
+ CacheEconomicsSummary,
6
+ CacheEconomicsTaskSummary,
7
+ CacheEconomicsUnattributedActivity,
8
+ } from "../observability/cache-economics.ts";
9
+ import { type CliDependencies, callAndPrint, humanField } from "./support.ts";
10
+
11
+ export const CACHE_USAGE_LINES = [" cache economics --since <ms> --until <ms> [--json]"];
12
+
13
+ interface CacheEconomicsArgs {
14
+ since: number;
15
+ until: number;
16
+ json: boolean;
17
+ }
18
+
19
+ function parseCacheArgs(action: string | undefined, args: string[]): CacheEconomicsArgs | null {
20
+ if (action !== "economics") return null;
21
+ let json = false;
22
+ let since: number | undefined;
23
+ let until: number | undefined;
24
+ for (let index = 0; index < args.length; index += 1) {
25
+ const argument = args[index];
26
+ if (argument === "--json") {
27
+ json = true;
28
+ continue;
29
+ }
30
+ if (argument !== "--since" && argument !== "--until") return null;
31
+ const raw = args[++index];
32
+ const value = raw === undefined ? Number.NaN : Number(raw);
33
+ if (!Number.isSafeInteger(value) || value < 0) return null;
34
+ if (argument === "--since") since = value;
35
+ else until = value;
36
+ }
37
+ if (since === undefined || until === undefined || until < since) return null;
38
+ return { since, until, json };
39
+ }
40
+
41
+ function formatUsdAmount(amount: number): string {
42
+ return `$${amount.toFixed(Math.abs(amount) < 0.01 && amount !== 0 ? 4 : 2)}`;
43
+ }
44
+
45
+ function basisSuffix(basis: "provider-reported" | "catalog-estimate" | "unknown"): string {
46
+ return basis === "provider-reported" ? "" : basis === "catalog-estimate" ? " (catalog estimate)" : "";
47
+ }
48
+
49
+ function formatCostField(amountUsd: number | null, basis: "provider-reported" | "catalog-estimate" | "unknown"): string {
50
+ return amountUsd === null ? "unknown" : `${formatUsdAmount(amountUsd)}${basisSuffix(basis)}`;
51
+ }
52
+
53
+ function formatAggregateFields(totals: CacheEconomicsAggregateTotals): string {
54
+ const payback = totals.paybackAchieved === null ? "n/a" : totals.paybackAchieved ? "yes" : "not yet";
55
+ return [
56
+ `read ${totals.cacheReadTokens.toLocaleString()} tok (${formatCostField(totals.cacheReadCostUsd, totals.cacheReadCostBasis)})`,
57
+ `write ${totals.cacheWriteTokens.toLocaleString()} tok (${formatCostField(totals.cacheWriteCostUsd, totals.cacheWriteCostBasis)})`,
58
+ `savings ${totals.savingsUsd === null ? "unknown" : formatUsdAmount(totals.savingsUsd)}`,
59
+ `premium ${totals.cacheWritePremiumUsd === null ? "unknown" : formatUsdAmount(totals.cacheWritePremiumUsd)}`,
60
+ `break-even ${totals.breakEvenReadTokens === null ? "unknown" : `${totals.breakEvenReadTokens.toLocaleString()} tok`}`,
61
+ `payback ${payback}`,
62
+ ].join(" · ");
63
+ }
64
+
65
+ function formatFreshnessSuffix(catalogFreshness: "fresh" | "stale" | null): string {
66
+ return catalogFreshness === "stale" ? " (stale catalog snapshot used for the estimate(s) above)" : "";
67
+ }
68
+
69
+ function formatModelLine(model: CacheEconomicsModelSummary): string {
70
+ return `- ${humanField(model.provider)}/${humanField(model.model)}: ${formatAggregateFields(model)}${formatFreshnessSuffix(model.catalogFreshness)}`;
71
+ }
72
+
73
+ function formatTaskLine(task: CacheEconomicsTaskSummary): string {
74
+ return `- ${humanField(task.taskId)}: ${formatAggregateFields(task)}${formatFreshnessSuffix(task.catalogFreshness)}`;
75
+ }
76
+
77
+ function formatUnattributedLine(activity: CacheEconomicsUnattributedActivity): string {
78
+ return [
79
+ `Unattributed cache activity (no Papyrus task focused):`,
80
+ `read ${activity.cacheReadTokens.toLocaleString()} tok (${formatCostField(activity.cacheReadCostUsd, activity.cacheReadCostBasis)})`,
81
+ `write ${activity.cacheWriteTokens.toLocaleString()} tok (${formatCostField(activity.cacheWriteCostUsd, activity.cacheWriteCostBasis)})`,
82
+ ].join(" · ");
83
+ }
84
+
85
+ function formatChurnPoint(point: CacheEconomicsStablePrefixPoint): string {
86
+ return `- ${new Date(point.observedAt).toISOString()} session ${humanField(point.sessionId)}: ${point.stablePrefixTokens.toLocaleString()} tok${point.resetReason === null ? "" : ` (${point.resetReason} reset)`}`;
87
+ }
88
+
89
+ export function formatCacheEconomics(summary: CacheEconomicsSummary): string {
90
+ const lines = [
91
+ `Cache economics: ${summary.models.length.toLocaleString()} model(s)${summary.truncated ? " (query limit reached; totals are a lower bound)" : ""}`,
92
+ ...summary.models.map(formatModelLine),
93
+ `By task: ${summary.tasks.length.toLocaleString()} task(s)`,
94
+ ...summary.tasks.map(formatTaskLine),
95
+ formatUnattributedLine(summary.unattributedCacheActivity),
96
+ ...(summary.stablePrefixChurn.length > 0
97
+ ? [
98
+ `Stable-prefix churn (${summary.stablePrefixChurn.length.toLocaleString()} snapshot(s), oldest first):`,
99
+ ...summary.stablePrefixChurn.map(formatChurnPoint),
100
+ ]
101
+ : []),
102
+ `Candidate missed-cache opportunities: ${summary.missedOpportunities.length.toLocaleString()}`,
103
+ ...summary.missedOpportunities.map(
104
+ (candidate) =>
105
+ `- session ${humanField(candidate.sessionId)}: ${candidate.resetReason} reset, then ${candidate.cacheWriteTokens.toLocaleString()} cache-write tok${candidate.cacheWriteCostUsd === null ? "" : ` (${formatUsdAmount(candidate.cacheWriteCostUsd)})`} -- ${candidate.note}`,
106
+ ),
107
+ ];
108
+ return lines.join("\n");
109
+ }
110
+
111
+ export async function runCacheCommand(
112
+ action: string | undefined,
113
+ rest: string[],
114
+ deps: CliDependencies,
115
+ usage: () => number,
116
+ ): Promise<number> {
117
+ const parsed = parseCacheArgs(action, rest);
118
+ if (!parsed) return usage();
119
+ return callAndPrint(deps, "cache.economics", { since: parsed.since, until: parsed.until }, parsed.json, formatCacheEconomics);
120
+ }
@@ -0,0 +1,123 @@
1
+ import { MODEL_CATALOG_MAX_QUERY_LIMIT } from "../constants.ts";
2
+ import type { ModelCatalogQuery, ModelCatalogQueryResult, ModelCatalogStatus } from "../optimization/model-selection/catalog.ts";
3
+ import { type CliDependencies, humanField } from "./support.ts";
4
+
5
+ export const CATALOG_USAGE_LINES = [
6
+ " catalog <status|refresh|list> [--provider <id>] [--model <id>] [--limit <n>] [--context-tokens <n>] [--input-tokens <n>] [--output-tokens <n>] [--input-price <usd-per-million>] [--output-price <usd-per-million>] [--force] [--json]",
7
+ ];
8
+
9
+ interface CatalogArgs {
10
+ action: "status" | "refresh" | "list";
11
+ json: boolean;
12
+ force: boolean;
13
+ query: ModelCatalogQuery;
14
+ }
15
+
16
+ function parsePositive(raw: string, integer: boolean): number | null {
17
+ const value = Number(raw);
18
+ if (!Number.isFinite(value) || value < 0 || (integer && !Number.isSafeInteger(value))) return null;
19
+ return value;
20
+ }
21
+
22
+ function parseCatalogArgs(action: string | undefined, args: string[]): CatalogArgs | null {
23
+ if (action !== "status" && action !== "refresh" && action !== "list") return null;
24
+ let json = false;
25
+ let force = false;
26
+ const query: ModelCatalogQuery = {};
27
+ for (let index = 0; index < args.length; index += 1) {
28
+ const argument = args[index];
29
+ if (argument === "--json") {
30
+ json = true;
31
+ continue;
32
+ }
33
+ if (argument === "--force" && action === "refresh") {
34
+ force = true;
35
+ continue;
36
+ }
37
+ if (action !== "list") return null;
38
+ if (
39
+ !argument ||
40
+ ![
41
+ "--provider",
42
+ "--model",
43
+ "--limit",
44
+ "--context-tokens",
45
+ "--input-tokens",
46
+ "--output-tokens",
47
+ "--input-price",
48
+ "--output-price",
49
+ ].includes(argument)
50
+ )
51
+ return null;
52
+ const raw = args[++index];
53
+ if (!raw) return null;
54
+ if (argument === "--provider") query.provider = raw;
55
+ else if (argument === "--model") query.model = raw;
56
+ else if (argument === "--limit") {
57
+ const value = parsePositive(raw, true);
58
+ if (value === null || value < 1 || value > MODEL_CATALOG_MAX_QUERY_LIMIT) return null;
59
+ query.limit = value;
60
+ } else {
61
+ const integer = argument.endsWith("-tokens");
62
+ const value = parsePositive(raw, integer);
63
+ if (value === null) return null;
64
+ const key = {
65
+ "--context-tokens": "contextTokens",
66
+ "--input-tokens": "inputTokens",
67
+ "--output-tokens": "outputTokens",
68
+ "--input-price": "inputPrice",
69
+ "--output-price": "outputPrice",
70
+ }[argument] as "contextTokens" | "inputTokens" | "outputTokens" | "inputPrice" | "outputPrice";
71
+ if (!query.overrides) query.overrides = {};
72
+ query.overrides[key] = value;
73
+ }
74
+ }
75
+ return { action, json, force, query };
76
+ }
77
+
78
+ export function formatCatalogStatus(status: ModelCatalogStatus): string {
79
+ if (!status.configured && !status.hasSnapshot) return "Model catalog: not configured (set JITTOR_MODELS_DEV_CATALOG=1)";
80
+ const state = status.ok === null ? "not refreshed" : status.ok ? "ready" : "refresh failed; last-good snapshot retained";
81
+ return `Model catalog: ${state} · ${status.entries.toLocaleString()} entries · revision ${status.revision ?? "unknown"}`;
82
+ }
83
+
84
+ export function formatCatalogQuery(result: ModelCatalogQueryResult): string {
85
+ return [
86
+ `Model catalog: ${result.completeness} · ${result.freshness} · ${result.entries.length.toLocaleString()} entries · ${humanField(result.provenance.revision)}`,
87
+ ...result.entries.map((entry) => {
88
+ const cost = entry.pricing
89
+ ? ` · $${entry.pricing.input ?? "unknown"}/$${entry.pricing.output ?? "unknown"} input/output per 1M`
90
+ : " · pricing unknown";
91
+ return `- ${humanField(entry.canonical)} · context ${entry.limits.context.toLocaleString()} · output ${entry.limits.output.toLocaleString()}${cost} · ${entry.status}`;
92
+ }),
93
+ ].join("\n");
94
+ }
95
+
96
+ export async function runCatalogCommand(
97
+ action: string | undefined,
98
+ rest: string[],
99
+ deps: CliDependencies,
100
+ usage: () => number,
101
+ ): Promise<number> {
102
+ const parsed = parseCatalogArgs(action, rest);
103
+ if (!parsed) return usage();
104
+ try {
105
+ const result =
106
+ parsed.action === "list"
107
+ ? await deps.client.call("catalog.query", parsed.query)
108
+ : parsed.action === "refresh"
109
+ ? await deps.client.call("catalog.refresh", { force: parsed.force })
110
+ : await deps.client.call("catalog.status", {});
111
+ deps.stdout(
112
+ parsed.json
113
+ ? JSON.stringify(result)
114
+ : parsed.action === "list"
115
+ ? formatCatalogQuery(result as ModelCatalogQueryResult)
116
+ : formatCatalogStatus(result as ModelCatalogStatus),
117
+ );
118
+ return 0;
119
+ } catch (error) {
120
+ deps.stderr(error instanceof Error ? error.message : String(error));
121
+ return 1;
122
+ }
123
+ }
@@ -1,4 +1,4 @@
1
- import type { CompactionDurationEstimate } from "../domain/context-telemetry.ts";
1
+ import type { CompactionDurationEstimate } from "../observability/context-telemetry.ts";
2
2
  import { parseJsonOnlyArgs } from "./router.ts";
3
3
  import { type CliDependencies, callAndPrint } from "./support.ts";
4
4
 
@@ -1,7 +1,12 @@
1
- import type { ContextAssessment } from "../domain/context-telemetry.ts";
1
+ import type { ContextDelta, ContextSnapshot } from "../observability/context-delta.ts";
2
+ import type { ContextAssessment } from "../observability/context-telemetry.ts";
2
3
  import type { CliDependencies } from "./support.ts";
3
4
 
4
- export const CONTEXT_USAGE_LINES = [" context [--since <ms>] [--until <ms>] [--json]"];
5
+ export const CONTEXT_USAGE_LINES = [
6
+ " context [--since <ms>] [--until <ms>] [--json]",
7
+ " context delta --session-id <opaque-id> [--json]",
8
+ " context snapshot --snapshot <json> [--json]",
9
+ ];
5
10
 
6
11
  function parseContextArgs(args: string[]): { input: { since?: number; until?: number }; json: boolean } | null {
7
12
  const input: { since?: number; until?: number } = {};
@@ -34,19 +39,87 @@ export function formatContextAssessment(summary: ContextAssessment): string {
34
39
  `Injection mix: rules ${summary.injection.ruleCharacters.toLocaleString()} chars · tasks ${summary.injection.taskCharacters.toLocaleString()} chars · estimated ${summary.injection.estimatedTokens.toLocaleString()} tokens · unchanged ${summary.injection.unchangedRate === null ? "unknown" : `${(summary.injection.unchangedRate * 100).toFixed(1)}%`}`,
35
40
  `Compactions: ${summary.compaction.completed} completed · ${summary.compaction.aborted} aborted · avg ${value(summary.compaction.averageDurationMs, "ms")} · ${summary.compaction.perRun === null ? "unknown" : summary.compaction.perRun.toFixed(3)} per agent run · ${summary.compaction.perTurn === null ? "unknown" : summary.compaction.perTurn.toFixed(3)} per turn`,
36
41
  `Between compactions: ${value(summary.compaction.averageTurnsBetween, " turns")} · ${value(summary.compaction.averageProviderTokensBetween, " provider tokens")} · ${value(summary.compaction.averageCacheReadTokensBetween, " cache-read tokens")}`,
42
+ `Effectiveness: ${summary.compaction.effectivenessSamples} samples · avg reduction ${value(summary.compaction.averageReductionRatio === null ? null : summary.compaction.averageReductionRatio * 100, "%")} · pre ${value(summary.compaction.averagePreContextTokens, " tokens")} · post ${value(summary.compaction.averagePostContextTokens, " tokens")}`,
43
+ `Regrowth: 50% ${summary.compaction.regrowth["50"] ? `${value(summary.compaction.regrowth["50"].averageTurns, " turns")} / ${value(summary.compaction.regrowth["50"].averageElapsedMs, "ms")}` : "unknown"} · 80% ${summary.compaction.regrowth["80"] ? `${value(summary.compaction.regrowth["80"].averageTurns, " turns")} / ${value(summary.compaction.regrowth["80"].averageElapsedMs, "ms")}` : "unknown"} · 100% ${summary.compaction.regrowth["100"] ? `${value(summary.compaction.regrowth["100"].averageTurns, " turns")} / ${value(summary.compaction.regrowth["100"].averageElapsedMs, "ms")}` : "unknown"}`,
44
+ `Mechanisms: Pi ${summary.compaction.mechanisms["pi-native"]} · provider ${summary.compaction.mechanisms["provider-side"]} · extension ${summary.compaction.mechanisms.extension}`,
37
45
  `Reasons: threshold ${summary.compaction.reasons.threshold} · overflow ${summary.compaction.reasons.overflow} · manual ${summary.compaction.reasons.manual}`,
38
46
  ].join("\n");
39
47
  }
40
48
 
49
+ export function formatContextDelta(delta: ContextDelta | null): string {
50
+ if (!delta) return "Context delta: unavailable (no snapshot recorded for this session)";
51
+ const first = delta.firstChangedSegment;
52
+ const lifecycle = new Map<string, number>();
53
+ for (const change of delta.changes) lifecycle.set(change.lifecycle, (lifecycle.get(change.lifecycle) ?? 0) + 1);
54
+ const lifecycleText = [...lifecycle.entries()].map(([name, count]) => `${name} ${count}`).join(" · ") || "none";
55
+ const growth = delta.growthBySource
56
+ .filter((item) => item.deltaTokens !== 0)
57
+ .map((item) => `${item.source} ${item.deltaTokens > 0 ? "+" : ""}${item.deltaTokens.toLocaleString()} tokens`)
58
+ .join(" · ");
59
+ return [
60
+ `Context delta: ${new Date(delta.capturedAt).toISOString()}`,
61
+ `Stable prefix: ${delta.stablePrefixTokens.toLocaleString()} tokens${
62
+ first ? ` · first change ${first.source} at request position ${first.requestPosition ?? "historical"}` : " · unchanged"
63
+ }`,
64
+ `Lifecycle: ${lifecycleText}`,
65
+ `Growth: ${growth || "none"}`,
66
+ "Stable-prefix correlation is structural evidence, not proof of provider cache behavior.",
67
+ ].join("\n");
68
+ }
69
+
70
+ function parseDeltaArgs(args: string[]): { input: { session_id: string }; json: boolean } | null {
71
+ let sessionId: string | undefined;
72
+ let json = false;
73
+ for (let index = 0; index < args.length; index++) {
74
+ const argument = args[index];
75
+ if (argument === "--json") json = true;
76
+ else if (argument === "--session-id") sessionId = args[++index];
77
+ else return null;
78
+ }
79
+ if (!sessionId || !/^[A-Za-z0-9_-]{32,64}$/.test(sessionId)) return null;
80
+ return { input: { session_id: sessionId }, json };
81
+ }
82
+
83
+ function parseSnapshotArgs(args: string[]): { input: ContextSnapshot; json: boolean } | null {
84
+ let snapshotValue: string | undefined;
85
+ let json = false;
86
+ for (let index = 0; index < args.length; index++) {
87
+ const argument = args[index];
88
+ if (argument === "--json") json = true;
89
+ else if (argument === "--snapshot") snapshotValue = args[++index];
90
+ else return null;
91
+ }
92
+ if (!snapshotValue) return null;
93
+ try {
94
+ return { input: JSON.parse(snapshotValue) as ContextSnapshot, json };
95
+ } catch {
96
+ return null;
97
+ }
98
+ }
99
+
41
100
  export async function runContextCommand(
42
101
  action: string | undefined,
43
102
  rest: string[],
44
103
  deps: CliDependencies,
45
104
  usage: () => number,
46
105
  ): Promise<number> {
47
- const parsed = parseContextArgs([...(action === undefined ? [] : [action]), ...rest]);
48
- if (!parsed) return usage();
49
106
  try {
107
+ if (action === "delta") {
108
+ const parsed = parseDeltaArgs(rest);
109
+ if (!parsed) return usage();
110
+ const delta = await deps.client.call("context.delta", parsed.input);
111
+ deps.stdout(parsed.json ? JSON.stringify(delta) : formatContextDelta(delta));
112
+ return 0;
113
+ }
114
+ if (action === "snapshot") {
115
+ const parsed = parseSnapshotArgs(rest);
116
+ if (!parsed) return usage();
117
+ const delta = await deps.client.call("context.snapshot", parsed.input);
118
+ deps.stdout(parsed.json ? JSON.stringify(delta) : formatContextDelta(delta));
119
+ return 0;
120
+ }
121
+ const parsed = parseContextArgs([...(action === undefined ? [] : [action]), ...rest]);
122
+ if (!parsed) return usage();
50
123
  const summary = await deps.client.call("context.assess", parsed.input);
51
124
  deps.stdout(parsed.json ? JSON.stringify(summary) : formatContextAssessment(summary));
52
125
  return 0;
@@ -0,0 +1,30 @@
1
+ import type { ObservationExportStatus } from "../telemetry-export/exporter.ts";
2
+ import type { CliDependencies } from "./support.ts";
3
+
4
+ export const EXPORT_USAGE_LINES = [" export <status|flush> [--json]"];
5
+
6
+ export function formatExportStatus(status: ObservationExportStatus): string {
7
+ if (!status.enabled) return "OTLP export: disabled";
8
+ return [
9
+ `OTLP export: enabled · semantic conventions ${status.semanticConventions}`,
10
+ `Queue: ${status.queued.toLocaleString()} queued · ${status.exported.toLocaleString()} exported · ${status.dropped.toLocaleString()} dropped · ${status.failures.toLocaleString()} failed batches`,
11
+ ].join("\n");
12
+ }
13
+
14
+ export async function runExportCommand(
15
+ action: string | undefined,
16
+ rest: string[],
17
+ deps: CliDependencies,
18
+ usage: () => number,
19
+ ): Promise<number> {
20
+ if ((action !== "status" && action !== "flush") || rest.some((argument) => argument !== "--json")) return usage();
21
+ const json = rest.includes("--json");
22
+ try {
23
+ const status = await deps.client.call(action === "flush" ? "export.flush" : "export.status", {});
24
+ deps.stdout(json ? JSON.stringify(status) : formatExportStatus(status));
25
+ return 0;
26
+ } catch (error) {
27
+ deps.stderr(error instanceof Error ? error.message : String(error));
28
+ return 1;
29
+ }
30
+ }
@@ -5,8 +5,14 @@ import {
5
5
  METRIC_BATCH_MAX_OBSERVATIONS,
6
6
  USAGE_MAX_DISTINCT_SCOPES,
7
7
  } from "../constants.ts";
8
- import { METRIC_UNITS, type MetricObservation, type MetricQuery, type MetricUnit, type StoredMetricObservation } from "../domain/metric.ts";
9
- import type { TaskCostSummary } from "../domain/task-cost.ts";
8
+ import {
9
+ METRIC_UNITS,
10
+ type MetricObservation,
11
+ type MetricQuery,
12
+ type MetricUnit,
13
+ type StoredMetricObservation,
14
+ } from "../observability/metric.ts";
15
+ import type { TaskCostSummary } from "../observability/task-cost.ts";
10
16
  import { type CliDependencies, callAndPrint, humanField } from "./support.ts";
11
17
 
12
18
  export const METRICS_USAGE_LINES = [
@@ -1,4 +1,4 @@
1
- import { EXPECTED_OPERATION_NAMES, type OperationName } from "../service.ts";
1
+ import { EXPECTED_OPERATION_NAMES, type OperationName } from "../vehicle/service.ts";
2
2
  import type { CliDependencies } from "./support.ts";
3
3
 
4
4
  export const OP_USAGE_LINES = [" op <operation> [--input <json>]"];
@@ -1,5 +1,5 @@
1
- import type { ModelCandidate } from "../domain/model-ranking.ts";
2
- import type { Route } from "../policy.ts";
1
+ import type { ModelCandidate } from "../optimization/model-selection/ranking.ts";
2
+ import type { Route } from "../optimization/routing/policy.ts";
3
3
 
4
4
  /** Shared `provider/model@thinking` parsing for router and benchmark CLI arguments -- a Route and a ModelCandidate are structurally identical at this boundary. */
5
5
  export function parseCandidate(raw: string): ModelCandidate | null {
@@ -1,6 +1,6 @@
1
1
  import { CLI_AVAILABLE_ROUTES_MAX } from "../constants.ts";
2
- import type { PolicyDecision, Route } from "../policy.ts";
3
- import type { RouteOverride, RouterStatus, TelemetryPollResult } from "../ports/router-controller.ts";
2
+ import type { RouteOverride, RouterStatus, TelemetryPollResult } from "../optimization/routing/controller.ts";
3
+ import type { PolicyDecision, Route } from "../optimization/routing/policy.ts";
4
4
  import { parseRoute } from "./route-args.ts";
5
5
  import { type CliDependencies, callAndPrint, humanField } from "./support.ts";
6
6
 
@@ -1,6 +1,6 @@
1
- import type { JittorClient } from "../client.ts";
2
1
  import { HUMAN_TEXT_FIELD_MAX_CHARACTERS } from "../constants.ts";
3
- import type { OperationInputs, OperationName, OperationOutputs } from "../service.ts";
2
+ import type { JittorClient } from "../vehicle/client.ts";
3
+ import type { OperationInputs, OperationName, OperationOutputs } from "../vehicle/service.ts";
4
4
 
5
5
  export interface CliDependencies {
6
6
  client: Pick<JittorClient, "call">;
package/src/cli.ts CHANGED
@@ -1,21 +1,38 @@
1
1
  #!/usr/bin/env bun
2
2
  import { fileURLToPath } from "node:url";
3
+ import { BACKFILL_USAGE_LINES, formatUsageImportResult, formatUsageImportStatus, runBackfillCommand } from "./cli-commands/backfill.ts";
3
4
  import { BENCHMARKS_USAGE_LINES, runBenchmarksCommand } from "./cli-commands/benchmarks.ts";
5
+ import { CACHE_USAGE_LINES, formatCacheEconomics, runCacheCommand } from "./cli-commands/cache.ts";
6
+ import { CATALOG_USAGE_LINES, formatCatalogQuery, formatCatalogStatus, runCatalogCommand } from "./cli-commands/catalog.ts";
4
7
  import { runCompactionCommand } from "./cli-commands/compaction.ts";
5
- import { CONTEXT_USAGE_LINES, formatContextAssessment, runContextCommand } from "./cli-commands/context.ts";
8
+ import { CONTEXT_USAGE_LINES, formatContextAssessment, formatContextDelta, runContextCommand } from "./cli-commands/context.ts";
9
+ import { EXPORT_USAGE_LINES, formatExportStatus, runExportCommand } from "./cli-commands/export.ts";
6
10
  import { formatCostByTask, formatMetricsQuery, METRICS_USAGE_LINES, runMetricsCommand } from "./cli-commands/metrics.ts";
7
11
  import { OP_USAGE_LINES, runOpCommand } from "./cli-commands/op.ts";
8
12
  import { formatRouterStatus, ROUTER_USAGE_LINES, runRouterCommand, runTelemetryCommand } from "./cli-commands/router.ts";
9
13
  import { installService, renderSystemdUnit, runServiceCommand, SERVICE_USAGE_LINES, systemctl } from "./cli-commands/service-daemon.ts";
10
14
  import { runSessionCommand, SESSION_USAGE_LINES } from "./cli-commands/session.ts";
11
15
  import type { CliDependencies } from "./cli-commands/support.ts";
12
- import { connectJittorClient } from "./client.ts";
13
16
  import { serveMain } from "./daemon.ts";
17
+ import { connectJittorClient } from "./vehicle/client.ts";
14
18
 
15
19
  // Re-exported for external callers (tests, daemon.ts's systemd-unit test) that import these
16
20
  // directly from cli.ts rather than reaching into src/cli-commands/*.
17
21
  export type { CliDependencies };
18
- export { formatContextAssessment, formatCostByTask, formatMetricsQuery, formatRouterStatus, renderSystemdUnit };
22
+ export {
23
+ formatCacheEconomics,
24
+ formatCatalogQuery,
25
+ formatCatalogStatus,
26
+ formatContextAssessment,
27
+ formatContextDelta,
28
+ formatCostByTask,
29
+ formatExportStatus,
30
+ formatMetricsQuery,
31
+ formatRouterStatus,
32
+ formatUsageImportResult,
33
+ formatUsageImportStatus,
34
+ renderSystemdUnit,
35
+ };
19
36
 
20
37
  const DEFAULT_DEPENDENCIES: CliDependencies = {
21
38
  get client() {
@@ -34,8 +51,12 @@ function usage(stderr: (line: string) => void): number {
34
51
  "Usage: jittor <command> [options]",
35
52
  " serve",
36
53
  ...SERVICE_USAGE_LINES,
54
+ ...BACKFILL_USAGE_LINES,
55
+ ...EXPORT_USAGE_LINES,
37
56
  ...CONTEXT_USAGE_LINES,
38
57
  ...BENCHMARKS_USAGE_LINES,
58
+ ...CATALOG_USAGE_LINES,
59
+ ...CACHE_USAGE_LINES,
39
60
  ...METRICS_USAGE_LINES,
40
61
  ...ROUTER_USAGE_LINES,
41
62
  ...SESSION_USAGE_LINES,
@@ -47,29 +68,46 @@ function usage(stderr: (line: string) => void): number {
47
68
 
48
69
  /**
49
70
  * Composes one command dispatcher per capability module (metrics, router+telemetry+compaction,
50
- * session identity, benchmarks, context, service lifecycle, the raw op escape hatch) instead of
51
- * a single switch that used to combine every command's own argument parsing, validation, and
52
- * presentation in one place. Each module owns its own usage lines and command handler; this
53
- * function only routes the top-level command word and forwards `usage` for the shared "not
54
- * recognized" fallback.
71
+ * session identity, benchmarks, context, service lifecycle, the raw op escape hatch). Each module
72
+ * owns its own argument parsing, validation, presentation, and usage lines; this function's switch
73
+ * only routes the top-level command word and forwards `usage` for the shared fallback.
55
74
  */
56
75
  export async function runCli(args: string[], deps: CliDependencies = DEFAULT_DEPENDENCIES): Promise<number> {
57
76
  const [command, action, ...rest] = args;
58
77
  const fail = () => usage(deps.stderr);
59
- if (command === "serve") {
60
- await deps.serve();
61
- return 0;
78
+ switch (command) {
79
+ case "serve":
80
+ await deps.serve();
81
+ return 0;
82
+ case "session":
83
+ return runSessionCommand(action, rest, deps, fail);
84
+ case "backfill":
85
+ return runBackfillCommand(action, rest, deps, fail);
86
+ case "export":
87
+ return runExportCommand(action, rest, deps, fail);
88
+ case "metrics":
89
+ return runMetricsCommand(action, rest, deps, fail);
90
+ case "telemetry":
91
+ return runTelemetryCommand(action, rest, deps, fail);
92
+ case "compaction":
93
+ return runCompactionCommand(action, rest, deps, fail);
94
+ case "router":
95
+ return runRouterCommand(action, rest, deps, fail);
96
+ case "op":
97
+ return runOpCommand(action, rest, deps, fail);
98
+ case "benchmarks":
99
+ return runBenchmarksCommand(action, rest, deps, fail);
100
+ case "catalog":
101
+ return runCatalogCommand(action, rest, deps, fail);
102
+ case "cache":
103
+ return runCacheCommand(action, rest, deps, fail);
104
+ case "context":
105
+ return runContextCommand(action, rest, deps, fail);
106
+ case "service":
107
+ return runServiceCommand(action, rest, deps, fail);
108
+ default:
109
+ return fail();
62
110
  }
63
- if (command === "session") return runSessionCommand(action, rest, deps, fail);
64
- if (command === "metrics") return runMetricsCommand(action, rest, deps, fail);
65
- if (command === "telemetry") return runTelemetryCommand(action, rest, deps, fail);
66
- if (command === "compaction") return runCompactionCommand(action, rest, deps, fail);
67
- if (command === "router") return runRouterCommand(action, rest, deps, fail);
68
- if (command === "op") return runOpCommand(action, rest, deps, fail);
69
- if (command === "benchmarks") return runBenchmarksCommand(action, rest, deps, fail);
70
- if (command === "context") return runContextCommand(action, rest, deps, fail);
71
- if (command === "service") return runServiceCommand(action, rest, deps, fail);
72
- return fail();
73
111
  }
74
112
 
75
113
  export async function main(args: string[] = process.argv.slice(2)): Promise<void> {
@@ -1,4 +1,4 @@
1
- import type { MetricObservation } from "../domain/metric.ts";
1
+ import type { MetricObservation } from "../observability/metric.ts";
2
2
 
3
3
  export interface CodexWindow {
4
4
  usedPercent: number;
@@ -0,0 +1,53 @@
1
+ import type { BudgetWindow } from "../observability/budget.ts";
2
+ import type { TelemetryBatch, TelemetrySource } from "../observability/telemetry-source.ts";
3
+ import {
4
+ type CodexRateLimitSnapshot,
5
+ CodexSubscriptionTelemetryAdapter,
6
+ type CodexTransport,
7
+ type CodexWindow,
8
+ loadCodexFileCredentials,
9
+ } from "./telemetry.ts";
10
+
11
+ function budgetWindow(limit: CodexRateLimitSnapshot, name: "primary" | "secondary", window: CodexWindow | null): BudgetWindow | null {
12
+ if (!window || window.windowSeconds === null || window.resetsAt === null) return null;
13
+ return {
14
+ id: `${limit.limitId}:${name}@${limit.observedAt}`,
15
+ source: "codex-subscription",
16
+ scope: limit.limitId === "codex" ? `codex:${name}` : `${limit.limitId}:${name}`,
17
+ usedFraction: window.usedPercent / 100,
18
+ windowSeconds: window.windowSeconds,
19
+ resetsAt: window.resetsAt * 1_000,
20
+ observedAt: limit.observedAt,
21
+ freshness: "fresh",
22
+ confidence: 0.8,
23
+ };
24
+ }
25
+
26
+ function windowsFromLimit(limit: CodexRateLimitSnapshot): BudgetWindow[] {
27
+ return [budgetWindow(limit, "primary", limit.primary), budgetWindow(limit, "secondary", limit.secondary)].filter(
28
+ (window): window is BudgetWindow => window !== null,
29
+ );
30
+ }
31
+
32
+ export class CodexTelemetrySource implements TelemetrySource {
33
+ readonly id = "codex-subscription";
34
+ readonly provider = "openai-codex";
35
+ readonly required = true;
36
+
37
+ constructor(
38
+ private readonly authFile: string,
39
+ private readonly transport: CodexTransport = fetch,
40
+ private readonly clock: () => number = Date.now,
41
+ ) {}
42
+
43
+ async poll(): Promise<TelemetryBatch> {
44
+ const observedAt = this.clock();
45
+ const adapter = new CodexSubscriptionTelemetryAdapter(loadCodexFileCredentials(this.authFile), this.transport);
46
+ const snapshot = await adapter.readUsage(observedAt);
47
+ return {
48
+ observedAt,
49
+ metrics: snapshot.metrics,
50
+ windows: [snapshot.defaultLimit, ...snapshot.additionalLimits].flatMap(windowsFromLimit),
51
+ };
52
+ }
53
+ }
@@ -1,5 +1,5 @@
1
1
  import { readFileSync, statSync } from "node:fs";
2
- import { type CodexRateLimitSnapshot, type CodexUsageSnapshot, parseCodexRateLimitHeaders, parseCodexUsage } from "./codex-contracts.ts";
2
+ import { type CodexRateLimitSnapshot, type CodexUsageSnapshot, parseCodexRateLimitHeaders, parseCodexUsage } from "./contracts.ts";
3
3
 
4
4
  export {
5
5
  type CodexCredits,
@@ -11,7 +11,7 @@ export {
11
11
  parseCodexRateLimitHeaders,
12
12
  parseCodexUsage,
13
13
  rateLimitMetrics,
14
- } from "./codex-contracts.ts";
14
+ } from "./contracts.ts";
15
15
 
16
16
  const CHATGPT_BACKEND_BASE_URL = "https://chatgpt.com/backend-api";
17
17