Compare commits

...

10 commits
v0.1.0 ... main

Author SHA1 Message Date
9acac8beb7 chore: org rename fai-modules/fai-plugins -> chain-modules/chain-plugins + LICENSE holder
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 1s
Signed-off-by: flemming-it <sf@flemming.it>
2026-06-16 18:25:43 +02:00
5b798c1bf2 docs/ci: chain-*-sdk references (renamed SDK)
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 2s
Signed-off-by: flemming-it <sf@flemming.it>
2026-06-16 11:32:28 +02:00
0ad1df619c refactor: depend on renamed chain-module-sdk
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 2s
Signed-off-by: flemming-it <sf@flemming.it>
2026-06-16 11:29:45 +02:00
b030f2c9c8 docs: old product name F∆I Platform -> Ch∆In
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 2s
The product is Ch∆In; the old 'F∆I Platform' name survived in module
docs/manifests. Generic 'platform' terms left untouched.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-16 10:15:31 +02:00
c4839e6532 refactor: rename to chain:platform WIT + provider chain
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 1s
Tracks the platform's fai->chain rename: capability provider chain,
WIT ABI chain:platform (binding paths/accessors), SDK pin bumped.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-15 22:54:59 +02:00
64d44f76f1 feat: schema_version 3 with DE/EN field descriptions
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 1s
Signed-off-by: flemming-it <sf@flemming.it>
2026-06-01 22:46:15 +02:00
d356d3584b ci: sign release bundles with FAI_SIGNING_KEY
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 2s
Drop-in from fai/platform .forgejo/workflow-templates/
sign-bundle-keypair.yml. Triggers on v*.*.* tag push: builds
wasm32-wasip2, fetches the fai CLI from get.fai.flemming.ai,
packs the bundle, ECDSA P-256 signs it against the org-level
Forgejo secret FAI_SIGNING_KEY, round-trip-verifies against
infra/cosign/official.pub on fai/platform main, and attaches
bundle + .sig to the Forgejo Release via the API.

Signed-off-by: flemming-it <sf@flemming.it>
2026-05-28 23:15:19 +02:00
dd32aadd9d chore(module): schema_version 2 + explicit provider
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 1s
Brings module.yaml in line with F∆I 0.12.0's capability naming
convention. The legacy schema_version 1 (with implicit provider)
still loads in 0.12.0 via the grace-period default, but this
bump makes the publisher identity explicit and unblocks
storage-layout migration via 'fai migrate'.

See fai/platform docs/reference/capability-namespaces.yaml +
docs/operations/migration-to-0.12.md.

Signed-off-by: flemming-it <sf@flemming.it>
2026-05-28 11:48:25 +02:00
7393756cca chore: SDK URL → git.flemming.ai/fai/module-sdk-rust
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 1s
The fai-module-sdk repo was renamed from `fai/module-sdk` to
`fai/module-sdk-rust` to align with the three SDK families
convention (base + language suffix). Pin updated accordingly.
The old git.flemming.ws URL is also retired in this pass.

Signed-off-by: flemming-it <sf@flemming.it>
2026-05-26 13:16:53 +02:00
7c989f3d91 docs: add MODULE.md + MODULE.de.md inline docs
Some checks failed
CI / Linux x86_64 (Forgejo) (push) Failing after 1s
Same shape as text-extract's docs commit. Audit-grade model-
provenance fields documented next to each output so the
operator sees the contract without leaving the Store sheet.

Signed-off-by: flemming-it <sf@flemming.it>
2026-05-25 14:06:04 +02:00
11 changed files with 502 additions and 52 deletions

View file

@ -30,7 +30,7 @@ jobs:
git fetch --depth=1 origin "$GITHUB_SHA" git fetch --depth=1 origin "$GITHUB_SHA"
git checkout -q FETCH_HEAD git checkout -q FETCH_HEAD
# The fai-module-sdk dependency is a git dep against a repo # The chain-module-sdk dependency is a git dep against a repo
# that lives in another Forgejo org. The repo-scoped # that lives in another Forgejo org. The repo-scoped
# GITHUB_TOKEN cannot read it, and the Forgejo instance has # GITHUB_TOKEN cannot read it, and the Forgejo instance has
# REQUIRE_SIGNIN_VIEW=true so anonymous read is also denied. # REQUIRE_SIGNIN_VIEW=true so anonymous read is also denied.

223
.forgejo/workflows/sign.yml Normal file
View file

@ -0,0 +1,223 @@
# 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 `<wasm_url>.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: text-translate
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}"

