Skill: kevins9527/gpt-image-2-toolkit (version 1.0.1)

--- name: gpt-image-2-toolkit description: Install, verify, repair, and diagnose GPT-Image-2 support for OpenClaw so agents can use model refs like hnbc/gpt-image-2 through the built-in image_generate tool. Use when a user wants to add GPT-Image-2 image generation, re-install the skill on another machine, or fix errors like 'No image-generation provider registered for hnbc'. --- # GPT-Image-2 for OpenClaw Use this skill when the user wants GPT-Image-2 image generation available through OpenClaw's built-in `image_generate` tool. ## What this skill does - Installs a plugin package into the global OpenClaw extensions directory - Registers provider id `hnbc` - Exposes model `hnbc/gpt-image-2` - Verifies installation from file, local runtime, and tool perspectives - Diagnoses the common split-brain case where disk/runtime sees `hnbc` but the running gateway tool view does not - Reminds you that a running gateway may need a restart before the tool sees the new provider ## When to use - "给 OpenClaw 加一个 GPT-Image-2 图像能力" - "让 image_generate 支持 hnbc/gpt-image-2" - "修复 No image-generation provider registered for hnbc" - "把这个能力做成别的 agent / 机器可安装的形式" - "检查 GPT-Image-2 provider 为什么工具侧看不到" ## Core workflow ### Install 1. Run `scripts/install.sh`. 2. Run `scripts/self-check.sh`. 3. Note: bundled `hnbc` under [REDACTED_SECRET] is also a valid source; missing `~/.openclaw/extensions/hnbc` alone does not prove the provider is absent. ### Verify Check both sides: 1. Local runtime/plugin registry 2. `image_generate(action="list")` ### Diagnose mismatch If local runtime sees `hnbc` but `image_generate list` does not: - explain that the currently running gateway likely still holds an old provider registry - ask before restarting the gateway - do **not** restart without explicit user approval - after restart, verify again and test a real generation ### Deep diagnosis If anything is unclear, run `scripts/diagnose.sh`. If you need extra interpretation guidance, read `references/troubleshooting.md`. ## Recommended validation order 1. `scripts/self-check.sh` 2. `image_generate(action="list")` 3. If missing from tool list, compare with local runtime using `scripts/diagnose.sh` 4. After install or restart, run `scripts/e2e-check.sh` 5. Test a real generation with `model="hnbc/gpt-image-2"` For next-version release guidance, read `references/release-1.0.1.md`. ## Important compatibility notes - `hnbc/gpt-image-2` supports generation, not edit. - Supported sizes: `1024x1024`, `1024x1536`, `1536x1024` - Supported aspect ratios: `1:1`, `2:3`, `3:2` - Do **not** pass `resolution`; HNBC currently rejects resolution overrides. - Auth should come from either: - `HNBC_API_KEY`, or - `models.providers.hnbc.apiKey`, or - an auth profile for provider `hnbc` ## Files bundled with this skill - `assets/plugin/` — the plugin package files - `scripts/install.sh` — installs the plugin into the global OpenClaw extensions dir - `scripts/self-check.sh` — verifies required files and manifest/package basics - `scripts/diagnose.sh` — prints a fuller runtime diagnosis - `scripts/e2e-check.sh` — runs a post-install validation checklist - `references/troubleshooting.md` — quick error-to-fix map - `references/release-1.0.1.md` — next release checklist and publish command ## Verification checklist - `scripts/self-check.sh` returns `STATUS=ok` - `image_generate(action="list")` shows `hnbc (default gpt-image-2)` - generating with `model="hnbc/gpt-image-2"` works - no `resolution` parameter is sent during generation

path: assets/plugin/image-generation-provider.js
content: import { H as resolveApiKeyForProvider } from "../../pi-embedded-BaSvmUpW.js";

const DEFAULT_OUTPUT_MIME = "image/png";
const DEFAULT_SIZE = "1024x1024";
const SUPPORTED_SIZES = [
  "1024x1024",
  "1024x1536",
  "1536x1024"
];
const SUPPORTED_ASPECT_RATIOS = [
  "1:1",
  "2:3",
  "3:2"
];
const ASPECT_RATIO_TO_SIZE = {
  "1:1": "1024x1024",
  "2:3": "1024x1536",
  "3:2": "1536x1024"
};

