Files
store/agents/agent-gem.sune

1 line
21 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[{"id":"ayh9lnn","name":"Agent Gem","pinned":true,"avatar":"data:image/webp;base64,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","url":"gh://sune-org/store/agents/agent-gem.sune","updatedAt":1757470283979,"settings":{"model":"g:gemini-2.5-pro","temperature":"","top_p":"","top_k":"","frequency_penalty":"","repetition_penalty":"","min_p":"","top_a":"","verbosity":"","reasoning_effort":"default","system_prompt":"You are an autonomous live agent. Depending on the task, you may return partial html or JavaScript. If returning html realize that you are inserting into already existing html. Tailwind, lucide, dom-cash, alpinejs are available. When you return code in triple backticks, it runs immediately.\nAccessing individual API keys:\nwindow.USER.apiKeyGoogle\nwindow.USER.apiKeyCloudflare\nwindow.USER.githubToken\nTypically when you send your response, the chat is concluded. If required anywhere in your response put <3 as in the heart of the conversation needs to stay alive for another round. The <3 will ensure the conversation doesnt end.\nYou can use this command to pass information to the next chat, for example when you need to know the return value of something, put it here and the next chat will output it:\n```js\nwindow.SUNE.log(str)\n```\nThe output of this function is rendered with markdown. So of you are expecting json for example, put str in a json code fence, etc.\nYou ('Agent Gem') have the ability to handoff the chat to other models, via: ```js\nwindow.SUNE.handoff(nameStr) ``` // no <3 necessary\nOther agents available are:\n\"Agent Qwen\" // qwen3-coder\n\"Agent Flash\" // gemini-2.5-flash\nExpect errors and wait to verify you were successful first. Don't forget to use <3 to stay alive unless handing off. Store your code in a window.var so we can access it and commit to GitHub.","html":"<div class=\"p-3 sm:p-4\">\n<div id=\"agent-panel-root\" class=\"mx-auto w-full max-w-3xl rounded-xl border border-gray-200 bg-white p-3 shadow-sm\">\n<div class=\"flex items-center justify-between gap-3\">\n<div class=\"flex items-center gap-2\">\n<i data-lucide=\"brain-circuit\" class=\"h-5 w-5 text-gray-600\"></i>\n<span class=\"text-sm font-medium text-gray-800\">Agent Control</span>\n</div>\n<span id=\"agent-panel-version\" class=\"text-xs text-gray-400\"></span>\n</div>\n\n<div class=\"mt-3 flex items-center justify-between rounded-lg bg-gray-100 p-2\">\n <label id=\"agent-panel-status\" class=\"cursor-pointer text-sm text-gray-700\"></label>\n <button type=\"button\" role=\"switch\" aria-checked=\"false\" id=\"agent-panel-toggle\" class=\"relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-gray-300 transition-colors duration-200 ease-in-out focus:outline-none\">\n <span id=\"agent-panel-toggle-handle\" class=\"pointer-events-none inline-block h-5 w-5 transform translate-x-0 rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out\"></span>\n </button>\n</div>\n\n<div class=\"mt-2 border-t border-gray-200 pt-2\">\n <button id=\"agent-panel-console-toggle\" class=\"flex w-full items-center justify-between text-left text-sm font-medium text-gray-600 hover:text-black\">\n <span>Console</span>\n <i id=\"agent-panel-console-chevron\" data-lucide=\"chevron-down\" class=\"h-4 w-4 transition-transform\"></i>\n </button>\n\n <div id=\"agent-panel-console-container\" class=\"mt-2 hidden\">\n <pre id=\"agent-panel-console\" class=\"max-h-56 overflow-y-auto rounded-md bg-gray-900 p-2 text-xs font-mono leading-relaxed text-white\"></pre>\n <div class=\"mt-2 grid grid-cols-3 gap-2\">\n <button id=\"agent-panel-clear-logs\" class=\"flex items-center justify-center gap-2 rounded-md bg-gray-100 px-3 py-1.5 text-xs text-gray-600 hover:bg-gray-200\">\n <i data-lucide=\"trash-2\" class=\"h-3 w-3\"></i> Clear\n </button>\n <button id=\"agent-panel-clear-exec\" class=\"flex items-center justify-center gap-2 rounded-md bg-gray-100 px-3 py-1.5 text-xs text-gray-600 hover:bg-gray-200\">\n <i data-lucide=\"rotate-ccw\" class=\"h-3 w-3\"></i> Forget\n </button>\n <button id=\"agent-panel-clear-canvas\" class=\"flex items-center justify-center gap-2 rounded-md bg-gray-100 px-3 py-1.5 text-xs text-gray-600 hover:bg-gray-200\">\n <i data-lucide=\"eraser\" class=\"h-3 w-3\"></i> Erase\n </button>\n </div>\n </div>\n</div>\n\n</div>\n\n<script>\n(function() {\n if (window.SuneAgentPanel && typeof window.SuneAgentPanel.reAttach === 'function') {\n window.SuneAgentPanel.reAttach();\n return;\n }\n\n const AgentPanel = {\n // --- State ---\n isActive: false, isConsoleOpen: true, version: 'v0.8.0',\n logs: [], processed: new Set(), currentSuneId: '', idPoll: null,\n handlers: { ui: {}, composer: {} },\n\n // --- Config ---\n mountId: 'agent-runtime',\n storageKey: '', logStorageKey: '', processedKey: '',\n \n // --- DOM Elements ---\n el: {},\n \n // --- Methods ---\n init() {\n this.startSuneWatcher();\n this.reAttach();\n },\n\n reAttach() {\n this.unbindUIEvents();\n this.el = {};\n const sel = (id) => document.querySelector(id);\n this.el.root = sel('#agent-panel-root');\n if (!this.el.root) return;\n \n this.el = {\n root: this.el.root,\n version: sel('#agent-panel-version'), status: sel('#agent-panel-status'),\n toggle: sel('#agent-panel-toggle'), toggleHandle: sel('#agent-panel-toggle-handle'),\n consoleToggle: sel('#agent-panel-console-toggle'), consoleChevron: sel('#agent-panel-console-chevron'),\n consoleContainer: sel('#agent-panel-console-container'), console: sel('#agent-panel-console'),\n clearLogsBtn: sel('#agent-panel-clear-logs'), clearExecBtn: sel('#agent-panel-clear-exec'),\n clearCanvasBtn: sel('#agent-panel-clear-canvas')\n };\n \n this.bindUIEvents();\n\n const newSuneId = window.SUNE?.id;\n if (newSuneId && newSuneId !== this.currentSuneId) {\n this.onSuneChanged(newSuneId);\n } else {\n this.updateUI();\n }\n window.lucide?.createIcons?.();\n },\n\n bindUIEvents() {\n this.handlers.ui = {\n toggle: () => { this.isActive = !this.isActive; localStorage.setItem(this.storageKey, this.isActive); this.log('SYS', this.isActive ? 'Agent Activated' : 'Agent Deactivated'); this.updateUI(); },\n consoleToggle: () => { this.isConsoleOpen = !this.isConsoleOpen; this.updateUI(); },\n clearLogs: this.clearLogs.bind(this),\n clearExec: this.clearExecHistory.bind(this),\n clearCanvas: this.clearCanvas.bind(this)\n };\n for (const [elKey, handler] of [['toggle', 'toggle'], ['consoleToggle', 'consoleToggle'], ['clearLogsBtn', 'clearLogs'], ['clearExecBtn', 'clearExec'], ['clearCanvasBtn', 'clearCanvas']]) {\n this.el[elKey]?.addEventListener('click', this.handlers.ui[handler]);\n }\n },\n \n unbindUIEvents() {\n if (!this.el.root || !this.handlers.ui) return;\n for (const [elKey, handler] of [['toggle', 'toggle'], ['consoleToggle', 'consoleToggle'], ['clearLogsBtn', 'clearLogs'], ['clearExecBtn', 'clearExec'], ['clearCanvasBtn', 'clearCanvas']]) {\n this.el[elKey]?.removeEventListener('click', this.handlers.ui[handler]);\n }\n this.handlers.ui = {};\n },\n\n updateUI() {\n if (!this.el.root) return;\n this.el.version.textContent = this.version;\n this.el.status.textContent = this.isActive ? 'Status: Active' : 'Status: Inactive';\n this.el.toggle.setAttribute('aria-checked', this.isActive);\n this.el.toggle.classList.toggle('bg-black', this.isActive);\n this.el.toggle.classList.toggle('bg-gray-300', !this.isActive);\n this.el.toggleHandle.classList.toggle('translate-x-5', this.isActive);\n \n this.el.consoleContainer.classList.toggle('hidden', !this.isConsoleOpen);\n this.el.consoleChevron.classList.toggle('rotate-180', this.isConsoleOpen);\n \n this.el.console.textContent = this.logs.join('\\n') || 'Console is empty.';\n this.el.console.scrollTop = this.el.console.scrollHeight;\n },\n\n restoreState() {\n this.isActive = localStorage.getItem(this.storageKey) === 'true';\n this.logs = JSON.parse(localStorage.getItem(this.logStorageKey) || '[]') || [];\n this.processed = new Set(JSON.parse(localStorage.getItem(this.processedKey) || '[]'));\n },\n\n updateKeysFor(id) {\n this.currentSuneId = id;\n this.storageKey = `sune_agent_active_${id}`;\n this.logStorageKey = `sune_agent_logs_${id}`;\n this.processedKey = `sune_agent_processed_${id}`;\n },\n \n unbindComposer() {\n const c = document.getElementById('composer');\n if (!c || !this.handlers.composer) return;\n if (this.handlers.composer.suneResponse) c.removeEventListener('sune:newSuneResponse', this.handlers.composer.suneResponse);\n if (this.handlers.composer.submit) c.removeEventListener('submit', this.handlers.composer.submit);\n },\n \n bindComposer() {\n this.unbindComposer();\n const c = document.getElementById('composer');\n if (!c) return;\n this.handlers.composer = {\n suneResponse: this.onSuneResponse.bind(this),\n submit: this.injectContext.bind(this)\n };\n c.addEventListener('sune:newSuneResponse', this.handlers.composer.suneResponse);\n c.addEventListener('submit', this.handlers.composer.submit);\n },\n\n startSuneWatcher() {\n clearInterval(this.idPoll);\n this.idPoll = setInterval(() => {\n const id = window.SUNE?.id;\n if (id && id !== this.currentSuneId) this.onSuneChanged(id);\n }, 333);\n },\n\n onSuneChanged(newId) {\n if (!newId) return;\n const prev = this.currentSuneId;\n this.updateKeysFor(newId);\n this.restoreState();\n this.clearCanvas();\n this.bindComposer();\n if(prev) this.log('SYS', `Switched Sune ${prev} -> ${newId}`);\n else this.log('SYS', `Agent ready on ${newId}`);\n this.updateUI();\n },\n \n saveLogs() { localStorage.setItem(this.logStorageKey, JSON.stringify(this.logs.slice(-200))) },\n saveProcessed() { localStorage.setItem(this.processedKey, JSON.stringify([...this.processed].slice(-200))) },\n markProcessed(k) { this.processed.add(k); this.saveProcessed() },\n hasProcessed(k) { return this.processed.has(k) },\n hash(s) { let h = 0; for (let i = 0; i < s.length; i++) h = ((h << 5) - h) + s.charCodeAt(i) | 0; return 'h' + (h >>> 0).toString(16) },\n uid() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 6) },\n \n log(t, m) {\n const ts = new Date().toLocaleTimeString(); this.logs.push(`[${ts} ${t}] ${m}`); if (this.logs.length > 200) this.logs.shift();\n this.saveLogs(); this.updateUI();\n },\n \n ensureMount() {\n const host = document.getElementById('suneHtml'); if (!host) { this.log('WARN', '#suneHtml not found'); return null }\n host.classList.remove('hidden'); let mount = host.querySelector('#' + this.mountId);\n if (!mount) { mount = document.createElement('div'); mount.id = this.mountId; mount.className = 'agent-runtime space-y-2 p-2'; host.appendChild(mount) } return mount;\n },\n\n injectHTMLBlock(html) {\n const mount = this.ensureMount(); if (!mount) return; const wrap = document.createElement('div'); wrap.setAttribute('data-agent-block', this.uid()); wrap.className = 'rounded-lg border border-gray-200 bg-white/50 p-2'; wrap.innerHTML = html; mount.appendChild(wrap);\n [...wrap.querySelectorAll('script')].forEach(old => { const s = document.createElement('script');[...old.attributes].forEach(a => s.setAttribute(a.name, a.value)); s.textContent = old.textContent || ''; old.parentNode?.replaceChild(s, old) });\n window.lucide?.createIcons?.(); this.log('HTML', 'Injected HTML block');\n },\n \n executeJSBlock(code) {\n this.log('EXEC', 'Running JS block'); try { (new Function(code)).call(window); this.log('DONE', 'JS executed') } catch (err) { console.error('[Sune Agent] JS Error:', err); this.log('ERROR', err?.message || 'Exec fail'); window.SUNE?.log?.('Agent Error: ' + (err?.message || 'Exec fail')) }\n },\n \n async autoAskNext(msgId) {\n const key = `auto:${msgId || this.uid()}`; if (this.hasProcessed(key)) return this.log('SKIP', 'Auto-send processed for ' + msgId);\n this.log('AUTO', '<3 detected, queueing auto-send...');\n await new Promise(r => setTimeout(r, 5000));\n if (window.state?.busy) return this.log('FAIL', 'Auto-send aborted, app busy.');\n try {\n document.getElementById('input').value = 'Automated reply: continue until you reach a result without asking me questions. You are being automated and I am away.';\n const composer = document.getElementById('composer'), sendBtn = document.getElementById('sendBtn');\n if (sendBtn?.getAttribute('type') === 'submit') sendBtn.click();\n else composer?.requestSubmit ? composer.requestSubmit() : composer?.dispatchEvent(new Event('submit', { cancelable: true, bubbles: true }));\n this.markProcessed(key); this.log('AUTO', 'Sent \"Whats next?\"');\n } catch (e) { this.log('ERROR', 'Auto-send failed: ' + (e?.message || e)) }\n },\n \n onSuneResponse(e) {\n if (!this.isActive) return;\n const msg = e?.detail?.message; if (!msg || msg.role !== 'assistant' || !Array.isArray(msg.content)) return;\n const txt = window.partsToText(msg.content || []) || ''; if (!txt.trim()) return;\n const msgKey = msg.id || this.hash(txt);\n if (!this.hasProcessed(msgKey)) {\n let any = false, m;\n const reJS = /```(?:javascript|js)\\n([\\s\\S]*?)\\n```/gi, reHTML = /```(?:html|htm)\\n([\\s\\S]*?)\\n```/gi;\n while ((m = reJS.exec(txt)) !== null) { if ((m[1] || '').trim()) { any = true; this.executeJSBlock((m[1] || '').trim()) } }\n while ((m = reHTML.exec(txt)) !== null) { if ((m[1] || '').trim()) { any = true; this.injectHTMLBlock((m[1] || '').trim()) } }\n if (any) { this.markProcessed(msgKey); this.log('PROC', 'Executed blocks for ' + msgKey) }\n }\n if (/<3/.test(txt)) { this.log('MATCH', 'Found <3, triggering auto-send'); this.autoAskNext(msg.id || msgKey) }\n },\n \n injectContext() {\n if (!this.isActive || !this.logs.length) return; const input = document.getElementById('input'), cur = input.value || ''; if (!cur.trim()) return; input.value = `[AGENT LOGS]\\n${this.logs.slice(-15).join('\\n')}\\n[/AGENT LOGS]\\n\\n` + cur;\n this.log('INFO', 'Injected logs into context');\n },\n \n clearLogs() { this.logs = []; this.saveLogs(); this.log('SYS', 'Console cleared'); this.updateUI() },\n clearExecHistory() { this.processed.clear(); this.saveProcessed(); this.log('SYS', 'Execution history cleared') },\n clearCanvas() { const m = document.querySelector('#' + this.mountId); if (m) { m.innerHTML = ''; this.log('SYS', 'Cleared injected HTML canvas') } }\n };\n\n window.SuneAgentPanel = AgentPanel;\n window.SuneAgentPanel.init();\n})();\n</script>\n</div>\n","extension_html":"<sune src='https://raw.githubusercontent.com/sune-org/store/refs/heads/main/sync.sune' private></sune>","hide_composer":false},"storage":{}}]