(function () { const esc = (s) => String(s ?? '').replace(/&/g,'&').replace(//g,'>'); let state = { threadId: null, selectedAgent: 'A6' }; /** Usa o helper global do Desk (app.js) — garante JWT igual aos outros módulos. */ async function agentsApi(path, opts = {}) { const deskApi = typeof globalThis.api === 'function' ? globalThis.api : null; if (deskApi) return deskApi(`/v1/agents${path}`, opts); const h = authHeaders({ ...(opts.headers || {}) }); if (!(opts.body instanceof FormData) && !h['Content-Type']) h['Content-Type'] = 'application/json'; const r = await fetchWithTimeout(`/api/v1/agents${path}`, { ...opts, headers: h }, 60000); if (r.status === 401) { logout(); throw new Error('sessão expirada — faça login novamente'); } if (!r.ok) throw new Error(`${r.status} ${(await r.text()).slice(0, 200)}`); return r.json(); } function agentCard(a) { const active = state.selectedAgent === a.id ? ' agentic-agent-active' : ''; return `

${esc(a.name)} ${esc(a.id)}

${esc(a.role)}

Aprovação: ${esc(a.approval)}

`; } function inboxRow(m) { return `
${esc(m.agent_name || m.from_id)} ${esc(m.thread_severity || 'info')}

${esc(m.thread_subject || m.message)} · ${esc(m.created_at)}

${esc((m.body || '').slice(0, 280))}

`; } function threadBubble(m) { const isHuman = m.from_type === 'human'; const cls = isHuman ? 'agentic-bubble-human' : 'agentic-bubble-agent'; return `
${esc(m.from_label || m.from_id)} · ${esc(m.created_at)}
${esc(m.body).replace(/\n/g, '
')}
`; } async function loadThread(el, threadId) { state.threadId = threadId; const box = el.querySelector('#agentic-thread-messages'); if (!box) return; box.innerHTML = '

Carregando thread…

'; const data = await agentsApi(`/threads/${threadId}/messages`); box.innerHTML = data.messages.map(threadBubble).join('') || '

Sem mensagens.

'; box.scrollTop = box.scrollHeight; } async function renderAgenticOps() { const el = document.getElementById('agentic-ops-content'); if (!el) return; el.innerHTML = '

Carregando Agentic Ops…

'; if (!getToken()) { el.innerHTML = '

Sessão não encontrada neste endereço. Fazer login (use sempre o mesmo URL — ex. desk.ligbox.com.br).

'; return; } if (typeof ensureValidSession === 'function') { const ok = await ensureValidSession(); if (!ok) { el.innerHTML = '

Sessão expirada. Fazer login

'; return; } } try { const [health, roster, inbox, threads, findings] = await Promise.all([ agentsApi('/health'), agentsApi('/roster'), agentsApi('/inbox?limit=20'), agentsApi('/threads?limit=15'), agentsApi('/findings?limit=15'), ]); const tier = health.tier === 't1' ? 'T1 LLM' : 'T0'; const ollama = health.ollama ? `Ollama · ${esc(health.model)}` : 'Ollama offline'; const agents = roster.agents || []; const inboxItems = inbox.messages || []; const threadOpts = (threads.threads || []).map(t => `` ).join(''); const fRows = (findings.findings || []).map(f => `
  • ${esc(f.title)} ${esc(f.severity)} ${f.suggested_human_action ? `
    ${esc(f.suggested_human_action)}` : ''}
  • ` ).join('') || '
  • Nenhum finding aberto.
  • '; el.innerHTML = `

    Agentic Ops

    Spec 029 · ${tier} ${ollama} · ${inboxItems.length} pendente(s)

    Agentes (A0–A7)

    Clique para seleccionar destino do chat.

    ${agents.map(agentCard).join('')}

    Inbox operadores

    Mensagens dos agentes que exigem acção humana.

    ${inboxItems.length ? inboxItems.map(inboxRow).join('') : '

    Inbox vazia.

    '}

    Findings abertos

    Janela de contexto

    Seleccione uma thread ou abra da inbox.


    Chat Copiloto (${esc(state.selectedAgent)})

    `; el.querySelector('#btn-agentic-refresh')?.addEventListener('click', renderAgenticOps); el.querySelectorAll('.agentic-agent-card').forEach(card => { card.addEventListener('click', () => { state.selectedAgent = card.dataset.agentId; renderAgenticOps(); }); }); el.querySelectorAll('[data-open-thread]').forEach(btn => { btn.addEventListener('click', () => loadThread(el, parseInt(btn.dataset.openThread, 10))); }); el.querySelectorAll('[data-ack-msg]').forEach(btn => { btn.addEventListener('click', async () => { await agentsApi(`/messages/${btn.dataset.ackMsg}/ack`, { method: 'POST' }); await renderAgenticOps(); }); }); el.querySelector('#agentic-thread-select')?.addEventListener('change', (e) => { const id = parseInt(e.target.value, 10); if (id) loadThread(el, id); }); el.querySelector('#btn-agentic-reply')?.addEventListener('click', async () => { const input = el.querySelector('#agentic-reply-input'); const tid = state.threadId || parseInt(el.querySelector('#agentic-thread-select')?.value, 10); const body = (input?.value || '').trim(); if (!tid || !body) return; await agentsApi(`/threads/${tid}/reply`, { method: 'POST', body: JSON.stringify({ body, target_agent: state.selectedAgent }), }); input.value = ''; await loadThread(el, tid); }); el.querySelector('#btn-agentic-chat')?.addEventListener('click', async () => { const input = el.querySelector('#agentic-chat-input'); const out = el.querySelector('#agentic-chat-answer'); const q = (input?.value || '').trim(); if (!q) return; out.hidden = false; out.innerHTML = '

    A pensar…

    '; try { const res = await agentsApi('/chat', { method: 'POST', body: JSON.stringify({ question: q, include_findings: true, target_agent: state.selectedAgent }), }); out.innerHTML = `

    ${esc(state.selectedAgent)} (${esc(res.model)})

    ${esc(res.answer)}

    `; if (res.thread_id) { state.threadId = res.thread_id; await loadThread(el, res.thread_id); } } catch (err) { out.innerHTML = `

    ${esc(err.message)}

    `; } }); if (state.threadId) await loadThread(el, state.threadId); } catch (err) { el.innerHTML = `

    Erro: ${esc(err.message)}

    `; } } window.renderAgenticOps = renderAgenticOps; })();