CoolFace
Apppublic

XAUUSDAITradingBot/EchoHeirloom

sourceHugging Faceapache-2.0updated 3d agoView on Hugging Face
0likes
App README

MedFlow Command

An operations console for medical logistics — shipments, cold chain, stock, transport, reported bed capacity, scheduling, procurement, incidents and recalls. A supervisor agent owns the spoken call through the AssemblyAI Voice Agent API, delegates to eight specialist services, and either acts within a policy envelope or hands a human validator a brief.

This is not a diagnostic or treatment system. No agent diagnoses, prescribes, changes a clinical instruction, picks a treatment or claims to be a clinician. All demo data is synthetic.

Run it

Hugging Face Space (Docker SDK): push these files, then add Space secrets.

SecretRequiredEffect
ASSEMBLYAI_API_KEYfor real callsSwitches the voice layer from the scripted mock to a live Voice Agent session
ASSEMBLYAI_AGENT_IDoptionalBinds a stored agent instead of sending inline session config
ENABLE_OUTBOUNDoptional1 allows outbound validator callbacks
ENABLE_PHONE, PHONE_PROVIDER, PHONE_NUMBER_IDoptionalPhone-number binding

Without ASSEMBLYAI_API_KEY the Space still runs end to end on the deterministic mock adapter, labelled as a mock in the UI.

Local:

bash
pip install -r requirements.txt
ASSEMBLYAI_API_KEY=... uvicorn app.main:app --port 7860
pytest -q tests.py     # 64 tests

Demo in 60 seconds

  1. 1.Sign in as Validator.
  2. 2.Overview → Use demo scenario → Send to supervisor. Inventory, Transport, Incident, Scheduling and Compliance report typed findings. Two temperature loggers on SHP-881 disagree, so the conflict gate fires.
  3. 3.Validation inbox shows the brief: verified facts, proposal, alternatives, impact, risk score with reasons, agent disagreement, and what is still unknown. Request evidence, edit, approve or reject (a reason is mandatory to reject or edit).
  4. 4.Ask it to "substitute a different insulin brand" — it refuses and routes to a human.
  5. 5.Voice centre → Start call. Live captions, tool activity, session.end on hang-up.

File tree

Dockerfile            HF Space image (python:3.11-slim, non-root, healthcheck)
README.md             this file
requirements.txt
tests.py              64 tests: acceptance, policy matrix, state machine, adversarial
app/config.py         env-only secrets, feature flags, voice tuning, system prompt
app/schemas.py        versioned protocol + workflow state machine
app/store.py          SQLite, append-only event log, outbox, redaction, synthetic seed
app/policy.py         autonomy policy engine, risk scoring, metrics
app/tools.py          12 allow-listed server-side tools
app/agents.py         supervisor + 8 specialists, briefs, approvals
app/voice.py          AssemblyAI adapter, mock adapter, outbound queue
app/main.py           REST, SSE, voice WebSocket bridge, RBAC, CSP
static/index.html     console shell
static/styles.css     design system (dark + light, WCAG AA, reduced motion)
static/app.js         14 screens, topology, kanban, captions, waveform

Architecture

browser ──WS(JSON/base64 PCM)──► FastAPI /ws/voice ──WSS──► agents.assemblyai.com/v1/ws
                                      │  tool.call → server-side execute → tool.result
                                      ▼
   supervisor ─► AgentTask ─► 8 specialists ─► AgentFinding (+evidence, confidence)
                                      ▼
            conflicts → RiskAssessment → policy engine → autonomous | ApprovalRequest
                                      ▼
            append-only event log → SSE → console + audit timeline + redacted report

The browser never sees the API key and never executes a tool. Audio is relayed through the server; the key travels only in the server's Authorization: Bearer upgrade header.

Workflow state machine

RECEIVED → TRIAGED → INVESTIGATING → PROPOSED → VALIDATION_REQUIRED → APPROVED → EXECUTING → VERIFIED → CLOSED, plus BLOCKED, REJECTED, CANCELLED, FAILED, ESCALATED. Transitions are declared in app/schemas.py; illegal moves raise. Every transition writes an event.

Autonomy policy matrix

Autonomous only if the category is eligible and every threshold passes.

Eligible for autonomyAlways needs a validator
status lookupsclinical decisions / instruction changes
remindersmedication substitution
ETA updatescontrolled substances
low-risk schedule proposalsemergency or ambulance dispatch
draft purchase requestspatient transfer or rerouting
routine exception noticescancelling a critical shipment
inventory reconciliation suggestionshigh-value or irreversible commitments, payment commitments
release of patient information, policy overrides
low confidence or unresolved conflict

Gates: confidence ≥ min_confidence_autonomous (0.75), zero unresolved conflicts, risk level low, evidence fresher than max_evidence_age_seconds (3600), amount under max_autonomous_amount (500), tool permitted, no prior failure, no compliance veto.

Risk score = weighted patient-safety, reversibility, PHI sensitivity, legal impact, conflicts, deadline urgency, prior failures, amount-vs-cap and inverse confidence, with a staleness penalty.

The 90% figure is measured, never targeted. Analytics shows actual autonomy rate on eligible work, approval latency, override rate, false-escalation rate, task success and tool failure. No code path reads the target when deciding. tests.py::test_autonomy_target_never_forces_approval pins this.

