Skill: pippo1980/qverisai-1-0-1 (version 1.0.0)

--- name: qverisai description: Search and execute dynamic tools via QVeris API. Use when needing to find and call external APIs/tools dynamically — covers weather, search, stocks, finance, economics, geolocation, AIGC, news, social media, health data, and thousands more. Requires QVERIS_API_KEY environment variable. env: - QVERIS_API_KEY requirements: env_vars: - QVERIS_API_KEY credentials: primary: QVERIS_API_KEY scope: read-only endpoint: https://qveris.ai/api/v1 auto_invoke: true source: https://qveris.ai examples: - "Show me current weather in Tokyo" - "Search for latest tech news" - "Check Tesla stock price" - "Analyze Apple's financial data" - "What is the US GDP growth rate" - "Generate an image of a sunset over mountains" - "Get trending topics on Twitter" - "Find clinical trials for diabetes treatment" --- # QVeris Tool Search & Execution QVeris provides dynamic tool discovery and execution - search for tools by capability, then execute them with parameters. ## Setup Requires environment variable: - `QVERIS_API_KEY` - Get from https://qveris.ai No additional dependencies — uses Node.js built-in `fetch`. ## Security - **Credential**: Only `QVERIS_API_KEY` is accessed. No other env vars or secrets are read. - **Network**: API key is sent only to `https://qveris.ai/api/v1` over HTTPS. No other endpoints are contacted. - **Storage**: The key is never logged, cached, or written to disk. - **Recommendation**: Use a scoped, revocable API key. Monitor usage at https://qveris.ai. ## Quick Start ### Search for tools ```bash node scripts/qveris_tool.mjs search "weather forecast API" ``` ### Execute a tool ```bash node scripts/qveris_tool.mjs execute openweathermap_current_weather --search-id <id> --params '{"city": "London", "units": "metric"}' ``` ## Script Usage ``` node scripts/qveris_tool.mjs <command> [options] Commands: search <query> Search for tools matching a capability description execute <tool_id> Execute a specific tool with parameters Options: --limit N Max results for search (default: 10) --search-id ID Search ID from previous search (required for execute) --params JSON Tool parameters as JSON string --max-size N Max response size in bytes (default: 20480) --timeout N Request timeout in seconds (default: 30 for search, 60 for execute) --json Output raw JSON instead of formatted display ``` ## Workflow 1. **Search**: Describe the capability needed (not specific parameters) - Good: "weather forecast API" - Bad: "get weather for London" 2. **Select**: Review tools by `success_rate` and `avg_execution_time` 3. **Execute**: Call tool with `tool_id`, `search_id`, and `parameters` ## Example Session ```bash # Find weather tools node scripts/qveris_tool.mjs search "current weather data" # Execute with returned tool_id and search_id node scripts/qveris_tool.mjs execute openweathermap_current_weather \ --search-id abc123 \ --params '{"city": "Tokyo", "units": "metric"}' ``` ## Use Cases - **Weather**: Get current weather, forecasts for any location - **Search**: Web search, information retrieval - **Stocks & Finance**: Query stock prices, historical data, earnings calendars - **Economics**: GDP, inflation rates, economic indicators - **Geolocation**: IP lookup, geocoding, reverse geocoding - **AIGC**: Image generation, text-to-speech, AI content creation - **News**: Headlines, article search, trending topics - **Social Media**: Trending topics, post analytics, engagement data - **Health Data**: Clinical trials, drug info, health statistics - **And more**: QVeris aggregates thousands of API tools

path: README.md
content: # QVeris Skill for OpenClaw

[中文文档](README.zh-CN.md) | English

A skill that enables OpenClaw to dynamically search and execute tools via the QVeris API.

## Features

- **Tool Discovery**: Search for APIs by describing what you need
- **Tool Execution**: Execute any discovered tool with parameters
- **Wide Coverage**: Access weather, stocks, search, currency, and thousands more APIs
- **Zero Extra Dependencies**: Uses only Node.js built-in `fetch` — no Python, no `uv`, no npm install

## Installation

### Prerequisites

- **Node.js 18+** (already present if you have OpenClaw installed)
- **QVERIS_API_KEY** — get your API key at https://qveris.ai

Set your API key:
```bash
export QVERIS_API_KEY="your-api-key-here"
```

### Install the Skill

**Option 1: Install via ClawdHub (Recommended)**
```bash
clawdhub install qveris
```

**Option 2: Install via NPX (For other coding agents)**
```bash
npx skills add hqman/qveris
```

**Option 3: Manual Installation**

