diff --git a/openclaw-inkling-akash/.env.example b/openclaw-inkling-akash/.env.example new file mode 100644 index 0000000..338a34d --- /dev/null +++ b/openclaw-inkling-akash/.env.example @@ -0,0 +1,10 @@ +# Image Docker construite et poussée dans un registre public +OPENCLAW_IMAGE=ghcr.io/USER/openclaw-inkling-akash:latest + +# Clé de l'API Inkling / AI Gateway +INKLING_API_KEY=change-me +INKLING_BASE_URL=https://ai-gateway.vercel.sh/v1 +INKLING_MODEL=thinkingmachines/inkling + +# Token fort utilisé pour protéger la gateway OpenClaw +OPENCLAW_GATEWAY_TOKEN=change-me-with-openssl-rand-hex-32 diff --git a/openclaw-inkling-akash/.gitignore b/openclaw-inkling-akash/.gitignore new file mode 100644 index 0000000..4a88bdd --- /dev/null +++ b/openclaw-inkling-akash/.gitignore @@ -0,0 +1,2 @@ +.env +deploy.yaml diff --git a/openclaw-inkling-akash/Dockerfile b/openclaw-inkling-akash/Dockerfile new file mode 100644 index 0000000..900d23f --- /dev/null +++ b/openclaw-inkling-akash/Dockerfile @@ -0,0 +1,11 @@ +ARG OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw:latest +FROM ${OPENCLAW_IMAGE} + +USER root +COPY entrypoint.sh /usr/local/bin/openclaw-inkling-entrypoint +RUN chmod 0755 /usr/local/bin/openclaw-inkling-entrypoint \ + && mkdir -p /home/node/.openclaw \ + && chown -R node:node /home/node/.openclaw + +USER node +ENTRYPOINT ["/usr/local/bin/openclaw-inkling-entrypoint"] diff --git a/openclaw-inkling-akash/README.md b/openclaw-inkling-akash/README.md new file mode 100644 index 0000000..45e5ea0 --- /dev/null +++ b/openclaw-inkling-akash/README.md @@ -0,0 +1,73 @@ +# OpenClaw + Inkling sur Akash + +Ce dossier fournit une image OpenClaw configurée avec un fournisseur Inkling compatible avec l'API OpenAI, ainsi qu'un modèle SDL Akash. + +## Prérequis + +- Docker +- un registre d'images public, par exemple GHCR +- une clé `INKLING_API_KEY` +- Akash Console ou Akash CLI +- `envsubst` (`gettext-base`) pour générer le SDL + +## 1. Configuration + +```bash +cd openclaw-inkling-akash +cp .env.example .env +openssl rand -hex 32 +``` + +Place le résultat dans `OPENCLAW_GATEWAY_TOKEN`, puis renseigne l'image et la clé API dans `.env`. + +Le réglage par défaut utilise : + +- URL : `https://ai-gateway.vercel.sh/v1` +- modèle : `thinkingmachines/inkling` + +Ces deux valeurs sont surchargeables dans `.env` si ton endpoint Inkling est différent. + +## 2. Construction et publication de l'image + +```bash +set -a +source .env +set +a + +docker build -t "$OPENCLAW_IMAGE" . +docker push "$OPENCLAW_IMAGE" +``` + +## 3. Génération du SDL Akash + +```bash +chmod +x render-deploy.sh +./render-deploy.sh +``` + +Le script produit `deploy.yaml`. Ce fichier contient les secrets injectés : ne le committe pas et supprime-le après le déploiement. + +## 4. Déploiement + +Importe `deploy.yaml` dans Akash Console, ou utilise la CLI Akash selon ton environnement. Le service expose le port `18789` et protège la gateway avec `OPENCLAW_GATEWAY_TOKEN`. + +## Vérification locale + +```bash +docker run --rm -p 18789:18789 \ + --env-file .env \ + "$OPENCLAW_IMAGE" +``` + +Puis vérifie que le conteneur reste actif et consulte ses journaux : + +```bash +docker ps +docker logs +``` + +## Sécurité + +- Ne committe jamais `.env` ni `deploy.yaml`. +- Utilise un token gateway long et aléatoire. +- Limite l'exposition publique ou ajoute un proxy TLS/authentifié devant OpenClaw pour un usage Internet. diff --git a/openclaw-inkling-akash/deploy.yaml.tpl b/openclaw-inkling-akash/deploy.yaml.tpl new file mode 100644 index 0000000..0599271 --- /dev/null +++ b/openclaw-inkling-akash/deploy.yaml.tpl @@ -0,0 +1,51 @@ +--- +version: "2.0" + +services: + openclaw: + image: ${OPENCLAW_IMAGE} + env: + - INKLING_API_KEY=${INKLING_API_KEY} + - INKLING_BASE_URL=${INKLING_BASE_URL} + - INKLING_MODEL=${INKLING_MODEL} + - OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN} + - OPENCLAW_PORT=18789 + - OPENCLAW_STATE_DIR=/home/node/.openclaw + expose: + - port: 18789 + as: 18789 + to: + - global: true + params: + storage: + data: + mount: /home/node/.openclaw + readOnly: false + +profiles: + compute: + openclaw: + resources: + cpu: + units: 1 + memory: + size: 2Gi + storage: + - size: 1Gi + - name: data + size: 5Gi + attributes: + persistent: true + class: beta3 + placement: + dcloud: + pricing: + openclaw: + denom: uakt + amount: 10000 + +deployment: + openclaw: + dcloud: + profile: openclaw + count: 1 diff --git a/openclaw-inkling-akash/entrypoint.sh b/openclaw-inkling-akash/entrypoint.sh new file mode 100644 index 0000000..73d6eba --- /dev/null +++ b/openclaw-inkling-akash/entrypoint.sh @@ -0,0 +1,65 @@ +#!/bin/sh +set -eu + +: "${INKLING_API_KEY:?INKLING_API_KEY est obligatoire}" +: "${OPENCLAW_GATEWAY_TOKEN:?OPENCLAW_GATEWAY_TOKEN est obligatoire}" + +INKLING_BASE_URL="${INKLING_BASE_URL:-https://ai-gateway.vercel.sh/v1}" +INKLING_MODEL="${INKLING_MODEL:-thinkingmachines/inkling}" +OPENCLAW_PORT="${OPENCLAW_PORT:-18789}" +OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-/home/node/.openclaw}" +OPENCLAW_CONFIG_PATH="${OPENCLAW_CONFIG_PATH:-${OPENCLAW_STATE_DIR}/openclaw.json}" + +export INKLING_API_KEY OPENCLAW_GATEWAY_TOKEN INKLING_BASE_URL INKLING_MODEL +export OPENCLAW_PORT OPENCLAW_STATE_DIR OPENCLAW_CONFIG_PATH + +mkdir -p "${OPENCLAW_STATE_DIR}" + +node <<'NODE' +const fs = require('fs'); +const path = require('path'); + +const model = process.env.INKLING_MODEL; +const configPath = process.env.OPENCLAW_CONFIG_PATH; +const config = { + models: { + mode: 'merge', + providers: { + inkling: { + baseUrl: process.env.INKLING_BASE_URL, + apiKey: process.env.INKLING_API_KEY, + api: 'openai-completions', + models: [{ + id: model, + name: 'Inkling', + reasoning: true, + input: ['text', 'image'], + contextWindow: 262144, + maxTokens: 32768 + }] + } + } + }, + agents: { + defaults: { + model: { primary: `inkling/${model}` }, + models: { [`inkling/${model}`]: { alias: 'Inkling' } } + } + }, + gateway: { + bind: 'lan', + port: Number(process.env.OPENCLAW_PORT), + auth: { + mode: 'token', + token: process.env.OPENCLAW_GATEWAY_TOKEN + } + } +}; + +fs.mkdirSync(path.dirname(configPath), { recursive: true }); +fs.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 0o600 }); +NODE + +echo "Démarrage OpenClaw sur 0.0.0.0:${OPENCLAW_PORT}" +echo "Modèle: inkling/${INKLING_MODEL}" +exec openclaw gateway --port "${OPENCLAW_PORT}" diff --git a/openclaw-inkling-akash/render-deploy.sh b/openclaw-inkling-akash/render-deploy.sh new file mode 100644 index 0000000..968cd4d --- /dev/null +++ b/openclaw-inkling-akash/render-deploy.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +ENV_FILE="${1:-${SCRIPT_DIR}/.env}" +OUTPUT_FILE="${2:-${SCRIPT_DIR}/deploy.yaml}" + +if [[ ! -f "${ENV_FILE}" ]]; then + echo "Fichier absent: ${ENV_FILE}" >&2 + echo "Copie .env.example vers .env puis renseigne les secrets." >&2 + exit 1 +fi + +set -a +# shellcheck disable=SC1090 +source "${ENV_FILE}" +set +a + +required=(OPENCLAW_IMAGE INKLING_API_KEY INKLING_BASE_URL INKLING_MODEL OPENCLAW_GATEWAY_TOKEN) +for name in "${required[@]}"; do + if [[ -z "${!name:-}" ]]; then + echo "Variable obligatoire absente: ${name}" >&2 + exit 1 + fi +done + +if ! command -v envsubst >/dev/null 2>&1; then + echo "envsubst est requis (paquet gettext-base)." >&2 + exit 1 +fi + +envsubst < "${SCRIPT_DIR}/deploy.yaml.tpl" > "${OUTPUT_FILE}" +chmod 600 "${OUTPUT_FILE}" +echo "SDL généré: ${OUTPUT_FILE}"