1
0

feat: migrate to Agno native HITL tool confirmation flow (#158)

Replace the homebrew regex-based tool extraction and manual dispatch
(tool_executor.py) with Agno's built-in Human-In-The-Loop confirmation:

- Toolkit(requires_confirmation_tools=...) marks dangerous tools
- agent.run() returns RunOutput with status=paused when confirmation needed
- RunRequirement.confirm()/reject() + agent.continue_run() resumes execution

Dashboard and Discord vendor both use the native flow. DuckDuckGo import
isolated so its absence doesn't kill all tools. Test stubs cleaned up
(agno is a real dependency, only truly optional packages stubbed).

1384 tests pass in parallel (~14s).

Co-authored-by: Trip T <trip@local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alexander Whitestone
2026-03-09 21:54:04 -04:00
committed by GitHub
parent 574031a55c
commit 904a7c564e
18 changed files with 1317 additions and 85 deletions

View File

@@ -12,12 +12,39 @@
<small class="text-muted">Position in queue: {{ queue_info.position }}/{{ queue_info.total }}</small>
</div>
{% endif %}
{% if tool_actions %}
{% for action in tool_actions %}
<div class="approval-card pending" id="tool-{{ action.approval_id }}">
<div class="d-flex justify-content-between align-items-start mb-1">
<div class="approval-card-title">{{ action.tool_name }}</div>
<span class="impact-badge impact-{{ action.impact }}">{{ action.impact }}</span>
</div>
<div class="approval-card-desc">{{ action.description | e }}</div>
<div class="approval-actions">
<button class="btn-approve"
hx-post="/agents/default/tool/{{ action.approval_id }}/approve"
hx-target="#tool-{{ action.approval_id }}"
hx-swap="outerHTML">
APPROVE
</button>
<button class="btn-reject"
hx-post="/agents/default/tool/{{ action.approval_id }}/reject"
hx-target="#tool-{{ action.approval_id }}"
hx-swap="outerHTML">
REJECT
</button>
</div>
</div>
{% endfor %}
{% endif %}
<script>
(function() {
var script = document.currentScript;
var prev = script.previousElementSibling;
// Skip queue-status div to find the agent message div
if (prev && prev.classList.contains('queue-status')) prev = prev.previousElementSibling;
// Skip approval cards and queue-status div to find the agent message div
while (prev && (prev.classList.contains('approval-card') || prev.classList.contains('queue-status'))) {
prev = prev.previousElementSibling;
}
var el = prev ? prev.querySelector('.timmy-md') : null;
if (el && typeof marked !== 'undefined' && typeof DOMPurify !== 'undefined') {
el.innerHTML = DOMPurify.sanitize(marked.parse(el.textContent));