ccproxy-api 0.1.6__py3-none-any.whl → 0.2.0__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.
Files changed (481) hide show
  1. ccproxy/api/__init__.py +1 -15
  2. ccproxy/api/app.py +439 -212
  3. ccproxy/api/bootstrap.py +30 -0
  4. ccproxy/api/decorators.py +85 -0
  5. ccproxy/api/dependencies.py +145 -176
  6. ccproxy/api/format_validation.py +54 -0
  7. ccproxy/api/middleware/cors.py +6 -3
  8. ccproxy/api/middleware/errors.py +402 -530
  9. ccproxy/api/middleware/hooks.py +563 -0
  10. ccproxy/api/middleware/normalize_headers.py +59 -0
  11. ccproxy/api/middleware/request_id.py +35 -16
  12. ccproxy/api/middleware/streaming_hooks.py +292 -0
  13. ccproxy/api/routes/__init__.py +5 -14
  14. ccproxy/api/routes/health.py +39 -672
  15. ccproxy/api/routes/plugins.py +277 -0
  16. ccproxy/auth/__init__.py +2 -19
  17. ccproxy/auth/bearer.py +25 -15
  18. ccproxy/auth/dependencies.py +123 -157
  19. ccproxy/auth/exceptions.py +0 -12
  20. ccproxy/auth/manager.py +35 -49
  21. ccproxy/auth/managers/__init__.py +10 -0
  22. ccproxy/auth/managers/base.py +523 -0
  23. ccproxy/auth/managers/base_enhanced.py +63 -0
  24. ccproxy/auth/managers/token_snapshot.py +77 -0
  25. ccproxy/auth/models/base.py +65 -0
  26. ccproxy/auth/models/credentials.py +40 -0
  27. ccproxy/auth/oauth/__init__.py +4 -18
  28. ccproxy/auth/oauth/base.py +533 -0
  29. ccproxy/auth/oauth/cli_errors.py +37 -0
  30. ccproxy/auth/oauth/flows.py +430 -0
  31. ccproxy/auth/oauth/protocol.py +366 -0
  32. ccproxy/auth/oauth/registry.py +408 -0
  33. ccproxy/auth/oauth/router.py +396 -0
  34. ccproxy/auth/oauth/routes.py +186 -113
  35. ccproxy/auth/oauth/session.py +151 -0
  36. ccproxy/auth/oauth/templates.py +342 -0
  37. ccproxy/auth/storage/__init__.py +2 -5
  38. ccproxy/auth/storage/base.py +279 -5
  39. ccproxy/auth/storage/generic.py +134 -0
  40. ccproxy/cli/__init__.py +1 -2
  41. ccproxy/cli/_settings_help.py +351 -0
  42. ccproxy/cli/commands/auth.py +1519 -793
  43. ccproxy/cli/commands/config/commands.py +209 -276
  44. ccproxy/cli/commands/plugins.py +669 -0
  45. ccproxy/cli/commands/serve.py +75 -810
  46. ccproxy/cli/commands/status.py +254 -0
  47. ccproxy/cli/decorators.py +83 -0
  48. ccproxy/cli/helpers.py +22 -60
  49. ccproxy/cli/main.py +359 -10
  50. ccproxy/cli/options/claude_options.py +0 -25
  51. ccproxy/config/__init__.py +7 -11
  52. ccproxy/config/core.py +227 -0
  53. ccproxy/config/env_generator.py +232 -0
  54. ccproxy/config/runtime.py +67 -0
  55. ccproxy/config/security.py +36 -3
  56. ccproxy/config/settings.py +382 -441
  57. ccproxy/config/toml_generator.py +299 -0
  58. ccproxy/config/utils.py +452 -0
  59. ccproxy/core/__init__.py +7 -271
  60. ccproxy/{_version.py → core/_version.py} +16 -3
  61. ccproxy/core/async_task_manager.py +516 -0
  62. ccproxy/core/async_utils.py +47 -14
  63. ccproxy/core/auth/__init__.py +6 -0
  64. ccproxy/core/constants.py +16 -50
  65. ccproxy/core/errors.py +53 -0
  66. ccproxy/core/id_utils.py +20 -0
  67. ccproxy/core/interfaces.py +16 -123
  68. ccproxy/core/logging.py +473 -18
  69. ccproxy/core/plugins/__init__.py +77 -0
  70. ccproxy/core/plugins/cli_discovery.py +211 -0
  71. ccproxy/core/plugins/declaration.py +455 -0
  72. ccproxy/core/plugins/discovery.py +604 -0
  73. ccproxy/core/plugins/factories.py +967 -0
  74. ccproxy/core/plugins/hooks/__init__.py +30 -0
  75. ccproxy/core/plugins/hooks/base.py +58 -0
  76. ccproxy/core/plugins/hooks/events.py +46 -0
  77. ccproxy/core/plugins/hooks/implementations/__init__.py +16 -0
  78. ccproxy/core/plugins/hooks/implementations/formatters/__init__.py +11 -0
  79. ccproxy/core/plugins/hooks/implementations/formatters/json.py +552 -0
  80. ccproxy/core/plugins/hooks/implementations/formatters/raw.py +370 -0
  81. ccproxy/core/plugins/hooks/implementations/http_tracer.py +431 -0
  82. ccproxy/core/plugins/hooks/layers.py +44 -0
  83. ccproxy/core/plugins/hooks/manager.py +186 -0
  84. ccproxy/core/plugins/hooks/registry.py +139 -0
  85. ccproxy/core/plugins/hooks/thread_manager.py +203 -0
  86. ccproxy/core/plugins/hooks/types.py +22 -0
  87. ccproxy/core/plugins/interfaces.py +416 -0
  88. ccproxy/core/plugins/loader.py +166 -0
  89. ccproxy/core/plugins/middleware.py +233 -0
  90. ccproxy/core/plugins/models.py +59 -0
  91. ccproxy/core/plugins/protocol.py +180 -0
  92. ccproxy/core/plugins/runtime.py +519 -0
  93. ccproxy/{observability/context.py → core/request_context.py} +137 -94
  94. ccproxy/core/status_report.py +211 -0
  95. ccproxy/core/transformers.py +13 -8
  96. ccproxy/data/claude_headers_fallback.json +558 -0
  97. ccproxy/data/codex_headers_fallback.json +121 -0
  98. ccproxy/http/__init__.py +30 -0
  99. ccproxy/http/base.py +95 -0
  100. ccproxy/http/client.py +323 -0
  101. ccproxy/http/hooks.py +642 -0
  102. ccproxy/http/pool.py +279 -0
  103. ccproxy/llms/formatters/__init__.py +7 -0
  104. ccproxy/llms/formatters/anthropic_to_openai/__init__.py +55 -0
  105. ccproxy/llms/formatters/anthropic_to_openai/errors.py +65 -0
  106. ccproxy/llms/formatters/anthropic_to_openai/requests.py +356 -0
  107. ccproxy/llms/formatters/anthropic_to_openai/responses.py +153 -0
  108. ccproxy/llms/formatters/anthropic_to_openai/streams.py +1546 -0
  109. ccproxy/llms/formatters/base.py +140 -0
  110. ccproxy/llms/formatters/base_model.py +33 -0
  111. ccproxy/llms/formatters/common/__init__.py +51 -0
  112. ccproxy/llms/formatters/common/identifiers.py +48 -0
  113. ccproxy/llms/formatters/common/streams.py +254 -0
  114. ccproxy/llms/formatters/common/thinking.py +74 -0
  115. ccproxy/llms/formatters/common/usage.py +135 -0
  116. ccproxy/llms/formatters/constants.py +55 -0
  117. ccproxy/llms/formatters/context.py +116 -0
  118. ccproxy/llms/formatters/mapping.py +33 -0
  119. ccproxy/llms/formatters/openai_to_anthropic/__init__.py +55 -0
  120. ccproxy/llms/formatters/openai_to_anthropic/_helpers.py +141 -0
  121. ccproxy/llms/formatters/openai_to_anthropic/errors.py +53 -0
  122. ccproxy/llms/formatters/openai_to_anthropic/requests.py +674 -0
  123. ccproxy/llms/formatters/openai_to_anthropic/responses.py +285 -0
  124. ccproxy/llms/formatters/openai_to_anthropic/streams.py +530 -0
  125. ccproxy/llms/formatters/openai_to_openai/__init__.py +53 -0
  126. ccproxy/llms/formatters/openai_to_openai/_helpers.py +325 -0
  127. ccproxy/llms/formatters/openai_to_openai/errors.py +6 -0
  128. ccproxy/llms/formatters/openai_to_openai/requests.py +388 -0
  129. ccproxy/llms/formatters/openai_to_openai/responses.py +594 -0
  130. ccproxy/llms/formatters/openai_to_openai/streams.py +1832 -0
  131. ccproxy/llms/formatters/utils.py +306 -0
  132. ccproxy/llms/models/__init__.py +9 -0
  133. ccproxy/llms/models/anthropic.py +619 -0
  134. ccproxy/llms/models/openai.py +844 -0
  135. ccproxy/llms/streaming/__init__.py +26 -0
  136. ccproxy/llms/streaming/accumulators.py +1074 -0
  137. ccproxy/llms/streaming/formatters.py +251 -0
  138. ccproxy/{adapters/openai/streaming.py → llms/streaming/processors.py} +193 -240
  139. ccproxy/models/__init__.py +8 -159
  140. ccproxy/models/detection.py +92 -193
  141. ccproxy/models/provider.py +75 -0
  142. ccproxy/plugins/access_log/README.md +32 -0
  143. ccproxy/plugins/access_log/__init__.py +20 -0
  144. ccproxy/plugins/access_log/config.py +33 -0
  145. ccproxy/plugins/access_log/formatter.py +126 -0
  146. ccproxy/plugins/access_log/hook.py +763 -0
  147. ccproxy/plugins/access_log/logger.py +254 -0
  148. ccproxy/plugins/access_log/plugin.py +137 -0
  149. ccproxy/plugins/access_log/writer.py +109 -0
  150. ccproxy/plugins/analytics/README.md +24 -0
  151. ccproxy/plugins/analytics/__init__.py +1 -0
  152. ccproxy/plugins/analytics/config.py +5 -0
  153. ccproxy/plugins/analytics/ingest.py +85 -0
  154. ccproxy/plugins/analytics/models.py +97 -0
  155. ccproxy/plugins/analytics/plugin.py +121 -0
  156. ccproxy/plugins/analytics/routes.py +163 -0
  157. ccproxy/plugins/analytics/service.py +284 -0
  158. ccproxy/plugins/claude_api/README.md +29 -0
  159. ccproxy/plugins/claude_api/__init__.py +10 -0
  160. ccproxy/plugins/claude_api/adapter.py +829 -0
  161. ccproxy/plugins/claude_api/config.py +52 -0
  162. ccproxy/plugins/claude_api/detection_service.py +461 -0
  163. ccproxy/plugins/claude_api/health.py +175 -0
  164. ccproxy/plugins/claude_api/hooks.py +284 -0
  165. ccproxy/plugins/claude_api/models.py +256 -0
  166. ccproxy/plugins/claude_api/plugin.py +298 -0
  167. ccproxy/plugins/claude_api/routes.py +118 -0
  168. ccproxy/plugins/claude_api/streaming_metrics.py +68 -0
  169. ccproxy/plugins/claude_api/tasks.py +84 -0
  170. ccproxy/plugins/claude_sdk/README.md +35 -0
  171. ccproxy/plugins/claude_sdk/__init__.py +80 -0
  172. ccproxy/plugins/claude_sdk/adapter.py +749 -0
  173. ccproxy/plugins/claude_sdk/auth.py +57 -0
  174. ccproxy/{claude_sdk → plugins/claude_sdk}/client.py +63 -39
  175. ccproxy/plugins/claude_sdk/config.py +210 -0
  176. ccproxy/{claude_sdk → plugins/claude_sdk}/converter.py +6 -6
  177. ccproxy/plugins/claude_sdk/detection_service.py +163 -0
  178. ccproxy/{services/claude_sdk_service.py → plugins/claude_sdk/handler.py} +123 -304
  179. ccproxy/plugins/claude_sdk/health.py +113 -0
  180. ccproxy/plugins/claude_sdk/hooks.py +115 -0
  181. ccproxy/{claude_sdk → plugins/claude_sdk}/manager.py +42 -32
  182. ccproxy/{claude_sdk → plugins/claude_sdk}/message_queue.py +8 -8
  183. ccproxy/{models/claude_sdk.py → plugins/claude_sdk/models.py} +64 -16
  184. ccproxy/plugins/claude_sdk/options.py +154 -0
  185. ccproxy/{claude_sdk → plugins/claude_sdk}/parser.py +23 -5
  186. ccproxy/plugins/claude_sdk/plugin.py +269 -0
  187. ccproxy/plugins/claude_sdk/routes.py +104 -0
  188. ccproxy/{claude_sdk → plugins/claude_sdk}/session_client.py +124 -12
  189. ccproxy/plugins/claude_sdk/session_pool.py +700 -0
  190. ccproxy/{claude_sdk → plugins/claude_sdk}/stream_handle.py +48 -43
  191. ccproxy/{claude_sdk → plugins/claude_sdk}/stream_worker.py +22 -18
  192. ccproxy/{claude_sdk → plugins/claude_sdk}/streaming.py +50 -16
  193. ccproxy/plugins/claude_sdk/tasks.py +97 -0
  194. ccproxy/plugins/claude_shared/README.md +18 -0
  195. ccproxy/plugins/claude_shared/__init__.py +12 -0
  196. ccproxy/plugins/claude_shared/model_defaults.py +171 -0
  197. ccproxy/plugins/codex/README.md +35 -0
  198. ccproxy/plugins/codex/__init__.py +6 -0
  199. ccproxy/plugins/codex/adapter.py +635 -0
  200. ccproxy/{config/codex.py → plugins/codex/config.py} +78 -12
  201. ccproxy/plugins/codex/detection_service.py +544 -0
  202. ccproxy/plugins/codex/health.py +162 -0
  203. ccproxy/plugins/codex/hooks.py +263 -0
  204. ccproxy/plugins/codex/model_defaults.py +39 -0
  205. ccproxy/plugins/codex/models.py +263 -0
  206. ccproxy/plugins/codex/plugin.py +275 -0
  207. ccproxy/plugins/codex/routes.py +129 -0
  208. ccproxy/plugins/codex/streaming_metrics.py +324 -0
  209. ccproxy/plugins/codex/tasks.py +106 -0
  210. ccproxy/plugins/codex/utils/__init__.py +1 -0
  211. ccproxy/plugins/codex/utils/sse_parser.py +106 -0
  212. ccproxy/plugins/command_replay/README.md +34 -0
  213. ccproxy/plugins/command_replay/__init__.py +17 -0
  214. ccproxy/plugins/command_replay/config.py +133 -0
  215. ccproxy/plugins/command_replay/formatter.py +432 -0
  216. ccproxy/plugins/command_replay/hook.py +294 -0
  217. ccproxy/plugins/command_replay/plugin.py +161 -0
  218. ccproxy/plugins/copilot/README.md +39 -0
  219. ccproxy/plugins/copilot/__init__.py +11 -0
  220. ccproxy/plugins/copilot/adapter.py +465 -0
  221. ccproxy/plugins/copilot/config.py +155 -0
  222. ccproxy/plugins/copilot/data/copilot_fallback.json +41 -0
  223. ccproxy/plugins/copilot/detection_service.py +255 -0
  224. ccproxy/plugins/copilot/manager.py +275 -0
  225. ccproxy/plugins/copilot/model_defaults.py +284 -0
  226. ccproxy/plugins/copilot/models.py +148 -0
  227. ccproxy/plugins/copilot/oauth/__init__.py +16 -0
  228. ccproxy/plugins/copilot/oauth/client.py +494 -0
  229. ccproxy/plugins/copilot/oauth/models.py +385 -0
  230. ccproxy/plugins/copilot/oauth/provider.py +602 -0
  231. ccproxy/plugins/copilot/oauth/storage.py +170 -0
  232. ccproxy/plugins/copilot/plugin.py +360 -0
  233. ccproxy/plugins/copilot/routes.py +294 -0
  234. ccproxy/plugins/credential_balancer/README.md +124 -0
  235. ccproxy/plugins/credential_balancer/__init__.py +6 -0
  236. ccproxy/plugins/credential_balancer/config.py +270 -0
  237. ccproxy/plugins/credential_balancer/factory.py +415 -0
  238. ccproxy/plugins/credential_balancer/hook.py +51 -0
  239. ccproxy/plugins/credential_balancer/manager.py +587 -0
  240. ccproxy/plugins/credential_balancer/plugin.py +146 -0
  241. ccproxy/plugins/dashboard/README.md +25 -0
  242. ccproxy/plugins/dashboard/__init__.py +1 -0
  243. ccproxy/plugins/dashboard/config.py +8 -0
  244. ccproxy/plugins/dashboard/plugin.py +71 -0
  245. ccproxy/plugins/dashboard/routes.py +67 -0
  246. ccproxy/plugins/docker/README.md +32 -0
  247. ccproxy/{docker → plugins/docker}/__init__.py +3 -0
  248. ccproxy/{docker → plugins/docker}/adapter.py +108 -10
  249. ccproxy/plugins/docker/config.py +82 -0
  250. ccproxy/{docker → plugins/docker}/docker_path.py +4 -3
  251. ccproxy/{docker → plugins/docker}/middleware.py +2 -2
  252. ccproxy/plugins/docker/plugin.py +198 -0
  253. ccproxy/{docker → plugins/docker}/stream_process.py +3 -3
  254. ccproxy/plugins/duckdb_storage/README.md +26 -0
  255. ccproxy/plugins/duckdb_storage/__init__.py +1 -0
  256. ccproxy/plugins/duckdb_storage/config.py +22 -0
  257. ccproxy/plugins/duckdb_storage/plugin.py +128 -0
  258. ccproxy/plugins/duckdb_storage/routes.py +51 -0
  259. ccproxy/plugins/duckdb_storage/storage.py +633 -0
  260. ccproxy/plugins/max_tokens/README.md +38 -0
  261. ccproxy/plugins/max_tokens/__init__.py +12 -0
  262. ccproxy/plugins/max_tokens/adapter.py +235 -0
  263. ccproxy/plugins/max_tokens/config.py +86 -0
  264. ccproxy/plugins/max_tokens/models.py +53 -0
  265. ccproxy/plugins/max_tokens/plugin.py +200 -0
  266. ccproxy/plugins/max_tokens/service.py +271 -0
  267. ccproxy/plugins/max_tokens/token_limits.json +54 -0
  268. ccproxy/plugins/metrics/README.md +35 -0
  269. ccproxy/plugins/metrics/__init__.py +10 -0
  270. ccproxy/{observability/metrics.py → plugins/metrics/collector.py} +20 -153
  271. ccproxy/plugins/metrics/config.py +85 -0
  272. ccproxy/plugins/metrics/grafana/dashboards/ccproxy-dashboard.json +1720 -0
  273. ccproxy/plugins/metrics/hook.py +403 -0
  274. ccproxy/plugins/metrics/plugin.py +268 -0
  275. ccproxy/{observability → plugins/metrics}/pushgateway.py +57 -59
  276. ccproxy/plugins/metrics/routes.py +107 -0
  277. ccproxy/plugins/metrics/tasks.py +117 -0
  278. ccproxy/plugins/oauth_claude/README.md +35 -0
  279. ccproxy/plugins/oauth_claude/__init__.py +14 -0
  280. ccproxy/plugins/oauth_claude/client.py +270 -0
  281. ccproxy/plugins/oauth_claude/config.py +84 -0
  282. ccproxy/plugins/oauth_claude/manager.py +482 -0
  283. ccproxy/plugins/oauth_claude/models.py +266 -0
  284. ccproxy/plugins/oauth_claude/plugin.py +149 -0
  285. ccproxy/plugins/oauth_claude/provider.py +571 -0
  286. ccproxy/plugins/oauth_claude/storage.py +212 -0
  287. ccproxy/plugins/oauth_codex/README.md +38 -0
  288. ccproxy/plugins/oauth_codex/__init__.py +14 -0
  289. ccproxy/plugins/oauth_codex/client.py +224 -0
  290. ccproxy/plugins/oauth_codex/config.py +95 -0
  291. ccproxy/plugins/oauth_codex/manager.py +256 -0
  292. ccproxy/plugins/oauth_codex/models.py +239 -0
  293. ccproxy/plugins/oauth_codex/plugin.py +146 -0
  294. ccproxy/plugins/oauth_codex/provider.py +574 -0
  295. ccproxy/plugins/oauth_codex/storage.py +92 -0
  296. ccproxy/plugins/permissions/README.md +28 -0
  297. ccproxy/plugins/permissions/__init__.py +22 -0
  298. ccproxy/plugins/permissions/config.py +28 -0
  299. ccproxy/{cli/commands/permission_handler.py → plugins/permissions/handlers/cli.py} +49 -25
  300. ccproxy/plugins/permissions/handlers/protocol.py +33 -0
  301. ccproxy/plugins/permissions/handlers/terminal.py +675 -0
  302. ccproxy/{api/routes → plugins/permissions}/mcp.py +34 -7
  303. ccproxy/{models/permissions.py → plugins/permissions/models.py} +65 -1
  304. ccproxy/plugins/permissions/plugin.py +153 -0
  305. ccproxy/{api/routes/permissions.py → plugins/permissions/routes.py} +20 -16
  306. ccproxy/{api/services/permission_service.py → plugins/permissions/service.py} +65 -11
  307. ccproxy/{api → plugins/permissions}/ui/permission_handler_protocol.py +1 -1
  308. ccproxy/{api → plugins/permissions}/ui/terminal_permission_handler.py +66 -10
  309. ccproxy/plugins/pricing/README.md +34 -0
  310. ccproxy/plugins/pricing/__init__.py +6 -0
  311. ccproxy/{pricing → plugins/pricing}/cache.py +7 -6
  312. ccproxy/{config/pricing.py → plugins/pricing/config.py} +32 -6
  313. ccproxy/plugins/pricing/exceptions.py +35 -0
  314. ccproxy/plugins/pricing/loader.py +440 -0
  315. ccproxy/{pricing → plugins/pricing}/models.py +13 -23
  316. ccproxy/plugins/pricing/plugin.py +169 -0
  317. ccproxy/plugins/pricing/service.py +191 -0
  318. ccproxy/plugins/pricing/tasks.py +300 -0
  319. ccproxy/{pricing → plugins/pricing}/updater.py +86 -72
  320. ccproxy/plugins/pricing/utils.py +99 -0
  321. ccproxy/plugins/request_tracer/README.md +40 -0
  322. ccproxy/plugins/request_tracer/__init__.py +7 -0
  323. ccproxy/plugins/request_tracer/config.py +120 -0
  324. ccproxy/plugins/request_tracer/hook.py +415 -0
  325. ccproxy/plugins/request_tracer/plugin.py +255 -0
  326. ccproxy/scheduler/__init__.py +2 -14
  327. ccproxy/scheduler/core.py +26 -41
  328. ccproxy/scheduler/manager.py +63 -107
  329. ccproxy/scheduler/registry.py +6 -32
  330. ccproxy/scheduler/tasks.py +346 -314
  331. ccproxy/services/__init__.py +0 -1
  332. ccproxy/services/adapters/__init__.py +11 -0
  333. ccproxy/services/adapters/base.py +123 -0
  334. ccproxy/services/adapters/chain_composer.py +88 -0
  335. ccproxy/services/adapters/chain_validation.py +44 -0
  336. ccproxy/services/adapters/chat_accumulator.py +200 -0
  337. ccproxy/services/adapters/delta_utils.py +142 -0
  338. ccproxy/services/adapters/format_adapter.py +136 -0
  339. ccproxy/services/adapters/format_context.py +11 -0
  340. ccproxy/services/adapters/format_registry.py +158 -0
  341. ccproxy/services/adapters/http_adapter.py +1045 -0
  342. ccproxy/services/adapters/mock_adapter.py +118 -0
  343. ccproxy/services/adapters/protocols.py +35 -0
  344. ccproxy/services/adapters/simple_converters.py +571 -0
  345. ccproxy/services/auth_registry.py +180 -0
  346. ccproxy/services/cache/__init__.py +6 -0
  347. ccproxy/services/cache/response_cache.py +261 -0
  348. ccproxy/services/cli_detection.py +437 -0
  349. ccproxy/services/config/__init__.py +6 -0
  350. ccproxy/services/config/proxy_configuration.py +111 -0
  351. ccproxy/services/container.py +256 -0
  352. ccproxy/services/factories.py +380 -0
  353. ccproxy/services/handler_config.py +76 -0
  354. ccproxy/services/interfaces.py +298 -0
  355. ccproxy/services/mocking/__init__.py +6 -0
  356. ccproxy/services/mocking/mock_handler.py +291 -0
  357. ccproxy/services/tracing/__init__.py +7 -0
  358. ccproxy/services/tracing/interfaces.py +61 -0
  359. ccproxy/services/tracing/null_tracer.py +57 -0
  360. ccproxy/streaming/__init__.py +23 -0
  361. ccproxy/streaming/buffer.py +1056 -0
  362. ccproxy/streaming/deferred.py +897 -0
  363. ccproxy/streaming/handler.py +117 -0
  364. ccproxy/streaming/interfaces.py +77 -0
  365. ccproxy/streaming/simple_adapter.py +39 -0
  366. ccproxy/streaming/sse.py +109 -0
  367. ccproxy/streaming/sse_parser.py +127 -0
  368. ccproxy/templates/__init__.py +6 -0
  369. ccproxy/templates/plugin_scaffold.py +695 -0
  370. ccproxy/testing/endpoints/__init__.py +33 -0
  371. ccproxy/testing/endpoints/cli.py +215 -0
  372. ccproxy/testing/endpoints/config.py +874 -0
  373. ccproxy/testing/endpoints/console.py +57 -0
  374. ccproxy/testing/endpoints/models.py +100 -0
  375. ccproxy/testing/endpoints/runner.py +1903 -0
  376. ccproxy/testing/endpoints/tools.py +308 -0
  377. ccproxy/testing/mock_responses.py +70 -1
  378. ccproxy/testing/response_handlers.py +20 -0
  379. ccproxy/utils/__init__.py +0 -6
  380. ccproxy/utils/binary_resolver.py +476 -0
  381. ccproxy/utils/caching.py +327 -0
  382. ccproxy/utils/cli_logging.py +101 -0
  383. ccproxy/utils/command_line.py +251 -0
  384. ccproxy/utils/headers.py +228 -0
  385. ccproxy/utils/model_mapper.py +120 -0
  386. ccproxy/utils/startup_helpers.py +95 -342
  387. ccproxy/utils/version_checker.py +279 -6
  388. ccproxy_api-0.2.0.dist-info/METADATA +212 -0
  389. ccproxy_api-0.2.0.dist-info/RECORD +417 -0
  390. {ccproxy_api-0.1.6.dist-info → ccproxy_api-0.2.0.dist-info}/WHEEL +1 -1
  391. ccproxy_api-0.2.0.dist-info/entry_points.txt +24 -0
  392. ccproxy/__init__.py +0 -4
  393. ccproxy/adapters/__init__.py +0 -11
  394. ccproxy/adapters/base.py +0 -80
  395. ccproxy/adapters/codex/__init__.py +0 -11
  396. ccproxy/adapters/openai/__init__.py +0 -42
  397. ccproxy/adapters/openai/adapter.py +0 -953
  398. ccproxy/adapters/openai/models.py +0 -412
  399. ccproxy/adapters/openai/response_adapter.py +0 -355
  400. ccproxy/adapters/openai/response_models.py +0 -178
  401. ccproxy/api/middleware/headers.py +0 -49
  402. ccproxy/api/middleware/logging.py +0 -180
  403. ccproxy/api/middleware/request_content_logging.py +0 -297
  404. ccproxy/api/middleware/server_header.py +0 -58
  405. ccproxy/api/responses.py +0 -89
  406. ccproxy/api/routes/claude.py +0 -371
  407. ccproxy/api/routes/codex.py +0 -1231
  408. ccproxy/api/routes/metrics.py +0 -1029
  409. ccproxy/api/routes/proxy.py +0 -211
  410. ccproxy/api/services/__init__.py +0 -6
  411. ccproxy/auth/conditional.py +0 -84
  412. ccproxy/auth/credentials_adapter.py +0 -93
  413. ccproxy/auth/models.py +0 -118
  414. ccproxy/auth/oauth/models.py +0 -48
  415. ccproxy/auth/openai/__init__.py +0 -13
  416. ccproxy/auth/openai/credentials.py +0 -166
  417. ccproxy/auth/openai/oauth_client.py +0 -334
  418. ccproxy/auth/openai/storage.py +0 -184
  419. ccproxy/auth/storage/json_file.py +0 -158
  420. ccproxy/auth/storage/keyring.py +0 -189
  421. ccproxy/claude_sdk/__init__.py +0 -18
  422. ccproxy/claude_sdk/options.py +0 -194
  423. ccproxy/claude_sdk/session_pool.py +0 -550
  424. ccproxy/cli/docker/__init__.py +0 -34
  425. ccproxy/cli/docker/adapter_factory.py +0 -157
  426. ccproxy/cli/docker/params.py +0 -274
  427. ccproxy/config/auth.py +0 -153
  428. ccproxy/config/claude.py +0 -348
  429. ccproxy/config/cors.py +0 -79
  430. ccproxy/config/discovery.py +0 -95
  431. ccproxy/config/docker_settings.py +0 -264
  432. ccproxy/config/observability.py +0 -158
  433. ccproxy/config/reverse_proxy.py +0 -31
  434. ccproxy/config/scheduler.py +0 -108
  435. ccproxy/config/server.py +0 -86
  436. ccproxy/config/validators.py +0 -231
  437. ccproxy/core/codex_transformers.py +0 -389
  438. ccproxy/core/http.py +0 -328
  439. ccproxy/core/http_transformers.py +0 -812
  440. ccproxy/core/proxy.py +0 -143
  441. ccproxy/core/validators.py +0 -288
  442. ccproxy/models/errors.py +0 -42
  443. ccproxy/models/messages.py +0 -269
  444. ccproxy/models/requests.py +0 -107
  445. ccproxy/models/responses.py +0 -270
  446. ccproxy/models/types.py +0 -102
  447. ccproxy/observability/__init__.py +0 -51
  448. ccproxy/observability/access_logger.py +0 -457
  449. ccproxy/observability/sse_events.py +0 -303
  450. ccproxy/observability/stats_printer.py +0 -753
  451. ccproxy/observability/storage/__init__.py +0 -1
  452. ccproxy/observability/storage/duckdb_simple.py +0 -677
  453. ccproxy/observability/storage/models.py +0 -70
  454. ccproxy/observability/streaming_response.py +0 -107
  455. ccproxy/pricing/__init__.py +0 -19
  456. ccproxy/pricing/loader.py +0 -251
  457. ccproxy/services/claude_detection_service.py +0 -269
  458. ccproxy/services/codex_detection_service.py +0 -263
  459. ccproxy/services/credentials/__init__.py +0 -55
  460. ccproxy/services/credentials/config.py +0 -105
  461. ccproxy/services/credentials/manager.py +0 -561
  462. ccproxy/services/credentials/oauth_client.py +0 -481
  463. ccproxy/services/proxy_service.py +0 -1827
  464. ccproxy/static/.keep +0 -0
  465. ccproxy/utils/cost_calculator.py +0 -210
  466. ccproxy/utils/disconnection_monitor.py +0 -83
  467. ccproxy/utils/model_mapping.py +0 -199
  468. ccproxy/utils/models_provider.py +0 -150
  469. ccproxy/utils/simple_request_logger.py +0 -284
  470. ccproxy/utils/streaming_metrics.py +0 -199
  471. ccproxy_api-0.1.6.dist-info/METADATA +0 -615
  472. ccproxy_api-0.1.6.dist-info/RECORD +0 -189
  473. ccproxy_api-0.1.6.dist-info/entry_points.txt +0 -4
  474. /ccproxy/{api/middleware/auth.py → auth/models/__init__.py} +0 -0
  475. /ccproxy/{claude_sdk → plugins/claude_sdk}/exceptions.py +0 -0
  476. /ccproxy/{docker → plugins/docker}/models.py +0 -0
  477. /ccproxy/{docker → plugins/docker}/protocol.py +0 -0
  478. /ccproxy/{docker → plugins/docker}/validators.py +0 -0
  479. /ccproxy/{auth/oauth/storage.py → plugins/permissions/handlers/__init__.py} +0 -0
  480. /ccproxy/{api → plugins/permissions}/ui/__init__.py +0 -0
  481. {ccproxy_api-0.1.6.dist-info → ccproxy_api-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,229 +1,195 @@
1
- """FastAPI dependency injection for authentication."""
1
+ """FastAPI dependency injection utilities for authentication."""
2
+
3
+ from __future__ import annotations
2
4
 
3
5
  from typing import TYPE_CHECKING, Annotated
4
6
 
5
- from fastapi import Depends, HTTPException, status
7
+ from fastapi import Depends, HTTPException, Request, status
6
8
  from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
7
9
 
8
-
9
- if TYPE_CHECKING:
10
- from ccproxy.config.settings import Settings
11
-
12
10
  from ccproxy.auth.bearer import BearerTokenAuthManager
13
- from ccproxy.auth.credentials_adapter import CredentialsAuthManager
14
11
  from ccproxy.auth.exceptions import AuthenticationError, AuthenticationRequiredError
15
12
  from ccproxy.auth.manager import AuthManager
13
+ from ccproxy.config.settings import Settings
16
14
 
17
15
 
18
- # FastAPI security scheme for bearer tokens
19
- bearer_scheme = HTTPBearer(auto_error=False)
20
-
21
-
22
- async def get_credentials_auth_manager() -> AuthManager:
23
- """Get credentials-based authentication manager.
24
-
25
- Returns:
26
- CredentialsAuthManager instance
27
- """
28
- return CredentialsAuthManager()
16
+ if TYPE_CHECKING: # pragma: no cover - import cycle guard for type checking only
17
+ pass
29
18
 
30
19
 
31
- async def get_bearer_auth_manager(
32
- credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(bearer_scheme)],
33
- ) -> AuthManager:
34
- """Get bearer token authentication manager.
20
+ # FastAPI security scheme for bearer tokens
21
+ bearer_scheme = HTTPBearer(auto_error=False)
35
22
 
36
- Args:
37
- credentials: HTTP authorization credentials
38
23
 
39
- Returns:
40
- BearerTokenAuthManager instance
24
+ def get_settings() -> Settings:
25
+ """Get settings instance directly (without service container)."""
26
+ return Settings()
41
27
 
42
- Raises:
43
- HTTPException: If no valid bearer token provided
44
- """
45
- if not credentials or not credentials.credentials:
46
- raise HTTPException(
47
- status_code=status.HTTP_401_UNAUTHORIZED,
48
- detail="Bearer token required",
49
- headers={"WWW-Authenticate": "Bearer"},
50
- )
51
28
 
