@cat-factory/app 0.286.2 → 0.286.4

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.
@@ -18,7 +18,17 @@ import {
18
18
  // on the step surfaces (step detail, pipeline timeline). A no-op when there are no
19
19
  // recorded calls. Clicking anywhere emits `inspect` so a parent can open the
20
20
  // drill-down panel.
21
- const props = defineProps<{ metrics: StepMetrics; clickable?: boolean }>()
21
+ const props = defineProps<{
22
+ metrics: StepMetrics
23
+ /**
24
+ * How the step's tokens were billed, off `PipelineStep.usageBilling`. It is what makes the
25
+ * amount below readable: both billing kinds are priced identically here, so a subscription
26
+ * step's list price is indistinguishable from money actually spent unless it says so.
27
+ * Absent for a step that recorded no usage, which is also a step with no amount to qualify.
28
+ */
29
+ billing?: 'metered' | 'subscription'
30
+ clickable?: boolean
31
+ }>()
22
32
  defineEmits<{ inspect: [] }>()
23
33
 
24
34
  const { t } = useI18n()
@@ -38,6 +48,7 @@ const hasCache = computed(() => cacheRead.value > 0 || cacheWrite.value > 0)
38
48
  // no rate for the model that ran — the figure is then OMITTED rather than shown as 0.00, which
39
49
  // would claim the step was free.
40
50
  const cost = computed(() => formatCost(m.value.costEstimate, m.value.costCurrency))
51
+ const onSubscription = computed(() => props.billing === 'subscription')
41
52
  const headroom = computed(() => headroomRatio(m.value))
42
53
  const transport = computed(() => transportRatio(m.value))
43
54
  const headroomTone = computed(() => headroomColor(headroom.value, m.value.truncatedCalls > 0))
@@ -68,8 +79,23 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
68
79
  </span>
69
80
  <template v-if="cost">
70
81
  <span class="text-slate-500">·</span>
71
- <span class="tabular-nums text-slate-300" :title="t('observability.metricsBar.costHint')">
72
- {{ cost }}
82
+ <span
83
+ class="tabular-nums"
84
+ :class="onSubscription ? 'text-slate-500' : 'text-slate-300'"
85
+ :title="
86
+ onSubscription
87
+ ? t('observability.metricsBar.subscriptionCostHint')
88
+ : t('observability.metricsBar.costHint')
89
+ "
90
+ >
91
+ {{ onSubscription ? `~${cost}` : cost }}
92
+ </span>
93
+ <span
94
+ v-if="onSubscription"
95
+ class="text-[10px] uppercase tracking-wide text-slate-500"
96
+ :title="t('observability.metricsBar.subscriptionCostHint')"
97
+ >
98
+ {{ t('observability.metricsBar.subscription') }}
73
99
  </span>
74
100
  </template>
75
101
  <div class="ms-auto flex items-center gap-1">
@@ -13,6 +13,8 @@ import StepMetricsBar from '~/components/observability/StepMetricsBar.vue'
13
13
  // nothing only when there's neither a run to inspect nor any recorded calls.
14
14
  const props = defineProps<{
15
15
  metrics?: StepMetrics | null
16
+ /** How the step's tokens were billed, so the rollup's amount is not read as spend. */
17
+ billing?: 'metered' | 'subscription'
16
18
  /** The run whose per-call panel the header link / bar click opens. */
17
19
  instanceId?: string
18
20
  }>()
@@ -43,6 +45,7 @@ function openObservability() {
43
45
  <StepMetricsBar
44
46
  v-if="hasCalls && metrics"
45
47
  :metrics="metrics"
48
+ :billing="billing"
46
49
  clickable
47
50
  @inspect="openObservability"
48
51
  />
@@ -299,7 +299,12 @@ async function copyRunId() {
299
299
  <!-- LLM observability rollup (tokens, output-limit headroom,
300
300
  transport-vs-execution); click to open the full per-call panel. Self-gates: the
301
301
  "View all calls →" link shows for any run, the metrics bar only when calls exist. -->
302
- <StepModelActivity class="mt-4" :metrics="step.metrics" :instance-id="instanceId" />
302
+ <StepModelActivity
303
+ class="mt-4"
304
+ :metrics="step.metrics"
305
+ :billing="step.usageBilling"
306
+ :instance-id="instanceId"
307
+ />
303
308
 
304
309
  <!-- standards (prompt fragments) folded into this step -->
305
310
  <div v-if="step.selectedFragmentIds && step.selectedFragmentIds.length" class="mt-4">
@@ -145,6 +145,10 @@ async function copyRunId() {
145
145
  run's observability panel even when this step recorded no calls (e.g. a gate that
146
146
  passed its precheck with no helper spun up), so every window reaches it the same
147
147
  way; the metrics bar shows only when the step itself made calls. -->
148
- <StepModelActivity :metrics="step.metrics" :instance-id="instanceId" />
148
+ <StepModelActivity
149
+ :metrics="step.metrics"
150
+ :billing="step.usageBilling"
151
+ :instance-id="instanceId"
152
+ />
149
153
  </div>
150
154
  </template>
@@ -549,6 +549,7 @@ const ITEM_ICON: Record<string, string> = {
549
549
  <StepMetricsBar
550
550
  v-if="s.metrics && s.metrics.calls > 0"
551
551
  :metrics="s.metrics"
552
+ :billing="s.usageBilling"
552
553
  clickable
553
554
  class="mt-2"
554
555
  @inspect="ui.openObservability(instance.id)"
@@ -3812,6 +3812,8 @@
3812
3812
  "calls": "{count} Aufruf | {count} Aufrufe",
3813
3813
  "inputCompletionTokens": "Eingabe- / Ausgabe-Tokens insgesamt. Die Eingabe zählt auch gecachte Tokens mit: Sie belegen weiterhin das Kontextfenster, genau wie es die Kontextanzeige von Claude Code zählt.",
3814
3814
  "costHint": "Geschätzte Kosten der Token dieses Schritts zu Listenpreisen, jede Eingabeklasse mit ihrem eigenen Satz. Ein Abonnementlauf zahlt nichts pro Token; dies ist also der Betrag, den dieselben Token nach Verbrauch gekostet hätten.",
3815
+ "subscription": "Abonnement",
3816
+ "subscriptionCostHint": "Dieser Schritt lief über ein Pauschalabonnement und kostete daher kein Geld pro Token. Der Betrag ist das, was dieselben Token über die verbrauchsabhängige API gekostet hätten, und er zählt nicht zum Ausgabenbudget.",
3815
3817
  "fresh": "{tokens} frisch",
3816
3818
  "freshHint": "Eingabe, die von Grund auf verarbeitet wurde, ohne Anteil aus dem Cache",
3817
3819
  "cacheRead": "{tokens} aus dem Cache gelesen",
@@ -1863,6 +1863,8 @@
1863
1863
  "calls": "{count} call | {count} calls",
1864
1864
  "inputCompletionTokens": "Total input / completion tokens. Input counts cached tokens too: they still occupy the context window, exactly as Claude Code's own context gauge counts them.",
1865
1865
  "costHint": "Estimated cost of this step's tokens at list rates, each input class priced at its own. A subscription run pays nothing per token, so this is what the same tokens would have cost metered.",
1866
+ "subscription": "subscription",
1867
+ "subscriptionCostHint": "This step ran on a flat-rate subscription, so it cost no money per token. The figure is what the same tokens would have cost on the metered API, and it is excluded from the spend budget.",
1866
1868
  "fresh": "{tokens} fresh",
1867
1869
  "freshHint": "Input processed from scratch, with nothing served from the cache",
1868
1870
  "cacheRead": "{tokens} cache read",
@@ -1759,6 +1759,8 @@
1759
1759
  "calls": "{count} llamada | {count} llamadas",
1760
1760
  "inputCompletionTokens": "Tokens totales de entrada / salida. La entrada tambien cuenta los tokens en caché: siguen ocupando la ventana de contexto, igual que los cuenta el medidor de contexto de Claude Code.",
1761
1761
  "costHint": "Coste estimado de los tokens de este paso a precios de lista, cada clase de entrada con su propia tarifa. Una ejecución por suscripción no paga nada por token, así que esto es lo que habrían costado los mismos tokens con pago por uso.",
1762
+ "subscription": "suscripción",
1763
+ "subscriptionCostHint": "Este paso se ejecutó con una suscripción de tarifa plana, así que no costó dinero por token. La cifra es lo que habrían costado los mismos tokens en la API de pago por uso, y queda excluida del presupuesto de gasto.",
1762
1764
  "fresh": "{tokens} frescos",
1763
1765
  "freshHint": "Entrada procesada desde cero, sin nada servido desde la caché",
1764
1766
  "cacheRead": "{tokens} leídos de caché",
@@ -1759,6 +1759,8 @@
1759
1759
  "calls": "{count} appel | {count} appels",
1760
1760
  "inputCompletionTokens": "Total des tokens d'entrée / de sortie. L'entree compte aussi les tokens en cache : ils occupent toujours la fenêtre de contexte, exactement comme les compte la jauge de contexte de Claude Code.",
1761
1761
  "costHint": "Coût estimé des tokens de cette étape aux tarifs publics, chaque classe d'entrée à son propre taux. Une exécution sur abonnement ne paie rien au token ; ceci est donc ce que les mêmes tokens auraient coûté à l'usage.",
1762
+ "subscription": "abonnement",
1763
+ "subscriptionCostHint": "Cette étape s'est exécutée sur un abonnement forfaitaire et n'a donc rien coûté au token. Le montant correspond à ce que les mêmes tokens auraient coûté via l'API facturée à l'usage, et il est exclu du budget de dépenses.",
1762
1764
  "fresh": "{tokens} frais",
1763
1765
  "freshHint": "Entrée traitée de zero, sans rien servi depuis le cache",
1764
1766
  "cacheRead": "{tokens} lus depuis le cache",
@@ -1759,6 +1759,8 @@
1759
1759
  "calls": "{count} קריאה | שתי קריאות | {count} קריאות",
1760
1760
  "inputCompletionTokens": "סך טוקני הקלט / הפלט. הקלט סופר גם טוקנים מהמטמון: הם עדיין תופסים את חלון ההקשר, בדיוק כפי שמד ההקשר של Claude Code סופר אותם.",
1761
1761
  "costHint": "עלות משוערת של הטוקנים בצעד זה לפי מחירון, כל סוג קלט בתעריף שלו. הרצה במסגרת מנוי אינה משלמת לפי טוקן, ולכן זהו הסכום שאותם טוקנים היו עולים בתשלום לפי שימוש.",
1762
+ "subscription": "מנוי",
1763
+ "subscriptionCostHint": "הצעד הזה רץ במסגרת מנוי בתעריף אחיד, ולכן לא עלה כסף לפי טוקן. הסכום הוא מה שאותם טוקנים היו עולים ב-API בתשלום לפי שימוש, והוא אינו נכלל בתקציב ההוצאות.",
1762
1764
  "fresh": "{tokens} חדשים",
1763
1765
  "freshHint": "קלט שעובד מאפס, ללא שום חלק שהוגש מהמטמון",
1764
1766
  "cacheRead": "{tokens} נקראו מהמטמון",
@@ -3812,6 +3812,8 @@
3812
3812
  "calls": "{count} chiamata | {count} chiamate",
3813
3813
  "inputCompletionTokens": "Token totali di input / output. L'input conta anche i token in cache: occupano comunque la finestra di contesto, esattamente come li conta l'indicatore di contesto di Claude Code.",
3814
3814
  "costHint": "Costo stimato dei token di questo passo ai prezzi di listino, ogni classe di input alla propria tariffa. Un'esecuzione in abbonamento non paga nulla per token, quindi questo è quanto sarebbero costati gli stessi token a consumo.",
3815
+ "subscription": "abbonamento",
3816
+ "subscriptionCostHint": "Questo passo è stato eseguito con un abbonamento a tariffa fissa, quindi non è costato denaro per token. La cifra è quanto sarebbero costati gli stessi token sull'API a consumo ed è esclusa dal budget di spesa.",
3815
3817
  "fresh": "{tokens} freschi",
3816
3818
  "freshHint": "Input elaborato da zero, senza nulla servito dalla cache",
3817
3819
  "cacheRead": "{tokens} letti dalla cache",
@@ -1759,6 +1759,8 @@
1759
1759
  "calls": "{count} 件の呼び出し | {count} 件の呼び出し",
1760
1760
  "inputCompletionTokens": "入力 / 出力トークンの合計。入力にはキャッシュされたトークンも含まれます。それらも依然としてコンテキストウィンドウを占有するため、Claude Code のコンテキスト表示と同じ数え方です。",
1761
1761
  "costHint": "このステップのトークンの定価ベースの推定コストで、入力の種類ごとに個別の単価を適用しています。サブスクリプション実行はトークン単位の課金がないため、これは同じトークンを従量課金で使った場合の金額です。",
1762
+ "subscription": "サブスクリプション",
1763
+ "subscriptionCostHint": "このステップは定額のサブスクリプションで実行されたため、トークン単位の費用は発生していません。表示額は同じトークンを従量課金の API で使った場合の金額であり、支出予算には含まれません。",
1762
1764
  "fresh": "{tokens} 新規",
1763
1765
  "freshHint": "キャッシュから提供された分を含まない、ゼロから処理された入力",
1764
1766
  "cacheRead": "{tokens} キャッシュ読み取り",
@@ -1759,6 +1759,8 @@
1759
1759
  "calls": "{count} wywołanie | {count} wywołania | {count} wywołań",
1760
1760
  "inputCompletionTokens": "Łączna liczba tokenów wejścia / wyjscia. Wejście liczy takze tokeny z pamięci podręcznej: nadal zajmują okno kontekstu, dokładnie tak, jak liczy je wskaźnik kontekstu w Claude Code.",
1761
1761
  "costHint": "Szacowany koszt tokenów tego kroku według cennika, każda klasa wejścia po własnej stawce. Uruchomienie w ramach subskrypcji nie płaci za tokeny, więc jest to kwota, jaką te same tokeny kosztowałyby w rozliczeniu za użycie.",
1762
+ "subscription": "subskrypcja",
1763
+ "subscriptionCostHint": "Ten krok wykonał się w ramach subskrypcji o stałej opłacie, więc nie kosztował nic za tokeny. Kwota to tyle, ile te same tokeny kosztowałyby w API rozliczanym za użycie, i nie wlicza się do budżetu wydatków.",
1762
1764
  "fresh": "{tokens} świeżych",
1763
1765
  "freshHint": "Wejście przetworzone od zera, bez żadnej części obsłużonej z pamięci podręcznej",
1764
1766
  "cacheRead": "{tokens} odczytane z pamięci podręcznej",
@@ -1759,6 +1759,8 @@
1759
1759
  "calls": "{count} çağrı | {count} çağrı",
1760
1760
  "inputCompletionTokens": "Toplam giriş / çıkış token'i. Giriş, önbelleğe alınmış token'ları da sayar: bunlar hâlâ bağlam penceresini kaplar, tıpkı Claude Code'un kendi bağlam göstergesinin saydığı gibi.",
1761
1761
  "costHint": "Bu adımın tokenlarının liste fiyatlarına göre, her girdi sınıfı kendi tarifesiyle hesaplanan tahmini maliyeti. Abonelikle yapılan bir çalıştırma token başına ücret ödemez; bu, aynı tokenların kullandıkça öde ile kaça mal olacağıdır.",
1762
+ "subscription": "abonelik",
1763
+ "subscriptionCostHint": "Bu adım sabit ücretli bir abonelik üzerinde çalıştı, dolayısıyla token başına para harcamadı. Gösterilen tutar, aynı tokenların kullandıkça öde API üzerinde kaça mal olacağıdır ve harcama bütçesine dahil edilmez.",
1762
1764
  "fresh": "{tokens} yeni",
1763
1765
  "freshHint": "Önbellekten hiçbir şey sunulmadan sıfırdan işlenen giriş",
1764
1766
  "cacheRead": "{tokens} önbellekten okundu",
@@ -1759,6 +1759,8 @@
1759
1759
  "calls": "{count} виклик | {count} виклики | {count} викликів",
1760
1760
  "inputCompletionTokens": "Загальна кількість токенів входу / виходу. Вхід враховує й токени з кешу: вони так само займають вікно контексту, точно як їх рахує індикатор контексту в Claude Code.",
1761
1761
  "costHint": "Орієнтовна вартість токенів цього кроку за прейскурантом, кожен клас вхідних токенів за власним тарифом. Запуск за підпискою не оплачується потокенно, тож це сума, яку ті самі токени коштували б за фактичне використання.",
1762
+ "subscription": "підписка",
1763
+ "subscriptionCostHint": "Цей крок виконувався за підпискою з фіксованою оплатою, тож не коштував грошей за токени. Сума показує, скільки ті самі токени коштували б в API з оплатою за використання, і вона не входить до бюджету витрат.",
1762
1764
  "fresh": "{tokens} нових",
1763
1765
  "freshHint": "Вхід, оброблений з нуля, без жодної частини з кешу",
1764
1766
  "cacheRead": "{tokens} прочитано з кешу",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.286.2",
3
+ "version": "0.286.4",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,7 +18,7 @@
18
18
  "access": "public"
19
19
  },
20
20
  "dependencies": {
21
- "@cat-factory/contracts": "0.331.0",
21
+ "@cat-factory/contracts": "0.333.0",
22
22
  "@modular-frontend/core": "0.6.0",
23
23
  "@modular-vue/core": "^1.5.0",
24
24
  "@modular-vue/journeys": "^1.4.0",