Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ git-smart-squash [OPTIONS]
| Option | Short | Description | Default |
|--------|-------|-------------|---------|
| `--base BASE` | | Base branch to compare against | Config file or `main` |
| `--ai-provider PROVIDER` | | AI provider to use (`local`, `openai`, `anthropic`, `gemini`) | Config file or `local` |
| `--ai-provider PROVIDER` | | AI provider to use (`local`, `openai`, `anthropic`, `gemini`, `openrouter`) | Config file or `local` |
| `--model MODEL` | | Specific model to use | Provider default |
| `--config PATH` | | Path to configuration file | Auto-detected |
| `--auto-apply` | | Apply changes without confirmation prompt | Config file or `false` |
Expand Down Expand Up @@ -269,6 +269,29 @@ export GEMINI_API_KEY="..."

**Pricing:** ~$0.01 per typical use

### OpenRouter

**Advantages:**
- Access to 100+ models from multiple providers through a single API
- Competitive pricing with flexible model selection
- Unified interface for various AI providers
- Fast response times with global infrastructure
- No vendor lock-in - switch models easily

**Setup:**
```bash
export OPENROUTER_API_KEY="sk-or-v1-..."
```

**Models:**
- `openai/gpt-5` (default) - Latest GPT-5 model with excellent performance
- `anthropic/claude-3.5-sonnet` - Claude Sonnet through OpenRouter
- `google/gemini-pro-1.5` - Gemini Pro through OpenRouter
- `meta-llama/llama-3.1-405b-instruct` - Llama 3.1 through OpenRouter
- Any other model available on OpenRouter - Specify with `--model` flag

**Pricing:** Variable based on selected model (~$0.005 - $0.03 per typical use)

## Configuration

### Configuration Hierarchy
Expand All @@ -284,7 +307,7 @@ Git Smart Squash looks for configuration in this order:
```yaml
# AI Provider Settings
ai:
provider: local # or openai, anthropic, gemini
provider: local # or openai, anthropic, gemini, openrouter
model: devstral # optional, uses provider default if not set
# You can specify ANY model supported by the provider
instructions: | # Optional custom instructions for AI
Expand Down Expand Up @@ -316,6 +339,7 @@ auto_apply: false # Set to true to apply commits without confirmation
| `OPENAI_API_KEY` | OpenAI API key |
| `ANTHROPIC_API_KEY` | Anthropic API key |
| `GEMINI_API_KEY` | Google Gemini API key |
| `OPENROUTER_API_KEY` | OpenRouter API key |
| `OLLAMA_HOST` | Ollama server URL (default: http://localhost:11434) |

## How It Works
Expand Down Expand Up @@ -405,6 +429,11 @@ git-smart-squash --ai-provider anthropic --model claude-3-haiku-20240307
git-smart-squash --ai-provider gemini --model gemini-1.5-flash
git-smart-squash --ai-provider gemini --model gemini-ultra

# OpenRouter examples
git-smart-squash --ai-provider openrouter --model openai/gpt-5
git-smart-squash --ai-provider openrouter --model anthropic/claude-3.5-sonnet
git-smart-squash --ai-provider openrouter --model google/gemini-pro-1.5

# Local Ollama examples
git-smart-squash --model codellama:13b
git-smart-squash --model mistral:latest
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ export ANTHROPIC_API_KEY="your-key"
export GEMINI_API_KEY="your-key"
```

**Option C: OpenRouter (100+ models)**
```bash
export OPENROUTER_API_KEY="sk-or-v1-your-key"
# Then run with: git-smart-squash --ai-provider openrouter
```

### 3. Run

```bash
Expand All @@ -68,7 +74,7 @@ That's it. Review the plan and approve.
| Parameter | Description | Default |
|-----------|-------------|---------|
| `--base` | Base branch to compare against | Config file or `main` |
| `--ai-provider` | AI provider to use (openai, anthropic, local, gemini) | Configured in settings |
| `--ai-provider` | AI provider to use (openai, anthropic, local, gemini, openrouter) | Configured in settings |
| `--model` | Specific AI model to use (see recommended models below) | Provider default |
| `--config` | Path to custom configuration file | `.git-smart-squash.yml` or `~/.git-smart-squash.yml` |
| `--auto-apply` | Apply commit plan without confirmation prompt | `false` |
Expand All @@ -82,6 +88,7 @@ That's it. Review the plan and approve.
- **OpenAI**: `gpt-4.1` (default)
- **Anthropic**: `claude-sonnet-4-20250514` (default)
- **Gemini**: `gemini-2.5-pro` (default)
- **OpenRouter**: `openai/gpt-5` (default)
- **Local/Ollama**: `devstral` (default)

### Model Selection
Expand All @@ -91,6 +98,10 @@ git-smart-squash --ai-provider openai --model gpt-4.1-mini

# For local Ollama
git-smart-squash --ai-provider local --model llama-3.1

# For OpenRouter (access to 100+ models)
git-smart-squash --ai-provider openrouter --model openai/gpt-5
git-smart-squash --ai-provider openrouter --model anthropic/claude-3.5-sonnet
```