52
- return BearerTokenAuthManager(credentials.credentials)
29
+ SettingsDep = Annotated[Settings, Depends(get_settings)]
53
30
 
54
31
 
55
- async def _get_auth_manager_with_settings(
56
- credentials: HTTPAuthorizationCredentials | None,
57
- settings: "Settings",
58
- ) -> AuthManager:
59
- """Internal function to get auth manager with specific settings.
32
+ def _resolve_runtime_settings(request: Request) -> Settings | None:
33
+ """Best-effort retrieval of settings without importing API dependencies."""
60
34
 
61
- Args:
62
- credentials: HTTP authorization credentials
63
- settings: Application settings
35
+ container = getattr(request.app.state, "service_container", None)
36
+ if container is None:
37
+ try:
38
+ from ccproxy.services.container import ServiceContainer
64
39
 
65
- Returns:
66
- AuthManager instance
40
+ container = ServiceContainer.get_current(strict=False)
41
+ except (ImportError, RuntimeError):
42
+ container = None
67
43
 
68
- Raises:
69
- HTTPException: If no valid authentication available
70
- """
71
- # Try bearer token first if provided
72
- if credentials and credentials.credentials:
44
+ if container is not None:
73
45
  try:
74
- # If API has configured auth_token, validate against it
75
- if settings.security.auth_token:
76
- if credentials.credentials == settings.security.auth_token:
77
- bearer_auth = BearerTokenAuthManager(credentials.credentials)
78
- if await bearer_auth.is_authenticated():
79
- return bearer_auth
80
- else:
81
- # Token doesn't match configured auth_token
82
- raise HTTPException(
83
- status_code=status.HTTP_401_UNAUTHORIZED,
84
- detail="Invalid bearer token",
85
- headers={"WWW-Authenticate": "Bearer"},
86
- )
87
- else:
88
- # No auth_token configured, accept any bearer token
89
- bearer_auth = BearerTokenAuthManager(credentials.credentials)
90
- if await bearer_auth.is_authenticated():
91
- return bearer_auth
92
- except (AuthenticationError, ValueError):
46
+ return container.get_service(Settings)
47
+ except ValueError:
48
+ # Service not registered yet; fall through to default settings.
93
49
  pass
94
50
 
95
- # Fall back to credentials only if no auth_token is configured
96
- if not settings.security.auth_token:
97
- try:
98
- credentials_auth = CredentialsAuthManager()
99
- if await credentials_auth.is_authenticated():
100
- return credentials_auth
101
- except AuthenticationError:
102
- pass
51
+ try:
52
+ return Settings()
53
+ except Exception:
54
+ # Settings construction can fail in minimal test contexts.
55
+ return None
103
56
 
104
- raise HTTPException(
105
- status_code=status.HTTP_401_UNAUTHORIZED,
106
- detail="Authentication required",
107
- headers={"WWW-Authenticate": "Bearer"},
108
- )
109
57
 
58
+ def _expected_token(settings: Settings | None) -> str | None:
59
+ """Extract configured auth token from settings if present."""
110
60
 
111
- async def get_auth_manager(
112
- credentials: Annotated[
113
- HTTPAuthorizationCredentials | None, Depends(bearer_scheme)
114
- ] = None,
115
- ) -> AuthManager:
116
- """Get authentication manager with fallback strategy.
61
+ if settings and settings.security.auth_token:
62
+ return settings.security.auth_token.get_secret_value()
63
+ return None
117
64
 
118
- Try bearer token first, then fall back to credentials.
119
65
 
120
- Args:
121
- credentials: HTTP authorization credentials
66
+ async def _build_bearer_auth_manager(
67
+ credentials: HTTPAuthorizationCredentials | None,
68
+ expected_token: str | None,
69
+ *,
70
+ require_credentials: bool,
71
+ ) -> AuthManager | None:
72
+ """Create a bearer auth manager when credentials satisfy expectations."""
73
+
74
+ token = credentials.credentials if credentials and credentials.credentials else None
75
+
76
+ if token is None:
77
+ if require_credentials:
78
+ raise HTTPException(
79
+ status_code=status.HTTP_401_UNAUTHORIZED,
80
+ detail="Authentication required",
81
+ headers={"WWW-Authenticate": "Bearer"},
82
+ )
83
+ return None
84
+
85
+ if expected_token is not None and token != expected_token:
86
+ raise HTTPException(
87
+ status_code=status.HTTP_401_UNAUTHORIZED,
88
+ detail="Invalid authentication credentials",
89
+ headers={"WWW-Authenticate": "Bearer"},
90
+ )
122
91
 
123
- Returns:
124
- AuthManager instance
92
+ try:
93
+ bearer_auth = BearerTokenAuthManager(token)
94
+ except ValueError as exc:
95
+ raise HTTPException(
96
+ status_code=status.HTTP_401_UNAUTHORIZED,
97
+ detail=str(exc),
98
+ headers={"WWW-Authenticate": "Bearer"},
99
+ ) from exc
125
100
 
126
- Raises:
127
- HTTPException: If no valid authentication available
128
- """
129
- # Import here to avoid circular imports
130
- from ccproxy.config.settings import get_settings
101
+ try:
102
+ if await bearer_auth.is_authenticated():
103
+ return bearer_auth
104
+ except AuthenticationError as exc:
105
+ raise HTTPException(
106
+ status_code=status.HTTP_401_UNAUTHORIZED,
107
+ detail=str(exc),
108
+ headers={"WWW-Authenticate": "Bearer"},
109
+ ) from exc
131
110
 