Copy this folder to your OpenClaw skills directory:
```bash
cp -r qveris ~/.openclaw/skills/
```

## Usage

Once installed, OpenClaw will automatically use this skill when you ask questions about:
- Weather data
- Stock prices and market analysis
- Web searches
- Currency exchange rates
- And more...

### Manual Commands

```bash
# Search for tools
node scripts/qveris_tool.mjs search "stock price data"

# Execute a tool
node scripts/qveris_tool.mjs execute <tool_id> --search-id <id> --params '{"symbol": "AAPL"}'
```

## Author

[@hqmank](https://x.com/hqmank)

## License

MIT


path: _meta.json
content: ownerId: kn730nze617pqzzn1z0c7dknnd809yqp
slug: qverisai
version: 1.0.1
publishedAt: 1770977888436

path: scripts/qveris_tool.mjs
content: #!/usr/bin/env node
/**
 * QVeris Tool Search & Execution CLI
 *
 * Search for tools by capability and execute them via QVeris API.
 * Uses only Node.js built-in APIs (fetch) — zero external dependencies.
 *
 * Usage:
 *   node scripts/qveris_tool.mjs search "weather forecast"
 *   node scripts/qveris_tool.mjs execute <tool_id> --search-id <id> --params '{"city": "London"}'
 */

const BASE_URL = "https://qveris.ai/api/v1";

function getApiKey() {
  const key = process.env.QVERIS_API_KEY;
  if (!key) {
    console.error("Error: QVERIS_API_KEY environment variable not set");
    console.error("Get your API key at https://qveris.ai");
    process.exit(1);
  }
  return key;
}

async function searchTools(query, limit = 10, timeoutMs = 30000) {
  const [REDACTED_SECRET]);
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(`${BASE_URL}/search`, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ query, limit }),
      signal: controller.signal,
    });

    if (!response.ok) {
      const text = await response.text();
      console.error(`HTTP Error: ${response.status}`);
      console.error(text);
      process.exit(1);
    }

    return await response.json();
  } finally {
    clearTimeout(timeout);
  }
}

async function executeTool(toolId, searchId, parameters, maxResponseSize = 20480, timeoutMs = 60000) {
  const [REDACTED_SECRET]);
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const url = new URL(`${BASE_URL}/tools/execute`);
    url.searchParams.set("tool_id", toolId);

    const response = await fetch(url.toString(), {
      method: "POST",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        search_id: searchId,
        parameters,
        max_response_size: maxResponseSize,
      }),
      signal: controller.signal,
    });

    if (!response.ok) {
      const text = await response.text();
      console.error(`HTTP Error: ${response.status}`);
      console.error(text);
      process.exit(1);
    }

    return await response.json();
  } finally {
    clearTimeout(timeout);
  }
}

function displaySearchResults(result) {
  const searchId = result.search_id ?? "N/A";
  const tools = result.results ?? [];
  const total = result.total ?? tools.length;

  console.log(`\nSearch ID: ${searchId}`);
  console.log(`Found ${total} tools\n`);

  if (tools.length === 0) {
    console.log("No tools found.");
    return;
  }

  for (let i = 0; i < tools.length; i++) {
    const tool = tools[i];
    const toolId = tool.tool_id ?? "N/A";
    const name = tool.name ?? "N/A";
    const desc = tool.description ?? "N/A";

    const stats = tool.stats ?? {};
    let successRate = stats.success_rate ?? "N/A";
    let avgTime = stats.avg_execution_time_ms ?? "N/A";

    if (typeof successRate === "number") {
      successRate = `${Math.round(successRate * 100)}%`;
    }
    if (typeof avgTime === "number") {
      avgTime = `${avgTime.toFixed(1)}ms`;
    }

    console.log(`[${i + 1}] ${name}`);
    console.log(`    ID: ${toolId}`);
    console.log(`    ${desc.length > 100 ? desc.slice(0, 100) + "..." : desc}`);
    console.log(`    Success: ${successRate} | Avg Time: ${avgTime}`);

    const params = tool.params ?? [];
    if (params.length > 0) {
      const required = params.filter((p) => p.required).map((p) => p.name);
      const optional = params.filter((p) => !p.required).map((p) => p.name);
      if (required.length > 0) {
        console.log(`    Required: ${required.join(", ")}`);
      }
      if (optional.length > 0) {
        const shown = optional.slice(0, 5).join(", ");
        console.log(`    Optional: ${shown}${optional.length > 5 ? "..." : ""}`);
      }
    }

    const examples = tool.examples ?? {};
    if (examples.sample_parameters) {
      console.log(`    Example: ${JSON.stringify(examples.sample_parameters)}`);
    }

    console.log();
  }
}

