// 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(); // Die Engine-API spricht IMMER reines HTTP auf Port 8080 direkt am Bosgame. // Bewusst nicht location.protocol uebernehmen: wer MC hinter einem Reverse-Proxy // (NPM) ueber https:// aufruft, bekaeme sonst eine kaputte https-:8080-URL. function baseUrl() { return `http://${location.hostname}:8080/v1`; } function isLanIp(h) { return /^\d{1,3}(\.\d{1,3}){3}$/.test(h); } // true, wenn MC offenbar ueber einen Proxy/Namen aufgerufen wird (nicht direkt per IP). function behindProxy() { return location.protocol === "https:" || !isLanIp(location.hostname); } function models() { return S?.models || []; } // Fertige opencode.json fuer einen OpenAI-kompatiblen Provider auf llama-swap. function openCodeConfig(url, ids) { const list = ids.length ? ids : ["coder"]; const modelMap = list.map(id => ` "${id}": { "name": "${id}" }`).join(",\n"); return `{ "$schema": "https://opencode.ai/config.json", "provider": { "llama-swap": { "npm": "@ai-sdk/openai-compatible", "name": "Bosgame (llama-swap)", "options": { "baseURL": "${url}", "apiKey": "local" }, "models": { ${modelMap} } } } }`; } // Fertige Zed-settings.json fuer einen OpenAI-kompatiblen Provider auf llama-swap. // Vision-Modelle bekommen capabilities.images=true, sonst sieht Zed sie als reine Text-Modelle. function zedConfig(url) { const ms = models(); const list = ms.length ? ms : [{ name: "coder" }]; const entries = list.map(m => { const img = (m.meta?.caps || []).some(c => /Bild|Vision/i.test(c)); const caps = img ? `, "capabilities": { "tools": true, "images": true }` : ""; return ` { "name": "${m.name}", "display_name": "${m.name}", "max_tokens": 32768${caps} }`; }).join(",\n"); return `{ "language_models": { "openai_compatible": { "bosgame": { "api_url": "${url}", "available_models": [ ${entries} ] } } } }`; } function field(label, value) { return `
`; } const okChip = txt => `${icon("check")}${esc(txt)}`; function toolRow(name, desc, url, badge) { return `
${esc(name)}${badge ? `${esc(badge)}` : ""}
${esc(desc)}
`; } 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)} ${behindProxy() ? `
Du rufst Mission Control offenbar über einen Proxy/Namen auf (NPM o.ä.). Die Engine-API läuft aber direkt am Bosgame auf Port 8080 ohne HTTPS — ein Proxy davor stört nur. Trag in deinen Tools die rohe LAN-Adresse ein: http://<Bosgame-IP>:8080/v1 (z.B. http://192.168.178.151:8080/v1), nicht den HTTPS-Namen.
` : ""}

Bilder einbinden (Vision)

Für Fehleranalyse per Screenshot brauchst du ein Vision-Modell.

Empfohlene Tools (Juni 2026)

Diese verbinden sich nahtlos mit deinem Stack. Einrichtungs-Configs findest du darunter.
${toolRow("Zed", "Schneller nativer Editor mit eingebautem KI-Agenten — verbindet sich direkt mit deinem Stack.", "https://zed.dev", "Empfohlen")} ${toolRow("OpenCode", "Open-Source-Coding-Agent (MIT) — Terminal, Desktop & IDE. Gute Alternative.", "https://opencode.ai")} ${toolRow("Cline", "Bestes Erlebnis in VS Code, Bring-Your-Own-Key, Mensch-im-Loop.", "https://cline.bot")} ${toolRow("Continue.dev", "Feinkörnige Kontrolle + bestes MCP-Ökosystem für Werkzeuge.", "https://continue.dev")}
Diese Tools sind Agenten: Sie lassen dein Modell selbst Dateien ändern und Befehle ausführen. Noch unklar, was Agent, Skill oder MCP heißt? Im Guide von Grund auf erklärt →
Zed — settings.json (empfohlen)

Zed konfigurierst du über seine settings.json (in Zed: Cmd/Strg + ,). Füge diesen Block ein — er meldet deine Modelle als eigenen Anbieter „bosgame" an:

${esc(zedConfig(url))}

API-Key: Zed speichert Keys nicht in der settings.json. Öffne den Agent-Panel → Anbieter bosgame → trag irgendeinen Wert ein (z.B. local) — llama-swap prüft ihn nicht. Alternativ als Umgebungsvariable BOSGAME_API_KEY=local.

Danach im Agent-Panel oben das Modell bosgame / ${esc(firstModel)} wählen. Das Auto-Swapping lädt das passende Modell selbst. ${behindProxy() ? "Achtung: in api_url die LAN-IP des Bosgame nutzen (siehe Warnung oben), nicht den Proxy-Namen." : ""}
OpenCode — Config-Datei (JSON)

OpenCode richtest du nicht über Felder ein, sondern über eine Config-Datei. Lege sie hier an:

Windows: %USERPROFILE%\\.config\\opencode\\opencode.json
(oder im Projektordner als opencode.json)

${esc(openCodeConfig(url, ids))}

Danach in OpenCode /models tippen und llama-swap/${esc(firstModel)} wählen. Das Auto-Swapping lädt das passende Modell von selbst.

Fehler „Connect to API could not be established"? Dann zeigt die baseURL ins Leere. Sie muss auf die LAN-IP des Bosgame zeigen (oben: ${esc(url)}) — niemals localhost oder 127.0.0.1, denn das wäre dein eigener PC, nicht der Server.
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 };