ccproxy-api 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,22 +32,6 @@ def validate_max_turns(
32
32
  return value
33
33
 
34
34
 
35
- def validate_permission_mode(
36
- ctx: typer.Context, param: typer.CallbackParam, value: str | None
37
- ) -> str | None:
38
- """Validate permission mode."""
39
- if value is None:
40
- return None
41
-
42
- valid_modes = {"default", "acceptEdits", "bypassPermissions"}
43
- if value not in valid_modes:
44
- raise typer.BadParameter(
45
- f"Permission mode must be one of: {', '.join(valid_modes)}"
46
- )
47
-
48
- return value
49
-
50
-
51
35
  def validate_claude_cli_path(
52
36
  ctx: typer.Context, param: typer.CallbackParam, value: str | None
53
37
  ) -> str | None:
@@ -78,99 +62,7 @@ def validate_cwd(
78
62
  return value
79
63
 
80
64
 
81
- def max_thinking_tokens_option() -> Any:
82
- """Max thinking tokens parameter."""
83
- return typer.Option(
84
- None,
85
- "--max-thinking-tokens",
86
- help="Maximum thinking tokens for Claude Code",
87
- callback=validate_max_thinking_tokens,
88
- rich_help_panel="Claude Settings",
89
- )
90
-
91
-
92
- def allowed_tools_option() -> Any:
93
- """Allowed tools parameter."""
94
- return typer.Option(
95
- None,
96
- "--allowed-tools",
97
- help="List of allowed tools (comma-separated)",
98
- rich_help_panel="Claude Settings",
99
- )
100
-
101
-
102
- def disallowed_tools_option() -> Any:
103
- """Disallowed tools parameter."""
104
- return typer.Option(
105
- None,
106
- "--disallowed-tools",
107
- help="List of disallowed tools (comma-separated)",
108
- rich_help_panel="Claude Settings",
109
- )
110
-
111
-
112
- def claude_cli_path_option() -> Any:
113
- """Claude CLI path parameter."""
114
- return typer.Option(
115
- None,
116
- "--claude-cli-path",
117
- help="Path to Claude CLI executable",
118
- callback=validate_claude_cli_path,
119
- rich_help_panel="Claude Settings",
120
- )
121
-
122
-
123
- def append_system_prompt_option() -> Any:
124
- """Append system prompt parameter."""
125
- return typer.Option(
126
- None,
127
- "--append-system-prompt",
128
- help="Additional system prompt to append",
129
- rich_help_panel="Claude Settings",
130
- )
131
-
132
-
133
- def permission_mode_option() -> Any:
134
- """Permission mode parameter."""
135
- return typer.Option(
136
- None,
137
- "--permission-mode",
138
- help="Permission mode: default, acceptEdits, or bypassPermissions",
139
- callback=validate_permission_mode,
140
- rich_help_panel="Claude Settings",
141
- )
142
-
143
-
144
- def max_turns_option() -> Any:
145
- """Max turns parameter."""
146
- return typer.Option(
147
- None,
148
- "--max-turns",
149
- help="Maximum conversation turns",
150
- callback=validate_max_turns,
151
- rich_help_panel="Claude Settings",
152
- )
153
-
154
-
155
- def cwd_option() -> Any:
156
- """Working directory parameter."""
157
- return typer.Option(
158
- None,
159
- "--cwd",
160
- help="Working directory path",
161
- callback=validate_cwd,
162
- rich_help_panel="Claude Settings",
163
- )
164
-
165
-
166
- def permission_prompt_tool_name_option() -> Any:
167
- """Permission prompt tool name parameter."""
168
- return typer.Option(
169
- None,
170
- "--permission-prompt-tool-name",
171
- help="Permission prompt tool name",
172
- rich_help_panel="Claude Settings",
173
- )
65
+ # Factory functions removed - use Annotated syntax directly in commands
174
66
 
175
67
 
176
68
  class ClaudeOptions:
@@ -187,10 +79,8 @@ class ClaudeOptions:
187
79
  disallowed_tools: str | None = None,
188
80
  claude_cli_path: str | None = None,
189
81
  append_system_prompt: str | None = None,
190
- permission_mode: str | None = None,
191
82
  max_turns: int | None = None,
192
83
  cwd: str | None = None,
193
- permission_prompt_tool_name: str | None = None,
194
84
  ):
195
85
  """Initialize Claude options.
196
86
 
@@ -200,17 +90,13 @@ class ClaudeOptions:
200
90
  disallowed_tools: List of disallowed tools (comma-separated)
201
91
  claude_cli_path: Path to Claude CLI executable
202
92
  append_system_prompt: Additional system prompt to append
203
- permission_mode: Permission mode
204
93
  max_turns: Maximum conversation turns
205
94
  cwd: Working directory path
206
- permission_prompt_tool_name: Permission prompt tool name
207
95
  """
208
96
  self.max_thinking_tokens = max_thinking_tokens
209
97
  self.allowed_tools = allowed_tools
210
98
  self.disallowed_tools = disallowed_tools
211
99
  self.claude_cli_path = claude_cli_path
212
100
  self.append_system_prompt = append_system_prompt
213
- self.permission_mode = permission_mode
214
101
  self.max_turns = max_turns
215
102
  self.cwd = cwd
216
- self.permission_prompt_tool_name = permission_prompt_tool_name
@@ -6,19 +6,7 @@ from typing import Any
6
6
  import typer
7
7
 
8
8
 
9
- def config_option() -> Any:
10
- """Configuration file parameter."""
11
- return typer.Option(
12
- None,
13
- "--config",
14
- "-c",
15
- help="Path to configuration file (TOML, JSON, or YAML)",
16
- exists=True,
17
- file_okay=True,
18
- dir_okay=False,
19
- readable=True,
20
- rich_help_panel="Configuration",
21
- )
9
+ # Factory functions removed - use Annotated syntax directly in commands
22
10
 
23
11
 
24
12
  class CoreOptions:
@@ -18,15 +18,7 @@ def validate_auth_token(
18
18
  return value
19
19
 
20
20
 
21
- def auth_token_option() -> Any:
22
- """Auth token parameter."""
23
- return typer.Option(
24
- None,
25
- "--auth-token",
26
- help="Bearer token for API authentication",
27
- callback=validate_auth_token,
28
- rich_help_panel="Security Settings",
29
- )
21
+ # Factory functions removed - use Annotated syntax directly in commands
30
22
 
31
23
 
32
24
  class SecurityOptions:
@@ -32,58 +32,7 @@ def validate_log_level(
32
32
  return value.upper()
33
33
 
34
34
 
35
- def port_option() -> Any:
36
- """Port parameter."""
37
- return typer.Option(
38
- None,
39
- "--port",
40
- "-p",
41
- help="Port to run the server on",
42
- callback=validate_port,
43
- rich_help_panel="Server Settings",
44
- )
45
-
46
-
47
- def host_option() -> Any:
48
- """Host parameter."""
49
- return typer.Option(
50
- None,
51
- "--host",
52
- "-h",
53
- help="Host to bind the server to",
54
- rich_help_panel="Server Settings",
55
- )
56
-
57
-
58
- def reload_option() -> Any:
59
- """Reload parameter."""
60
- return typer.Option(
61
- None,
62
- "--reload/--no-reload",
63
- help="Enable auto-reload for development",
64
- rich_help_panel="Server Settings",
65
- )
66
-
67
-
68
- def log_level_option() -> Any:
69
- """Log level parameter."""
70
- return typer.Option(
71
- None,
72
- "--log-level",
73
- help="Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",
74
- callback=validate_log_level,
75
- rich_help_panel="Server Settings",
76
- )
77
-
78
-
79
- def log_file_option() -> Any:
80
- """Log file parameter."""
81
- return typer.Option(
82
- None,
83
- "--log-file",
84
- help="Path to JSON log file. If specified, logs will be written to this file in JSON format",
85
- rich_help_panel="Server Settings",
86
- )
35
+ # Factory functions removed - use Annotated syntax directly in commands
87
36
 
88
37
 
89
38
  class ServerOptions:
ccproxy/config/auth.py CHANGED
@@ -10,9 +10,9 @@ from pydantic import BaseModel, Field, field_validator
10
10
  def _get_default_storage_paths() -> list[Path]:
11
11
  """Get default storage paths"""
12
12
  return [
13
- Path("~/.config/claude/.credentials.json"),
14
- Path("~/.claude/.credentials.json"),
15
13
  Path("~/.config/ccproxy/credentials.json"),
14
+ Path("~/.claude/.credentials.json"),
15
+ Path("~/.config/claude/.credentials.json"),
16
16
  ]
17
17
 
18
18
 
@@ -158,7 +158,7 @@ class DockerSettings(BaseModel):
158
158
  """Docker configuration settings for running Claude commands in containers."""
159
159
 
160
160
  docker_image: str = Field(
161
- default=f"ghcr.io/caddyglow/ccproxy:{format_version(__version__, level='docker')}",
161
+ default=f"ghcr.io/caddyglow/ccproxy-api:{format_version(__version__, level='docker')}",
162
162
  description="Docker image to use for Claude commands",
163
163
  )
164
164
 
ccproxy/config/pricing.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from pathlib import Path
4
4
 
5
5
  from pydantic import Field, field_validator
6
- from pydantic_settings import BaseSettings
6
+ from pydantic_settings import BaseSettings, SettingsConfigDict
7
7
 
8
8
  from ccproxy.core.system import get_xdg_cache_home
9
9
 
@@ -81,8 +81,7 @@ class PricingSettings(BaseSettings):
81
81
  raise ValueError("Source URL must start with http:// or https://")
82
82
  return v
83
83
 
84
- class Config:
85
- """Pydantic configuration."""
86
-
87
- env_prefix = "PRICING__"
88
- case_sensitive = False
84
+ model_config = SettingsConfigDict(
85
+ env_prefix="PRICING__",
86
+ case_sensitive=False,
87
+ )
@@ -1,7 +1,7 @@
1
1
  """Scheduler configuration settings."""
2
2
 
3
3
  from pydantic import Field
4
- from pydantic_settings import BaseSettings
4
+ from pydantic_settings import BaseSettings, SettingsConfigDict
5
5
 
6
6
 
7
7
  class SchedulerSettings(BaseSettings):
@@ -82,8 +82,7 @@ class SchedulerSettings(BaseSettings):
82
82
  description="Interval in seconds between stats printing",
83
83
  )
84
84
 
85
- class Config:
86
- """Pydantic configuration."""
87
-
88
- env_prefix = "SCHEDULER__"
89
- case_sensitive = False
85
+ model_config = SettingsConfigDict(
86
+ env_prefix="SCHEDULER__",
87
+ case_sensitive=False,
88
+ )
@@ -467,11 +467,9 @@ class ConfigurationManager:
467
467
  claude_opts = {}
468
468
  for key in [
469
469
  "max_thinking_tokens",
470
- "permission_mode",
471
470
  "cwd",
472
471
  "max_turns",
473
472
  "append_system_prompt",
474
- "permission_prompt_tool_name",
475
473
  "continue_conversation",
476
474
  ]:
477
475
  if cli_args.get(key) is not None:
@@ -319,7 +319,7 @@ def format_version(version: str, level: str) -> str:
319
319
  # Docker-compatible version (no + characters)
320
320
  if suffix:
321
321
  return f"{base_version}-{suffix}"
322
- return base_version
322
+ return f"{major}.{minor}"
323
323
  elif level == "npm":
324
324
  # NPM-compatible version
325
325
  if suffix:
ccproxy/core/types.py CHANGED
@@ -4,7 +4,7 @@ from dataclasses import dataclass, field
4
4
  from enum import Enum
5
5
  from typing import Any, Optional, Union
6
6
 
7
- from pydantic import BaseModel, Field
7
+ from pydantic import BaseModel, ConfigDict, Field
8
8
 
9
9
 
10
10
  class ProxyMethod(str, Enum):
@@ -106,10 +106,7 @@ class ProxyConfig(BaseModel):
106
106
  default=10, description="Maximum number of redirects to follow"
107
107
  )
108
108
 
109
- class Config:
110
- """Pydantic configuration."""
111
-
112
- extra = "forbid"
109
+ model_config = ConfigDict(extra="forbid")
113
110
 
114
111
 
115
112
  class MiddlewareConfig(BaseModel):
@@ -123,7 +120,4 @@ class MiddlewareConfig(BaseModel):
123
120
  default_factory=dict, description="Additional middleware configuration"
124
121
  )
125
122
 
126
- class Config:
127
- """Pydantic configuration."""
128
-
129
- extra = "allow"
123
+ model_config = ConfigDict(extra="allow")
@@ -34,8 +34,7 @@ class MetadataParams(BaseModel):
34
34
  Field(description="External identifier for the user", max_length=256),
35
35
  ] = None
36
36
 
37
- class Config:
38
- extra = "allow" # Allow additional fields in metadata
37
+ model_config = ConfigDict(extra="allow") # Allow additional fields in metadata
39
38
 
40
39
 
41
40
  class ToolChoiceParams(BaseModel):
@@ -143,42 +143,6 @@ class APIError(BaseModel):
143
143
  )
144
144
 
145
145
 
146
- class PermissionToolAllowResponse(BaseModel):
147
- """Response model for allowed permission tool requests."""
148
-
149
- behavior: Annotated[Literal["allow"], Field(description="Permission behavior")] = (
150
- "allow"
151
- )
152
- updated_input: Annotated[
153
- dict[str, Any],
154
- Field(
155
- description="Updated input parameters for the tool, or original input if unchanged",
156
- alias="updatedInput",
157
- ),
158
- ]
159
-
160
- model_config = ConfigDict(extra="forbid", populate_by_name=True)
161
-
162
-
163
- class PermissionToolDenyResponse(BaseModel):
164
- """Response model for denied permission tool requests."""
165
-
166
- behavior: Annotated[Literal["deny"], Field(description="Permission behavior")] = (
167
- "deny"
168
- )
169
- message: Annotated[
170
- str,
171
- Field(
172
- description="Human-readable explanation of why the permission was denied"
173
- ),
174
- ]
175
-
176
- model_config = ConfigDict(extra="forbid")
177
-
178
-
179
- PermissionToolResponse = PermissionToolAllowResponse | PermissionToolDenyResponse
180
-
181
-
182
146
  class RateLimitError(APIError):
183
147
  """Rate limit error."""
184
148
 
ccproxy/pricing/models.py CHANGED
@@ -4,7 +4,7 @@ from collections.abc import Iterator
4
4
  from decimal import Decimal
5
5
  from typing import Any
6
6
 
7
- from pydantic import BaseModel, Field, RootModel, field_validator
7
+ from pydantic import BaseModel, ConfigDict, Field, RootModel, field_validator
8
8
 
9
9
 
10
10
  class ModelPricing(BaseModel):
@@ -32,11 +32,10 @@ class ModelPricing(BaseModel):
32
32
  return v
33
33
  raise TypeError(f"Cannot convert {type(v)} to Decimal")
34
34
 
35
- class Config:
36
- """Pydantic configuration."""
37
-
38
- arbitrary_types_allowed = True
39
- json_encoders = {Decimal: lambda v: float(v)}
35
+ model_config = ConfigDict(
36
+ arbitrary_types_allowed=True,
37
+ json_encoders={Decimal: lambda v: float(v)},
38
+ )
40
39
 
41
40
 
42
41
  class PricingData(RootModel[dict[str, ModelPricing]]):
@@ -446,7 +446,10 @@ class ProxyService:
446
446
  async def _get_access_token(self) -> str:
447
447
  """Get access token for upstream authentication.
448
448
 
449
- Tries configured auth_token first, then falls back to OAuth credentials.
449
+ Uses OAuth credentials from Claude CLI for upstream authentication.
450
+
451
+ NOTE: The SECURITY__AUTH_TOKEN is only for authenticating incoming requests,
452
+ not for upstream authentication.
450
453
 
451
454
  Returns:
452
455
  Valid access token
@@ -454,12 +457,8 @@ class ProxyService:
454
457
  Raises:
455
458
  HTTPException: If no valid token is available
456
459
  """
