@danypops/jittor 0.13.0 → 0.15.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 (59) hide show
  1. package/package.json +4 -3
  2. package/src/adapters/artificial-analysis-direct-source.ts +42 -11
  3. package/src/adapters/lmarena-hf-source.ts +37 -15
  4. package/src/adapters/metric-benchmark-store.ts +29 -18
  5. package/src/adapters/openrouter-benchmark-source.ts +75 -19
  6. package/src/adapters/openrouter-design-arena-source.ts +36 -19
  7. package/src/adapters/sqlite-metric-store.ts +48 -25
  8. package/src/adapters/sqlite-session-identity-store.ts +13 -7
  9. package/src/cli-commands/benchmarks.ts +87 -22
  10. package/src/cli-commands/compaction.ts +7 -2
  11. package/src/cli-commands/context.ts +10 -2
  12. package/src/cli-commands/metrics.ts +128 -31
  13. package/src/cli-commands/op.ts +6 -1
  14. package/src/cli-commands/route-args.ts +5 -1
  15. package/src/cli-commands/router.ts +61 -18
  16. package/src/cli-commands/service-daemon.ts +28 -12
  17. package/src/cli-commands/session.ts +15 -4
  18. package/src/cli-commands/support.ts +1 -1
  19. package/src/cli.ts +30 -23
  20. package/src/client.ts +1 -1
  21. package/src/constants.ts +6 -2
  22. package/src/daemon.ts +44 -24
  23. package/src/domain/benchmark.ts +72 -40
  24. package/src/domain/codex-recovery.ts +34 -25
  25. package/src/domain/context-hub.ts +44 -25
  26. package/src/domain/context-telemetry.ts +106 -35
  27. package/src/domain/metric.ts +11 -11
  28. package/src/domain/model-observation.ts +139 -55
  29. package/src/domain/model-ranking-service.ts +13 -3
  30. package/src/domain/model-ranking.ts +126 -60
  31. package/src/domain/task-cost.ts +52 -11
  32. package/src/domain/task-focus.ts +11 -8
  33. package/src/domain/usage.ts +2 -2
  34. package/src/index.ts +69 -69
  35. package/src/log.ts +7 -2
  36. package/src/operations/benchmark-operations.ts +1 -1
  37. package/src/operations/context-operations.ts +15 -6
  38. package/src/operations/metrics-operations.ts +63 -28
  39. package/src/operations/model-ranking-operations.ts +9 -2
  40. package/src/operations/router-operations.ts +8 -4
  41. package/src/operations/session-identity-operations.ts +1 -1
  42. package/src/operations/session-scope.ts +5 -3
  43. package/src/policy.ts +22 -17
  44. package/src/ports/benchmark-controller.ts +1 -5
  45. package/src/ports/metric-store.ts +1 -1
  46. package/src/providers/anthropic-contracts.ts +13 -3
  47. package/src/providers/codex-contracts.ts +60 -52
  48. package/src/providers/codex.ts +16 -19
  49. package/src/providers/google-vertex-budget-contracts.ts +24 -14
  50. package/src/providers/google-vertex-budget.ts +15 -13
  51. package/src/providers/google-vertex-contracts.ts +36 -24
  52. package/src/providers/openrouter-contracts.ts +49 -51
  53. package/src/providers/openrouter.ts +21 -15
  54. package/src/providers/telemetry-sources.ts +13 -10
  55. package/src/router.ts +92 -43
  56. package/src/service.ts +93 -32
  57. package/src/session-identity-service.ts +10 -2
  58. package/src/state.ts +4 -10
  59. package/src/vehicle-registration.ts +154 -0
@@ -1,6 +1,6 @@
1
1
  import { BENCHMARK_MAX_OBSERVATIONS_PER_SNAPSHOT, MAX_DYNAMIC_ROUTES, MODEL_AGGREGATE_MAX_ROWS } from "../constants.ts";
2
- import { normalizeModelIdentity, type BenchmarkObservation } from "./benchmark.ts";
3
- import { TASK_DOMAINS, TASK_TYPES, type ModelMetricAggregate, type ModelTaskDomain, type ModelTaskType } from "./model-observation.ts";
2
+ import { type BenchmarkObservation, normalizeModelIdentity } from "./benchmark.ts";
3
+ import { type ModelMetricAggregate, type ModelTaskDomain, type ModelTaskType, TASK_DOMAINS, TASK_TYPES } from "./model-observation.ts";
4
4
 
5
5
  export type ScopeAuthority = "exact-session" | "available-models";
6
6
  export type UtilityComponentName = "quality" | "cost" | "latency" | "context" | "reliability";