132
- settings = get_settings()
133
- return await _get_auth_manager_with_settings(credentials, settings)
111
+ if require_credentials:
112
+ raise HTTPException(
113
+ status_code=status.HTTP_401_UNAUTHORIZED,
114
+ detail="Authentication failed",
115
+ headers={"WWW-Authenticate": "Bearer"},
116
+ )
117
+ return None
134
118
 
135
119
 
136
- async def get_auth_manager_with_injected_settings(
137
- credentials: Annotated[
138
- HTTPAuthorizationCredentials | None, Depends(bearer_scheme)
139
- ] = None,
120
+ async def get_auth_manager(
121
+ credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(bearer_scheme)],
122
+ settings: SettingsDep,
140
123
  ) -> AuthManager:
141
- """Get authentication manager with dependency-injected settings.
142
-
143
- This version uses FastAPI's dependency injection for settings,
144
- which allows test overrides to work properly.
145
-
146
- Args:
147
- credentials: HTTP authorization credentials
148
- settings: Application settings (injected by FastAPI)
124
+ """Return an authentication manager when credentials are required."""
149
125
 
150
- Returns:
151
- AuthManager instance
152
-
153
- Raises:
154
- HTTPException: If no valid authentication available
155
- """
156
- # Import here to avoid circular imports
157
- from ccproxy.config.settings import get_settings
158
-
159
- settings = get_settings()
160
- return await _get_auth_manager_with_settings(credentials, settings)
126
+ auth_manager = await _build_bearer_auth_manager(
127
+ credentials,
128
+ _expected_token(settings),
129
+ require_credentials=True,
130
+ )
131
+ # require_credentials ensures auth_manager is never None here.
132
+ assert auth_manager is not None
133
+ return auth_manager
161
134
 
