Skip to content

KI ​

Geben Sie dem Editor einen KI-Provider, und Ihre Nutzenden erhalten einen KI-Assistenten, der das geöffnete Template bearbeitet: einen Chat mit Rückgängig, „Rewrite with AI“ in der Absatz-Werkzeugleiste, prüfbare Alt-Text-Entwürfe im Issues-Panel, statische, lokalisierte Einstiegsanfragen und ein Template aus einem Screenshot oder einer PDF. Ihr Backend spricht mit dem Modell — mit Ihren Schlüsseln, Ihren Vereinbarungen zur Datenverarbeitung und Ihren Regeln.

Der Editor übernimmt die Oberflächen, das Streaming, das Anwenden der KI-Änderungen mit Rückgängig und die Kennzeichnung der Inhalte als KI-generiert. Sie übernehmen den Modellaufruf: eine Funktion pro Feature oder einige HTTP-Endpunkte, deren Großteil @templatical/ai-kit bereitstellt.

Schnellstart ​

ts
import { init } from '@templatical/editor';
import '@templatical/editor/style.css';
import { createHttpAiProvider } from '@templatical/ai-kit/client';
import type { Template } from '@templatical/types';

const editor = await init({
  container: '#editor',
  templates: {
    load: async (id): Promise<Template> => {
      const response = await fetch(`/api/templates/${encodeURIComponent(id)}`);
      if (!response.ok) throw new Error('Template load failed.');
      return response.json();
    },
    create: false,
    save: false,
  },
  ai: createHttpAiProvider({
    baseUrl: '/api/ai',
  }),
});

await editor.load('tpl_123');

createHttpAiProvider spricht ein dokumentiertes REST- und Server-Sent-Events-Protokoll. Eigenes KI-Backend anbinden baut die Serverseite mit @templatical/ai-kit/server auf; die KI-API-Referenz dokumentiert das Protokoll für Backends in jeder Sprache.

KI braucht ein geladenes Template. Jede Anfrage benennt es, daher erscheinen die Einstiegspunkte, sobald create() oder load() abgeschlossen ist. Lassen Sie ai weg, fehlt das Feature: keine KI-Schaltfläche, keine Schaltfläche in der Werkzeugleiste, und kein Code seiner Oberfläche wird geladen.

Der Vertrag ​

ts
import type {
  SyntaxPresetName,
  Operation,
  OperationErrorCode,
  TemplateContent,
} from "@templatical/types";

export type AiMergeTagSyntax = SyntaxPresetName | "custom";

export interface AiMergeTag {
  value: string;
  label: string;
  group?: string;
  description?: string;
}

export interface AiMergeTags {
  syntax: AiMergeTagSyntax;
  tags: AiMergeTag[];
}

export interface AiRequestBase {
  templateId: string;
  /**
   * The template as the editor has it, after it sent its pending edits. A
   * backend that holds the template itself (Templatical Cloud) ignores it.
   */
  content: TemplateContent;
  /** The collaboration revision `content` is at, or `null` without collaboration. */
  revision: number | null;
  /** The editor session (`X-Templatical-Session` on the wire). */
  sessionId: string;
  /** The editor syntax and declared tags; `tags` is empty when none are declared. */
  mergeTags: AiMergeTags;
}

export interface AiChatAttachment {
  file: Blob;
  kind: "image" | "pdf";
  name: string;
}

export interface AiChatRequest extends AiRequestBase {
  /** 1–4,000 characters. */
  message: string;
  /** The selected block, when the backend has it; `null` otherwise. */
  selectedBlockId: string | null;
  /** Always present; at most 4 files, each at most 5 MB, at most 10 MB together. */
  attachments: AiChatAttachment[];
}

export interface AiFixFinding {
  /** Non-empty lint rule id, at most 200 characters. */
  ruleId: string;
  /** The problem, at most 1,000 code points. */
  message: string;
  /** The linter's suggested action, at most 1,000 code points. */
  suggestion: string;
  /** Rule docs URL: http(s), at most 2,048 characters; never fetched by the model. */
  reference: string;
  /** Block id (at most 200 characters), or null for a template-level finding. */
  blockId: string | null;
  /** Diagnostic excerpt when supplied by the rule, at most 1,000 code points. */
  excerpt?: string;
}

export interface AiFixRequest extends AiRequestBase {
  finding: AiFixFinding;
}

export type AiRewritePreset =
  "shorten" | "expand" | "friendlier" | "formal" | "fixGrammar" | "translate";

export interface AiRewriteRequest extends AiRequestBase {
  /**
   * The paragraph's HTML (1–20,000 characters), merge tags as the editor's
   * tags (`<span data-merge-tag="{{first_name}}" …>`).
   */
  html: string;
  preset: AiRewritePreset | null;
  /** A BCP 47 tag; set when `preset` is `translate`. */
  language: string | null;
  /** ≤ 500 characters. At least one of `preset` and `instruction` is set. */
  instruction: string | null;
}

export interface AiAltTextRequest {
  templateId: string;
  sessionId: string;
  blockId: string;
  image: { url: string };
  currentAlt: string | null;
  linkHref: string | null;
  /** Plain text, at most 2,000 code points. */
  nearbyText: string;
  locale: string;
  /** Effective lint altMaxLength: integer 1–1,000, counted as string.length. */
  maxLength: number;
}

export interface AiAppliedBatch {
  batchId: string;
  revision: number;
  operationCount: number;
}

export type AiOperationsResult =
  | { applied: true; inverse: Operation[] }
  | {
      applied: false;
      code: OperationErrorCode;
      opIndex: number;
      message: string;
    };

export interface AiTurnHandlers {
  onText(text: string): void;
  onOperations(ops: Operation[]): Promise<AiOperationsResult>;
  onApplied(batch: AiAppliedBatch): void;
}

export interface AiRewriteHandlers {
  /** A chunk of the rewritten text, for a live preview. */
  onText(text: string): void;
}

export interface AiTurnResult {
  /** The assistant message's id in `conversation`, or `null` without history. */
  messageId: string | null;
  /** The whole reply. */
  text: string;
}

export type AiReplay =
  | { operations: Operation[]; replayId: string }
  | { applied: { batchId: string; revision: number } };

export type AiMessageKind = "chat" | "fix";

export interface AiMessageBatch {
  batchId: string;
  revision: number | null;
  operationCount: number;
}

export interface AiChatMessage {
  id: string;
  role: "user" | "assistant";
  kind: AiMessageKind;
  /** The author's message, a fix's "Fix: {message}", or the assistant's reply. */
  text: string;
  /** Reference metadata on user messages only; file retention is the backend's choice. */
  attachments?: { name: string; kind: "image" | "pdf" }[];
  /** What the assistant's turn applied; empty for user messages. */
  batches: AiMessageBatch[];
  /** `true` after Undo, `false` after Redo. */
  undone: boolean;
  /** ISO 8601. */
  createdAt: string;
}

export interface AiConversationProvider {
  /** Settle an editor-applied replay, idempotently, after applying or refusing it. */
  settleReplay(
    templateId: string,
    messageId: string,
    outcome: AiReplayOutcome,
  ): Promise<void>;
  /** Oldest first. */
  list(templateId: string): Promise<AiChatMessage[]>;
  /** New chat; `false` hides the button. */
  clear: false | ((templateId: string) => Promise<void>);
  undo:
    | false
    | ((
        templateId: string,
        messageId: string,
        context: AiReplayContext,
      ) => Promise<AiReplay>);
  redo:
    | false
    | ((
        templateId: string,
        messageId: string,
        context: AiReplayContext,
      ) => Promise<AiReplay>);
}

export interface AiReplayOutcome {
  replayId: string;
  direction: "undo" | "redo";
  applied: boolean;
  sessionId: string;
}

