import { ref, triggerRef, watch, computed, nextTick, onUnmounted, defineComponent, mergeProps, useSSRContext, createSlots, withCtx, openBlock, createBlock, createCommentVNode, toDisplayString, Fragment, renderList, createVNode, unref, createTextVNode, resolveDynamicComponent, withModifiers, onUpdated, toRef, onMounted, resolveComponent } from "vue"; import { ssrRenderAttrs, ssrRenderSlot, ssrRenderComponent, ssrRenderAttr, ssrInterpolate, ssrRenderList, ssrRenderVNode, ssrRenderClass, ssrIncludeBooleanAttr, ssrRenderStyle } from "vue/server-renderer"; import { useRouter, useRoute } from "vue-router"; import { u as useChatStore, w as ws, a as agents, g as getApiBase, b as auth, _ as _export_sfc, c as useTtsPlayer, d as useUI, e as agentLogo, s as scrollbarOptions } from "../main.mjs"; import { marked } from "marked"; import { OverlayScrollbarsComponent } from "overlayscrollbars-vue"; import { BoltIcon, ComputerDesktopIcon, CpuChipIcon, GlobeAltIcon, DocumentPlusIcon, WrenchIcon, PencilIcon, BookOpenIcon, ChatBubbleLeftIcon, LinkIcon, Cog6ToothIcon, SpeakerWaveIcon, ExclamationTriangleIcon, ChevronDownIcon, InformationCircleIcon, LockClosedIcon, UserGroupIcon, ChatBubbleBottomCenterTextIcon, PaperClipIcon, MicrophoneIcon, StopIcon, ArrowUpIcon } from "@heroicons/vue/20/solid"; import "@unhead/vue/server"; import "pinia"; import "@heroicons/vue/24/outline"; import "overlayscrollbars"; const VISIBLE_PAGE$1 = 50; const MAX_HUD_NODES = 100; function useSessionHistory(isAgentRunning, visibleCount, agentIdFn) { const store = useChatStore(); const sessionHistoryComplete = ref(false); const lastUsage = ref(null); let loadStartTime = null; let pendingMessages = []; let pendingUsageTotals = null; const lastSystemMsgRef = ref(null); const hudTree = ref([]); const hudVersion = ref(0); const hudPending = /* @__PURE__ */ new Map(); const hudTurns = /* @__PURE__ */ new Map(); const toolCallMap = /* @__PURE__ */ new Map(); function lookupByToolCallId(toolCallId) { if (!toolCallId) return null; const ref2 = toolCallMap.get(toolCallId); if (!ref2) return null; const node = ref2.deref(); if (!node) { toolCallMap.delete(toolCallId); return null; } return node; } const activeTurnCorrId = ref(null); function makeNode(partial) { return { id: partial.id || crypto.randomUUID(), type: partial.type || "received", state: partial.state || "running", label: partial.label || "", children: [], replay: partial.replay ?? false, startedAt: partial.startedAt || Date.now(), ...partial }; } function findNode(nodes, corrId) { for (const n of nodes) { if (n.correlationId === corrId) return n; if (n.children) { const found = findNode(n.children, corrId); if (found) return found; } } return null; } function addHudNode(node, parentCorrelationId) { if (parentCorrelationId && parentCorrelationId !== "history") { const parent = hudTurns.get(parentCorrelationId); if (parent) { parent.children.push(node); triggerRef(hudTree); hudVersion.value++; return; } } hudTree.value.unshift(node); if (hudTree.value.length > MAX_HUD_NODES) hudTree.value.splice(MAX_HUD_NODES); triggerRef(hudTree); hudVersion.value++; } function pushHudEvent(event) { const replay = !!event.replay; const ts = event.ts || Date.now(); const corrId = event.correlationId; const parentId = event.parentId; switch (event.event) { case "turn_start": { if (corrId && (hudPending.has(corrId) || hudTurns.has(corrId))) break; const node = makeNode({ type: "turn", state: "running", label: "🔄 Turn", correlationId: corrId, startedAt: ts, replay }); if (corrId) { hudPending.set(corrId, node); hudTurns.set(corrId, node); } if (!replay && corrId) activeTurnCorrId.value = corrId; addHudNode(node); break; } case "turn_end": { const node = corrId ? hudPending.get(corrId) : null; if (node) { node.state = "done"; node.endedAt = ts; node.durationMs = event.durationMs; if (corrId) { hudPending.delete(corrId); hudTurns.delete(corrId); } triggerRef(hudTree); hudVersion.value++; } if (!replay && corrId && activeTurnCorrId.value === corrId) activeTurnCorrId.value = null; break; } case "think_start": { const node = makeNode({ type: "think", state: "running", label: "Thinking", correlationId: corrId, startedAt: ts, replay }); if (corrId) hudPending.set(corrId, node); addHudNode(node, parentId); break; } case "think_end": { const node = corrId ? hudPending.get(corrId) : null; if (node) { node.state = "done"; node.endedAt = ts; node.durationMs = event.durationMs; if (corrId) hudPending.delete(corrId); triggerRef(hudTree); hudVersion.value++; } else { addHudNode(makeNode({ type: "think", state: "done", label: "Thinking", correlationId: corrId, startedAt: ts, endedAt: ts, durationMs: event.durationMs, replay }), parentId); } break; } case "tool_start": { const tool = event.tool || "unknown"; const args = event.args || {}; const label = buildToolLabel(tool, args); const node = makeNode({ type: "tool", state: "running", label, tool, args, correlationId: corrId, startedAt: ts, replay }); if (corrId) hudPending.set(corrId, node); if (event.toolCallId) toolCallMap.set(event.toolCallId, new WeakRef(node)); addHudNode(node, parentId); lastSystemMsgRef.value = label; break; } case "tool_end": { const tool = event.tool || "unknown"; const result = event.result || {}; let node = lookupByToolCallId(event.toolCallId) ?? (corrId ? hudPending.get(corrId) : null); if (!node && parentId) { const turnNode = findNode(hudTree.value, parentId); if (turnNode?.children) { const match = turnNode.children.find( (n) => n.type === "tool" && n.state === "running" && (n.tool === tool || n.tool === "unknown") ); if (match) { node = match; if (match.correlationId) hudPending.delete(match.correlationId); } } } if (node) { node.state = result.ok === false ? "error" : "done"; node.result = result; node.endedAt = ts; node.durationMs = event.durationMs; node.label = buildToolLabel(tool, node.args || {}, result); if (corrId) hudPending.delete(corrId); if (event.toolCallId) toolCallMap.delete(event.toolCallId); triggerRef(hudTree); hudVersion.value++; } else { const label = buildToolLabel(tool, event.args || {}, result); addHudNode(makeNode({ type: "tool", state: "done", label, tool, result, correlationId: corrId, startedAt: ts, endedAt: ts, durationMs: event.durationMs, replay }), parentId); } break; } case "received": { const node = makeNode({ type: "received", state: "done", subtype: event.subtype, label: event.label || event.subtype || "received", startedAt: ts, endedAt: ts, replay }); addHudNode(node); break; } } } function buildToolLabel(tool, args, result) { const fileTools = ["read", "write", "edit", "append"]; if (fileTools.includes(tool)) { const vp = args.viewerPath || args.path || ""; const filename = vp.split("/").pop() || vp; const area = result?.area || args.area; const areaStr = area ? `:L${area.startLine}–${area.endLine}` : ""; return `${filename}${areaStr}`; } if (tool === "exec") { const cmd = args.command || ""; return `${cmd.slice(0, 60)}${cmd.length > 60 ? "…" : ""}`; } if (tool === "web_fetch") return (args.url || "").slice(0, 60); if (tool === "web_search") return (args.query || "").slice(0, 60); return tool; } function getToolsForTurn(corrId) { if (!corrId) return []; const turn = hudTree.value.find((n) => n.correlationId === corrId) ?? [...hudTurns.values()].find((n) => n.correlationId === corrId); return turn ? turn.children.filter((c) => c.type === "tool") : []; } function hudSnapshot() { const lines = [`HUD tree — ${hudTree.value.length} root node(s) `]; for (const node of hudTree.value) { const dur = node.durationMs != null ? ` [${node.durationMs}ms]` : ""; const repl = node.replay ? " (replay)" : ""; lines.push(` ${node.state === "running" ? "⏳" : node.state === "error" ? "❌" : "✅"} [${node.type}] ${node.label}${dur}${repl}`); lines.push(` id=${node.id.slice(0, 8)} corrId=${(node.correlationId || "—").slice(0, 8)} children=${node.children.length}`); for (const child of node.children) { const cdur = child.durationMs != null ? ` [${child.durationMs}ms]` : ""; lines.push(` ${child.state === "running" ? "⏳" : child.state === "error" ? "❌" : "✅"} [${child.type}] ${child.label}${cdur}`); if (child.args) lines.push(` args: ${JSON.stringify(child.args).slice(0, 80)}`); if (child.result) lines.push(` result: ${JSON.stringify(child.result).slice(0, 80)}`); } } return lines.join("\n"); } function pushSystem(text) { lastSystemMsgRef.value = text; } function flushPendingClear(pendingClearRef) { if (!pendingClearRef.value) return; pendingClearRef.value = false; store.clearMessages(); visibleCount.value = VISIBLE_PAGE$1; sessionHistoryComplete.value = false; loadStartTime = performance.now(); pendingMessages = []; pendingUsageTotals = null; } function revealMessages() { loadStartTime = null; const _pending = pendingMessages; const _usage = pendingUsageTotals; pendingMessages = []; pendingUsageTotals = null; const idx = store.messages.findIndex((m) => m.role === "system" && m.content.includes("Loading session history...")); if (idx !== -1) { store.messages.splice(idx, 1, ..._pending); } else { store.messages.unshift(..._pending); } const revealedCount = _pending.filter((m) => m.role !== "system").length; store.sessionContextHint = revealedCount > 0 ? `${revealedCount} msgs in context` : "fresh context"; if (_usage) lastUsage.value = _usage; } function handleSessionHistory(entries) { if (!entries?.length) return; if (loadStartTime === null) loadStartTime = performance.now(); if (!store.messages.some((m) => m.content?.includes("Loading session history..."))) { store.pushSystem("⏳ Loading session history...", agentIdFn()); } const newMsgs = []; const currentAgentId = agentIdFn(); const currentSessionId = store.localSessionId; let pendingUsage = null; for (const data of entries) { if (data.type === "hud") { pushHudEvent({ ...data, replay: true }); continue; } if (data.event === "tool_start" || data.event === "tool_end" || data.event === "think_start" || data.event === "think_end" || data.event === "turn_start" || data.event === "turn_end" || data.event === "received") { pushHudEvent({ ...data, replay: true }); continue; } if (data.entry_type === "session_context") { newMsgs.push({ role: "session_context", content: data.content || "", agentId: currentAgentId, sessionId: currentSessionId }); } else if (data.entry_type === "user_message") { newMsgs.push({ role: "user", content: data.content || "", agentId: currentAgentId, sessionId: currentSessionId }); } else if (data.entry_type === "assistant_text") { const content = (data.content || "").replace(/^\[\[reply_to[^\]]*\]\]\s*/i, "").trim(); if (!content) continue; const msg = { role: "assistant", content, streaming: false, agentId: currentAgentId, sessionId: currentSessionId, timestamp: data.ts || null }; if (data.truncated) msg.truncated = true; if (pendingUsage) { msg.usage = pendingUsage; pendingUsage = null; } newMsgs.push(msg); } else if (data.entry_type === "usage") { pendingUsage = { input_tokens: data.input_tokens || 0, output_tokens: data.output_tokens || 0, total_tokens: data.total_tokens || 0, cost: Number(data.cost || 0) }; const last = newMsgs[newMsgs.length - 1]; if (last?.role === "assistant") { last.usage = pendingUsage; pendingUsage = null; } } } pendingMessages = newMsgs; const totalUsage = entries.filter((e) => e.entry_type === "usage").reduce((acc, e) => ({ input_tokens: acc.input_tokens + (e.input_tokens || 0), output_tokens: acc.output_tokens + (e.output_tokens || 0), total_tokens: acc.total_tokens + (e.total_tokens || 0), cost: acc.cost + Number(e.cost || 0) }), { input_tokens: 0, output_tokens: 0, total_tokens: 0, cost: 0 }); pendingUsageTotals = totalUsage.total_tokens > 0 ? totalUsage : null; } function handleSessionEntry(data, sentMessages, pushSystemFn) { if (data.type === "hud") { pushHudEvent(data); return; } const isReplay = !sessionHistoryComplete.value; const currentAgentId = agentIdFn(); const currentSessionId = store.localSessionId; switch (data.entry_type) { case "user_message": { const raw = data.content || ""; if (raw.startsWith("A new session was started")) break; if (!isReplay && raw.includes("[voice transcript]:")) break; const hasByMsgId = data.msgId && store.messages.some((m) => m.msgId === data.msgId); if (hasByMsgId) break; if (!isReplay && !sentMessages.has(raw.trim())) { store.messages.push({ role: "user", content: raw, agentId: currentAgentId, sessionId: currentSessionId, msgId: data.msgId }); } else { sentMessages.delete(raw.trim()); } break; } } } function resetHudMaps() { hudPending.clear(); hudTurns.clear(); toolCallMap.clear(); activeTurnCorrId.value = null; hudTree.value = []; hudVersion.value++; } function toolCallMapSnapshot() { return [...toolCallMap.entries()].map(([k, ref2]) => { const node = ref2.deref(); return { toolCallId: k, label: node?.label ?? null, state: node?.state ?? null, stale: !node }; }); } return { sessionHistoryComplete, lastUsage, lastSystemMsgRef, hudTree, hudVersion, activeTurnCorrId, getToolsForTurn, pushHudEvent, hudSnapshot, toolCallMapSnapshot, resetHudMaps, flushPendingClear, revealMessages, handleSessionHistory, handleSessionEntry, pushSystem }; } function useAgentSocket(visibleCount, lastUsage, pendingClearRef, sentMessages, restoreLastSent) { const chatStore = useChatStore(); const { send: wsSend, onMessage: onWsMessage, replayBuffer } = ws; const { updateFromServer, selectedAgent } = agents; const handoverInProgress = () => chatStore.smState === "HANDOVER_PENDING" || chatStore.smState === "HANDOVER_DONE"; const isAgentRunning = () => chatStore.smState === "AGENT_RUNNING"; const history = useSessionHistory(isAgentRunning, visibleCount, () => selectedAgent.value); history.lastUsage = lastUsage; watch(history.activeTurnCorrId, (id) => { chatStore.activeTurnCorrId = id; }); function pushSystem(text) { history.pushSystem(text); } function mount() { const handlers = { auth_ok(data) { updateFromServer(data); }, ready(data) { updateFromServer(data); if (data.session_id) chatStore.sessionKey = data.session_id; else if (data.sessionId) chatStore.sessionKey = data.sessionId; chatStore.applyConnectionState("SYNCED"); chatStore.applyChannelState("READY"); }, // assay session info — store session ID for reconnect session_info(data) { if (data.session_id) chatStore.sessionKey = data.session_id; }, // assay UI controls — store for later rendering controls(_data) { }, // assay artifacts — store for later rendering artifacts(_data) { }, // assay session cleared cleared(_data) { chatStore.messages.splice(0); }, thinking(data) { if (!handoverInProgress()) chatStore.appendThinking(data.content); }, delta(data) { if (!handoverInProgress()) { history.flushPendingClear(pendingClearRef); chatStore.collapseThinking(); chatStore.appendAssistantDelta(data.content, data.agentId); } }, message(data) { if (handoverInProgress()) return; history.flushPendingClear(pendingClearRef); if (data.streaming === false) { chatStore.createCompleteAssistantMessage(data.content, data.agentId, data.usage); } else if (data.final) { chatStore.finalizeAssistantMessage(null, data.usage); } }, truncated_warning(_data) { chatStore.collapseThinking(); if (chatStore.hasActiveStreamingMessage()) chatStore.finalizeAssistantMessage(null, void 0, true); chatStore.truncatedWarning = true; }, done(data) { if (handoverInProgress()) return; chatStore.collapseThinking(); if (data.suppress) { chatStore.suppressAssistantMessage(); } else { const doneContent = data.content || null; if (chatStore.hasActiveStreamingMessage()) { const deltaLen = chatStore.streamingMessageLength(); const useContent = doneContent && deltaLen < doneContent.length ? doneContent : null; chatStore.finalizeAssistantMessage(useContent, data.usage); } else if (doneContent) { chatStore.createCompleteAssistantMessage(doneContent, void 0, data.usage); } } history.lastSystemMsgRef.value = null; }, session_history(data) { if (chatStore.hasActiveStreamingMessage()) chatStore.finalizeAssistantMessage(null); chatStore.collapseThinking(); history.flushPendingClear(pendingClearRef); history.handleSessionHistory(data.entries); }, hud(data) { history.pushHudEvent(data); if (data.event === "turn_start" && !data.replay) { chatStore.activeTurnCorrId = data.correlationId ?? null; chatStore.startNewAssistantMessage(selectedAgent.value); } }, event(data) { if (data.event === "agent") { const stream = data.payload?.stream; if (stream === "tool") { console.log("[HUD agent/tool]", JSON.stringify(data.payload).slice(0, 400)); } } }, tool(data) { if (data.action === "call") { pushSystem(`${data.tool} ${data.args || ""}`); } else if (data.action === "result") { pushSystem(`→ ${data.result || ""}`); } }, session_entry(data) { history.handleSessionEntry(data, sentMessages, pushSystem); }, message_update(data) { if (!data.msgId || !data.patch) return; const patch = { ...data.patch }; if (patch.voiceAudioUrl) { const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; patch.voiceAudioUrl = `${patch.voiceAudioUrl}?token=${encodeURIComponent(token)}`; } if (patch.transcript) { sentMessages.add(`[voice transcript]: ${patch.transcript}`.trim()); } const patched = chatStore.patchMessage(data.msgId, patch); if (!patched) { console.warn("[message_update] no message found for msgId:", data.msgId); } }, handover_done(data) { chatStore.messages.push({ role: "assistant", content: data.content || "📋 Handover written.", agentId: selectedAgent.value, sessionId: chatStore.localSessionId }); chatStore.messages.push({ role: "system", content: "Start a new session with this handover context?", confirmNew: true, confirmed: false, agentId: selectedAgent.value, sessionId: chatStore.localSessionId }); }, handover_context(_data) { }, // New two-SM protocol: channel_state + connection_state channel_state(data) { if (!data.state) return; if (data.clear_history) { console.log("[clear] channel switch", { state: data.state, msgCount: chatStore.messages.length }); history.resetHudMaps(); chatStore.messages.length = 0; pendingClearRef.value = false; } const prevChannel = chatStore.channelState; chatStore.applyChannelState(data.state); if (data.state === "READY" || data.state === "FRESH") { history.lastSystemMsgRef.value = null; if (chatStore.queuedThought !== null && prevChannel === "AGENT_RUNNING") { const thought = chatStore.queuedThought; chatStore.queuedThought = null; wsSend({ type: "message", content: thought }); } } }, connection_state(data) { if (!data.state) return; chatStore.applyConnectionState(data.state); if (data.state === "LOADING_HISTORY") { history.resetHudMaps(); chatStore.messages.length = 0; pendingClearRef.value = false; } if (data.state === "SYNCED") { history.flushPendingClear(pendingClearRef); history.revealMessages(); } }, // Legacy: still handle session_state for backward compat session_state(data) { if (!data.state) return; if (data.reconnected) ; if (data.reconnected || data.clear_history) { console.log("[clear] immediate flush", { reconnected: data.reconnected, clear_history: data.clear_history, state: data.state, msgCount: chatStore.messages.length }); chatStore.stashMessages(); history.resetHudMaps(); chatStore.messages.length = 0; pendingClearRef.value = false; } chatStore.applySessionState(data.state); if (data.state === "READY" || data.state === "FRESH" || data.state === "IDLE") { history.lastSystemMsgRef.value = null; if (chatStore.queuedThought !== null) { const thought = chatStore.queuedThought; chatStore.queuedThought = null; wsSend({ type: "message", content: thought }); } } }, session_total_tokens(data) { chatStore.sessionTotalTokens = data; }, finance_update(data) { chatStore.finance = data; }, usage(data) { if (!handoverInProgress()) { chatStore.sessionTotalTokens = { input_tokens: data.input_tokens || (chatStore.sessionTotalTokens?.input_tokens || 0), cache_read_tokens: data.cache_read_tokens || (chatStore.sessionTotalTokens?.cache_read_tokens || 0), output_tokens: data.output_tokens || (chatStore.sessionTotalTokens?.output_tokens || 0) }; } }, session_status(data) { if (data.status === "no_session") { pendingClearRef.value = true; history.flushPendingClear(pendingClearRef); chatStore.messages.push({ role: "system", type: "no_session", content: "-- NO SESSION --", agentId: selectedAgent.value, sessionId: chatStore.localSessionId }); chatStore.sessionContextHint = ""; } else if (data.status === "watching") { history.flushPendingClear(pendingClearRef); history.sessionHistoryComplete.value = true; history.revealMessages(); } }, sent(_data) { }, switch_ok(data) { history.sessionHistoryComplete.value = false; if (data.sessionKey) chatStore.sessionKey = data.sessionKey; }, new_ok(_data) { history.sessionHistoryComplete.value = false; }, error(data) { if (data.code === "SESSION_TERMINATED") { chatStore.pushSystem("⚠️ Message not delivered — session was resetting. Please try again.", selectedAgent.value); restoreLastSent?.(); } else if (data.code === "DISCARDED_NOT_IDLE" || data.code === "DISCARDED_NOT_READY") { chatStore.pushSystem("⚠️ Message not delivered — agent was busy. Please try again.", selectedAgent.value); restoreLastSent?.(); } }, stopped(_data) { chatStore.pushSystem("✅ Agent stopped", selectedAgent.value); }, killed(_data) { chatStore.pushSystem("☠️ Agent killed", selectedAgent.value); } }; const unsubscribe = onWsMessage((data) => { const handler = handlers[data.type]; if (handler) handler(data); }); replayBuffer((data) => { const handler = handlers[data.type]; if (handler) handler(data); }); return unsubscribe; } return { mount, lastSystemMsg: history.lastSystemMsgRef, hudTree: history.hudTree, hudVersion: history.hudVersion, getToolsForTurn: history.getToolsForTurn, hudSnapshot: history.hudSnapshot, toolCallMapSnapshot: history.toolCallMapSnapshot, sessionHistoryComplete: history.sessionHistoryComplete, pushSystem, hasActiveStreamingMessage: chatStore.hasActiveStreamingMessage }; } function generateMsgId() { return crypto.randomUUID(); } const renderer = new marked.Renderer(); renderer.link = ({ href, title, text }) => { const titleAttr = title ? ` title="${title}"` : ""; return `${text}`; }; function ansiToHtml(text) { const colorMap = { 30: "#555", 31: "#e06c75", 32: "#98c379", 33: "#e5c07b", 34: "#61afef", 35: "#c678dd", 36: "#56b6c2", 37: "#abb2bf" }; let open = false, bold = false, dim = false; const result = text.replace(/\x1b\[([0-9;]*)m/g, (_match, codes) => { const parts = codes.split(";").map(Number); let out = ""; for (const code of parts) { if (code === 0) { if (open) { out += ""; open = false; } if (bold) { out += ""; bold = false; } if (dim) { out += ""; dim = false; } } else if (code === 1) { if (!bold) { out += ""; bold = true; } } else if (code === 2) { if (!dim) { out += ''; dim = true; } } else if (colorMap[code]) { if (open) { out += ""; } out += ``; open = true; } } return out; }); let tail = ""; if (open) tail += ""; if (bold) tail += ""; if (dim) tail += ""; return result + tail; } const WORKSPACE_PATH_RE = /(workspace\/[^\s"'<>)]+\.(?:pdf|png|jpg|jpeg|gif|csv|json|txt|md|html|zip|mp3|wav|ogg|webm|m4a))/g; const WORKSPACE_PREFIX = ""; const AUDIO_EXTENSIONS = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "webm", "m4a"]); function linkifyWorkspaceFiles(html) { return html.replace(WORKSPACE_PATH_RE, (match) => { const name = match.split("/").pop() || match; const absPath = match.startsWith("/") ? match : WORKSPACE_PREFIX + match; const ext = name.split(".").pop()?.toLowerCase() || ""; if (AUDIO_EXTENSIONS.has(ext)) { return ``; } return ``; }); } if (typeof window !== "undefined" && !window.__hermesAudioSrc) { window.__hermesAudioSrc = (el) => { if (el.src) return; const filepath = el.dataset.filepath; if (!filepath) return; const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; const apiBase = getApiBase(); el.src = `${apiBase}/api/files${filepath}?token=${encodeURIComponent(token)}`; }; } if (typeof window !== "undefined" && !window.__hermesDownload) { window.__hermesDownload = async (el) => { const filepath = el.dataset.filepath; const filename = el.dataset.filename || "download"; if (!filepath) return; el.textContent = "⏳ " + filename; try { const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; const apiBase2 = getApiBase(); const res = await fetch(`${apiBase2}/api/files${filepath}?token=${encodeURIComponent(token)}`); if (!res.ok) throw new Error(`${res.status}`); const blob = await res.blob(); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); el.textContent = "✅ " + filename; } catch (err) { el.textContent = "❌ " + filename; console.error("[download]", err); } }; } function parseMd(content) { const raw = content || ""; if (/\x1b\[/.test(raw)) { const escaped = raw.replace(/&/g, "&").replace(//g, ">"); return `
${ansiToHtml(escaped)}
`; } let html = marked.parse(raw, { renderer, async: false, gfm: true, breaks: true }); html = linkifyWorkspaceFiles(html); return html; } const DRAFT_KEY = "chat_draft"; const HISTORY_KEY = "chat_input_history"; const HISTORY_MAX = 50; function loadDraft() { try { return sessionStorage.getItem(DRAFT_KEY) || ""; } catch { return ""; } } function saveDraft(v) { try { if (v) sessionStorage.setItem(DRAFT_KEY, v); else sessionStorage.removeItem(DRAFT_KEY); } catch { } } function loadHistory() { try { return JSON.parse(sessionStorage.getItem(HISTORY_KEY) || "[]"); } catch { return []; } } function pushHistory(v) { try { const h = loadHistory().filter((x) => x !== v); h.unshift(v); sessionStorage.setItem(HISTORY_KEY, JSON.stringify(h.slice(0, HISTORY_MAX))); } catch { } } function useMessages(wsSendFn) { const store = useChatStore(); const sending = ref(false); const input = ref(loadDraft()); const messagesEl = ref(null); let historyIdx = -1; function getViewport() { const el = messagesEl.value; if (!el) return null; const root = el.$el || el; return root.querySelector?.("[data-overlayscrollbars-viewport]") || root; } function scrollToBottom() { nextTick(() => { nextTick(() => { requestAnimationFrame(() => { const vp = getViewport(); if (vp) vp.scrollTop = vp.scrollHeight; }); }); }); } function scrollIfAtBottom() { const vp = getViewport(); if (!vp) return; if (vp.scrollHeight - vp.scrollTop - vp.clientHeight < 80) scrollToBottom(); } let draftTimer = null; function onInputChange() { if (draftTimer) clearTimeout(draftTimer); draftTimer = setTimeout(() => saveDraft(input.value), 1e3); } function navigateHistory(dir) { const history = loadHistory(); if (!history.length) return; if (dir === "up") { historyIdx = Math.min(historyIdx + 1, history.length - 1); } else { historyIdx = Math.max(historyIdx - 1, -1); } input.value = historyIdx === -1 ? "" : history[historyIdx]; } let lastSentContent = ""; function restoreLastSent() { input.value = lastSentContent; } async function send(attachmentPayload) { const hasText = input.value.trim().length > 0; const hasAttachments = attachmentPayload && attachmentPayload.length > 0; if (!hasText && !hasAttachments || sending.value) return; const content = input.value.trim(); if (hasText) { lastSentContent = content; pushHistory(content); } historyIdx = -1; input.value = ""; saveDraft(""); sending.value = true; const msgId = generateMsgId(); const localAttachments = hasAttachments ? attachmentPayload.map((a) => { const mime = a.mimeType.split(";")[0]; let dataUrl; if (a.mimeType.startsWith("audio/")) { const bytes = Uint8Array.from(atob(a.content), (c) => c.charCodeAt(0)); dataUrl = URL.createObjectURL(new Blob([bytes], { type: mime })); } else { dataUrl = `data:${mime};base64,${a.content}`; } return { mimeType: a.mimeType, fileName: a.fileName, dataUrl }; }) : void 0; const hasAudio = hasAttachments && attachmentPayload.some((a) => a.mimeType.startsWith("audio/")); store.pushMessage({ role: "user", content, agentId: null, msgId, attachments: localAttachments, pending: hasAudio // audio messages are pending until transcript arrives }); const payload = { type: "message", content, msgId }; if (hasAttachments) payload.attachments = attachmentPayload; wsSendFn(payload); sending.value = false; } return { sending, input, messagesEl, parseMd, scrollToBottom, scrollIfAtBottom, send, onInputChange, navigateHistory, restoreLastSent, startNewAssistantMessage: store.startNewAssistantMessage, appendAssistantMessage: store.appendAssistantDelta, finalizeAssistantMessage: store.finalizeAssistantMessage, resetAssistantMessageState: store.resetLocalSession, hasActiveStreamingMessage: store.hasActiveStreamingMessage, streamingMessageVisibleContent: computed(() => store.streamingMessageVisibleContent) }; } function useMessageGrouping(messages, visibleCount, selectedAgent, allAgents, sessionKey) { const VISIBLE_PAGE2 = 50; const visibleMsgs = computed(() => { const all = messages.value; const start = Math.max(0, all.length - visibleCount.value); return all.slice(start).map((m, i) => ({ ...m, _sourceIndex: start + i })); }); const hasMore = computed(() => messages.value.length > visibleCount.value); function loadMore() { visibleCount.value += VISIBLE_PAGE2; } function getFormattedAgentName(agentId) { if (!agentId) return "Unknown"; const agent = allAgents.value.find((a) => a.id === agentId); return agent ? agent.name : agentId; } function shouldShowHeadline(index, msgsArr) { if (index === 0) return true; const current = msgsArr[index]; const prev = msgsArr[index - 1]; if (!current.agentId || !prev.agentId) { return current.sessionId !== prev.sessionId; } return current.agentId !== prev.agentId || current.sessionId !== prev.sessionId; } function formatHeadlineText(agentName) { const key = sessionKey?.value; return key ? `${agentName} · ${key}` : agentName; } function getHeadline(index, msgsArr) { const current = msgsArr[index]; const targetAgentId = current.agentId || selectedAgent.value; const agentName = getFormattedAgentName(targetAgentId); if (index === 0) return { text: formatHeadlineText(agentName), kind: "agent" }; const prev = msgsArr[index - 1]; if (current.agentId !== prev.agentId) return { text: formatHeadlineText(agentName), kind: "agent" }; if (current.sessionId !== prev.sessionId) return { text: "New Session", kind: "new-session" }; return { text: formatHeadlineText(agentName), kind: "agent" }; } const groupedVisibleMsgs = computed(() => { const raw = visibleMsgs.value; const result = []; let currentGroup = null; for (let i = 0; i < raw.length; i++) { const msg = raw[i]; if (shouldShowHeadline(i, raw)) { if (currentGroup) { result.push(currentGroup); currentGroup = null; } const { text, kind } = getHeadline(i, raw); result.push({ role: "system", type: "headline", content: text, headlineKind: kind, agentId: msg.agentId, sessionId: msg.sessionId, position: "header" // Header appears before agent block }); } if (msg.role === "system" && msg.type !== "no_session") { if (!currentGroup) { currentGroup = { role: "system_group", messages: [msg], agentId: msg.agentId, sessionId: msg.sessionId }; } else { currentGroup.messages.push(msg); } } else { if (currentGroup) { result.push(currentGroup); currentGroup = null; } result.push(msg); const effectiveAgentId = msg.agentId || selectedAgent.value; if (effectiveAgentId && i === raw.length - 1) { const agentName = getFormattedAgentName(effectiveAgentId); result.push({ role: "system", type: "headline", content: formatHeadlineText(agentName), headlineKind: "agent", agentId: effectiveAgentId, sessionId: msg.sessionId, position: "footer" }); } } } if (currentGroup) result.push(currentGroup); return result; }); return { visibleMsgs, groupedVisibleMsgs, hasMore, loadMore, getFormattedAgentName }; } function useInputAutogrow(input) { const inputEl = ref(null); const isShaking = ref(false); function autoGrow() { const el = inputEl.value; if (!el) return; el.style.height = "auto"; el.style.height = el.scrollHeight + "px"; el.style.overflowY = el.scrollHeight > 160 ? "auto" : "hidden"; } function triggerShake() { isShaking.value = true; setTimeout(() => { isShaking.value = false; }, 400); } watch(input, (val) => { if (!val) nextTick(() => autoGrow()); }); return { inputEl, isShaking, autoGrow, triggerShake }; } function useAgentDisplay(selectedAgent, defaultAgent, allAgents) { const chatStore = useChatStore(); const defaultAgentName = computed(() => { const agent = allAgents.value.find((a) => a.id === defaultAgent.value); return agent ? agent.name : defaultAgent.value; }); const agentDisplayName = computed(() => { const agent = allAgents.value.find((a) => a.id === selectedAgent.value); return (agent ? agent.name : selectedAgent.value).toUpperCase(); }); const isAgentRunning = computed(() => chatStore.smState === "AGENT_RUNNING"); const agentStatusDone = computed(() => chatStore.channelState === "READY" || chatStore.channelState === "FRESH"); const agentStatus = computed(() => { switch (chatStore.smState) { case "CONNECTING": return "⚙️ Connecting…"; case "AGENT_RUNNING": return "⚙️ Working…"; case "HANDOVER_PENDING": return "📝 Writing handover…"; case "HANDOVER_DONE": return "✅ Handover ready"; case "SWITCHING": return "🔀 Switching…"; default: return null; } }); return { defaultAgentName, agentDisplayName, isAgentRunning, agentStatusDone, agentStatus }; } const ACCEPTED_TYPES = [ "image/jpeg", "image/png", "image/gif", "image/webp", "application/pdf", "audio/webm", "audio/mp4", "audio/ogg", "audio/mpeg", "audio/wav", "audio/x-m4a" ]; const MAX_BYTES = 10 * 1024 * 1024; function readAsBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { const result = reader.result; const idx = result.indexOf(","); resolve(idx >= 0 ? result.slice(idx + 1) : result); }; reader.onerror = () => reject(reader.error); reader.readAsDataURL(file); }); } function useAttachments() { const attachments = ref([]); async function addFiles(files) { for (const file of Array.from(files)) { const baseType = file.type.split(";")[0]; if (!ACCEPTED_TYPES.includes(baseType) && !ACCEPTED_TYPES.includes(file.type)) { console.warn(`[attachments] skipped ${file.name}: unsupported type ${file.type}`); continue; } if (file.size > MAX_BYTES) { console.warn(`[attachments] skipped ${file.name}: exceeds 5MB (${(file.size / 1024 / 1024).toFixed(1)}MB)`); continue; } const base64 = await readAsBase64(file); const preview = URL.createObjectURL(file); attachments.value.push({ file, preview, base64, mimeType: file.type, fileName: file.name }); } } function removeAttachment(index) { const att = attachments.value[index]; if (att) URL.revokeObjectURL(att.preview); attachments.value.splice(index, 1); } function clearAttachments() { for (const att of attachments.value) URL.revokeObjectURL(att.preview); attachments.value = []; } function toPayload() { return attachments.value.map((a) => ({ type: a.mimeType.startsWith("image/") ? "image" : a.mimeType.startsWith("audio/") ? "audio" : "document", mimeType: a.mimeType, content: a.base64, fileName: a.fileName })); } function hasAttachments() { return attachments.value.length > 0; } return { attachments, addFiles, removeAttachment, clearAttachments, toPayload, hasAttachments }; } function useAudioRecorder() { const isRecording = ref(false); const duration = ref(0); const audioLevel = ref(0); const micDenied = ref(false); let mediaRecorder = null; let stream = null; let audioCtx = null; let analyser = null; let levelBuf = null; let chunks = []; let timer = null; let startTime = 0; function cleanup() { if (timer) { clearInterval(timer); timer = null; } if (audioCtx) { audioCtx.close().catch(() => { }); audioCtx = null; analyser = null; levelBuf = null; } if (stream) { stream.getTracks().forEach((t) => t.stop()); stream = null; } mediaRecorder = null; chunks = []; duration.value = 0; audioLevel.value = 0; isRecording.value = false; } function updateLevel() { if (!analyser || !levelBuf) return; analyser.getByteTimeDomainData(levelBuf); let sum = 0; for (let i = 0; i < levelBuf.length; i++) { const v = (levelBuf[i] - 128) / 128; sum += v * v; } audioLevel.value = Math.min(1, Math.sqrt(sum / levelBuf.length) * 3); } async function startRecording() { if (isRecording.value) return; try { stream = await navigator.mediaDevices.getUserMedia({ audio: true }); } catch (err) { console.warn("[audio] mic access denied:", err); micDenied.value = true; setTimeout(() => { micDenied.value = false; }, 5e3); return; } try { audioCtx = new AudioContext(); const source = audioCtx.createMediaStreamSource(stream); analyser = audioCtx.createAnalyser(); analyser.fftSize = 256; source.connect(analyser); levelBuf = new Uint8Array(analyser.fftSize); } catch (err) { console.warn("[audio] analyser setup failed:", err); } chunks = []; const mimeType = MediaRecorder.isTypeSupported("audio/webm;codecs=opus") ? "audio/webm;codecs=opus" : MediaRecorder.isTypeSupported("audio/webm") ? "audio/webm" : ""; mediaRecorder = new MediaRecorder(stream, mimeType ? { mimeType } : void 0); mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) chunks.push(e.data); }; mediaRecorder.start(250); isRecording.value = true; startTime = Date.now(); timer = setInterval(() => { duration.value = Math.floor((Date.now() - startTime) / 1e3); updateLevel(); }, 80); } function stopRecording() { return new Promise((resolve) => { if (!mediaRecorder || mediaRecorder.state === "inactive") { cleanup(); resolve(null); return; } mediaRecorder.onstop = () => { const mimeType = mediaRecorder?.mimeType || "audio/webm"; const ext = mimeType.includes("mp4") ? "mp4" : mimeType.includes("ogg") ? "ogg" : "webm"; const blob = new Blob(chunks, { type: mimeType }); const file = new File([blob], `recording-${Date.now()}.${ext}`, { type: mimeType }); cleanup(); resolve(file); }; mediaRecorder.stop(); }); } function cancelRecording() { if (mediaRecorder && mediaRecorder.state !== "inactive") { mediaRecorder.onstop = () => { }; mediaRecorder.stop(); } cleanup(); } function formatDuration(secs) { const m = Math.floor(secs / 60); const s = secs % 60; return `${m}:${s.toString().padStart(2, "0")}`; } onUnmounted(cleanup); return { isRecording, duration, audioLevel, micDenied, startRecording, stopRecording, cancelRecording, formatDuration }; } const _sfc_main$6 = /* @__PURE__ */ defineComponent({ __name: "MessageFrame", __ssrInlineRender: true, props: { role: {}, copyContent: {} }, setup(__props) { return (_ctx, _push, _parent, _attrs) => { _push(``); if (__props.role !== "system") { _push(``); } else { _push(``); } ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent); if (_ctx.$slots.footer) { _push(``); } else { _push(``); } _push(``); }; } }); const _sfc_setup$6 = _sfc_main$6.setup; _sfc_main$6.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/MessageFrame.vue"); return _sfc_setup$6 ? _sfc_setup$6(props, ctx) : void 0; }; const _sfc_main$5 = /* @__PURE__ */ defineComponent({ __name: "UserMessage", __ssrInlineRender: true, props: { msg: {} }, setup(__props) { const props = __props; const username = auth.currentUser; const expandedSrc = ref(""); function expandImage(src) { expandedSrc.value = src; } const audioAttachment = computed(() => (props.msg.attachments || []).find((a) => a.mimeType?.startsWith("audio/"))); const nonAudioAttachments = computed(() => (props.msg.attachments || []).filter((a) => !a.mimeType?.startsWith("audio/"))); return (_ctx, _push, _parent, _attrs) => { _push(``); _push(ssrRenderComponent(_sfc_main$6, { role: "user", copyContent: __props.msg.content }, createSlots({ default: withCtx((_, _push2, _parent2, _scopeId) => { if (_push2) { if (__props.msg.voiceAudioUrl) { _push2(``); } else if (audioAttachment.value) { _push2(``); } else { _push2(``); } if (__props.msg.pending) { _push2(`
transcribing...
`); } else { _push2(``); } if (__props.msg.content) { _push2(`
${ssrInterpolate(__props.msg.content)}
`); } else { _push2(``); } if (nonAudioAttachments.value.length) { _push2(`
`); ssrRenderList(nonAudioAttachments.value, (att, i) => { _push2(``); if (att.mimeType === "application/pdf") { _push2(`
📄${ssrInterpolate(att.fileName || "document.pdf")}
`); } else { _push2(`
`); } _push2(``); }); _push2(`
`); } else { _push2(``); } } else { return [ __props.msg.voiceAudioUrl ? (openBlock(), createBlock("audio", { key: 0, controls: "", src: __props.msg.voiceAudioUrl, class: "user-att-audio" }, null, 8, ["src"])) : audioAttachment.value ? (openBlock(), createBlock("audio", { key: 1, controls: "", src: audioAttachment.value.dataUrl, class: "user-att-audio" }, null, 8, ["src"])) : createCommentVNode("", true), __props.msg.pending ? (openBlock(), createBlock("div", { key: 2, class: "voice-pending" }, "transcribing...")) : createCommentVNode("", true), __props.msg.content ? (openBlock(), createBlock("div", { key: 3 }, toDisplayString(__props.msg.content), 1)) : createCommentVNode("", true), nonAudioAttachments.value.length ? (openBlock(), createBlock("div", { key: 4, class: "user-attachments" }, [ (openBlock(true), createBlock(Fragment, null, renderList(nonAudioAttachments.value, (att, i) => { return openBlock(), createBlock(Fragment, { key: i }, [ att.mimeType === "application/pdf" ? (openBlock(), createBlock("div", { key: 0, class: "user-att-pdf", title: att.fileName || "PDF" }, [ createVNode("span", { class: "pdf-icon" }, "📄"), createVNode("span", { class: "pdf-name" }, toDisplayString(att.fileName || "document.pdf"), 1) ], 8, ["title"])) : (openBlock(), createBlock("div", { key: 1, class: "user-att-thumb", onClick: ($event) => expandImage(att.dataUrl) }, [ createVNode("img", { src: att.dataUrl, alt: att.fileName || "image", loading: "lazy" }, null, 8, ["src", "alt"]) ], 8, ["onClick"])) ], 64); }), 128)) ])) : createCommentVNode("", true) ]; } }), _: 2 }, [ unref(username) ? { name: "footer", fn: withCtx((_, _push2, _parent2, _scopeId) => { if (_push2) { _push2(`${ssrInterpolate(unref(username))}`); } else { return [ createTextVNode(toDisplayString(unref(username)), 1) ]; } }), key: "0" } : void 0 ]), _parent)); if (expandedSrc.value) { _push(``); } else { _push(``); } _push(``); }; } }); const _sfc_setup$5 = _sfc_main$5.setup; _sfc_main$5.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/UserMessage.vue"); return _sfc_setup$5 ? _sfc_setup$5(props, ctx) : void 0; }; const UserMessage = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-90f9dace"]]); const _sfc_main$4 = /* @__PURE__ */ defineComponent({ __name: "ToolIcon", __ssrInlineRender: true, props: { tool: {} }, setup(__props) { const props = __props; const iconMap = { read: BookOpenIcon, write: PencilIcon, edit: WrenchIcon, append: DocumentPlusIcon, exec: BoltIcon, web_search: GlobeAltIcon, web_fetch: GlobeAltIcon, memory_search: CpuChipIcon, memory_get: CpuChipIcon, browser: ComputerDesktopIcon }; const icon = computed(() => { if (!props.tool) return BoltIcon; const t = props.tool.toLowerCase(); if (iconMap[t]) return iconMap[t]; if (t.includes("message")) return ChatBubbleLeftIcon; if (t.includes("session")) return LinkIcon; return Cog6ToothIcon; }); return (_ctx, _push, _parent, _attrs) => { ssrRenderVNode(_push, createVNode(resolveDynamicComponent(icon.value), mergeProps({ class: "tool-icon w-3.5 h-3.5 inline shrink-0" }, _attrs), null), _parent); }; } }); const _sfc_setup$4 = _sfc_main$4.setup; _sfc_main$4.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/ToolIcon.vue"); return _sfc_setup$4 ? _sfc_setup$4(props, ctx) : void 0; }; function relativeTime(isoOrDate) { const then = typeof isoOrDate === "string" ? new Date(isoOrDate) : isoOrDate; const now = Date.now(); const diffMs = now - then.getTime(); if (diffMs < 0) return "just now"; const sec = Math.floor(diffMs / 1e3); if (sec < 60) return "just now"; const min = Math.floor(sec / 60); if (min < 60) return `${min}m ago`; const hr = Math.floor(min / 60); if (hr < 24) return `${hr}h ago`; const days = Math.floor(hr / 24); if (days < 30) return `${days}d ago`; return then.toLocaleDateString(); } const _sfc_main$3 = /* @__PURE__ */ defineComponent({ __name: "AssistantMessage", __ssrInlineRender: true, props: { msg: {}, agentDisplayName: {}, isAgentRunning: { type: Boolean }, allAgents: {}, getToolsForTurn: { type: Function }, hudVersion: {} }, setup(__props) { const chatStore = useChatStore(); const ttsPlayer = useTtsPlayer(); const props = __props; const displayName = computed(() => { const id = props.msg.agentId; if (id) { const agent = props.allAgents?.find((a) => a.id === id); return (agent ? agent.name : id).toUpperCase(); } return props.agentDisplayName; }); const msgTimeLabel = computed(() => { if (props.msg.timestamp) { return relativeTime(props.msg.timestamp); } return "Done"; }); const content = computed(() => { if (props.msg.streaming) { return chatStore.streamingMessageVisibleContent + '...'; } return props.msg.content; }); const tools = computed(() => { void props.hudVersion; return props.getToolsForTurn(props.msg.turnCorrId); }); return (_ctx, _push, _parent, _attrs) => { _push(ssrRenderComponent(_sfc_main$6, mergeProps({ role: "assistant", copyContent: __props.msg.content }, _attrs), { footer: withCtx((_, _push2, _parent2, _scopeId) => { if (_push2) { _push2(`${ssrInterpolate(displayName.value)}`); if (!__props.msg.streaming && __props.msg.content) { _push2(``); } else { _push2(``); } if (__props.msg.streaming && tools.value.length === 0) { _push2(` ...`); } else if (!__props.msg.streaming && tools.value.length === 0) { _push2(` | ${ssrInterpolate(msgTimeLabel.value)}`); } else { _push2(``); } if (tools.value.length > 0) { _push2(``); ssrRenderList(tools.value, (tool) => { _push2(``); _push2(ssrRenderComponent(_sfc_main$4, { tool: tool.tool || "" }, null, _parent2, _scopeId)); _push2(``); }); _push2(``); } else { _push2(``); } if (__props.msg.truncated) { _push2(``); _push2(ssrRenderComponent(unref(ExclamationTriangleIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId)); _push2(` Output limit reached — response was cut off`); } else { _push2(``); } } else { return [ createVNode("span", { class: "footer-name" }, toDisplayString(displayName.value), 1), !__props.msg.streaming && __props.msg.content ? (openBlock(), createBlock("button", { key: 0, class: ["tts-btn", { active: unref(ttsPlayer).isPlayingMsg(__props.msg) }], onClick: withModifiers(($event) => unref(ttsPlayer).play(__props.msg, __props.msg._sourceIndex ?? 0), ["stop"]), title: "Listen" }, [ unref(ttsPlayer).isPlayingMsg(__props.msg) && unref(ttsPlayer).state.value === "loading" ? (openBlock(), createBlock("span", { key: 0, class: "tts-spinner" })) : (openBlock(), createBlock(unref(SpeakerWaveIcon), { key: 1, class: "w-3.5 h-3.5" })) ], 10, ["onClick"])) : createCommentVNode("", true), __props.msg.streaming && tools.value.length === 0 ? (openBlock(), createBlock("span", { key: 1, class: "footer-status" }, " ...")) : !__props.msg.streaming && tools.value.length === 0 ? (openBlock(), createBlock("span", { key: 2, class: "footer-status" }, " | " + toDisplayString(msgTimeLabel.value), 1)) : createCommentVNode("", true), tools.value.length > 0 ? (openBlock(), createBlock("span", { key: 3, class: "footer-tools" }, [ (openBlock(true), createBlock(Fragment, null, renderList(tools.value, (tool) => { return openBlock(), createBlock("span", { key: tool.id, class: ["footer-tool-icon", tool.state], title: `${tool.label} [${tool.state}]` }, [ createVNode(_sfc_main$4, { tool: tool.tool || "" }, null, 8, ["tool"]) ], 10, ["title"]); }), 128)) ])) : createCommentVNode("", true), __props.msg.truncated ? (openBlock(), createBlock("span", { key: 4, class: "truncated-notice" }, [ createVNode(unref(ExclamationTriangleIcon), { class: "w-4 h-4 inline" }), createTextVNode(" Output limit reached — response was cut off") ])) : createCommentVNode("", true) ]; } }), default: withCtx((_, _push2, _parent2, _scopeId) => { if (_push2) { _push2(`
${unref(parseMd)(content.value) ?? ""}
`); } else { return [ createVNode("div", { innerHTML: unref(parseMd)(content.value) }, null, 8, ["innerHTML"]) ]; } }), _: 1 }, _parent)); }; } }); const _sfc_setup$3 = _sfc_main$3.setup; _sfc_main$3.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/AssistantMessage.vue"); return _sfc_setup$3 ? _sfc_setup$3(props, ctx) : void 0; }; const AssistantMessage = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-a59db10d"]]); const _sfc_main$2 = /* @__PURE__ */ defineComponent({ __name: "SystemMessage", __ssrInlineRender: true, props: { msg: {} }, setup(__props) { const props = __props; const isCollapsed = ref(false); const groupContentEl = ref(null); onUpdated(() => { nextTick(() => { if (groupContentEl.value) { groupContentEl.value.scrollTop = groupContentEl.value.scrollHeight; } }); }); function isSqlResult(content) { if (!content) return false; const raw = content.startsWith("→ ") ? content.slice(2) : content; const lines = raw.split("\n").filter((l) => l.trim()); if (lines.length < 2) return false; return lines.filter((l) => l.includes(" ")).length >= 2; } function parseSqlTable(content) { const raw = content.startsWith("→ ") ? content.slice(2) : content; const lines = raw.split("\n").filter((l) => l.trim()); const [headerLine, ...dataLines] = lines; const headers = headerLine.split(" "); const rows = dataLines.filter((l) => !l.startsWith("… [")).map((l) => l.split(" ")); return { headers, rows }; } function getSummary() { const msgs = props.msg.messages; if (!msgs?.length) return "Event"; const toolNames = []; for (const m of msgs) { const raw = m.content || ""; const match = raw.match(/^[^\w]*(\w+)/u); if (match) { const name = match[1]; if (!["true", "false", "null", "done", "ok"].includes(name.toLowerCase())) { if (!toolNames.includes(name)) toolNames.push(name); } } } const callCount = msgs.length; const label = toolNames.length ? toolNames.join(" · ") : "Event"; return callCount === 1 ? label : `${label} · ${callCount}`; } return (_ctx, _push, _parent, _attrs) => { _push(``); if (__props.msg.type === "headline" && __props.msg.headlineKind !== "new-session" && __props.msg.position !== "footer") { _push(`
${ssrInterpolate(__props.msg.content)}
`); } else if (__props.msg.type === "headline" && __props.msg.headlineKind !== "new-session" && __props.msg.position === "footer") { _push(``); } else if (__props.msg.type === "headline" && __props.msg.headlineKind === "new-session") { _push(`
${ssrInterpolate(__props.msg.content)}
`); } else if (__props.msg.role === "system_group" || __props.msg.messages) { _push(`
`); _push(ssrRenderComponent(unref(Cog6ToothIcon), { class: "system-group-icon-svg" }, null, _parent)); _push(`${ssrInterpolate(getSummary())}`); _push(ssrRenderComponent(unref(ChevronDownIcon), { class: ["chevron", { open: !isCollapsed.value }] }, null, _parent)); _push(`
`); if (!isCollapsed.value) { _push(`
`); ssrRenderList(__props.msg.messages, (subMsg, idx) => { _push(`
`); if (isSqlResult(subMsg.content)) { _push(`
`); ssrRenderList(parseSqlTable(subMsg.content).headers, (col, ci) => { _push(``); }); _push(``); ssrRenderList(parseSqlTable(subMsg.content).rows, (row, ri) => { _push(``); ssrRenderList(row, (cell, ci) => { _push(``); }); _push(``); }); _push(`
${ssrInterpolate(col)}
${ssrInterpolate(cell)}
`); } else { _push(`
${ssrInterpolate(subMsg.content)}
`); } _push(`
`); }); _push(`
`); } else { _push(``); } _push(`
`); } else { _push(`
`); _push(ssrRenderComponent(unref(InformationCircleIcon), { class: "system-group-icon-svg" }, null, _parent)); _push(`${ssrInterpolate(__props.msg.content)}
`); } _push(``); }; } }); const _sfc_setup$2 = _sfc_main$2.setup; _sfc_main$2.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/SystemMessage.vue"); return _sfc_setup$2 ? _sfc_setup$2(props, ctx) : void 0; }; const SystemMessage = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-6cdcd5f1"]]); const _sfc_main$1 = /* @__PURE__ */ defineComponent({ __name: "HudControls", __ssrInlineRender: true, props: { smState: String, connected: Boolean, isAgentRunning: Boolean, handoverPending: Boolean, isPublic: Boolean }, emits: ["new", "handover", "confirm-new", "stay"], setup(__props) { return (_ctx, _push, _parent, _attrs) => { _push(`
`); if (!__props.isPublic) { _push(``); } else { _push(``); } _push(`
`); }; } }); const _sfc_setup$1 = _sfc_main$1.setup; _sfc_main$1.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/HudControls.vue"); return _sfc_setup$1 ? _sfc_setup$1(props, ctx) : void 0; }; const HudControls = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-89c5a82c"]]); const VISIBLE_PAGE = 50; const _sfc_main = /* @__PURE__ */ defineComponent({ ...{ name: "AgentsView" }, __name: "AgentsView", __ssrInlineRender: true, setup(__props) { useRouter(); const agentsRoute = useRoute(); const chatStore = useChatStore(); const showPicker = computed(() => !agentsRoute.query.agent); watch(() => agentsRoute.query.agent, (val) => { if (!val && agentsRoute.name === "agents") ; }, { immediate: true }); const prevSessions = ref([]); const prevHasMore = ref(false); const prevLoading = ref(false); const prevSkip = ref(0); const prevMessages = computed(() => prevSessions.value.flatMap((s) => s.messages)); async function fetchPreviousSession(loadMore2 = false) { if (!selectedAgent.value || prevLoading.value) return; prevLoading.value = true; try { const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; const skip = loadMore2 ? prevSkip.value : 0; const apiBase = getApiBase(); const res = await fetch(`${apiBase}/api/session-history?agent=${selectedAgent.value}&mode=${selectedMode.value}&skip=${skip}&count=1`, { headers: { "Authorization": `Bearer ${token}` } }); if (!res.ok) return; const data = await res.json(); const newSessions = (data.sessions || []).map((s) => ({ messages: (s.entries || []).map((e) => ({ role: e.role, content: e.content, timestamp: e.timestamp, agentId: selectedAgent.value, streaming: false })), timestamp: s.resetTimestamp, timeLabel: s.resetTimestamp ? relativeTime(s.resetTimestamp) : "" })); if (loadMore2) { prevSessions.value = [...newSessions, ...prevSessions.value]; } else { prevSessions.value = newSessions; } prevSkip.value = skip + newSessions.length; prevHasMore.value = data.hasMore ?? false; } catch { } finally { prevLoading.value = false; } } const { connected, status, send: wsSend } = ws; useUI(status); ref(""); const { isLoggedIn } = auth; const { selectedAgent, selectedMode, filteredAgents, defaultAgent, allAgents } = agents; const SEGMENTS = ["personal", "common", "private", "public"]; const agentSegments = computed( () => SEGMENTS.map((key) => ({ key, agents: filteredAgents.value.filter((a) => (a.segment ?? "utility") === key).sort((a, b) => a.name.localeCompare(b.name)) })).filter((s) => s.agents.length > 0) ); computed(() => agentLogo(selectedAgent.value)); const { sending, input, messagesEl, scrollToBottom, restoreLastSent } = useMessages(wsSend); const controlsEl = ref(null); ref(null); const smState = toRef(chatStore, "smState"); const channelState = toRef(chatStore, "channelState"); const connectionState = toRef(chatStore, "connectionState"); const smLabel = toRef(chatStore, "smLabel"); const isHidden = computed(() => connectionState.value !== "SYNCED"); const footerHeadline = computed(() => { const msgs = groupedVisibleMsgs.value; const last = msgs[msgs.length - 1]; return last?.position === "footer" ? last : null; }); const lastRealMsgIdx = computed(() => { const msgs = groupedVisibleMsgs.value; for (let i = msgs.length - 1; i >= 0; i--) { if (msgs[i].type !== "headline") return i; } return -1; }); const visibleCount = ref(VISIBLE_PAGE); const { groupedVisibleMsgs, hasMore, loadMore, getFormattedAgentName } = useMessageGrouping( computed(() => chatStore.messages), visibleCount, selectedAgent, allAgents, toRef(chatStore, "sessionKey") ); const sentMessages = /* @__PURE__ */ new Set(); const lastUsage = ref(null); const pendingClearRef = ref(false); const { mount, hudVersion, getToolsForTurn, hudSnapshot, toolCallMapSnapshot } = useAgentSocket(visibleCount, lastUsage, pendingClearRef, sentMessages, restoreLastSent); if (typeof window !== "undefined") { window.__hudSnapshot = hudSnapshot; window.__toolCallMap = toolCallMapSnapshot; } const viewActive = computed(() => agentsRoute.name === "agents"); let userSendInFlight = false; const spacerHeight = ref(0); function getViewport() { const el = messagesEl.value; if (!el) return null; const root = el.$el || el; return root.querySelector("[data-overlayscrollbars-viewport]"); } function recalcSpacerSync() { const viewport = getViewport(); if (!viewport) return 0; const controls = controlsEl.value || viewport.querySelector(".msg-controls"); if (!controls) return 0; const userMsgs = viewport.querySelectorAll(".message.user"); const last = userMsgs[userMsgs.length - 1]; if (!last) return 0; const vpRect = viewport.getBoundingClientRect(); const st = viewport.scrollTop; const msgTop = last.getBoundingClientRect().top - vpRect.top + st; const ctrlBottom = controls.getBoundingClientRect().bottom - vpRect.top + st; const vpH = viewport.clientHeight; const needed = msgTop - 40 + vpH; const h = Math.max(0, needed - ctrlBottom); spacerHeight.value = h; return h; } let _spacerInterval = null; onMounted(() => { _spacerInterval = setInterval(recalcSpacerSync, 200); onUnmounted(() => { if (_spacerInterval) clearInterval(_spacerInterval); }); }); watch(connectionState, (val) => { if (!viewActive.value) return; if (val === "SYNCED") { if (!prevMessages.value.length) fetchPreviousSession(); scrollToBottom(); } }); watch(channelState, (val, prev) => { if (!viewActive.value) return; if (prev === "AGENT_RUNNING" && (val === "READY" || val === "FRESH")) { userSendInFlight = false; } if (val === "AGENT_RUNNING" && prev !== "AGENT_RUNNING") { if (!userSendInFlight) { scrollToBottom(); } } }); function onNew() { chatStore.newSession(); scrollToBottom(); } function onConfirmNew() { chatStore.confirmNew(); scrollToBottom(); } const { isShaking } = useInputAutogrow(input); const { isAgentRunning } = useAgentDisplay(selectedAgent, defaultAgent, allAgents); const { attachments, hasAttachments } = useAttachments(); ref(null); const isDragOver = ref(false); const { isRecording, duration, audioLevel, micDenied, formatDuration } = useAudioRecorder(); watch([selectedAgent, selectedMode], ([agent, mode], [oldAgent, oldMode]) => { if (agent !== oldAgent || mode !== oldMode) { sessionStorage.setItem("agent", agent); lastUsage.value = null; sentMessages.clear(); prevSessions.value = []; prevHasMore.value = false; prevSkip.value = 0; chatStore.resetLocalSession(); } }); onMounted(() => { chatStore.setWsSend(wsSend); const unsubscribe = mount(); if (connectionState.value === "SYNCED") fetchPreviousSession(); const viewport = getViewport(); let ro = null; if (viewport) { ro = new ResizeObserver(() => recalcSpacerSync()); ro.observe(viewport); } recalcSpacerSync(); onUnmounted(() => { unsubscribe(); ro?.disconnect(); }); }); return (_ctx, _push, _parent, _attrs) => { const _component_RouterLink = resolveComponent("RouterLink"); if (unref(isLoggedIn)) { _push(`

Select an agent

`); ssrRenderList(agentSegments.value, (seg) => { _push(`
${ssrInterpolate(seg.key)}
`); ssrRenderList(seg.agents, (agent) => { _push(`
`); if (agent.modes?.includes("private")) { _push(``); } else { _push(``); } if (agent.modes?.includes("public")) { _push(``); } else { _push(``); } _push(`
`); }); _push(`
`); }); _push(`
`); _push(ssrRenderComponent(unref(OverlayScrollbarsComponent), { class: ["messages h-full pb-4 flex flex-col gap-3 relative", { "is-switching": isHidden.value }], options: unref(scrollbarOptions), ref_key: "messagesEl", ref: messagesEl, element: "div" }, { default: withCtx((_, _push2, _parent2, _scopeId) => { if (_push2) { if (prevSessions.value.length) { _push2(``); if (prevHasMore.value) { _push2(``); } else { _push2(``); } _push2(``); ssrRenderList(prevSessions.value, (session, si) => { _push2(`
Session ${ssrInterpolate(prevSessions.value.length - si)}${ssrInterpolate(session.timeLabel ? " — " + session.timeLabel : "")}
`); ssrRenderList(session.messages, (msg, mi) => { _push2(``); if (msg.role === "user") { _push2(ssrRenderComponent(UserMessage, { msg }, null, _parent2, _scopeId)); } else if (msg.role === "assistant") { _push2(ssrRenderComponent(AssistantMessage, { msg, agentDisplayName: unref(getFormattedAgentName)(msg.agentId || unref(selectedAgent)), isAgentRunning: false, allAgents: unref(allAgents), getToolsForTurn: () => [], hudVersion: 0 }, null, _parent2, _scopeId)); } else { _push2(``); } _push2(``); }); _push2(`
`); }); _push2(`
Current session
`); } else { _push2(``); } _push2(``); ssrRenderList(unref(groupedVisibleMsgs), (msg, i) => { _push2(``); if (msg.type === "no_session") { _push2(`
— NO SESSION —
`); } else { _push2(``); } if (msg.type !== "no_session" && (msg.role === "system" || msg.role === "system_group" || msg.type === "headline") && msg.position !== "footer") { _push2(ssrRenderComponent(SystemMessage, { msg }, null, _parent2, _scopeId)); } else { _push2(``); } if (unref(hasMore) && msg.type === "headline" && msg.position !== "footer" && i === 0) { _push2(``); } else if (msg.role === "session_context") { _push2(`
${ssrInterpolate(msg.content)}
`); } else if (msg.role === "user") { _push2(ssrRenderComponent(UserMessage, { msg }, null, _parent2, _scopeId)); } else if (msg.role === "thinking") { _push2(`
`); _push2(ssrRenderComponent(unref(ChatBubbleBottomCenterTextIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId)); _push2(` thinking…
${ssrInterpolate(typeof msg.content === "object" ? msg.content.value : msg.content)}
`); } else if (msg.role === "assistant") { _push2(ssrRenderComponent(AssistantMessage, { msg, agentDisplayName: unref(getFormattedAgentName)(msg.agentId), isAgentRunning: unref(isAgentRunning), allAgents: unref(allAgents), getToolsForTurn: unref(getToolsForTurn), hudVersion: unref(hudVersion) }, null, _parent2, _scopeId)); } else { _push2(``); } if (i === lastRealMsgIdx.value) { _push2(`
${ssrInterpolate(smLabel.value)}
`); } else { _push2(``); } _push2(``); }); _push2(``); if (lastRealMsgIdx.value === -1) { _push2(`
${ssrInterpolate(smLabel.value)}
`); } else { _push2(``); } if (footerHeadline.value) { _push2(ssrRenderComponent(SystemMessage, { msg: footerHeadline.value }, null, _parent2, _scopeId)); } else { _push2(``); } _push2(`
`); _push2(ssrRenderComponent(HudControls, { smState: smState.value, connected: unref(connected), isAgentRunning: unref(chatStore).isRunning, handoverPending: unref(chatStore).handoverPending, isPublic: unref(selectedMode) === "public", onNew, onHandover: ($event) => unref(chatStore).handover(), onConfirmNew, onStay: ($event) => unref(chatStore).stay() }, null, _parent2, _scopeId)); _push2(`
`); } else { return [ prevSessions.value.length ? (openBlock(), createBlock(Fragment, { key: 0 }, [ prevHasMore.value ? (openBlock(), createBlock("button", { key: 0, class: "prev-load-more", onClick: ($event) => fetchPreviousSession(true), disabled: prevLoading.value }, toDisplayString(prevLoading.value ? "Loading..." : "Load older session"), 9, ["onClick", "disabled"])) : createCommentVNode("", true), (openBlock(true), createBlock(Fragment, null, renderList(prevSessions.value, (session, si) => { return openBlock(), createBlock(Fragment, { key: "ps-" + si }, [ createVNode("div", { class: "prev-session-header" }, " Session " + toDisplayString(prevSessions.value.length - si) + toDisplayString(session.timeLabel ? " — " + session.timeLabel : ""), 1), createVNode("div", { class: "prev-session-wrapper" }, [ (openBlock(true), createBlock(Fragment, null, renderList(session.messages, (msg, mi) => { return openBlock(), createBlock(Fragment, { key: "prev-" + si + "-" + mi }, [ msg.role === "user" ? (openBlock(), createBlock(UserMessage, { key: 0, msg }, null, 8, ["msg"])) : msg.role === "assistant" ? (openBlock(), createBlock(AssistantMessage, { key: 1, msg, agentDisplayName: unref(getFormattedAgentName)(msg.agentId || unref(selectedAgent)), isAgentRunning: false, allAgents: unref(allAgents), getToolsForTurn: () => [], hudVersion: 0 }, null, 8, ["msg", "agentDisplayName", "allAgents"])) : createCommentVNode("", true) ], 64); }), 128)) ]) ], 64); }), 128)), createVNode("div", { class: "session-divider" }, [ createVNode("span", { class: "session-divider-text" }, "Current session") ]) ], 64)) : createCommentVNode("", true), (openBlock(true), createBlock(Fragment, null, renderList(unref(groupedVisibleMsgs), (msg, i) => { return openBlock(), createBlock(Fragment, { key: i }, [ msg.type === "no_session" ? (openBlock(), createBlock("div", { key: 0, class: "no-session-center" }, "— NO SESSION —")) : createCommentVNode("", true), msg.type !== "no_session" && (msg.role === "system" || msg.role === "system_group" || msg.type === "headline") && msg.position !== "footer" ? (openBlock(), createBlock(SystemMessage, { key: 1, msg }, null, 8, ["msg"])) : createCommentVNode("", true), unref(hasMore) && msg.type === "headline" && msg.position !== "footer" && i === 0 ? (openBlock(), createBlock("button", { key: 2, class: "load-more-btn", onClick: unref(loadMore) }, "↑ Load previous messages", 8, ["onClick"])) : msg.role === "session_context" ? (openBlock(), createBlock("div", { key: 3, class: "session-context-badge" }, [ createVNode("span", { class: "session-context-text" }, toDisplayString(msg.content), 1) ])) : msg.role === "user" ? (openBlock(), createBlock(UserMessage, { key: 4, msg }, null, 8, ["msg"])) : msg.role === "thinking" ? (openBlock(), createBlock("div", { key: 5, class: "message thinking" }, [ createVNode("details", { open: !msg.collapsed }, [ createVNode("summary", null, [ createVNode(unref(ChatBubbleBottomCenterTextIcon), { class: "w-4 h-4 inline" }), createTextVNode(" thinking…") ]), createVNode("pre", { class: "thinking-content" }, toDisplayString(typeof msg.content === "object" ? msg.content.value : msg.content), 1) ], 8, ["open"]) ])) : msg.role === "assistant" ? (openBlock(), createBlock(AssistantMessage, { key: 6, msg, agentDisplayName: unref(getFormattedAgentName)(msg.agentId), isAgentRunning: unref(isAgentRunning), allAgents: unref(allAgents), getToolsForTurn: unref(getToolsForTurn), hudVersion: unref(hudVersion) }, null, 8, ["msg", "agentDisplayName", "isAgentRunning", "allAgents", "getToolsForTurn", "hudVersion"])) : createCommentVNode("", true), i === lastRealMsgIdx.value ? (openBlock(), createBlock("div", { key: 7, class: "sm-status-bar" }, [ createVNode("div", { class: ["sm-dot", smState.value] }, null, 2), createVNode("span", { class: "sm-status-label" }, toDisplayString(smLabel.value), 1) ])) : createCommentVNode("", true) ], 64); }), 128)), lastRealMsgIdx.value === -1 ? (openBlock(), createBlock("div", { key: 1, class: "sm-status-bar" }, [ createVNode("div", { class: ["sm-dot", smState.value] }, null, 2), createVNode("span", { class: "sm-status-label" }, toDisplayString(smLabel.value), 1) ])) : createCommentVNode("", true), footerHeadline.value ? (openBlock(), createBlock(SystemMessage, { key: 2, msg: footerHeadline.value }, null, 8, ["msg"])) : createCommentVNode("", true), createVNode("div", { class: "msg-controls", ref_key: "controlsEl", ref: controlsEl }, [ createVNode(HudControls, { smState: smState.value, connected: unref(connected), isAgentRunning: unref(chatStore).isRunning, handoverPending: unref(chatStore).handoverPending, isPublic: unref(selectedMode) === "public", onNew, onHandover: ($event) => unref(chatStore).handover(), onConfirmNew, onStay: ($event) => unref(chatStore).stay() }, null, 8, ["smState", "connected", "isAgentRunning", "handoverPending", "isPublic", "onHandover", "onStay"]) ], 512), createVNode("div", { class: "scroll-spacer", style: { height: spacerHeight.value + "px", flexShrink: 0 } }, null, 4) ]; } }), _: 1 }, _parent)); _push(`
`); if (unref(micDenied)) { _push(`
Mic access denied — enable in browser settings
`); } else { _push(``); } if (unref(isRecording)) { _push(`
${ssrInterpolate(unref(formatDuration)(unref(duration)))}
`); } else { _push(``); } if (unref(attachments).length) { _push(`
`); ssrRenderList(unref(attachments), (att, i) => { _push(`
`); if (att.mimeType.startsWith("audio/")) { _push(`${ssrInterpolate(att.fileName)}`); } else { _push(``); } _push(`
`); }); _push(`
`); } else { _push(``); } _push(`
`); if (smState.value === "AGENT_RUNNING" || smState.value === "STOP_PENDING") { _push(``); } else { _push(``); } _push(`
`); } else { _push(`

`); _push(ssrRenderComponent(unref(LockClosedIcon), { class: "w-5 h-5 inline" }, null, _parent)); _push(` Not logged in

`); _push(ssrRenderComponent(_component_RouterLink, { to: "/login" }, { default: withCtx((_, _push2, _parent2, _scopeId) => { if (_push2) { _push2(`Sign in →`); } else { return [ createTextVNode("Sign in →") ]; } }), _: 1 }, _parent)); _push(``); } }; } }); const _sfc_setup = _sfc_main.setup; _sfc_main.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/AgentsView.vue"); return _sfc_setup ? _sfc_setup(props, ctx) : void 0; }; const AgentsView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-8c19bd9d"]]); export { AgentsView as default };