457
- # First try to get configured auth_token from settings
458
- if self.settings.security.auth_token:
459
- logger.debug("using_configured_auth_token")
460
- return self.settings.security.auth_token
461
-
462
- # Fall back to OAuth credentials
460
+ # Always use OAuth credentials for upstream authentication
461
+ # The SECURITY__AUTH_TOKEN is only for client authentication, not upstream
463
462
  try:
464
463
  access_token = await self.credentials_manager.get_access_token()
465
464
  if not access_token:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ccproxy-api
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: API server that provides an Anthropic and OpenAI compatible interface over Claude Code, allowing to use your Claude OAuth account or over the API.
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -43,14 +43,26 @@ It includes a translation layer to support both Anthropic and OpenAI-compatible
43
43
  # The official claude-code CLI is required for SDK mode
44
44
  npm install -g @anthropic-ai/claude-code
45
45
 
46
- # Install ccproxy
47
- pipx install git+https://github.com/caddyglow/ccproxy-api.git@dev
46
+ # run it with uv
47
+ uvx ccproxy-api
48
+
49
+ # run it with pipx
50
+ pipx run ccproxy-api
51
+
52
+ # install with uv
53
+ uv tool install ccproxy-api
54
+
55
+ # Install ccproxy with pip
56
+ pipx install ccproxy-api
48
57
 