export interface AiReplayContext {
  sessionId: string;
}

export type AiErrorCode =
  | "feature_unavailable"
  | "limit_reached"
  | "rate_limited"
  | "ai_turn_running"
  | "content_too_large"
  | "ai_output_invalid"
  | "ai_provider_error";

export interface AiLimitDetails extends Readonly<Record<string, unknown>> {
  /** Which allowance ran out, in the backend's words (`aiMonthly`). */
  limit: string;
  /** ISO 8601: when it renews. */
  resetsAt: string;
}

export interface AiProvider {
  chat:
    | false
    | ((
        request: AiChatRequest,
        on: AiTurnHandlers,
        signal: AbortSignal,
      ) => Promise<AiTurnResult>);
  fixFinding:
    | false
    | ((
        request: AiFixRequest,
        on: AiTurnHandlers,
        signal: AbortSignal,
      ) => Promise<AiTurnResult>);
  /** True means chat accepts attachments; has no effect while chat is false. */
  chatAttachments: false | true;
  rewrite:
    | false
    | ((
        request: AiRewriteRequest,
        on: AiRewriteHandlers,
        signal: AbortSignal,
      ) => Promise<{ html: string }>);
  altText:
    | false
    | ((
        request: AiAltTextRequest,
        signal: AbortSignal,
      ) => Promise<{ alt: string }>);
  conversation?: AiConversationProvider;
}

export type AiFeatureName = Exclude<keyof AiProvider, "conversation">;

Chat, Fix und Umformulieren erhalten den content des Editors nach dem Senden ausstehender Änderungen, die Zusammenarbeitsrevision revision (oder null), templateId, sessionId und das erforderliche mergeTags: { syntax, tags }. Ohne deklarierte Tags sendet der Editor seine Syntax (standardmäßig liquid) und tags: []. Fehlender oder null gesetzter Kontext ergibt 422. Jeder Aufruf erhält ein AbortSignal; Stop bricht ihn ab.

Die Deklarationen oben und die API-Anfragelimits definieren jedes Feld. Auf dem Wire verwenden Template-ID und Sitzung Pfad und Header; Rewrite lässt content und revision weg. Das Server-Kit prüft Merge-Tags auch bei leeren Listen; die Syntax custom bleibt ungeprüft.

Durchläufe: Chat und Beheben ​

Ein Durchlauf streamt seine Antwort über on.onText und übergibt Änderungen auf einem von zwei Wegen:

  • on.onOperations(ops): Operationen, die der Editor anwenden soll. Er wendet sie sofort an und antwortet mit { applied: true, inverse } oder mit { applied: false, code, opIndex, message }, wenn sie nicht mehr zum Template passen (jemand hat einen Block geändert oder hält seine Sperre). Die Batches eines Durchlaufs bilden einen Rückgängig-Schritt.
  • on.onApplied({ batchId, revision, operationCount }): Ihr Backend hat den Batch bereits auf seine Kopie angewendet. Mit einem Zusammenarbeits-Provider folgt der Editor der Revision; mit einem reinen Templates-Provider lädt er das Template am Ende des Durchlaufs neu. Ohne beide verweigert er den Batch.

Ohne Zusammenarbeit verhindert eine eigene Bearbeitung nach Beginn eines Durchlaufs das automatische Neuladen, auch während eine Ladeanfrage läuft. Der Editor behält Ihre Version und zeigt einen Hinweis mit Neu laden. Die Änderungen der KI bleiben auf dem Server gespeichert. Wählen Sie Neu laden, um sie zu laden; wenn Sie Ihre Version speichern, ersetzen Sie die Änderungen der KI. Im Editor angewendete Batches der KI zählen nicht als eigene Bearbeitungen.

chat sendet message, selectedBlockId (nur einen Block, den Ihr Backend kennt) und attachments, immer als Array. fixFinding sendet die unten beschriebene Lint-Projektion.

