@zaip-ai/cli 1.0.8 → 1.3.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 (212) hide show
  1. package/README.md +1 -1
  2. package/dist/services/adapters.d.ts +1 -1
  3. package/dist/services/adapters.js +1 -1
  4. package/dist/services/agent-adapters.js +2 -2
  5. package/dist/services/agent-adapters.js.map +1 -1
  6. package/dist/services/agent-adapters.test.js +5 -0
  7. package/dist/services/agent-adapters.test.js.map +1 -1
  8. package/dist/services/logger.test.js +2 -2
  9. package/dist/services/runtime-template.test.js +6 -6
  10. package/dist/services/template-manifest.d.ts.map +1 -1
  11. package/dist/services/template-manifest.js +5 -0
  12. package/dist/services/template-manifest.js.map +1 -1
  13. package/package.json +1 -1
  14. package/templates/.agents/architecture/software-architecture.md +131 -0
  15. package/templates/.agents/branding/brandbook.docx +0 -0
  16. package/templates/.agents/branding/brandbook.md +60 -0
  17. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -1
  18. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -1
  19. package/templates/.agents/dashboard/.tmp-run-list.json +254 -0
  20. package/templates/.agents/dashboard/.zaip-managed.json +252 -136
  21. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-Z60df2r-.js → CostCalculationGuidePage-DxR_pgSV.js} +1 -1
  22. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-4jZLTWE_.js +2156 -0
  23. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Coc6pA-1.js → PricingSettingsDialog-CKcsqb-r.js} +1 -1
  24. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BomxqCBU.css +1 -0
  25. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-DmmJD2Th.js +3 -0
  26. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BwtitWa_.js +1 -0
  27. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-N5Csr0RP.js +68 -0
  28. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DFBuc_qp.js → icons-vendor-C0fj2uU9.js} +1 -1
  29. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4aIB1PV.js +2 -0
  30. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CCQOHdVI.js → react-vendor-BEsJ-FYH.js} +1 -1
  31. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-pC2_0J8x.js → traceability-B6y6Gw12.js} +1 -1
  32. package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
  33. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  34. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +204 -32
  35. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +11 -11
  36. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +14 -7
  37. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +4 -2
  38. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +3 -1
  39. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +14 -11
  40. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +19 -4
  41. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +24 -2
  42. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +22 -1
  43. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +3 -1
  44. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +36 -26
  45. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +2 -2
  46. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +40 -6
  47. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +39 -1
  48. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +89 -23
  49. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +219 -29
  50. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +61 -7
  51. package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +3 -6
  52. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +2 -2
  53. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +3 -4
  54. package/templates/.agents/dashboard/apps/frontend/vite.config.ts +4 -1
  55. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  56. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +89 -19
  57. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +31 -16
  58. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +43 -14
  59. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +5 -5
  60. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +1 -1
  61. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +67 -42
  62. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +115 -39
  63. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +188 -38
  64. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +75 -17
  65. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +147 -58
  66. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +5 -2
  67. package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +2 -2
  68. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +2 -1
  69. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +18 -7
  70. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +95 -9
  71. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +29 -17
  72. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +0 -24
  73. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +225 -424
  74. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +24 -15
  75. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +6 -1
  76. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-monitor-projection-agents.test.ts +31 -0
  77. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-summary-projection-duration.test.ts +414 -0
  78. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  79. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +26 -23
  80. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +31 -11
  81. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +3 -1
  82. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +51 -21
  83. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +47 -5
  84. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +1 -4
  85. package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +32 -10
  86. package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +9 -3
  87. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +13 -5
  88. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +12 -4
  89. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +1 -4
  90. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +1 -2
  91. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +385 -4
  92. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +481 -61
  93. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +14 -1
  94. package/templates/.agents/dashboard/modules/operations/src/react/export/xlsx-runtime-e2e.test.ts +248 -0
  95. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +4 -4
  96. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +6 -4
  97. package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +4 -1
  98. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +1 -1
  99. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +1 -1
  100. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +46 -6
  101. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +1 -4
  102. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +82 -6
  103. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +2 -1
  104. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +1 -1
  105. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +19 -7
  106. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +4 -1
  107. package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +11 -5
  108. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  109. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  110. package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
  111. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  112. package/templates/.agents/dashboard/packages/contracts/src/index.ts +1 -0
  113. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  114. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +152 -149
  115. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs.metafile.json +7333 -0
  116. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +149 -146
  117. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  118. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +15 -7
  119. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +44 -13
  120. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +5 -2
  121. package/templates/.agents/dashboard/packages/local-runtime/scripts/source-size-runtime-scripts/sqlite-read-model-fixture.mjs +397 -0
  122. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +472 -145
  123. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +15 -3
  124. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +129 -31
  125. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +153 -150
  126. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +6 -2
  127. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +3 -3
  128. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +55 -16
  129. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +23 -13
  130. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +19 -4
  131. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +7 -3
  132. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +132 -9
  133. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +126 -60
  134. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +16 -2
  135. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +1861 -350
  136. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1218 -352
  137. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +119 -42
  138. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +45 -20
  139. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  140. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  141. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +7 -5
  142. package/templates/.agents/design/.zaip-managed.json +3 -3
  143. package/templates/.agents/design/apps/catalog/package.json +1 -1
  144. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  145. package/templates/.agents/growth/estrategia-bootstrap-90-dias.md +169 -0
  146. package/templates/.agents/growth/strategy.md +27 -0
  147. package/templates/.agents/marketing/estrategia-marketing-zaip-90-dias.md +197 -0
  148. package/templates/.agents/marketing/strategy.md +29 -0
  149. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  150. package/templates/.agents/requirements/comparative-audit.md +1 -1
  151. package/templates/.agents/requirements/context-engine.md +1 -1
  152. package/templates/.agents/requirements/cost-observability.md +1 -1
  153. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  154. package/templates/.agents/requirements/data-export.md +1 -1
  155. package/templates/.agents/requirements/design-system.md +1 -1
  156. package/templates/.agents/requirements/execution-engine.md +1 -1
  157. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  158. package/templates/.agents/requirements/model-orchestration.md +1 -1
  159. package/templates/.agents/requirements/public-distribution.md +1 -1
  160. package/templates/.agents/requirements/software-architecture.md +1 -1
  161. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  162. package/templates/.agents/requirements/work-lifecycle.md +1 -1
  163. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  164. package/templates/.agents/runtime/VERSION +1 -1
  165. package/templates/.agents/runtime/bin/zaip.mjs +30 -29
  166. package/templates/.agents/runtime/checksums.sha256 +6 -6
  167. package/templates/.agents/runtime/manifest.json +1 -1
  168. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
  169. package/templates/.agents/runtime/provenance.json +5 -5
  170. package/templates/.agents/runtime/sbom.cdx.json +3 -3
  171. package/templates/.agents/sales/playbook.md +32 -0
  172. package/templates/.agents/sales/roteiro-comercial-zaip.md +252 -0
  173. package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
  174. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +9 -2
  175. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +39 -0
  176. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +1 -1
  177. package/templates/.agents/skills/zaip-skill-enforce-architecture/SKILL.md +2 -0
  178. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +6 -0
  179. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +6 -0
  180. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +39 -82
  181. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +13 -8
  182. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +44 -14
  183. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +19 -9
  184. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +29 -5
  185. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +77 -0
  186. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +6 -0
  187. package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +28 -5
  188. package/templates/.agents/zaip-aios/INDEX.md +10 -0
  189. package/templates/.agents/zaip-aios/README.md +2 -1
  190. package/templates/.agents/zaip-aios/VERSION +1 -1
  191. package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +76 -0
  192. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +72 -0
  193. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +330 -0
  194. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +52 -0
  195. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +69 -0
  196. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +483 -0
  197. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +85 -0
  198. package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +18 -0
  199. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +44 -0
  200. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +167 -0
  201. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +144 -0
  202. package/templates/.agents/zaip-aios/guides/assets/diagrams/lifecycles-task-spec-prd.png +0 -0
  203. package/templates/.agents/zaip-aios/guides/assets/diagrams/prd-lifecycle.png +0 -0
  204. package/templates/.agents/zaip-aios/guides/assets/diagrams/spec-lifecycle.png +0 -0
  205. package/templates/.agents/zaip-aios/guides/assets/diagrams/task-lifecycle.png +0 -0
  206. package/templates/template-manifest.json +313 -177
  207. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-Cs6dzDmW.js +0 -1505
  208. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-QE1k9yZB.css +0 -1
  209. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-_Pf5DA_A.js +0 -3
  210. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BVlz3DLZ.js +0 -1
  211. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cf9ctPVt.js +0 -68
  212. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8A4DcNXM.js +0 -2