function resolveHnbcBaseUrl(cfg) {
  const direct = cfg?.models?.providers?.hnbc?.baseUrl?.trim() || "https://api.1415.xin/v1";
  return direct.replace(/\/+$/u, "");
}

function decodeBase64Payload(value) {
  if (!value || typeof value !== "string") return null;
  const trimmed = value.trim();
  if (!trimmed) return null;
  const match = /^data:([^;]+);base64,(.+)$/u.exec(trimmed);
  if (match) {
    return {
      buffer: Buffer.from(match[2], "base64"),
      mimeType: match[1] || DEFAULT_OUTPUT_MIME
    };
  }
  try {
    return {
      buffer: Buffer.from(trimmed, "base64"),
      mimeType: DEFAULT_OUTPUT_MIME
    };
  } catch {
    return null;
  }
}

function normalizeImageEntries(payload) {
  const data = payload?.data;
  if (!Array.isArray(data)) return [];
  const images = [];
  let idx = 0;
  for (const entry of data) {
    const decoded = decodeBase64Payload(entry?.b64_json || entry?.base64 || entry?.image_base64);
    if (!decoded) continue;
    idx += 1;
    images.push({
      buffer: decoded.buffer,
      mimeType: decoded.mimeType,
      fileName: `image-${idx}.png`,
      ...(entry?.revised_prompt ? { revisedPrompt: entry.revised_prompt } : {})
    });
  }
  return images;
}

function resolveRequestedSize(req) {
  const size = req.size?.trim();
  if (size) return size;
  const aspectRatio = req.aspectRatio?.trim();
  if (aspectRatio && ASPECT_RATIO_TO_SIZE[aspectRatio]) return ASPECT_RATIO_TO_SIZE[aspectRatio];
  return DEFAULT_SIZE;
}

