One answer per profile, asked once, with the Desktop strip's three equal choices (Send to Nous / Local only / No thanks) now offered by: - `hermes setup`: at the end of every flow (Quick, Full, Blank Slate, Portal, --quick), via the setup-completed record they all funnel into. - `hermes` / `hermes --tui`: once before an interactive chat on a profile that never answered. Skipped for -q, piped/JSON output, spawned actions (HERMES_NONINTERACTIVE), Desktop-hosted panes and managed installs. - Web dashboard: a banner for the profile being managed, backed by GET/PUT /api/shared-metrics/consent. "No thanks" is the terminal default so Enter never opts anyone in; Esc and the banner's X leave the question open. Also fixes the answer that could not stick: a CLI "no" equals the shipped defaults, so save_config stripped it and every surface (Desktop strip included) kept asking. The answer is now written to config.yaml directly, and `decided` has one definition shared by the RPC, the CLI and the router.
49 lines
1.6 KiB
Python
49 lines
1.6 KiB
Python
"""``/api/shared-metrics/consent``: the dashboard's first-run shared-metrics offer.
|
|
|
|
The twin of Desktop's composer strip and the terminal's offer: one answer per profile, the same
|
|
two config.yaml keys (``telemetry.shared_metrics.enabled`` / ``.send``), read and written through
|
|
``hermes_cli.observability.shared_metrics_consent`` for the ``?profile=`` being managed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter
|
|
from pydantic import BaseModel
|
|
|
|
from hermes_cli.web_routers._common import config_write_scope, scoped_to_thread
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class ConsentAnswer(BaseModel):
|
|
enabled: bool
|
|
send: bool = False
|
|
|
|
|
|
def _read_consent() -> dict:
|
|
"""``{enabled, send, decided, managed}``; a managed install cannot save, so it is never offered."""
|
|
from hermes_cli.config import is_managed, read_raw_config
|
|
from hermes_cli.observability.shared_metrics_consent import consent_state
|
|
|
|
return {**consent_state(read_raw_config()), "managed": is_managed()}
|
|
|
|
|
|
@router.get("/api/shared-metrics/consent")
|
|
async def get_shared_metrics_consent(profile: Optional[str] = None):
|
|
return await scoped_to_thread(profile, _read_consent)
|
|
|
|
|
|
@router.put("/api/shared-metrics/consent")
|
|
async def put_shared_metrics_consent(body: ConsentAnswer, profile: Optional[str] = None):
|
|
from hermes_cli.observability.shared_metrics_consent import save_consent
|
|
|
|
def _write() -> dict:
|
|
with config_write_scope(profile):
|
|
save_consent(body.enabled, body.send)
|
|
return _read_consent()
|
|
|
|
return await asyncio.to_thread(_write)
|