diff --git a/model_tools.py b/model_tools.py index c8682dacb..cc2cea9c9 100644 --- a/model_tools.py +++ b/model_tools.py @@ -95,6 +95,7 @@ def _discover_tools(): "tools.send_message_tool", "tools.honcho_tools", "tools.homeassistant_tool", + "tools.infsh_tool", ] import importlib for mod_name in _modules: diff --git a/skills/inference-sh/DESCRIPTION.md b/skills/inference-sh/DESCRIPTION.md new file mode 100644 index 000000000..a4b2aa91c --- /dev/null +++ b/skills/inference-sh/DESCRIPTION.md @@ -0,0 +1,23 @@ +# inference.sh + +Run 150+ AI applications in the cloud via the [inference.sh](https://inference.sh) platform. + +**One API key for everything** - Access all AI services with a single account. No need to manage separate API keys for FLUX, Veo, Claude, Tavily, Twitter, etc. You can also bring your own keys if you prefer. + +## Available Skills + +- **cli**: The inference.sh CLI (`infsh`) for running AI apps + +## What's Included + +- **Image Generation**: FLUX, Reve, Seedream, Grok Imagine, Gemini +- **Video Generation**: Veo, Wan, Seedance, OmniHuman, HunyuanVideo +- **LLMs**: Claude, Gemini, Kimi, GLM-4 (via OpenRouter) +- **Search**: Tavily, Exa +- **3D**: Rodin +- **Social**: Twitter/X automation +- **Audio**: TTS, voice cloning + +## Tools + +This category provides the `infsh` and `infsh_install` tools in the `inference` toolset. diff --git a/skills/inference-sh/cli/SKILL.md b/skills/inference-sh/cli/SKILL.md new file mode 100644 index 000000000..67e33436e --- /dev/null +++ b/skills/inference-sh/cli/SKILL.md @@ -0,0 +1,372 @@ +--- +name: inference-sh-cli +description: "Run 150+ AI apps via inference.sh CLI (infsh) - image generation, video creation, LLMs, search, 3D, Twitter automation. Models: FLUX, Veo, Gemini, Grok, Claude, Seedance, OmniHuman, Tavily, Exa, OpenRouter. Triggers: inference.sh, infsh, ai apps, serverless ai, flux, veo, image generation, video generation" +version: 1.0.0 +author: inference.sh +license: MIT +metadata: + hermes: + tags: [AI, image-generation, video, LLM, search, inference, FLUX, Veo, Claude] + requires_tools: [infsh] +--- + +# inference.sh CLI + +Run 150+ AI apps in the cloud with a simple CLI. No GPU required. + +**One API key for everything** - Manage all AI services (FLUX, Veo, Claude, Tavily, X/Twitter, and more) with a single inference.sh account. No need to sign up for dozens of different providers. You can also bring your own API keys if you prefer. + +## Tools + +This skill is backed by the `infsh` and `infsh_install` tools: + +- **infsh**: Run any infsh command (app list, app run, etc.) +- **infsh_install**: Install the CLI if not already present + +## Quick Start + +```bash +# Install (if needed) +infsh_install + +# List available apps +infsh app list + +# Search for apps +infsh app list --search flux +infsh app list --search video + +# Run an app +infsh app run falai/flux-dev-lora --input '{"prompt": "a cat astronaut"}' --json +``` + +## Local File Uploads + +The CLI automatically uploads local files when you provide a file path instead of a URL: + +```bash +# Upscale a local image +infsh app run falai/topaz-image-upscaler --input '{"image": "/path/to/photo.jpg", "upscale_factor": 2}' --json + +# Image-to-video from local file +infsh app run falai/wan-2-5-i2v --input '{"image": "/path/to/image.png", "prompt": "make it come alive"}' --json + +# Video generation with local first frame +infsh app run bytedance/seedance-1-5-pro --input '{"prompt": "dancing figure", "image": "./first-frame.png"}' --json +``` + +## Image Generation + +```bash +# Gemini 2.5 Flash Image (Google) - fast, high quality +infsh app run google/gemini-2-5-flash-image --input '{"prompt": "futuristic city", "num_images": 1}' --json + +# Gemini 3 Pro Image Preview (Google) - latest model +infsh app run google/gemini-3-pro-image-preview --input '{"prompt": "photorealistic landscape"}' --json + +# Gemini 3.1 Flash Image Preview (Google) +infsh app run google/gemini-3-1-flash-image-preview --input '{"prompt": "artistic portrait"}' --json + +# FLUX Dev with LoRA support +infsh app run falai/flux-dev-lora --input '{"prompt": "sunset over mountains", "num_images": 1}' --json + +# FLUX 2 Klein with LoRA +infsh app run falai/flux-2-klein-lora --input '{"prompt": "portrait photo"}' --json + +# Reve - stylized generation and editing +infsh app run falai/reve --input '{"prompt": "cyberpunk city"}' --json + +# Seedream 5 Lite - high-quality 2K-3K (ByteDance) +infsh app run bytedance/seedream-5-lite --input '{"prompt": "nature scene"}' --json + +# Seedream 4.5 - 2K-4K images +infsh app run bytedance/seedream-4-5 --input '{"prompt": "detailed illustration"}' --json + +# Seedream 3.0 - cinematic quality +infsh app run bytedance/seedream-3-0-t2i --input '{"prompt": "fantasy landscape"}' --json + +# Grok Imagine - xAI image generation +infsh app run xai/grok-imagine-image --input '{"prompt": "abstract art"}' --json + +# Grok Imagine Pro - higher quality +infsh app run xai/grok-imagine-image-pro --input '{"prompt": "photorealistic portrait"}' --json + +# Qwen Image 2 Pro (Alibaba) +infsh app run alibaba/qwen-image-2-pro --input '{"prompt": "anime character"}' --json +``` + +## Video Generation + +```bash +# Veo 3.1 Fast (Google) +infsh app run google/veo-3-1-fast --input '{"prompt": "drone shot of coastline"}' --json + +# Veo 3.1 (higher quality) +infsh app run google/veo-3-1 --input '{"prompt": "cinematic scene"}' --json + +# Veo 3 Fast +infsh app run google/veo-3-fast --input '{"prompt": "nature documentary shot"}' --json + +# Veo 2 +infsh app run google/veo-2 --input '{"prompt": "slow motion water splash"}' --json + +# Grok Imagine Video - xAI +infsh app run xai/grok-imagine-video --input '{"prompt": "timelapse of clouds"}' --json + +# Seedance 1.5 Pro - ByteDance +infsh app run bytedance/seedance-1-5-pro --input '{"prompt": "dancing figure", "resolution": "1080p"}' --json + +# Seedance 1.0 Pro +infsh app run bytedance/seedance-1-0-pro --input '{"prompt": "walking through forest"}' --json + +# Seedance 1.0 Pro Fast +infsh app run bytedance/seedance-1-0-pro-fast --input '{"prompt": "quick motion"}' --json + +# Seedance 1.0 Lite - 720p lightweight +infsh app run bytedance/seedance-1-0-lite --input '{"prompt": "simple animation"}' --json + +# Wan 2.5 - text-to-video +infsh app run falai/wan-2-5 --input '{"prompt": "person walking through city"}' --json + +# Wan 2.5 Image-to-Video +infsh app run falai/wan-2-5-i2v --input '{"image": "/path/to/image.png", "prompt": "make it move naturally"}' --json + +# LTX Video +infsh app run infsh/ltx-video --input '{"prompt": "realistic scene"}' --json + +# Magi 1 +infsh app run infsh/magi-1 --input '{"prompt": "creative video"}' --json +``` + +## Avatar & Lipsync + +```bash +# OmniHuman 1.5 - multi-character audio-driven avatars +infsh app run bytedance/omnihuman-1-5 --input '{"audio": "/path/to/audio.mp3", "image": "/path/to/face.jpg"}' --json + +# OmniHuman 1.0 +infsh app run bytedance/omnihuman-1-0 --input '{"audio": "/path/to/speech.wav", "image": "/path/to/portrait.png"}' --json + +# Fabric 1.0 - image animation +infsh app run falai/fabric-1-0 --input '{"image": "/path/to/photo.jpg"}' --json + +# PixVerse Lipsync +infsh app run falai/pixverse-lipsync --input '{"audio": "/path/to/audio.mp3", "video": "/path/to/video.mp4"}' --json +``` + +## Upscaling + +```bash +# Topaz Image Upscaler - up to 4x +infsh app run falai/topaz-image-upscaler --input '{"image": "/path/to/photo.jpg", "upscale_factor": 2}' --json + +# Topaz Video Upscaler +infsh app run falai/topaz-video-upscaler --input '{"video": "/path/to/video.mp4"}' --json + +# Real-ESRGAN - image enhancement +infsh app run infsh/real-esrgan --input '{"image": "/path/to/image.jpg"}' --json + +# Thera - upscale to any size +infsh app run infsh/thera --input '{"image": "/path/to/image.jpg"}' --json +``` + +## LLMs (via OpenRouter) + +```bash +# Claude Opus 4.6 +infsh app run openrouter/claude-opus-46 --input '{"prompt": "Explain quantum computing"}' --json + +# Claude Sonnet 4.5 +infsh app run openrouter/claude-sonnet-45 --input '{"prompt": "Write a poem"}' --json + +# Claude Haiku 4.5 +infsh app run openrouter/claude-haiku-45 --input '{"prompt": "Quick question"}' --json + +# Gemini 3 Pro Preview +infsh app run openrouter/gemini-3-pro-preview --input '{"prompt": "Analyze this"}' --json + +# Kimi K2 Thinking +infsh app run openrouter/kimi-k2-thinking --input '{"prompt": "Solve this step by step"}' --json + +# GLM 4.6 +infsh app run openrouter/glm-46 --input '{"prompt": "Help me with"}' --json + +# MiniMax M2.5 +infsh app run openrouter/minimax-m-25 --input '{"prompt": "Creative writing"}' --json + +# Intellect 3 +infsh app run openrouter/intellect-3 --input '{"prompt": "Research question"}' --json +``` + +## Web Search + +```bash +# Tavily Search Assistant - comprehensive results +infsh app run tavily/search-assistant --input '{"query": "latest AI news", "include_answer": true}' --json + +# Tavily Extract - get content from URLs +infsh app run tavily/extract --input '{"urls": ["https://example.com"]}' --json + +# Exa Search - neural search +infsh app run exa/search --input '{"query": "machine learning tutorials"}' --json + +# Exa Answer - LLM-powered answers +infsh app run exa/answer --input '{"query": "what is transformers architecture"}' --json + +# Exa Extract - extract web content +infsh app run exa/extract --input '{"url": "https://example.com"}' --json +``` + +## 3D Generation + +```bash +# Rodin 3D Generator +infsh app run infsh/rodin-3d-generator --input '{"prompt": "a wooden chair"}' --json + +# HunyuanImage to 3D +infsh app run infsh/hunyuan-image-to-3d-2 --input '{"image": "/path/to/object.png"}' --json +``` + +## Text-to-Speech + +```bash +# Kokoro TTS - lightweight +infsh app run falai/kokoro-tts --input '{"text": "Hello, this is a test."}' --json + +# Dia TTS - realistic dialogue +infsh app run falai/dia-tts --input '{"text": "Two characters talking"}' --json +``` + +## Twitter/X Automation + +```bash +# Post a tweet +infsh app run x/post-tweet --input '{"text": "Hello from AI!"}' --json + +# Create post with media +infsh app run x/post-create --input '{"text": "Check this out", "media": "/path/to/image.jpg"}' --json + +# Send DM +infsh app run x/dm-send --input '{"recipient_id": "123456", "text": "Hi there!"}' --json + +# Follow user +infsh app run x/user-follow --input '{"user_id": "123456"}' --json + +# Like a post +infsh app run x/post-like --input '{"post_id": "123456789"}' --json + +# Retweet +infsh app run x/post-retweet --input '{"post_id": "123456789"}' --json + +# Get user profile +infsh app run x/user-get --input '{"username": "elonmusk"}' --json + +# Get post +infsh app run x/post-get --input '{"post_id": "123456789"}' --json + +# Delete post +infsh app run x/post-delete --input '{"post_id": "123456789"}' --json +``` + +## Utilities + +```bash +# Browser automation +infsh app run infsh/agent-browser --function open --session new --input '{"url": "https://example.com"}' --json + +# Media merger - combine videos/images +infsh app run infsh/media-merger --input '{"files": ["/path/to/video1.mp4", "/path/to/video2.mp4"]}' --json + +# Video audio extractor +infsh app run infsh/video-audio-extractor --input '{"video": "/path/to/video.mp4"}' --json + +# Video audio merger +infsh app run infsh/video-audio-merger --input '{"video": "/path/to/video.mp4", "audio": "/path/to/audio.mp3"}' --json + +# Caption videos +infsh app run infsh/caption-videos --input '{"video": "/path/to/video.mp4"}' --json + +# Stitch images +infsh app run infsh/stitch-images --input '{"images": ["/path/to/1.jpg", "/path/to/2.jpg"]}' --json + +# Python executor +infsh app run infsh/python-executor --input '{"code": "print(2+2)"}' --json + +# HTML to image +infsh app run infsh/html-to-image --input '{"html": "

