Skill: pinke/opencode-free-models (version 1.0.0)

--- title: "OpenCode Free Models" summary: "配置 opencode.ai 免费模型到 OpenClaw/QClaw" read_when: - 用户需要免费 AI 模型 - 用户提到"opencode"、"opencode 免费"、"free model" --- # OpenCode Free Models 自动配置 opencode.ai 的免费 AI 模型到 OpenClaw/QClaw。 ## 触发词 - "配置 opencode 免费模型" - "添加 opencode 模型" - "opencode 免费" - "free model" ## 功能 1. **查询免费模型**: 从 opencode.ai API 获取可用免费模型 2. **自动配置**: 将模型添加到 `~/.openclaw/openclaw.json` (或 `~/.qclaw/openclaw.json`) 3. **增量更新**: 只添加新模型,跳过已存在的 ## 使用方式 AI 工具会自动执行以下步骤: 1. 查询模型列表: `curl -sS https://opencode.ai/zen/v1/models` 2. 筛选免费模型 (包含 "free" 的模型 ID) 3. 读取现有配置: `~/.openclaw/openclaw.json` 4. 将免费模型添加到 `models.providers` 配置中 5. 使用公开凭据 "public" 作为 API Key ## 模型配置格式 ```json { "opencode-free": { "baseUrl": "https://opencode.ai/zen/v1", "apiKey": "public", "api": "openai-completions", "models": [ { "id": "minimax-m2.5-free", "name": "MiniMax M2.5 Free", "reasoning": true, "input": ["text"], "cost": { "input": 0, "output": 0 }, "contextWindow": 131072, "maxTokens": 8192 } ] } } ``` ## 注意事项 - **无需 API Key**: 使用公开的 "public" 作为凭据 - **免费模型**: 包含 "free" 关键词的模型 - **端点**: https://opencode.ai/zen/v1/chat/completions - **配置文件**: ~/.openclaw/openclaw.json 或 ~/.qclaw/openclaw.json

path: README.md
content: # OpenCode Free Models

自动配置 opencode.ai 免费 AI 模型到 OpenClaw/QClaw。

## 快速使用

```
配置 opencode 免费模型
```

OpenClaw 会自动:
1. 从 opencode.ai 获取免费模型列表
2. 添加到 ~/.openclaw/openclaw.json
3. 使用 "public" 作为 API Key

## 支持的免费模型

| 模型 | 推理 | 上下文 |
|------|------|--------|
| minimax-m2.5-free | ✅ | 131K |
| trinity-large-preview-free | ✅ | - |
| nemotron-3-super-free | ✅ | - |

## 手动运行

```bash
python3 scripts/configure-models.py
```

## 配置文件位置

- OpenClaw: ~/.openclaw/openclaw.json
- QClaw: ~/.qclaw/openclaw.json

## 仓库

- GitHub: https://github.com/pinke/opencode-free-models-skills
- ClawHub: https://clawhub.ai/skill/opencode-free-models

path: scripts/configure-models.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
OpenCode Free Models - 自动配置 opencode.ai 免费模型到 OpenClaw/QClaw
"""

import json
import os
import ssl
import urllib.request
import urllib.error
from pathlib import Path


OPENCLAW_PATH = Path.home() / ".openclaw" / "openclaw.json"
QCLAW_PATH = Path.home() / ".qclaw" / "openclaw.json"
OPENCODEL_API = "https://opencode.ai/zen/v1/models"


def get_models_file():
    """获取配置文件路径"""
    if OPENCLAW_PATH.exists():
        return OPENCLAW_PATH
    elif QCLAW_PATH.exists():
        return QCLAW_PATH
    else:
        return OPENCLAW_PATH


def fetch_free_models():
    """从 opencode.ai 获取免费模型"""
    try:
        req = urllib.request.Request(OPENCODEL_API)
        req.add_header("User-Agent", "OpenClaw-Free-Models/1.0")
        
        context = ssl.create_default_context()
        
        with urllib.request.urlopen(req, timeout=10, context=context) as response:
            data = json.loads(response.read().decode("utf-8"))
        
        free_models = []
        for m in data.get("data", []):
            model_id = m.get("id", "")
            if "free" in model_id.lower():
                free_models.append({
                    "id": model_id,
                    "name": m.get("name", model_id),
                    "reasoning": m.get("reasoning", False),
                    "input": m.get("input", ["text"]),
                    "contextWindow": m.get("max_tokens", 131072),
                    "maxTokens": 8192,
                    "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}
                })
        
        return free_models
    
    except Exception as e:
        print(f"❌ 获取模型失败: {e}")
        return []


def load_config(config_file):
    """加载现有配置"""
    if not config_file.exists():
        return {"models": {"providers": {}}}
    
    try:
        with open(config_file, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception as e:
        print(f"❌ 加载配置失败: {e}")
        return {"models": {"providers": {}}}


def save_config(config_file, config):
    """保存配置"""
    try:
        config_file.parent.mkdir(parents=True, exist_ok=True)
        with open(config_file, "w", encoding="utf-8") as f:
            json.dump(config, f, indent=2, ensure_ascii=False)
        print(f"✅ 配置已保存: {config_file}")
        return True
    except Exception as e:
        print(f"❌ 保存配置失败: {e}")
        return False


def add_models(config_file, free_models):
    """添加免费模型到配置"""
    config = load_config(config_file)
    
    if "models" not in config:
        config["models"] = {}
    if "providers" not in config["models"]:
        config["models"]["providers"] = {}
    
    provider_key = "opencode-free"
    if provider_key not in config["models"]["providers"]:
        config["models"]["providers"][provider_key] = {
            "baseUrl": "https://opencode.ai/zen/v1",
            "apiKey": "public",
            "api": "openai-completions",
            "models": []
        }
    
    existing_ids = {m["id"] for m in config["models"]["providers"][provider_key].get("models", [])}
    
    added_count = 0
    for model in free_models:
        if model["id"] not in existing_ids:
            config["models"]["providers"][provider_key]["models"].append(model)
            added_count += 1
            print(f"✅ 添加: {model['id']}")
    
    if added_count > 0:
        save_config(config_file, config)
    
    return added_count


def main():
    print("=" * 50)
    print("OpenCode Free Models 配置工具")
    print("=" * 50)
    
    config_file = get_models_file()
    print(f"📁 配置文件: {config_file}")
    
    print("🔍 正在查询 opencode.ai 免费模型...")
    free_models = fetch_free_models()
    
    if not free_models:
        print("❌ 未找到免费模型")
        return 1
    
    print(f"✅ 找到 {len(free_models)} 个免费模型:")
    for m in free_models:
        print(f"   - {m['id']}")
    
    added = add_models(config_file, free_models)
    print(f"\n✨ 新增模型: {added}")
    
    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

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