Chat-Anhänge ​

AiChatAttachment ist { file: Blob; kind: "image" | "pdf"; name: string }. AiChatRequest.attachments ist immer vorhanden: [] ohne Dateien. chatAttachments: true bedeutet, dass Ihre chat-Funktion Anhänge akzeptiert; bei chat: false hat das Flag keine Wirkung. Die Steuerung braucht beide Funktionen und ein geladenes Template. Der HTTP-Provider aktiviert das Flag standardmäßig bei aktivem Chat; setzen Sie für ein reines Text-Backend features: { chatAttachments: false }.

Personen können PNG-, JPEG-, WebP-, GIF- oder PDF-Dateien über Dateien anhängen oder per Drag-and-drop hinzufügen. Pro Nachricht sind höchstens 4 Dateien erlaubt, jede höchstens 5 MB (5 * 1024 * 1024 Byte), zusammen höchstens 10 MB (10 * 1024 * 1024 Byte). Ungültige Dateien zeigen Validierungsnachrichten. Dateinamen-Chips haben Entfernen-Schaltflächen; die Steuerung ist während eines Durchlaufs deaktiviert. Senden leert die Anhänge; ein fehlgeschlagener Durchlauf stellt Text und Dateien wieder her.

Aus Screenshot oder PDF importieren ist die Chat-Anhang-Verknüpfung auf der leeren Arbeitsfläche. Die Import-Verknüpfung öffnet zuerst die Dateiauswahl, öffnet nach einer Auswahl den Chat, hängt die Dateien an und füllt einen leeren Eingabebereich mit „Diese E-Mail aus dem angehängten Design aufbauen“. Vorhandener Text bleibt erhalten. Die Person sendet selbst; nichts wird automatisch gesendet. Bilder werden Platzhalter; ersetzen Sie sie nach dem Import. Der Prompt ersetzt das ganze Template nur bei leerem Inhalt oder ausdrücklicher Aufforderung; sonst dienen Anhänge als Referenz für die angeforderte Änderung. Ein Ersatz ist ein Rückgängig-Schritt.

Die mit KI beschriftete Schaltfläche im Header öffnet und schließt den KI-Assistenten.

Der Verlauf hat Typ chat und speichert nur optionale attachments: { name: string; kind: "image" | "pdf" }[] auf Benutzernachrichten. Die Dateiaufbewahrung bestimmt das Backend. Das Multipart-Generate-Protokoll und der Backend-Leitfaden zeigen Einlesen und Modellzuordnung.

Mit KI beheben ​

fixFinding erhält finding: { ruleId, message, suggestion, reference, blockId, excerpt? }, die JSON-serialisierbare Projektion eines Lint-Befunds. severity, clients und die lokale fix-Funktion werden nie gesendet. Alle Felder sind unvertrauenswürdige Diagnosedaten, keine Anweisungen; das Modell darf den reference-Link nicht abrufen.

AI_FIXABLE_RULES aus @templatical/editor enthält genau die folgenden Regel-IDs. Das Issues-Panel bietet Mit KI beheben für diese Regel-IDs an, wenn der Befund keine deterministische fix-Funktion hat, fixFinding eine Funktion ist und ein Template geladen ist:

  • a11y.link-vague-text
  • a11y.button-vague-label
  • a11y.link-empty
  • a11y.text-all-caps
  • a11y.missing-preheader
  • deliverability.link-text-domain-mismatch
  • deliverability.low-text

Der Editor zeigt eine Schaltfläche pro ruleId/blockId-Paar, unabhängig vom Schweregrad. Die Fix-Schaltflächen sind während KI-Bearbeitungen deaktiviert; während unabhängiger Alt-Text-Entwürfe können Sie weiterhin Fixes starten; der laufende Fix zeigt Wird behoben… und Stoppen. Der Durchlauf bleibt ein Undo-Schritt mit Verlaufstyp fix. Die Überprüfung verwendet ein Lint-Ergebnis, das den endgültigen Inhalt des Fixes bereits abdeckt; andernfalls wartet sie auf die nächste Lint-Prüfung. Bleibt ein Treffer für das Paar, erscheint Nach der Korrektur weiterhin markiert. Das ist keine Aussage über einzelne Vorkommen innerhalb eines Blocks.