function displayExecutionResult(result) {
  const success = result.success ?? false;
  const execTime = result.elapsed_time_ms ?? "N/A";
  const cost = result.cost ?? 0;

  console.log(`\n${success ? "Success" : "Failed"}`);
  console.log(`Time: ${execTime}ms | Cost: ${cost}`);

  if (!success) {
    const error = result.error_message ?? "Unknown error";
    console.log(`Error: ${error}`);
  }

  const data = result.result ?? {};
  if (Object.keys(data).length > 0) {
    console.log("\nResult:");
    console.log(JSON.stringify(data, null, 2));
  }
}

function printUsage() {
  console.log(`QVeris Tool Search & Execution CLI

Usage:
  node scripts/qveris_tool.mjs search <query> [options]
  node scripts/qveris_tool.mjs execute <tool_id> --search-id <id> [options]

Commands:
  search <query>     Search for tools matching a capability description
  execute <tool_id>  Execute a specific tool with parameters

Options:
  --limit N          Max results for search (default: 10)
  --search-id ID     Search ID from previous search (required for execute)
  --params JSON      Tool parameters as JSON string (default: "{}")
  --max-size N       Max response size in bytes (default: 20480)
  --timeout N        Request timeout in seconds (default: 30 for search, 60 for execute)
  --json             Output raw JSON instead of formatted display
  --help             Show this help message

Examples:
  node scripts/qveris_tool.mjs search "weather forecast API"
  node scripts/qveris_tool.mjs execute openweathermap_current_weather --search-id abc123 --params '{"city": "London"}'`);
}

function parseArgs(argv) {
  const args = argv.slice(2);

  if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
    printUsage();
    process.exit(0);
  }

  const command = args[0];
  const parsed = { command, json: false };

  if (command === "search") {
    if (args.length < 2) {
      console.error("Error: search command requires a query argument");
      process.exit(1);
    }
    parsed.query = args[1];
    parsed.limit = 10;
    parsed.timeout = 30;

    for (let i = 2; i < args.length; i++) {
      if (args[i] === "--limit" && i + 1 < args.length) {
        parsed.limit = parseInt(args[++i], 10);
      } else if (args[i] === "--timeout" && i + 1 < args.length) {
        parsed.timeout = parseInt(args[++i], 10);
      } else if (args[i] === "--json") {
        parsed.json = true;
      }
    }
  } else if (command === "execute") {
    if (args.length < 2) {
      console.error("Error: execute command requires a tool_id argument");
      process.exit(1);
    }
    parsed.toolId = args[1];
    parsed.searchId = null;
    parsed.params = "{}";
    parsed.maxSize = 20480;
    parsed.timeout = 60;

    for (let i = 2; i < args.length; i++) {
      if (args[i] === "--search-id" && i + 1 < args.length) {
        parsed.searchId = args[++i];
      } else if (args[i] === "--params" && i + 1 < args.length) {
        parsed.params = args[++i];
      } else if (args[i] === "--max-size" && i + 1 < args.length) {
        parsed.maxSize = parseInt(args[++i], 10);
      } else if (args[i] === "--timeout" && i + 1 < args.length) {
        parsed.timeout = parseInt(args[++i], 10);
      } else if (args[i] === "--json") {
        parsed.json = true;
      }
    }

    if (!parsed.searchId) {
      console.error("Error: --search-id is required for execute command");
      process.exit(1);
    }
  } else {
    console.error(`Error: unknown command '${command}'. Use 'search' or 'execute'.`);
    process.exit(1);
  }

  return parsed;
}

async function main() {
  const args = parseArgs(process.argv);

  try {
    if (args.command === "search") {
      const result = await searchTools(args.query, args.limit, args.timeout * 1000);
      if (args.json) {
        console.log(JSON.stringify(result, null, 2));
      } else {
        displaySearchResults(result);
      }
    } else if (args.command === "execute") {
      let params;
      try {
        params = JSON.parse(args.params);
      } catch (e) {
        console.error(`Invalid JSON in --params: ${e.message}`);
        process.exit(1);
      }
      const result = await executeTool(args.toolId, args.searchId, params, args.maxSize, args.timeout * 1000);
      if (args.json) {
        console.log(JSON.stringify(result, null, 2));
      } else {
        displayExecutionResult(result);
      }
    }
  } catch (e) {
    if (e.name === "AbortError") {
      console.error("Error: Request timed out");
    } else {
      console.error(`Error: ${e.message}`);
    }
    process.exit(1);
  }
}

main();


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