From 2764f0ccd804076418c0fed5b70e497c1eb70e5e Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 11:42:28 +0100 Subject: [PATCH 1/8] docs: comprehensive GenVM configuration guide Rewrites the GenVM configuration page with: - Full explanation of YAML + Lua config system - All 4 provider types (ollama, openai-compatible, anthropic, google) - Step-by-step Ollama local setup example - OpenRouter aggregator example - Complete Lua scripting API reference (15 core + LLM + web functions) - Provider selection strategies (default, greybox, custom) - Equivalence Principle prompt template docs - Web module configuration (URL restrictions, webdriver) - Hot-reload and troubleshooting --- pages/validators/genvm-configuration.mdx | 473 +++++++++++++++++------ 1 file changed, 354 insertions(+), 119 deletions(-) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index ab810809..648e8562 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -2,182 +2,261 @@ import { Callout } from "nextra-theme-docs"; # GenVM Configuration -You need to set up an LLM for your node to use to provide answers to natural language prompts. You can use any LLM you wish, however the quality of its answers will affect the performance of your node. +GenVM uses a layered configuration system: **YAML files** define providers, models, and module settings, while **Lua scripts** implement execution logic (provider selection, fallback strategies, text processing). You can customize both without rebuilding GenVM. + +Configuration files live at `third_party/genvm/config/`. + +## LLM Provider Credits GenLayer has partnered with multiple LLM providers to offer free credits for validators: - **[Heurist](https://www.heurist.ai/)** - A Layer 2 network for AI model hosting and inference, built on the ZK Stack. It offers serverless access to open-source AI models through a decentralized network. GenLayer Validators can obtain free [Heurist API credits](https://dev-api-form.heurist.ai) by using the referral code: _"genlayer"_. + **[Heurist](https://www.heurist.ai/)** - A Layer 2 network for AI model hosting and inference. GenLayer Validators can obtain free [Heurist API credits](https://dev-api-form.heurist.ai) by using the referral code: _"genlayer"_. - **[Comput3](https://genlayer.comput3.ai/)** - A decentralized compute network providing access to various AI models. GenLayer Validators can use the Comput3.ai inferencing API with access to llama3, hermes3 and qwen3 models. Validators can obtain free [Comput3 API credits](https://genlayer.comput3.ai/) to get started with their validator setup. + **[Comput3](https://genlayer.comput3.ai/)** - A decentralized compute network providing access to various AI models. Validators can obtain free [Comput3 API credits](https://genlayer.comput3.ai/). - **[io.net](/partners/ionet)** - A decentralized compute network providing GPU access for AI inference. GenLayer Validators can create an account at [id.io.net](https://id.io.net/login) and obtain free credits by [filling out this form](https://form.typeform.com/to/pDmCCViV). + **[io.net](/partners/ionet)** - A decentralized compute network providing GPU access for AI inference. Create an account at [id.io.net](https://id.io.net/login) and obtain free credits by [filling out this form](https://form.typeform.com/to/pDmCCViV). - **[Chutes](/partners/chutes)** - Serverless inference for open-source AI models running on decentralized GPU infrastructure. GenLayer Validators can create an account at [chutes.ai](https://chutes.ai) and generate an API key from their account settings. + **[Chutes](/partners/chutes)** - Serverless inference for open-source AI models on decentralized GPU infrastructure. Create an account at [chutes.ai](https://chutes.ai) and generate an API key from your account settings. - **[Morpheus](/partners/morpheus)** - A decentralized AI inference network where open-source model providers compete on a peer-to-peer marketplace. GenLayer Validators can obtain a [Morpheus API key](https://mor.org/) to access models like DeepSeek, Llama, Qwen, and others through an OpenAI-compatible API. + **[Morpheus](/partners/morpheus)** - A decentralized AI inference network. Obtain a [Morpheus API key](https://mor.org/) to access models like DeepSeek, Llama, Qwen, and others through an OpenAI-compatible API. -The GenVM configuration files are located at `third_party/genvm/config/` +## Configuration Files -## genvm-module-llm.yaml +### genvm-module-llm.yaml — LLM Providers & Models -This is the configuration file of the LLM module. In this file you can set up and configure various LLM providers, as well as the system prompts of your validator. +Controls which LLM backends are available, what models each offers, and which Lua script runs the execution logic. -You should not need to modify this in general. +```yaml +# Which Lua script handles provider selection and execution +lua_script_path: ${exeDir}/../config/genvm-llm-default.lua + +# Lua library path +lua_path: ${exeDir}/../lib/genvm-lua/?.lua + +# Module binding and performance +bind_address: 127.0.0.1:3031 +vm_count: 6 # Number of Lua VMs in the pool +threads: 4 # Async runtime threads +blocking_threads: 16 # Blocking task threads + +# LLM backends — add as many as you need +backends: + my-provider: + enabled: true # Set false to disable without removing + host: https://api.example.com # API endpoint + provider: openai-compatible # Provider type (see below) + key: ${ENV[MY_API_KEY]} # API key via environment variable + models: + model-name: + enabled: true + supports_json: true # Can return structured JSON + supports_image: false # Can process image inputs + use_max_completion_tokens: false # Use max_completion_tokens instead of max_tokens + meta: {} # Custom metadata (used by greybox, etc.) + +# Equivalence Principle prompt templates +prompt_templates: + eq_comparative: + system: "..." + user: "..." + eq_non_comparative_leader: + system: "..." + user: "..." + eq_non_comparative_validator: + system: "..." + user: "..." +``` -However, from here you can: -- turn on and off various LLMs by setting the `enabled` field to `false`: By default they all come enabled for you to use. You will get warnings in the logs for each one that's enabled and not configured. Disabling non used LLM providers will hide those warnings +### genvm-module-web.yaml — Web Access -Note environment variable names for LLM API keys (e.g., `HEURISTKEY`, `COMPUT3KEY`, `IOINTELLIGENCE_API_KEY`, `CHUTES_API_KEY`, `MORPHEUS_API_KEY`). You will need to ensure the appropriate key is correctly set before [running the node](/validators/setup-guide#running-the-node). +Controls how contracts access the internet — webdriver for page rendering, URL restrictions. -## genvm-module-web.yaml +```yaml +bind_address: 127.0.0.1:3032 +lua_script_path: ${exeDir}/../config/genvm-web-default.lua -This is the configuration of webdriver module that enables the GenVM to access the internet. You should not need to modify this. +# Selenium webdriver endpoint for rendering pages +webdriver_host: http://127.0.0.1:4444 -## genvm-manager.yaml +# Browser session configuration (Firefox headless) +session_create_request: '{"capabilities":{"alwaysMatch":{"moz:firefoxOptions":{"args":["-headless"]}}}}' -This is the configuration of the GenVM manager. You should not need to modify this. However, if you are running the node on -macos (natively), you may want to set `permits` to some large value, as auto-detection is not supported there yet, such as `32`. +# URL access control +extra_tld: [] # Additional TLDs to allow beyond defaults +always_allow_hosts: [] # Hosts that bypass all URL restrictions +``` -## Greyboxing LLMs +### genvm-manager.yaml — Execution Manager -Switch your GenLayer node from random LLM provider selection to deterministic ordered fallback via OpenRouter. +Controls the GenVM manager process that coordinates LLM and web modules. -## What is Greybox? +```yaml +permits: 8 # Max concurrent GenVM executions (set higher on powerful machines) +``` -By default, the node picks a random LLM provider for each call. With **greybox**, the node uses a fixed priority chain configured via `meta.greybox` fields in the YAML config. + + On macOS (native), auto-detection of permits is not supported. Set `permits` to a value like `32` manually. + -**Default text chain:** deepseek-v3.2 → qwen3-235b → claude-haiku-4.5 → kimi-k2 → glm-5 → llama-3.3 (heurist) → llama-3.3 (ionet) +## Supported Provider Types -**Default image chain:** gpt-5.1-mini → gemini-3-flash → claude-haiku-4.5 +GenVM has built-in support for four provider types, each handling API communication differently: -Chain order is determined by the `meta.greybox` priority numbers on each model in the YAML. Lower number = higher priority. You can change the order by editing these numbers — no Lua changes needed. +| Type | Description | Example Services | +|---|---|---| +| `openai-compatible` | OpenAI-compatible chat/completions API | OpenAI, OpenRouter, Heurist, X.ai, Comput3, Chutes, Morpheus | +| `ollama` | Ollama's native `/api/generate` endpoint | Local Ollama instance | +| `anthropic` | Anthropic's Messages API | Claude models | +| `google` | Google's Generative Language API | Gemini models | -OpenRouter is the primary aggregator. If it fails, the node falls back to direct provider APIs (heurist, ionet). +## Setting Up LLM Providers -## Prerequisites +### Example: Local Ollama -- GenLayer node **v0.5.7+** (tarball must include `genvm-modules-llm-release.yaml` and `genvm-llm-greybox.lua`) -- An **OpenRouter API key** — get one at https://openrouter.ai/keys +Run your own LLM locally and point GenVM to it: -## Step-by-Step Setup +**1. Install Ollama and pull a model:** +```bash +# Install Ollama (https://ollama.com) +curl -fsSL https://ollama.com/install.sh | sh -### 1. Stop the node +# Pull a model +ollama pull llama3.3 +``` -```bash -sudo systemctl stop genlayer-node +**2. Add a backend entry** to `genvm-module-llm.yaml`: +```yaml +backends: + # ... existing backends ... + + my-ollama: + host: http://localhost:11434 + provider: ollama + models: + llama3.3: + supports_json: true + supports_image: false ``` -### 2. Add OpenRouter API key to .env +No API key needed — Ollama runs locally. +**3. Restart the LLM module** (see [Updating Configuration](#updating-configuration) below). + +**4. Verify** in the logs: ```bash -# Find your active .env -ENV_FILE="/opt/genlayer-node/.env" +sudo journalctl -u genlayer-node --no-hostname | grep "my-ollama" +``` + +### Example: OpenRouter (Aggregator) + +OpenRouter provides access to many models through a single API key: -# Add the key (or edit the file manually) -echo "OPENROUTERKEY=sk-or-v1-your-key-here" >> ${ENV_FILE} +```yaml +backends: + openrouter: + host: https://openrouter.ai/api + provider: openai-compatible + key: ${ENV[OPENROUTERKEY]} + models: + deepseek/deepseek-v3.2: + supports_json: true + anthropic/claude-haiku-4.5: + supports_json: true + supports_image: true + openai/gpt-5.1-mini: + supports_json: true + supports_image: true ``` -### 3. Apply the release LLM config +### Environment Variables for API Keys -The tarball ships with a unified config that includes all backends (openrouter, morpheus, heurist, ionet, etc.). +Set these in your `.env` file or environment before starting the node: -```bash -VERSION=$(readlink /opt/genlayer-node/bin | sed 's|/bin||; s|.*/||') +| Variable | Provider | +|---|---| +| `OPENROUTERKEY` | OpenRouter | +| `OPENAIKEY` | OpenAI | +| `ANTHROPICKEY` | Anthropic | +| `GEMINIKEY` | Google Gemini | +| `HEURISTKEY` | Heurist | +| `XAIKEY` | X.ai (Grok) | +| `COMPUT3KEY` | Comput3 | +| `IOINTELLIGENCE_API_KEY` | io.net | +| `CHUTES_API_KEY` | Chutes | +| `MORPHEUS_API_KEY` | Morpheus | +| `ATOMAKEY` | Atoma | -cp /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-modules-llm-release.yaml \ - /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml -``` +Keys use the `${ENV[VARIABLE_NAME]}` syntax in the YAML config. -### 4. Switch to greybox strategy + + Enabled backends without a configured API key will show warnings in the logs. Either set the key or disable the backend with `enabled: false`. + -```bash -sed -i 's/genvm-llm-default\.lua/genvm-llm-greybox.lua/' \ - /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml -``` +## Provider Selection Strategies -### 5. Verify the config +The Lua script referenced by `lua_script_path` controls how GenVM selects which provider to use for each LLM call. -```bash -# Check lua script path -grep lua_script_path /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml -# Expected: lua_script_path: ${exeDir}/../config/genvm-llm-greybox.lua +### Default (Random Selection) -# Check openrouter is present -grep -A2 'openrouter:' /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml -# Expected: enabled: true +The default script (`genvm-llm-default.lua`) iterates through all enabled providers that match the required capabilities (JSON support, image support) and tries them in arbitrary order. If a provider returns an overload error (429, 503, 408, 504, 529), it falls back to the next one. -# Check the greybox Lua file exists -ls -la /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-llm-greybox.lua -``` +### Greybox (Ordered Fallback via OpenRouter) -### 6. Start the node +Switch from random selection to a deterministic priority chain. Models are tried in order based on `meta.greybox` priority numbers in the YAML config. -```bash -sudo systemctl start genlayer-node -``` +**Default text chain:** deepseek-v3.2 → qwen3-235b → claude-haiku-4.5 → kimi-k2 → glm-5 → llama-3.3 (heurist) → llama-3.3 (ionet) -### 7. Verify greybox is active +**Default image chain:** gpt-5.1-mini → gemini-3-flash → claude-haiku-4.5 -Wait for an LLM transaction to be processed, then check the logs: +#### Setup +**1. Stop the node:** ```bash -sudo journalctl -u genlayer-node --no-hostname | grep "greybox" +sudo systemctl stop genlayer-node ``` -You should see entries like: -``` -greybox: using text chain count: 5 -greybox: success provider: openrouter model: deepseek/deepseek-v3.2 is_primary: true +**2. Add OpenRouter API key:** +```bash +echo "OPENROUTERKEY=sk-or-v1-your-key-here" >> /opt/genlayer-node/.env ``` -## Switching Back to Default +**3. Apply the release LLM config:** +```bash +VERSION=$(readlink /opt/genlayer-node/bin | sed 's|/bin||; s|.*/||') -To revert to random provider selection: +cp /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-modules-llm-release.yaml \ + /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml +``` +**4. Switch to greybox strategy:** ```bash -sudo systemctl stop genlayer-node - -sed -i 's/genvm-llm-greybox\.lua/genvm-llm-default.lua/' \ +sed -i 's/genvm-llm-default\.lua/genvm-llm-greybox.lua/' \ /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml +``` +**5. Start the node:** +```bash sudo systemctl start genlayer-node ``` -## Updating Greybox on a Running Node (No Full Restart) - -If you need to update the Lua script or model config without stopping the whole node, -you can restart just the LLM module on each GenVM instance: - +**6. Verify:** ```bash -# Find the GenVM manager port (check your config or active ports) -PORT=3999 - -# Stop the LLM module -curl -X POST "http://127.0.0.1:${PORT}/module/stop" \ - -H 'Content-Type: application/json' \ - -d '{"module_type": "Llm"}' - -# Start the LLM module (reloads Lua script and config) -curl -X POST "http://127.0.0.1:${PORT}/module/start" \ - -H 'Content-Type: application/json' \ - -d '{"module_type": "Llm", "config": null}' +sudo journalctl -u genlayer-node --no-hostname | grep "greybox" +# Expected: greybox: success provider: openrouter model: deepseek/deepseek-v3.2 ``` -Repeat for each GenVM instance port. There is no atomic restart — each instance -restarts independently. +#### Customizing Chain Order -## Customizing the Chain Order - -The greybox Lua script reads chain membership and priority from `meta.greybox` on each model in the YAML config. Example: +Priority is controlled by `meta.greybox` on each model: ```yaml models: deepseek/deepseek-v3.2: supports_json: true meta: - greybox: { text: 1 } # text chain, priority 1 (primary) + greybox: { text: 1 } # text chain, priority 1 (tried first) openai/gpt-5.1-mini: supports_json: true supports_image: true @@ -187,33 +266,189 @@ models: supports_json: true supports_image: true meta: - greybox: { text: 3, image: 3 } # both chains + greybox: { text: 3, image: 3 } # both chains, priority 3 +``` + +Lower number = tried first. Remove `meta.greybox` to exclude a model from the chain. + +#### Reverting to Default + +```bash +sudo systemctl stop genlayer-node +sed -i 's/genvm-llm-greybox\.lua/genvm-llm-default.lua/' \ + /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml +sudo systemctl start genlayer-node +``` + +### Writing a Custom Strategy + +You can write your own Lua script for provider selection. Create a new `.lua` file in the config directory and point `lua_script_path` to it. + +Your script must export two global functions: + +```lua +-- Called for direct prompts (gl.nondet.exec_prompt) +function ExecPrompt(ctx, args, remaining_gen) + -- args.prompt: string + -- args.response_format: "text" | "json" + -- args.images: table of image bytes (optional) + -- remaining_gen: number (remaining gas) + -- + -- Must return: {data: string, consumed_gen: number, input_tokens: number, output_tokens: number} +end + +-- Called for template prompts (Equivalence Principle) +function ExecPromptTemplate(ctx, args, remaining_gen) + -- args.template: "EqComparative" | "EqNonComparativeValidator" | "EqNonComparativeLeader" + -- args.vars: table of template variable substitutions + -- + -- Must return: same as ExecPrompt +end +``` + +Use the helper libraries: +```lua +local lib = require("lib-genvm") -- logging, error handling, utilities +local llm = require("lib-llm") -- provider selection, prompt transforms + +-- Select providers matching required capabilities +local providers = llm.select_providers_for(prompt, format) + +-- Execute on a specific provider +local result = llm.rs.exec_prompt_in_provider(ctx, { + provider = "my-provider", + model = "model-name", + prompt = mapped_prompt, + format = "text", -- or "json" or "bool" +}) ``` -**Change model order:** Edit the priority numbers. Lower number = tried first. +## Lua Scripting API + +### Core Functions (`lib.rs` / `__dflt`) + +Available in all Lua scripts: + +| Function | Description | +|---|---| +| `lib.rs.request(ctx, {method, url, headers, body, json, sign})` | Make HTTP request. `json: true` returns parsed response. | +| `lib.rs.json_parse(str)` | Parse JSON string to table | +| `lib.rs.json_stringify(value)` | Serialize table to JSON string | +| `lib.rs.base64_encode(data)` | Base64 encode | +| `lib.rs.base64_decode(data)` | Base64 decode | +| `lib.rs.filter_text(text, filters)` | Apply text filters: `"NFC"`, `"NFKC"`, `"NormalizeWS"`, `"RmZeroWidth"` | +| `lib.rs.filter_image(bytes, filters)` | Apply image filters: `{Denoise=0.5}`, `{JPEG=0.9}`, `{GuassianNoise=0.1}` | +| `lib.rs.split_url(url)` | Parse URL → `{schema, host, port}` | +| `lib.rs.url_encode(text)` | URL-encode text | +| `lib.rs.sleep_seconds(n)` | Async sleep | +| `lib.rs.random_bytes(n)` | Generate n random bytes | +| `lib.rs.random_float()` | Random float in [0, 1) | +| `lib.rs.user_error({causes, fatal, ctx})` | Raise a user error | +| `lib.rs.as_user_error(err)` | Try to convert error to user error (returns nil if not) | +| `lib.log({level, message, ...})` | Structured logging (levels: trace, debug, info, warn, error) | + +### LLM Functions (`llm.rs` / `__llm`) + +Available in LLM module scripts: + +| Function | Description | +|---|---| +| `llm.rs.exec_prompt_in_provider(ctx, request)` | Execute prompt on a specific provider/model | +| `llm.providers` | Table of all configured providers and their models | +| `llm.templates` | Equivalence Principle prompt templates | +| `llm.select_providers_for(prompt, format)` | Filter providers by capability (JSON, images) | +| `llm.exec_prompt_transform(args)` | Transform raw prompt args to internal format | +| `llm.exec_prompt_template_transform(args)` | Transform template args with variable substitution | +| `llm.overloaded_statuses` | Set of HTTP status codes indicating overload: `{408, 429, 503, 504, 529}` | + +### Web Functions (`web.rs` / `__web`) + +Available in web module scripts: + +| Function | Description | +|---|---| +| `web.config` | Web module configuration (webdriver_host, etc.) | +| `web.allowed_tld` | Set of allowed top-level domains | +| `web.check_url(url)` | Validate URL against schema, port, and TLD restrictions | + +## Prompt Templates + +The Equivalence Principle uses three prompt templates, configured in `genvm-module-llm.yaml` under `prompt_templates`: + +| Template | Used By | Input Variables | Returns | +|---|---|---|---| +| `eq_comparative` | Comparative validation | `#{task}`, `#{criteria}`, `#{output1}`, `#{output2}` | Boolean (are outputs equivalent?) | +| `eq_non_comparative_leader` | Leader execution | `#{task}`, `#{criteria}` | Text result | +| `eq_non_comparative_validator` | Validator checking | `#{task}`, `#{criteria}`, `#{output}` | Boolean + reason | + +Templates use `#{variable_name}` syntax for substitution. You can customize the system and user prompts to change how validators evaluate results. + +## Web Module Configuration + +The web module enables contracts to fetch web pages, make HTTP requests, and capture screenshots. -**Add a model to the chain:** Add `meta: { greybox: { text: N } }` to any model in any enabled backend. +### URL Restrictions -**Remove a model from the chain:** Remove its `meta.greybox` field. +By default, contracts can only access URLs with standard TLDs (com, org, net, etc.) on ports 80 and 443. Customize with: -**Disable an entire provider:** Remove its API key from `.env` — all its models drop out automatically. +- `extra_tld: ["local", "internal"]` — allow additional TLDs +- `always_allow_hosts: ["my-api.internal"]` — bypass all URL checks for specific hosts -The YAML config **must** have `meta.greybox` fields on at least some models. If none are found, the LLM module will fail to start with an error. +### Webdriver -After editing the YAML, restart the LLM module (see "Updating Greybox on a Running Node" above) or restart the node. +The webdriver (Selenium with headless Firefox) handles page rendering and screenshots. The web module scripts implement two functions: + +- `Render(ctx, payload)` — render a page as text, HTML, or screenshot +- `Request(ctx, payload)` — make HTTP requests (GET, POST, etc.) + +## Updating Configuration + +### Hot-Reload (No Full Restart) + +Restart individual modules without stopping the node: + +```bash +PORT=3999 # GenVM manager port + +# Restart LLM module (reloads Lua script + YAML config) +curl -X POST "http://127.0.0.1:${PORT}/module/stop" \ + -H 'Content-Type: application/json' \ + -d '{"module_type": "Llm"}' + +curl -X POST "http://127.0.0.1:${PORT}/module/start" \ + -H 'Content-Type: application/json' \ + -d '{"module_type": "Llm", "config": null}' + +# Restart Web module +curl -X POST "http://127.0.0.1:${PORT}/module/stop" \ + -H 'Content-Type: application/json' \ + -d '{"module_type": "Web"}' + +curl -X POST "http://127.0.0.1:${PORT}/module/start" \ + -H 'Content-Type: application/json' \ + -d '{"module_type": "Web", "config": null}' +``` + +### Full Restart + +```bash +sudo systemctl stop genlayer-node +# ... edit config files ... +sudo systemctl start genlayer-node +``` ## Troubleshooting +**Warnings for unconfigured providers:** +Enabled backends without API keys log warnings. Either set the key in `.env` or disable the backend with `enabled: false`. + **"module_failed_to_start" error:** -- Check that `genvm-llm-greybox.lua` exists in the config directory -- Check that `OPENROUTERKEY` is set in `.env` and not empty -- Check that the openrouter backend shows `enabled: true` in the YAML - -**No "greybox:" entries in logs:** -- The greybox Lua only logs when an LLM call happens. Run a transaction that uses an intelligent contract with LLM calls. -- Verify `lua_script_path` points to `genvm-llm-greybox.lua` (not `default`) - -**All models exhausted error:** -- OpenRouter may be down or your key is invalid -- Check your key at https://openrouter.ai/settings/keys -- Fallback providers (heurist, ionet) also need valid keys if you want fallback to work +- Check that the Lua script file exists at the path in `lua_script_path` +- Check that required API keys are set in `.env` +- Check YAML syntax (indentation, colons) + +**"NO_PROVIDER_FOR_PROMPT" error:** +No enabled provider matches the required capabilities. Ensure at least one backend has `supports_json: true` (and `supports_image: true` if the contract sends images). + +**All models exhausted / overload errors:** +All providers returned overload status codes (429, 503, etc.). Check API key validity, provider status pages, and consider adding more backends as fallback. From fd04ddad01023f0fd32928b027d1678467ead90a Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 11:46:55 +0100 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20add=20motivation=20to=20GenVM=20conf?= =?UTF-8?q?ig=20intro=20=E2=80=94=20costs,=20performance,=20rewards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/validators/genvm-configuration.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index 648e8562..7f91ffca 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -2,6 +2,10 @@ import { Callout } from "nextra-theme-docs"; # GenVM Configuration +Your validator's GenVM needs two things to function: **LLM providers** to process AI-powered contract logic, and a **web module** to fetch live internet data. This page covers how to configure both. + +**Why this matters:** The LLM providers you choose directly affect your validator's operating costs and performance. Faster, cheaper models reduce your costs per transaction. Higher-quality models improve your consensus accuracy, which affects your rewards and avoids slashing. By tuning your provider setup — choosing the right models, configuring fallback chains, or running local inference — you can optimize the economics of running your validator. + GenVM uses a layered configuration system: **YAML files** define providers, models, and module settings, while **Lua scripts** implement execution logic (provider selection, fallback strategies, text processing). You can customize both without rebuilding GenVM. Configuration files live at `third_party/genvm/config/`. From cef67675dc7d06233fd0bd5dd504ae1330638207 Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 12:02:20 +0100 Subject: [PATCH 3/8] fix: restructure around greyboxing as umbrella concept, hot-reload up top, cost management note --- pages/validators/genvm-configuration.mdx | 466 +++++++++-------------- 1 file changed, 183 insertions(+), 283 deletions(-) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index 7f91ffca..794908f4 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -4,137 +4,74 @@ import { Callout } from "nextra-theme-docs"; Your validator's GenVM needs two things to function: **LLM providers** to process AI-powered contract logic, and a **web module** to fetch live internet data. This page covers how to configure both. -**Why this matters:** The LLM providers you choose directly affect your validator's operating costs and performance. Faster, cheaper models reduce your costs per transaction. Higher-quality models improve your consensus accuracy, which affects your rewards and avoids slashing. By tuning your provider setup — choosing the right models, configuring fallback chains, or running local inference — you can optimize the economics of running your validator. +**Why this matters:** The LLM providers you choose directly affect your validator's operating costs and performance. Faster, cheaper models reduce your costs per transaction. Higher-quality models improve your consensus accuracy, which affects your rewards and avoids slashing. By tuning your provider setup — choosing the right models, configuring fallback chains, running local inference, or applying input filters — you can optimize the economics of running your validator. -GenVM uses a layered configuration system: **YAML files** define providers, models, and module settings, while **Lua scripts** implement execution logic (provider selection, fallback strategies, text processing). You can customize both without rebuilding GenVM. +## Hot-Reload -Configuration files live at `third_party/genvm/config/`. +You can modify configuration files on the fly and reload without stopping your node. This is important when experimenting with providers or tuning your setup. -## LLM Provider Credits - - - GenLayer has partnered with multiple LLM providers to offer free credits for validators: - - **[Heurist](https://www.heurist.ai/)** - A Layer 2 network for AI model hosting and inference. GenLayer Validators can obtain free [Heurist API credits](https://dev-api-form.heurist.ai) by using the referral code: _"genlayer"_. - - **[Comput3](https://genlayer.comput3.ai/)** - A decentralized compute network providing access to various AI models. Validators can obtain free [Comput3 API credits](https://genlayer.comput3.ai/). +```bash +PORT=3999 # GenVM manager port - **[io.net](/partners/ionet)** - A decentralized compute network providing GPU access for AI inference. Create an account at [id.io.net](https://id.io.net/login) and obtain free credits by [filling out this form](https://form.typeform.com/to/pDmCCViV). +# Restart LLM module (reloads Lua script + YAML config) +curl -X POST "http://127.0.0.1:${PORT}/module/stop" \ + -H 'Content-Type: application/json' \ + -d '{"module_type": "Llm"}' - **[Chutes](/partners/chutes)** - Serverless inference for open-source AI models on decentralized GPU infrastructure. Create an account at [chutes.ai](https://chutes.ai) and generate an API key from your account settings. +curl -X POST "http://127.0.0.1:${PORT}/module/start" \ + -H 'Content-Type: application/json' \ + -d '{"module_type": "Web", "config": null}' +``` - **[Morpheus](/partners/morpheus)** - A decentralized AI inference network. Obtain a [Morpheus API key](https://mor.org/) to access models like DeepSeek, Llama, Qwen, and others through an OpenAI-compatible API. - +Repeat for each GenVM instance if running multiple. For a full restart: `sudo systemctl restart genlayer-node`. ## Configuration Files -### genvm-module-llm.yaml — LLM Providers & Models +All configuration lives at `third_party/genvm/config/`. Three files: -Controls which LLM backends are available, what models each offers, and which Lua script runs the execution logic. +| File | What it controls | Should you modify? | +|---|---|---| +| `genvm-module-llm.yaml` | LLM providers, models, prompt templates, Lua script selection | **Yes** — this is your main configuration file | +| `genvm-module-web.yaml` | Web access, webdriver, URL restrictions | Rarely — only for advanced URL policy changes | +| `genvm-manager.yaml` | Concurrency permits, VM pool | Rarely — only if tuning for your hardware | -```yaml -# Which Lua script handles provider selection and execution -lua_script_path: ${exeDir}/../config/genvm-llm-default.lua +## Configuring Your LLM Backends -# Lua library path -lua_path: ${exeDir}/../lib/genvm-lua/?.lua +The `backends` section in `genvm-module-llm.yaml` defines which LLMs your validator can use. The Lua script (configured via `lua_script_path`) then selects from these backends at runtime. -# Module binding and performance -bind_address: 127.0.0.1:3031 -vm_count: 6 # Number of Lua VMs in the pool -threads: 4 # Async runtime threads -blocking_threads: 16 # Blocking task threads +### Backend entry format -# LLM backends — add as many as you need +```yaml backends: - my-provider: - enabled: true # Set false to disable without removing - host: https://api.example.com # API endpoint - provider: openai-compatible # Provider type (see below) - key: ${ENV[MY_API_KEY]} # API key via environment variable + my-provider: # Your name for this backend + enabled: true # Set false to disable without removing + host: https://api.example.com + provider: openai-compatible # Provider type (see table below) + key: ${ENV[MY_API_KEY]} # API key via environment variable models: model-name: enabled: true - supports_json: true # Can return structured JSON - supports_image: false # Can process image inputs - use_max_completion_tokens: false # Use max_completion_tokens instead of max_tokens - meta: {} # Custom metadata (used by greybox, etc.) - -# Equivalence Principle prompt templates -prompt_templates: - eq_comparative: - system: "..." - user: "..." - eq_non_comparative_leader: - system: "..." - user: "..." - eq_non_comparative_validator: - system: "..." - user: "..." + supports_json: true # Can return structured JSON output + supports_image: false # Can process image inputs + use_max_completion_tokens: false + meta: {} # Custom metadata (used by greyboxing strategies) ``` -### genvm-module-web.yaml — Web Access +### Supported provider types -Controls how contracts access the internet — webdriver for page rendering, URL restrictions. - -```yaml -bind_address: 127.0.0.1:3032 -lua_script_path: ${exeDir}/../config/genvm-web-default.lua - -# Selenium webdriver endpoint for rendering pages -webdriver_host: http://127.0.0.1:4444 - -# Browser session configuration (Firefox headless) -session_create_request: '{"capabilities":{"alwaysMatch":{"moz:firefoxOptions":{"args":["-headless"]}}}}' - -# URL access control -extra_tld: [] # Additional TLDs to allow beyond defaults -always_allow_hosts: [] # Hosts that bypass all URL restrictions -``` - -### genvm-manager.yaml — Execution Manager - -Controls the GenVM manager process that coordinates LLM and web modules. - -```yaml -permits: 8 # Max concurrent GenVM executions (set higher on powerful machines) -``` - - - On macOS (native), auto-detection of permits is not supported. Set `permits` to a value like `32` manually. - - -## Supported Provider Types - -GenVM has built-in support for four provider types, each handling API communication differently: - -| Type | Description | Example Services | +| Type | Description | Example services | |---|---|---| -| `openai-compatible` | OpenAI-compatible chat/completions API | OpenAI, OpenRouter, Heurist, X.ai, Comput3, Chutes, Morpheus | +| `openai-compatible` | OpenAI-compatible chat/completions API | OpenAI, OpenRouter, Heurist, Comput3, Chutes, Morpheus, X.ai | | `ollama` | Ollama's native `/api/generate` endpoint | Local Ollama instance | | `anthropic` | Anthropic's Messages API | Claude models | | `google` | Google's Generative Language API | Gemini models | -## Setting Up LLM Providers - -### Example: Local Ollama +### Example: Adding a local Ollama instance -Run your own LLM locally and point GenVM to it: +Add this to the `backends` section. No API key needed — Ollama runs locally. Follow [Ollama's install guide](https://ollama.com) to set up the server and pull a model. -**1. Install Ollama and pull a model:** -```bash -# Install Ollama (https://ollama.com) -curl -fsSL https://ollama.com/install.sh | sh - -# Pull a model -ollama pull llama3.3 -``` - -**2. Add a backend entry** to `genvm-module-llm.yaml`: ```yaml backends: - # ... existing backends ... - my-ollama: host: http://localhost:11434 provider: ollama @@ -144,18 +81,9 @@ backends: supports_image: false ``` -No API key needed — Ollama runs locally. - -**3. Restart the LLM module** (see [Updating Configuration](#updating-configuration) below). - -**4. Verify** in the logs: -```bash -sudo journalctl -u genlayer-node --no-hostname | grep "my-ollama" -``` - -### Example: OpenRouter (Aggregator) +### Example: Adding OpenRouter -OpenRouter provides access to many models through a single API key: +[OpenRouter](https://openrouter.ai) provides access to many models through a single API key: ```yaml backends: @@ -174,9 +102,9 @@ backends: supports_image: true ``` -### Environment Variables for API Keys +### API key environment variables -Set these in your `.env` file or environment before starting the node: +Set these in your `.env` file before starting the node. Keys use `${ENV[VARIABLE_NAME]}` syntax in the YAML. | Variable | Provider | |---|---| @@ -190,269 +118,241 @@ Set these in your `.env` file or environment before starting the node: | `IOINTELLIGENCE_API_KEY` | io.net | | `CHUTES_API_KEY` | Chutes | | `MORPHEUS_API_KEY` | Morpheus | -| `ATOMAKEY` | Atoma | - -Keys use the `${ENV[VARIABLE_NAME]}` syntax in the YAML config. - Enabled backends without a configured API key will show warnings in the logs. Either set the key or disable the backend with `enabled: false`. + Enabled backends without a configured API key will log warnings. Either set the key or disable the backend with `enabled: false`. -## Provider Selection Strategies +### LLM provider credits -The Lua script referenced by `lua_script_path` controls how GenVM selects which provider to use for each LLM call. + + GenLayer has partnered with multiple LLM providers to offer free credits for validators: -### Default (Random Selection) + **[Heurist](https://www.heurist.ai/)** — free [API credits](https://dev-api-form.heurist.ai) with referral code _"genlayer"_. -The default script (`genvm-llm-default.lua`) iterates through all enabled providers that match the required capabilities (JSON support, image support) and tries them in arbitrary order. If a provider returns an overload error (429, 503, 408, 504, 529), it falls back to the next one. + **[Comput3](https://genlayer.comput3.ai/)** — free [API credits](https://genlayer.comput3.ai/) for llama3, hermes3, and qwen3 models. -### Greybox (Ordered Fallback via OpenRouter) + **[io.net](/partners/ionet)** — create an account at [id.io.net](https://id.io.net/login) and [request free credits](https://form.typeform.com/to/pDmCCViV). -Switch from random selection to a deterministic priority chain. Models are tried in order based on `meta.greybox` priority numbers in the YAML config. + **[Chutes](/partners/chutes)** — create an account at [chutes.ai](https://chutes.ai) and generate an API key from settings. -**Default text chain:** deepseek-v3.2 → qwen3-235b → claude-haiku-4.5 → kimi-k2 → glm-5 → llama-3.3 (heurist) → llama-3.3 (ionet) + **[Morpheus](/partners/morpheus)** — obtain a [Morpheus API key](https://mor.org/) for DeepSeek, Llama, Qwen, and more via OpenAI-compatible API. + -**Default image chain:** gpt-5.1-mini → gemini-3-flash → claude-haiku-4.5 +## Greyboxing: Optimizing Your Validator -#### Setup +Greyboxing is how you configure and optimize your validator's LLM execution. The term comes from the idea that each validator operates as a semi-transparent box — you control what goes in, which model processes it, and how outputs are handled, but the contract's logic remains a black box. -**1. Stop the node:** -```bash -sudo systemctl stop genlayer-node -``` +Every validator's greybox is unique. This has two benefits: +- **Security** — attackers cannot predict your validator's specific configuration, making universal attacks harder +- **Economics** — you can optimize for cost, speed, and quality to maximize your rewards -**2. Add OpenRouter API key:** -```bash -echo "OPENROUTERKEY=sk-or-v1-your-key-here" >> /opt/genlayer-node/.env -``` +### What you can control -**3. Apply the release LLM config:** -```bash -VERSION=$(readlink /opt/genlayer-node/bin | sed 's|/bin||; s|.*/||') +Greyboxing encompasses several layers of configuration, all implemented in the Lua script that `lua_script_path` points to: -cp /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-modules-llm-release.yaml \ - /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml -``` +**Model selection** — Choose which LLM handles each request. You can route text prompts to a cheap fast model and image prompts to a vision-capable one. This can be random, an ordered fallback chain, or a custom router. -**4. Switch to greybox strategy:** -```bash -sed -i 's/genvm-llm-default\.lua/genvm-llm-greybox.lua/' \ - /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml -``` +**Input filtering** — Apply filters to prompts before they reach the LLM. Available text filters: `NFKC` (Unicode normalization), `NormalizeWS` (whitespace), `RmZeroWidth` (remove zero-width characters). Available image filters: `Denoise`, `JPEG` (compression), `GuassianNoise`, `Unsharpen`. Filtering normalizes inputs across validators and can improve consensus. -**5. Start the node:** -```bash -sudo systemctl start genlayer-node -``` +**LLM parameters** — Temperature, max tokens, system prompts. Configured per-model in YAML or overridden in your Lua script. -**6. Verify:** -```bash -sudo journalctl -u genlayer-node --no-hostname | grep "greybox" -# Expected: greybox: success provider: openrouter model: deepseek/deepseek-v3.2 -``` +**Cost management** — In future versions, your greyboxing script will be able to track execution costs and decide when a transaction is too expensive to process. As a validator, if the cost of LLM calls exceeds what makes economic sense, you can timeout the transaction rather than executing at a loss. -#### Customizing Chain Order +### Built-in strategies -Priority is controlled by `meta.greybox` on each model: +GenVM ships with two Lua scripts. Switch between them by changing `lua_script_path` in `genvm-module-llm.yaml`. + +#### Default: Random selection + +**Script:** `genvm-llm-default.lua` + +Iterates through all enabled backends that match the required capabilities (JSON support, image support) and tries them in arbitrary order. Falls back to the next provider on overload errors (429, 503, 408, 504, 529). + +This is the simplest strategy — works out of the box with no tuning. + +#### Ordered fallback chain + +**Script:** `genvm-llm-greybox.lua` + +Uses a fixed priority chain configured via `meta.greybox` fields in the YAML. Each model declares which chain it belongs to (text, image, or both) and its priority. Lower number = tried first. ```yaml models: deepseek/deepseek-v3.2: supports_json: true meta: - greybox: { text: 1 } # text chain, priority 1 (tried first) + greybox: { text: 1 } # text chain, priority 1 (tried first) openai/gpt-5.1-mini: supports_json: true supports_image: true meta: - greybox: { image: 1 } # image chain, priority 1 + greybox: { image: 1 } # image chain, priority 1 anthropic/claude-haiku-4.5: supports_json: true supports_image: true meta: - greybox: { text: 3, image: 3 } # both chains, priority 3 + greybox: { text: 3, image: 3 } # both chains, lower priority ``` -Lower number = tried first. Remove `meta.greybox` to exclude a model from the chain. - -#### Reverting to Default +**To enable:** ```bash sudo systemctl stop genlayer-node -sed -i 's/genvm-llm-greybox\.lua/genvm-llm-default.lua/' \ + +# Set your OpenRouter key (or whichever provider you're using) +echo "OPENROUTERKEY=sk-or-v1-your-key-here" >> /opt/genlayer-node/.env + +# Apply the release config with greybox metadata +VERSION=$(readlink /opt/genlayer-node/bin | sed 's|/bin||; s|.*/||') +cp /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-modules-llm-release.yaml \ + /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml + +# Switch to greybox script +sed -i 's/genvm-llm-default\.lua/genvm-llm-greybox.lua/' \ /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml + sudo systemctl start genlayer-node ``` -### Writing a Custom Strategy +**Verify:** +```bash +sudo journalctl -u genlayer-node --no-hostname | grep "greybox" +# Expected: greybox: success provider: openrouter model: deepseek/deepseek-v3.2 +``` + +**To revert:** change `genvm-llm-greybox.lua` back to `genvm-llm-default.lua` and restart. + +#### Writing a custom strategy -You can write your own Lua script for provider selection. Create a new `.lua` file in the config directory and point `lua_script_path` to it. +For full control, write your own Lua script. Create a `.lua` file in the config directory and point `lua_script_path` to it. Your script must export two global functions: ```lua --- Called for direct prompts (gl.nondet.exec_prompt) +local lib = require("lib-genvm") +local llm = require("lib-llm") + function ExecPrompt(ctx, args, remaining_gen) - -- args.prompt: string - -- args.response_format: "text" | "json" - -- args.images: table of image bytes (optional) - -- remaining_gen: number (remaining gas) - -- - -- Must return: {data: string, consumed_gen: number, input_tokens: number, output_tokens: number} + -- args.prompt: the text prompt + -- args.response_format: "text" or "json" + -- args.images: table of image bytes (may be nil) + -- remaining_gen: gas budget (for future cost tracking) + + -- Transform the raw args into internal format + local mapped = llm.exec_prompt_transform(args) + + -- Apply input filters + args.prompt = lib.rs.filter_text(args.prompt, {'NFKC', 'NormalizeWS'}) + + -- Select providers that match requirements + local providers = llm.select_providers_for(mapped.prompt, mapped.format) + + -- Execute on a specific provider + local result = llm.rs.exec_prompt_in_provider(ctx, { + provider = "my-provider", + model = "model-name", + prompt = mapped.prompt, + format = mapped.format, + }) + + result.consumed_gen = 0 -- Cost tracking (future) + return result end --- Called for template prompts (Equivalence Principle) function ExecPromptTemplate(ctx, args, remaining_gen) - -- args.template: "EqComparative" | "EqNonComparativeValidator" | "EqNonComparativeLeader" - -- args.vars: table of template variable substitutions - -- - -- Must return: same as ExecPrompt + -- Called for Equivalence Principle template prompts + -- args.template: "EqComparative", "EqNonComparativeValidator", "EqNonComparativeLeader" + -- args.vars: template variable substitutions + + local mapped = llm.exec_prompt_template_transform(args) + + -- ... your provider selection logic ... end ``` -Use the helper libraries: -```lua -local lib = require("lib-genvm") -- logging, error handling, utilities -local llm = require("lib-llm") -- provider selection, prompt transforms - --- Select providers matching required capabilities -local providers = llm.select_providers_for(prompt, format) - --- Execute on a specific provider -local result = llm.rs.exec_prompt_in_provider(ctx, { - provider = "my-provider", - model = "model-name", - prompt = mapped_prompt, - format = "text", -- or "json" or "bool" -}) -``` +## Prompt Templates + +The `prompt_templates` section in `genvm-module-llm.yaml` configures how your validator acts as a **judge** in [Equivalence Principle](/developers/intelligent-contracts/features/non-determinism) scenarios. Your validator isn't just running raw LLM calls — in certain consensus situations, it needs to evaluate whether two outputs are equivalent or whether a result meets specified criteria. + +Three templates, using `#{variable}` syntax for substitution: + +| Template | When it's used | What it returns | +|---|---|---| +| `eq_comparative` | Comparing leader vs validator outputs | Boolean: are they equivalent? | +| `eq_non_comparative_leader` | Leader producing a result | Text output | +| `eq_non_comparative_validator` | Validator checking leader's result | Boolean + reasoning | + +You can tune these prompts to improve your validator's judgment quality. Better prompts → more accurate consensus → higher rewards. ## Lua Scripting API -### Core Functions (`lib.rs` / `__dflt`) +### Core functions (`lib.rs`) Available in all Lua scripts: | Function | Description | |---|---| -| `lib.rs.request(ctx, {method, url, headers, body, json, sign})` | Make HTTP request. `json: true` returns parsed response. | -| `lib.rs.json_parse(str)` | Parse JSON string to table | -| `lib.rs.json_stringify(value)` | Serialize table to JSON string | -| `lib.rs.base64_encode(data)` | Base64 encode | -| `lib.rs.base64_decode(data)` | Base64 decode | -| `lib.rs.filter_text(text, filters)` | Apply text filters: `"NFC"`, `"NFKC"`, `"NormalizeWS"`, `"RmZeroWidth"` | -| `lib.rs.filter_image(bytes, filters)` | Apply image filters: `{Denoise=0.5}`, `{JPEG=0.9}`, `{GuassianNoise=0.1}` | +| `lib.rs.request(ctx, {method, url, headers, body, json, sign})` | HTTP request. `json: true` returns parsed response. | +| `lib.rs.json_parse(str)` | Parse JSON string to Lua table | +| `lib.rs.json_stringify(value)` | Serialize Lua table to JSON | +| `lib.rs.base64_encode(data)` / `base64_decode(data)` | Base64 encode/decode | +| `lib.rs.filter_text(text, filters)` | Text filters: `"NFC"`, `"NFKC"`, `"NormalizeWS"`, `"RmZeroWidth"` | +| `lib.rs.filter_image(bytes, filters)` | Image filters: `{Denoise=0.5}`, `{JPEG=0.9}`, `{GuassianNoise=0.1}`, `{Unsharpen={0.5, 0.5}}` | | `lib.rs.split_url(url)` | Parse URL → `{schema, host, port}` | | `lib.rs.url_encode(text)` | URL-encode text | | `lib.rs.sleep_seconds(n)` | Async sleep | -| `lib.rs.random_bytes(n)` | Generate n random bytes | -| `lib.rs.random_float()` | Random float in [0, 1) | +| `lib.rs.random_bytes(n)` / `random_float()` | Random data generation | | `lib.rs.user_error({causes, fatal, ctx})` | Raise a user error | -| `lib.rs.as_user_error(err)` | Try to convert error to user error (returns nil if not) | -| `lib.log({level, message, ...})` | Structured logging (levels: trace, debug, info, warn, error) | +| `lib.rs.as_user_error(err)` | Try to convert error to user error (nil if not) | +| `lib.log({level, message, ...})` | Structured logging (trace, debug, info, warn, error) | -### LLM Functions (`llm.rs` / `__llm`) - -Available in LLM module scripts: +### LLM functions (`llm.rs`) | Function | Description | |---|---| | `llm.rs.exec_prompt_in_provider(ctx, request)` | Execute prompt on a specific provider/model | -| `llm.providers` | Table of all configured providers and their models | +| `llm.providers` | Table of all configured backends and models | | `llm.templates` | Equivalence Principle prompt templates | -| `llm.select_providers_for(prompt, format)` | Filter providers by capability (JSON, images) | +| `llm.select_providers_for(prompt, format)` | Filter backends by capability (JSON, images) | | `llm.exec_prompt_transform(args)` | Transform raw prompt args to internal format | | `llm.exec_prompt_template_transform(args)` | Transform template args with variable substitution | -| `llm.overloaded_statuses` | Set of HTTP status codes indicating overload: `{408, 429, 503, 504, 529}` | - -### Web Functions (`web.rs` / `__web`) +| `llm.overloaded_statuses` | HTTP codes indicating overload: `{408, 429, 503, 504, 529}` | -Available in web module scripts: +### Web functions (`web.rs`) | Function | Description | |---|---| -| `web.config` | Web module configuration (webdriver_host, etc.) | +| `web.config` | Web module configuration | | `web.allowed_tld` | Set of allowed top-level domains | | `web.check_url(url)` | Validate URL against schema, port, and TLD restrictions | -## Prompt Templates - -The Equivalence Principle uses three prompt templates, configured in `genvm-module-llm.yaml` under `prompt_templates`: - -| Template | Used By | Input Variables | Returns | -|---|---|---|---| -| `eq_comparative` | Comparative validation | `#{task}`, `#{criteria}`, `#{output1}`, `#{output2}` | Boolean (are outputs equivalent?) | -| `eq_non_comparative_leader` | Leader execution | `#{task}`, `#{criteria}` | Text result | -| `eq_non_comparative_validator` | Validator checking | `#{task}`, `#{criteria}`, `#{output}` | Boolean + reason | - -Templates use `#{variable_name}` syntax for substitution. You can customize the system and user prompts to change how validators evaluate results. - -## Web Module Configuration - -The web module enables contracts to fetch web pages, make HTTP requests, and capture screenshots. - -### URL Restrictions - -By default, contracts can only access URLs with standard TLDs (com, org, net, etc.) on ports 80 and 443. Customize with: - -- `extra_tld: ["local", "internal"]` — allow additional TLDs -- `always_allow_hosts: ["my-api.internal"]` — bypass all URL checks for specific hosts +## Advanced: Web Module -### Webdriver - -The webdriver (Selenium with headless Firefox) handles page rendering and screenshots. The web module scripts implement two functions: +The web module (`genvm-module-web.yaml`) enables contracts to fetch web pages, make HTTP requests, and capture screenshots. You generally don't need to modify this. +The Lua script (`genvm-web-default.lua`) implements two functions: - `Render(ctx, payload)` — render a page as text, HTML, or screenshot - `Request(ctx, payload)` — make HTTP requests (GET, POST, etc.) -## Updating Configuration - -### Hot-Reload (No Full Restart) - -Restart individual modules without stopping the node: - -```bash -PORT=3999 # GenVM manager port - -# Restart LLM module (reloads Lua script + YAML config) -curl -X POST "http://127.0.0.1:${PORT}/module/stop" \ - -H 'Content-Type: application/json' \ - -d '{"module_type": "Llm"}' - -curl -X POST "http://127.0.0.1:${PORT}/module/start" \ - -H 'Content-Type: application/json' \ - -d '{"module_type": "Llm", "config": null}' +**What you might customize:** +- `extra_tld: ["local"]` — allow additional TLDs beyond the standard set +- `always_allow_hosts: ["my-api.internal"]` — bypass URL checks for specific hosts -# Restart Web module -curl -X POST "http://127.0.0.1:${PORT}/module/stop" \ - -H 'Content-Type: application/json' \ - -d '{"module_type": "Web"}' - -curl -X POST "http://127.0.0.1:${PORT}/module/start" \ - -H 'Content-Type: application/json' \ - -d '{"module_type": "Web", "config": null}' -``` +## Advanced: GenVM Manager -### Full Restart +The manager (`genvm-manager.yaml`) controls concurrency. The main setting is `permits` — max concurrent GenVM executions. -```bash -sudo systemctl stop genlayer-node -# ... edit config files ... -sudo systemctl start genlayer-node -``` + + On macOS (native), auto-detection is not supported. Set `permits` manually (e.g., `32`). + ## Troubleshooting -**Warnings for unconfigured providers:** -Enabled backends without API keys log warnings. Either set the key in `.env` or disable the backend with `enabled: false`. +**Warnings for unconfigured providers:** Enabled backends without API keys log warnings. Set the key in `.env` or disable with `enabled: false`. -**"module_failed_to_start" error:** -- Check that the Lua script file exists at the path in `lua_script_path` -- Check that required API keys are set in `.env` -- Check YAML syntax (indentation, colons) +**"module_failed_to_start":** Check that the Lua script exists at the path in `lua_script_path`, API keys are set, and YAML syntax is valid. -**"NO_PROVIDER_FOR_PROMPT" error:** -No enabled provider matches the required capabilities. Ensure at least one backend has `supports_json: true` (and `supports_image: true` if the contract sends images). +**"NO_PROVIDER_FOR_PROMPT":** No enabled backend matches the request's capabilities. Ensure at least one has `supports_json: true` (and `supports_image: true` for image prompts). -**All models exhausted / overload errors:** -All providers returned overload status codes (429, 503, etc.). Check API key validity, provider status pages, and consider adding more backends as fallback. +**All models exhausted:** All providers returned overload errors. Check API key validity and provider status pages. Add more backends as fallback. From 7b24cbb2ab8fccc8567de5972f08493dc3cfff8a Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 12:09:27 +0100 Subject: [PATCH 4/8] =?UTF-8?q?fix:=20capability=20matrix=20(input=C3=97ou?= =?UTF-8?q?tput),=20move=20credits=20to=20top,=20clarify=20env=20vars?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/validators/genvm-configuration.mdx | 49 ++++++++++++++++-------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index 794908f4..b4a701ed 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -6,6 +6,22 @@ Your validator's GenVM needs two things to function: **LLM providers** to proces **Why this matters:** The LLM providers you choose directly affect your validator's operating costs and performance. Faster, cheaper models reduce your costs per transaction. Higher-quality models improve your consensus accuracy, which affects your rewards and avoids slashing. By tuning your provider setup — choosing the right models, configuring fallback chains, running local inference, or applying input filters — you can optimize the economics of running your validator. +## LLM Provider Credits + + + GenLayer has partnered with multiple LLM providers to offer free credits for validators: + + **[Heurist](https://www.heurist.ai/)** — free [API credits](https://dev-api-form.heurist.ai) with referral code _"genlayer"_. + + **[Comput3](https://genlayer.comput3.ai/)** — free [API credits](https://genlayer.comput3.ai/) for llama3, hermes3, and qwen3 models. + + **[io.net](/partners/ionet)** — create an account at [id.io.net](https://id.io.net/login) and [request free credits](https://form.typeform.com/to/pDmCCViV). + + **[Chutes](/partners/chutes)** — create an account at [chutes.ai](https://chutes.ai) and generate an API key from settings. + + **[Morpheus](/partners/morpheus)** — obtain a [Morpheus API key](https://mor.org/) for DeepSeek, Llama, Qwen, and more via OpenAI-compatible API. + + ## Hot-Reload You can modify configuration files on the fly and reload without stopping your node. This is important when experimenting with providers or tuning your setup. @@ -57,6 +73,22 @@ backends: meta: {} # Custom metadata (used by greyboxing strategies) ``` +### Model capabilities + +Intelligent Contract LLM requests have two axes: + +- **Input:** text only, or text + one or more images +- **Output:** free-form text, or structured JSON + +This gives four combinations: text→text, text→JSON, images+text→text, images+text→JSON. The capability flags control which models are eligible: + +- `supports_json: true` — model can produce structured JSON output +- `supports_image: true` — model can accept image inputs + +**Your validator must support all combinations across your model set.** Not every model needs to support everything — that's where routing comes in. You can use a cheap text model for simple prompts and a vision-capable model for image requests. But if a contract sends an image prompt and none of your enabled models support images, the request will fail. + +The `supports_json` and `supports_image` flags tell the Lua script which models are eligible for each request type. Set them accurately for each model. + ### Supported provider types | Type | Description | Example services | @@ -104,7 +136,7 @@ backends: ### API key environment variables -Set these in your `.env` file before starting the node. Keys use `${ENV[VARIABLE_NAME]}` syntax in the YAML. +Set these in your `.env` file before starting the node. You only need to set the keys for providers you're actually using. Keys use `${ENV[VARIABLE_NAME]}` syntax in the YAML. | Variable | Provider | |---|---| @@ -123,21 +155,6 @@ Set these in your `.env` file before starting the node. Keys use `${ENV[VARIABLE Enabled backends without a configured API key will log warnings. Either set the key or disable the backend with `enabled: false`. -### LLM provider credits - - - GenLayer has partnered with multiple LLM providers to offer free credits for validators: - - **[Heurist](https://www.heurist.ai/)** — free [API credits](https://dev-api-form.heurist.ai) with referral code _"genlayer"_. - - **[Comput3](https://genlayer.comput3.ai/)** — free [API credits](https://genlayer.comput3.ai/) for llama3, hermes3, and qwen3 models. - - **[io.net](/partners/ionet)** — create an account at [id.io.net](https://id.io.net/login) and [request free credits](https://form.typeform.com/to/pDmCCViV). - - **[Chutes](/partners/chutes)** — create an account at [chutes.ai](https://chutes.ai) and generate an API key from settings. - - **[Morpheus](/partners/morpheus)** — obtain a [Morpheus API key](https://mor.org/) for DeepSeek, Llama, Qwen, and more via OpenAI-compatible API. - ## Greyboxing: Optimizing Your Validator From 0e58b2f2eea941b719384f9b394decc2f785242f Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 12:10:03 +0100 Subject: [PATCH 5/8] =?UTF-8?q?fix:=20correct=20greyboxing=20definition=20?= =?UTF-8?q?=E2=80=94=20grey=20box=20from=20network's=20perspective,=20not?= =?UTF-8?q?=20validator's?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/validators/genvm-configuration.mdx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index b4a701ed..2a96e5d0 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -158,11 +158,9 @@ Set these in your `.env` file before starting the node. You only need to set the ## Greyboxing: Optimizing Your Validator -Greyboxing is how you configure and optimize your validator's LLM execution. The term comes from the idea that each validator operates as a semi-transparent box — you control what goes in, which model processes it, and how outputs are handled, but the contract's logic remains a black box. +Greyboxing is how you configure and optimize your validator's LLM execution. From the network's point of view, each validator is a **grey box** — an attacker can see that LLMs are being used, but cannot know which model will process a given request, how it's configured, or what filters are applied. This per-validator opacity is a security property: it makes prompt injection and manipulation attacks much harder because there's no single configuration to target. -Every validator's greybox is unique. This has two benefits: -- **Security** — attackers cannot predict your validator's specific configuration, making universal attacks harder -- **Economics** — you can optimize for cost, speed, and quality to maximize your rewards +As a validator operator, greyboxing is also your primary lever for **economics** — by choosing the right models, configuring fallback chains, and applying filters, you control your operating costs and consensus quality. ### What you can control From 76263e66c3b7d6cf1e5a64aeb4988cc4f3678813 Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 14:12:42 +0100 Subject: [PATCH 6/8] =?UTF-8?q?docs:=20add=20model=20selection=20guidance?= =?UTF-8?q?=20=E2=80=94=20start=20capable,=20optimize=20down?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/validators/genvm-configuration.mdx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index 2a96e5d0..e40afabf 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -162,6 +162,19 @@ Greyboxing is how you configure and optimize your validator's LLM execution. Fro As a validator operator, greyboxing is also your primary lever for **economics** — by choosing the right models, configuring fallback chains, and applying filters, you control your operating costs and consensus quality. +### Choosing models + +Start with a capable model and optimize down over time. Your validator needs to produce correct consensus results — using a model that's too weak will hurt your accuracy, leading to missed rewards or slashing. Once you're confident in your setup, you can experiment with cheaper alternatives. + +**Recommended starting points:** +- **Frontier tier:** Claude Sonnet 4.6, GPT-5, Gemini 2.5 Flash — high accuracy, higher cost +- **Strong open-source:** DeepSeek V3.2, Qwen3-235B, Llama 4 Maverick — good accuracy, lower cost +- **Budget tier:** Nemotron, smaller Llama variants — lowest cost, test carefully before relying on these + +For image-capable requests, you need at least one vision model (e.g., GPT-5, Gemini Flash, Claude Sonnet). + +A practical approach: use a frontier model as your primary, with cheaper models as fallback. The greyboxing ordered fallback strategy (below) makes this easy. + ### What you can control Greyboxing encompasses several layers of configuration, all implemented in the Lua script that `lua_script_path` points to: From 67654b39ed6c1f59b4bc660a2adfcc1686d8b6dd Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 14:19:29 +0100 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20Gemini=202.5=20Flash=20=E2=86=92=20G?= =?UTF-8?q?emini=203=20Flash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/validators/genvm-configuration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index e40afabf..6dca9a6d 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -167,7 +167,7 @@ As a validator operator, greyboxing is also your primary lever for **economics** Start with a capable model and optimize down over time. Your validator needs to produce correct consensus results — using a model that's too weak will hurt your accuracy, leading to missed rewards or slashing. Once you're confident in your setup, you can experiment with cheaper alternatives. **Recommended starting points:** -- **Frontier tier:** Claude Sonnet 4.6, GPT-5, Gemini 2.5 Flash — high accuracy, higher cost +- **Frontier tier:** Claude Sonnet 4.6, GPT-5, Gemini 3 Flash — high accuracy, higher cost - **Strong open-source:** DeepSeek V3.2, Qwen3-235B, Llama 4 Maverick — good accuracy, lower cost - **Budget tier:** Nemotron, smaller Llama variants — lowest cost, test carefully before relying on these From d5021acbb43d068eef5a7377f1840c1c7799a6bf Mon Sep 17 00:00:00 2001 From: Edgars Date: Thu, 9 Apr 2026 14:23:02 +0100 Subject: [PATCH 8/8] fix: max 2 images per prompt (hard limit in GenVM) --- pages/validators/genvm-configuration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/validators/genvm-configuration.mdx b/pages/validators/genvm-configuration.mdx index 6dca9a6d..847183a1 100644 --- a/pages/validators/genvm-configuration.mdx +++ b/pages/validators/genvm-configuration.mdx @@ -77,7 +77,7 @@ backends: Intelligent Contract LLM requests have two axes: -- **Input:** text only, or text + one or more images +- **Input:** text only, or text + up to 2 images - **Output:** free-form text, or structured JSON This gives four combinations: text→text, text→JSON, images+text→text, images+text→JSON. The capability flags control which models are eligible: