# llm.chat Generischer LLM-Chat-Adapter. Das Baustein-Modul für jeden Flow, der eine LLM-Einzelantwort braucht — klassifizieren, Felder extrahieren, umformulieren, entscheiden — ohne einen eigenen HTTP-Client zu bauen. Spricht drei Wire-Formate, wählbar über die optionale Eingabe `api`: Ollama (Default), OpenAI Chat Completions (OpenAI, vLLM, kompatible Server) und die Anthropic Messages API. ## Capability - `llm.chat@0.2.0` ## Eingaben | Name | Typ | Beschreibung | | ---------------- | ---- | ------------------------------------------------------------------------- | | `prompt` | text | Der User-Prompt. | | `endpoint` | text | Chat-Endpunkt-URL passend zur gewählten `api` (siehe unten). | | `model` | text | Modell-ID (z. B. `qwen2.5:14b`, `claude-fable-5`). | | `api_key` | text | Optionaler API-Key. Erscheint nie in Ausgaben, Logs oder Events. | | `system_prompt` | text | Optionale System-Nachricht. Leer = Default des Modells. | | `api` | text | Optionales Wire-Format: `ollama` (Default), `openai`, `anthropic`. | ### Wire-Formate (`api`) | `api` | Endpunkt-Form | Auth-Header | Hinweise | | ----------- | ----------------------------------------- | ---------------------------------- | ------------------------------------------------------------ | | `ollama` | `http://localhost:11434/api/chat` | `Authorization: Bearer` (optional) | Verhalten wie v0.1.0, unverändert. Modell-Digest-Probe via `/api/show`. | | `openai` | `https://.../v1/chat/completions` | `Authorization: Bearer` | OpenAI-Chat-Completions-Format — sprechen auch vLLM und die meisten selbst gehosteten Inferenz-Server. | | `anthropic` | `https://api.anthropic.com/v1/messages` | `x-api-key` + `anthropic-version` | Messages API: `system` ist Top-Level-Feld; `max_tokens` ist Pflicht und steht fest auf 4096. | ## Ausgaben | Name | Typ | Beschreibung | | ---------------- | ---- | --------------------------------------------------------------------- | | `response` | text | Die Antwort des Assistants als Plain-Text. | | `model_endpoint` | text | URL, gegen die die Antwort erzeugt wurde. | | `model_name` | text | Modell-ID wie an die LLM-API gesendet. | | `model_digest` | text | SHA-256-Digest des bedienenden Ollama-Modells. Leer bei `openai`/`anthropic` — diese APIs bieten keinen Digest; das Feld bleibt leer statt erfunden. | Zusammen beantworten die drei `model_*`-Ausgaben die Audit- Frage: „Welches genaue Modell hat diese Antwort erzeugt?" — diese Spur ist der Grund, warum Flows dieses Modul nutzen statt eigene HTTP-Calls zu sprechen. ## Berechtigungen ```yaml permissions: - "net: localhost" - "net: 127.0.0.1" - "net: api.openai.com" - "net: api.anthropic.com" ``` Loopback (lokales Ollama / vLLM) per Default. Cloud-Endpunkte brauchen einen Operator-Policy-Override in `~/.chain/config.yaml#security.max_permissions`. ## Warum dieses Modul statt Inline-HTTP Drei Gründe: 1. **Audit.** Jeder LLM-Aufruf erzeugt `model_endpoint`, `model_name`, `model_digest` als separate Ausgaben, die im hash-verketteten Audit-Log neben der Response landen. Eine Aufsichts-Reproduzierbarkeits-Prüfung vergleicht einfach das Digest-Feld mit dem Modell-Snapshot. 2. **Permission-Posture.** Operator:innen sehen `llm.chat` in den installierten Modulen + dessen deklarierte `net:`-Liste. Ein hausgemachtes HTTP-Modul würde seine Endpunkte entweder verstecken oder bei jeder Installation eine frische Review-Oberfläche schaffen. 3. **Endpunkt-Portabilität.** Endpunkt, Modell und Wire-Format sind Flow-Inputs, keine Compile-Time-Konstanten. Derselbe Flow läuft in der Entwicklung gegen `localhost:11434` und in Produktion gegen ein vLLM-Cluster — nur die Eingaben wechseln. ## Grenzen in v0.2.0 - Kein Streaming. Die ganze Antwort wird gepuffert, bevor der Output-Step feuert. - Keine Tool-Call- / Function-Call-Oberfläche. Ein Flow, der Tool-Use braucht, kombiniert mehrere `llm.chat`-Schritte mit Prompt-Engineering oder nutzt MCP via Bridge. - Anthropic-`max_tokens` steht fest auf 4096 (die API verlangt das Feld; eine konfigurierbare Eingabe kommt, sobald ein Flow sie braucht). ## Beispiel-Flows ```yaml name: classify-incoming inputs: text: text steps: - id: classify use: llm.chat@^0 with: prompt: $inputs.text system_prompt: | Klassifiziere den Text als: question, complaint, feedback, spam. Antworte nur mit dem Label. endpoint: "http://localhost:11434/api/chat" model: "qwen2.5:14b" outputs: category: $classify.response audit_model: $classify.model_digest ``` Gegen einen vLLM-Server (OpenAI-kompatibel): ```yaml steps: - id: classify use: llm.chat@^0 with: api: "openai" endpoint: "http://inference.internal:8000/v1/chat/completions" model: "meta-llama/Llama-3.1-8B-Instruct" prompt: $inputs.text ``` Gegen die Anthropic Messages API: ```yaml steps: - id: classify use: llm.chat@^0 with: api: "anthropic" endpoint: "https://api.anthropic.com/v1/messages" model: "claude-fable-5" api_key: $inputs.anthropic_key prompt: $inputs.text ``` ## Build ```bash cargo build --release --target wasm32-wasip2 # Ausgabe: target/wasm32-wasip2/release/llm_chat.wasm ```