24
Cargo.lock generated
View file

@ -39,17 +39,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]] [[package]]
name = "equivalent" name = "chain-module-sdk"
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" version = "0.1.2"
source = "git+https://git.flemming.ws/fai/module-sdk.git?branch=main#f209fbc86f531b53e576f3cdbdf75750eef3b07a" source = "git+https://git.flemming.ai/fai/chain-module-sdk-rust.git?branch=main#98e98e9371f7409560a1ef08bc0923d9a2506449"
dependencies = [ dependencies = [
"fai-module-sdk-macros", "chain-module-sdk-macros",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
@ -57,15 +51,21 @@ dependencies = [
] ]
[[package]] [[package]]
name = "fai-module-sdk-macros" name = "chain-module-sdk-macros"
version = "0.1.2" version = "0.1.2"
source = "git+https://git.flemming.ws/fai/module-sdk.git?branch=main#f209fbc86f531b53e576f3cdbdf75750eef3b07a" source = "git+https://git.flemming.ai/fai/chain-module-sdk-rust.git?branch=main#98e98e9371f7409560a1ef08bc0923d9a2506449"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
] ]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.2.2" version = "1.2.2"
@ -267,7 +267,7 @@ dependencies = [
name = "text_translate" name = "text_translate"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fai-module-sdk", "chain-module-sdk",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",

View file

@ -17,7 +17,7 @@ description = "F∆I module providing text.translate"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
fai-module-sdk = { git = "https://git.flemming.ws/fai/module-sdk.git", branch = "main" } chain-module-sdk = { git = "https://git.flemming.ai/fai/chain-module-sdk-rust.git", branch = "main" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
thiserror = "2" thiserror = "2"

View file

@ -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. 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 fai-modules Copyright 2026 Flemming.AI
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

94
MODULE.de.md Normal file
View file

@ -0,0 +1,94 @@
# text.translate
Ollama-basierte Übersetzung zwischen Sprachen. Sendet Quelltext
an einen konfigurierten LLM-Endpunkt mit einem
Übersetzungs-System-Prompt und liefert die Übersetzung plus
audit-taugliche Modell-Herkunfts-Felder.
## Capability
- `text.translate@0.1.0`
## Eingaben
| Name | Typ | Beschreibung |
| ----------------- | ---- | ------------------------------------------------------------------------- |
| `text` | text | Quelltext. |
| `target_language` | text | Zielsprache in einfachem Englisch (z.B. `German`, `French`, `ja-JP`). |
| `source_language` | text | Optionaler Hinweis auf die Ausgangssprache. Leer = Modell erkennt selbst. |
| `endpoint` | text | Ollama-förmiger `/api/chat`-Endpunkt. |
| `model` | text | Modell-ID am Endpunkt (z.B. `qwen2.5:14b`). |
| `api_key` | text | Optionaler Bearer-Token für Cloud-Endpunkte. |
## Ausgaben
| Name | Typ | Beschreibung |
| ----------------- | ---- | ------------------------------------------------------------------ |
| `translation` | text | Die Übersetzung. |
| `source_language` | text | Echo der Eingabe (oder erkannte Sprache bei Auto). |
| `target_language` | text | Echo der Eingabe. |
| `model_endpoint` | text | URL, gegen die übersetzt wurde. |
| `model_name` | text | Modell-ID wie an die LLM-API gesendet. |
| `model_digest` | text | SHA-256-Digest des bedienenden Ollama-Modells (wenn erreichbar). |
Die drei `model_*`-Ausgaben sind das Audit-Primitiv: jede
Übersetzung im Flow-Log lässt sich auch Monate später dem exakten
Modell-Hash zuordnen, der sie erzeugt hat.
## Berechtigungen
```yaml
permissions:
- "net: localhost"
- "net: 127.0.0.1"
- "net: api.openai.com"
- "net: api.anthropic.com"
```
Default-Policy erlaubt lokales Ollama und die zwei großen
Hosted-Anbieter. Mit privatem LLM-Endpunkt: Hostname in die
Operator-Policy-Ceiling aufnehmen; das Modul prüft seine
Berechtigungen gegen diese Ceiling bei der Installation.
## Für regulierte Umgebungen gebaut
Der Ollama-Endpunkt steht per Default auf einem lokalen Daemon
— Quelltext verlässt nie den Rechner. Cloud-Anbieter sind
Opt-in über die URL + Operator-Policy. Das `model_digest`-Feld
ist der kryptographische Vertrauensanker für die
Übersetzungs-Herkunft: zwei Ausgaben mit gleichem Digest
stammen vom selben Modell-Gewicht, Punkt.
## Grenzen in v0.1.0
- Single-Shot. Lange Dokumente mit Chunking + Überlapp-
Stitching folgt in v0.2.0.
- Keine Glossar-/Terminologie-Listen. Aktuell verlässt sich das
Modul auf das Allgemeinwissen des Modells; ein `glossary`-
Input ist auf der v0.2.0-Roadmap.
## Beispiel-Flow
```yaml
name: translate-to-german
inputs:
source: text
steps:
- id: translate
use: text.translate@^0
with:
text: $inputs.source
target_language: "German"
endpoint: "http://localhost:11434/api/chat"
model: "qwen2.5:14b"
outputs:
translation: $translate.translation
audit_model: $translate.model_digest
```
## Build
```bash
cargo build --release --target wasm32-wasip2
# Ausgabe: target/wasm32-wasip2/release/text_translate.wasm
```

94
MODULE.md Normal file
View file

@ -0,0 +1,94 @@
# text.translate
Ollama-backed translation between languages. Sends source text
to a configured LLM endpoint with a translation system prompt
and emits the translated text plus audit-grade
model-provenance fields.
## Capability
- `text.translate@0.1.0`
## Inputs
| Name | Type | Description |
| ----------------- | ---- | ---------------------------------------------------------------------- |
| `text` | text | Source text to translate. |
| `target_language` | text | Target language in plain English (e.g. `German`, `French`, `ja-JP`). |
| `source_language` | text | Optional source-language hint. Empty = let the model auto-detect. |
| `endpoint` | text | Ollama-shaped `/api/chat` endpoint URL. |
| `model` | text | Model identifier the endpoint serves (e.g. `qwen2.5:14b`). |
| `api_key` | text | Optional bearer token for cloud-hosted endpoints. |
## Outputs
| Name | Type | Description |
| ----------------- | ---- | -------------------------------------------------------------------- |
| `translation` | text | The translated text. |
| `source_language` | text | Echo of the input value (or detected language when auto). |
| `target_language` | text | Echo of the input value. |
| `model_endpoint` | text | URL the translation was generated against. |
| `model_name` | text | Model identifier as supplied to the LLM API. |
| `model_digest` | text | SHA-256 digest of the served Ollama model (when reachable). |
The three `model_*` outputs are the audit primitive: every
translation in the flow log can be matched to the exact model
hash that produced it, even months later.
## Permissions
```yaml
permissions:
- "net: localhost"
- "net: 127.0.0.1"
- "net: api.openai.com"
- "net: api.anthropic.com"
```
The default policy allows local Ollama and the two major
hosted providers. Operators with a private LLM endpoint add
their hostname to the operator-policy ceiling; the module's
permissions are enforced against that ceiling at install time.
## Built for regulated environments
The Ollama endpoint defaults to a local daemon — source text
never leaves the host. Cloud providers are opt-in via the
endpoint URL + operator policy. The `model_digest` field is
the cryptographic root-of-trust for translation provenance:
two outputs with the same digest came from the same model
weights, period.
## Limits in v0.1.0
- Single-shot translation. Long-document chunked translation
with overlap-stitching is the v0.2.0 plan.
- No glossary / terminology-list support. Operators currently
rely on the model's general knowledge; a `glossary` input
is on the v0.2.0 roadmap.
## Example flow
```yaml
name: translate-to-german
inputs:
source: text
steps:
- id: translate
use: text.translate@^0
with:
text: $inputs.source
target_language: "German"
endpoint: "http://localhost:11434/api/chat"
model: "qwen2.5:14b"
outputs:
translation: $translate.translation
audit_model: $translate.model_digest
```
## Build
```bash
cargo build --release --target wasm32-wasip2
# Output: target/wasm32-wasip2/release/text_translate.wasm
```

View file

@ -1,6 +1,6 @@
# text-translate # text-translate
Provides the `text.translate` capability for F∆I Platform. Provides the `text.translate` capability for Ch∆In.
## Build ## Build
@ -15,7 +15,7 @@ cargo test # host-side unit + integration tests
fai test . # load the wasm component in the runtime sandbox fai test . # load the wasm component in the runtime sandbox
``` ```
## Authoring with fai-module-sdk ## Authoring with chain-module-sdk
The module body is one decorated function: The module body is one decorated function:
@ -29,12 +29,12 @@ pub fn invoke(_ctx: Context, inputs: Inputs) -> Result<Outputs, ModuleError> {
The macro hides the wit_bindgen call, the Guest impl, the The macro hides the wit_bindgen call, the Guest impl, the
Payload variant matching, and the `wit_bindgen::export!` Payload variant matching, and the `wit_bindgen::export!`
invocation. See `fai-module-sdk` documentation for the full invocation. See `chain-module-sdk` documentation for the full
surface. surface.
## SDK source ## SDK source
The Cargo.toml git-deps `fai-module-sdk` from The Cargo.toml git-deps `chain-module-sdk` from
`https://git.flemming.ws/fai/module-sdk.git`. If your environment requires `https://git.flemming.ws/fai/module-sdk.git`. If your environment requires
authentication for that host (e.g. Forgejo with authentication for that host (e.g. Forgejo with
`REQUIRE_SIGNIN_VIEW=true`), set up `git config insteadOf` with `REQUIRE_SIGNIN_VIEW=true`), set up `git config insteadOf` with

BIN
module.wasm Normal file

Binary file not shown.

View file

@ -1,46 +1,85 @@
schema_version: 1 schema_version: 3
provider: chain
name: text-translate name: text-translate
version: 0.1.0 version: 0.1.0
# Capability provided by this module.
provides: provides:
- capability: text.translate - capability: text.translate
version: 0.1.0 version: 0.1.0
# Inputs the invoke function accepts.
inputs: inputs:
# Source text to translate. text:
text: text type: text
# Target language name in plain English (e.g. "German", description:
# "French", "ja-JP" — anything the configured LLM en: Source text to translate.
# understands). de: Quelltext, der übersetzt werden soll.
target_language: text target_language:
# Optional source language hint. Empty string lets the model type: text
# auto-detect. description:
source_language: text en: |
# Ollama-shaped /api/chat endpoint. Target language name in plain English (e.g. "German",
endpoint: text "French", "ja-JP" — anything the configured LLM
# Model identifier (e.g. "qwen2.5:14b"). understands).
model: text de: |
# Optional bearer token for cloud-hosted endpoints. Zielsprache in Klartext (z. B. "German", "French",
api_key: text "ja-JP" — alles was das konfigurierte LLM versteht).
source_language:
type: text
description:
en: |
Optional source language hint. Empty = let the model
auto-detect.
de: |
Optionaler Hinweis zur Quellsprache. Leer = das Modell
erkennt sie selbst.
endpoint:
type: text
description:
en: Ollama-shaped /api/chat endpoint.
de: Ollama-kompatibler /api/chat-Endpunkt.
model:
type: text
description:
en: Model identifier (e.g. "qwen2.5:14b").
de: Modell-Identifier (z. B. "qwen2.5:14b").
api_key:
type: text
description:
en: Optional bearer token for cloud-hosted endpoints.
de: Optionaler Bearer-Token für Cloud-Endpunkte.
# Outputs produced.
outputs: outputs:
# The translated text. translation:
translation: text type: text
# Echo of the source-language input for downstream audit. description:
source_language: text en: The translated text.
# Echo of the target-language input. de: Der übersetzte Text.
target_language: text source_language:
# Endpoint the translation was generated against. type: text
model_endpoint: text description:
# Model identifier as supplied to the LLM API. en: Echo of the source-language input for downstream audit.
model_name: text de: Echo des source_language-Inputs für Downstream-Audit.
# SHA-256 digest of the served Ollama model (when reachable). target_language:
model_digest: text type: text
description:
en: Echo of the target-language input.
de: Echo des target_language-Inputs.
model_endpoint:
type: text
description:
en: Endpoint the translation was generated against.
de: Endpunkt, gegen den die Übersetzung erzeugt wurde.
model_name:
type: text
description:
en: Model identifier as supplied to the LLM API.
de: An die LLM-API übergebenes Modell.
model_digest:
type: text
description:
en: SHA-256 digest of the served Ollama model (when reachable).
de: SHA-256-Digest des bedienten Ollama-Modells (wenn erreichbar).
# Permissions required.
permissions: permissions:
- "net: localhost" - "net: localhost"
- "net: 127.0.0.1" - "net: 127.0.0.1"

View file

@ -10,7 +10,7 @@
mod llm; mod llm;
use fai_module_sdk::prelude::*; use chain_module_sdk::prelude::*;
const SYSTEM_PROMPT: &str = "You are a faithful translation engine. \ const SYSTEM_PROMPT: &str = "You are a faithful translation engine. \
Translate the user's text into the requested target language. \ Translate the user's text into the requested target language. \