## Custom Instructions
Expand Down Expand Up @@ -130,6 +141,7 @@ git-smart-squash --base develop
### "I want to use a specific AI provider"
```bash
git-smart-squash --ai-provider openai
git-smart-squash --ai-provider openrouter # Access to 100+ models
```

## Safety
Expand Down Expand Up @@ -157,6 +169,7 @@ git reset --hard your-branch-backup-[timestamp]
| **OpenAI** | ~$0.01 | Cloud |
| **Anthropic** | ~$0.01 | Cloud |
| **Gemini** | ~$0.01 | Cloud |
| **OpenRouter** | ~$0.005-$0.03 | Cloud |

## Advanced Configuration (Optional)

Expand Down
64 changes: 62 additions & 2 deletions git_smart_squash/ai/providers/simple_unified.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class UnifiedAIProvider:
'local': 32000, # Ollama hard maximum
'openai': 1000000, # OpenAI hard maximum (1M tokens)
'gemini': 1000000, # Gemini hard maximum (1M tokens)
'anthropic': 200000 # Anthropic hard maximum (200k tokens)
'anthropic': 200000, # Anthropic hard maximum (200k tokens)
'openrouter': 1000000 # OpenRouter hard maximum (1M tokens)
}

# Conservative defaults
Expand Down Expand Up @@ -177,6 +178,8 @@ def generate(self, prompt: str) -> str:
return self._generate_anthropic(prompt)
elif self.provider_type == "gemini":
return self._generate_gemini(prompt)
elif self.provider_type == "openrouter":
return self._generate_openrouter(prompt)
else:
raise ValueError(f"Unsupported provider: {self.provider_type}")

Expand Down Expand Up @@ -439,4 +442,61 @@ def _generate_gemini(self, prompt: str) -> str:
except ImportError:
raise Exception("Google Generative AI library not installed. Run: pip install google-generativeai")
except Exception as e:
raise Exception(f"Google Gemini generation failed: {e}")
raise Exception(f"Google Gemini generation failed: {e}")


def _generate_openrouter(self, prompt: str) -> str:
"""Generate using OpenRouter API with structured output enforcement."""
try:
import openai

api_key = os.getenv('OPENROUTER_API_KEY')
if not api_key:
raise Exception("OPENROUTER_API_KEY environment variable not set")

# Calculate dynamic parameters
params = self._calculate_dynamic_params(prompt)

# Use provider-level context limit
model_context_limit = self.PROVIDER_MAX_CONTEXT_TOKENS.get('openrouter', 1000000)

# Check if prompt exceeds model context limit
if params["prompt_tokens"] > model_context_limit - 1000: # Reserve 1000 for response
raise Exception(f"Prompt ({params['prompt_tokens']} tokens) exceeds {self.config.ai.model} context limit ({model_context_limit}). Consider reducing diff size.")

# Warn if prompt is large but manageable
if params["prompt_tokens"] > model_context_limit * 0.7:
logger.warning(f"Large prompt ({params['prompt_tokens']} tokens) approaching {self.config.ai.model} context limit.")

client = openai.OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=api_key
)

response = client.chat.completions.create(
model=self.config.ai.model,
messages=[{"role": "user", "content": prompt}],
max_tokens=self.MAX_PREDICT_TOKENS,
temperature=0.7,
response_format={
"type": "json_schema",
"json_schema": {
"name": "commit_plan",
"schema": self.COMMIT_SCHEMA,
"strict": True
}
}
)

# Check if response was truncated
if response.choices[0].finish_reason == "length":
logger.warning(f"OpenAI response truncated at {self.MAX_PREDICT_TOKENS} tokens. Consider reducing diff size.")

# Return the full structured response
content = response.choices[0].message.content
return content # OpenAI already returns the correct format with json_schema

except ImportError:
raise Exception("OpenAI library not installed. Run: pip install openai")
except Exception as e:
raise Exception(f"OpenAI generation failed: {e}")
2 changes: 1 addition & 1 deletion git_smart_squash/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def create_parser(self) -> argparse.ArgumentParser:

parser.add_argument(
'--ai-provider',
choices=['openai', 'anthropic', 'local', 'gemini'],
choices=['openai', 'anthropic', 'local', 'gemini', 'openrouter'],
help='AI provider to use'
)

Expand Down
1 change: 1 addition & 0 deletions git_smart_squash/simple_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def _get_default_model(self, provider: str) -> str:
'openai': 'gpt-4.1',
'anthropic': 'claude-sonnet-4-20250514', # Claude Sonnet 4 model
'gemini': 'gemini-2.5-pro' # Gemini 2.5 Pro model
'openrouter': 'openai/gpt-5' # OpenAI GPT-5 model
}
return defaults.get(provider, 'devstral')

Expand Down