Bei Domain-Abweichungen wird nur der sichtbare Linktext in beschreibende Wörter umgeschrieben, nie das href. Bei zu wenig Text (blockId: null) wird Text im E-Mail-Inhalt aus vorhandenen Fakten ergänzt, nicht im Alt-Text oder Preheader. a11y.missing-preheader setzt über updateSettings einen preheaderText mit höchstens 100 Zeichen aus dem einleitenden Inhalt.

Mit KI beheben und Alt-Text schreiben erscheinen nur, wenn @templatical/quality installiert und Lint eingeschaltet ist (lint.disabled ist nicht true). Zusätzlich müssen der jeweilige Provider-Aufruf und ein passender Befund verfügbar sowie ein Template geladen sein.

AiFixFinding sendet nur ruleId, message, suggestion, reference, blockId und optional excerpt; severity, clients und die lokale fix-Funktion bleiben im Editor. ruleId hat 1–200 UTF-16-Einheiten; blockId ist null oder höchstens 200 Einheiten lang. message, suggestion und excerpt sind auf je 1.000 Codepoints begrenzt; reference ist eine http:- oder https:-URL mit höchstens 2.048 UTF-16-Einheiten. Der Server verwirft ungültige Werte mit Status 422 und kürzt nichts.

Die kanonischen Verträge stehen unter Barrierefreiheit, Accessibility-Regelkatalog, Zustellbarkeit, Zustellbarkeits-Regelkatalog und Lint-Optionen.

Alt-Text ​

altText(request, signal) liefert { alt: string } für ein Bild, ohne den Inhalt zu ändern oder einen Chat-Verlauf anzulegen. Die Anfrage ist AiAltTextRequest aus @templatical/types:

Alle Felder und ihre Nullbarkeit stehen in AiAltTextRequest im Vertrag.

Das Bild erreicht das Modell per URL. Der Modellanbieter ruft sie ab; Ihr Backend muss daher Template und Block autorisieren und private oder signierte Medien auflösen. currentAlt ist bei leerem Alt-Text oder dekorativen Bildern null; linkHref stammt aus linkUrl. nearbyText enthält den nächsten Klartext vor und nach dem Bild in seiner Spalte, ersatzweise in seinem Abschnitt, begrenzt auf 2.000 Codepoints. locale ist die Sprache des Templates: ein BCP-47-Tag mit höchstens 35 UTF-16-Einheiten. image.url muss http: oder https: verwenden und ist auf 2.048 UTF-16-Einheiten begrenzt; currentAlt und linkHref sind jeweils null oder höchstens 2.048 Einheiten lang. blockId hat 1–200 Einheiten.

maxLength ist der wirksame Accessibility-Lint-Schwellwert altMaxLength: eine Ganzzahl von 1 bis 1.000, Standard 125 bei fehlendem oder ungültigem Wert oder deaktiviertem Lint. Gezählt werden UTF-16-Einheiten (string.length). Verwenden Sie den Anfragewert mit checkAltText in Ihrem Backend. Der Server im Backend-Leitfaden und evalAltTextWith senden bei leerem, mehrzeiligem, HTML-haltigem oder zu langem Alt-Text genau eine Reparaturanfrage. Ist auch die zweite Antwort ungültig, löst die abschließende Prüfung mit checkAltText den Fehler ai_output_invalid (502) aus.

