// connect.js — „Verbinden" (v4): IDEs/Agenten anbinden, Verbindung testen, Bild/Vision-Flow. import { api } from "../core/api.js"; import { $, esc, icon } from "../core/ui.js"; let S = null; let lastSig = ""; window.mcCopyVal = btn => { const i = btn.previousElementSibling; navigator.clipboard?.writeText(i.value); const o = btn.textContent; btn.textContent = "Kopiert!"; setTimeout(() => (btn.textContent = o), 1200); }; window.mcCopyCode = btn => { const code = btn.parentElement.querySelector("code"); navigator.clipboard?.writeText(code.textContent); const o = btn.textContent; btn.textContent = "Kopiert!"; setTimeout(() => (btn.textContent = o), 1200); }; window.cnGo = v => document.querySelector(`.nav-item[data-view="${v}"]`)?.click(); function baseUrl() { return `${location.protocol}//${location.hostname}:8080/v1`; } function models() { return S?.models || []; } function field(label, value) { return `
`; } const okChip = txt => `${icon("check")}${esc(txt)}`; function render() { const c = $(".view[data-view='connect']"); if (!c) return; const url = baseUrl(); const ids = models().map(m => m.name); const firstModel = ids[0] || "coder"; const visionModel = models().find(m => m.meta?.caps?.includes("Bild"))?.name; c.innerHTML = `

Verbinden

Binde deine lokalen Modelle in IDEs, Agenten & Tools ein — getestet, mit Copy-Paste-Config.

Verbindung zur Engine

Alle Tools nutzen diese OpenAI-kompatible Adresse. Das Auto-Swapping lädt das passende Modell je Anfrage automatisch.
${field("Basis-URL (OpenAI-kompatibel)", url)}

Bilder einbinden (Vision)

Für Fehleranalyse per Screenshot brauchst du ein Vision-Modell.
OpenCode (Windows)

Lege in OpenCode einen OpenAI-kompatiblen Provider an:

${field("Basis-URL", url)} ${field("Modell-ID", firstModel)} ${field("API-Key", "(dein Token oder leer lassen)")}
Cline / Cursor

Provider „OpenAI Compatible" wählen:

${field("Basis-URL", url)} ${field("Modell-ID", firstModel)}
OpenWebUI

Settings → Admin → Connections → neue OpenAI-Verbindung:

${field("Basis-URL", url)} ${field("API-Key", "dummy-key")}
`; $("#cn-test").addEventListener("click", testConnection); renderVision(url, visionModel); } function renderVision(url, visionModel) { const el = $("#cn-vision"); if (!el) return; if (visionModel) { const snippet = `curl ${url}/chat/completions \\ -H "Content-Type: application/json" \\ -d '{ "model": "${visionModel}", "messages": [{"role":"user","content":[ {"type":"text","text":"Was ist auf dem Bild falsch?"}, {"type":"image_url","image_url":{"url":"data:image/png;base64,"}} ]}] }'`; el.innerHTML = `${okChip(`Vision-Modell „${visionModel}" bereit`)}
${esc(snippet)}
`; } else { el.innerHTML = `
Noch kein Vision-Modell installiert
Im Cookbook unter „Bilder verstehen" mit einem Klick einrichten.
`; } } async function testConnection() { const res = $("#cn-test-result"); res.innerHTML = `
Teste Verbindung…
`; try { const r = await api("/api/integration/test"); res.innerHTML = r.ok ? okChip(`Funktioniert — ${r.models.length} Modell(e): ${r.models.join(", ")}`) : `
Keine Verbindung zur Engine: ${esc(r.error)}
`; } catch (e) { res.innerHTML = `
${esc(e.message)}
`; } } function mount() { render(); } function onStatus(s) { S = s; const sig = (s?.models || []).map(m => m.name).join(",") + "|" + !!s; if (sig !== lastSig) { lastSig = sig; render(); } } export default { id: "connect", mount, onStatus };