Skill: qidu/free-models-for-openclaw (version 0.3.0)

name: free-models alias: - free-models-for-openclaw - free-models-of-openclaw - free-models-for-agents description: Discover free/cheap models from OpenRouter for AI agents (e.g. OpenClaw). Includes model discovery, filtering, and easy model selection for openclaw and other agent workflows. metadata: version: 0.2.0 homepage: https://openrouter.ai --- # free-models-for-agent Discover free, cheap, and high-value models from OpenRouter for your OpenClaw and other AI agents. ## Usage ### Find free models ```javascript import { discoverFreeModels } from './scripts/free-models.js'; const models = await discoverFreeModels(); // Returns models with $0.00 or very low pricing ``` ### Filter by criteria ```javascript import { filterModels } from './scripts/free-models.js'; // High context + low price (best for tool calling) const models = await filterModels({ minContext: 200000, // 200k+ tokens maxPromptPrice: 0.00001 // Under $0.00001/1M tokens }); // Specific provider only const openaiModels = await filterModels({ author: 'openai', minContext: 100000 }); // Name contains filter const flashModels = await filterModels({ author: 'google', nameContains: 'flash' }); // All filters combined const cheapGoogle = await filterModels({ author: 'google', minContext: 500000, maxPromptPrice: 0.000001 }); ``` ### Get best free model for agent ```javascript import { getBestFreeModel } from './scripts/free-models.js'; // Best overall (highest context) const bestModel = await getBestFreeModel(); // Best for reasoning tasks const reasoningModel = await getBestFreeModel({ needReasoning: true, }); // Best for tool calling (high context is key) const toolModel = await getBestFreeModel({ preferReasoning: true, maxPrice: 0.00001 }); // Best for vision tasks const visionModel = await getBestFreeModel({ needVision: true, }); ``` ## CLI Usage User should register and get a access key from [https://openrouter.ai/settings/keys](https://openrouter.ai/settings/keys) Openclaw should export the key (or string with a prefix "sk-or-") as the value of Environment Variable `OPENROUTER_API_KEY` before calling the cli. ```bash export OPENROUTER_API_KEY="sk-or-v1-..." node scripts/free-models.js ``` ## Common Free Models | Model | Context | Price | Best For | |-------|---------|-------|----------| | x-ai/grok-4.1-fast | 2M | $0.0000002/1M | Tool calling, agents | | openai/gpt-5.4 | 1M | $0.0000025/1M | General purpose | | google/gemini-3.1-flash-lite | 1M | $0.00000025/1M | Fast/cheap tasks | | google/gemini-2.5-flash | 1M | $0.0000003/1M | Tool calling | | qwen/qwen3.5-flash-02-23 | 1M | $0.0000001/1M | Budget option | ## API Reference ### fetchAllModels() Returns all available models from OpenRouter. ### discoverFreeModels() Filters and returns only models with $0 or very low pricing (< $0.0001/1M). ### filterModels(options) Filters models by: - `maxPromptPrice`: Maximum prompt price per 1M tokens - `minContext`: Minimum context window (tokens) - `author` or `provider`: Model provider (e.g., 'anthropic', 'openai', 'google', 'deepseek', 'minimax', 'kimi', 'z.ai') - `maxCompletionPrice`: Maximum completion price per 1M tokens - `nameContains`: Filter by name substring ### getBestFreeModel(options) Returns the best free model based on: - `needReasoning`: Requires strong reasoning capability - `preferReasoning`: Prefers models with reasoning - `needVision`: Requires vision capabilities - `maxPrice`: Maximum price threshold ### getModelsByAuthor(author) Returns all models from a specific provider. ### getCheapestModels(limit) Returns the cheapest models (default: 10). ## Resources - OpenRouter Models: https://openrouter.ai/models - Models API: https://openrouter.ai/api/v1/models

