{
  "id": "com.schuettken.sac.datacopilot",
  "version": "2.3.0",
  "name": "Data Copilot",
  "description": "Chat with your data: bindet sich an eine Datenquelle der Story, reagiert auf Navigation und Filter, zeigt Kennzahlen und KI-Zusammenfassungen (Sonnet) und beantwortet Fragen zum sichtbaren Datenausschnitt. Optional (planningConfig): What-if per Chat, Version-Diff, Plan-per-Chat und ein Submit-Gate — das Widget schreibt dabei nie selbst, es meldet Intents an das Story-Script.",
  "newInstancePrefix": "DataCopilot",
  "vendor": "Schuettken",
  "eula": "",
  "license": "",
  "icon": "https://sac-web.schuettken.net/widgets/data-copilot/icon.png",
  "webcomponents": [
    {
      "kind": "main",
      "tag": "com-schuettken-sac-datacopilot",
      "url": "https://sac-web.schuettken.net/widgets/data-copilot/main.js",
      "integrity": "",
      "ignoreIntegrity": true
    },
    {
      "kind": "styling",
      "tag": "com-schuettken-sac-datacopilot-styling",
      "url": "https://sac-web.schuettken.net/widgets/data-copilot/styling.js",
      "integrity": "",
      "ignoreIntegrity": true
    }
  ],
  "dataBindings": {
    "myDataBinding": {
      "feeds": [
        {
          "id": "dimensions",
          "description": "Dimensionen",
          "type": "dimension"
        },
        {
          "id": "measures",
          "description": "Kennzahlen",
          "type": "mainStructureMember"
        }
      ]
    }
  },
  "properties": {
    "width": {
      "type": "integer",
      "default": 560
    },
    "height": {
      "type": "integer",
      "default": 640
    },
    "endpoint": {
      "type": "string",
      "description": "URL des LLM-Proxys",
      "default": "https://sac-web.schuettken.net/api/llm"
    },
    "demoKey": {
      "type": "string",
      "description": "Demo-Key. Bewusst leer - im Builder-Panel der Story eintragen, damit er nicht im oeffentlich lesbaren JS steht.",
      "default": ""
    },
    "quality": {
      "type": "string",
      "description": "fast (Haiku, guenstig) oder good (Sonnet, beste Qualitaet)",
      "default": "good"
    },
    "autoSummary": {
      "type": "boolean",
      "description": "Bei jeder Datenaenderung (Navigation, Filter) automatisch eine neue KI-Zusammenfassung holen",
      "default": true
    },
    "context": {
      "type": "string",
      "description": "Fachlicher Kontext fuer die KI, z.B. 'Umsatz nach Region, Werte in EUR'",
      "default": ""
    },
    "voice": {
      "type": "boolean",
      "description": "Analysen und Antworten vorlesen (Sprachausgabe)",
      "default": false
    },
    "charts": {
      "type": "boolean",
      "description": "KI darf Diagramme vorschlagen (ECharts)",
      "default": true
    },
    "debug": {
      "type": "boolean",
      "description": "Debug-Logging in die Browser-Konsole (Praefix [DataCopilot]). Warnungen erscheinen immer.",
      "default": false
    },
    "planningConfig": {
      "type": "string",
      "description": "JSON-Konfiguration fuer Planning-Faehigkeiten (v2.3): {\"versionDim\":\"Version\",\"dataActions\":[{\"name\":\"DA_X\",\"label\":\"...\",\"params\":[{\"name\":\"P\",\"label\":\"...\",\"type\":\"number\"}]}],\"submitHint\":\"...\"}. Leer/fehlend = Planning aus, Widget verhaelt sich wie v2.2.1. Parse-Fehler -> Planning aus (kein Throw).",
      "default": ""
    }
  },
  "methods": {
    "ask": {
      "description": "Stellt eine Frage zum aktuellen Datenausschnitt. Antwort kommt ueber das Event onAnswer.",
      "parameters": [
        {
          "name": "question",
          "type": "string",
          "description": "Die Frage"
        }
      ]
    },
    "summarize": {
      "description": "Holt eine frische KI-Zusammenfassung des aktuellen Datenausschnitts"
    },
    "getSummary": {
      "returnType": "string",
      "description": "Liefert die zuletzt erzeugte Zusammenfassung"
    },
    "getLastIntent": {
      "returnType": "string",
      "description": "Liefert den zuletzt vom LLM gelieferten Intent als JSON-String (oder leeren String). SAC-Events tragen keine Payload - deshalb dieser Pull-Getter zum Event onIntent."
    },
    "getAnomalies": {
      "returnType": "string",
      "description": "Lokale z-Score-Ausreisser des aktuellen Ausschnitts als JSON-Array [{key,value,z}] (leer, wenn keine)."
    },
    "reportActionResult": {
      "description": "Script meldet das Ausfuehrungsergebnis eines runDataAction-Intents zurueck: {\"ok\":true|false,\"action\":\"...\",\"message\":\"...\"}. Loest den Status-Chip auf und zeigt eine Chat-Zeile. Bei ok=true bleibt der Aktions-Kontext fuer die naechste Insight-Diff-Erklaerung aktiv.",
      "parameters": [
        {
          "name": "resultJson",
          "type": "string",
          "description": "JSON-String mit ok/action/message"
        }
      ]
    },
    "compareVersions": {
      "description": "Fuehrt einen Versionsvergleich (versionDiff) programmatisch aus, ohne Chat/LLM. Setzt den Intent (getLastIntent) und feuert onIntent, rendert Mover-Panel/Chart und stoesst eine gestreamte Erklaerung an. Nur wirksam, wenn planningConfig aktiv ist.",
      "parameters": [
        {
          "name": "a",
          "type": "string",
          "description": "Member-ID/Label der ersten Version"
        },
        {
          "name": "b",
          "type": "string",
          "description": "Member-ID/Label der zweiten Version"
        }
      ]
    },
    "openSubmitGate": {
      "description": "Startet den Submit-Gate-Flow programmatisch (z.B. von einem Story-Button), identisch zum Header-Button. Nur wirksam, wenn planningConfig aktiv ist."
    }
  },
  "events": {
    "onAnswer": {
      "description": "Antwort auf eine Frage ist eingetroffen"
    },
    "onSummary": {
      "description": "Neue Zusammenfassung ist eingetroffen"
    },
    "onError": {
      "description": "LLM-Aufruf ist fehlgeschlagen"
    },
    "onIntent": {
      "description": "Das LLM hat einen Steuerungs-Intent geliefert. Details per getLastIntent() abholen — Feld 'applied' sagt, ob das Widget ihn schon selbst angewendet hat (Linked Analysis/Variable); nur bei applied=false muss das Story-Script handeln."
    }
  },
  "supportsLinkedAnalysisFilterOnSelection": true
}