@@ -7,7 +7,6 @@ import {
7
7
  import type { CostGroupRow, CostRunRow, DurationCoverage } from "../contracts.js";
8
8
  import { MoreVerticalIcon } from "./CostTableIcons.js";
9
9
  import type { CostCurrency, CostLocale } from "./cost-monitor-copy.js";
10
- import type { CostGroupTotals } from "./use-cost-group-page.js";
11
10
  import {
12
11
  agentRunModelPresentation,
13
12
  formatApiSpeedScenario,
@@ -29,6 +28,7 @@ import {
29
28
  formatUsd,
30
29
  isCompactRunColumnVisible,
31
30
  } from "./cost-table-presentation.js";
31
+ import type { CostGroupTotals } from "./use-cost-group-page.js";
32
32
 
33
33
  export { CostModelsAuditTable } from "./CostModelsAuditTable.js";
34
34
 
@@ -61,7 +61,9 @@ export {
61
61
  export function displayCostGroupLabel(label: string, locale: CostLocale): string {
62
62
  const normalized = label.trim().toLowerCase();
63
63
  return normalized.length === 0 || normalized === "unknown"
64
- ? (locale === "pt-BR" ? "Sem modelo/provedor atribuído" : "No model/provider assigned")
64
+ ? locale === "pt-BR"
65
+ ? "Sem modelo/provedor atribuído"
66
+ : "No model/provider assigned"
65
67
  : label;
66
68
  }
67
69
 
@@ -97,8 +99,7 @@ const formatInvocationDuration = (value: number | null, locale: CostLocale) =>
97
99
  formatAuditableDuration(value, locale);
98
100
  const formatInvocationRate = (value: number | null, locale: CostLocale) =>
99
101
  formatRate(value, locale);
100
- const formatInvocationUsd = (value: number | null, locale: CostLocale) =>
101
- formatUsd(value, locale);
102
+ const formatInvocationUsd = (value: number | null, locale: CostLocale) => formatUsd(value, locale);
102
103
  const formatInvocationBrlRate = (value: number | null, locale: CostLocale) =>
103
104
  formatBrlRate(value, locale);
104
105
  const formatInvocationMultiplierPair = (
@@ -113,30 +114,99 @@ function invocationMetricDescription(locale: CostLocale, metric: string): string
113
114
  ? "Valor da projeção SQLite/API desta Invocação de Agente. Fato canônico nulo permanece indisponível e não é convertido em zero."
114
115
  : "Value from this Agent Invocation's SQLite/API projection. A null canonical fact remains unavailable and is not converted to zero.";
115
116
  const details: Record<string, readonly [string, string]> = {
116
- duration: ["Tempo factual da invocação, quando capturado ou reconciliado.", "Factual invocation duration, when captured or reconciled."],
117
- inputTokens: ["Input total informado pela fonte; inclui a parcela de cache.", "Source-reported total input; includes the cached portion."],
118
- cachedInputTokens: ["Parcela de cache já incluída no input total.", "Cached portion already included in total input."],
119
- outputTokens: ["Output total informado pela fonte; inclui a parcela de raciocínio.", "Source-reported total output; includes the reasoning portion."],
120
- reasoningTokens: ["Parcela de raciocínio já incluída no output total.", "Reasoning portion already included in total output."],
121
- totalTokens: ["Soma de entrada e saída quando ambas são conhecidas; caso contrário, total informado pela fonte.", "Input plus output when both are known; otherwise the source-reported total."],
122
- inputRate: ["Tarifa efetiva de entrada em USD por milhão de tokens.", "Effective input rate in USD per million tokens."],
123
- cacheRate: ["Tarifa efetiva de entrada em cache em USD por milhão de tokens.", "Effective cached-input rate in USD per million tokens."],
124
- outputRate: ["Tarifa efetiva de saída em USD por milhão de tokens.", "Effective output rate in USD per million tokens."],
125
- reasoningRate: ["Tarifa efetiva de raciocínio em USD por milhão de tokens.", "Effective reasoning rate in USD per million tokens."],
126
- contextMultiplier: ["Multiplicadores de contexto de entrada/saída aplicados aos segmentos internos.", "Input/output context multipliers applied to internal segments."],
127
- inputCost: ["Custo USD de entrada calculado com tokens e tarifa efetiva.", "Input USD cost calculated from tokens and the effective rate."],
128
- cacheCost: ["Custo USD da entrada em cache calculado com tokens e tarifa efetiva.", "Cached-input USD cost calculated from tokens and the effective rate."],
129
- outputCost: ["Custo USD de saída calculado com tokens e tarifa efetiva.", "Output USD cost calculated from tokens and the effective rate."],
130
- reasoningCost: ["Custo USD de raciocínio calculado com tokens e tarifa efetiva.", "Reasoning USD cost calculated from tokens and the effective rate."],
131
- standardCost: ["Custo USD no cenário Standard, antes do acréscimo de velocidade.", "USD cost in the Standard scenario, before the speed uplift."],
132
- speedUplift: ["Acréscimo USD do cenário Priority/Fast, já incluído no custo efetivo.", "USD uplift from the Priority/Fast scenario, already included in the effective cost."],
133
- finalUsd: ["Custo final estimado da API em USD, somando os componentes de custo desta invocação.", "Estimated final API cost in USD, summing this invocation's cost components."],
134
- fxRate: ["Câmbio BRL/USD atual aplicado para converter o custo final atual.", "Current BRL/USD exchange rate used to convert the current final cost."],
135
- recordedFxRate: ["Câmbio BRL/USD registrado no período da atividade.", "BRL/USD exchange rate recorded for the activity period."],
136
- recordedBrl: ["Custo final BRL registrado no período, preservado para auditoria histórica.", "Final BRL cost recorded in the period, retained for historical audit."],
137
- cost: ["Custo final atual: USD estimado ou sua conversão BRL pelo câmbio atual selecionado.", "Current final cost: estimated USD or its BRL conversion at the selected current exchange rate."],
117
+ duration: [
118
+ "Tempo factual da invocação, quando capturado ou reconciliado.",
119
+ "Factual invocation duration, when captured or reconciled.",
120
+ ],
121
+ inputTokens: [
122
+ "Input total informado pela fonte; inclui a parcela de cache.",
123
+ "Source-reported total input; includes the cached portion.",
124
+ ],
125
+ cachedInputTokens: [
126
+ "Parcela de cache já incluída no input total.",
127
+ "Cached portion already included in total input.",
128
+ ],
129
+ outputTokens: [
130
+ "Output total informado pela fonte; inclui a parcela de raciocínio.",
131
+ "Source-reported total output; includes the reasoning portion.",
132
+ ],
133
+ reasoningTokens: [
134
+ "Parcela de raciocínio já incluída no output total.",
135
+ "Reasoning portion already included in total output.",
136
+ ],
137
+ totalTokens: [
138
+ "Soma de entrada e saída quando ambas são conhecidas; caso contrário, total informado pela fonte.",
139
+ "Input plus output when both are known; otherwise the source-reported total.",
140
+ ],
141
+ inputRate: [
142
+ "Tarifa efetiva de entrada em USD por milhão de tokens.",
143
+ "Effective input rate in USD per million tokens.",
144
+ ],
145
+ cacheRate: [
146
+ "Tarifa efetiva de entrada em cache em USD por milhão de tokens.",
147
+ "Effective cached-input rate in USD per million tokens.",
148
+ ],
149
+ outputRate: [
150
+ "Tarifa efetiva de saída em USD por milhão de tokens.",
151
+ "Effective output rate in USD per million tokens.",
152
+ ],
153
+ reasoningRate: [
154
+ "Tarifa efetiva de raciocínio em USD por milhão de tokens.",
155
+ "Effective reasoning rate in USD per million tokens.",
156
+ ],
157
+ contextMultiplier: [
158
+ "Multiplicadores de contexto de entrada/saída aplicados aos segmentos internos.",
159
+ "Input/output context multipliers applied to internal segments.",
160
+ ],
161
+ inputCost: [
162
+ "Custo USD de entrada calculado com tokens e tarifa efetiva.",
163
+ "Input USD cost calculated from tokens and the effective rate.",
164
+ ],
165
+ cacheCost: [
166
+ "Custo USD da entrada em cache calculado com tokens e tarifa efetiva.",
167
+ "Cached-input USD cost calculated from tokens and the effective rate.",
168
+ ],
169
+ outputCost: [
170
+ "Custo USD de saída calculado com tokens e tarifa efetiva.",
171
+ "Output USD cost calculated from tokens and the effective rate.",
172
+ ],
173
+ reasoningCost: [
174
+ "Custo USD de raciocínio calculado com tokens e tarifa efetiva.",
175
+ "Reasoning USD cost calculated from tokens and the effective rate.",
176
+ ],
177
+ standardCost: [
178
+ "Custo USD no cenário Standard, antes do acréscimo de velocidade.",
179
+ "USD cost in the Standard scenario, before the speed uplift.",
180
+ ],
181
+ speedUplift: [
182
+ "Acréscimo USD do cenário Priority/Fast, já incluído no custo efetivo.",
183
+ "USD uplift from the Priority/Fast scenario, already included in the effective cost.",
184
+ ],
185
+ finalUsd: [
186
+ "Custo final estimado da API em USD, somando os componentes de custo desta invocação.",
187
+ "Estimated final API cost in USD, summing this invocation's cost components.",
188
+ ],
189
+ fxRate: [
190
+ "Câmbio BRL/USD atual aplicado para converter o custo final atual.",
191
+ "Current BRL/USD exchange rate used to convert the current final cost.",
192
+ ],
193
+ recordedFxRate: [
194
+ "Câmbio BRL/USD registrado no período da atividade.",
195
+ "BRL/USD exchange rate recorded for the activity period.",
196
+ ],
197
+ recordedBrl: [
198
+ "Custo final BRL registrado no período, preservado para auditoria histórica.",
199
+ "Final BRL cost recorded in the period, retained for historical audit.",
200
+ ],
201
+ cost: [
202
+ "Custo final atual: USD estimado ou sua conversão BRL pelo câmbio atual selecionado.",
203
+ "Current final cost: estimated USD or its BRL conversion at the selected current exchange rate.",
204
+ ],
138
205
  };
139
- const detail = details[metric] ?? ["Métrica numérica desta invocação.", "Numeric metric for this invocation."];
206
+ const detail = details[metric] ?? [
207
+ "Métrica numérica desta invocação.",
208
+ "Numeric metric for this invocation.",
209
+ ];
140
210
  return `${detail[locale === "pt-BR" ? 0 : 1]} ${source}`;
141
211
  }
142
212
 
@@ -332,13 +402,8 @@ export function CostRunsTable({
332
402
  key: "totalTokens",
333
403
  label: locale === "pt-BR" ? "Total tokens" : "Total tokens",
334
404
  description: invocationMetricDescription(locale, "totalTokens"),
335
- render: (row) =>
336
- formatInvocationNumber(
337
- inclusiveTokenTotal(row),
338
- locale,
339
- ),
340
- sortValue: (row) =>
341
- inclusiveTokenTotal(row),
405
+ render: (row) => formatInvocationNumber(inclusiveTokenTotal(row), locale),
406
+ sortValue: (row) => inclusiveTokenTotal(row),
342
407
  align: "right",
343
408
  footer: formatInvocationNumber(totalTokens, locale),
344
409
  },
@@ -636,19 +701,22 @@ export function CostGroupsTable({
636
701
  usd: sumNumbers(rows.map((row) => row.estimated_usd)),
637
702
  brl: sumNumbers(rows.map((row) => row.estimated_brl)),
638
703
  };
639
- const totals = suppliedTotals === undefined ? pageTotals : {
640
- runs: suppliedTotals.run_count,
641
- tasks: suppliedTotals.task_count ?? 0,
642
- prds: suppliedTotals.prd_count,
643
- specs: suppliedTotals.spec_count,
644
- evidences: suppliedTotals.evidence_count,
645
- tests: suppliedTotals.test_count,
646
- durationKnownMs: suppliedTotals.duration.known_sum,
647
- durationPartial: !suppliedTotals.duration.complete,
648
- tokens: suppliedTotals.total_tokens,
649
- usd: suppliedTotals.estimated_usd,
650
- brl: suppliedTotals.estimated_brl,
651
- };
704
+ const totals =
705
+ suppliedTotals === undefined
706
+ ? pageTotals
707
+ : {
708
+ runs: suppliedTotals.run_count,
709
+ tasks: suppliedTotals.task_count ?? 0,
710
+ prds: suppliedTotals.prd_count,
711
+ specs: suppliedTotals.spec_count,
712
+ evidences: suppliedTotals.evidence_count,
713
+ tests: suppliedTotals.test_count,
714
+ durationKnownMs: suppliedTotals.duration.known_sum,
715
+ durationPartial: !suppliedTotals.duration.complete,
716
+ tokens: suppliedTotals.total_tokens,
717
+ usd: suppliedTotals.estimated_usd,
718
+ brl: suppliedTotals.estimated_brl,
719
+ };
652
720
  const totalDurationDisplay = formatDurationCoverage(
653
721
  suppliedTotals?.duration ?? {
654
722
  known_sum: totals.durationKnownMs,
@@ -686,8 +754,16 @@ export function CostGroupsTable({
686
754
  },
687
755
  ...(showAgentIdentity
688
756
  ? [
689
- { key: "persona", label: locale === "pt-BR" ? "Persona" : "Persona", render: (row: CostGroupRow) => row.persona ?? "" },
690
- { key: "job", label: locale === "pt-BR" ? "Cargo" : "Job", render: (row: CostGroupRow) => row.job ?? "" },
757
+ {
758
+ key: "persona",
759
+ label: locale === "pt-BR" ? "Persona" : "Persona",
760
+ render: (row: CostGroupRow) => row.persona ?? "",
761
+ },
762
+ {
763
+ key: "job",
764
+ label: locale === "pt-BR" ? "Cargo" : "Job",
765
+ render: (row: CostGroupRow) => row.job ?? "",
766
+ },
691
767
  ]
692
768
  : []),
693
769
  {
@@ -724,14 +800,21 @@ export function CostGroupsTable({
724
800
  ...(showAgentIdentity
725
801
  ? []
726
802
  : [
727
- {
728
- key: "tasks",
729
- label: showAgentIdentity || showInvocationTasks ? (locale === "pt-BR" ? "Tarefas com invocação" : "Tasks with invocations") : (locale === "pt-BR" ? "Tarefas criadas" : "Tasks created"),
730
- render: (row: CostGroupRow) => row.task_count ?? 0,
731
- align: "right" as const,
732
- footer: totals.tasks,
733
- },
734
- ]),
803
+ {
804
+ key: "tasks",
805
+ label:
806
+ showAgentIdentity || showInvocationTasks
807
+ ? locale === "pt-BR"
808
+ ? "Tarefas com invocação"
809
+ : "Tasks with invocations"
810
+ : locale === "pt-BR"
811
+ ? "Tarefas criadas"
812
+ : "Tasks created",
813
+ render: (row: CostGroupRow) => row.task_count ?? 0,
814
+ align: "right" as const,
815
+ footer: totals.tasks,
816
+ },
817
+ ]),
735
818
  ]
736
819
  : [
737
820
  {
@@ -835,7 +918,13 @@ export function CostGroupsTable({
835
918
  ]
836
919
  : []),
837
920
  ]}
838
- defaultSort={period === undefined ? null : { key: "label", direction: "desc" }}
921
+ defaultSort={
922
+ showAgentIdentity
923
+ ? { key: "cost", direction: "desc" }
924
+ : period === undefined
925
+ ? null
926
+ : { key: "label", direction: "desc" }
927
+ }
839
928
  locale={locale}
840
929
  pageSize={100}
841
930
  rowKey={(row) => row.key}
@@ -237,14 +237,17 @@
237
237
  min-width: 0;
238
238
  table-layout: fixed;
239
239
  }
240
- .cost-content:is(.cost-content-daily, .cost-content-monthly, .cost-content-annual) .cost-page-controls {
240
+ .cost-content:is(.cost-content-daily, .cost-content-monthly, .cost-content-annual)
241
+ .cost-page-controls {
241
242
  display: flex;
242
243
  align-items: center;
243
244
  justify-content: flex-end;
244
245
  gap: 10px;
245
246
  margin-top: 12px;
246
247
  }
247
- .cost-content:is(.cost-content-daily, .cost-content-monthly, .cost-content-annual) .cost-page-controls output {
248
+ .cost-content:is(.cost-content-daily, .cost-content-monthly, .cost-content-annual)
249
+ .cost-page-controls
250
+ output {
248
251
  min-width: 8.5rem;
249
252
  color: var(--muted);
250
253
  font-size: 0.78rem;
@@ -1,5 +1,5 @@
1
+ export type { CompactLifecycleCostPage } from "./CompactLifecycleCostTable.js";
1
2
  export * from "./CostMonitorPage.js";
2
3
  export { CostRunsTable } from "./CostTables.js";
3
- export type { CompactLifecycleCostPage } from "./CompactLifecycleCostTable.js";
4
- export { matches as matchesCostRunFilter } from "./cost-monitor-row-filters.js";
5
4
  export type { CostCurrency, CostLocale } from "./cost-monitor-copy.js";
5
+ export { matches as matchesCostRunFilter } from "./cost-monitor-row-filters.js";
@@ -127,7 +127,8 @@ export function summarizeCostPeriodAverages(
127
127
  ): CostPeriodAverages {
128
128
  const divisor = rows.length;
129
129
  return {
130
- tasks: divisor === 0 ? null : rows.reduce((sum, row) => sum + (row.task_count ?? 0), 0) / divisor,
130
+ tasks:
131
+ divisor === 0 ? null : rows.reduce((sum, row) => sum + (row.task_count ?? 0), 0) / divisor,
131
132
  specs: divisor === 0 ? null : rows.reduce((sum, row) => sum + row.spec_count, 0) / divisor,
132
133
  prds: divisor === 0 ? null : rows.reduce((sum, row) => sum + row.prd_count, 0) / divisor,
133
134
  durationMs: averagePerPeriod(
@@ -3,8 +3,8 @@ import {
3
3
  type CompactLifecycleCostPage,
4
4
  withTokenBackedCompactDuration,
5
5
  } from "./CompactLifecycleCostTable.js";
6
- import type { CostView } from "./cost-monitor-views.js";
7
6
  import type { CostFilterState } from "./CostFilters.js";
7
+ import type { CostView } from "./cost-monitor-views.js";
8
8
 
9
9
  type CompactReadModelKind = CompactLifecycleCostPage["kind"];
10
10
  export type LoadCompactCostPage = (request: {
@@ -43,6 +43,7 @@ export function useCompactCostPage({
43
43
  }) {
44
44
  const [offset, setOffset] = useState(0);
45
45
  const [page, setPage] = useState<CompactLifecycleCostPage | null>(null);
46
+ const [resolvedKey, setResolvedKey] = useState<string | null>(null);
46
47
  const [loading, setLoading] = useState(false);
47
48
  const [error, setError] = useState<string | null>(null);
48
49
  const [attempt, setAttempt] = useState(0);
@@ -54,6 +55,9 @@ export function useCompactCostPage({
54
55
  const rangeTo = range?.to;
55
56
  const filterKey = Object.values(filters).join("\u0000");
56
57
  const paginationKey = `${view}\u0000${query ?? ""}\u0000${rangeFrom ?? ""}\u0000${rangeTo ?? ""}\u0000${filterKey}`;
58
+ const requestKey = `${paginationKey}\u0000${offset}`;
59
+ const requestInputRef = useRef({ filters, query, rangeFrom, rangeTo });
60
+ requestInputRef.current = { filters, query, rangeFrom, rangeTo };
57
61
  useEffect(() => {
58
62
  void paginationKey;
59
63
  setOffset(0);
@@ -73,18 +77,23 @@ export function useCompactCostPage({
73
77
  setError(null);
74
78
  const loadPage = loadRef.current;
75
79
  if (loadPage === undefined) return;
80
+ const requestInput = requestInputRef.current;
76
81
  void loadPage({
77
82
  kind,
78
83
  offset,
79
84
  limit: 50,
80
- ...(rangeFrom === undefined || rangeTo === undefined ? {} : { from: rangeFrom, to: rangeTo }),
81
- ...(query ? { query } : {}),
82
- filters,
85
+ ...(requestInput.rangeFrom === undefined || requestInput.rangeTo === undefined
86
+ ? {}
87
+ : { from: requestInput.rangeFrom, to: requestInput.rangeTo }),
88
+ ...(requestInput.query ? { query: requestInput.query } : {}),
89
+ filters: requestInput.filters,
83
90
  signal: controller.signal,
84
91
  })
85
92
  .then((next) => {
86
- if (!controller.signal.aborted && generation === generationRef.current)
93
+ if (!controller.signal.aborted && generation === generationRef.current) {
87
94
  setPage({ ...next, rows: next.rows.map(withTokenBackedCompactDuration) });
95
+ setResolvedKey(requestKey);
96
+ }
88
97
  })
89
98
  .catch((cause: unknown) => {
90
99
  if (!controller.signal.aborted && generation === generationRef.current)
@@ -96,11 +105,13 @@ export function useCompactCostPage({
96
105
  return () => controller.abort();
97
106
  // App supplies an inline loader. Its identity changes after state updates;
98
107
  // retaining it here would abort/restart this exact request forever.
99
- }, [attempt, filterKey, hasLoad, offset, query, rangeFrom, rangeTo, view]);
108
+ }, [attempt, hasLoad, offset, requestKey, view]);
100
109
  return {
101
110
  compactPageOffset: offset,
102
111
  setCompactPageOffset: setOffset,
103
- compactPage: page,
112
+ // A response for another tab, range, filter, or offset must never occupy
113
+ // this view while the next request is in flight.
114
+ compactPage: resolvedKey === requestKey ? page : null,
104
115
  compactPageLoading: loading,
105
116
  compactPageError: error,
106
117
  retryCompactPage: () => setAttempt((value) => value + 1),
@@ -4,10 +4,40 @@ import type { CostFilterState } from "./CostFilters.js";
4
4
  import type { CostLocale } from "./cost-monitor-copy.js";
5
5
 
6
6
  /** Pre-pagination aggregate for the exact page query. */
7
- export type CostGroupTotals = Pick<CostGroupRow, "run_count" | "task_count" | "prd_count" | "spec_count" | "evidence_count" | "test_count" | "event_count" | "total_tokens" | "estimated_usd" | "estimated_brl" | "duration_ms" | "duration">;
8
- export type CostGroupPage = { offset: number; limit: number; total_count: number; has_more: boolean; rows: readonly CostGroupRow[]; totals?: CostGroupTotals };
7
+ export type CostGroupTotals = Pick<
8
+ CostGroupRow,
9
+ | "run_count"
10
+ | "task_count"
11
+ | "prd_count"
12
+ | "spec_count"
13
+ | "evidence_count"
14
+ | "test_count"
15
+ | "event_count"
16
+ | "total_tokens"
17
+ | "estimated_usd"
18
+ | "estimated_brl"
19
+ | "duration_ms"
20
+ | "duration"
21
+ >;
22
+ export type CostGroupPage = {
23
+ offset: number;
24
+ limit: number;
25
+ total_count: number;
26
+ has_more: boolean;
27
+ rows: readonly CostGroupRow[];
28
+ totals?: CostGroupTotals;
29
+ };
9
30
  export type CostGroupFilters = CostFilterState;
10
- export type LoadCostGroupPage = (request: { view: "daily" | "monthly" | "annual" | "agents" | "models" | "providers"; from?: string; to?: string; offset: number; limit: number; query?: string; filters: CostGroupFilters; signal?: AbortSignal }) => Promise<CostGroupPage>;
31
+ export type LoadCostGroupPage = (request: {
32
+ view: "daily" | "monthly" | "annual" | "agents" | "models" | "providers";
33
+ from?: string;
34
+ to?: string;
35
+ offset: number;
36
+ limit: number;
37
+ query?: string;
38
+ filters: CostGroupFilters;
39
+ signal?: AbortSignal;
40
+ }) => Promise<CostGroupPage>;
11
41
 
12
42
  export function effectiveCostGroupQuery(filters: CostGroupFilters, globalQuery: string): string {
13
43
  return filters.query || globalQuery;
@@ -49,12 +79,68 @@ export function reconcileCostGroupTotalsWithCards(
49
79
  };
50
80
  }
51
81
 
52
- export function useCostGroupPage({ view, range, globalQuery, filters, load }: { view: "daily" | "monthly" | "annual" | "agents" | "models" | "providers"; range?: { from: string; to: string }; globalQuery: string; filters: CostGroupFilters; load?: LoadCostGroupPage }) {
53
- const [offset, setOffset] = useState(0); const [page, setPage] = useState<CostGroupPage | null>(null); const [resolvedKey, setResolvedKey] = useState<string | null>(null); const [loading, setLoading] = useState(false); const generation = useRef(0); const loader = useRef(load); loader.current = load;
82
+ export function useCostGroupPage({
83
+ view,
84
+ range,
85
+ globalQuery,
86
+ filters,
87
+ load,
88
+ }: {
89
+ view: "daily" | "monthly" | "annual" | "agents" | "models" | "providers";
90
+ range?: { from: string; to: string };
91
+ globalQuery: string;
92
+ filters: CostGroupFilters;
93
+ load?: LoadCostGroupPage;
94
+ }) {
95
+ const [offset, setOffset] = useState(0);
96
+ const [page, setPage] = useState<CostGroupPage | null>(null);
97
+ const [resolvedKey, setResolvedKey] = useState<string | null>(null);
98
+ const [loading, setLoading] = useState(false);
99
+ const generation = useRef(0);
100
+ const loader = useRef(load);
101
+ loader.current = load;
54
102
  const query = effectiveCostGroupQuery(filters, globalQuery);
55
103
  const filterKey = `${Object.values(filters).join("\u0000")}\u0000${query}`;
56
- const requestKey = `${view}\u0000${range?.from ?? ""}\u0000${range?.to ?? ""}\u0000${filterKey}\u0000${offset}`;
57
- useEffect(() => { setOffset(0); }, [view, range?.from, range?.to, filterKey]);
58
- useEffect(() => { if (!loader.current) return; const controller = new AbortController(); const current = ++generation.current; const limit = view === "daily" ? 30 : 50; setLoading(true); void loader.current({ view, offset, limit, ...(query ? { query } : {}), filters, ...(range ?? {}), signal: controller.signal }).then((next) => { if (!controller.signal.aborted && current === generation.current) { setPage(next); setResolvedKey(requestKey); } }).finally(() => { if (!controller.signal.aborted && current === generation.current) setLoading(false); }); return () => controller.abort(); }, [filterKey, offset, range?.from, range?.to, requestKey, view]);
59
- return { page: isCurrentCostGroupPage(resolvedKey, requestKey) ? page : null, loading, offset, setOffset };
104
+ const paginationKey = `${view}\u0000${range?.from ?? ""}\u0000${range?.to ?? ""}\u0000${filterKey}`;
105
+ const requestKey = `${paginationKey}\u0000${offset}`;
106
+ const requestInputRef = useRef({ filters, query, range, view });
107
+ requestInputRef.current = { filters, query, range, view };
108
+ useEffect(() => {
109
+ void paginationKey;
110
+ setOffset(0);
111
+ }, [paginationKey]);
112
+ useEffect(() => {
113
+ if (!loader.current) return;
114
+ const controller = new AbortController();
115
+ const current = ++generation.current;
116
+ const requestInput = requestInputRef.current;
117
+ const limit = requestInput.view === "daily" ? 30 : 50;
118
+ setLoading(true);
119
+ void loader
120
+ .current({
121
+ view: requestInput.view,
122
+ offset,
123
+ limit,
124
+ ...(requestInput.query ? { query: requestInput.query } : {}),
125
+ filters: requestInput.filters,
126
+ ...(requestInput.range ?? {}),
127
+ signal: controller.signal,
128
+ })
129
+ .then((next) => {
130
+ if (!controller.signal.aborted && current === generation.current) {
131
+ setPage(next);
132
+ setResolvedKey(requestKey);
133
+ }
134
+ })
135
+ .finally(() => {
136
+ if (!controller.signal.aborted && current === generation.current) setLoading(false);
137
+ });
138
+ return () => controller.abort();
139
+ }, [offset, requestKey]);
140
+ return {
141
+ page: isCurrentCostGroupPage(resolvedKey, requestKey) ? page : null,
142
+ loading,
143
+ offset,
144
+ setOffset,
145
+ };
60
146
  }
@@ -35,13 +35,34 @@ export function useCostRunPage({
35
35
  const rangeTo = range?.to;
36
36
  const effectiveFilters = { ...filters, query: filters.query || globalQuery };
37
37
  const paginationKey = `${Object.values(effectiveFilters).join("\u0000")}\u0000${rangeFrom ?? ""}\u0000${rangeTo ?? ""}`;
38
+ const requestKey = `${view}\u0000${eligible}\u0000${currency}\u0000${paginationKey}\u0000${refresh ?? ""}`;
39
+ const requestInputRef = useRef({
40
+ view,
41
+ eligible,
42
+ currency,
43
+ effectiveFilters,
44
+ rangeFrom,
45
+ rangeTo,
46
+ refresh,
47
+ });
48
+ requestInputRef.current = {
49
+ view,
50
+ eligible,
51
+ currency,
52
+ effectiveFilters,
53
+ rangeFrom,
54
+ rangeTo,
55
+ refresh,
56
+ };
38
57
  useEffect(() => {
39
58
  void paginationKey;
40
59
  setOffset(0);
41
60
  }, [paginationKey]);
42
61
  useEffect(() => {
43
62
  void attempt;
44
- if (view !== "agentCalls" || !eligible) {
63
+ void requestKey;
64
+ const requestInput = requestInputRef.current;
65
+ if (requestInput.view !== "agentCalls" || !requestInput.eligible) {
45
66
  setData(null);
46
67
  setError(null);
47
68
  setLoading(false);
@@ -52,11 +73,13 @@ export function useCostRunPage({
52
73
  setLoading(true);
53
74
  setError(null);
54
75
  void (loadRef.current ?? loadCostMonitorRunPage)({
55
- currency,
56
- filters: effectiveFilters,
57
- ...(rangeFrom === undefined || rangeTo === undefined ? {} : { from: rangeFrom, to: rangeTo }),
76
+ currency: requestInput.currency,
77
+ filters: requestInput.effectiveFilters,
78
+ ...(requestInput.rangeFrom === undefined || requestInput.rangeTo === undefined
79
+ ? {}
80
+ : { from: requestInput.rangeFrom, to: requestInput.rangeTo }),
58
81
  offset,
59
- refresh,
82
+ refresh: requestInput.refresh,
60
83
  signal: controller.signal,
61
84
  })
62
85
  .then((next) => {
@@ -83,18 +106,7 @@ export function useCostRunPage({
83
106
  return () => controller.abort();
84
107
  // Do not depend on App's inline loader identity: a render caused by loading
85
108
  // state must not cancel and recreate the same page request.
86
- }, [
87
- attempt,
88
- currency,
89
- eligible,
90
- filters,
91
- globalQuery,
92
- offset,
93
- rangeFrom,
94
- rangeTo,
95
- refresh,
96
- view,
97
- ]);
109
+ }, [attempt, offset, requestKey]);
98
110
  return {
99
111
  runPageOffset: offset,
100
112
  setRunPageOffset: setOffset,
@@ -680,30 +680,6 @@ describe("Cost Monitor V2", () => {
680
680
  });
681
681
  expect(specialized.runs[0]?.agent_name).toBe("zaip-agent-reviewer");
682
682
  });
683
- it("uses the catalog agent id for Sub-Runs even when their inherited name is stale", () => {
684
- const operations = operationsWithPricedRun();
685
- const source = operations.runs[0];
686
- if (source === undefined) throw new Error("priced Run fixture is missing");
687
- source.agent = "agent-finalizer";
688
- source.agent_name = "zaip-agent-orchestrator";
689
- source.run_kind = "subrun";
690
- source.parent_run_id = "RUN-PARENT";
691
- const projection = buildCostMonitorProjection(operations, undefined, {
692
- agentNamesById: { "agent-finalizer": "zaip-agent-finalizer" },
693
- });
694
- expect(projection.runs[0]?.agent_name).toBe("zaip-agent-finalizer");
695
- });
696
- it("maps an unmapped orchestrator internal id through its catalog role", () => {
697
- const operations = operationsWithPricedRun();
698
- const source = operations.runs[0];
699
- if (source === undefined) throw new Error("priced Run fixture is missing");
700
- source.agent = "orchestrator";
701
- source.agent_name = "orchestrator";
702
- const projection = buildCostMonitorProjection(operations, undefined, {
703
- agentNamesByRole: { orchestrator: "zaip-agent-orchestrator" },
704
- });
705
- expect(projection.runs[0]?.agent_name).toBe("zaip-agent-orchestrator");
706
- });
707
683
  it("maps the canonical orchestrator id when catalog loading is unavailable", () => {
708
684
  const operations = operationsWithPricedRun();
709
685
  const source = operations.runs[0];