path: package.json
content: {
  "name": "free-models-for-agent",
  "version": "0.2.1",
  "description": "Discover and use free/cheap models from OpenRouter for AI agents (e.g. OpenClaw). Includes model discovery, filtering, and easy model selection for agent workflows.",
  "main": "scripts/free-models.js",
  "type": "module",
  "scripts": {
    "start": "node scripts/free-models.js",
    "test": "node scripts/free-models.js"
  },
  "keywords": [
    "free-models",
    "tool-calling",
    "openrouter",
    "ai-agents",
    "model-discovery"
  ],
  "author": "qidu",
  "license": "MIT",
  "homepage": "https://openrouter.ai",
  "repository": {
    "type": "git",
    "url": "https://github.com/openclaw/openclaw"
  },
  "engines": {
    "node": ">=18.0.0"
  },
  "dependencies": {},
  "devDependencies": {},
  "bugs": {
    "url": "https://github.com/openclaw/openclaw/issues"
  }
}


path: scripts/free-models.js
content: /**
 * Free Models Discovery for OpenRouter
 * Discover and use free/cheap models for AI agents
 * 
 * Usage:
 *   node free-models.js
 * 
 * Environment:
 *   OPENROUTER_API_KEY - Your OpenRouter API key (required)
 */

/** @type {string|null} */
const [REDACTED_SECRET] || null;

/**
 * Fetch all available models from OpenRouter
 * @returns {Promise<Array>}
 */
async function fetchAllModels() {
  const res = await fetch('https://openrouter.ai/api/v1/models');
  if (!res.ok) {
    throw new Error(`Failed to fetch models: ${res.statusText}`);
  }
  const data = await res.json();
  
  return data.data.map((m) => ({
    id: m.id,
    name: m.name,
    description: m.description,
    context_length: m.context_length,
    pricing: m.pricing,
    top_provider: m.top_provider,
    author: m.id.split('/')[0],
  }));
}

/**
 * Discover models with free or near-free pricing
 * @returns {Promise<Array>}
 */
async function discoverFreeModels() {
  const models = await fetchAllModels();
  return models.filter((m) => {
    const promptPrice = parseFloat(m.pricing.prompt);
    return promptPrice === 0 || promptPrice < 0.0001;
  });
}

/**
 * Filter models by various criteria
 * @param {Object} filter
 * @returns {Promise<Array>}
 */
async function filterModels(filter = {}) {
  let models = await fetchAllModels();
  
  if (filter.maxPromptPrice !== undefined) {
    models = models.filter((m) => {
      const price = parseFloat(m.pricing.prompt);
      return price <= filter.maxPromptPrice;
    });
  }
  
  if (filter.minContext !== undefined) {
    models = models.filter((m) => m.context_length >= filter.minContext);
  }
  
  if (filter.author) {
    models = models.filter((m) => m.author === filter.author);
  }
  
  if (filter.maxCompletionPrice !== undefined) {
    models = models.filter((m) => {
      const price = parseFloat(m.pricing.completion);
      return price <= filter.maxCompletionPrice;
    });
  }
  
  if (filter.nameContains) {
    models = models.filter((m) =>
      m.name.toLowerCase().includes(filter.nameContains.toLowerCase())
    );
  }
  
  return models;
}

/**
 * Get the best free model based on specific requirements
 * @param {Object} options
 * @returns {Promise<Object|null>}
 */
async function getBestFreeModel(options = {}) {
  let models = await discoverFreeModels();
  
  // Sort by context length (more context is better by default)
  models.sort((a, b) => b.context_length - a.context_length);
  
  // Filter for specific capabilities
  if (options.needVision) {
    const visionKeywords = ['vision', 'multimodal', 'see', 'image'];
    models = models.filter((m) =>
      visionKeywords.some((kw) =>
        m.name.toLowerCase().includes(kw) || m.id.includes(kw)
      )
    );
  }
  
  if (options.needReasoning || options.preferReasoning) {
    models = models.filter((m) =>
      m.context_length >= 100000 ||
      m.name.toLowerCase().includes('reasoning') ||
      m.name.toLowerCase().includes('opus') ||
      m.name.toLowerCase().includes('sonnet')
    );
  }
  
  if (options.maxPrice !== undefined) {
    models = models.filter((m) => {
      const price = parseFloat(m.pricing.prompt);
      return price <= options.maxPrice;
    });
  }
  
  return models[0] || null;
}

/**
 * Get models by specific author/provider
 * @param {string} author
 * @returns {Promise<Array>}
 */
async function getModelsByAuthor(author) {
  return filterModels({ author });
}

/**
 * Get the cheapest models regardless of capabilities
 * @param {number} [limit=10]
 * @returns {Promise<Array>}
 */
async function getCheapestModels(limit = 10) {
  const models = await fetchAllModels();
  
  return models
    .filter((m) => parseFloat(m.pricing.prompt) > 0)
    .sort((a, b) => parseFloat(a.pricing.prompt) - parseFloat(b.pricing.prompt))
    .slice(0, limit);
}

/**
 * Format model info for display
 * @param {Object} model
 * @returns {string}
 */
function formatModel(model) {
  const promptPrice = parseFloat(model.pricing.prompt);
  const completionPrice = parseFloat(model.pricing.completion);
  
  return `
  ${model.name}
    ID: ${model.id}
    Context: ${model.context_length.toLocaleString()} tokens
    Pricing: $${promptPrice}/1M prompt | $${completionPrice}/1M completion
    ${model.description ? `\n    ${model.description}` : ''}
  `.trim();
}

/**
 * Main CLI execution
 */
async function main() {
  if (!API_KEY) {
    console.error('❌ Error: Set OPENROUTER_API_KEY environment variable');
    console.error('   Example: export OPENROUTER_API_KEY="sk-or-v1-..."');
    process.exit(1);
  }
  
  console.log('🔍 Fetching models from OpenRouter...\n');
  
  try {
    const freeModels = await discoverFreeModels();
    
    console.log(`🆓 Found ${freeModels.length} free/near-free models:\n`);
    
    if (freeModels.length === 0) {
      console.log('   No free models found. Checking cheap models...\n');
      const cheapModels = await getCheapestModels(10);
      cheapModels.forEach((m) => {
        const price = parseFloat(m.pricing.prompt);
        console.log(`  • ${m.name} - $${price}/1M tokens (${m.context_length.toLocaleString()} ctx)`);
        console.log(`    ${m.id}`);
        console.log();
      });
    } else {
      freeModels.slice(0, 20).forEach((m) => {
        const price = parseFloat(m.pricing.prompt);
        console.log(`  • ${m.name}`);
        console.log(`    ${m.id}`);
        console.log(`    Context: ${m.context_length.toLocaleString()} tokens`);
        if (price > 0) {
          console.log(`    Price: $${price}/1M tokens`);
        } else {
          console.log(`    Price: FREE`);
        }
        console.log();
      });
      
      if (freeModels.length > 20) {
        console.log(`  ... and ${freeModels.length - 20} more`);
      }
    }
    
    console.log('\n📊 Best free model for agents:');
    const best = await getBestFreeModel();
    if (best) {
      console.log(formatModel(best));
    }
    
    console.log('\n🏆 Cheapest models:');
    const cheap = await getCheapestModels(5);
    cheap.forEach((m) => {
      const p = parseFloat(m.pricing.prompt);
      console.log(`  ${m.name}: $${p}/1M tokens`);
    });
    
  } catch (error) {
    console.error('Error fetching models:', error.message);
    process.exit(1);
  }
}

// Export functions for ES modules
export {
  fetchAllModels,
  discoverFreeModels,
  filterModels,
  getBestFreeModel,
  getModelsByAuthor,
  getCheapestModels,
  formatModel,
};

// Run CLI if executed directly (ESM compatible)
const isMain = process.argv[1]?.endsWith('free-models.js');
if (isMain) {
  main();
}


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