# SafetyMonitorAgent — A2A Spec **Product:** NomGap **Trigger:** Telemetry event `fasting.duration_milestone` where `hours IN [24, 42, 48, 72]`, or on-demand via `nomgap.safety.check(userId)` **Output:** Push notification (`refeeding_reminder` or `extended_fast_warning`) + structured safety brief logged as telemetry event --- ## Agent roster | Step | Agent | Input | Output | | ---- | -------------------------- | ----------------------------------- | ------------------------------------------------------------------- | | 1 | `FastStateInspectorAgent` | `userId`, current timestamp | Active fasting session doc + elapsed hours + protocol name | | 2 | `ThresholdEvaluatorAgent` | Fasting session + elapsed hours | Safety level (`safe` / `caution` / `critical`) + recommended action | | 3 | `SafetyNotificationAgent` | Safety level + userId + protocol | Push notification fired + telemetry event logged | | 4 | `ExtendedFastHandoffAgent` | Session (hours ≥ 48) + safety brief | A2A handoff to `ExtendedFastDetectionAgent` (if escalation needed) | --- ## Agent contracts ### FastStateInspectorAgent ```typescript // Tool: nomgap.fasting.getSession (GET /fasting-sessions/active?userId=) input: { userId: string; } output: { sessionId: string; protocolId: string; protocolName: string; startedAt: string; // ISO 8601 elapsedHours: number; targetHours: number; isActive: boolean; } ``` ### ThresholdEvaluatorAgent ```typescript // Pure in-process evaluation — no external calls // Thresholds defined in nomgap safety rules: // 0-24h: safe // 24-42h: caution (electrolyte reminder at 24h) // 42-48h: caution (pre-refeeding warning) // 48h+: critical (refeeding_reminder + medical supervision flag) // 72h+: critical (escalate to ExtendedFastDetectionAgent) input: { sessionId: string; elapsedHours: number; protocolName: string; targetHours: number; } output: { safetyLevel: 'safe' | 'caution' | 'critical'; pushType: 'refeeding_reminder' | 'extended_fast_warning' | 'electrolyte_reminder' | null; escalate: boolean; // true when elapsedHours >= 72 messageVariables: Record; // { hours, protocolName, refeedingTip } } ``` ### SafetyNotificationAgent ```typescript // Tool: nomgap.push.fire (POST platform-service /push-triggers) // Tool: platform.telemetry.events (POST platform-service /telemetry/events) input: { userId: string; pushType: string; messageVariables: Record; sessionId: string; safetyLevel: string; } output: { notified: boolean; pushTriggerId: string; telemetryEventId: string; } ``` ### ExtendedFastHandoffAgent ```typescript // Fires only when ThresholdEvaluatorAgent.escalate === true (hours >= 72) // A2A handoff artifact is emitted as a telemetry event so any subscribed // ExtendedFastDetectionAgent can pick it up. input: { userId: string; sessionId: string; elapsedHours: number; safetyLevel: 'critical'; } output: { handoffEventId: string; handoffPayload: { productId: 'nomgap'; agentTarget: 'ExtendedFastDetectionAgent'; userId: string; sessionId: string; elapsedHours: number; triggeredAt: string; } } ``` --- ## Data model ```typescript interface SafetyCheckResult { userId: string; productId: 'nomgap'; sessionId: string; elapsedHours: number; safetyLevel: 'safe' | 'caution' | 'critical'; actionsTaken: string[]; // e.g. ['push:refeeding_reminder', 'telemetry:logged', 'handoff:ExtendedFastDetectionAgent'] checkedAt: string; // ISO 8601 } ``` --- ## Threshold table | Elapsed hours | Safety level | Push type | Escalate? | | ------------- | ------------ | ----------------------- | --------- | | < 24 h | `safe` | none | no | | 24 h | `caution` | `electrolyte_reminder` | no | | 42 h | `caution` | `refeeding_reminder` | no | | 48 h | `critical` | `refeeding_reminder` | no | | 72 h+ | `critical` | `extended_fast_warning` | **yes** | --- ## Error handling - If the user has no active fasting session, `FastStateInspectorAgent` returns `isActive: false` and the pipeline exits with no action. - If `nomgap.push.fire` fails, the telemetry event is still logged (best-effort notification). - If `ExtendedFastHandoffAgent` cannot emit the handoff event, the critical push notification still fires — escalation failure is non-blocking. - Idempotent within a 1-hour window: a safety check that already fired the same `pushType` within the last 60 minutes is skipped. --- ## MCP tool surface ```typescript nomgap.safety.check(userId: string): SafetyCheckResult nomgap.safety.getThresholds(): ThresholdTable // returns the threshold table above ``` --- ## Implementation checklist - [ ] `FastStateInspectorAgent` — thin wrapper over `GET /fasting-sessions/active` - [ ] `ThresholdEvaluatorAgent` — pure evaluation logic (no I/O), unit-testable - [ ] `SafetyNotificationAgent` — calls `nomgap.push.fire` + logs telemetry event - [ ] `ExtendedFastHandoffAgent` — emits A2A handoff telemetry event for ≥ 72 h fasts - [ ] Cron or event subscription: subscribe to `fasting.duration_milestone` telemetry events - [ ] Deduplication guard: skip if same `(userId, pushType)` fired within 60 minutes - [ ] MCP tool registration: `nomgap.safety.check` + `nomgap.safety.getThresholds` - [ ] Unit tests for `ThresholdEvaluatorAgent` covering all 5 threshold rows