function buildHnbcImageGenerationProvider() {
  return {
    id: "hnbc",
    label: "HNBC",
    defaultModel: "gpt-image-2",
    models: ["gpt-image-2"],
    capabilities: {
      generate: {
        maxCount: 4,
        supportsSize: true,
        supportsAspectRatio: true,
        supportsResolution: false
      },
      edit: {
        enabled: false,
        maxCount: 0,
        maxInputImages: 0,
        supportsSize: false,
        supportsAspectRatio: false,
        supportsResolution: false
      },
      geometry: {
        sizes: [...SUPPORTED_SIZES],
        aspectRatios: [...SUPPORTED_ASPECT_RATIOS]
      }
    },
    async generateImage(req) {
      if ((req.inputImages?.length ?? 0) > 0) {
        throw new Error("HNBC image provider v1 暂不支持参考图编辑");
      }
      const auth = await resolveApiKeyForProvider({
        provider: "hnbc",
        cfg: req.cfg,
        agentDir: req.agentDir,
        store: req.authStore
      });
      const [REDACTED_SECRET] || req.cfg?.models?.providers?.hnbc?.apiKey?.trim();
      if (!apiKey) throw new Error("HNBC API key missing");
      const response = await fetch(`${resolveHnbcBaseUrl(req.cfg)}/images/generations`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${apiKey}`,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          model: req.model || "gpt-image-2",
          prompt: req.prompt,
          n: req.count ?? 1,
          size: resolveRequestedSize(req)
        })
      });
      if (!response.ok) {
        const text = await response.text().catch(() => "");
        throw new Error(`HNBC image generation failed (${response.status}): ${text || response.statusText}`);
      }
      const payload = await response.json();
      const images = normalizeImageEntries(payload);
      if (images.length === 0) {
        throw new Error("HNBC image generation response missing image data");
      }
      return {
        images,
        model: req.model || "gpt-image-2",
        metadata: payload?.created ? { created: payload.created } : void 0
      };
    }
  };
}

export { buildHnbcImageGenerationProvider };


path: assets/plugin/index.js
content: import { t as definePluginEntry } from "../../plugin-entry-CK-4XWE0.js";
import { buildHnbcImageGenerationProvider } from "./image-generation-provider.js";

var hnbc_default = definePluginEntry({
  id: "hnbc",
  name: "HNBC Provider",
  description: "Bundled HNBC image generation provider",
  register(api) {
    api.registerImageGenerationProvider(buildHnbcImageGenerationProvider());
  }
});

export { hnbc_default as default };


path: assets/plugin/openclaw.plugin.json
content: {
  "id": "hnbc",
  "providers": [
    "hnbc"
  ],
  "providerAuthEnvVars": {
    "hnbc": [
      "HNBC_API_KEY"
    ]
  },
  "providerAuthChoices": [
    {
      "provider": "hnbc",
      "method": "api-key",
      "choiceId": "hnbc-api-key",
      "choiceLabel": "HNBC API key",
      "groupId": "hnbc",
      "groupLabel": "HNBC",
      "groupHint": "Image generation",
      "onboardingScopes": [
        "image-generation"
      ],
      "optionKey": "hnbcApiKey",
      "cliFlag": "--hnbc-api-key",
      "cliOption": "--hnbc-api-key <key>",
      "cliDescription": "HNBC API key"
    }
  ],
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {}
  }
}


path: assets/plugin/package.json
content: {
  "name": "@openclaw/hnbc-provider",
  "version": "2026.5.22",
  "private": true,
  "description": "OpenClaw HNBC provider plugins",
  "type": "module",
  "openclaw": {
    "extensions": [
      "./index.js"
    ]
  }
}


path: references/release-1.0.1.md
content: # GPT-Image-2 for OpenClaw 1.0.1 plan

## Recommended changes
- Add `scripts/e2e-check.sh` for post-install end-to-end validation
- Mention ClawHub listing optimization on next publish:
  - improve changelog wording
  - consider tags when the registry supports meaningful discovery tags
- Keep public guidance explicit about the two common pitfalls:
  - gateway may still hold an old provider registry until restart
  - `resolution` must not be sent to `hnbc/gpt-image-2`

## Release checklist
1. Run `scripts/self-check.sh`
2. Run `scripts/e2e-check.sh`
3. Confirm `image_generate(action="list")` shows `hnbc`
4. Confirm a real image generation works without `resolution`
5. Publish as `1.0.1`

## Suggested publish command
```bash
clawhub publish /root/.openclaw/workspace/skills/gpt-image-2-toolkit \
  --slug gpt-image-2-toolkit \
  --name "GPT-Image-2 for OpenClaw" \
  --version 1.0.1 \
  --changelog "Add end-to-end validation script and tighten installation verification guidance."
```


path: references/troubleshooting.md
content: Use this file only when you need extra detail while working with the HNBC skill.

## Fast failure map

### 1. `No image-generation provider registered for hnbc`
Most likely causes:
- plugin is neither available under `~/.openclaw/extensions/hnbc` nor bundled under `/usr/lib/node_modules/openclaw/dist/extensions/hnbc`
- running gateway has not reloaded after plugin install
- tool-side runtime is still using an older provider registry

### 2. `hnbc generate does not support resolution overrides`
Cause:
- request passed `resolution`

Fix:
- remove `resolution`
- use only supported `size` or `aspectRatio`

### 3. HNBC visible in local runtime, invisible in `image_generate list`
Interpretation:
- disk files and plugin load path are fine
- running gateway likely needs restart

### 4. `HNBC API key missing`
Check one of:
- env: `HNBC_API_KEY`
- config: `models.providers.hnbc.apiKey`
- auth profile for provider `hnbc`

## Supported request geometry
- sizes:
  - `1024x1024`
  - `1024x1536`
  - `1536x1024`
- aspect ratios:
  - `1:1`
  - `2:3`
  - `3:2`
- edit mode: unsupported


path: scripts/diagnose.sh
content: #!/usr/bin/env bash
set -euo pipefail

WORKDIR="${1:-/root/.openclaw/workspace}"
export WORKDIR
CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}"
USER_PLUGIN_DIR="$CONFIG_DIR/extensions/hnbc"
BUNDLED_PLUGIN_DIR="/usr/lib/node_modules/openclaw/dist/extensions/hnbc"

echo '=== HNBC DIAGNOSE START ==='
echo "WORKDIR=$WORKDIR"
echo "CONFIG_DIR=$CONFIG_DIR"
echo

echo '--- plugin files ---'
echo "USER_PLUGIN_DIR=$USER_PLUGIN_DIR"
if [ -d "$USER_PLUGIN_DIR" ]; then
  find "$USER_PLUGIN_DIR" -maxdepth 1 -type f | sort
else
  echo "USER_PLUGIN_DIR_MISSING=$USER_PLUGIN_DIR"
fi
echo
echo "BUNDLED_PLUGIN_DIR=$BUNDLED_PLUGIN_DIR"
if [ -d "$BUNDLED_PLUGIN_DIR" ]; then
  find "$BUNDLED_PLUGIN_DIR" -maxdepth 1 -type f | sort
else
  echo "BUNDLED_PLUGIN_DIR_MISSING=$BUNDLED_PLUGIN_DIR"
fi
echo

echo '--- gateway status ---'
openclaw gateway status || true
echo

echo '--- tool-side providers ---'
# This script only prints guidance. Agents should use image_generate(action=list) directly.
echo 'Use tool call: image_generate(action="list")'
echo

echo '--- local runtime registry ---'
node - <<'NODE'
(async () => {
  const envmod = await import('file:///usr/lib/node_modules/openclaw/dist/env-D1ktUnAV.js');
  const pimod = await import('file:///usr/lib/node_modules/openclaw/dist/pi-embedded-BaSvmUpW.js');
  const cfg = envmod.O();
  const discovery = envmod.Lt({ workspaceDir: process.env.WORKDIR, extraPaths: cfg?.plugins?.loadPaths, cache: false, env: process.env });
  const dc = discovery.candidates.filter(c => String(c.rootDir || '').includes('/hnbc') || String(c.source || '').includes('/hnbc') || String(c.idHint || '').includes('hnbc'));
  console.log('DISCOVERY_HNBC_COUNT=' + dc.length);
  console.log(JSON.stringify(dc, null, 2));
  const manifest = envmod.kt({ config: cfg, workspaceDir: process.env.WORKDIR, cache: false, env: process.env, candidates: discovery.candidates, diagnostics: discovery.diagnostics });
  const mp = manifest.plugins.filter(p => p.id === 'hnbc');
  console.log('MANIFEST_HNBC_COUNT=' + mp.length);
  console.log(JSON.stringify(mp, null, 2));
  const reg = pimod.gt({ config: cfg, workspaceDir: process.env.WORKDIR, cache: false, env: process.env, throwOnLoadError: false });
  const ap = reg.plugins.filter(p => p.id === 'hnbc');
  console.log('ACTIVE_HNBC_COUNT=' + ap.length);
  console.log(JSON.stringify(ap, null, 2));
  console.log('ACTIVE_IMAGE_GEN_PROVIDER_IDS=' + JSON.stringify((reg.imageGenerationProviders || []).map(x => x.provider?.id)));
})();
NODE
echo

echo '--- hints ---'
echo 'Bundled hnbc under /usr/lib/node_modules/openclaw/dist/extensions/hnbc is a valid install source; missing ~/.openclaw/extensions/hnbc alone does not prove the provider is absent.'
echo 'If local runtime sees hnbc but image_generate(action=list) does not, the running gateway likely still holds an old provider registry and needs restart.'
echo 'If generation fails with resolution override error, remove resolution and keep only size/aspectRatio.'
echo '=== HNBC DIAGNOSE END ==='


path: scripts/e2e-check.sh
content: #!/usr/bin/env bash
set -euo pipefail

WORKDIR="${1:-/root/.openclaw/workspace}"
export WORKDIR

echo '=== HNBC E2E CHECK START ==='
echo "WORKDIR=$WORKDIR"
echo

echo '[1/4] Installed plugin files'
"$(cd "$(dirname "$0")" && pwd)/self-check.sh"
echo

echo '[2/4] Gateway status'
openclaw gateway status || true
echo

echo '[3/4] Local runtime registry view'
node - <<'NODE'
(async () => {
  const envmod = await import('file:///usr/lib/node_modules/openclaw/dist/env-D1ktUnAV.js');
  const pimod = await import('file:///usr/lib/node_modules/openclaw/dist/pi-embedded-BaSvmUpW.js');
  const cfg = envmod.O();
  const reg = pimod.gt({ config: cfg, workspaceDir: process.env.WORKDIR, cache: false, env: process.env, throwOnLoadError: false });
  const plugin = (reg.plugins || []).find(p => p.id === 'hnbc');
  const providers = (reg.imageGenerationProviders || []).map(x => x.provider?.id).filter(Boolean);
  console.log('ACTIVE_PLUGIN=' + (plugin ? plugin.status : 'missing'));
  console.log('ACTIVE_IMAGE_PROVIDERS=' + providers.join(','));
})();
NODE
echo

echo '[4/4] Tool-side verification reminder'
echo 'Run tool call: image_generate(action="list")'
echo 'Expected: hnbc (default gpt-image-2)'
echo 'Bundled hnbc is valid; missing ~/.openclaw/extensions/hnbc alone does not prove failure.'
echo 'If local runtime sees hnbc but tool-side list does not, restart the running gateway with user approval.'
echo 'Do not pass resolution when generating with hnbc/gpt-image-2.'
echo '=== HNBC E2E CHECK END ==='


path: scripts/install.sh
content: #!/usr/bin/env bash
set -euo pipefail

SRC_DIR="$(cd "$(dirname "$0")/../assets/plugin" && pwd)"
DEST_ROOT="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}/extensions"
DEST_DIR="$DEST_ROOT/hnbc"

mkdir -p "$DEST_ROOT"
rm -rf "$DEST_DIR"
cp -a "$SRC_DIR" "$DEST_DIR"

printf 'Installed HNBC plugin to: %s\n' "$DEST_DIR"
printf 'Next step: restart the running OpenClaw gateway if it is already running.\n'


path: scripts/self-check.sh
content: #!/usr/bin/env bash
set -euo pipefail

EXPLICIT_DIR="${1:-}"
CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}"
CANDIDATES=()

if [ -n "$EXPLICIT_DIR" ]; then
  CANDIDATES+=("$EXPLICIT_DIR")
fi

CANDIDATES+=(
  "$CONFIG_DIR/extensions/hnbc"
  "/usr/lib/node_modules/openclaw/dist/extensions/hnbc"
)

PLUGIN_DIR=""
for dir in "${CANDIDATES[@]}"; do
  if [ -d "$dir" ]; then
    PLUGIN_DIR="$dir"
    break
  fi
done

if [ -z "$PLUGIN_DIR" ]; then
  echo "STATUS=missing"
  echo "CHECKED_DIRS=$(printf '%s,' "${CANDIDATES[@]}" | sed 's/,$//')"
  exit 1
fi

required_files=(
  "index.js"
  "image-generation-provider.js"
  "package.json"
  "openclaw.plugin.json"
)

missing=0
for f in "${required_files[@]}"; do
  if [ ! -f "$PLUGIN_DIR/$f" ]; then
    echo "MISSING_FILE=$f"
    missing=1
  fi
done

if [ "$missing" -ne 0 ]; then
  echo "STATUS=incomplete"
  echo "PLUGIN_DIR=$PLUGIN_DIR"
  exit 2
fi

echo "STATUS=ok"
echo "PLUGIN_DIR=$PLUGIN_DIR"
node - "$PLUGIN_DIR" <<'NODE'
const fs = require('fs');
const path = require('path');
const dir = process.argv[2];
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
const manifest = JSON.parse(fs.readFileSync(path.join(dir, 'openclaw.plugin.json'), 'utf8'));
console.log('PACKAGE_NAME=' + (pkg.name || ''));
console.log('PACKAGE_VERSION=' + (pkg.version || ''));
console.log('PLUGIN_ID=' + (manifest.id || ''));
console.log('PROVIDERS=' + ((manifest.providers || []).join(',')));
NODE


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)