@zaip-ai/cli 4.6.0 → 4.7.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.
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/services/adapters.d.ts +1 -1
- package/dist/services/adapters.d.ts.map +1 -1
- package/dist/services/adapters.js +3 -3
- package/dist/services/adapters.js.map +1 -1
- package/dist/services/codex-config-overlay.d.ts.map +1 -1
- package/dist/services/codex-config-overlay.js +27 -10
- package/dist/services/codex-config-overlay.js.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.test.js +1 -1
- package/dist/services/codex-pre-tool-hook-template.test.js.map +1 -1
- package/dist/services/global-codex-config.d.ts.map +1 -1
- package/dist/services/global-codex-config.js +2 -1
- package/dist/services/global-codex-config.js.map +1 -1
- package/dist/services/global-codex-config.test.js +3 -1
- package/dist/services/global-codex-config.test.js.map +1 -1
- package/dist/services/hook-readiness.d.ts.map +1 -1
- package/dist/services/hook-readiness.js.map +1 -1
- package/dist/services/install-agents-template.js +2 -2
- package/dist/services/install-agents-template.js.map +1 -1
- package/dist/services/logger.d.ts +1 -1
- package/dist/services/logger.d.ts.map +1 -1
- package/dist/services/logger.js.map +1 -1
- package/dist/services/logger.test.js +9 -3
- package/dist/services/logger.test.js.map +1 -1
- package/dist/services/runtime-template-integrity.test.d.ts +2 -0
- package/dist/services/runtime-template-integrity.test.d.ts.map +1 -0
- package/dist/services/runtime-template-integrity.test.js +26 -0
- package/dist/services/runtime-template-integrity.test.js.map +1 -0
- package/dist/services/runtime-template-test-support.d.ts.map +1 -1
- package/dist/services/runtime-template-test-support.js.map +1 -1
- package/dist/services/runtime-template.test.js +18 -21
- package/dist/services/runtime-template.test.js.map +1 -1
- package/package.json +1 -1
- package/templates/.agents/config/agents/discovery.json +1 -1
- package/templates/.agents/dashboard/.zaip-managed.json +62 -46
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-BRtiPijr.js → CostCalculationGuidePage-OUjdwEcM.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-BR4ZeYpE.js → DashboardHelpDialog-Cei1ChjE.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Dr4QDFmn.js → PricingSettingsDialog-_woNCrTT.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-BG0N5dw_.js → ProjectSettingsPage-B2_7MVOP.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-BvoM-YQ0.js → TraceabilityWorkspace-C_jCsSZe.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{cost-monitor-fTQhSL85.js → cost-monitor-C8zQDBT7.js} +2 -2
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-Bc6vux5t.js → icons-vendor-iMPXot7Y.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{index-BMfzKaAR.js → index-DiCwz0sr.js} +2 -2
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-DNJQFov3.js → react-vendor-721Re3Ss.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-B7tjIB7W.js → traceability-BjdTkWS0.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
- package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
- package/templates/.agents/dashboard/modules/operations/package.json +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +7 -2
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +6 -6
- package/templates/.agents/dashboard/modules/operations/src/react/overview-duration-hint.ts +14 -0
- package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
- package/templates/.agents/dashboard/packages/branding/package.json +1 -1
- package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
- package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +238 -171
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +227 -160
- package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +240 -173
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-summary-elapsed.ts +107 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-summary.ts +41 -54
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +7 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-counts-every-root-execution-day-returns.test.ts +5 -5
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +4 -4
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-schema.ts +3 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-base-views.ts +9 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-dashboard-views.ts +10 -8
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-spec-root-elapsed-view.ts +61 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-spec-root-elapsed.test.ts +210 -0
- package/templates/.agents/dashboard/packages/ui/package.json +1 -1
- package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
- package/templates/.agents/design/.zaip-managed.json +3 -3
- package/templates/.agents/design/apps/catalog/package.json +1 -1
- package/templates/.agents/design/packages/local-runtime/package.json +1 -1
- package/templates/.agents/requirements/autonomous-assurance.md +1 -1
- package/templates/.agents/requirements/cloud-hostinger-autonomy.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/VERSION +1 -1
- package/templates/.agents/runtime/bin/zaip.mjs +9 -10
- package/templates/.agents/runtime/checksums.sha256 +5 -5
- package/templates/.agents/runtime/manifest.json +1 -1
- package/templates/.agents/runtime/provenance.json +4 -4
- package/templates/.agents/runtime/sbom.cdx.json +1 -1
- package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +2 -0
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.mjs +6 -2
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.test.mjs +3 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +2 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +9 -0
- package/templates/.agents/zaip-aios/VERSION +1 -1
- package/templates/template-manifest.json +96 -80
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { SqliteQueryContext } from "./sqlite-query-context.js";
|
|
2
|
+
|
|
3
|
+
type DailyElapsed = { known_sum: number; eligible_runs: number; known_runs: number };
|
|
4
|
+
|
|
5
|
+
export function costSummaryElapsedByDay(
|
|
6
|
+
database: SqliteQueryContext["database"],
|
|
7
|
+
from: string | null,
|
|
8
|
+
to: string | null,
|
|
9
|
+
): Map<string, DailyElapsed> {
|
|
10
|
+
const rows = database
|
|
11
|
+
.prepare(`SELECT day, cost_monitor_total_duration AS duration_ms,
|
|
12
|
+
cost_monitor_duration_eligible_runs AS eligible_runs,
|
|
13
|
+
cost_monitor_duration_known_runs AS known_runs
|
|
14
|
+
FROM zaip_vw_daily_aggregates
|
|
15
|
+
WHERE (? IS NULL OR day >= ?) AND (? IS NULL OR day <= ?)`)
|
|
16
|
+
.all(from, from, to, to) as Array<Record<string, unknown>>;
|
|
17
|
+
const result = new Map<string, DailyElapsed>();
|
|
18
|
+
for (const row of rows) {
|
|
19
|
+
const eligible = Number(row.eligible_runs ?? 0);
|
|
20
|
+
if (typeof row.duration_ms !== "number" && eligible === 0) continue;
|
|
21
|
+
result.set(String(row.day), {
|
|
22
|
+
known_sum: typeof row.duration_ms === "number" ? row.duration_ms : 0,
|
|
23
|
+
eligible_runs: eligible,
|
|
24
|
+
known_runs: Number(row.known_runs ?? 0),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Apply dimension filters before unioning observed source intervals by local day. */
|
|
31
|
+
export function filteredCostSummaryElapsedByDay(
|
|
32
|
+
database: SqliteQueryContext["database"],
|
|
33
|
+
from: string | null,
|
|
34
|
+
to: string | null,
|
|
35
|
+
dimensionClauses: readonly string[],
|
|
36
|
+
dimensionValues: readonly (string | number | null)[],
|
|
37
|
+
): Map<string, DailyElapsed> {
|
|
38
|
+
const rows = database
|
|
39
|
+
.prepare(`SELECT a.activity_row_id AS id, a.source_started_at AS started_at,
|
|
40
|
+
a.source_finished_at AS finished_at, a.source_occurred_at AS source_at,
|
|
41
|
+
a.occurred_at AS occurred_at
|
|
42
|
+
FROM activities a
|
|
43
|
+
WHERE (a.total_tokens IS NOT NULL OR a.cost_usd IS NOT NULL OR a.cost_brl IS NOT NULL)
|
|
44
|
+
${dimensionClauses.map((clause) => `AND ${clause}`).join("\n")}`)
|
|
45
|
+
.all(...dimensionValues) as Array<{
|
|
46
|
+
id: number;
|
|
47
|
+
started_at: string | null;
|
|
48
|
+
finished_at: string | null;
|
|
49
|
+
source_at: string | null;
|
|
50
|
+
occurred_at: string | null;
|
|
51
|
+
}>;
|
|
52
|
+
const threeHours = 3 * 60 * 60 * 1000;
|
|
53
|
+
const localDay = (ms: number) => new Date(ms - threeHours).toISOString().slice(0, 10);
|
|
54
|
+
const inRange = (day: string) => (from === null || day >= from) && (to === null || day <= to);
|
|
55
|
+
const byDay = new Map<
|
|
56
|
+
string,
|
|
57
|
+
{ intervals: Array<[number, number]>; eligible: Set<number>; known: Set<number> }
|
|
58
|
+
>();
|
|
59
|
+
const bucket = (day: string) => {
|
|
60
|
+
let value = byDay.get(day);
|
|
61
|
+
if (value === undefined) {
|
|
62
|
+
value = { intervals: [], eligible: new Set(), known: new Set() };
|
|
63
|
+
byDay.set(day, value);
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
};
|
|
67
|
+
for (const row of rows) {
|
|
68
|
+
const start = row.started_at === null ? Number.NaN : Date.parse(row.started_at);
|
|
69
|
+
const end = row.finished_at === null ? Number.NaN : Date.parse(row.finished_at);
|
|
70
|
+
if (Number.isFinite(start) && Number.isFinite(end) && end > start) {
|
|
71
|
+
for (let segmentStart = start; segmentStart < end; ) {
|
|
72
|
+
const day = localDay(segmentStart);
|
|
73
|
+
const segmentEnd = Math.min(end, Date.parse(`${day}T03:00:00.000Z`) + 86_400_000);
|
|
74
|
+
if (inRange(day)) {
|
|
75
|
+
const value = bucket(day);
|
|
76
|
+
value.intervals.push([segmentStart, segmentEnd]);
|
|
77
|
+
value.eligible.add(row.id);
|
|
78
|
+
value.known.add(row.id);
|
|
79
|
+
}
|
|
80
|
+
segmentStart = segmentEnd;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
const occurred = row.started_at ?? row.source_at ?? row.occurred_at;
|
|
84
|
+
if (occurred === null) continue;
|
|
85
|
+
const occurredMs = Date.parse(occurred);
|
|
86
|
+
if (!Number.isFinite(occurredMs)) continue;
|
|
87
|
+
const day = localDay(occurredMs);
|
|
88
|
+
if (inRange(day)) bucket(day).eligible.add(row.id);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const result = new Map<string, DailyElapsed>();
|
|
92
|
+
for (const [day, value] of byDay) {
|
|
93
|
+
const sorted = value.intervals.sort((a, b) => a[0] - b[0]);
|
|
94
|
+
let total = 0;
|
|
95
|
+
let mergedEnd = Number.NEGATIVE_INFINITY;
|
|
96
|
+
for (const [start, end] of sorted) {
|
|
97
|
+
total += Math.max(0, end - Math.max(start, mergedEnd));
|
|
98
|
+
mergedEnd = Math.max(mergedEnd, end);
|
|
99
|
+
}
|
|
100
|
+
result.set(day, {
|
|
101
|
+
known_sum: Math.round(total),
|
|
102
|
+
eligible_runs: value.eligible.size,
|
|
103
|
+
known_runs: value.known.size,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { CostSummarySource } from "@zaip-ai/dashboard-cost-monitor/server";
|
|
2
2
|
import { artifactStructuralRowsSql } from "./sqlite-artifact-counts.js";
|
|
3
3
|
import { buildCostSummaryDetails } from "./sqlite-cost-summary-details.js";
|
|
4
|
+
import {
|
|
5
|
+
costSummaryElapsedByDay,
|
|
6
|
+
filteredCostSummaryElapsedByDay,
|
|
7
|
+
} from "./sqlite-cost-summary-elapsed.js";
|
|
4
8
|
import type { SqliteQueryContext } from "./sqlite-query-context.js";
|
|
5
9
|
import { costMonitorFilterDay } from "./sqlite-read-model-canonical.js";
|
|
6
10
|
import type { SqliteReadModelFileSystem } from "./sqlite-read-model-filesystem.js";
|
|
@@ -11,21 +15,8 @@ export function queryCostMonitorSummaryAggregate(
|
|
|
11
15
|
const { from, to, providers = [], models = [] } = filter;
|
|
12
16
|
const sourceFrom = costMonitorFilterDay(from);
|
|
13
17
|
const sourceTo = costMonitorFilterDay(to);
|
|
14
|
-
const
|
|
15
|
-
const generationCached = context.costMonitorSummaryCache.get(cacheKey);
|
|
16
|
-
if (generationCached !== undefined) return structuredClone(generationCached);
|
|
17
|
-
const remember = (value: CostSummarySource) => {
|
|
18
|
-
if (context.costMonitorSummaryCache.size >= 64) {
|
|
19
|
-
const oldest = context.costMonitorSummaryCache.keys().next().value as string | undefined;
|
|
20
|
-
if (oldest !== undefined) context.costMonitorSummaryCache.delete(oldest);
|
|
21
|
-
}
|
|
22
|
-
context.costMonitorSummaryCache.set(cacheKey, structuredClone(value));
|
|
23
|
-
return structuredClone(value);
|
|
24
|
-
};
|
|
25
|
-
const unfilteredAllTime =
|
|
18
|
+
const noDimensionFilters =
|
|
26
19
|
!filter.query &&
|
|
27
|
-
sourceFrom === null &&
|
|
28
|
-
sourceTo === null &&
|
|
29
20
|
[
|
|
30
21
|
providers,
|
|
31
22
|
models,
|
|
@@ -41,7 +32,19 @@ export function queryCostMonitorSummaryAggregate(
|
|
|
41
32
|
filter.risks,
|
|
42
33
|
filter.origins,
|
|
43
34
|
filter.workTypes,
|
|
44
|
-
].every((
|
|
35
|
+
].every((items) => items === undefined || items.length === 0);
|
|
36
|
+
const cacheKey = JSON.stringify({ ...filter, from: sourceFrom, to: sourceTo });
|
|
37
|
+
const generationCached = context.costMonitorSummaryCache.get(cacheKey);
|
|
38
|
+
if (generationCached !== undefined) return structuredClone(generationCached);
|
|
39
|
+
const remember = (value: CostSummarySource) => {
|
|
40
|
+
if (context.costMonitorSummaryCache.size >= 64) {
|
|
41
|
+
const oldest = context.costMonitorSummaryCache.keys().next().value as string | undefined;
|
|
42
|
+
if (oldest !== undefined) context.costMonitorSummaryCache.delete(oldest);
|
|
43
|
+
}
|
|
44
|
+
context.costMonitorSummaryCache.set(cacheKey, structuredClone(value));
|
|
45
|
+
return structuredClone(value);
|
|
46
|
+
};
|
|
47
|
+
const unfilteredAllTime = noDimensionFilters && sourceFrom === null && sourceTo === null;
|
|
45
48
|
if (unfilteredAllTime) {
|
|
46
49
|
const cached = context.database
|
|
47
50
|
.prepare(
|
|
@@ -55,27 +58,7 @@ export function queryCostMonitorSummaryAggregate(
|
|
|
55
58
|
if (summary.filters_available !== undefined) return remember(summary);
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
|
-
if (
|
|
59
|
-
!filter.query &&
|
|
60
|
-
sourceFrom !== null &&
|
|
61
|
-
sourceTo !== null &&
|
|
62
|
-
[
|
|
63
|
-
providers,
|
|
64
|
-
models,
|
|
65
|
-
filter.agents,
|
|
66
|
-
filter.phases,
|
|
67
|
-
filter.statuses,
|
|
68
|
-
filter.tasks,
|
|
69
|
-
filter.specs,
|
|
70
|
-
filter.prds,
|
|
71
|
-
filter.executions,
|
|
72
|
-
filter.changes,
|
|
73
|
-
filter.priorities,
|
|
74
|
-
filter.risks,
|
|
75
|
-
filter.origins,
|
|
76
|
-
filter.workTypes,
|
|
77
|
-
].every((values) => values === undefined || values.length === 0)
|
|
78
|
-
) {
|
|
61
|
+
if (noDimensionFilters && sourceFrom !== null && sourceTo !== null) {
|
|
79
62
|
const cached = context.database
|
|
80
63
|
.prepare(
|
|
81
64
|
"SELECT payload_json FROM zaip_aios_activities WHERE payload_type='cost_monitor_summary_month_cache' ORDER BY recorded_at DESC LIMIT 1",
|
|
@@ -384,12 +367,25 @@ export function queryCostMonitorSummaryAggregate(
|
|
|
384
367
|
);
|
|
385
368
|
const financialByDay = new Map(dailyRows.map((row) => [String(row.key), row]));
|
|
386
369
|
const structuralByDay = new Map(structuralRows.map((row) => [String(row.day), row]));
|
|
387
|
-
|
|
370
|
+
// Financial events belong to their source start day. Elapsed wall time
|
|
371
|
+
// belongs to every local day actually crossed by its observed interval.
|
|
372
|
+
const elapsedByDay = noDimensionFilters
|
|
373
|
+
? costSummaryElapsedByDay(context.database, sourceFrom, sourceTo)
|
|
374
|
+
: filteredCostSummaryElapsedByDay(
|
|
375
|
+
context.database,
|
|
376
|
+
sourceFrom,
|
|
377
|
+
sourceTo,
|
|
378
|
+
clauses.slice(2),
|
|
379
|
+
values.slice(4),
|
|
380
|
+
);
|
|
381
|
+
const days = [
|
|
382
|
+
...new Set([...financialByDay.keys(), ...structuralByDay.keys(), ...elapsedByDay.keys()]),
|
|
383
|
+
].sort();
|
|
388
384
|
const compactDailyRows = days.map((day) => {
|
|
389
385
|
const financial = financialByDay.get(day);
|
|
390
386
|
const structural = structuralByDay.get(day);
|
|
391
387
|
const eligible = number(financial?.eligible_runs);
|
|
392
|
-
const
|
|
388
|
+
const elapsed = elapsedByDay.get(day);
|
|
393
389
|
return {
|
|
394
390
|
key: day,
|
|
395
391
|
prd_count: number(structural?.prd_count),
|
|
@@ -398,9 +394,12 @@ export function queryCostMonitorSummaryAggregate(
|
|
|
398
394
|
validation_count: number(structural?.validation_count),
|
|
399
395
|
evidence_count: number(structural?.evidence_count),
|
|
400
396
|
total_run_count: eligible,
|
|
401
|
-
total_duration:
|
|
402
|
-
duration_known:
|
|
403
|
-
duration_unknown: Math.max(
|
|
397
|
+
total_duration: elapsed?.known_runs ? elapsed.known_sum : null,
|
|
398
|
+
duration_known: elapsed?.known_sum ?? 0,
|
|
399
|
+
duration_unknown: Math.max(
|
|
400
|
+
0,
|
|
401
|
+
(elapsed?.eligible_runs ?? eligible) - (elapsed?.known_runs ?? 0),
|
|
402
|
+
),
|
|
404
403
|
total_tokens: nullable(financial?.total_tokens),
|
|
405
404
|
total_cost_usd: nullable(financial?.cost_usd),
|
|
406
405
|
total_cost_brl: nullable(financial?.cost_brl),
|
|
@@ -447,19 +446,7 @@ export function queryCostMonitorSummaryAggregate(
|
|
|
447
446
|
];
|
|
448
447
|
}),
|
|
449
448
|
);
|
|
450
|
-
const durations = Object.fromEntries(
|
|
451
|
-
dailyRows.map((row) => {
|
|
452
|
-
const value = metric(row);
|
|
453
|
-
return [
|
|
454
|
-
String(row.key),
|
|
455
|
-
{
|
|
456
|
-
known_sum: number(row.duration_ms),
|
|
457
|
-
eligible_runs: value._duration_population.eligible_runs,
|
|
458
|
-
known_runs: value._duration_population.known_runs,
|
|
459
|
-
},
|
|
460
|
-
];
|
|
461
|
-
}),
|
|
462
|
-
);
|
|
449
|
+
const durations = Object.fromEntries(elapsedByDay);
|
|
463
450
|
const { model_groups, filters_available } = buildCostSummaryDetails(
|
|
464
451
|
context,
|
|
465
452
|
selected,
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts
CHANGED
|
@@ -26,11 +26,13 @@ import {
|
|
|
26
26
|
} from "@zaip-ai/costs";
|
|
27
27
|
import type { RunV2Fold, UsageRecordedV2 } from "../../../../../packages/decisions/src/index.js";
|
|
28
28
|
import { saoPauloDay } from "./sqlite-calendar.js";
|
|
29
|
+
import {
|
|
30
|
+
MAX_RECONCILED_RUN_INTERVAL_MS,
|
|
31
|
+
MAX_SOURCE_INTERVAL_MS,
|
|
32
|
+
} from "./sqlite-read-model-schema.js";
|
|
29
33
|
|
|
30
34
|
export { saoPauloDay } from "./sqlite-calendar.js";
|
|
31
35
|
|
|
32
|
-
const MAX_RECONCILED_RUN_INTERVAL_MS = 2 * 3_600_000;
|
|
33
|
-
|
|
34
36
|
export function saoPauloCurrentMonth(): { from: string; to: string } {
|
|
35
37
|
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
36
38
|
timeZone: "America/Sao_Paulo",
|
|
@@ -362,9 +364,7 @@ export function factualDuration(record: UsageRecordedV2): boolean {
|
|
|
362
364
|
export type ResolvedSourceInterval = { start: string; end: string; duration: number };
|
|
363
365
|
|
|
364
366
|
/**
|
|
365
|
-
*
|
|
366
|
-
* happened. It wins over Run finalization elapsed time, which may include
|
|
367
|
-
* orchestration/capture lag or be recorded much later.
|
|
367
|
+
* Observed source boundaries outrank delayed administrative Run finalization.
|
|
368
368
|
*/
|
|
369
369
|
export function resolvedSourceInterval(
|
|
370
370
|
records: readonly UsageRecordedV2[],
|
|
@@ -379,7 +379,7 @@ export function resolvedSourceInterval(
|
|
|
379
379
|
Number.isFinite(startMs) &&
|
|
380
380
|
Number.isFinite(endMs) &&
|
|
381
381
|
endMs > startMs &&
|
|
382
|
-
endMs - startMs <=
|
|
382
|
+
endMs - startMs <= MAX_SOURCE_INTERVAL_MS
|
|
383
383
|
? [{ start, end, startMs, endMs }]
|
|
384
384
|
: [];
|
|
385
385
|
});
|
|
@@ -390,7 +390,7 @@ export function resolvedSourceInterval(
|
|
|
390
390
|
const end = intervals.reduce((latest, interval) =>
|
|
391
391
|
interval.endMs > latest.endMs ? interval : latest,
|
|
392
392
|
);
|
|
393
|
-
return end.endMs - start.startMs <=
|
|
393
|
+
return end.endMs - start.startMs <= MAX_SOURCE_INTERVAL_MS
|
|
394
394
|
? { start: start.start, end: end.end, duration: end.endMs - start.startMs }
|
|
395
395
|
: null;
|
|
396
396
|
}
|
|
@@ -49,7 +49,7 @@ describe("SQLite dashboard read model", () => {
|
|
|
49
49
|
expect.objectContaining({
|
|
50
50
|
id: "SPEC-B",
|
|
51
51
|
invocation_count: 2,
|
|
52
|
-
total_duration:
|
|
52
|
+
total_duration: 2_400_000,
|
|
53
53
|
total_tokens: 4,
|
|
54
54
|
total_cost_brl: 10,
|
|
55
55
|
}),
|
|
@@ -189,13 +189,13 @@ describe("SQLite dashboard read model", () => {
|
|
|
189
189
|
status_counts: { planning: 3 },
|
|
190
190
|
classification_counts: { structured: 2 },
|
|
191
191
|
total_run_count: 3,
|
|
192
|
-
total_duration_ms:
|
|
192
|
+
total_duration_ms: 3_000_000,
|
|
193
193
|
total_tokens: 6,
|
|
194
194
|
total_cost_brl: 15,
|
|
195
|
-
average_duration_ms:
|
|
195
|
+
average_duration_ms: 1_000_000,
|
|
196
196
|
});
|
|
197
197
|
expect(allTime.macro_metrics.specs.top_entities.slice(0, 2)).toMatchObject([
|
|
198
|
-
{ rank: 1, entity_id: "SPEC-B", total_duration_ms:
|
|
198
|
+
{ rank: 1, entity_id: "SPEC-B", total_duration_ms: 2_400_000 },
|
|
199
199
|
{ rank: 2, entity_id: "SPEC-A", total_duration_ms: 600_000 },
|
|
200
200
|
]);
|
|
201
201
|
expect(allTime.macro_metrics.prds).toMatchObject({
|
|
@@ -314,7 +314,7 @@ describe("SQLite dashboard read model", () => {
|
|
|
314
314
|
expect(pagedDailyCostPage.totals).toMatchObject({
|
|
315
315
|
total_tokens: dailyCostRows.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0),
|
|
316
316
|
total_cost_brl: dailyCostRows.reduce((sum, row) => sum + Number(row.total_cost_brl ?? 0), 0),
|
|
317
|
-
total_duration:
|
|
317
|
+
total_duration: null,
|
|
318
318
|
});
|
|
319
319
|
expect(annualCostPage).toMatchObject({
|
|
320
320
|
total_count: 1,
|
|
@@ -130,10 +130,10 @@ describe("SQLite dashboard read model multi-provider", () => {
|
|
|
130
130
|
expect(
|
|
131
131
|
allAgentGroups.rows.reduce((total, row) => total + Number(row.total_cost_usd ?? 0), 0),
|
|
132
132
|
).toBe(allCostTotals.total_cost_usd);
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
expect(allCostTotals.cost_monitor_total_duration).toBe(
|
|
133
|
+
// The calendar overview uses three observed one-minute source intervals.
|
|
134
|
+
// The agent table reports 120 seconds attributable to token-active facts;
|
|
135
|
+
// it does not assign the remaining source elapsed minute to an Agent.
|
|
136
|
+
expect(allCostTotals.cost_monitor_total_duration).toBe(180_000);
|
|
137
137
|
expect(allAgentGroups.totals).toMatchObject({
|
|
138
138
|
invocation_count: allCostTotals.total_run_count,
|
|
139
139
|
total_duration: 120_000,
|
|
@@ -7,7 +7,7 @@ export const dbRelativePath = ".local/sqlite/zaip-aios-dashboard.sqlite";
|
|
|
7
7
|
// Schema 83 adds canonical priority, Run work type and reconciled macro stages.
|
|
8
8
|
// Old snapshots must rebuild even when their canonical hashes still match.
|
|
9
9
|
// Refresh persisted first-fold summaries after factual duration/coverage semantics change.
|
|
10
|
-
export const readModelSchemaVersion = "
|
|
10
|
+
export const readModelSchemaVersion = "85";
|
|
11
11
|
export const requiredPersistedTables = [
|
|
12
12
|
"zaip_aios_activities",
|
|
13
13
|
"zaip_dim_llm_model",
|
|
@@ -51,6 +51,8 @@ export const requiredViews = [
|
|
|
51
51
|
"zaip_vw_operations_agent_invocations",
|
|
52
52
|
] as const;
|
|
53
53
|
export const MAX_RECONCILED_RUN_INTERVAL_MS = 2 * 3_600_000;
|
|
54
|
+
/** Explicit source observations can span a workday; inferred Run pairs cannot. */
|
|
55
|
+
export const MAX_SOURCE_INTERVAL_MS = 48 * 3_600_000;
|
|
54
56
|
export function sqliteReadModelPath(workspaceRoot: string): string {
|
|
55
57
|
return resolve(process.env.ZAIP_SQLITE_DB_PATH ?? resolve(workspaceRoot, dbRelativePath));
|
|
56
58
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { costInvocationProjectionSelect } from "./sqlite-cost-invocation-projection.js";
|
|
2
|
+
import { specRootElapsedViewSql } from "./sqlite-spec-root-elapsed-view.js";
|
|
2
3
|
export const baseViewSql = `
|
|
3
4
|
CREATE INDEX zaip_activities_agent_run ON zaip_aios_activities(activity_source_kind, agent_run_id, occurred_day_sp, occurred_at DESC);
|
|
4
5
|
CREATE INDEX zaip_activities_relationships ON zaip_aios_activities(task_id, spec_id, prd_id, execution_id, conversation_id);
|
|
@@ -55,6 +56,7 @@ export const baseViewSql = `
|
|
|
55
56
|
WHERE allocation.spec_id=a.spec_id AND allocation.run_id=a.run_id
|
|
56
57
|
)
|
|
57
58
|
UNION ALL SELECT * FROM shared_creation_allocations;
|
|
59
|
+
${specRootElapsedViewSql}
|
|
58
60
|
CREATE VIEW attributed_token_active AS
|
|
59
61
|
SELECT f.activity_row_id, f.occurred_day_sp, f.attributed_token_active_ms,
|
|
60
62
|
a.run_id, a.execution_id, a.task_id, a.spec_id, a.prd_id, a.conversation_id,
|
|
@@ -214,11 +216,11 @@ export const baseViewSql = `
|
|
|
214
216
|
SELECT day, interval_group, MIN(start_ms) AS start_ms, MAX(end_ms) AS end_ms
|
|
215
217
|
FROM cost_monitor_grouped_intervals GROUP BY day, interval_group
|
|
216
218
|
), cost_monitor_daily_duration AS (
|
|
217
|
-
--
|
|
218
|
-
--
|
|
219
|
-
--
|
|
220
|
-
SELECT
|
|
221
|
-
FROM
|
|
219
|
+
-- Cost daily duration is factual elapsed time from source intervals.
|
|
220
|
+
-- The union removes root/subrun overlap; token-active allocation
|
|
221
|
+
-- remains a distinct Operations and attribution measure.
|
|
222
|
+
SELECT day, ROUND(SUM(end_ms - start_ms)) AS total_duration
|
|
223
|
+
FROM cost_monitor_merged_intervals GROUP BY day
|
|
222
224
|
), cost_monitor_duration_coverage AS (
|
|
223
225
|
SELECT day, COUNT(DISTINCT activity_id) AS eligible_runs,
|
|
224
226
|
COUNT(DISTINCT activity_id) AS known_runs
|
|
@@ -267,7 +269,7 @@ export const baseViewSql = `
|
|
|
267
269
|
i.total_root_run_duration,
|
|
268
270
|
i.total_sub_run_duration,
|
|
269
271
|
o.total_duration AS operations_total_duration,
|
|
270
|
-
|
|
272
|
+
dcm.total_duration AS cost_monitor_total_duration,
|
|
271
273
|
coverage.eligible_runs AS cost_monitor_duration_eligible_runs,
|
|
272
274
|
coverage.known_runs AS cost_monitor_duration_known_runs,
|
|
273
275
|
o.total_duration AS total_duration,
|
|
@@ -305,7 +307,7 @@ export const baseViewSql = `
|
|
|
305
307
|
-- population rather than Operations' broader Run/activity totals.
|
|
306
308
|
CREATE VIEW cost_monitor_overview AS SELECT period_kind, period_key, cost_monitor_invocation_count AS total_run_count, cost_monitor_invocation_count AS invocation_count, llm_call_count, source_event_count, cost_monitor_total_duration, total_tokens, total_cost_usd, total_cost_brl FROM overview;
|
|
307
309
|
CREATE VIEW task_summary AS SELECT t.id, t.title, t.status, t.risk, t.occurred_at, t.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, SUM(i.duration_ms) AS total_duration, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM tasks t LEFT JOIN activities i ON i.task_id = t.id GROUP BY t.id, t.title, t.status, t.risk, t.occurred_at, t.occurred_day_sp;
|
|
308
|
-
CREATE VIEW spec_summary AS SELECT s.id, s.title, s.status, s.risk, s.occurred_at, s.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count,
|
|
310
|
+
CREATE VIEW spec_summary AS SELECT s.id, s.title, s.status, s.risk, s.occurred_at, s.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, elapsed.total_duration_ms AS total_duration, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM specs s LEFT JOIN macro_spec_activities i ON i.spec_id = s.id LEFT JOIN spec_root_elapsed elapsed ON elapsed.spec_id=s.id GROUP BY s.id, s.title, s.status, s.risk, s.occurred_at, s.occurred_day_sp;
|
|
309
311
|
CREATE VIEW prd_summary AS SELECT p.id, p.title, p.status, p.risk, p.occurred_at, p.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, SUM(i.duration_ms) AS total_duration, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM prds p LEFT JOIN activities i ON i.prd_id = p.id GROUP BY p.id, p.title, p.status, p.risk, p.occurred_at, p.occurred_day_sp;
|
|
310
312
|
CREATE VIEW cost_monitor_group_daily AS SELECT * FROM cost_monitor_group_daily_cache;
|
|
311
313
|
CREATE VIEW vw_overview AS SELECT * FROM overview;
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-dashboard-views.ts
CHANGED
|
@@ -51,7 +51,9 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
51
51
|
FROM entity_activity GROUP BY entity_kind, entity_id
|
|
52
52
|
), durations AS (
|
|
53
53
|
SELECT entity_kind, entity_id, ROUND(SUM(duration_ms)) AS total_duration
|
|
54
|
-
FROM entity_activity GROUP BY entity_kind, entity_id
|
|
54
|
+
FROM entity_activity WHERE entity_kind <> 'spec' GROUP BY entity_kind, entity_id
|
|
55
|
+
UNION ALL
|
|
56
|
+
SELECT 'spec', spec_id, total_duration_ms FROM spec_root_elapsed
|
|
55
57
|
)
|
|
56
58
|
SELECT w.entity_kind, w.id, w.title, w.status, w.risk, w.occurred_at, w.occurred_day_sp,
|
|
57
59
|
f.invocation_count, f.llm_call_count, d.total_duration,
|
|
@@ -231,7 +233,6 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
231
233
|
WITH usage AS (
|
|
232
234
|
SELECT spec_id,
|
|
233
235
|
COUNT(*) AS total_run_count,
|
|
234
|
-
ROUND(SUM(duration_ms)) AS total_duration_ms,
|
|
235
236
|
SUM(total_tokens) AS total_tokens,
|
|
236
237
|
SUM(cost_usd) AS total_cost_usd,
|
|
237
238
|
SUM(cost_brl) AS total_cost_brl
|
|
@@ -239,16 +240,17 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
239
240
|
)
|
|
240
241
|
SELECT COUNT(*) AS entity_count,
|
|
241
242
|
SUM(usage.total_run_count) AS total_run_count,
|
|
242
|
-
SUM(
|
|
243
|
+
SUM(elapsed.total_duration_ms) AS total_duration_ms,
|
|
243
244
|
SUM(usage.total_tokens) AS total_tokens,
|
|
244
245
|
SUM(usage.total_cost_usd) AS total_cost_usd,
|
|
245
246
|
SUM(usage.total_cost_brl) AS total_cost_brl,
|
|
246
|
-
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(
|
|
247
|
+
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(elapsed.total_duration_ms)/COUNT(*) END AS average_duration_ms,
|
|
247
248
|
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(usage.total_tokens)/COUNT(*) END AS average_tokens,
|
|
248
249
|
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(usage.total_cost_usd)/COUNT(*) END AS average_cost_usd,
|
|
249
250
|
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(usage.total_cost_brl)/COUNT(*) END AS average_cost_brl,
|
|
250
251
|
MAX(s.occurred_at) AS latest_created_at
|
|
251
|
-
FROM spec_summary s LEFT JOIN usage ON usage.spec_id=s.id
|
|
252
|
+
FROM spec_summary s LEFT JOIN usage ON usage.spec_id=s.id
|
|
253
|
+
LEFT JOIN spec_root_elapsed elapsed ON elapsed.spec_id=s.id;
|
|
252
254
|
CREATE VIEW vw_first_fold_prd_metrics_all_time AS
|
|
253
255
|
WITH usage AS (
|
|
254
256
|
SELECT prd_id,
|
|
@@ -276,16 +278,16 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
276
278
|
SELECT spec_id,
|
|
277
279
|
COUNT(*) AS total_run_count,
|
|
278
280
|
SUM(llm_call_count) AS llm_call_count,
|
|
279
|
-
ROUND(SUM(duration_ms)) AS total_duration_ms,
|
|
280
281
|
SUM(total_tokens) AS total_tokens,
|
|
281
282
|
SUM(cost_usd) AS total_cost_usd,
|
|
282
283
|
SUM(cost_brl) AS total_cost_brl
|
|
283
284
|
FROM macro_spec_activities GROUP BY spec_id
|
|
284
285
|
), ranked AS (
|
|
285
286
|
SELECT s.id AS entity_id, s.title, s.status, usage.total_run_count, usage.llm_call_count,
|
|
286
|
-
|
|
287
|
-
ROW_NUMBER() OVER (ORDER BY
|
|
287
|
+
elapsed.total_duration_ms, usage.total_tokens, usage.total_cost_usd, usage.total_cost_brl,
|
|
288
|
+
ROW_NUMBER() OVER (ORDER BY elapsed.total_duration_ms IS NOT NULL DESC, elapsed.total_duration_ms DESC, usage.total_run_count DESC, s.id) AS rank
|
|
288
289
|
FROM spec_summary s LEFT JOIN usage ON usage.spec_id=s.id
|
|
290
|
+
LEFT JOIN spec_root_elapsed elapsed ON elapsed.spec_id=s.id
|
|
289
291
|
), total AS (SELECT SUM(total_duration_ms) AS total_duration_ms FROM ranked)
|
|
290
292
|
SELECT ranked.rank, ranked.entity_id, ranked.title, ranked.status,
|
|
291
293
|
COALESCE(ranked.total_run_count,0) AS total_run_count, ranked.llm_call_count,
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-spec-root-elapsed-view.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPEC elapsed time is the union of factual root Run intervals within each
|
|
3
|
+
* SPEC. A root and its children must not both contribute elapsed time. A Run
|
|
4
|
+
* linked to two SPECs remains visible in each; the cross-SPEC sum is therefore
|
|
5
|
+
* a sum of entity durations, not a global wall-clock total.
|
|
6
|
+
*/
|
|
7
|
+
export const specRootElapsedViewSql = `
|
|
8
|
+
CREATE VIEW spec_root_elapsed AS
|
|
9
|
+
WITH roots AS (
|
|
10
|
+
SELECT spec_id, run_id,
|
|
11
|
+
MAX(source_duration_ms) AS source_duration_ms,
|
|
12
|
+
MIN(source_started_at) AS source_started_at,
|
|
13
|
+
MAX(source_finished_at) AS source_finished_at
|
|
14
|
+
FROM macro_spec_activities
|
|
15
|
+
WHERE spec_id IS NOT NULL AND run_role='root'
|
|
16
|
+
GROUP BY spec_id, run_id
|
|
17
|
+
), source_intervals AS (
|
|
18
|
+
SELECT spec_id,
|
|
19
|
+
(julianday(source_started_at) - 2440587.5) * 86400000.0 AS start_ms,
|
|
20
|
+
(julianday(source_finished_at) - 2440587.5) * 86400000.0 AS end_ms
|
|
21
|
+
FROM roots
|
|
22
|
+
WHERE source_started_at IS NOT NULL AND source_finished_at IS NOT NULL
|
|
23
|
+
AND julianday(source_finished_at) > julianday(source_started_at)
|
|
24
|
+
), ordered AS (
|
|
25
|
+
SELECT spec_id, start_ms, end_ms,
|
|
26
|
+
MAX(end_ms) OVER (
|
|
27
|
+
PARTITION BY spec_id ORDER BY start_ms, end_ms
|
|
28
|
+
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
|
|
29
|
+
) AS prior_end_ms
|
|
30
|
+
FROM source_intervals
|
|
31
|
+
), grouped AS (
|
|
32
|
+
SELECT spec_id, start_ms, end_ms,
|
|
33
|
+
SUM(CASE WHEN prior_end_ms IS NULL OR start_ms > prior_end_ms THEN 1 ELSE 0 END)
|
|
34
|
+
OVER (PARTITION BY spec_id ORDER BY start_ms, end_ms) AS interval_group
|
|
35
|
+
FROM ordered
|
|
36
|
+
), merged AS (
|
|
37
|
+
SELECT spec_id, interval_group, MIN(start_ms) AS start_ms, MAX(end_ms) AS end_ms
|
|
38
|
+
FROM grouped GROUP BY spec_id, interval_group
|
|
39
|
+
), source_totals AS (
|
|
40
|
+
SELECT spec_id, SUM(end_ms - start_ms) AS duration_ms
|
|
41
|
+
FROM merged GROUP BY spec_id
|
|
42
|
+
), fallback_totals AS (
|
|
43
|
+
-- A terminal factual duration without source boundaries remains
|
|
44
|
+
-- available, but cannot be unioned against another Run interval.
|
|
45
|
+
SELECT spec_id, SUM(source_duration_ms) AS duration_ms
|
|
46
|
+
FROM roots
|
|
47
|
+
WHERE source_duration_ms IS NOT NULL
|
|
48
|
+
AND NOT (
|
|
49
|
+
source_started_at IS NOT NULL AND source_finished_at IS NOT NULL
|
|
50
|
+
AND julianday(source_finished_at) > julianday(source_started_at)
|
|
51
|
+
)
|
|
52
|
+
GROUP BY spec_id
|
|
53
|
+
), known_specs AS (
|
|
54
|
+
SELECT spec_id FROM source_totals UNION SELECT spec_id FROM fallback_totals
|
|
55
|
+
)
|
|
56
|
+
SELECT known_specs.spec_id,
|
|
57
|
+
ROUND(COALESCE(source_totals.duration_ms, 0) + COALESCE(fallback_totals.duration_ms, 0)) AS total_duration_ms
|
|
58
|
+
FROM known_specs
|
|
59
|
+
LEFT JOIN source_totals USING(spec_id)
|
|
60
|
+
LEFT JOIN fallback_totals USING(spec_id);
|
|
61
|
+
`;
|