162
135
 
163
136
  async def require_auth(
164
137
  auth_manager: Annotated[AuthManager, Depends(get_auth_manager)],
165
138
  ) -> AuthManager:
166
- """Require authentication for endpoint.
167
-
168
- Args:
169
- auth_manager: Authentication manager
139
+ """Enforce authentication, translating failures into HTTP errors."""
170
140
 
171
- Returns:
172
- AuthManager instance
173
-
174
- Raises:
175
- HTTPException: If authentication fails
176
- """
177
141
  try:
178
142
  if not await auth_manager.is_authenticated():
179
143
  raise AuthenticationRequiredError("Authentication required")
180
144
  return auth_manager
181
- except AuthenticationError as e:
145
+ except AuthenticationError as exc:
182
146
  raise HTTPException(
183
147
  status_code=status.HTTP_401_UNAUTHORIZED,
184
- detail=str(e),
148
+ detail=str(exc),
185
149
  headers={"WWW-Authenticate": "Bearer"},
186
- ) from e
150
+ ) from exc
187
151
 
188
152
 
189
153
  async def get_access_token(
190
154
  auth_manager: Annotated[AuthManager, Depends(require_auth)],
191
155
  ) -> str:
192
- """Get access token from authenticated manager.
193
-
194
- Args:
195
- auth_manager: Authentication manager
156
+ """Retrieve an access token from an authenticated manager."""
196
157
 
197
- Returns:
198
- Access token string
199
-
200
- Raises:
201
- HTTPException: If token retrieval fails
202
- """
203
158
  try:
