forked from Rockachopa/Timmy-time-dashboard
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>
63 lines
2.4 KiB
HTML
63 lines
2.4 KiB
HTML
<div class="chat-message user">
|
|
<div class="msg-meta">YOU // {{ timestamp }}</div>
|
|
<div class="msg-body">{{ user_message | e }}</div>
|
|
</div>
|
|
{% if response %}
|
|
<div class="chat-message agent"{% if task_id %} data-task-id="{{ task_id }}"{% endif %}>
|
|
<div class="msg-meta">TIMMY // {{ timestamp }}</div>
|
|
<div class="msg-body timmy-md">{{ response | e }}</div>
|
|
</div>
|
|
{% if queue_info %}
|
|
<div class="queue-status" data-task-id="{{ task_id }}" data-position="{{ queue_info.position }}" data-total="{{ queue_info.total }}">
|
|
<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 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));
|
|
if (typeof hljs !== 'undefined') {
|
|
el.querySelectorAll('pre code').forEach(function(block) { hljs.highlightElement(block); });
|
|
}
|
|
}
|
|
})();
|
|
</script>
|
|
{% elif error %}
|
|
<div class="chat-message error-msg">
|
|
<div class="msg-meta">SYSTEM // {{ timestamp }}</div>
|
|
<div class="msg-body">{{ error | e }}</div>
|
|
</div>
|
|
{% endif %}
|