AI_ALT_TEXT_RULES aus @templatical/editor enthält genau a11y.img-missing-alt, a11y.img-alt-is-filename, a11y.img-alt-too-long und a11y.img-linked-no-context. Das Issues-Panel bietet Alt-Text schreiben einmal je Bild für a11y.img-missing-alt, a11y.img-alt-is-filename, a11y.img-alt-too-long und a11y.img-linked-no-context an. Die Inline-Prüfung enthält einen bearbeitbaren Entwurf. Übernehmen schreibt { alt, decorative: false }; Als dekorativ markieren schreibt { alt: "", decorative: true }; Abbrechen und Escape schreiben nichts. Ein leerer alt allein löst weiterhin img-missing-alt aus. Der Renderer erzwingt bei dekorativen Bildern alt="" und role="presentation".

Entwürfe laufen unabhängig, lassen sich stoppen und werden beim Template-Wechsel oder beim Zerstören des Editors abgebrochen. Das Anwenden nutzt einen KI-Batch und einen Rückgängig-Schritt, bei Bedarf in Teile mit 100 Operationen aufgeteilt; mit Zusammenarbeit ist es der Batch der Person mit origin: 'ai'. Beides legt keinen Chat-Verlauf an. altText: false blendet die Aktion aus; über HTTP gilt features: { altText: false }.

Wenn mindestens zwei unterschiedliche Bilder Alt-Text-Befunde haben, öffnet Fehlende Alt-Texte schreiben ({count}) eine gemeinsame Prüfung in Dokumentreihenfolge mit höchstens 3 gleichzeitigen Provider-Aufrufen. Prüfen Sie jedes Vorschaubild und den bearbeitbaren Entwurf, markieren Sie bei Bedarf dekorative Bilder und wählen Sie die zu übernehmenden Zeilen aus. Stoppen bricht laufende Entwürfe ab und lässt noch nicht entworfene Zeilen bearbeitbar. Vor Ausgewählte übernehmen ({count}) wird nichts geschrieben; die ausgewählten Zeilen werden in einem Batch mit einem Rückgängig-Schritt angewendet. Abbrechen und Escape schreiben nichts.

Umformulieren ​

rewrite erhält das html eines Absatzes und ein preset (shorten, expand, friendlier, formal, fixGrammar, translate mit einer language), eine instruction oder beides. Es streamt den Text für eine Live-Vorschau und liefert das fertige HTML.

Eine gesonderte Funktion für die Übersetzung ganzer Templates gibt es nicht. Auf Anfrage kann der KI-Assistent per Chat in-place übersetzen, als einen Rückgängig-Schritt und auf Best-Effort-Basis, ohne Prüfung der Feldabdeckung oder Merge-Tags. Die Vorgabe Übersetzen beim Umformulieren übersetzt einen einzelnen Absatz.

Einstiegsanfragen ​

Ein Chat ohne Nachrichten zeigt drei statische, lokalisierte Einstiegsanfragen für eine Vorlage ohne Blöcke und vier für eine Vorlage mit Blöcken. Ein Klick sendet den angezeigten Text als Chat-Nachricht. Die Anfragen benötigen keinen Modellaufruf und lassen sich nicht durch den Integrator überschreiben.

Inhaltsprüfungen ​

Der deterministische Linter meldet konkrete Inhalts-, Client- und Größenbefunde. Er sagt die Platzierung im Posteingang nicht voraus. Siehe Zustellbarkeit und Kompatibilität.

Verlauf ​

conversation ist optional. Damit lädt der Chat beim Öffnen gespeicherte Nachrichten; „Undo“ und „Redo“ einer Nachricht rufen Ihr Backend auf. Es antwortet mit anzuwendenden Operationen ({ operations, replayId }) oder einem bereits angewendeten Batch ({ applied: { batchId, revision } }). Ohne conversation bleibt der Chat für die Sitzung im Speicher, und „Undo“ einer Nachricht wendet die eigene Inverse des Durchlaufs an. Hat jemand die betroffenen Blöcke inzwischen geändert, wird dies verweigert.