204
159
  return await auth_manager.get_access_token()
205
- except AuthenticationError as e:
160
+ except AuthenticationError as exc:
206
161
  raise HTTPException(
207
162
  status_code=status.HTTP_401_UNAUTHORIZED,
208
- detail=str(e),
163
+ detail=str(exc),
209
164
  headers={"WWW-Authenticate": "Bearer"},
210
- ) from e
165
+ ) from exc
211
166
 
212
167
 
213
- async def get_auth_manager_dependency(
168
+ async def get_conditional_auth_manager(
169
+ request: Request,
214
170
  credentials: Annotated[
215
171
  HTTPAuthorizationCredentials | None, Depends(bearer_scheme)
216
172
  ] = None,
217
- ) -> AuthManager:
218
- """Dependency wrapper for getting auth manager with settings injection."""
219
- # Import here to avoid circular imports
220
- from ccproxy.config.settings import get_settings
173
+ ) -> AuthManager | None:
174
+ """Return an auth manager only when the configuration requires it."""
221
175
 
222
- settings = get_settings()
223
- return await _get_auth_manager_with_settings(credentials, settings)
176
+ settings = _resolve_runtime_settings(request)
177
+ expected_token = _expected_token(settings)
178
+
179
+ if expected_token is None:
180
+ return None
181
+
182
+ return await _build_bearer_auth_manager(
183
+ credentials,
184
+ expected_token,
185
+ require_credentials=True,
186
+ )
224
187
 
