smithery.ai

add-driver

Scaffold a new LLM provider driver for Prompture.

First seen Mar 20, 2026

Installation

$ npx skills add https://smithery.ai

Summary

  • Scaffold a new LLM provider driver for Prompture.
  • Creates sync + async driver classes, registers them in the driver registry, adds settings, env template, setup.py extras, package exports, discovery integration, and models.dev pricing.
  • Use when adding support for a new LLM provider.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version2.0
Declared agents claude-code
More metadata
author
prompture
version
2.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,658 B
  • docs SUMMARY.md 301 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Add a New LLM Driver

Scaffolds all files needed to integrate a new LLM provider into Prompture.

Before Starting

Ask the user for:

  • Provider name (lowercase, used as registry key and provider/model prefix)
  • SDK package name on PyPI and minimum version (or requests/httpx for raw HTTP)
  • Default model ID
  • Authentication — API key env var name, endpoint URL, or both
  • API compatibility — OpenAI-compatible (/v1/chat/completions), custom SDK, or proprietary HTTP
  • Lazy or eager import — lazy if SDK is optional, eager if it's in install_requires

Also look up the provider on models.dev to determine:

  • models.dev provider name (e.g., "anthropic" for Claude, "xai" for Grok, "moonshotai" for Moonshot)
  • Whether models.dev has entries — if yes, pricing comes from models.dev live data (set MODELPRICING = {}). Either way, add a JSON rate file in prompture/infra/rates/ with model capabilities (tokensparam, supports_temperature, etc.).

Files to Create or Modify (11 total)

1. NEW: prompture/drivers/{provider}_driver.py (sync driver)

See [references/driver-template.md](references/driver-template.md) for the full skeleton.

Key rules:

  • Subclass CostMixin, Driver (NOT just Driver)
  • Set class-level capability flags: supportsjsonmode, supportsjsonschema, supportstooluse, supportsstreaming, supportsvision, supports_messages
  • Use self.getmodelconfig(provider, model) to get per-model tokensparam and supports_temperature from models.dev
  • Use self.calculatecost(provider, model, prompttokens, completiontokens) — do NOT manually compute costs
  • Use self.validatemodel_capabilities(provider, model, ...) before API calls to warn about unsupported features
  • Set MODEL_PRICING: dict[str, dict[str, Any]] = {} (always empty — pricing and config come from JSON rate files and models.dev)
  • Create a JSON rate file at prompture/infra/rates/{provider}.json with model capabilities
  • generate() returns {"text": str, "meta": dict}
  • meta MUST contain: prompttokens, completiontokens, totaltokens, cost, rawresponse, model_name
  • Implement generatemessages(), generatemessageswithtools(), and generatemessagesstream() for full feature support
  • Optional SDK: wrap import in try/except, raise ImportError pointing to pip install prompture[{provider}]

2. NEW: prompture/drivers/async{provider}driver.py (async driver)

Mirror of the sync driver using AsyncDriver base class:

  • Subclass CostMixin, AsyncDriver
  • Same capability flags as the sync driver
  • Share MODELPRICING from the sync driver: MODELPRICING = {Provider}Driver.MODEL_PRICING
  • Use httpx.AsyncClient for HTTP calls (or async SDK methods)
  • All generate methods are async def
  • Streaming returns AsyncIterator[dict[str, Any]]

3. prompture/drivers/init.py

  • Add sync import: from .{provider}_driver import {Provider}Driver
  • Add async import: from .async{provider}driver import Async{Provider}Driver
  • Register sync driver with register_driver():

``python registerdriver( "{provider}", lambda model=None: {Provider}Driver( apikey=settings.{provider}apikey, model=model or settings.{provider}_model, ), overwrite=True, ) ``

  • Add "{Provider}Driver" and "Async{Provider}Driver" to all

4. prompture/init.py

  • Add {Provider}Driver to the .drivers import line
  • Add "{Provider}Driver" to all under # Drivers

5. prompture/settings.py

Add inside Settings class:

# {Provider}
{provider}_api_key: Optional[str] = None
{provider}_model: str = "default-model"
# Add endpoint if the provider supports custom endpoints:
# {provider}_endpoint: str = "https://api.example.com/v1"

6. prompture/discovery.py

Two changes required:

a) Add to provider_classes dict and configuration check:

  • Import the driver class at the top of the file
  • Add to provider_classes: "{provider}": {Provider}Driver
  • Add configuration check in the is_configured block:

``python elif provider == "{provider}": if settings.{provider}apikey or os.getenv("{PROVIDER}APIKEY"): is_configured = True `` For local/endpoint-only providers (like ollama), use endpoint presence instead.

