diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 56ea4e9..89d5a1d 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: git fetch --depth=1 origin "$GITHUB_SHA" git checkout -q FETCH_HEAD - # The chain-module-sdk dependency is a git dep against a repo + # The fai-module-sdk dependency is a git dep against a repo # that lives in another Forgejo org. The repo-scoped # GITHUB_TOKEN cannot read it, and the Forgejo instance has # REQUIRE_SIGNIN_VIEW=true so anonymous read is also denied. diff --git a/.forgejo/workflows/sign.yml b/.forgejo/workflows/sign.yml deleted file mode 100644 index df54b75..0000000 --- a/.forgejo/workflows/sign.yml +++ /dev/null @@ -1,223 +0,0 @@ -# F∆I module bundle signing workflow (cosign key-pinning model). -# -# Drop-in template for any module repo under chain-modules/. -# Triggers on tag push (vX.Y.Z) — builds the module, packs the -# .fai bundle, signs the bundle bytes with the Flemming.AI -# signing key (ECDSA P-256), and attaches bundle + .sig sidecar -# to the matching Forgejo Release. -# -# The hub-side verifier ships in 0.12.0+: when an operator sets -# `require_signatures: true`, install downloads the .sig sidecar -# from `.sig` and verifies it against the pinned store -# public key (built-in for `bundled` / `official`, per-store -# config for everything else). -# -# Adopt by copying this file to `.forgejo/workflows/sign.yml` in -# the module repo and replacing the MODULE_NAME placeholder. -# Add the signing key to Forgejo secrets as FAI_SIGNING_KEY (PEM, -# unencrypted, ECDSA P-256). Rotation is a 5-minute key-roll + -# binary re-release; see infra/cosign/README.md. - -name: sign-bundle - -on: - push: - tags: - - 'v*.*.*' - -env: - CARGO_TERM_COLOR: always - RUST_TOOLCHAIN: "1.86" - CARGO_NET_GIT_FETCH_WITH_CLI: "true" - -jobs: - sign: - runs-on: ubuntu-latest - permissions: - contents: write # attach signature to release - - env: - # The canonical module name as written in module.yaml. - # Used in the bundle filename + wasm path. - MODULE_NAME: llm-chat - - steps: - # See fai/platform CI for background on the manual external - # checkout: the DinD runner cannot resolve forgejo:3000, so - # we clone via the external URL with $GITHUB_TOKEN. - - name: Checkout via external URL - run: | - set -eu - mkdir -p "$GITHUB_WORKSPACE" - cd "$GITHUB_WORKSPACE" - git init -q - git remote add origin \ - "https://x-access-token:${GITHUB_TOKEN}@git.flemming.ai/${GITHUB_REPOSITORY}.git" - git fetch --depth=1 origin "$GITHUB_SHA" - git checkout -q FETCH_HEAD - - # The chain-module-sdk dependency lives in another Forgejo org - # behind REQUIRE_SIGNIN_VIEW. MODULE_SDK_PAT (org-level - # secret, read-only on fai/module-sdk) authenticates cargo's - # git fetch via insteadOf. - - name: Configure git URL rewrite for SDK fetch - env: - SDK_PAT: ${{ secrets.MODULE_SDK_PAT }} - run: | - git config --global \ - "url.https://x-access-token:${SDK_PAT}@git.flemming.ai/.insteadOf" \ - "https://git.flemming.ai/" - - - name: Install system dependencies - run: | - apt-get update -qq - apt-get install -y --no-install-recommends \ - curl \ - ca-certificates \ - build-essential \ - pkg-config \ - libssl-dev \ - git \ - jq \ - openssl - - - name: Install Rust toolchain - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ - | sh -s -- -y \ - --profile minimal \ - --default-toolchain "$RUST_TOOLCHAIN" \ - --target wasm32-wasip2 - echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - - - name: Build module (wasm32-wasip2) - run: cargo build --release --target wasm32-wasip2 - - - name: Install fai CLI - # Pinned to the production channel; signing requires the - # `fai pack` command. Override FAI_VERSION when bundle - # format compatibility matters. - run: | - curl -fsSL https://get.chain.flemming.ai | sh -s -- --no-bootstrap - # The installer drops fai at $HOME/.local/bin - echo "$HOME/.local/bin" >> "$GITHUB_PATH" - export PATH="$HOME/.local/bin:$PATH" - fai --version - - - name: Stage bundle inputs - # The wasm artefact is named after the Cargo package - # (underscored), which may differ from the module name - # in module.yaml (dashed). Resolve it from Cargo.toml so - # the template stays agnostic to the project's naming - # convention. - run: | - set -eu - CARGO_NAME=$(grep -E '^name *= *"' Cargo.toml \ - | head -1 | sed 's/.*"\(.*\)".*/\1/') - mkdir -p staging - cp module.yaml staging/ - cp "target/wasm32-wasip2/release/${CARGO_NAME}.wasm" staging/module.wasm - if [ -f sbom.cdx.json ]; then cp sbom.cdx.json staging/; fi - if [ -f MODULE.md ]; then cp MODULE.md staging/; fi - if [ -f MODULE.de.md ]; then cp MODULE.de.md staging/; fi - - - name: Pack bundle - id: pack - run: | - export PATH="$HOME/.local/bin:$PATH" - BUNDLE="${{ env.MODULE_NAME }}-${{ github.ref_name }}.fai" - fai pack staging --output "$BUNDLE" - echo "bundle=$BUNDLE" >> "$GITHUB_OUTPUT" - ls -la "$BUNDLE" - - - name: Sign bundle (Flemming.AI signing key) - env: - FAI_SIGNING_KEY_PEM: ${{ secrets.FAI_SIGNING_KEY }} - run: | - if [ -z "${FAI_SIGNING_KEY_PEM:-}" ]; then - cat >&2 <<'EOF' - - FAI_SIGNING_KEY secret is empty or undefined. - - This workflow signs module bundles with the Flemming.AI - module-signing key (ECDSA P-256, PKCS#8 PEM, unencrypted). - The matching public key is pinned in the fai-hub binary at - infra/cosign/official.pub — hubs that require_signatures - will reject anything not signed with this key. - - To configure: - 1. Forgejo -> chain-modules org -> Settings -> Secrets - 2. Add secret FAI_SIGNING_KEY (org-level recommended) - 3. Paste the unencrypted PEM (BEGIN PRIVATE KEY ...) - The encrypted source-of-truth lives on Stefan's Mac at - ~/.fai-secrets/flemming-ai-signing.key (passphrase in - mSecure under "Ch∆In — Module Signing Key (Private)"). - - See fai/platform infra/cosign/OPERATOR-HANDOFF.md for the - full setup runbook and rotation process. - EOF - exit 1 - fi - umask 077 - echo "$FAI_SIGNING_KEY_PEM" > /tmp/signing-key.pem - openssl dgst -sha256 \ - -sign /tmp/signing-key.pem \ - -out "${{ steps.pack.outputs.bundle }}.sig.raw" \ - "${{ steps.pack.outputs.bundle }}" - base64 < "${{ steps.pack.outputs.bundle }}.sig.raw" \ - > "${{ steps.pack.outputs.bundle }}.sig" - rm "${{ steps.pack.outputs.bundle }}.sig.raw" - shred -u /tmp/signing-key.pem || rm -f /tmp/signing-key.pem - ls -la "${{ steps.pack.outputs.bundle }}.sig" - - - name: Round-trip verify - # Sanity-check: the freshly-signed bundle must verify - # against the well-known public key before we publish it. - run: | - curl -fsSL https://git.flemming.ai/fai/platform/raw/branch/main/infra/cosign/official.pub \ - -o /tmp/official.pub - openssl dgst -sha256 \ - -verify /tmp/official.pub \ - -signature <(base64 -d < "${{ steps.pack.outputs.bundle }}.sig") \ - "${{ steps.pack.outputs.bundle }}" - - - name: Attach bundle + signature to Forgejo Release - run: | - set -eu - BUNDLE="${{ steps.pack.outputs.bundle }}" - SIG="$BUNDLE.sig" - REL_JSON=$(curl -sS \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "https://git.flemming.ai/api/v1/repos/${GITHUB_REPOSITORY}/releases/tags/${GITHUB_REF_NAME}") - REL_ID=$(echo "$REL_JSON" | jq -r '.id // empty') - if [ -z "$REL_ID" ] || [ "$REL_ID" = "null" ]; then - REL_ID=$(curl -sS -X POST \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - -H "Content-Type: application/json" \ - "https://git.flemming.ai/api/v1/repos/${GITHUB_REPOSITORY}/releases" \ - -d "{\"tag_name\":\"${GITHUB_REF_NAME}\",\"name\":\"${GITHUB_REF_NAME}\",\"draft\":false,\"prerelease\":false,\"body\":\"Auto-generated by sign-bundle workflow\"}" \ - | jq -r '.id') - fi - upload_one() { - local asset_path="$1" asset - asset=$(basename "$asset_path") - EXISTING=$(curl -sS \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "https://git.flemming.ai/api/v1/repos/${GITHUB_REPOSITORY}/releases/${REL_ID}/assets" \ - | jq -r ".[] | select(.name==\"${asset}\") | .id") - if [ -n "$EXISTING" ]; then - curl -sS -X DELETE \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "https://git.flemming.ai/api/v1/repos/${GITHUB_REPOSITORY}/releases/${REL_ID}/assets/${EXISTING}" \ - || true - fi - curl -sS -X POST \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - -F "attachment=@${asset_path}" \ - "https://git.flemming.ai/api/v1/repos/${GITHUB_REPOSITORY}/releases/${REL_ID}/assets?name=${asset}" \ - > /dev/null - echo "uploaded $asset" - } - upload_one "$BUNDLE" - upload_one "$SIG" - echo "release ${GITHUB_REF_NAME} ready: https://git.flemming.ai/${GITHUB_REPOSITORY}/releases/tag/${GITHUB_REF_NAME}" diff --git a/Cargo.lock b/Cargo.lock index dcff588..df3d448 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,11 +39,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "chain-module-sdk" +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fai-module-sdk" version = "0.1.2" -source = "git+https://git.flemming.ai/fai/chain-module-sdk-rust.git?branch=main#98e98e9371f7409560a1ef08bc0923d9a2506449" +source = "git+https://git.flemming.ws/fai/module-sdk.git?branch=main#f209fbc86f531b53e576f3cdbdf75750eef3b07a" dependencies = [ - "chain-module-sdk-macros", + "fai-module-sdk-macros", "serde", "serde_json", "thiserror", @@ -51,21 +57,15 @@ dependencies = [ ] [[package]] -name = "chain-module-sdk-macros" +name = "fai-module-sdk-macros" version = "0.1.2" -source = "git+https://git.flemming.ai/fai/chain-module-sdk-rust.git?branch=main#98e98e9371f7409560a1ef08bc0923d9a2506449" +source = "git+https://git.flemming.ws/fai/module-sdk.git?branch=main#f209fbc86f531b53e576f3cdbdf75750eef3b07a" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -140,7 +140,7 @@ checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545" name = "llm_chat" version = "0.1.0" dependencies = [ - "chain-module-sdk", + "fai-module-sdk", "serde", "serde_json", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 72db65b..f15b1f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ description = "F∆I module providing llm.chat" crate-type = ["cdylib", "rlib"] [dependencies] -chain-module-sdk = { git = "https://git.flemming.ai/fai/chain-module-sdk-rust.git", branch = "main" } +fai-module-sdk = { git = "https://git.flemming.ws/fai/module-sdk.git", branch = "main" } serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "2" diff --git a/LICENSE b/LICENSE index cdde5b2..9536d06 100644 --- a/LICENSE +++ b/LICENSE @@ -58,7 +58,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2026 Flemming.AI +Copyright 2026 fai-modules Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MODULE.de.md b/MODULE.de.md deleted file mode 100644 index 4d12be6..0000000 --- a/MODULE.de.md +++ /dev/null @@ -1,106 +0,0 @@ -# llm.chat - -Generischer Ollama-kompatibler 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. - -## Capability - -- `llm.chat@0.1.0` - -## Eingaben - -| Name | Typ | Beschreibung | -| ---------------- | ---- | ------------------------------------------------------------------------- | -| `prompt` | text | Der User-Prompt. | -| `endpoint` | text | Ollama-förmiger `/api/chat`-URL (z.B. `http://localhost:11434/api/chat`). | -| `model` | text | Modell-ID (z.B. `qwen2.5:14b`, `llama3.1:8b`). | -| `api_key` | text | Optionaler Bearer-Token für Cloud-Endpunkte. | -| `system_prompt` | text | Optionale System-Nachricht. Leer = Default des Modells. | - -## 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 Cloud-APIs. | - -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) 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 sind Flow- - Inputs, keine Compile-Time-Konstanten. Derselbe Flow läuft - in der Entwicklung gegen `localhost:11434` und in Produktion - gegen ein Inferenz-Cluster — nur die Eingabe wechselt. - -## Grenzen in v0.1.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. -- Cloud-Provider-Adapter für OpenAI und Anthropic kommen erst, - wenn ein Flow sie braucht. Heute ist das Ollama-Wire-Format - das einzige Ziel. - -## Beispiel-Flow - -```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 -``` - -## Build - -```bash -cargo build --release --target wasm32-wasip2 -# Ausgabe: target/wasm32-wasip2/release/llm_chat.wasm -``` diff --git a/MODULE.md b/MODULE.md deleted file mode 100644 index 49460ad..0000000 --- a/MODULE.md +++ /dev/null @@ -1,104 +0,0 @@ -# llm.chat - -Generic Ollama-compatible LLM chat adapter. The building-block -module any flow uses when it needs a one-shot LLM completion — -classify, extract-fields, rewrite, decide — instead of rolling -its own HTTP client. - -## Capability - -- `llm.chat@0.1.0` - -## Inputs - -| Name | Type | Description | -| ---------------- | ---- | --------------------------------------------------------------- | -| `prompt` | text | The user-facing prompt. | -| `endpoint` | text | Ollama-shaped `/api/chat` URL (e.g. `http://localhost:11434/api/chat`). | -| `model` | text | Model identifier (e.g. `qwen2.5:14b`, `llama3.1:8b`). | -| `api_key` | text | Optional bearer token for cloud-hosted endpoints. | -| `system_prompt` | text | Optional system message. Empty = use the model's default. | - -## Outputs - -| Name | Type | Description | -| ---------------- | ---- | ------------------------------------------------------------------- | -| `response` | text | The assistant's plain-text reply. | -| `model_endpoint` | text | The endpoint the response was generated against. | -| `model_name` | text | The model identifier as supplied to the LLM API. | -| `model_digest` | text | SHA-256 digest of the served Ollama model. Empty for cloud APIs. | - -Together the three `model_*` outputs answer the audit -question: "which exact model produced this response?" — that -audit trail is the reason flows use this module rather than -spawning their own HTTP calls. - -## Permissions - -```yaml -permissions: - - "net: localhost" - - "net: 127.0.0.1" - - "net: api.openai.com" - - "net: api.anthropic.com" -``` - -Loopback (local Ollama) by default. Cloud endpoints require an -operator-policy override in `~/.chain/config.yaml#security.max_permissions`. - -## Why this module instead of inline HTTP - -Three reasons: - -1. **Audit.** Every LLM call surfaces `model_endpoint`, - `model_name`, `model_digest` as separate outputs that land - in the hash-chained audit log alongside the response. A - regulator-facing reproducibility check just compares the - digest field to the model snapshot. -2. **Permission posture.** The operator sees `llm.chat` in - the installed modules + its declared `net:` list. A - home-grown HTTP module would either hide its endpoints - or be a fresh review surface every time. -3. **Endpoint portability.** The endpoint + model are flow - inputs, not compile-time constants. The same flow runs - against `localhost:11434` in dev and a production - inference cluster in prod just by swapping the input. - -## Limits in v0.1.0 - -- No streaming. The whole reply is buffered before the output - step fires. -- No tool-call / function-call surface. A flow needing tool - use composes multiple `llm.chat` steps with prompt - engineering, or uses MCP via the bridge. -- Cloud-provider adapters for OpenAI and Anthropic are - deferred until a flow actually needs them. Today the - Ollama wire-format is the only target. - -## Example flow - -```yaml -name: classify-incoming -inputs: - text: text -steps: - - id: classify - use: llm.chat@^0 - with: - prompt: $inputs.text - system_prompt: | - Classify the text as one of: question, complaint, - feedback, spam. Answer with the label only. - endpoint: "http://localhost:11434/api/chat" - model: "qwen2.5:14b" -outputs: - category: $classify.response - audit_model: $classify.model_digest -``` - -## Build - -```bash -cargo build --release --target wasm32-wasip2 -# Output: target/wasm32-wasip2/release/llm_chat.wasm -``` diff --git a/README.md b/README.md index 275de8d..4002f93 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ on every successful invocation. Together they answer the audit question "which exact model produced this response?" The digest probe targets Ollama's `/api/show` and is best-effort — non- Ollama endpoints and transient probe failures yield an empty -digest rather than blocking the response. Cf. Ch∆In +digest rather than blocking the response. Cf. F∆I Platform `docs/advanced/compliance-gaps.md` Gap 1. ## Build @@ -47,7 +47,7 @@ cargo build --release --target wasm32-wasip2 ## SDK source -The Cargo.toml git-deps `chain-module-sdk` from +The Cargo.toml git-deps `fai-module-sdk` from `https://git.flemming.ws/fai/module-sdk.git`. The Forgejo instance has `REQUIRE_SIGNIN_VIEW=true`, so anonymous clones fail; CI uses the `MODULE_SDK_PAT` actions secret + `git config @@ -58,5 +58,5 @@ transparently. Local dev uses the same pattern via env vars. Apache-2.0. -Author: Dr. Stefan Flemming, Flemming.AI -Repository: https://git.flemming.ws/chain-modules/llm-chat +Author: Dr. Stefan Flemming, Flemming.AI +Repository: https://git.flemming.ws/fai-modules/llm-chat diff --git a/module.wasm b/module.wasm deleted file mode 100644 index 51fc8b7..0000000 Binary files a/module.wasm and /dev/null differ diff --git a/module.yaml b/module.yaml index 503111a..4448cfd 100644 --- a/module.yaml +++ b/module.yaml @@ -1,5 +1,4 @@ -schema_version: 3 -provider: chain +schema_version: 1 name: llm-chat version: 0.1.0 @@ -8,81 +7,38 @@ provides: - capability: llm.chat version: 0.1.0 -# Declared inputs in verbose v3 form. Studio renders the -# description in the active locale as a tooltip on each -# port; the editor falls back to the English description -# when no peer is configured. +# Inputs the invoke function accepts. inputs: - prompt: - type: text - description: - en: The user-facing prompt text the model should respond to. - de: Der vom Modell zu beantwortende Prompt-Text. - endpoint: - type: text - description: - en: | - Ollama-shaped /api/chat endpoint, e.g. - "http://localhost:11434/api/chat". - de: | - Ollama-kompatibler /api/chat-Endpunkt, z. B. - "http://localhost:11434/api/chat". - model: - type: text - description: - en: Model identifier as registered with the endpoint, e.g. "qwen2.5:14b" or "llama3.1:8b". - de: Modell-Identifier wie beim Endpunkt registriert, z. B. "qwen2.5:14b" oder "llama3.1:8b". - api_key: - type: text - description: - en: | - Optional bearer token for cloud-hosted endpoints. - Empty string means no Authorization header is sent. - de: | - Optionaler Bearer-Token für Cloud-Endpunkte. - Leer = kein Authorization-Header gesendet. - system_prompt: - type: text - description: - en: | - Optional system prompt. Empty string omits the system - message and lets the model use its built-in default. - de: | - Optionaler System-Prompt. Leer = das Modell verwendet - seinen eingebauten Default. + # The user-facing prompt text. + prompt: text + # Ollama-shaped /api/chat endpoint, e.g. + # "http://localhost:11434/api/chat". + endpoint: text + # Model identifier as registered with the endpoint, e.g. + # "qwen2.5:14b" or "llama3.1:8b". + model: text + # Optional bearer token for cloud-hosted endpoints. Empty + # string means no Authorization header is sent. + api_key: text + # Optional system prompt. Empty string omits the system + # message and lets the model use its built-in default. + system_prompt: text # Outputs produced. outputs: - response: - type: text - description: - en: The assistant's plain-text reply. - de: Die Klartext-Antwort des Modells. - model_endpoint: - type: text - description: - en: The endpoint the response was generated against. Used for audit correlation. - de: Der Endpunkt, gegen den die Antwort erzeugt wurde — für Audit-Korrelation. - model_name: - type: text - description: - en: The model identifier as supplied to the LLM API. - de: Der an die LLM-API übergebene Modell-Identifier. - model_digest: - type: text - description: - en: | - SHA-256 digest of the served Ollama model, when reachable. - Empty for non-Ollama endpoints (OpenAI / Anthropic do not - expose a digest API). Together with model_endpoint and - model_name this answers the audit question "which exact - model produced this response?" - de: | - SHA-256-Digest des bedienten Ollama-Modells, wenn erreichbar. - Leer für Nicht-Ollama-Endpunkte (OpenAI / Anthropic stellen - keine Digest-API bereit). Zusammen mit model_endpoint und - model_name beantwortet das die Audit-Frage "welches genaue - Modell hat diese Antwort erzeugt?" + # The assistant's plain-text reply. + response: text + # The endpoint the response was generated against. Used for + # audit correlation. + model_endpoint: text + # The model identifier as supplied to the LLM API. + model_name: text + # SHA-256 digest of the served Ollama model, when reachable. + # Empty for non-Ollama endpoints (OpenAI / Anthropic do not + # expose a digest API). Together with model_endpoint and + # model_name this answers the audit question "which exact + # model produced this response?" + model_digest: text # Permissions required. # diff --git a/src/lib.rs b/src/lib.rs index c13d8f1..f329bc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ mod llm; -use chain_module_sdk::prelude::*; +use fai_module_sdk::prelude::*; #[fai_module] pub fn invoke(_ctx: Context, inputs: Inputs) -> Result {