Hello

"}' --json + +# NSFW detection +infsh app run infsh/falconsai-nsfw-detection --input '{"image": "/path/to/image.jpg"}' --json + +# Media analyzer +infsh app run infsh/media-analyzer --input '{"file": "/path/to/media.jpg"}' --json +``` + +## Common Patterns + +### Generate + Upscale Pipeline + +```bash +# Generate image, capture URL, then upscale +infsh app run falai/flux-dev-lora --input '{"prompt": "portrait photo"}' --json --save result.json + +# Extract URL and upscale (using jq) +IMG=$(cat result.json | jq -r '.images[0].url') +infsh app run falai/topaz-image-upscaler --input "{\"image\": \"$IMG\", \"upscale_factor\": 2}" --json +``` + +### Get App Schema + +```bash +# See what inputs an app accepts +infsh app get falai/flux-dev-lora + +# Generate sample input +infsh app sample falai/flux-dev-lora + +# Save sample to file, edit, then run +infsh app sample falai/flux-dev-lora --save input.json +# edit input.json... +infsh app run falai/flux-dev-lora --input input.json --json +``` + +### Long-running Tasks + +```bash +# Start without waiting +infsh app run google/veo-3-1 --input '{"prompt": "..."}' --no-wait + +# Check status later +infsh task get + +# Save result when done +infsh task get --save result.json +``` + +## Available Categories + +| Category | Apps | +|----------|------| +| **Image** | google/nano-banana, google/nano-banana-pro, google/nano-banana-2, falai/flux-dev-lora, bytedance/seedream-5-lite, falai/reve, xai/grok-imagine-image | +| **Video** | google/veo-*, xai/grok-imagine-video, bytedance/seedance-*, falai/wan-2-5*, infsh/ltx-video, infsh/magi-1 | +| **Avatar** | bytedance/omnihuman-*, falai/fabric-1-0, falai/pixverse-lipsync | +| **Upscale** | falai/topaz-image-upscaler, falai/topaz-video-upscaler, infsh/real-esrgan, infsh/thera | +| **LLMs** | openrouter/claude-*, openrouter/gemini-*, openrouter/kimi-*, openrouter/glm-* | +| **Search** | tavily/search-assistant, tavily/extract, exa/search, exa/answer, exa/extract | +| **3D** | infsh/rodin-3d-generator, infsh/hunyuan-image-to-3d-2 | +| **TTS** | falai/kokoro-tts, falai/dia-tts | +| **Social** | x/post-tweet, x/post-create, x/dm-send, x/user-follow, x/post-like, x/post-retweet | +| **Utils** | infsh/agent-browser, infsh/media-merger, infsh/caption-videos, infsh/stitch-images | + +## Reference Files + +- [Authentication & Setup](references/authentication.md) +- [Discovering Apps](references/app-discovery.md) +- [Running Apps](references/running-apps.md) +- [CLI Reference](references/cli-reference.md) + +## Documentation + +- [inference.sh Docs](https://inference.sh/docs) +- [CLI Setup Guide](https://inference.sh/docs/extend/cli-setup) +- [Apps Overview](https://inference.sh/docs/apps/overview) diff --git a/skills/inference-sh/cli/references/app-discovery.md b/skills/inference-sh/cli/references/app-discovery.md new file mode 100644 index 000000000..adcac8c5d --- /dev/null +++ b/skills/inference-sh/cli/references/app-discovery.md @@ -0,0 +1,112 @@ +# Discovering Apps + +## List All Apps + +```bash +infsh app list +``` + +## Pagination + +```bash +infsh app list --page 2 +``` + +## Filter by Category + +```bash +infsh app list --category image +infsh app list --category video +infsh app list --category audio +infsh app list --category text +infsh app list --category other +``` + +## Search + +```bash +infsh app search "flux" +infsh app search "video generation" +infsh app search "tts" -l +infsh app search "image" --category image +``` + +Or use the flag form: + +```bash +infsh app list --search "flux" +infsh app list --search "video generation" +infsh app list --search "tts" +``` + +## Featured Apps + +```bash +infsh app list --featured +``` + +## Newest First + +```bash +infsh app list --new +``` + +## Detailed View + +```bash +infsh app list -l +``` + +Shows table with app name, category, description, and featured status. + +## Save to File + +```bash +infsh app list --save apps.json +``` + +## Your Apps + +List apps you've deployed: + +```bash +infsh app my +infsh app my -l # detailed +``` + +## Get App Details + +```bash +infsh app get falai/flux-dev-lora +infsh app get falai/flux-dev-lora --json +``` + +Shows full app info including input/output schema. + +## Popular Apps by Category + +### Image Generation +- `falai/flux-dev-lora` - FLUX.2 Dev (high quality) +- `falai/flux-2-klein-lora` - FLUX.2 Klein (fastest) +- `infsh/sdxl` - Stable Diffusion XL +- `google/gemini-3-pro-image-preview` - Gemini 3 Pro +- `xai/grok-imagine-image` - Grok image generation + +### Video Generation +- `google/veo-3-1-fast` - Veo 3.1 Fast +- `google/veo-3` - Veo 3 +- `bytedance/seedance-1-5-pro` - Seedance 1.5 Pro +- `infsh/ltx-video-2` - LTX Video 2 (with audio) +- `bytedance/omnihuman-1-5` - OmniHuman avatar + +### Audio +- `infsh/dia-tts` - Conversational TTS +- `infsh/kokoro-tts` - Kokoro TTS +- `infsh/fast-whisper-large-v3` - Fast transcription +- `infsh/diffrythm` - Music generation + +## Documentation + +- [Browsing the Grid](https://inference.sh/docs/apps/browsing-grid) - Visual app browsing +- [Apps Overview](https://inference.sh/docs/apps/overview) - Understanding apps +- [Running Apps](https://inference.sh/docs/apps/running) - How to run apps diff --git a/skills/inference-sh/cli/references/authentication.md b/skills/inference-sh/cli/references/authentication.md new file mode 100644 index 000000000..3b6519d3d --- /dev/null +++ b/skills/inference-sh/cli/references/authentication.md @@ -0,0 +1,59 @@ +# Authentication & Setup + +## Install the CLI + +```bash +curl -fsSL https://cli.inference.sh | sh +``` + +## Login + +```bash +infsh login +``` + +This opens a browser for authentication. After login, credentials are stored locally. + +## Check Authentication + +```bash +infsh me +``` + +Shows your user info if authenticated. + +## Environment Variable + +For CI/CD or scripts, set your API key: + +```bash +export INFSH_API_KEY=your-api-key +``` + +The environment variable overrides the config file. + +## Update CLI + +```bash +infsh update +``` + +Or reinstall: + +```bash +curl -fsSL https://cli.inference.sh | sh +``` + +## Troubleshooting + +| Error | Solution | +|-------|----------| +| "not authenticated" | Run `infsh login` | +| "command not found" | Reinstall CLI or add to PATH | +| "API key invalid" | Check `INFSH_API_KEY` or re-login | + +## Documentation + +- [CLI Setup](https://inference.sh/docs/extend/cli-setup) - Complete CLI installation guide +- [API Authentication](https://inference.sh/docs/api/authentication) - API key management +- [Secrets](https://inference.sh/docs/secrets/overview) - Managing credentials diff --git a/skills/inference-sh/cli/references/cli-reference.md b/skills/inference-sh/cli/references/cli-reference.md new file mode 100644 index 000000000..50825825f --- /dev/null +++ b/skills/inference-sh/cli/references/cli-reference.md @@ -0,0 +1,104 @@ +# CLI Reference + +## Installation + +```bash +curl -fsSL https://cli.inference.sh | sh +``` + +## Global Commands + +| Command | Description | +|---------|-------------| +| `infsh help` | Show help | +| `infsh version` | Show CLI version | +| `infsh update` | Update CLI to latest | +| `infsh login` | Authenticate | +| `infsh me` | Show current user | + +## App Commands + +### Discovery + +| Command | Description | +|---------|-------------| +| `infsh app list` | List available apps | +| `infsh app list --category ` | Filter by category (image, video, audio, text, other) | +| `infsh app search ` | Search apps | +| `infsh app list --search ` | Search apps (flag form) | +| `infsh app list --featured` | Show featured apps | +| `infsh app list --new` | Sort by newest | +| `infsh app list --page ` | Pagination | +| `infsh app list -l` | Detailed table view | +| `infsh app list --save ` | Save to JSON file | +| `infsh app my` | List your deployed apps | +| `infsh app get ` | Get app details | +| `infsh app get --json` | Get app details as JSON | + +### Execution + +| Command | Description | +|---------|-------------| +| `infsh app run --input ` | Run app with input file | +| `infsh app run --input ''` | Run with inline JSON | +| `infsh app run --input --no-wait` | Run without waiting for completion | +| `infsh app sample ` | Show sample input | +| `infsh app sample --save ` | Save sample to file | + +## Task Commands + +| Command | Description | +|---------|-------------| +| `infsh task get ` | Get task status and result | +| `infsh task get --json` | Get task as JSON | +| `infsh task get --save ` | Save task result to file | + +### Development + +| Command | Description | +|---------|-------------| +| `infsh app init` | Create new app (interactive) | +| `infsh app init ` | Create new app with name | +| `infsh app test --input ` | Test app locally | +| `infsh app deploy` | Deploy app | +| `infsh app deploy --dry-run` | Validate without deploying | +| `infsh app pull ` | Pull app source | +| `infsh app pull --all` | Pull all your apps | + +## Environment Variables + +| Variable | Description | +|----------|-------------| +| `INFSH_API_KEY` | API key (overrides config) | + +## Shell Completions + +```bash +# Bash +infsh completion bash > /etc/bash_completion.d/infsh + +# Zsh +infsh completion zsh > "${fpath[1]}/_infsh" + +# Fish +infsh completion fish > ~/.config/fish/completions/infsh.fish +``` + +## App Name Format + +Apps use the format `namespace/app-name`: + +- `falai/flux-dev-lora` - fal.ai's FLUX 2 Dev +- `google/veo-3` - Google's Veo 3 +- `infsh/sdxl` - inference.sh's SDXL +- `bytedance/seedance-1-5-pro` - ByteDance's Seedance +- `xai/grok-imagine-image` - xAI's Grok + +Version pinning: `namespace/app-name@version` + +## Documentation + +- [CLI Setup](https://inference.sh/docs/extend/cli-setup) - Complete CLI installation guide +- [Running Apps](https://inference.sh/docs/apps/running) - How to run apps via CLI +- [Creating an App](https://inference.sh/docs/extend/creating-app) - Build your own apps +- [Deploying](https://inference.sh/docs/extend/deploying) - Deploy apps to the cloud diff --git a/skills/inference-sh/cli/references/running-apps.md b/skills/inference-sh/cli/references/running-apps.md new file mode 100644 index 000000000..e930d5cfb --- /dev/null +++ b/skills/inference-sh/cli/references/running-apps.md @@ -0,0 +1,171 @@ +# Running Apps + +## Basic Run + +```bash +infsh app run user/app-name --input input.json +``` + +## Inline JSON + +```bash +infsh app run falai/flux-dev-lora --input '{"prompt": "a sunset over mountains"}' +``` + +## Version Pinning + +```bash +infsh app run user/app-name@1.0.0 --input input.json +``` + +## Local File Uploads + +The CLI automatically uploads local files when you provide a file path instead of a URL. Any field that accepts a URL also accepts a local path: + +```bash +# Upscale a local image +infsh app run falai/topaz-image-upscaler --input '{"image": "/path/to/photo.jpg", "upscale_factor": 2}' + +# Image-to-video from local file +infsh app run falai/wan-2-5-i2v --input '{"image": "./my-image.png", "prompt": "make it move"}' + +# Avatar with local audio and image +infsh app run bytedance/omnihuman-1-5 --input '{"audio": "/path/to/speech.mp3", "image": "/path/to/face.jpg"}' + +# Post tweet with local media +infsh app run x/post-create --input '{"text": "Check this out!", "media": "./screenshot.png"}' +``` + +Supported paths: +- Absolute paths: `/home/user/images/photo.jpg` +- Relative paths: `./image.png`, `../data/video.mp4` +- Home directory: `~/Pictures/photo.jpg` + +## Generate Sample Input + +Before running, generate a sample input file: + +```bash +infsh app sample falai/flux-dev-lora +``` + +Save to file: + +```bash +infsh app sample falai/flux-dev-lora --save input.json +``` + +Then edit `input.json` and run: + +```bash +infsh app run falai/flux-dev-lora --input input.json +``` + +## Workflow Example + +### Image Generation with FLUX + +```bash +# 1. Get app details +infsh app get falai/flux-dev-lora + +# 2. Generate sample input +infsh app sample falai/flux-dev-lora --save input.json + +# 3. Edit input.json +# { +# "prompt": "a cat astronaut floating in space", +# "num_images": 1, +# "image_size": "landscape_16_9" +# } + +# 4. Run +infsh app run falai/flux-dev-lora --input input.json +``` + +### Video Generation with Veo + +```bash +# 1. Generate sample +infsh app sample google/veo-3-1-fast --save input.json + +# 2. Edit prompt +# { +# "prompt": "A drone shot flying over a forest at sunset" +# } + +# 3. Run +infsh app run google/veo-3-1-fast --input input.json +``` + +### Text-to-Speech + +```bash +# Quick inline run +infsh app run falai/kokoro-tts --input '{"text": "Hello, this is a test."}' +``` + +## Task Tracking + +When you run an app, the CLI shows the task ID: + +``` +Running falai/flux-dev-lora +Task ID: abc123def456 +``` + +For long-running tasks, you can check status anytime: + +```bash +# Check task status +infsh task get abc123def456 + +# Get result as JSON +infsh task get abc123def456 --json + +# Save result to file +infsh task get abc123def456 --save result.json +``` + +### Run Without Waiting + +For very long tasks, run in background: + +```bash +# Submit and return immediately +infsh app run google/veo-3 --input input.json --no-wait + +# Check later +infsh task get +``` + +## Output + +The CLI returns the app output directly. For file outputs (images, videos, audio), you'll receive URLs to download. + +Example output: + +```json +{ + "images": [ + { + "url": "https://cloud.inference.sh/...", + "content_type": "image/png" + } + ] +} +``` + +## Error Handling + +| Error | Cause | Solution | +|-------|-------|----------| +| "invalid input" | Schema mismatch | Check `infsh app get` for required fields | +| "app not found" | Wrong app name | Check `infsh app list --search` | +| "quota exceeded" | Out of credits | Check account balance | + +## Documentation + +- [Running Apps](https://inference.sh/docs/apps/running) - Complete running apps guide +- [Streaming Results](https://inference.sh/docs/api/sdk/streaming) - Real-time progress updates +- [Setup Parameters](https://inference.sh/docs/apps/setup-parameters) - Configuring app inputs diff --git a/tests/tools/test_infsh_tool.py b/tests/tools/test_infsh_tool.py new file mode 100644 index 000000000..f866df1e3 --- /dev/null +++ b/tests/tools/test_infsh_tool.py @@ -0,0 +1,114 @@ +"""Tests for tools/infsh_tool.py — inference.sh CLI integration.""" + +import json +import subprocess +from unittest.mock import patch, MagicMock + +import pytest + +from tools.infsh_tool import ( + check_infsh_requirements, + infsh_tool, + infsh_install, +) + + +class TestCheckRequirements: + def test_returns_bool(self): + result = check_infsh_requirements() + assert isinstance(result, bool) + + def test_returns_true_when_infsh_on_path(self, monkeypatch): + monkeypatch.setattr("shutil.which", lambda cmd: "/usr/local/bin/infsh" if cmd == "infsh" else None) + assert check_infsh_requirements() is True + + def test_returns_false_when_missing(self, monkeypatch): + monkeypatch.setattr("shutil.which", lambda cmd: None) + assert check_infsh_requirements() is False + + +class TestInfshTool: + def test_not_installed_returns_error(self, monkeypatch): + monkeypatch.setattr("tools.infsh_tool.check_infsh_requirements", lambda: False) + result = json.loads(infsh_tool("app list")) + assert result["success"] is False + assert "not installed" in result["error"].lower() + + def test_successful_command(self, monkeypatch): + monkeypatch.setattr("tools.infsh_tool.check_infsh_requirements", lambda: True) + mock_result = MagicMock() + mock_result.returncode = 0 + mock_result.stdout = '{"apps": ["flux", "veo"]}' + mock_result.stderr = "" + + with patch("subprocess.run", return_value=mock_result) as mock_run: + result = json.loads(infsh_tool("app list --search flux")) + assert result["success"] is True + mock_run.assert_called_once() + call_cmd = mock_run.call_args[0][0] + assert "infsh app list --search flux" in call_cmd + + def test_failed_command(self, monkeypatch): + monkeypatch.setattr("tools.infsh_tool.check_infsh_requirements", lambda: True) + mock_result = MagicMock() + mock_result.returncode = 1 + mock_result.stdout = "" + mock_result.stderr = "unknown command" + + with patch("subprocess.run", return_value=mock_result): + result = json.loads(infsh_tool("badcommand")) + assert result["success"] is False + assert result["exit_code"] == 1 + + def test_timeout_handled(self, monkeypatch): + monkeypatch.setattr("tools.infsh_tool.check_infsh_requirements", lambda: True) + + with patch("subprocess.run", side_effect=subprocess.TimeoutExpired("infsh", 300)): + result = json.loads(infsh_tool("app run something", timeout=300)) + assert result["success"] is False + assert "timed out" in result["error"].lower() + + def test_json_output_parsed(self, monkeypatch): + monkeypatch.setattr("tools.infsh_tool.check_infsh_requirements", lambda: True) + mock_result = MagicMock() + mock_result.returncode = 0 + mock_result.stdout = '{"url": "https://example.com/image.png"}' + mock_result.stderr = "" + + with patch("subprocess.run", return_value=mock_result): + result = json.loads(infsh_tool("app run flux --json")) + assert result["success"] is True + assert isinstance(result["output"], dict) + assert result["output"]["url"] == "https://example.com/image.png" + + +class TestInfshInstall: + def test_already_installed(self, monkeypatch): + monkeypatch.setattr("tools.infsh_tool.check_infsh_requirements", lambda: True) + monkeypatch.setattr("tools.infsh_tool._get_infsh_path", lambda: "/usr/local/bin/infsh") + mock_result = MagicMock() + mock_result.returncode = 0 + mock_result.stdout = "infsh v1.2.3" + + with patch("subprocess.run", return_value=mock_result): + result = json.loads(infsh_install()) + assert result["success"] is True + assert result["already_installed"] is True + + +class TestToolRegistration: + def test_tools_registered(self): + from tools.registry import registry + assert "infsh" in registry._tools + assert "infsh_install" in registry._tools + + def test_infsh_in_inference_toolset(self): + from toolsets import TOOLSETS + assert "inference" in TOOLSETS + assert "infsh" in TOOLSETS["inference"]["tools"] + assert "infsh_install" in TOOLSETS["inference"]["tools"] + + def test_infsh_not_in_core_tools(self): + from toolsets import _HERMES_CORE_TOOLS + assert "infsh" not in _HERMES_CORE_TOOLS + assert "infsh_install" not in _HERMES_CORE_TOOLS diff --git a/tools/infsh_tool.py b/tools/infsh_tool.py new file mode 100644 index 000000000..ede785dd1 --- /dev/null +++ b/tools/infsh_tool.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python3 +""" +Inference.sh Tool Module + +A simple tool for running AI apps via the inference.sh CLI (infsh). +Provides two functions: + - infsh_install: Install the infsh CLI + - infsh: Run any infsh command + +This is a lightweight wrapper that gives agents direct access to 150+ AI apps +including image generation (FLUX, Reve), video (Veo, Wan), LLMs, search, and more. + +Usage: + from tools.infsh_tool import infsh_tool, infsh_install + + # Install the CLI + result = infsh_install() + + # Search for apps first (always do this!) + result = infsh_tool("app list --search flux") + + # Run an app + result = infsh_tool("app run falai/flux-dev-lora --input '{\"prompt\": \"a cat\"}' --json") +""" + +import json +import logging +import os +import shutil +import subprocess +from typing import Optional + +logger = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# Configuration +# --------------------------------------------------------------------------- + +DEFAULT_TIMEOUT = 300 # 5 minutes for long-running AI tasks +INSTALL_TIMEOUT = 60 + + +# --------------------------------------------------------------------------- +# Availability check +# --------------------------------------------------------------------------- + +def check_infsh_requirements() -> bool: + """Check if infsh is available in PATH.""" + return shutil.which("infsh") is not None + + +def _get_infsh_path() -> Optional[str]: + """Get the path to infsh binary.""" + return shutil.which("infsh") + + +# --------------------------------------------------------------------------- +# Install function +# --------------------------------------------------------------------------- + +def infsh_install() -> str: + """ + Install the inference.sh CLI. + + Downloads and installs the infsh binary using the official installer script. + The installer detects OS/arch, downloads the correct binary, verifies checksum, + and places it in PATH. + + Returns: + JSON string with success/error status + """ + try: + # Check if already installed + if check_infsh_requirements(): + infsh_path = _get_infsh_path() + # Get version + version_result = subprocess.run( + ["infsh", "--version"], + capture_output=True, + text=True, + timeout=10 + ) + version = version_result.stdout.strip() if version_result.returncode == 0 else "unknown" + return json.dumps({ + "success": True, + "message": f"infsh is already installed at {infsh_path}", + "version": version, + "already_installed": True + }) + + # Run the installer + result = subprocess.run( + ["sh", "-c", "curl -fsSL https://cli.inference.sh | sh"], + capture_output=True, + text=True, + timeout=INSTALL_TIMEOUT, + env={**os.environ, "NONINTERACTIVE": "1"} + ) + + if result.returncode != 0: + return json.dumps({ + "success": False, + "error": f"Installation failed: {result.stderr}", + "stdout": result.stdout + }) + + # Verify installation + if not check_infsh_requirements(): + return json.dumps({ + "success": False, + "error": "Installation completed but infsh not found in PATH. You may need to restart your shell or add ~/.local/bin to PATH.", + "stdout": result.stdout + }) + + return json.dumps({ + "success": True, + "message": "infsh installed successfully", + "stdout": result.stdout, + "next_step": "Run 'infsh login' to authenticate, or set INFSH_API_KEY environment variable" + }) + + except subprocess.TimeoutExpired: + return json.dumps({ + "success": False, + "error": f"Installation timed out after {INSTALL_TIMEOUT}s" + }) + except Exception as e: + logger.exception("infsh_install error: %s", e) + return json.dumps({ + "success": False, + "error": f"Installation error: {type(e).__name__}: {e}" + }) + + +# --------------------------------------------------------------------------- +# Main tool function +# --------------------------------------------------------------------------- + +def infsh_tool( + command: str, + timeout: Optional[int] = None, +) -> str: + """ + Execute an infsh CLI command. + + Args: + command: The infsh command to run (without the 'infsh' prefix). + Examples: "app list", "app run falai/flux-schnell --input '{}'" + timeout: Command timeout in seconds (default: 300) + + Returns: + JSON string with output, exit_code, and error fields + """ + try: + effective_timeout = timeout or DEFAULT_TIMEOUT + + # Check if infsh is installed + if not check_infsh_requirements(): + return json.dumps({ + "success": False, + "error": "infsh CLI is not installed. Use infsh_install to install it first.", + "hint": "Call the infsh_install tool to set up the CLI" + }) + + # Build the full command + full_command = f"infsh {command}" + + # Execute + result = subprocess.run( + full_command, + shell=True, + capture_output=True, + text=True, + timeout=effective_timeout, + env=os.environ + ) + + output = result.stdout + error = result.stderr + + # Try to parse JSON output if present + parsed_output = None + if output.strip(): + try: + parsed_output = json.loads(output) + except json.JSONDecodeError: + pass # Not JSON, keep as string + + response = { + "success": result.returncode == 0, + "exit_code": result.returncode, + "output": parsed_output if parsed_output is not None else output, + } + + if error: + response["stderr"] = error + + return json.dumps(response, indent=2) + + except subprocess.TimeoutExpired: + return json.dumps({ + "success": False, + "error": f"Command timed out after {effective_timeout}s", + "hint": "For long-running tasks, consider using --no-wait flag" + }) + except Exception as e: + logger.exception("infsh_tool error: %s", e) + return json.dumps({ + "success": False, + "error": f"Execution error: {type(e).__name__}: {e}" + }) + + +# --------------------------------------------------------------------------- +# Registry +# --------------------------------------------------------------------------- + +from tools.registry import registry + +INFSH_TOOL_DESCRIPTION = """Run AI apps via inference.sh CLI. Access 150+ apps for image generation, video, LLMs, search, 3D, and more. + +One API key for everything - manage all AI services (FLUX, Veo, Claude, Tavily, etc.) with a single inference.sh account. You can also bring your own API keys. + +IMPORTANT: Always use 'app list --search ' first to find the exact app ID before running. App names change frequently. + +Commands: +- app list --search : Find apps (ALWAYS DO THIS FIRST) +- app run --input '' --json: Run an app +- app get : Get app schema before running + +Verified app examples (use --search to confirm current names): +- Image: google/nano-banana, google/nano-banana-pro, google/nano-banana-2, falai/flux-dev-lora, bytedance/seedream-5-lite, falai/reve, xai/grok-imagine-image +- Video: google/veo-3-1-fast, bytedance/seedance-1-5-pro, falai/wan-2-5 +- Upscale: falai/topaz-image-upscaler +- Search: tavily/search-assistant, exa/search +- LLM: openrouter/claude-sonnet-45 + +Workflow: ALWAYS search first, then run: +1. app list --search image +2. app run falai/flux-dev-lora --input '{"prompt": "a sunset"}' --json""" + +INFSH_SCHEMA = { + "name": "infsh", + "description": INFSH_TOOL_DESCRIPTION, + "parameters": { + "type": "object", + "properties": { + "command": { + "type": "string", + "description": "The infsh command (without 'infsh' prefix). ALWAYS use 'app list --search ' first to find correct app IDs, then 'app run --input --json'" + }, + "timeout": { + "type": "integer", + "description": "Max seconds to wait (default: 300). AI tasks like video generation may take 1-2 minutes.", + "minimum": 1 + } + }, + "required": ["command"] + } +} + +INFSH_INSTALL_SCHEMA = { + "name": "infsh_install", + "description": "Install the inference.sh CLI (infsh). Downloads and installs the binary. Run this first if infsh is not available.", + "parameters": { + "type": "object", + "properties": {}, + "required": [] + } +} + + +def _handle_infsh(args, **kw): + return infsh_tool( + command=args.get("command", ""), + timeout=args.get("timeout"), + ) + + +def _handle_infsh_install(args, **kw): + return infsh_install() + + +# Register both tools under the "inference" toolset +registry.register( + name="infsh", + toolset="inference", + schema=INFSH_SCHEMA, + handler=_handle_infsh, + check_fn=check_infsh_requirements, + requires_env=[], +) + +registry.register( + name="infsh_install", + toolset="inference", + schema=INFSH_INSTALL_SCHEMA, + handler=_handle_infsh_install, + check_fn=lambda: True, # Always available - it's the installer + requires_env=[], +) diff --git a/toolsets.py b/toolsets.py index 1a73ff1b8..b94ea580d 100644 --- a/toolsets.py +++ b/toolsets.py @@ -183,6 +183,12 @@ TOOLSETS = { "tools": ["execute_code"], "includes": [] }, + + "inference": { + "description": "inference.sh CLI (infsh) — run 150+ AI apps: image gen (FLUX, Reve), video (Veo, Wan), LLMs, search (Tavily, Exa), 3D, and more", + "tools": ["infsh", "infsh_install"], + "includes": [] + }, "delegation": { "description": "Spawn subagents with isolated context for complex subtasks",