Nach Operationen bestätigt der Editor das Ergebnis mit settleReplay(templateId, messageId, { replayId, direction, applied, sessionId }). Ändern Sie undone erst bei applied: true; bei applied: false oder ohne Bestätigung bleibt der Zustand erhalten. Jede replayId wird nur einmal abgeschlossen; weitere Bestätigungen sind wirkungslos. Ein serverseitig angewendeter Batch ({ applied }) wird nicht bestätigt. Schlägt die Bestätigung fehl, erreicht der Fehler onError, und die lokale Zeile zeigt weiterhin, was am Template angewendet wurde.

conversation.list liefert AiChatMessage[] vom ältesten zum neuesten Eintrag. createdAt ist ISO 8601; batches ist für Benutzernachrichten leer. Für serverseitig angewendete Batches ist revision eine Zahl, für im Editor angewendete Batches null. kind ist "chat" | "fix"; Alt-Text-Entwürfe erzeugen keinen Verlauf. Optionale attachments enthalten nur Namen und Art auf Benutzernachrichten, keine Dateien.

Funktionen steuern ​

Setzen Sie ein Mitglied auf false, entfällt sein Einstiegspunkt: chat: false blendet den KI-Assistenten aus, rewrite: false die Schaltfläche der Werkzeugleiste, fixFinding: false die Schaltflächen „Mit KI beheben“ bei Lint-Befunden, chatAttachments: false die Anhang-Steuerung und Import-Verknüpfungen. Bei createHttpAiProvider übergeben Sie features: { rewrite: false, conversation: false }.

Fehler ​

Lehnen Sie mit einem SdkError ab, dessen code der Editor kennt und dessen Nachricht die Nutzenden verstehen:

codeWann
feature_unavailableDas Feature ist für diese Person ausgeschaltet
limit_reachedEin Kontingent ist aufgebraucht; details: { limit, resetsAt }
rate_limitedZu viele Anfragen; ein ThrottledError mit retryAfterMs
ai_turn_runningAuf diesem Template läuft bereits ein Durchlauf
content_too_largeDas Template ist für das Modell zu groß
ai_output_invalidDie Umformulierung oder Alt-Text-Ausgabe des Modells verletzt die Regeln
ai_provider_errorDer Modell-Provider ist fehlgeschlagen

Rückgängig und Wiederholen dürfen mit einem Operationscode (precondition_failed, …) als CollaborationConflict ablehnen. Ein AbortError bedeutet, dass die Person den Aufruf gestoppt hat; er wird nie angezeigt. Der Editor beschreibt jeden Fehler in Worten und reicht ihn auch an init({ onError }) weiter.

Ein gestoppter oder fehlgeschlagener Durchlauf behält die bereits angewendeten Batches. Rückgängig nimmt editorseitig angewendete Batches als einen Schritt zurück, sofern der Editor ihre Inversen besitzt. Für serverseitige onApplied-Batches braucht der gespeicherte Verlauf ein aufrufbares conversation.undo; ohne diese Replay-Unterstützung ist Rückgängig nicht verfügbar. Zwischenzeitliche Änderungen anderer können die Rücknahme verhindern. Stop führt keinen Rollback aus.

Im Editor ​

  • Header: Die mit KI beschriftete Schaltfläche öffnet und schließt den KI-Assistenten. Sie erscheint, wenn chat eine Funktion ist und ein Template geladen ist.
  • Chat: als „AI assistant“ gekennzeichnet („Replies and changes come from AI.“), pro Durchlauf „Applied N changes“ mit „Undo“ und „Redo“, „Stop“ während eines Durchlaufs, „New chat“ und statische Einstiegsanfragen. Cmd/Strg+Z macht einen ganzen Durchlauf rückgängig.
  • Absatz-Werkzeugleiste: „AI“ mit den Vorgaben, einer Zielsprachen-Auswahl und einer freien Anweisung. Das Ergebnis erscheint als „AI suggestion“, Merge-Tags als Tags und das Markup bereinigt; „Replace“ übernimmt es als eigene Änderung der Person.
  • Chat-Anhänge: Dateien per Schaltfläche oder Drag-and-drop hinzufügen, Dateinamen prüfen und Dateien vor dem Senden entfernen. Der Eingabebereich hat ein Textfeld über die volle Breite und darunter eine Werkzeugleiste mit Anhängen links und Senden oder Stoppen rechts. Die Dateinamen-Chips bleiben über dem Eingabebereich.
  • Leere Arbeitsfläche: Verknüpfungen zum KI-Assistenten und zu Aus Screenshot oder PDF importieren.