@@ -85,7 +85,8 @@ function finiteBound(value: number, name: string, minimum: number, maximum: numb
85
85
 
86
86
  function candidateIdentity(candidate: ModelCandidate): string {
87
87
  const identity = normalizeModelIdentity(candidate.provider, candidate.model);
88
- if (typeof candidate.thinking !== "string" || candidate.thinking.length === 0 || candidate.thinking.length > 160) throw new Error("candidate thinking level is invalid");
88
+ if (typeof candidate.thinking !== "string" || candidate.thinking.length === 0 || candidate.thinking.length > 160)
89
+ throw new Error("candidate thinking level is invalid");
89
90
  return `${identity.canonical}:${candidate.thinking}`;
90
91
  }
91
92
 
@@ -93,19 +94,48 @@ function average(values: number[]): number {
93
94
  return values.reduce((sum, value) => sum + value, 0) / values.length;
94
95
  }
95
96
 
96
- function externalValues(candidate: ModelCandidate, evidence: BenchmarkObservation[], dimensions: string[], now: number): { values: number[]; confidences: number[]; provenance: RankingProvenance[] } {
97
+ function externalValues(
98
+ candidate: ModelCandidate,
99
+ evidence: BenchmarkObservation[],
100
+ dimensions: string[],
101
+ now: number,
102
+ ): { values: number[]; confidences: number[]; provenance: RankingProvenance[] } {
97
103
  const identity = normalizeModelIdentity(candidate.provider, candidate.model);
98
- const matching = evidence.filter((item) => (item.model.canonical === identity.canonical || item.model.aliases.includes(identity.canonical)) && dimensions.includes(item.dimension));
104
+ const matching = evidence.filter(
105
+ (item) =>
106
+ (item.model.canonical === identity.canonical || item.model.aliases.includes(identity.canonical)) &&
107
+ dimensions.includes(item.dimension),
108
+ );
99
109
  return {
100
110
  values: matching.map((item) => item.value),
101
111
  confidences: matching.map((item) => item.provenance.confidence * (now <= item.provenance.freshUntil ? 1 : 0.25)),
102
- provenance: matching.map((item) => ({ sourceId: item.provenance.sourceId, publisher: item.provenance.publisher, url: item.provenance.url, revision: item.provenance.revision, freshness: now <= item.provenance.freshUntil ? "fresh" : "stale" })),
112
+ provenance: matching.map((item) => ({
113
+ sourceId: item.provenance.sourceId,
114
+ publisher: item.provenance.publisher,
115
+ url: item.provenance.url,
116
+ revision: item.provenance.revision,
117
+ freshness: now <= item.provenance.freshUntil ? "fresh" : "stale",
118
+ })),
103
119
  };
104
120
  }
105
121
 
106
- function localValues(candidate: ModelCandidate, domain: ModelTaskDomain, type: ModelTaskType, evidence: ModelMetricAggregate[], dimension: string): ModelMetricAggregate[] {
122
+ function localValues(
123
+ candidate: ModelCandidate,
124
+ domain: ModelTaskDomain,
125
+ type: ModelTaskType,
126
+ evidence: ModelMetricAggregate[],
127
+ dimension: string,
128
+ ): ModelMetricAggregate[] {
107
129
  const identity = normalizeModelIdentity(candidate.provider, candidate.model);
108
- return evidence.filter((item) => item.provider === identity.provider && item.model === identity.model && item.thinking === candidate.thinking && item.domain === domain && item.type === type && item.dimension === dimension);
130
+ return evidence.filter(
131
+ (item) =>
132
+ item.provider === identity.provider &&
133
+ item.model === identity.model &&
134
+ item.thinking === candidate.thinking &&
135
+ item.domain === domain &&
136
+ item.type === type &&
137
+ item.dimension === dimension,
138
+ );
109
139
  }
110
140
 
111
141
  /**
@@ -123,7 +153,10 @@ function qualityDimensions(domain: ModelTaskDomain, type: ModelTaskType): string
123
153
  return dimensions;
124
154
  }
125
155
 
126
- function rawComponents(candidate: ModelCandidate, input: ModelRankingInput): { components: Record<UtilityComponentName, RawComponent>; provenance: RankingProvenance[] } {
156
+ function rawComponents(
157
+ candidate: ModelCandidate,
158
+ input: ModelRankingInput,
159
+ ): { components: Record<UtilityComponentName, RawComponent>; provenance: RankingProvenance[] } {
127
160
  const quality = externalValues(candidate, input.externalEvidence, qualityDimensions(input.domain, input.type), input.now);
128
161
  const priceInput = externalValues(candidate, input.externalEvidence, ["price-input"], input.now);
129
162
  const priceOutput = externalValues(candidate, input.externalEvidence, ["price-output"], input.now);
@@ -139,23 +172,33 @@ function rawComponents(candidate: ModelCandidate, input: ModelRankingInput): { c
139
172
  const latencyValues = localLatency.length > 0 ? localLatency.map((item) => item.median) : latency.values;
140
173
  const latencyConfidences = localLatency.length > 0 ? localLatency.map((item) => item.confidence) : latency.confidences;
141
174
  const reliabilityValues = [...failures.map((item) => 1 - item.median), ...outcomes.map((item) => item.median)];
142
- const withEvidence = (values: number[], confidences: number[], lowerIsBetter: boolean, label: string): RawComponent => values.length === 0
143
- ? { value: null, confidence: 0, evidenceCount: 0, reason: `${label} evidence is missing`, lowerIsBetter }
144
- : {
145
- value: average(values),
146
- confidence: average(confidences) / (1 + ((Math.max(...values) - Math.min(...values)) / Math.max(Math.abs(average(values)), Number.EPSILON))),
147
- evidenceCount: values.length,
148
- reason: `${values.length} ${label} observation${values.length === 1 ? "" : "s"}`,
149
- lowerIsBetter,
150
- };
175
+ const withEvidence = (values: number[], confidences: number[], lowerIsBetter: boolean, label: string): RawComponent =>
176
+ values.length === 0
177
+ ? { value: null, confidence: 0, evidenceCount: 0, reason: `${label} evidence is missing`, lowerIsBetter }
178
+ : {
179
+ value: average(values),
180
+ confidence:
181
+ average(confidences) / (1 + (Math.max(...values) - Math.min(...values)) / Math.max(Math.abs(average(values)), Number.EPSILON)),
182
+ evidenceCount: values.length,
183
+ reason: `${values.length} ${label} observation${values.length === 1 ? "" : "s"}`,
184
+ lowerIsBetter,
185
+ };
151
186
  const components: Record<UtilityComponentName, RawComponent> = {
152
187
  quality: withEvidence(qualityValues, quality.confidences, false, "task quality"),
153
188
  cost: withEvidence(prices, [...priceInput.confidences, ...priceOutput.confidences], true, "price"),
154
189
  latency: withEvidence(latencyValues, latencyConfidences, true, "latency"),
155
190
  context: withEvidence(context.values, context.confidences, false, "context window"),
156
- reliability: withEvidence(reliabilityValues, [...failures, ...outcomes].map((item) => item.confidence), false, "local reliability"),
191
+ reliability: withEvidence(
192
+ reliabilityValues,
193
+ [...failures, ...outcomes].map((item) => item.confidence),
194
+ false,
195
+ "local reliability",
196
+ ),
197
+ };
198
+ return {
199
+ components,
200
+ provenance: [...quality.provenance, ...priceInput.provenance, ...priceOutput.provenance, ...latency.provenance, ...context.provenance],
157
201
  };
158
- return { components, provenance: [...quality.provenance, ...priceInput.provenance, ...priceOutput.provenance, ...latency.provenance, ...context.provenance] };
159
202
  }
160
203
 
161
204
  function normalizedScore(value: number, values: number[], lowerIsBetter: boolean): number {
@@ -167,55 +210,78 @@ function normalizedScore(value: number, values: number[], lowerIsBetter: boolean
167
210
  }
168
211
 
169
212
  export function rankModelCandidates(value: ModelRankingInput): ModelRankingResult {
170
- if (!Array.isArray(value.candidates) || value.candidates.length === 0 || value.candidates.length > MAX_DYNAMIC_ROUTES) throw new Error("candidate count is outside its supported range");
171
- if (!Array.isArray(value.externalEvidence) || value.externalEvidence.length > BENCHMARK_MAX_OBSERVATIONS_PER_SNAPSHOT * 4) throw new Error("external evidence exceeds the supported bound");
172
- if (!Array.isArray(value.localEvidence) || value.localEvidence.length > MODEL_AGGREGATE_MAX_ROWS) throw new Error("local evidence exceeds the supported bound");
173
- if (value.scopeAuthority !== "exact-session" && value.scopeAuthority !== "available-models") throw new Error("scope authority is invalid");
213
+ if (!Array.isArray(value.candidates) || value.candidates.length === 0 || value.candidates.length > MAX_DYNAMIC_ROUTES)
214
+ throw new Error("candidate count is outside its supported range");
215
+ if (!Array.isArray(value.externalEvidence) || value.externalEvidence.length > BENCHMARK_MAX_OBSERVATIONS_PER_SNAPSHOT * 4)
216
+ throw new Error("external evidence exceeds the supported bound");
217
+ if (!Array.isArray(value.localEvidence) || value.localEvidence.length > MODEL_AGGREGATE_MAX_ROWS)
218
+ throw new Error("local evidence exceeds the supported bound");
219
+ if (value.scopeAuthority !== "exact-session" && value.scopeAuthority !== "available-models")
220
+ throw new Error("scope authority is invalid");
174
221
  if (!TASK_DOMAINS.includes(value.domain)) throw new Error("task domain is invalid");
175
222
  if (!TASK_TYPES.includes(value.type)) throw new Error("task type is invalid");
176
223
  if (!Number.isSafeInteger(value.now) || value.now <= 0) throw new Error("ranking time is invalid");
177
224
  const budgetPressure = finiteBound(value.budgetPressure, "budget pressure", 0, 2);
178
- const weights = Object.fromEntries(COMPONENTS.map((name) => [name, finiteBound(value.weights[name], `${name} weight`, 0, 10)])) as unknown as UtilityWeights;
225
+ const weights = Object.fromEntries(
226
+ COMPONENTS.map((name) => [name, finiteBound(value.weights[name], `${name} weight`, 0, 10)]),
227
+ ) as unknown as UtilityWeights;
179
228
  const seen = new Set<string>();
180
- const candidates = value.candidates.map((candidate) => ({ ...candidate })).filter((candidate) => {
181
- const identity = candidateIdentity(candidate);
182
- if (seen.has(identity)) return false;
183
- seen.add(identity);
184
- return true;
185
- });
229
+ const candidates = value.candidates
230
+ .map((candidate) => ({ ...candidate }))
231
+ .filter((candidate) => {
232
+ const identity = candidateIdentity(candidate);
233
+ if (seen.has(identity)) return false;
234
+ seen.add(identity);
235
+ return true;
236
+ });
186
237
  const raw = candidates.map((candidate) => rawComponents(candidate, value));
187
238
  const effectiveWeights: UtilityWeights = { ...weights, cost: weights.cost * (1 + budgetPressure) };
188
- const ranked = candidates.map((candidate, index): RankedModel => {
189
- const source = raw[index]!;
190
- const components = COMPONENTS.map((name): UtilityComponent => {
191
- const component = source.components[name];
192
- const comparable = raw.map((item) => item.components[name].value).filter((item): item is number => item !== null);
239
+ const ranked = candidates
240
+ .map((candidate, index): RankedModel => {
241
+ const source = raw[index]!;
242
+ const components = COMPONENTS.map((name): UtilityComponent => {
243
+ const component = source.components[name];
244
+ const comparable = raw.map((item) => item.components[name].value).filter((item): item is number => item !== null);
245
+ return {
246
+ name,
247
+ score: component.value === null ? null : normalizedScore(component.value, comparable, component.lowerIsBetter),
248
+ confidence: component.confidence,
249
+ weight: effectiveWeights[name],
250
+ evidenceCount: component.evidenceCount,
251
+ reason: component.reason,
252
+ };
253
+ });
254
+ const known = components.filter(
255
+ (component): component is UtilityComponent & { score: number } => component.score !== null && component.weight > 0,
256
+ );
257
+ const knownWeight = known.reduce((sum, component) => sum + component.weight, 0);
258
+ const totalWeight = components.reduce((sum, component) => sum + component.weight, 0);
259
+ const utility =
260
+ knownWeight === 0 ? null : known.reduce((sum, component) => sum + component.score * component.weight, 0) / knownWeight;
261
+ const confidence =
262
+ totalWeight === 0 ? 0 : known.reduce((sum, component) => sum + component.confidence * component.weight, 0) / totalWeight;
263
+ const provenance = [
264
+ ...new Map(source.provenance.map((item) => [`${item.sourceId}:${item.revision}:${item.url}`, item])).values(),
265
+ ].sort((left, right) => left.sourceId.localeCompare(right.sourceId) || left.revision.localeCompare(right.revision));
193
266
  return {
194
- name,
195
- score: component.value === null ? null : normalizedScore(component.value, comparable, component.lowerIsBetter),
196
- confidence: component.confidence,
197
- weight: effectiveWeights[name],
198
- evidenceCount: component.evidenceCount,
199
- reason: component.reason,
267
+ candidate,
268
+ identity: candidateIdentity(candidate),
269
+ utility,
270
+ confidence,
271
+ components,
272
+ provenance,
273
+ trace: [
274
+ `domain ${value.domain}, type ${value.type}`,
275
+ `budget pressure ${budgetPressure.toFixed(3)} makes cost weight ${effectiveWeights.cost.toFixed(3)}`,
276
+ `${known.length}/${components.length} utility components have evidence`,
277
+ `scope authority ${value.scopeAuthority}`,
278
+ ],
200
279
  };
201
- });
202
- const known = components.filter((component): component is UtilityComponent & { score: number } => component.score !== null && component.weight > 0);
203
- const knownWeight = known.reduce((sum, component) => sum + component.weight, 0);
204
- const totalWeight = components.reduce((sum, component) => sum + component.weight, 0);
205
- const utility = knownWeight === 0 ? null : known.reduce((sum, component) => sum + (component.score * component.weight), 0) / knownWeight;
206
- const confidence = totalWeight === 0 ? 0 : known.reduce((sum, component) => sum + (component.confidence * component.weight), 0) / totalWeight;
207
- const provenance = [...new Map(source.provenance.map((item) => [`${item.sourceId}:${item.revision}:${item.url}`, item])).values()]
208
- .sort((left, right) => left.sourceId.localeCompare(right.sourceId) || left.revision.localeCompare(right.revision));
209
- return {
210
- candidate,
211
- identity: candidateIdentity(candidate),
212
- utility,
213
- confidence,
214
- components,
215
- provenance,
216
- trace: [`domain ${value.domain}, type ${value.type}`, `budget pressure ${budgetPressure.toFixed(3)} makes cost weight ${effectiveWeights.cost.toFixed(3)}`, `${known.length}/${components.length} utility components have evidence`, `scope authority ${value.scopeAuthority}`],
217
- };
218
- }).sort((left, right) => (right.utility ?? -1) - (left.utility ?? -1) || right.confidence - left.confidence || left.identity.localeCompare(right.identity));
280
+ })
281
+ .sort(
282
+ (left, right) =>
283
+ (right.utility ?? -1) - (left.utility ?? -1) || right.confidence - left.confidence || left.identity.localeCompare(right.identity),
284
+ );
219
285
  const knownComponents = ranked.reduce((sum, item) => sum + item.components.filter((component) => component.score !== null).length, 0);
220
286
  const possibleComponents = ranked.length * COMPONENTS.length;
221
287
  const completeness = knownComponents === 0 ? "insufficient-evidence" : knownComponents === possibleComponents ? "complete" : "partial";
@@ -44,7 +44,15 @@ function attributeText(attributes: Record<string, unknown>, key: string): string
44
44
  function entryFor(byTask: Map<string, TaskCostEntry>, taskId: string): TaskCostEntry {
45
45
  const existing = byTask.get(taskId);
46
46
  if (existing) return existing;
47
- const created: TaskCostEntry = { taskId, costUsd: 0, inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, byModel: [] };
47
+ const created: TaskCostEntry = {
48
+ taskId,
49
+ costUsd: 0,
50
+ inputTokens: 0,
51
+ outputTokens: 0,
52
+ cacheReadTokens: 0,
53
+ cacheWriteTokens: 0,
54
+ byModel: [],
55
+ };
48
56
  byTask.set(taskId, created);
49
57
  return created;
50
58
  }
@@ -53,7 +61,16 @@ function breakdownFor(byModel: Map<string, TaskCostBreakdown>, provider: string,
53
61
  const key = `${provider}\u0000${model}\u0000${thinking}`;
54
62
  const existing = byModel.get(key);
55
63
  if (existing) return existing;
56
- const created: TaskCostBreakdown = { provider, model, thinking, costUsd: 0, inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
64
+ const created: TaskCostBreakdown = {
65
+ provider,
66
+ model,
67
+ thinking,
68
+ costUsd: 0,
69
+ inputTokens: 0,
70
+ outputTokens: 0,
71
+ cacheReadTokens: 0,
72
+ cacheWriteTokens: 0,
73
+ };
57
74
  byModel.set(key, created);
58
75
  return created;
59
76
  }
@@ -80,25 +97,49 @@ export function buildTaskCostSummary(rows: StoredMetricObservation[], options: T
80
97
  for (const row of rows) {
81
98
  if (row.source !== "pi" || typeof row.value !== "number" || !Number.isFinite(row.value) || row.value < 0) continue;
82
99
  if (row.observedAt < options.since || row.observedAt > options.until) continue;
83
- const taskId = typeof row.attributes["taskId"] === "string" ? row.attributes["taskId"] : undefined;
100
+ const taskId = typeof row.attributes.taskId === "string" ? row.attributes.taskId : undefined;
84
101
  if (row.metric === "cost" && row.unit === "usd") {
85
- if (taskId === undefined) { unattributedCostUsd += row.value; continue; }
102
+ if (taskId === undefined) {
103
+ unattributedCostUsd += row.value;
104
+ continue;
105
+ }
86
106
  entryFor(byTask, taskId).costUsd += row.value;
87
107
  if (!byTaskModel.has(taskId)) byTaskModel.set(taskId, new Map());
88
- breakdownFor(byTaskModel.get(taskId)!, attributeText(row.attributes, "provider"), attributeText(row.attributes, "model"), attributeText(row.attributes, "thinking")).costUsd += row.value;
108
+ breakdownFor(
109
+ byTaskModel.get(taskId)!,
110
+ attributeText(row.attributes, "provider"),
111
+ attributeText(row.attributes, "model"),
112
+ attributeText(row.attributes, "thinking"),
113
+ ).costUsd += row.value;
89
114
  continue;
90
115
  }
91
116
  if (taskId === undefined || row.unit !== "tokens" || !TOKEN_METRICS.has(row.metric)) continue;
92
117
  const entry = entryFor(byTask, taskId);
93
118
  if (!byTaskModel.has(taskId)) byTaskModel.set(taskId, new Map());
94
- const breakdown = breakdownFor(byTaskModel.get(taskId)!, attributeText(row.attributes, "provider"), attributeText(row.attributes, "model"), attributeText(row.attributes, "thinking"));
95
- if (row.metric === "input-tokens") { entry.inputTokens += row.value; breakdown.inputTokens += row.value; }
96
- else if (row.metric === "output-tokens") { entry.outputTokens += row.value; breakdown.outputTokens += row.value; }
97
- else if (row.metric === "cache-read-tokens") { entry.cacheReadTokens += row.value; breakdown.cacheReadTokens += row.value; }
98
- else { entry.cacheWriteTokens += row.value; breakdown.cacheWriteTokens += row.value; }
119
+ const breakdown = breakdownFor(
120
+ byTaskModel.get(taskId)!,
121
+ attributeText(row.attributes, "provider"),
122
+ attributeText(row.attributes, "model"),
123
+ attributeText(row.attributes, "thinking"),
124
+ );
125
+ if (row.metric === "input-tokens") {
126
+ entry.inputTokens += row.value;
127
+ breakdown.inputTokens += row.value;
128
+ } else if (row.metric === "output-tokens") {
129
+ entry.outputTokens += row.value;
130
+ breakdown.outputTokens += row.value;
131
+ } else if (row.metric === "cache-read-tokens") {
132
+ entry.cacheReadTokens += row.value;
133
+ breakdown.cacheReadTokens += row.value;
134
+ } else {
135
+ entry.cacheWriteTokens += row.value;
136
+ breakdown.cacheWriteTokens += row.value;
137
+ }
99
138
  }
100
139
  for (const [taskId, entry] of byTask) {
101
- entry.byModel = [...(byTaskModel.get(taskId)?.values() ?? [])].sort((left, right) => right.costUsd - left.costUsd || left.model.localeCompare(right.model));
140
+ entry.byModel = [...(byTaskModel.get(taskId)?.values() ?? [])].sort(
141
+ (left, right) => right.costUsd - left.costUsd || left.model.localeCompare(right.model),
142
+ );
102
143
  }
103
144
  const entries = [...byTask.values()].sort((left, right) => right.costUsd - left.costUsd || left.taskId.localeCompare(right.taskId));
104
145
  return { since: options.since, until: options.until, entries, unattributedCostUsd, truncated: options.truncated === true };
@@ -16,12 +16,14 @@ const STATUSES = new Set<string>(["focused", "paused", "unpaused", "cleared"]);
16
16
  function record(value: unknown): Record<string, unknown> {
17
17
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("task-focus event must be an object");
18
18
  const result = value as Record<string, unknown>;
19
- for (const key of Object.keys(result)) if (!TOP_LEVEL_FIELDS.has(key)) throw new Error(`task-focus event contains unexpected field: ${key}`);
19
+ for (const key of Object.keys(result))
20
+ if (!TOP_LEVEL_FIELDS.has(key)) throw new Error(`task-focus event contains unexpected field: ${key}`);
20
21
  return result;
21
22
  }
22
23
 
23
24
  function boundedId(value: unknown, name: string): string {
24
- if (typeof value !== "string" || value.length === 0 || value.length > TASK_FOCUS_ID_MAX_LENGTH) throw new Error(`${name} must be a non-empty bounded string`);
25
+ if (typeof value !== "string" || value.length === 0 || value.length > TASK_FOCUS_ID_MAX_LENGTH)
26
+ throw new Error(`${name} must be a non-empty bounded string`);
25
27
  return value;
26
28
  }
27
29
 
@@ -34,16 +36,17 @@ function boundedId(value: unknown, name: string): string {
34
36
  */
35
37
  export function validateTaskFocusEvent(value: unknown, now = Date.now()): TaskFocusEvent {
36
38
  const input = record(value);
37
- if (input["schema"] !== PAPYRUS_TASK_FOCUS_SCHEMA) throw new Error("task-focus event schema is not supported");
38
- const status = input["status"];
39
+ if (input.schema !== PAPYRUS_TASK_FOCUS_SCHEMA) throw new Error("task-focus event schema is not supported");
40
+ const status = input.status;
39
41
  if (typeof status !== "string" || !STATUSES.has(status)) throw new Error("task-focus event status is not supported");
40
- const observedAt = input["observedAt"];
41
- if (typeof observedAt !== "number" || !Number.isSafeInteger(observedAt) || observedAt < 0) throw new Error("task-focus event observedAt must be a non-negative integer");
42
+ const observedAt = input.observedAt;
43
+ if (typeof observedAt !== "number" || !Number.isSafeInteger(observedAt) || observedAt < 0)
44
+ throw new Error("task-focus event observedAt must be a non-negative integer");
42
45
  if (Math.abs(now - observedAt) > TASK_FOCUS_EVENT_MAX_AGE_MS) throw new Error("task-focus event is stale");
43
- const rawTaskId = input["taskId"];
46
+ const rawTaskId = input.taskId;
44
47
  const taskId = rawTaskId === null ? null : boundedId(rawTaskId, "taskId");
45
48
  if (taskId === null && status !== "cleared") throw new Error(`task-focus event of status "${status}" requires a taskId`);
46
- const rawSessionId = input["sessionId"];
49
+ const rawSessionId = input.sessionId;
47
50
  const sessionId = rawSessionId === undefined ? undefined : boundedId(rawSessionId, "sessionId");
48
51
  return {
49
52
  schema: PAPYRUS_TASK_FOCUS_SCHEMA,
@@ -7,9 +7,9 @@ export const USAGE_PERIODS = [
7
7
  { id: "monthly", label: "Monthly", windowMs: 30 * MILLISECONDS_PER_DAY, bucketCount: 30 },
8
8
  { id: "quarterly", label: "Quarterly", windowMs: 90 * MILLISECONDS_PER_DAY, bucketCount: 90 },
9
9
  ] as const;
10
- export type UsagePeriod = typeof USAGE_PERIODS[number]["id"];
10
+ export type UsagePeriod = (typeof USAGE_PERIODS)[number]["id"];
11
11
 
12
- export function usagePeriod(period: UsagePeriod): typeof USAGE_PERIODS[number] {
12
+ export function usagePeriod(period: UsagePeriod): (typeof USAGE_PERIODS)[number] {
13
13
  return USAGE_PERIODS.find((candidate) => candidate.id === period)!;
14
14
  }
15
15
 
package/src/index.ts CHANGED
@@ -1,51 +1,44 @@
1
- export * from "./constants.ts";
2
1
  export {
2
+ connectJittorClient,
3
3
  type FetchTransport,
4
4
  JittorClient,
5
- connectJittorClient,
6
5
  } from "./client.ts";
6
+ export * from "./constants.ts";
7
7
  export {
8
- EXPECTED_OPERATION_NAMES,
9
- InvalidSessionSecretError,
10
- JittorService,
11
- UnknownOperationError,
12
- createApp,
13
- type JittorAppOptions,
14
- type OperationInputs,
15
- type OperationName,
16
- type OperationOutputs,
17
- } from "./service.ts";
18
- export {
19
- type CompactionDurationEstimate,
20
- type CompactionStart,
21
- CompactionTelemetry,
22
- type ContextAssessment,
23
- type PapyrusContextInjection,
24
- assessContextTelemetry,
25
- estimateCompactionDuration,
26
- papyrusContextMetric,
27
- validatePapyrusContextInjection,
28
- } from "./domain/context-telemetry.ts";
29
- export {
30
- type TaskFocusEvent,
31
- type TaskFocusStatus,
32
- applyTaskFocusEvent,
33
- validateTaskFocusEvent,
34
- } from "./domain/task-focus.ts";
8
+ type CodexFailure,
9
+ type CodexFailureKind,
10
+ type CodexFailureMetadata,
11
+ type CodexRecoveryAttempt,
12
+ type CodexRecoveryOptions,
13
+ type CodexRecoveryPlan,
14
+ CodexRecoveryPolicy,
15
+ classifyCodexFailure,
16
+ } from "./domain/codex-recovery.ts";
35
17
  export {
36
18
  type ContextConfidenceTier,
37
19
  type ContextContribution,
38
20
  type ContextSegment,
39
21
  type ContextSegmentItem,
22
+ computeToolSchemaLedger,
23
+ contextContributionMetric,
40
24
  type ToolLedgerEntry,
41
25
  type ToolLedgerSourceUsage,
42
26
  type ToolLedgerToolUsage,
43
- computeToolSchemaLedger,
44
- contextContributionMetric,
45
27
  toolLedgerSegment,
46
28
  validateContextContribution,
47
29
  validateContextSegment,
48
30
  } from "./domain/context-hub.ts";
31
+ export {
32
+ assessContextTelemetry,
33
+ type CompactionDurationEstimate,
34
+ type CompactionStart,
35
+ CompactionTelemetry,
36
+ type ContextAssessment,
37
+ estimateCompactionDuration,
38
+ type PapyrusContextInjection,
39
+ papyrusContextMetric,
40
+ validatePapyrusContextInjection,
41
+ } from "./domain/context-telemetry.ts";
49
42
  export {
50
43
  METRIC_UNITS,
51
44
  type MetricObservation,
@@ -55,8 +48,8 @@ export {
55
48
  validateMetricObservation,
56
49
  } from "./domain/metric.ts";
57
50
  export {
58
- TASK_DOMAINS,
59
- TASK_TYPES,
51
+ aggregateModelMetrics,
52
+ classifyTaskFromTools,
60
53
  type ExplicitOutcome,
61
54
  type ModelAggregateOptions,
62
55
  type ModelMetricAggregate,
@@ -64,9 +57,9 @@ export {
64
57
  type ModelTaskClassification,
65
58
  type ModelTaskDomain,
66
59
  type ModelTaskType,
67
- aggregateModelMetrics,
68
- classifyTaskFromTools,
69
60
  modelRunMetrics,
61
+ TASK_DOMAINS,
62
+ TASK_TYPES,
70
63
  validateModelRunObservation,
71
64
  } from "./domain/model-observation.ts";
72
65
  export {
@@ -75,17 +68,27 @@ export {
75
68
  type ModelRankingResult,
76
69
  type RankedModel,
77
70
  type RankingProvenance,
71
+ rankModelCandidates,
78
72
  type ScopeAuthority,
79
73
  type UtilityComponent,
80
74
  type UtilityComponentName,
81
75
  type UtilityWeights,
82
- rankModelCandidates,
83
76
  } from "./domain/model-ranking.ts";
84
77
  export {
85
- USAGE_PERIODS,
78
+ applyTaskFocusEvent,
79
+ type TaskFocusEvent,
80
+ type TaskFocusStatus,
81
+ validateTaskFocusEvent,
82
+ } from "./domain/task-focus.ts";
83
+ export {
84
+ buildCostGraph,
85
+ buildUsageGraph,
86
86
  type CostBucket,
87
87
  type CostGraph,
88
88
  type CostSeries,
89
+ identity,
90
+ resolveUsageWindow,
91
+ USAGE_PERIODS,
89
92
  type UsageAggregateRow,
90
93
  type UsageBreakdown,
91
94
  type UsageBucket,
@@ -94,43 +97,13 @@ export {
94
97
  type UsageGraphOptions,
95
98
  type UsagePeriod,
96
99
  type UsageSeries,
97
- buildCostGraph,
98
- buildUsageGraph,
99
- identity,
100
- resolveUsageWindow,
101
100
  usageBucketIndex,
102
101
  usagePeriod,
103
102
  usagePeriodStart,
104
103
  } from "./domain/usage.ts";
105
104
  export {
106
- CodexRecoveryPolicy,
107
- classifyCodexFailure,
108
- type CodexFailure,
109
- type CodexFailureKind,
110
- type CodexFailureMetadata,
111
- type CodexRecoveryAttempt,
112
- type CodexRecoveryOptions,
113
- type CodexRecoveryPlan,
114
- } from "./domain/codex-recovery.ts";
115
- export {
116
- hasAnthropicRateLimitHeaders,
117
- parseAnthropicRateLimitHeaders,
118
- type AnthropicMetricSource,
119
- type AnthropicRateLimitSnapshot,
120
- type AnthropicRateLimitWindow,
121
- } from "./providers/anthropic-contracts.ts";
122
- export { parseCodexRateLimitHeaders } from "./providers/codex.ts";
123
- export {
124
- classifyGoogleVertexFailure,
125
- googleVertexFailureMetrics,
126
- type GoogleVertexFailure,
127
- type GoogleVertexFailureKind,
128
- type GoogleVertexFailureMetadata,
129
- type GoogleVertexMetricSource,
130
- } from "./providers/google-vertex-contracts.ts";
131
- export {
132
- evaluateRoutingPolicy,
133
105
  type BudgetWindow,
106
+ evaluateRoutingPolicy,
134
107
  type PolicyAction,
135
108
  type PolicyConfig,
136
109
  type PolicyDecision,
@@ -140,6 +113,7 @@ export {
140
113
  type Route,
141
114
  type TelemetryFreshness,
142
115
  } from "./policy.ts";
116
+ export type { DistinctScopesFilter, MetricStore, UsageAggregateFilter } from "./ports/metric-store.ts";
143
117
  export type {
144
118
  RouteOverride,
145
119
  RouterController,
@@ -147,5 +121,31 @@ export type {
147
121
  TelemetryPollResult,
148
122
  TelemetrySourceStatus,
149
123
  } from "./ports/router-controller.ts";
150
- export type { DistinctScopesFilter, MetricStore, UsageAggregateFilter } from "./ports/metric-store.ts";
124
+ export {
125
+ type AnthropicMetricSource,
126
+ type AnthropicRateLimitSnapshot,
127
+ type AnthropicRateLimitWindow,
128
+ hasAnthropicRateLimitHeaders,
129
+ parseAnthropicRateLimitHeaders,
130
+ } from "./providers/anthropic-contracts.ts";
131
+ export { parseCodexRateLimitHeaders } from "./providers/codex.ts";
132
+ export {
133
+ classifyGoogleVertexFailure,
134
+ type GoogleVertexFailure,
135
+ type GoogleVertexFailureKind,
136
+ type GoogleVertexFailureMetadata,
137
+ type GoogleVertexMetricSource,
138
+ googleVertexFailureMetrics,
139
+ } from "./providers/google-vertex-contracts.ts";
140
+ export {
141
+ createApp,
142
+ EXPECTED_OPERATION_NAMES,
143
+ InvalidSessionSecretError,
144
+ type JittorAppOptions,
145
+ JittorService,
146
+ type OperationInputs,
147
+ type OperationName,
148
+ type OperationOutputs,
149
+ UnknownOperationError,
150
+ } from "./service.ts";
151
151
  export { VERSION as jittorVersion } from "./version.ts";
package/src/log.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * four daemons. `component`/`level`/`timestamp` and credential-safety (callers still must pass
9
9
  * only bounded, non-sensitive fields) are unchanged.
10
10
  */
11
- import { createLogger, type LogLevel as VehicleLogLevel, type Logger } from "@danypops/vehicle-server/logging";
11
+ import { createLogger, type Logger, type LogLevel as VehicleLogLevel } from "@danypops/vehicle-server/logging";
12
12
 
13
13
  export type LogLevel = Extract<VehicleLogLevel, "info" | "warn" | "error">;
14
14
 
@@ -19,7 +19,12 @@ export type LogLevel = Extract<VehicleLogLevel, "info" | "warn" | "error">;
19
19
  * `console.error` entirely) so existing tooling/tests that intercept `console.error` keep working.
20
20
  */
21
21
  export const logger: Logger = createLogger("jittor-daemon", {
22
- destination: { write: (chunk: string) => { console.error(chunk.replace(/\n$/, "")); return true; } },
22
+ destination: {
23
+ write: (chunk: string) => {
24
+ console.error(chunk.replace(/\n$/, ""));
25
+ return true;
26
+ },
27
+ },
23
28
  });
24
29
 
25
30
  /** Credential-safe structured daemon event. Callers must pass bounded, non-sensitive fields. */
@@ -5,7 +5,7 @@ import type { OperationHandlerMap } from "./types.ts";
5
5
  /** benchmark.* -- every operation whose only collaborator is the benchmark-controller port. */
6
6
  export function benchmarkOperations(benchmarks: BenchmarkController): OperationHandlerMap {
7
7
  return {
8
- "benchmark.refresh": (input) => benchmarks.refresh(input["force"] === true),
8
+ "benchmark.refresh": (input) => benchmarks.refresh(input.force === true),
9
9
  "benchmark.status": () => benchmarks.status(),
10
10
  "benchmark.query": (input) => benchmarks.query(input as unknown as BenchmarkQuery),
11
11
  };