feat: initialize OmniClaw skills registry
This commit is contained in:
85
skills/sub2api-gpt-image-2/SKILL.md
Normal file
85
skills/sub2api-gpt-image-2/SKILL.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
name: sub2api-gpt-image-2
|
||||
description: Use when Codex or another agent needs to call, document, troubleshoot, or generate code for GPT Image 2 through sub2api/OpenAI-compatible image APIs, including /v1/images/generations, /v1/images/edits, Responses image_generation tools, 4K image settings, streaming partial images, base64 decoding, and production error handling.
|
||||
---
|
||||
|
||||
# Sub2API GPT Image 2
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Treat `gpt-image-2` as an image generation/editing model, not a Codex or agent main model.
|
||||
2. Use `/v1/images/generations` for direct text-to-image and `/v1/images/edits` for reference-image or mask edits.
|
||||
3. Use `/v1/responses` with a text/agent model such as `gpt-5.5` plus an `image_generation` tool when an agent should reason before generating images.
|
||||
4. Never print, commit, or hard-code real API keys. Read credentials from `API_KEY` and `BASE_URL`.
|
||||
5. For detailed parameter rules, read `references/api.md`.
|
||||
6. For quick non-streaming generation tests, run `scripts/generate_image.py`.
|
||||
|
||||
## Defaults
|
||||
|
||||
Use these defaults unless the task says otherwise:
|
||||
|
||||
```text
|
||||
BASE_URL=https://claude.omniclaw.store/v1
|
||||
model=gpt-image-2
|
||||
size=1024x1024
|
||||
quality=medium
|
||||
output_format=png
|
||||
n=1
|
||||
timeout=300 for 4K, 120 otherwise
|
||||
```
|
||||
|
||||
Use `3840x2160` only when explicitly requested or when a final 4K asset is needed. For prompt iteration, generate smaller images first.
|
||||
|
||||
## Direct Generation
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
export API_KEY="sk-..."
|
||||
export BASE_URL="https://claude.omniclaw.store/v1"
|
||||
python3 ~/.codex/skills/sub2api-gpt-image-2/scripts/generate_image.py \
|
||||
--prompt "A premium product poster for an AI service" \
|
||||
--size 1536x1024 \
|
||||
--quality medium \
|
||||
--output image.png
|
||||
```
|
||||
|
||||
Use `--dry-run` to inspect payloads without calling the API.
|
||||
|
||||
## Editing
|
||||
|
||||
Use multipart form requests with `image[]=@file.png`; add `mask=@mask.png` only for local masked edits. For `gpt-image-2`, omit `input_fidelity` because it always processes image inputs at high fidelity.
|
||||
|
||||
## Responses Tool Pattern
|
||||
|
||||
For agentic workflows:
|
||||
|
||||
```json
|
||||
{
|
||||
"model": "gpt-5.5",
|
||||
"input": "Generate a clean product poster for an AI proxy service.",
|
||||
"tools": [
|
||||
{
|
||||
"type": "image_generation",
|
||||
"size": "1536x1024",
|
||||
"quality": "medium",
|
||||
"output_format": "png"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Do not set the Responses `model` to `gpt-image-2`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- `401`: wrong or disabled sub2api key.
|
||||
- `400`: invalid params such as unsupported transparent background or invalid size.
|
||||
- `429`: upstream account usage limit; prefer plus/team/pro accounts.
|
||||
- `502`: upstream did not return image output, network failed, or content was refused; inspect sub2api logs and simplify the prompt.
|
||||
- Long latency: 4K/high can take minutes; use `jpeg`, `quality=low|medium`, or smaller sizes for drafts.
|
||||
|
||||
## Safety
|
||||
|
||||
Reject or rewrite sexualized young-looking subjects, minors, non-consensual sexual content, explicit nudity, and other disallowed content before calling the API.
|
||||
|
||||
5
skills/sub2api-gpt-image-2/agents/openai.yaml
Normal file
5
skills/sub2api-gpt-image-2/agents/openai.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
interface:
|
||||
display_name: "Sub2API GPT Image 2"
|
||||
short_description: "Generate and debug GPT Image 2 calls."
|
||||
default_prompt: "Use sub2api-gpt-image-2 to generate, edit, stream, or troubleshoot GPT Image 2 API requests."
|
||||
|
||||
106
skills/sub2api-gpt-image-2/references/api.md
Normal file
106
skills/sub2api-gpt-image-2/references/api.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# GPT Image 2 API Reference For sub2api
|
||||
|
||||
Source links:
|
||||
|
||||
- https://developers.openai.com/api/docs/models/gpt-image-2
|
||||
- https://developers.openai.com/api/docs/guides/image-generation
|
||||
- https://developers.openai.com/api/reference/resources/images
|
||||
- Repository docs: `apis/sub2api/gpt-image-2.zh.md` and `apis/sub2api/gpt-image-2.en.md`
|
||||
|
||||
## Endpoints
|
||||
|
||||
```text
|
||||
POST /v1/images/generations
|
||||
POST /v1/images/edits
|
||||
POST /v1/responses # image_generation tool with a text/agent model
|
||||
```
|
||||
|
||||
`/v1/models` may only list Codex/text models in this deployment. That does not mean `/v1/images/generations` cannot accept `gpt-image-2`.
|
||||
|
||||
## Generation Parameters
|
||||
|
||||
| Parameter | Values | Notes |
|
||||
|---|---|---|
|
||||
| `model` | `gpt-image-2`, `gpt-image-2-2026-04-21` | Required for Images API. |
|
||||
| `prompt` | string | Required. Be concrete about subject, composition, style, lighting, and safety constraints. |
|
||||
| `n` | `1-10` | Prefer `1` for production retries and billing attribution. |
|
||||
| `size` | `auto` or valid `WxH` | Common: `1024x1024`, `1536x1024`, `1024x1536`, `3840x2160`. |
|
||||
| `quality` | `low`, `medium`, `high`, `auto` | Use `low` for drafts, `medium` for normal, `high` for final. |
|
||||
| `output_format` | `png`, `jpeg`, `webp` | `jpeg` is usually faster than `png`. |
|
||||
| `output_compression` | `0-100` | Applies to `jpeg` and `webp`. |
|
||||
| `background` | `auto`, `opaque` | `gpt-image-2` does not support `transparent`. |
|
||||
| `moderation` | `auto`, `low` | Changes filter strictness but does not bypass policy. |
|
||||
| `stream` | boolean | Enables SSE image events. |
|
||||
| `partial_images` | `0-3` | Streaming only; each partial image adds output token cost. |
|
||||
| `user` | string | End-user identifier for abuse monitoring. |
|
||||
|
||||
## Size Constraints
|
||||
|
||||
- Maximum edge length: `3840px`.
|
||||
- Both edges must be multiples of `16px`.
|
||||
- Long edge to short edge ratio must be at most `3:1`.
|
||||
- Total pixels must be between `655360` and `8294400`.
|
||||
- Outputs larger than `2560x1440` should be treated as high-latency experimental outputs.
|
||||
|
||||
## Edit Notes
|
||||
|
||||
- Use multipart form data.
|
||||
- Send reference images as `image[]`.
|
||||
- Optional `mask` must match input image format and dimensions, be under 50MB, and include an alpha channel.
|
||||
- Omit `input_fidelity` for `gpt-image-2`.
|
||||
|
||||
## Response Shape
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"b64_json": "...",
|
||||
"revised_prompt": "..."
|
||||
}
|
||||
],
|
||||
"model": "gpt-image-2",
|
||||
"size": "1024x1024",
|
||||
"quality": "medium",
|
||||
"output_format": "png",
|
||||
"usage": {
|
||||
"input_tokens": 43,
|
||||
"output_tokens": 196,
|
||||
"total_tokens": 239
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Always decode `data[0].b64_json` unless streaming.
|
||||
|
||||
## Production Dispatch
|
||||
|
||||
- Prefer plus/team/pro upstream OpenAI OAuth accounts for image workloads.
|
||||
- Set client timeout to `120s` for normal images and `300s` for 4K.
|
||||
- Retry only transient network/5xx failures with low retry counts.
|
||||
- Do not retry policy or validation errors without changing the prompt or params.
|
||||
- Log `usage`, latency, size, quality, output format, account ID, API key ID, and request ID.
|
||||
|
||||
## Valid curl Template
|
||||
|
||||
```bash
|
||||
curl -sS "$BASE_URL/images/generations" \
|
||||
-H "Authorization: Bearer $API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
--max-time 300 \
|
||||
-d '{
|
||||
"model": "gpt-image-2",
|
||||
"prompt": "A premium product poster for an AI service",
|
||||
"size": "1536x1024",
|
||||
"quality": "medium",
|
||||
"output_format": "png",
|
||||
"n": 1
|
||||
}' > image.json
|
||||
```
|
||||
|
||||
Decode:
|
||||
|
||||
```bash
|
||||
jq -r '.data[0].b64_json' image.json | base64 --decode > image.png
|
||||
```
|
||||
|
||||
123
skills/sub2api-gpt-image-2/scripts/generate_image.py
Executable file
123
skills/sub2api-gpt-image-2/scripts/generate_image.py
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate an image with gpt-image-2 through an OpenAI-compatible /v1/images/generations endpoint."
|
||||
)
|
||||
parser.add_argument("--base-url", default=os.environ.get("BASE_URL", "https://claude.omniclaw.store/v1"))
|
||||
parser.add_argument("--api-key-env", default="API_KEY")
|
||||
parser.add_argument("--prompt", required=True)
|
||||
parser.add_argument("--output", default="image.png")
|
||||
parser.add_argument("--model", default="gpt-image-2")
|
||||
parser.add_argument("--size", default="1024x1024")
|
||||
parser.add_argument("--quality", default="medium", choices=["low", "medium", "high", "auto"])
|
||||
parser.add_argument("--format", default="png", choices=["png", "jpeg", "webp"])
|
||||
parser.add_argument("--compression", type=int, default=None)
|
||||
parser.add_argument("--background", default=None, choices=["auto", "opaque"])
|
||||
parser.add_argument("--moderation", default=None, choices=["auto", "low"])
|
||||
parser.add_argument("--n", type=int, default=1)
|
||||
parser.add_argument("--timeout", type=float, default=300.0)
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def build_payload(args: argparse.Namespace) -> dict:
|
||||
payload = {
|
||||
"model": args.model,
|
||||
"prompt": args.prompt,
|
||||
"size": args.size,
|
||||
"quality": args.quality,
|
||||
"output_format": args.format,
|
||||
"n": args.n,
|
||||
}
|
||||
if args.compression is not None:
|
||||
payload["output_compression"] = args.compression
|
||||
if args.background:
|
||||
payload["background"] = args.background
|
||||
if args.moderation:
|
||||
payload["moderation"] = args.moderation
|
||||
return payload
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
payload = build_payload(args)
|
||||
url = args.base_url.rstrip("/") + "/images/generations"
|
||||
|
||||
if args.dry_run:
|
||||
print(json.dumps({"url": url, "payload": payload}, ensure_ascii=False, indent=2))
|
||||
return 0
|
||||
|
||||
api_key = os.environ.get(args.api_key_env)
|
||||
if not api_key:
|
||||
print(f"Missing API key env: {args.api_key_env}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=body,
|
||||
method="POST",
|
||||
headers={
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
started = time.monotonic()
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=args.timeout) as resp:
|
||||
status = resp.status
|
||||
raw = resp.read()
|
||||
except urllib.error.HTTPError as exc:
|
||||
raw = exc.read()
|
||||
print(f"HTTP {exc.code}", file=sys.stderr)
|
||||
print(raw.decode("utf-8", "replace")[:4000], file=sys.stderr)
|
||||
return 1
|
||||
except Exception as exc:
|
||||
print(f"request failed: {type(exc).__name__}: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
elapsed = time.monotonic() - started
|
||||
data = json.loads(raw.decode("utf-8"))
|
||||
if "error" in data:
|
||||
print(json.dumps(data["error"], ensure_ascii=False), file=sys.stderr)
|
||||
return 1
|
||||
|
||||
items = data.get("data") or []
|
||||
if not items or "b64_json" not in items[0]:
|
||||
print("No b64_json image returned", file=sys.stderr)
|
||||
print(json.dumps(data, ensure_ascii=False)[:4000], file=sys.stderr)
|
||||
return 1
|
||||
|
||||
image = base64.b64decode(items[0]["b64_json"])
|
||||
with open(args.output, "wb") as f:
|
||||
f.write(image)
|
||||
|
||||
summary = {
|
||||
"status": status,
|
||||
"elapsed_seconds": round(elapsed, 3),
|
||||
"output": args.output,
|
||||
"bytes": len(image),
|
||||
"model": data.get("model"),
|
||||
"size": data.get("size"),
|
||||
"quality": data.get("quality"),
|
||||
"output_format": data.get("output_format"),
|
||||
"usage": data.get("usage"),
|
||||
}
|
||||
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
||||
11
skills/sub2api-gpt-image-2/skill.registry.json
Normal file
11
skills/sub2api-gpt-image-2/skill.registry.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "sub2api-gpt-image-2",
|
||||
"version": "0.1.0",
|
||||
"title": "Sub2API GPT Image 2",
|
||||
"description": "Generate, edit, stream, and troubleshoot GPT Image 2 calls through sub2api/OpenAI-compatible image APIs.",
|
||||
"tags": ["sub2api", "openai", "gpt-image-2", "images", "responses", "codex"],
|
||||
"agents": ["codex", "openai-compatible-agent"],
|
||||
"api_docs": ["sub2api/gpt-image-2.zh", "sub2api/gpt-image-2.en"],
|
||||
"updated_at": "2026-04-24"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user