KI-Inhalte werden immer als KI gekennzeichnet, wie Artikel 50 des EU AI Act es für Systeme vorsieht, die mit Menschen interagieren.

Mit Zusammenarbeit ​

Mit einem Zusammenarbeits-Provider werden die Operationen der KI als eigene Batches der Person mit origin: 'ai' übertragen. Ein Backend, das dies berücksichtigt, sendet den Batch mit einem ai-Akteur weiter. Andere Editoren zeigen „AI (for Ada) changed 3 blocks“ mit einem Rahmen um diese Blöcke; der anfragende Editor zeigt nur den Rahmen.

Events ​

Fehler erreichen init({ onError }). Batches aus einer anderen Sitzung, auch die einer KI, erreichen init({ onRemoteChange }) wie jeder Zusammenarbeits-Batch.

Headless-Nutzung ​

Der Provider ist ein einfaches Objekt: Rufen Sie chat oder rewrite aus Ihrem eigenen Code mit denselben Anfragen auf, und wenden Sie die Operationen mit applyOperations aus @templatical/types an. @templatical/ai-kit/testing bietet createMockAiProvider für Oberflächentests und runAiProviderConformance zum Prüfen eines selbst geschriebenen Providers.

Im Playground ​

Das AI-Setup spielt aufgezeichnete Durchläufe über createMockAiProvider ab: kein Modell und keine Schlüssel. Bitten Sie um eine Titeländerung, oder klicken Sie doppelt auf einen Absatz und formulieren Sie ihn um. ?history=1 behält einen Gesprächsverlauf; ?collaboration=1&user=Ada in zwei Tabs zeigt, wie KI-Änderungen anderswo ankommen.

Im Playground öffnen

Prüfen ​

Klicken Sie auf die mit KI beschriftete Schaltfläche im Header, um den KI-Assistenten zu öffnen, und erneut, um ihn zu schließen. Öffnen Sie den KI-Assistenten für eine geladene Vorlage ohne Blöcke: Er zeigt drei Einstiegsanfragen. Fügen Sie einen Block hinzu: Er zeigt vier. Ein Klick sendet den angezeigten Text. Prüfen Sie den Provider mit der Konformitätssuite.

Öffnen Sie das Issues-Panel mit einem Befund aus der obigen Liste ohne deterministischen Fix. Mit KI beheben sendet die Lint-Projektion; nach der erneuten Prüfung verschwindet der Befund oder zeigt Nach der Korrektur weiterhin markiert. Ein Undo nimmt den gesamten Fix zurück.

Öffnen Sie einen Bildbefund und wählen Sie Alt-Text schreiben. Bearbeiten und übernehmen Sie den Entwurf, dann wählen Sie Rückgängig: alt und decorative erhalten ihre vorherigen Werte. Als dekorativ markieren entfernt img-missing-alt nach der erneuten Lint-Prüfung. Abbrechen lässt das Bild unverändert.

Wählen Sie für Anhänge auf der leeren Arbeitsfläche Aus Screenshot oder PDF importieren, wählen Sie eine Datei und prüfen Sie, dass der Chat ohne Senden öffnet. Senden Sie die vorausgefüllte Nachricht und machen Sie die Änderungen rückgängig. Prüfen Sie die Upload-Limits mit der Protokoll-Konformitätssuite bei aktiven Anhängen.