225
188
 
226
189
  # Type aliases for common dependencies
227
190
  AuthManagerDep = Annotated[AuthManager, Depends(get_auth_manager)]
228
191
  RequiredAuthDep = Annotated[AuthManager, Depends(require_auth)]
229
192
  AccessTokenDep = Annotated[str, Depends(get_access_token)]
193
+ ConditionalAuthDep = Annotated[
194
+ AuthManager | None, Depends(get_conditional_auth_manager)
195
+ ]
@@ -61,19 +61,7 @@ class OAuthError(AuthenticationError):
61
61
  pass
62
62
 
63
63
 
64
- class OAuthLoginError(OAuthError):
65
- """OAuth login failed."""
66
-
67
- pass
68
-
69
-
70
64
  class OAuthTokenRefreshError(OAuthError):
71
65
  """OAuth token refresh failed."""
72
66
 
73
67
  pass
74
-
75
-
76
- class OAuthCallbackError(OAuthError):
77
- """OAuth callback failed."""
78
-
79
- pass
ccproxy/auth/manager.py CHANGED
@@ -1,13 +1,21 @@
1
- """Authentication manager interfaces for centralized auth handling."""
1
+ """Unified authentication manager interface for all providers."""
2
2
 
3
- from abc import ABC, abstractmethod
4
- from typing import Any, Protocol
3
+ from typing import Any, Protocol, runtime_checkable
5
4
 
