hub / content /engineering /modules /agents.html
amirmh's picture
Audit pass: merge duplicate docs (57 total), fix ADR index links, header overflow, mobile tables, members button in header, WebP illustrations
612e777 verified
Raw
History Blame Contribute Delete
7.19 kB
<article class="doc" id="doc-modules-agents" aria-hidden="true"><div class="strip"><span class="path">modules/agents.md</span><span class="tag">Engineering, modules</span><span class="meta">~2 min read</span></div>
<h1>Module: <code>agents</code></h1>
<blockquote>
<p>Part of the Travi AI Agent monolith (<code>app/modules/agents/</code>). Read <code>00-overview.md</code> §3 (hard rules) before changing anything here.</p>
</blockquote>
<div class="tbl-wrap"><table class="plain col-table compact"><colgroup><col class="col-auto"/><col class="col-lg"/></colgroup>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td data-label=""><strong>Purpose</strong></td>
<td data-label="">The six bounded agents, their policy envelopes, evidence records, kill switches, and exception routing. Agents gather evidence; they never set state.</td>
</tr>
<tr>
<td data-label=""><strong>Owns (data)</strong></td>
<td data-label="">agent_action, policy envelopes (versioned)</td>
</tr>
<tr>
<td data-label=""><strong>Public surface</strong></td>
<td data-label="">goal queue (internal), <code>/admin/kill-switches</code> enforcement point</td>
</tr>
<tr>
<td data-label=""><strong>Depends on</strong></td>
<td data-label="">episode (evidence → engine), notification, ehr_adapter, Twilio voice</td>
</tr>
<tr>
<td data-label=""><strong>Requirements owned</strong></td>
<td data-label="">AUT-001/006/009</td>
</tr>
<tr>
<td data-label=""><strong>Constraining ADRs</strong></td>
<td data-label="">ADR-011 (routing targets)</td>
</tr>
<tr>
<td data-label=""><strong>Key references</strong></td>
<td data-label="">modules/episode.md (who actually moves state)</td>
</tr>
</tbody>
</table></div>
<hr/>
<h1>12. Agentic Execution Layer</h1>
<h2 id="doc-modules-agents--h1">12.1 Orchestration Loop (deterministic core)</h2>
<ol>
<li>Workflow engine (episode module) emits a <strong>goal</strong> (e.g., <code>verify_dispense(plan_item)</code>) to the agent queue with the current policy envelope version.</li>
<li>Agent plans with LLM assist (optional) but may only call tools on its allowlist; every call → <code>agent_action</code> row (params redacted, result, evidence).</li>
<li>Agent returns <strong>structured evidence</strong>, never a state: e.g., <code>{dispense_status:"picked_up", source:"pharmacy_phone", confidence:"confirmed"}</code>.</li>
<li>Workflow engine validates evidence against deterministic rules and executes the §7.1 transition (five-element contract).</li>
<li>Retry ladder per envelope; exhaustion → L1 exception route (§12.5); kill switches checked before every tool call (cached ≤10 s).</li>
</ol>
<h2 id="doc-modules-agents--h2">12.2 Agent Catalog &amp; Envelopes</h2>
<div class="tbl-wrap"><table class="col-table compact"><colgroup><col class="col-auto"/><col class="col-lg"/><col class="col-auto"/><col class="col-lg"/></colgroup>
<thead>
<tr>
<th>Agent</th>
<th>Tool Allowlist</th>
<th>Max Retries</th>
<th>Hard Prohibitions</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Agent">Engagement</td>
<td data-label="Tool Allowlist">notification.send, channel.select, schedule.reminder</td>
<td data-label="Max Retries">3/task/day</td>
<td data-label="Hard Prohibitions">No PHI in payloads; no promises of clinician monitoring (CLN-008 language lint).</td>
</tr>
<tr>
<td data-label="Agent">Appointment</td>
<td data-label="Tool Allowlist">ehr.search_slots, ehr.book(with patient authorization token), patient.present_options</td>
<td data-label="Max Retries">3</td>
<td data-label="Hard Prohibitions">Never book/cancel without explicit patient authorization event; never invent availability (APT rules).</td>
</tr>
<tr>
<td data-label="Agent">Med Access</td>
<td data-label="Tool Allowlist">pharmacy.call (Twilio flow), pharmacy.status_form, patient.ask_structured</td>
<td data-label="Max Retries">2/barrier</td>
<td data-label="Hard Prohibitions">No substitutions, dose advice, or clinical guidance, script templates only.</td>
</tr>
<tr>
<td data-label="Agent">Records</td>
<td data-label="Tool Allowlist">ehr.list_documents, ehr.fetch_binary</td>
<td data-label="Max Retries">5</td>
<td data-label="Hard Prohibitions">Approved document types only; read-only.</td>
</tr>
<tr>
<td data-label="Agent">Brief</td>
<td data-label="Tool Allowlist">facts.read(published), brief.render, notify.clinician_link</td>
<td data-label="Max Retries">2</td>
<td data-label="Hard Prohibitions">Assembles <strong>published</strong> facts only; cannot trigger confirmations.</td>
</tr>
<tr>
<td data-label="Agent">Outcome</td>
<td data-label="Tool Allowlist">adt.match, hie.lookup, claims.ingest</td>
<td data-label="Max Retries">5</td>
<td data-label="Hard Prohibitions">Read/match only; flags completeness, never edits episodes.</td>
</tr>
</tbody>
</table></div>
<h2 id="doc-modules-agents--h3">12.3 Policy Envelope (stored, versioned, enforced in code)</h2>
<pre><code>{ "agent": "med_access", "version": 4,
"tools": ["pharmacy.call","pharmacy.status_form","patient.ask_structured"],
"max_retries": 2, "retry_backoff_hours": [4, 24],
"requires_patient_authorization": false,
"clinical_boundaries": ["no_substitution","no_dose_advice"],
"cost_caps": {"tokens_per_run": 20000, "voice_minutes_per_run": 6},
"kill_scopes": ["global","tenant","cohort","agent","tool","integration"],
"logging": "full_evidence", "pii_redaction": "params_hashed" }
</code></pre>
<h2 id="doc-modules-agents--h4">12.4 Kill Switches (AUT-009)</h2>
<p>Six scopes resolve most-specific-wins; state lives in <code>tenant_config</code> with Redis cache TTL 10 s; the admin endpoint requires reason + role and takes effect before the next tool call. Read-only surfaces (Today, brief) are never disabled by agent kills.</p>
<h2 id="doc-modules-agents--h5">12.5 Exception Routing (PRD §8.1)</h2>
<div class="tbl-wrap"><table class="col-table compact"><colgroup><col class="col-xs"/><col class="col-md"/><col class="col-lg"/></colgroup>
<thead>
<tr>
<th>Level</th>
<th>Trigger</th>
<th>Terminal Route (MVP)</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Level">L1</td>
<td data-label="Trigger">Retry exhaustion on operational tasks (unreachable, scheduling fail, stock-out)</td>
<td data-label="Terminal Route (MVP)">Caregiver prompt (if consented) → <code>blocked</code> persists → weekly exception report; hospital queue only if <code>ops.tier=2</code> (AUT-006 keeps routine ops out of hospital queues).</td>
</tr>
<tr>
<td data-label="Level">L2</td>
<td data-label="Trigger">Conflicting sources; transcript vs order; uncertain material fact</td>
<td data-label="Terminal Route (MVP)"><code>pending_clinical_decision</code> → previsit brief open-questions; if no appointment within window → configured transition-team endpoint digest.</td>
</tr>
<tr>
<td data-label="Level">L3</td>
<td data-label="Trigger">Severe symptom report / explicit help request</td>
<td data-label="Terminal Route (MVP)">Immediate approved emergency instructions (911/ED language, versioned per EDU-007) + alert to configured clinical endpoint; never an improvised agent reply.</td>
</tr>
</tbody>
</table></div>
<div class="pn"><a class="pn-prev" href="#"></a><a class="pn-next" href="#"></a></div></article>