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
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,59 @@ providers = {
```
</details>

<details>
<summary>Claude Code CLI (Local Subprocess)</summary>

The Claude Code CLI provider runs Claude as a local subprocess instead of making HTTP API calls. No API key needed - uses local authentication.

**Installation:**
```bash
pip install claude-code
```

**Configuration:**
```lua
providers = {
claude_cli = {
name = "claude_cli",
-- Use the command field instead of endpoint for CLI providers
command = "claude", -- Assumes 'claude' is in PATH

-- Optional: additional command arguments (e.g., "--model", "opus")
command_args = {},

-- Models (static list for selection)
models = {
"claude-sonnet-4-5",
"claude-opus-4-5",
"claude-haiku-4",
},

params = {
chat = {},
command = {},
},
},
}
```

**Features:**
- No API key required (uses Claude CLI's local auth)
- Runs Claude as a subprocess instead of HTTP API calls
- Automatic streaming via `--output-format stream-json`
- Supports visual selection and chat history
- System prompts via `--system-prompt` flag
- Works with all parrot.nvim features

**How it works:**
1. Executes `claude -p --output-format stream-json`
2. Passes system prompt via `--system-prompt` flag
3. Sends user messages via stdin
4. Receives streaming JSON output via stdout
5. Parrot displays output in real-time

</details>

<details>
<summary>Google Gemini</summary>

Expand Down
173 changes: 173 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Claude CLI Provider Examples

This directory contains example scripts demonstrating how to use CLI-based providers with parrot.nvim.

## Overview

The Claude CLI Provider allows you to integrate command-line tools with parrot.nvim instead of using HTTP APIs directly. This is useful for:

- Running local LLM tools
- Using custom wrapper scripts
- Integrating with tools that don't have HTTP APIs
- Testing and development

## Example Scripts

### 1. `claude_api_wrapper.py` - Full Claude API Integration

A production-ready wrapper that interfaces with the Claude API via the `anthropic` Python package.

**Installation:**
```bash
pip install anthropic
```

**Usage:**
```bash
export ANTHROPIC_API_KEY="your-api-key"
echo "Hello Claude" | python claude_api_wrapper.py --stream
```

**Parrot.nvim Configuration:**
```lua
require("parrot").setup {
providers = {
claude_cli = {
name = "claude_cli",
-- For actual Claude CLI (no API key needed)
command = "claude",
models = {
"claude-sonnet-4-5",
"claude-opus-4-5",
"claude-haiku-4",
},
},
},
}
```

### 2. `claude_cli_wrapper.py` - Simple Demo Wrapper

A minimal example showing the stdin/stdout interface pattern.

**Usage:**
```bash
echo "Test prompt" | python claude_cli_wrapper.py --stream
```

## How CLI Providers Work

CLI providers differ from HTTP providers in several ways:

1. **Command Execution**: Instead of making HTTP requests, they execute a subprocess
2. **Input**: Messages are formatted as plain text and sent via stdin
3. **Output**: Responses are read from stdout line-by-line
4. **Streaming**: Supported via flush on each output chunk

### Interface Contract

Your CLI script should:

1. Read input from stdin (formatted prompt text)
2. Process the input (call API, run model, etc.)
3. Write output to stdout
4. Support `--stream` flag for streaming output (optional)
5. Exit with code 0 on success

### Input Format

The CLI provider converts OpenAI-style messages to this format:

```
System: [system prompt if any]

User: [user message]```

### Output Format

For streaming (`--stream` flag):
- Write output character by character or line by line
- Flush stdout after each write
- The CLI provider reads each line via `on_stdout`

For non-streaming:
- Write complete response to stdout
- The CLI provider reads on `on_exit`

## Creating Your Own CLI Provider

To create a custom CLI wrapper:

1. **Create a script** that follows the interface contract
2. **Handle stdin/stdout** for communication
3. **Support streaming** if needed (via flush)
4. **Configure in parrot.nvim** using the `command` field

Example minimal wrapper:

```python
#!/usr/bin/env python3
import sys

# Read from stdin
prompt = sys.stdin.read().strip()

# Process (your logic here)
response = process_prompt(prompt)

# Write to stdout
print(response, flush=True)
```

## Testing

Test your CLI wrapper:

```bash
# Test stdin/stdout
echo "Hello" | python your_wrapper.py

# Test streaming
echo "Tell me a story" | python your_wrapper.py --stream

# Test with visual selection (simulated)
echo -e "User: Fix this code\n\nfunc() { return 1 }" | python your_wrapper.py --stream
```

## Troubleshooting

**Script not executing:**
- Check file permissions: `chmod +x your_script.py`
- Verify command path in config
- Check logs: `:PrtInfo` for provider details

**No output:**
- Ensure script writes to stdout, not stderr
- Check for proper flush on streaming output
- Verify exit code is 0

**API key issues:**
- Set environment variable before starting Neovim
- Or use command/function in api_key field

## Advanced: Chat History Support

The CLI provider automatically includes chat history when calling from a chat buffer. The input format includes previous messages:

```
System: You are a helpful assistant

User: What is Python?
Assistant: Python is a high-level programming language

User: Tell me more

[Previous conversation continues...]
```

Your wrapper should handle multi-turn conversations if needed, or simply respond to the full context as a single prompt.

## License

Same as parrot.nvim (MIT)

86 changes: 86 additions & 0 deletions examples/claude_api_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""
Claude API CLI wrapper for parrot.nvim

This script provides a stdin/stdout interface to the Claude API,
suitable for use with parrot.nvim's ClaudeCliProvider.

Installation:
pip install anthropic

Usage:
export ANTHROPIC_API_KEY="your-api-key"
echo "Your prompt" | python claude_api_wrapper.py [--stream] [--model MODEL]

Configuration in parrot.nvim:
providers = {
claude_cli = {
name = "claude_cli",
command = { "python", "/path/to/claude_api_wrapper.py" },
command_args = { "--stream" },
api_key = os.getenv("ANTHROPIC_API_KEY"),
models = {
"claude-sonnet-4-5",
"claude-opus-4-5",
"claude-haiku-4",
},
}
}
"""

import sys
import os
import argparse

def main():
parser = argparse.ArgumentParser(description='Claude API CLI wrapper')
parser.add_argument('--stream', action='store_true', help='Enable streaming output')
parser.add_argument('--model', default='claude-sonnet-4-5-20250929', help='Model to use')
args = parser.parse_args()

# Read prompt from stdin
prompt = sys.stdin.read().strip()

if not prompt:
print("Error: No input provided", file=sys.stderr)
sys.exit(1)

# Get API key from environment
api_key = os.getenv('ANTHROPIC_API_KEY')
if not api_key:
print("Error: ANTHROPIC_API_KEY environment variable not set", file=sys.stderr)
sys.exit(1)

try:
from anthropic import Anthropic

client = Anthropic(api_key=api_key)

if args.stream:
# Streaming response
with client.messages.stream(
model=args.model,
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
) as stream:
for text in stream.text_stream:
print(text, end='', flush=True)
print() # Final newline
else:
# Non-streaming response
message = client.messages.create(
model=args.model,
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
)
print(message.content[0].text)

except ImportError:
print("Error: anthropic package not installed. Run: pip install anthropic", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {str(e)}", file=sys.stderr)
sys.exit(1)

if __name__ == "__main__":
main()
68 changes: 68 additions & 0 deletions examples/claude_cli_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""
Example wrapper for Claude Code CLI integration with parrot.nvim

This script demonstrates how to create a CLI interface that works with
the ClaudeCliProvider. It reads from stdin, processes the input, and
writes to stdout with optional streaming.

Usage:
echo "Your prompt here" | python claude_cli_wrapper.py [--stream]

To use with parrot.nvim:
providers = {
claude_cli = {
name = "claude_cli",
command = { "python", "/path/to/claude_cli_wrapper.py" },
command_args = { "--stream" },
models = { "claude-sonnet-4-5" },
}
}
"""

import sys
import time

def main():
# Check for streaming flag
streaming = "--stream" in sys.argv

# Read input from stdin
prompt = sys.stdin.read().strip()

if not prompt:
print("Error: No input provided", file=sys.stderr)
sys.exit(1)

# Here you would call the actual Claude Code CLI or API
# For demonstration, we'll simulate a response

# Example: Call claude-code if available
# Uncomment and modify based on actual Claude Code CLI interface
"""
import subprocess
result = subprocess.run(
['claude', '--prompt', prompt],
capture_output=True,
text=True
)
response = result.stdout
"""

# Simulated response for demonstration
response = f"Claude response to: {prompt[:50]}..."

if streaming:
# Simulate streaming output
for char in response:
print(char, end='', flush=True)
time.sleep(0.01) # Small delay to simulate streaming
print() # Final newline
else:
# Non-streaming: output all at once
print(response)

sys.exit(0)

if __name__ == "__main__":
main()
Loading