b) This ensures getavailablemodels() returns the provider's models from both:

  • Static detection: capabilities KB (JSON rate files) via getkbmodelsforprovider()
  • models.dev enrichment: via PROVIDERMAP in modelrates.py (see step 7)

7. prompture/modelrates.py — PROVIDERMAP

If models.dev has this provider's data, add the mapping:

PROVIDER_MAP: dict[str, str] = {
    ...
    "{provider}": "{models_dev_name}",  # e.g., "moonshot": "moonshotai"
}

This enables:

  • Live pricing via getmodelrates() — used by CostMixin.calculatecost()
  • Capability metadata via getmodelcapabilities() — used by getmodelconfig() and validatemodelcapabilities()
  • Model discovery via getallprovider_models() — called by discovery.py to list all available models

To find the correct models.dev name, check: https://models.dev/{modelsdevname}

If models.dev does NOT have this provider, skip this step. The driver will use hardcoded MODEL_PRICING for costs and return None for capabilities.

8. setup.py / pyproject.toml

If optional: add "{provider}": ["{sdk}>={version}"] to extrasrequire. If required: add to installrequires.

9. .env.copy

Add section:

# {Provider} Configuration
{PROVIDER}_API_KEY=your-api-key-here
{PROVIDER}_MODEL=default-model

10. CLAUDE.md

Add {provider} to the driver list in the Module Layout bullet.

11. OPTIONAL: examples/{provider}_example.py

Follow the existing example pattern (see grokexample.py or groqexample.py):

  • Two extraction examples: default instruction + custom instruction
  • Show different models if available
  • Print JSON output and token usage statistics

Important: Reasoning Model Handling

If the provider has reasoning models (models with reasoning: true on models.dev):

  • Check caps.isreasoning before sending responseformat — reasoning models often don't support it
  • Handle reasoning_content field in responses (both regular and streaming)
  • Some reasoning models don't support temperature — respect supportstemperature from getmodelconfig()

Example pattern (see moonshot_driver.py):

if options.get("json_mode"):
    from ..model_rates import get_model_capabilities

    caps = get_model_capabilities("{provider}", model)
    is_reasoning = caps is not None and caps.is_reasoning is True
    model_supports_structured = (
        caps is None or caps.supports_structured_output is not False
    ) and not is_reasoning

    if model_supports_structured:
        # Send response_format
        ...

How models.dev Integration Works

User calls extract_and_jsonify("moonshot/kimi-k2.5", ...)
    │
    ├─► core.py checks driver.supports_json_mode → decides json_mode
    │
    ├─► driver._get_model_config("moonshot", "kimi-k2.5")
    │       └─► model_rates.get_model_capabilities("moonshot", "kimi-k2.5")
    │               └─► PROVIDER_MAP["moonshot"] → "moonshotai"
    │               └─► models.dev data["moonshotai"]["models"]["kimi-k2.5"]
    │               └─► Returns: supports_temperature, is_reasoning, context_window, etc.
    │
    ├─► driver._calculate_cost("moonshot", "kimi-k2.5", tokens...)
    │       └─► model_rates.get_model_rates("moonshot", "kimi-k2.5")
    │               └─► Same lookup → returns {input: 0.6, output: 3.0} per 1M tokens
    │
    └─► discovery.get_available_models()
            └─► Iterates PROVIDER_MAP → get_all_provider_models("moonshotai")
            └─► Returns all model IDs under the provider

Model Name Resolution

Model names are always provider-scoped. The format is "provider/model_id".

  • getdriverfor_model("openrouter/qwen-2.5") → looks up "openrouter" in the driver registry
  • getmodelcapabilities("openrouter", "qwen-2.5") → looks in models.dev under data["openrouter"]["models"]["qwen-2.5"]
  • getmodelcapabilities("modelscope", "qwen-2.5") → looks in models.dev under data["modelscope"]["models"]["qwen-2.5"]

The same model ID under different providers is not ambiguous — each provider has its own namespace in both the driver registry and models.dev data.

Verification

# Import check
python -c "from prompture import {Provider}Driver; print('OK')"
python -c "from prompture.drivers import Async{Provider}Driver; print('OK')"

# Registry check
python -c "from prompture.drivers import get_driver_for_model; d = get_driver_for_model('{provider}/test'); print(type(d).__name__, d.model)"

# Discovery check
python -c "from prompture import get_available_models; ms = [m for m in get_available_models() if m.startswith('{provider}/')]; print(f'Found {{len(ms)}} models'); print(ms[:5])"

# Run tests
pytest tests/ -x -q