File size: 7,190 Bytes
612e777 5a79992 612e777 5a79992 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | <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 & 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>
|