49
58
  # Optional: Enable shell completion
50
59
  eval "$(ccproxy --show-completion zsh)" # For zsh
51
60
  eval "$(ccproxy --show-completion bash)" # For bash
52
61
  ```
53
62
 
63
+
64
+ For dev version replace `ccproxy-api` with `git+https://github.com/caddyglow/ccproxy-api.git@dev`
65
+
54
66
  ## Authentication
55
67
 
56
68
  The proxy uses two different authentication mechanisms depending on the mode.
@@ -61,12 +73,23 @@ The proxy uses two different authentication mechanisms depending on the mode.
61
73
  claude /login
62
74
  ```
63
75
 
76
+ It's also possible now to get a long live token to avoid renewing issues
77
+ using
78
+ ```sh
79
+ ```bash
80
+ claude setup-token`
81
+
64
82
  2. **ccproxy (`api` mode):**
65
83
  This mode uses its own OAuth2 flow to obtain credentials for direct API access.
66
84
  ```bash
67
85
  ccproxy auth login
68
86
  ```
69
- You can check the status of these credentials with `ccproxy auth validate` and `ccproxy auth info`.
87
+
88
+ If you are already connected with Claude CLI the credentials should be found automatically
89
+
90
+ You can check the status of these credentials with `ccproxy auth validate` and `ccproxy auth info`.
91
+
92
+ Warning is show on start up if no credentials are setup.
70
93
 
71
94
  ## Usage
72
95
 
@@ -102,6 +125,38 @@ export ANTHROPIC_BASE_URL="http://localhost:8000/api"
102
125
  export ANTHROPIC_API_KEY="dummy-key"
103
126
  ```
104
127
 
128
+
129
+ ## Using with Aider
130
+
131
+ CCProxy works seamlessly with Aider and other AI coding assistants:
132
+
133
+ ### Anthropic Mode
134
+ ```bash
135
+ export ANTHROPIC_API_KEY=dummy
136
+ export ANTHROPIC_BASE_URL=http://127.0.0.1:8000/api
137
+ aider --model claude-sonnet-4-20250514
138
+ ```
139
+
140
+ ### OpenAI Mode with Model Mapping
141
+
142
+ If your tool only supports OpenAI settings, ccproxy automatically maps OpenAI models to Claude:
143
+
144
+ ```bash
145
+ export OPENAI_API_KEY=dummy
146
+ export OPENAI_BASE_URL=http://127.0.0.1:8000/api/v1
147
+ aider --model o3-mini
148
+ ```
149
+
150
+ ### API Mode (Direct Proxy)
151
+
152
+ For minimal interference and direct API access:
153
+
154
+ ```bash
155
+ export OPENAI_API_KEY=dummy
156
+ export OPENAI_BASE_URL=http://127.0.0.1:8000/api/v1
157
+ aider --model o3-mini
158
+ ```
159
+
105
160
  ### `curl` Example
106
161
 
107
162
  ```bash
@@ -185,16 +240,16 @@ You can enable token authentication for the proxy. This supports multiple header
185
240
  **1. Generate a Token:**
186
241
  ```bash
187
242
  ccproxy generate-token
188
- # Output: AUTH_TOKEN=abc123xyz789...
243
+ # Output: SECURITY__AUTH_TOKEN=abc123xyz789...
189
244
  ```
190
245
 
191
246
  **2. Configure the Token:**
192
247
  ```bash
193
248
  # Set environment variable
194
- export AUTH_TOKEN=abc123xyz789...
249
+ export SECURITY__AUTH_TOKEN=abc123xyz789...
195
250
 
196
251
  # Or add to .env file
197
- echo "AUTH_TOKEN=abc123xyz789..." >> .env
252
+ echo "SECURITY__AUTH_TOKEN=abc123xyz789..." >> .env
198
253
  ```
199
254
 
200
255
  **3. Use in Requests:**