@zaip-ai/cli 1.3.2 → 1.3.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.
- package/LICENSE +6 -3
- package/README.md +8 -2
- package/dist/services/codex-pre-tool-hook-template.js +1 -1
- package/dist/services/runtime-template.test.js +9 -8
- package/dist/services/runtime-template.test.js.map +1 -1
- package/package.json +2 -2
- package/templates/.agents/dashboard/.zaip-managed.json +401 -381
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-ovxurkIk.js → CostCalculationGuidePage-BZWjXQB-.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-BXy6nti1.js → DashboardHelpDialog-D8qqeIPE.js} +30 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-vSvvOHQp.js → PricingSettingsDialog-Cm12_A0v.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-zH758vfs.js → ProjectSettingsPage-DxO9F8B4.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CTH2wDs5.js → TraceabilityWorkspace-_x0twOcS.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cpp8xFij.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-B_lDDHn1.js → icons-vendor-CR4Fbf3g.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-ncC1rxap.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-B3TJrD4O.js → react-vendor-DRJQbKnp.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-7f1j5wx3.js → traceability-CMrDYqjR.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
- package/templates/.agents/dashboard/apps/frontend/src/App.tsx +48 -3
- package/templates/.agents/dashboard/apps/frontend/src/AppRequestGuards.tsx +44 -0
- package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +92 -1
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.test.ts +60 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +26 -9
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorNavigation.tsx +189 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +122 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +70 -155
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +59 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +55 -2
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +274 -246
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +255 -227
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +263 -235
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.test.ts +282 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.ts +71 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-launch-progress.ts +18 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-stale-seed.ts +50 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +9 -6
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +45 -73
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +79 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-work-item-index.test.ts +56 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +26 -8
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +45 -4
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.mjs +58 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.test.mjs +81 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +171 -71
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +152 -11
- package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +4 -9
- package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +9 -1
- package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-period-transition.spec.ts +232 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +26 -5
- package/templates/.agents/requirements/autonomous-assurance.md +1 -1
- package/templates/.agents/requirements/comparative-audit.md +1 -1
- package/templates/.agents/requirements/context-engine.md +1 -1
- package/templates/.agents/requirements/cost-observability.md +1 -1
- package/templates/.agents/requirements/dashboard-launch.md +1 -1
- package/templates/.agents/requirements/data-export.md +1 -1
- package/templates/.agents/requirements/design-system.md +1 -1
- package/templates/.agents/requirements/execution-engine.md +1 -1
- package/templates/.agents/requirements/kanban-dashboard.md +1 -1
- package/templates/.agents/requirements/model-orchestration.md +1 -1
- package/templates/.agents/requirements/public-distribution.md +1 -1
- package/templates/.agents/requirements/software-architecture.md +1 -1
- package/templates/.agents/requirements/strategic-improvements.md +1 -1
- package/templates/.agents/requirements/work-lifecycle.md +1 -1
- package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
- package/templates/.agents/runtime/bin/zaip.mjs +7 -7
- package/templates/.agents/runtime/checksums.sha256 +3 -3
- package/templates/.agents/runtime/provenance.json +3 -3
- package/templates/.agents/runtime/sbom.cdx.json +1595 -3491
- package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +16 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +19 -20
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.test.mjs +143 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +14 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +3 -1
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +21 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +3 -0
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +29 -0
- package/templates/template-manifest.json +536 -932
- package/templates/.agents/dashboard/.tmp-run-list.json +0 -254
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CuMcoUni.js +0 -2
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.test.ts
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { rebuildCostInvocationDimensionFactsSql } from "./sqlite-cost-dimension-facts.js";
|
|
4
|
+
|
|
5
|
+
const databases: DatabaseSync[] = [];
|
|
6
|
+
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
while (databases.length > 0) databases.pop()?.close();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
function databaseWithFinancialFixture(): DatabaseSync {
|
|
12
|
+
const database = new DatabaseSync(":memory:");
|
|
13
|
+
databases.push(database);
|
|
14
|
+
database.exec(`
|
|
15
|
+
CREATE TABLE zaip_aios_activities (
|
|
16
|
+
activity_row_id TEXT PRIMARY KEY, payload_type TEXT, activity_source_kind TEXT, agent_run_id TEXT,
|
|
17
|
+
source_started_at TEXT, source_occurred_at TEXT, occurred_at TEXT, occurred_day_sp TEXT,
|
|
18
|
+
input_tokens REAL, cached_input_tokens REAL, output_tokens REAL, reasoning_tokens REAL,
|
|
19
|
+
total_tokens REAL, cost_usd REAL, cost_brl REAL
|
|
20
|
+
);
|
|
21
|
+
CREATE TEMP TABLE invocation_usage_segments (
|
|
22
|
+
agent_invocation_id TEXT, provider TEXT, model TEXT, service_tier TEXT, reasoning_effort TEXT,
|
|
23
|
+
input_tokens REAL, cached_input_tokens REAL, uncached_input_tokens REAL, output_tokens REAL,
|
|
24
|
+
reasoning_tokens REAL, visible_output_tokens REAL, total_tokens REAL, input_rate_usd_per_million REAL,
|
|
25
|
+
cached_input_rate_usd_per_million REAL, output_rate_usd_per_million REAL, reasoning_rate_usd_per_million REAL,
|
|
26
|
+
context_input_multiplier REAL, context_output_multiplier REAL, speed_cost_multiplier REAL, pricing_scenario TEXT,
|
|
27
|
+
standard_cost_usd REAL, speed_uplift_usd REAL, input_cost_usd REAL, cached_input_cost_usd REAL,
|
|
28
|
+
output_cost_usd REAL, reasoning_cost_usd REAL, calculated_cost_usd REAL, recorded_cost_usd REAL,
|
|
29
|
+
cost_variance_usd REAL, cost_usd REAL, cost_brl REAL, cost_method TEXT, pricing_model TEXT,
|
|
30
|
+
pricing_source TEXT, fx_rate REAL
|
|
31
|
+
);
|
|
32
|
+
CREATE TEMP TABLE attributed_token_active_facts (
|
|
33
|
+
activity_row_id TEXT, occurred_day_sp TEXT, attributed_token_active_ms REAL,
|
|
34
|
+
PRIMARY KEY(activity_row_id, occurred_day_sp)
|
|
35
|
+
);
|
|
36
|
+
`);
|
|
37
|
+
const activity = database.prepare(
|
|
38
|
+
"INSERT INTO zaip_aios_activities VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
|
39
|
+
);
|
|
40
|
+
activity.run(
|
|
41
|
+
"ACTV-ONE",
|
|
42
|
+
null,
|
|
43
|
+
"agent_run",
|
|
44
|
+
"AINV-ONE",
|
|
45
|
+
"2026-08-31T03:00:00Z",
|
|
46
|
+
null,
|
|
47
|
+
"2026-08-31T03:00:00Z",
|
|
48
|
+
"2026-08-31",
|
|
49
|
+
100,
|
|
50
|
+
10,
|
|
51
|
+
20,
|
|
52
|
+
5,
|
|
53
|
+
135,
|
|
54
|
+
13.5,
|
|
55
|
+
67.5,
|
|
56
|
+
);
|
|
57
|
+
activity.run(
|
|
58
|
+
"ACTV-TWO",
|
|
59
|
+
null,
|
|
60
|
+
"agent_run",
|
|
61
|
+
"AINV-TWO",
|
|
62
|
+
null,
|
|
63
|
+
null,
|
|
64
|
+
"2026-08-31T04:00:00Z",
|
|
65
|
+
"2026-08-31",
|
|
66
|
+
30,
|
|
67
|
+
0,
|
|
68
|
+
0,
|
|
69
|
+
0,
|
|
70
|
+
30,
|
|
71
|
+
null,
|
|
72
|
+
3,
|
|
73
|
+
);
|
|
74
|
+
activity.run(
|
|
75
|
+
"ACTV-FIN",
|
|
76
|
+
null,
|
|
77
|
+
"manual",
|
|
78
|
+
null,
|
|
79
|
+
null,
|
|
80
|
+
null,
|
|
81
|
+
"2026-08-31T05:00:00Z",
|
|
82
|
+
"2026-08-31",
|
|
83
|
+
10,
|
|
84
|
+
null,
|
|
85
|
+
null,
|
|
86
|
+
null,
|
|
87
|
+
10,
|
|
88
|
+
1,
|
|
89
|
+
5,
|
|
90
|
+
);
|
|
91
|
+
activity.run(
|
|
92
|
+
"ACTV-UNKNOWN",
|
|
93
|
+
null,
|
|
94
|
+
"manual",
|
|
95
|
+
null,
|
|
96
|
+
null,
|
|
97
|
+
null,
|
|
98
|
+
"2026-08-31T06:00:00Z",
|
|
99
|
+
"2026-08-31",
|
|
100
|
+
null,
|
|
101
|
+
null,
|
|
102
|
+
null,
|
|
103
|
+
null,
|
|
104
|
+
null,
|
|
105
|
+
2,
|
|
106
|
+
null,
|
|
107
|
+
);
|
|
108
|
+
const usage = database.prepare(
|
|
109
|
+
"INSERT INTO invocation_usage_segments VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
|
110
|
+
);
|
|
111
|
+
usage.run(
|
|
112
|
+
"AINV-ONE",
|
|
113
|
+
"openai",
|
|
114
|
+
"model-a",
|
|
115
|
+
null,
|
|
116
|
+
null,
|
|
117
|
+
60,
|
|
118
|
+
6,
|
|
119
|
+
54,
|
|
120
|
+
10,
|
|
121
|
+
3,
|
|
122
|
+
10,
|
|
123
|
+
79,
|
|
124
|
+
null,
|
|
125
|
+
null,
|
|
126
|
+
null,
|
|
127
|
+
null,
|
|
128
|
+
null,
|
|
129
|
+
null,
|
|
130
|
+
null,
|
|
131
|
+
null,
|
|
132
|
+
null,
|
|
133
|
+
null,
|
|
134
|
+
null,
|
|
135
|
+
null,
|
|
136
|
+
null,
|
|
137
|
+
null,
|
|
138
|
+
null,
|
|
139
|
+
null,
|
|
140
|
+
null,
|
|
141
|
+
7.9,
|
|
142
|
+
39.5,
|
|
143
|
+
null,
|
|
144
|
+
null,
|
|
145
|
+
null,
|
|
146
|
+
null,
|
|
147
|
+
);
|
|
148
|
+
usage.run(
|
|
149
|
+
"AINV-ONE",
|
|
150
|
+
null,
|
|
151
|
+
null,
|
|
152
|
+
null,
|
|
153
|
+
null,
|
|
154
|
+
20,
|
|
155
|
+
2,
|
|
156
|
+
18,
|
|
157
|
+
5,
|
|
158
|
+
1,
|
|
159
|
+
5,
|
|
160
|
+
26,
|
|
161
|
+
null,
|
|
162
|
+
null,
|
|
163
|
+
null,
|
|
164
|
+
null,
|
|
165
|
+
null,
|
|
166
|
+
null,
|
|
167
|
+
null,
|
|
168
|
+
null,
|
|
169
|
+
null,
|
|
170
|
+
null,
|
|
171
|
+
null,
|
|
172
|
+
null,
|
|
173
|
+
null,
|
|
174
|
+
null,
|
|
175
|
+
null,
|
|
176
|
+
null,
|
|
177
|
+
null,
|
|
178
|
+
2.6,
|
|
179
|
+
13,
|
|
180
|
+
null,
|
|
181
|
+
null,
|
|
182
|
+
null,
|
|
183
|
+
null,
|
|
184
|
+
);
|
|
185
|
+
const duration = database.prepare("INSERT INTO attributed_token_active_facts VALUES (?,?,?)");
|
|
186
|
+
duration.run("ACTV-ONE", "2026-08-30", 40);
|
|
187
|
+
duration.run("ACTV-ONE", "2026-08-31", 60);
|
|
188
|
+
duration.run("ACTV-FIN", "2026-08-30", 4);
|
|
189
|
+
duration.run("ACTV-FIN", "2026-08-31", 6);
|
|
190
|
+
return database;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const legacySql = `
|
|
194
|
+
CREATE TEMP TABLE legacy_usage_payloads AS
|
|
195
|
+
SELECT json_object('agent_invocation_id', agent_invocation_id, 'model', model, 'provider', provider,
|
|
196
|
+
'input_tokens', input_tokens, 'cached_input_tokens', cached_input_tokens, 'output_tokens', output_tokens,
|
|
197
|
+
'reasoning_tokens', reasoning_tokens, 'total_tokens', total_tokens, 'cost_usd', cost_usd, 'cost_brl', cost_brl) AS payload_json
|
|
198
|
+
FROM temp.invocation_usage_segments;
|
|
199
|
+
CREATE TEMP VIEW legacy_usage AS
|
|
200
|
+
SELECT json_extract(payload_json, '$.agent_invocation_id') AS agent_invocation_id,
|
|
201
|
+
json_extract(payload_json, '$.model') AS model, json_extract(payload_json, '$.provider') AS provider,
|
|
202
|
+
json_extract(payload_json, '$.input_tokens') AS input_tokens, json_extract(payload_json, '$.cached_input_tokens') AS cached_input_tokens,
|
|
203
|
+
json_extract(payload_json, '$.output_tokens') AS output_tokens, json_extract(payload_json, '$.reasoning_tokens') AS reasoning_tokens,
|
|
204
|
+
json_extract(payload_json, '$.total_tokens') AS total_tokens, json_extract(payload_json, '$.cost_usd') AS cost_usd,
|
|
205
|
+
json_extract(payload_json, '$.cost_brl') AS cost_brl FROM legacy_usage_payloads;
|
|
206
|
+
CREATE TEMP TABLE legacy_duration_payloads AS
|
|
207
|
+
SELECT json_object('activity_row_id', activity_row_id, 'occurred_day_sp', occurred_day_sp,
|
|
208
|
+
'attributed_token_active_ms', attributed_token_active_ms) AS payload_json FROM temp.attributed_token_active_facts;
|
|
209
|
+
CREATE TEMP VIEW legacy_duration AS
|
|
210
|
+
SELECT json_extract(payload_json, '$.activity_row_id') AS activity_row_id,
|
|
211
|
+
json_extract(payload_json, '$.attributed_token_active_ms') AS attributed_token_active_ms FROM legacy_duration_payloads;
|
|
212
|
+
CREATE TEMP VIEW legacy_activities AS
|
|
213
|
+
SELECT a.*, f.duration_ms FROM zaip_aios_activities a
|
|
214
|
+
LEFT JOIN (SELECT activity_row_id, SUM(attributed_token_active_ms) AS duration_ms FROM legacy_duration GROUP BY activity_row_id) f USING(activity_row_id)
|
|
215
|
+
WHERE a.payload_type IS NULL;
|
|
216
|
+
CREATE TABLE legacy_cost_invocation_dimension_facts AS
|
|
217
|
+
SELECT a.agent_run_id AS agent_invocation_id, date(COALESCE(a.source_started_at, a.source_occurred_at, a.occurred_at), '-3 hours') AS occurred_day_sp,
|
|
218
|
+
CASE WHEN u.model IS NULL OR trim(u.model)='' OR u.model='unavailable' THEN 'unavailable' ELSE u.model END AS model,
|
|
219
|
+
CASE WHEN u.provider IS NULL OR trim(u.provider)='' OR u.provider='unavailable' THEN 'unavailable' ELSE u.provider END AS provider,
|
|
220
|
+
u.input_tokens, u.cached_input_tokens, u.output_tokens, u.reasoning_tokens, u.total_tokens, u.cost_usd, u.cost_brl, a.duration_ms, 0 AS residual
|
|
221
|
+
FROM legacy_activities a JOIN legacy_usage u ON u.agent_invocation_id=a.agent_run_id
|
|
222
|
+
WHERE a.activity_source_kind='agent_run' AND (u.total_tokens IS NOT NULL OR u.cost_usd IS NOT NULL OR u.cost_brl IS NOT NULL);
|
|
223
|
+
INSERT INTO legacy_cost_invocation_dimension_facts
|
|
224
|
+
SELECT a.agent_run_id, date(COALESCE(a.source_started_at, a.source_occurred_at, a.occurred_at), '-3 hours'), 'unavailable', 'unavailable',
|
|
225
|
+
a.input_tokens-COALESCE(s.input_tokens,0), a.cached_input_tokens-COALESCE(s.cached_input_tokens,0), a.output_tokens-COALESCE(s.output_tokens,0), a.reasoning_tokens-COALESCE(s.reasoning_tokens,0), a.total_tokens-COALESCE(s.total_tokens,0), a.cost_usd-COALESCE(s.cost_usd,0), a.cost_brl-COALESCE(s.cost_brl,0), a.duration_ms, 1
|
|
226
|
+
FROM legacy_activities a LEFT JOIN (
|
|
227
|
+
SELECT agent_invocation_id, SUM(input_tokens) input_tokens, SUM(cached_input_tokens) cached_input_tokens, SUM(output_tokens) output_tokens, SUM(reasoning_tokens) reasoning_tokens, SUM(total_tokens) total_tokens, SUM(cost_usd) cost_usd, SUM(cost_brl) cost_brl
|
|
228
|
+
FROM legacy_cost_invocation_dimension_facts GROUP BY agent_invocation_id
|
|
229
|
+
) s ON s.agent_invocation_id=a.agent_run_id
|
|
230
|
+
WHERE a.activity_source_kind='agent_run' AND (a.total_tokens<>COALESCE(s.total_tokens,0) OR a.cost_usd<>COALESCE(s.cost_usd,0) OR a.cost_brl<>COALESCE(s.cost_brl,0));
|
|
231
|
+
INSERT INTO legacy_cost_invocation_dimension_facts
|
|
232
|
+
SELECT 'activity:' || a.activity_row_id, a.occurred_day_sp, 'unavailable', 'unavailable', a.input_tokens, a.cached_input_tokens, a.output_tokens, a.reasoning_tokens, a.total_tokens, a.cost_usd, a.cost_brl, f.attributed_token_active_ms, 1
|
|
233
|
+
FROM zaip_aios_activities a LEFT JOIN legacy_duration f USING(activity_row_id)
|
|
234
|
+
WHERE a.payload_type IS NULL AND a.activity_source_kind <> 'agent_run'
|
|
235
|
+
AND (a.total_tokens IS NOT NULL OR a.cost_usd IS NOT NULL OR a.cost_brl IS NOT NULL)
|
|
236
|
+
AND NOT EXISTS (SELECT 1 FROM legacy_cost_invocation_dimension_facts d WHERE d.agent_invocation_id='activity:' || a.activity_row_id);
|
|
237
|
+
`;
|
|
238
|
+
|
|
239
|
+
function factRows(database: DatabaseSync, table: string) {
|
|
240
|
+
return database
|
|
241
|
+
.prepare(
|
|
242
|
+
`SELECT * FROM ${table} ORDER BY agent_invocation_id, residual, model, provider, duration_ms`,
|
|
243
|
+
)
|
|
244
|
+
.all();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
describe("cost invocation dimension rebuild", () => {
|
|
248
|
+
it("preserves the legacy JSON numeric round trip before aggregation and residuals", () => {
|
|
249
|
+
const database = databaseWithFinancialFixture();
|
|
250
|
+
database
|
|
251
|
+
.prepare("UPDATE temp.invocation_usage_segments SET cost_usd=?, cost_brl=?")
|
|
252
|
+
.run(0.1 + 0.2, 1234567.8912345679);
|
|
253
|
+
database
|
|
254
|
+
.prepare("UPDATE temp.attributed_token_active_facts SET attributed_token_active_ms=?")
|
|
255
|
+
.run(1234567.8912345679);
|
|
256
|
+
database.exec(legacySql);
|
|
257
|
+
database.exec(rebuildCostInvocationDimensionFactsSql);
|
|
258
|
+
expect(factRows(database, "cost_invocation_dimension_facts")).toEqual(
|
|
259
|
+
factRows(database, "legacy_cost_invocation_dimension_facts"),
|
|
260
|
+
);
|
|
261
|
+
expect(factRows(database, "cost_invocation_dimension_facts")).toContainEqual(
|
|
262
|
+
expect.objectContaining({ residual: 0, cost_usd: 0.3, cost_brl: 1234567.89123457 }),
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("matches the legacy CTAS and both residual inserts while reading TEMP facts", () => {
|
|
267
|
+
const database = databaseWithFinancialFixture();
|
|
268
|
+
database.exec(legacySql);
|
|
269
|
+
database.exec(rebuildCostInvocationDimensionFactsSql);
|
|
270
|
+
expect(factRows(database, "cost_invocation_dimension_facts")).toEqual(
|
|
271
|
+
factRows(database, "legacy_cost_invocation_dimension_facts"),
|
|
272
|
+
);
|
|
273
|
+
expect(factRows(database, "cost_invocation_dimension_facts")).toContainEqual(
|
|
274
|
+
expect.objectContaining({ agent_invocation_id: "activity:ACTV-FIN", duration_ms: 4 }),
|
|
275
|
+
);
|
|
276
|
+
expect(factRows(database, "cost_invocation_dimension_facts")).toContainEqual(
|
|
277
|
+
expect.objectContaining({ agent_invocation_id: "activity:ACTV-FIN", duration_ms: 6 }),
|
|
278
|
+
);
|
|
279
|
+
expect(rebuildCostInvocationDimensionFactsSql).not.toContain("invocation_usage u");
|
|
280
|
+
expect(rebuildCostInvocationDimensionFactsSql).not.toContain("invocations i");
|
|
281
|
+
});
|
|
282
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Financial dimensions are constructed while the canonical rebuild tables are
|
|
3
|
+
* still available. Reusing those TEMP facts avoids reparsing persisted JSON
|
|
4
|
+
* views during the same rebuild without changing the persisted projection.
|
|
5
|
+
*/
|
|
6
|
+
export const rebuildCostInvocationDimensionFactsSql = `
|
|
7
|
+
-- Preserve the numeric representation of the old json_object/json_extract
|
|
8
|
+
-- payload path once per input, before sums. Raw REALs can differ at the last
|
|
9
|
+
-- significant digits; removing JSON round trips must not change finances.
|
|
10
|
+
CREATE TEMP TABLE cost_dimension_duration AS
|
|
11
|
+
SELECT activity_row_id, occurred_day_sp,
|
|
12
|
+
json_extract(json_object('v', attributed_token_active_ms), '$.v') AS attributed_token_active_ms
|
|
13
|
+
FROM temp.attributed_token_active_facts;
|
|
14
|
+
CREATE INDEX cost_dimension_duration_activity ON cost_dimension_duration(activity_row_id);
|
|
15
|
+
CREATE TEMP TABLE cost_dimension_duration_by_activity AS
|
|
16
|
+
SELECT activity_row_id, SUM(attributed_token_active_ms) AS duration_ms
|
|
17
|
+
FROM cost_dimension_duration GROUP BY activity_row_id;
|
|
18
|
+
CREATE INDEX cost_dimension_duration_by_activity_row
|
|
19
|
+
ON cost_dimension_duration_by_activity(activity_row_id);
|
|
20
|
+
CREATE TEMP TABLE cost_dimension_usage AS
|
|
21
|
+
SELECT agent_invocation_id, provider, model,
|
|
22
|
+
json_extract(json_object('v', input_tokens), '$.v') AS input_tokens,
|
|
23
|
+
json_extract(json_object('v', cached_input_tokens), '$.v') AS cached_input_tokens,
|
|
24
|
+
json_extract(json_object('v', output_tokens), '$.v') AS output_tokens,
|
|
25
|
+
json_extract(json_object('v', reasoning_tokens), '$.v') AS reasoning_tokens,
|
|
26
|
+
json_extract(json_object('v', total_tokens), '$.v') AS total_tokens,
|
|
27
|
+
json_extract(json_object('v', cost_usd), '$.v') AS cost_usd,
|
|
28
|
+
json_extract(json_object('v', cost_brl), '$.v') AS cost_brl
|
|
29
|
+
FROM temp.invocation_usage_segments;
|
|
30
|
+
CREATE INDEX cost_dimension_usage_invocation ON cost_dimension_usage(agent_invocation_id);
|
|
31
|
+
CREATE TABLE cost_invocation_dimension_facts AS
|
|
32
|
+
SELECT a.agent_run_id AS agent_invocation_id,
|
|
33
|
+
date(COALESCE(a.source_started_at, a.source_occurred_at, a.occurred_at), '-3 hours') AS occurred_day_sp,
|
|
34
|
+
CASE WHEN u.model IS NULL OR trim(u.model)='' OR u.model='unavailable' THEN 'unavailable' ELSE u.model END AS model,
|
|
35
|
+
CASE WHEN u.provider IS NULL OR trim(u.provider)='' OR u.provider='unavailable' THEN 'unavailable' ELSE u.provider END AS provider,
|
|
36
|
+
u.input_tokens, u.cached_input_tokens, u.output_tokens, u.reasoning_tokens,
|
|
37
|
+
u.total_tokens, u.cost_usd, u.cost_brl, d.duration_ms, 0 AS residual
|
|
38
|
+
FROM zaip_aios_activities a
|
|
39
|
+
JOIN cost_dimension_usage u ON u.agent_invocation_id=a.agent_run_id
|
|
40
|
+
LEFT JOIN cost_dimension_duration_by_activity d USING(activity_row_id)
|
|
41
|
+
WHERE a.payload_type IS NULL AND a.activity_source_kind='agent_run'
|
|
42
|
+
AND (u.total_tokens IS NOT NULL OR u.cost_usd IS NOT NULL OR u.cost_brl IS NOT NULL);
|
|
43
|
+
CREATE INDEX cost_dimension_facts_day_model ON cost_invocation_dimension_facts(occurred_day_sp, model);
|
|
44
|
+
CREATE INDEX cost_dimension_facts_day_provider ON cost_invocation_dimension_facts(occurred_day_sp, provider);
|
|
45
|
+
CREATE INDEX cost_dimension_facts_invocation ON cost_invocation_dimension_facts(agent_invocation_id);
|
|
46
|
+
INSERT INTO cost_invocation_dimension_facts
|
|
47
|
+
SELECT a.agent_run_id, date(COALESCE(a.source_started_at, a.source_occurred_at, a.occurred_at), '-3 hours'), 'unavailable', 'unavailable',
|
|
48
|
+
a.input_tokens-COALESCE(s.input_tokens,0), a.cached_input_tokens-COALESCE(s.cached_input_tokens,0),
|
|
49
|
+
a.output_tokens-COALESCE(s.output_tokens,0), a.reasoning_tokens-COALESCE(s.reasoning_tokens,0),
|
|
50
|
+
a.total_tokens-COALESCE(s.total_tokens,0), a.cost_usd-COALESCE(s.cost_usd,0),
|
|
51
|
+
a.cost_brl-COALESCE(s.cost_brl,0), d.duration_ms, 1
|
|
52
|
+
FROM zaip_aios_activities a
|
|
53
|
+
LEFT JOIN (
|
|
54
|
+
SELECT agent_invocation_id, SUM(input_tokens) input_tokens, SUM(cached_input_tokens) cached_input_tokens,
|
|
55
|
+
SUM(output_tokens) output_tokens, SUM(reasoning_tokens) reasoning_tokens, SUM(total_tokens) total_tokens,
|
|
56
|
+
SUM(cost_usd) cost_usd, SUM(cost_brl) cost_brl
|
|
57
|
+
FROM cost_invocation_dimension_facts GROUP BY agent_invocation_id
|
|
58
|
+
) s ON s.agent_invocation_id=a.agent_run_id
|
|
59
|
+
LEFT JOIN cost_dimension_duration_by_activity d USING(activity_row_id)
|
|
60
|
+
WHERE a.payload_type IS NULL AND a.activity_source_kind='agent_run'
|
|
61
|
+
AND (a.total_tokens<>COALESCE(s.total_tokens,0) OR a.cost_usd<>COALESCE(s.cost_usd,0) OR a.cost_brl<>COALESCE(s.cost_brl,0));
|
|
62
|
+
INSERT INTO cost_invocation_dimension_facts
|
|
63
|
+
SELECT 'activity:' || a.activity_row_id, a.occurred_day_sp, 'unavailable', 'unavailable',
|
|
64
|
+
a.input_tokens, a.cached_input_tokens, a.output_tokens, a.reasoning_tokens,
|
|
65
|
+
a.total_tokens, a.cost_usd, a.cost_brl, f.attributed_token_active_ms, 1
|
|
66
|
+
FROM zaip_aios_activities a
|
|
67
|
+
LEFT JOIN cost_dimension_duration f USING(activity_row_id)
|
|
68
|
+
WHERE a.payload_type IS NULL AND a.activity_source_kind <> 'agent_run'
|
|
69
|
+
AND (a.total_tokens IS NOT NULL OR a.cost_usd IS NOT NULL OR a.cost_brl IS NOT NULL)
|
|
70
|
+
AND NOT EXISTS (SELECT 1 FROM cost_invocation_dimension_facts f WHERE f.agent_invocation_id='activity:' || a.activity_row_id);
|
|
71
|
+
`;
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-launch-progress.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const launchProgressStartedAt = performance.now();
|
|
2
|
+
|
|
3
|
+
export function reportSqliteReadModelLaunchProgress(
|
|
4
|
+
phase: string,
|
|
5
|
+
percent: number,
|
|
6
|
+
detail: string,
|
|
7
|
+
): void {
|
|
8
|
+
if (process.env.ZAIP_DASHBOARD_LAUNCH_PROGRESS !== "1") return;
|
|
9
|
+
process.stderr.write(
|
|
10
|
+
`${JSON.stringify({
|
|
11
|
+
event: "dashboard_sqlite_rebuild_progress",
|
|
12
|
+
phase,
|
|
13
|
+
percent,
|
|
14
|
+
detail,
|
|
15
|
+
elapsed_ms: Math.round(performance.now() - launchProgressStartedAt),
|
|
16
|
+
})}\n`,
|
|
17
|
+
);
|
|
18
|
+
}
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-stale-seed.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
3
|
+
import { reportSqliteReadModelLaunchProgress } from "./sqlite-read-model-launch-progress.js";
|
|
4
|
+
import { materializeSnapshot, mostRecentCompatibleSnapshot } from "./sqlite-snapshot-cache.js";
|
|
5
|
+
|
|
6
|
+
type PreferredStaleSeed = {
|
|
7
|
+
files: number;
|
|
8
|
+
path: string;
|
|
9
|
+
cache: "stale_seed";
|
|
10
|
+
fingerprint_ms: number;
|
|
11
|
+
materialize_ms: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function materializePreferredStaleSeed(input: {
|
|
15
|
+
destination: string;
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
fingerprintMs: number;
|
|
18
|
+
schemaVersion: string;
|
|
19
|
+
hasRequiredPayloads: (database: DatabaseSync) => boolean;
|
|
20
|
+
reportProgress?: boolean;
|
|
21
|
+
}): Promise<PreferredStaleSeed | null> {
|
|
22
|
+
if (!input.enabled) return null;
|
|
23
|
+
if (input.reportProgress)
|
|
24
|
+
reportSqliteReadModelLaunchProgress(
|
|
25
|
+
"stale_seed_probe",
|
|
26
|
+
4,
|
|
27
|
+
"Verificando o último seed SQLite compatível.",
|
|
28
|
+
);
|
|
29
|
+
const fallback = await mostRecentCompatibleSnapshot(
|
|
30
|
+
process.env.ZAIP_SQLITE_CACHE_DIR ?? join(dirname(input.destination), "cache"),
|
|
31
|
+
input.schemaVersion,
|
|
32
|
+
input.hasRequiredPayloads,
|
|
33
|
+
);
|
|
34
|
+
if (fallback === null) return null;
|
|
35
|
+
const materializeStartedAt = performance.now();
|
|
36
|
+
await materializeSnapshot(fallback.path, input.destination);
|
|
37
|
+
if (input.reportProgress)
|
|
38
|
+
reportSqliteReadModelLaunchProgress(
|
|
39
|
+
"stale_seed_ready",
|
|
40
|
+
18,
|
|
41
|
+
"Seed SQLite compatível materializado.",
|
|
42
|
+
);
|
|
43
|
+
return {
|
|
44
|
+
files: fallback.files,
|
|
45
|
+
path: input.destination,
|
|
46
|
+
cache: "stale_seed",
|
|
47
|
+
fingerprint_ms: input.fingerprintMs,
|
|
48
|
+
materialize_ms: Math.round(performance.now() - materializeStartedAt),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -1179,12 +1179,15 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1179
1179
|
const snapshot = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
|
|
1180
1180
|
readOnly: true,
|
|
1181
1181
|
});
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1182
|
+
try {
|
|
1183
|
+
expect(
|
|
1184
|
+
snapshot
|
|
1185
|
+
.prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key='schema_version'")
|
|
1186
|
+
.get(),
|
|
1187
|
+
).toEqual({ value: "71" });
|
|
1188
|
+
} finally {
|
|
1189
|
+
snapshot.close();
|
|
1190
|
+
}
|
|
1188
1191
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
1189
1192
|
try {
|
|
1190
1193
|
expect(filesystem.viewPage("operations_work_kanban", { limit: 20 }).rows).toEqual([
|