AssemblyAI integration

  • —Endpoint wss://agents.assemblyai.com/v1/ws, REST under https://agents.assemblyai.com/v1.
  • —Auth: Authorization: Bearer <key>, server-side only.
  • —First message session.update with everything nested under session; when ASSEMBLYAI_AGENT_ID is set, the payload binds the stored agent and sends nothing inline.
  • —ASR universal-3.5-pro-realtime; greeting, medical-logistics key terms, language list, interruption handling and turn detection configured.
  • —transcript.user.delta is cumulative — the UI replaces the partial caption rather than concatenating. transcript.agent.delta drives live agent captions.
  • —Tool schemas are flat: { type: "function", name, description, parameters }.
  • —tool.call arguments are read from arguments, never args.
  • —Tools execute on the server. tool.result is buffered until reply.done is the most recent event, then flushed. Failures carry is_error: true.
  • —session.end is sent when a call finishes so the resumable grace period stops billing.
  • —Reconnect uses session.resume; tool idempotency keys (call_id:tool_call_id) mean a resumed socket cannot double-execute an action.
  • —Outbound validator calls check consent, quiet hours, retry limit and escalation cooldown. With no phone provider bound the request is queued and shown blocked — never faked as connected.

API contracts

MethodPathNotes
POST/api/signindemo identity + role, httpOnly cookies
GET/api/bootstraporg, users, flags, agents, states, policies, metrics
POST/api/intake{utterance} → full supervisor cycle (operator+)
GET/api/workflows, /api/workflows/{id}board data; findings, events, executions
GET/api/approvalspending briefs
POST/api/approvals/{id}/decideapprove, reject, edit_approve, request_evidence, pause, take_over + expected_version (validator only)
GET/api/ops, /api/audit, /api/tools, /api/integrationsoperational data
POST/api/tools/dry-run, /api/policies, /api/callbackdry run, policy patch, queued callback
GET/api/report/{id}redacted markdown report
GET/api/events/streamSSE workflow events
WS/ws/voicebrowser ⇄ server ⇄ AssemblyAI
GET/healthzliveness

Tools

get_inventory_status, check_lot_and_expiry, get_temperature_history, get_shipment_status, estimate_route, list_capacity_reports, propose_schedule, draft_purchase_request, create_incident, notify_validator, request_validator_callback, write_audit_event

Each declares a strict schema, data classification, role check, idempotency behaviour, timeout/retry, dry-run mode, approval requirement and an audit event, and has a deterministic mock path. See Integrations in the console for the live catalogue.

Threat model

ThreatControl
Prompt injection via caller speech or tool outputTools are allow-listed with fixed schemas; the policy engine, not the model, decides autonomy; always-validate categories are unreachable from any prompt or API
Forged agent eventsWorkflow state changes only through transition() with a legal-transition check; a written event never mutates state
Cross-tenant readorg_id on every query; tenant_guard raises PermissionError
Duplicate or replayed approvalStatus check plus optimistic version; second decision returns 409
Tool-result tampering / double executionIdempotency key per (workflow, action) or (call, tool_call_id); replay returns the stored result
Stale evidenceEvidence carries freshnessSeconds; staleness adds risk and blocks autonomy
Secret or PHI leakageSecrets are env-only; regex redaction on every event, audit, transcript and tool record before write; CSP, nosniff, no-referrer; raw audio never stored
Privilege escalationRBAC on every mutating route plus per-tool role lists
Silent failureDead-letter table, structured event log, health check, degraded UI states

No HIPAA claim. Security controls are not compliance. Encryption at rest, BAAs, retention enforcement and access reviews are organisational work outside this repository.

Architecture decision records

ADR-1 — Python/FastAPI on one container instead of a TypeScript monorepo. The brief specified Next.js + Prisma + Redis/BullMQ. The target is a Hugging Face Space running a single Docker image, and the brief's own delivery constraint is Python. Kept: strict schemas (Pydantic v2 instead of Zod), migrations-equivalent schema bootstrap, seeded demo tenant, typed protocol.

ADR-2 — SQLite (WAL) instead of PostgreSQL, asyncio instead of Redis/BullMQ. A Space has no sidecar services. The properties actually relied on — transactional writes, an append-only outbox, idempotency keys, a dead-letter queue — are implemented directly. app/store.py is the only file that needs to change to move to Postgres.

ADR-3 — Audio is relayed through the server, not via a browser temporary token. A browser token would be one fetch less, but tool execution and PHI redaction must stay server-side, and relaying keeps a single audit point for every call.

ADR-4 — Specialists are deterministic, not LLM-backed. Logistics findings must be reproducible and traceable to a tool result. Only the supervisor's spoken turn uses a model, and it cannot execute anything the policy engine has not cleared.

ADR-5 — SSE for live updates. One-way fan-out; simpler than a second WebSocket and it survives proxy buffering with an explicit keepalive.

Integration checklist

BehaviourState
Supervisor, 8 specialists, typed protocol, state machine, policy engineimplemented
Append-only event log, outbox, dead letters, idempotency, RBAC, redaction, audit reportimplemented
Validation inbox: approve / reject / edit / request evidence / pause / take over, SLA, override reasonsimplemented
14 screens, topology, kanban, map, cold-chain chart, heatmap, gauges, empty/offline/degraded statesimplemented
AssemblyAI session, transcripts, tool execution, session.end, reconnectimplemented, live only with ASSEMBLYAI_API_KEY
Specialist intelligencemocked — deterministic services over real store data
Scripted voice sessionmocked — labelled in the UI when no key is set
Stored-agent bindingprovider-dependent — needs ASSEMBLYAI_AGENT_ID
Outbound validator calls, phone-number bindingprovider-dependent — queue and show blocked until configured
Geographic mapsynthetic coordinates for the demo tenant
Postgres, Redis, Playwright e2enot built — see ADR-1 and ADR-2

Accessibility

WCAG AA contrast in both themes; every status carries a glyph and a word as well as colour; full keyboard navigation with visible focus rings; aria-live on the event feed and captions; prefers-reduced-motion disables all animation, including the topology pulses and the waveform refresh rate.