Config policies (16 files): alert_routing, architecture_pressure, backlog, cost_weights, data_governance, incident_escalation, incident_intelligence, network_allowlist, nodes_registry, observability_sources, rbac_tools_matrix, release_gate, risk_attribution, risk_policy, slo_policy, tool_limits, tools_rollout Ops (22 files): Caddyfile, calendar compose, grafana voice dashboard, deployments/incidents logs, runbooks for alerts/audit/backlog/incidents/sofiia/voice, cron jobs, scripts (alert_triage, audit_cleanup, migrate_*, governance, schedule), task_registry, voice alerts/ha/latency/policy Docs (30+ files): HUMANIZED_STEPAN v2.7-v3 changelogs and runbooks, NODA1/NODA2 status and setup, audit index and traces, backlog, incident, supervisor, tools, voice, opencode, release, risk, aistalk, spacebot Made-with: Cursor
7.7 KiB
cost_analyzer_tool — FinOps & Resource Analyzer
Категорія: FinOps / Observability
RBAC: tools.cost.read (report, top, anomalies, weights), tools.cost.gate (gate)
Ролі: agent_cto (read + gate), agent_oncall (read)
Timeout: 20 s
Rate limit: 10 rpm
Призначення
cost_analyzer_tool дає CTO/oncall команді відповіді на питання:
- Хто спалює ресурси? (по агентам, tools, workspace)
- Чи є аномальні сплески? (порівняння вікна з базовим рівнем)
- Які налаштування ваг? (для FinOps калібрування)
Всі розрахунки базуються на відносних cost_units без реальних грошових значень.
Payload ніколи не зберігається і не логується.
Actions
report — агрегований звіт за період
{
"action": "report",
"time_range": { "from": "2026-02-16T00:00:00Z", "to": "2026-02-23T00:00:00Z" },
"group_by": ["tool", "agent_id"],
"top_n": 10,
"include_failed": true,
"include_hourly": false
}
Відповідь:
{
"time_range": { "from": "...", "to": "..." },
"totals": {
"calls": 1240,
"cost_units": 4821.5,
"failed": 12,
"denied": 3,
"error_rate": 0.0097
},
"breakdowns": {
"tool": [
{ "tool": "comfy_generate_video", "count": 42, "cost_units": 5200.0, "avg_duration_ms": 8200 },
{ "tool": "pr_reviewer_tool", "count": 87, "cost_units": 960.0, ... }
],
"agent_id": [...]
}
}
top — швидкий топ-N за вікно (24h/7d)
{
"action": "top",
"window_hours": 24,
"top_n": 10
}
Відповідь: top_tools, top_agents, top_users, top_workspaces.
anomalies — виявлення сплесків
{
"action": "anomalies",
"window_minutes": 60,
"baseline_hours": 24,
"ratio_threshold": 3.0,
"min_calls": 50
}
Алгоритм:
- Вікно =
[now - window_minutes, now] - Базовий рівень =
[now - baseline_hours, now - window_minutes] - Spike =
window_rate / baseline_rate >= ratio_thresholdANDcalls >= min_calls - Error spike =
error_rate > 10%ANDcalls >= min_calls
Відповідь:
{
"anomalies": [
{
"type": "cost_spike",
"key": "tool:comfy_generate_image",
"tool": "comfy_generate_image",
"window": "last_60m",
"baseline": "prev_24h",
"window_calls": 120,
"baseline_calls": 8,
"ratio": 6.3,
"recommendation": "'comfy_generate_image' cost spike..."
}
],
"anomaly_count": 1,
"stats": { "window_calls": 120, "baseline_calls": 8 }
}
weights — поточні ваги cost model
{ "action": "weights" }
Повертає конфіг з config/cost_weights.yml: defaults, per-tool weights, anomaly thresholds.
Cost Model
cost_units = cost_per_call(tool) + duration_ms × cost_per_ms(tool)
Це відносні одиниці, не реальні $. Калібруйте через config/cost_weights.yml.
| Tool | cost_per_call | cost_per_ms |
|---|---|---|
comfy_generate_video |
120.0 | 0.005 |
comfy_generate_image |
50.0 | 0.003 |
pr_reviewer_tool |
10.0 | 0.002 |
observability_tool |
2.0 | 0.001 |
| (default) | 1.0 | 0.001 |
Audit persistence (AuditStore)
Кожен tool call через ToolGovernance.post_call() автоматично зберігається.
Backend (env var AUDIT_BACKEND):
| Backend | Config | Опис |
|---|---|---|
jsonl (default) |
AUDIT_JSONL_DIR |
Append-only файли по датах: ops/audit/tool_audit_YYYY-MM-DD.jsonl |
postgres |
DATABASE_URL |
async asyncpg → таблиця tool_audit_events |
memory |
— | In-process (тести, dev) |
null |
— | Вимкнено |
Поля в store (без payload):
ts, req_id, workspace_id, user_id, agent_id, tool, action,
status, duration_ms, in_size, out_size, input_hash,
graph_run_id?, graph_node?, job_id?
Non-fatal: якщо store недоступний — логується warning, tool call не падає.
Інтеграція в release_check (cost_watch gate)
cost_watch — warning-only gate: завжди pass=true, додає рекомендації.
# ops/task_registry.yml (release_check inputs)
run_cost_watch: true # вмикає gate
cost_watch_window_hours: 24 # вікно аналізу
cost_spike_ratio_threshold: 3.0
cost_min_calls_threshold: 50
Gate output:
{
"name": "cost_watch",
"status": "pass",
"anomalies_count": 2,
"anomalies_preview": [...],
"note": "2 anomaly(ies) detected",
"recommendations": ["Cost spike: comfy_generate_image — apply rate limit."]
}
Якщо cost_analyzer_tool недоступний → skipped: true, реліз не блокується.
RBAC
cost_analyzer_tool:
actions:
report: { entitlements: ["tools.cost.read"] }
top: { entitlements: ["tools.cost.read"] }
anomalies: { entitlements: ["tools.cost.read"] }
weights: { entitlements: ["tools.cost.read"] }
gate: { entitlements: ["tools.cost.gate"] }
role_entitlements:
agent_cto: [..., tools.cost.read, tools.cost.gate]
agent_oncall: [..., tools.cost.read]
Limits
cost_analyzer_tool:
timeout_ms: 20000 # 20s
max_chars_in: 2000
max_bytes_out: 1048576 # 1MB
rate_limit_rpm: 10
concurrency: 2
Security
- Payload НІКОЛИ не зберігається і не логується.
- AuditStore writes: тільки hash + sizes + metadata.
- Всі aggregation queries фільтруються тільки по метаданим (ts, tool, agent_id, workspace_id).
anomaliesendpoint не розкриває вміст tool calls.
Тести
tests/test_cost_analyzer.py (18 тестів):
| Тест | Перевірка |
|---|---|
test_audit_persist_nonfatal |
Broken store не ламає tool call |
test_cost_report_aggregation |
20 events → правильні totals і top |
test_cost_event_cost_units |
pr_reviewer 500ms = 11.0 units |
test_anomalies_spike_detection |
80 calls у вікні vs 2 в baseline → spike |
test_anomalies_no_spike |
Стабільний трафік → 0 anomalies |
test_top_report |
comfy_generate_video як #1 spender |
test_release_check_cost_watch_always_passes |
gate pass=True з аномаліями |
test_cost_watch_gate_in_full_release_check |
full run_release_check зберігає pass |
test_rbac_cost_tool_deny |
alateya (agent_media) → denied |
test_rbac_cost_tool_allow |
sofiia (agent_cto) → allowed |
test_weights_loaded |
cost_weights.yml читається коректно |
test_jsonl_store_roundtrip |
write + read JSONL |
test_cost_watch_skipped_on_tool_error |
tool error → gate skipped, не error |
test_anomalies_error_rate_spike |
80% failure rate → error_spike |
Наступні кроки (після MVP)
- Postgres backend — для довгострокового зберігання (>7d) і SQL-запитів.
- Token-level cost — якщо є метрика LLM tokens → точний $ cost.
- Budget alerts — notify oncall при перевищенні щоденного бюджету.
- Cost dashboard — Grafana panel на базі
tool_audit_eventstable. - Per-graph cost — tracking через
graph_run_id(вже є в schema).