Skip to content
Closed
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
12 changes: 10 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,17 @@ jobs:
run: |
uv sync

- name: Run pre-commit hooks (formatters, linters)
- name: Run ruff linter
run: |
uv run pre-commit run --all-files
uv run ruff check .

- name: Run ruff formatter
run: |
uv run ruff format --check .

- name: Run mypy type checker
run: |
uv run mypy .

# If ever there are tests to run, uncomment the following lines.
#
Expand Down
44 changes: 0 additions & 44 deletions .pre-commit-config.yaml

This file was deleted.

25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,28 @@ This project leverages Python and [uv](https://docs.astral.sh/uv/) to manage dep
uv sync
```

5. **Pre-commit Hooks:**
- Install pre-commit hooks:
5. **Git Hooks (Optional):**
- Set up a git pre-commit hook that runs ruff automatically:
```bash
pip install pre-commit
pre-commit install
./setup-git-hooks.sh
```
- This will run `ruff check` and `ruff format --check` before each commit
- To skip the hook for a specific commit: `git commit --no-verify`

6. **Running the linter:**
- Run the linter with:
6. **Code Quality:**
- Run ruff for linting and formatting:
```bash
pre-commit run --all-files
# Check for linting issues
uv run ruff check .

# Auto-fix linting issues
uv run ruff check --fix .

# Format code
uv run ruff format .

# Run type checking
uv run mypy .
```

7. **Running Tests:**
Expand Down
18 changes: 9 additions & 9 deletions anthropic_common/streaming.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
"""Common streaming utilities for Anthropic API."""

from typing import IO, TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
from typing import IO, TYPE_CHECKING, Any, Union

# Runtime imports with type checking separation
import anthropic # noqa: E402
import click
from anthropic.types import MessageParam # noqa: E402, F401


# Define type aliases for better readability
if TYPE_CHECKING:
from anthropic import Anthropic, AnthropicVertex # noqa: F401
Expand All @@ -22,10 +23,10 @@ def stream_anthropic_response(
temperature: float,
max_tokens: int,
thinking_budget_tokens: int,
conv_log_writer: Optional[IO[str]] = None,
resp_log_writer: Optional[IO[str]] = None,
conv_log_writer: IO[str] | None = None,
resp_log_writer: IO[str] | None = None,
echo_to_terminal: bool = True,
) -> Tuple[str, Dict[str, Any]]:
) -> tuple[str, dict[str, Any]]:
"""
Streams the Anthropic API response using the provided client.

Expand All @@ -48,7 +49,7 @@ def stream_anthropic_response(
messages: list[MessageParam] = [{"role": "user", "content": prompt}]

# Build the parameters for the API call
api_params: Dict[str, Any] = {
api_params: dict[str, Any] = {
"model": model,
"system": system_prompt,
"messages": messages,
Expand All @@ -67,7 +68,7 @@ def stream_anthropic_response(
api_params["temperature"] = 1.0

# Initialize token usage tracking and text collection
token_usage: Dict[str, Any] = {}
token_usage: dict[str, Any] = {}
text_chunks: list[str] = []

try:
Expand Down Expand Up @@ -136,14 +137,13 @@ def stream_anthropic_response(
return response_text, token_usage


def print_token_usage(token_usage: Dict[str, Any]) -> None:
def print_token_usage(token_usage: dict[str, Any]) -> None:
"""Print token usage information in a consistent format."""
click.echo("\n\n--- Token Usage ---")
click.echo(f"Input tokens: {token_usage.get('input_tokens', 0)}")
click.echo(f"Output tokens: {token_usage.get('output_tokens', 0)}")
click.echo(
f"Cache creation tokens: "
f"{token_usage.get('cache_creation_input_tokens', 0)}"
f"Cache creation tokens: {token_usage.get('cache_creation_input_tokens', 0)}"
)
click.echo(f"Cache read tokens: {token_usage.get('cache_read_input_tokens', 0)}")
total_input = (
Expand Down
5 changes: 2 additions & 3 deletions claude_cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ def main(
"""
# Read the main prompt
try:
with open(prompt_file, "r", encoding="utf-8") as f:
with open(prompt_file, encoding="utf-8") as f:
prompt = f.read()
except OSError as exc:
click.echo(f"Error reading prompt file: {exc}", err=True)
sys.exit(1)

# Read the system prompt
try:
with open(system_prompt_file, "r", encoding="utf-8") as f:
with open(system_prompt_file, encoding="utf-8") as f:
system_prompt = f.read()
except OSError as exc:
click.echo(f"Error reading system prompt file: {exc}", err=True)
Expand All @@ -90,7 +90,6 @@ def main(
open(conversation_path, "a", encoding="utf-8") as conv_f,
open(response_path, "w", encoding="utf-8") as resp_f,
):

# Log the prompt part to the conversation file
conv_f.write(f"--- Prompt: {timestamp} ---\n")
conv_f.write(f"{prompt}\n")
Expand Down
4 changes: 2 additions & 2 deletions gemini_cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ def main(
"""
# Read the prompt from the specified file
try:
with open(prompt_file, "r", encoding="utf-8") as f:
with open(prompt_file, encoding="utf-8") as f:
prompt = f.read()
except OSError as exc:
click.echo(f"Error reading prompt file: {exc}", err=True)
sys.exit(1)

# Read the system prompt from the specified file
try:
with open(system_prompt_file, "r", encoding="utf-8") as f:
with open(system_prompt_file, encoding="utf-8") as f:
system_prompt = f.read()
except OSError as exc:
click.echo(f"Error reading system prompt file: {exc}", err=True)
Expand Down
4 changes: 2 additions & 2 deletions openai_cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ def main(
"""
# Read the main prompt
try:
with open(prompt_file, "r", encoding="utf-8") as f:
with open(prompt_file, encoding="utf-8") as f:
prompt = f.read()
except OSError as exc:
click.echo(f"Error reading prompt file: {exc}", err=True)
sys.exit(1)

# Read the system prompt
try:
with open(system_prompt_file, "r", encoding="utf-8") as f:
with open(system_prompt_file, encoding="utf-8") as f:
system_prompt = f.read()
except OSError as exc:
click.echo(f"Error reading system prompt file: {exc}", err=True)
Expand Down
36 changes: 33 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,38 @@ packages = ["anthropic_common", "claude_cli", "gemini_cli", "gemini_common", "op

[dependency-groups]
dev = [
"flake8>=7.1.1",
"pre-commit>=4.1.0",
"flake8-type-checking>=3.0.0",
"ruff>=0.8.0",
"mypy>=1.14.1"
]

[tool.ruff]
target-version = "py311"
line-length = 88

[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"UP", # pyupgrade
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"TCH", # flake8-type-checking
]
ignore = [
"E203", # whitespace before ':'
"TC002", # Move third-party import into type-checking block (requires careful handling)
]

[tool.ruff.lint.per-file-ignores]
"test_*.py" = ["E712"] # Allow e.g. `assert foo() == True` in test files

[tool.ruff.lint.isort]
# Configure isort to be compatible with black formatting
force-single-line = false
lines-after-imports = 2

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
53 changes: 53 additions & 0 deletions setup-git-hooks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#\!/usr/bin/env bash
# Setup script for git hooks that use ruff for code quality

set -e

HOOK_DIR=".git/hooks"
HOOK_FILE="$HOOK_DIR/pre-commit"

echo "Setting up git pre-commit hook with ruff..."

# Create the pre-commit hook
cat > "$HOOK_FILE" << 'HOOK_EOF'
#\!/usr/bin/env bash
# Git pre-commit hook that runs ruff for code quality checks
set -e

echo "Running ruff checks before commit..."

# Check if uv is available
if \! command -v uv &> /dev/null; then
echo "Error: uv is not installed or not in PATH"
echo "Please install uv: curl -LsSf https://astral.sh/uv/install.sh < /dev/null | sh"
exit 1
fi

# Run ruff linting on main package files only
echo "β†’ Running ruff check..."
if \! uv run ruff check anthropic_common/ claude_cli/ gemini_cli/ openai_cli/ vertex_cli/ 2>/dev/null; then
echo "❌ Ruff linting failed. Please fix the issues above."
echo "πŸ’‘ You can auto-fix many issues with: uv run ruff check --fix ."
exit 1
fi

# Run ruff formatting check on main package files only
echo "β†’ Running ruff format check..."
if \! uv run ruff format --check anthropic_common/ claude_cli/ gemini_cli/ openai_cli/ vertex_cli/ 2>/dev/null; then
echo "❌ Ruff formatting check failed. Please format your code."
echo "πŸ’‘ You can auto-format with: uv run ruff format ."
exit 1
fi

echo "βœ… All ruff checks passed\!"
HOOK_EOF

# Make the hook executable
chmod +x "$HOOK_FILE"

echo "βœ… Git pre-commit hook installed successfully\!"
echo ""
echo "The hook will now run 'uv run ruff check' and 'uv run ruff format --check'"
echo "before each commit to ensure code quality."
echo ""
echo "To skip the hook for a specific commit, use: git commit --no-verify"
Loading