6
- from ccproxy.auth.models import ClaudeCredentials, UserProfile
5
+ from ccproxy.auth.models.credentials import BaseCredentials
6
+ from ccproxy.auth.oauth.protocol import StandardProfileFields
7
7
 
8
8
 
9
+ @runtime_checkable
9
10
  class AuthManager(Protocol):
10
- """Protocol for authentication managers."""
11
+ """Unified authentication manager protocol for all providers.
12
+
13
+ This protocol defines the complete interface that all authentication managers
14
+ must implement, supporting both provider-specific methods (like Claude credentials)
15
+ and generic methods (like auth headers) for maximum flexibility.
16
+ """
17
+
18
+ # ==================== Core Authentication Methods ====================
11
19
 
12
20
  async def get_access_token(self) -> str:
13
21
  """Get valid access token.
@@ -20,14 +28,17 @@ class AuthManager(Protocol):
20
28
  """
21
29
  ...
22
30
 
23
- async def get_credentials(self) -> ClaudeCredentials:
31
+ async def get_credentials(self) -> BaseCredentials:
24
32
  """Get valid credentials.
25
33
 
34
+ Note: For non-Claude providers, this may return minimal/dummy credentials
35
+ or raise AuthenticationError if not supported.
36
+
26
37
  Returns:
27
38
  Valid credentials
28
39
 
29
40
  Raises:
30
- AuthenticationError: If authentication fails
41
+ AuthenticationError: If authentication fails or not supported
31
42
  """
32
43
  ...
33
44
 
@@ -39,64 +50,39 @@ class AuthManager(Protocol):
39
50
  """
40
51
  ...
41
52
 
42
- async def get_user_profile(self) -> UserProfile | None:
43
- """Get user profile information.
53
+ async def get_user_profile(self) -> StandardProfileFields | None:
54
+ """Get standardized user profile information.
44
55
 
45
56
  Returns:
46
- UserProfile if available, None otherwise
57
+ Standardized profile details when available, otherwise ``None``
58
+ for providers that do not expose profile metadata.
47
59
  """
48
60
  ...
49
61
 
62
+ # ==================== Provider-Generic Methods ====================
50
63
 
51
- class BaseAuthManager(ABC):
52
- """Base class for authentication managers."""
53
-
54
- @abstractmethod
55
- async def get_access_token(self) -> str:
56
- """Get valid access token.
57
-
58
- Returns:
59
- Access token string
60
-
61
- Raises:
62
- AuthenticationError: If authentication fails
63
- """
64
- pass
65
-
66
- @abstractmethod
67
- async def get_credentials(self) -> ClaudeCredentials:
68
- """Get valid credentials.
64
+ async def validate_credentials(self) -> bool:
65
+ """Validate that credentials are available and valid.
69
66
 
70
67
  Returns:
71
- Valid credentials
72
-
73
- Raises:
74
- AuthenticationError: If authentication fails
68
+ True if credentials are valid, False otherwise
75
69
  """
76
- pass
70
+ ...
77
71
 
78
- @abstractmethod
79
- async def is_authenticated(self) -> bool:
80
- """Check if current authentication is valid.
72
+ def get_provider_name(self) -> str:
73
+ """Get the provider name for logging.
81
74
 
82
75
  Returns:
83
- True if authenticated, False otherwise
76
+ Provider name string (e.g., "anthropic-claude", "openai-codex")
84
77
  """
85
- pass
78
+ ...
86
79
 
87
- async def get_user_profile(self) -> UserProfile | None:
88
- """Get user profile information.
80
+ # ==================== Context Manager Support ====================
89
81
 
90
- Returns:
91
- UserProfile if available, None otherwise
92
- """
93
- return None
94
-
95
- async def __aenter__(self) -> "BaseAuthManager":
82
+ async def __aenter__(self) -> "AuthManager":
96
83
  """Async context manager entry."""
97
- return self
84
+ ...
98
85
 
99
- @abstractmethod
100
86
  async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
101
87
  """Async context manager exit."""
102
- pass
88
+ ...
@@ -0,0 +1,10 @@
1
+ """Token managers for different authentication providers."""
2
+
3
+ from ccproxy.auth.managers.base import BaseTokenManager
4
+ from ccproxy.auth.managers.token_snapshot import TokenSnapshot
5
+
6
+
7
+ __all__ = [
8
+ "BaseTokenManager",
9
+ "TokenSnapshot",
10
+ ]