ccproxy-api 0.1.7__py3-none-any.whl → 0.2.0a4__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 +434 -219
  3. ccproxy/api/bootstrap.py +30 -0
  4. ccproxy/api/decorators.py +85 -0
  5. ccproxy/api/dependencies.py +144 -168
  6. ccproxy/api/format_validation.py +54 -0
  7. ccproxy/api/middleware/cors.py +6 -3
  8. ccproxy/api/middleware/errors.py +388 -524
  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 +540 -19
  97. ccproxy/data/codex_headers_fallback.json +114 -7
  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 +61 -105
  329. ccproxy/scheduler/registry.py +6 -32
  330. ccproxy/scheduler/tasks.py +268 -276
  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 +68 -446
  387. ccproxy/utils/version_checker.py +273 -6
  388. ccproxy_api-0.2.0a4.dist-info/METADATA +212 -0
  389. ccproxy_api-0.2.0a4.dist-info/RECORD +417 -0
  390. {ccproxy_api-0.1.7.dist-info → ccproxy_api-0.2.0a4.dist-info}/WHEEL +1 -1
  391. ccproxy_api-0.2.0a4.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 -1251
  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 -243
  458. ccproxy/services/codex_detection_service.py +0 -252
  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.7.dist-info/METADATA +0 -615
  472. ccproxy_api-0.1.7.dist-info/RECORD +0 -191
  473. ccproxy_api-0.1.7.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.7.dist-info → ccproxy_api-0.2.0a4.dist-info}/licenses/LICENSE +0 -0
@@ -1,158 +0,0 @@
1
- """JSON file storage implementation for token storage."""
2
-
3
- import contextlib
4
- import json
5
- from pathlib import Path
6
-
7
- from structlog import get_logger
8
-
9
- from ccproxy.auth.exceptions import (
10
- CredentialsInvalidError,
11
- CredentialsStorageError,
12
- )
13
- from ccproxy.auth.models import ClaudeCredentials
14
- from ccproxy.auth.storage.base import TokenStorage
15
-
16
-
17
- logger = get_logger(__name__)
18
-
19
-
20
- class JsonFileTokenStorage(TokenStorage):
21
- """JSON file storage implementation for Claude credentials with keyring fallback."""
22
-
23
- def __init__(self, file_path: Path):
24
- """Initialize JSON file storage.
25
-
26
- Args:
27
- file_path: Path to the JSON credentials file
28
- """
29
- self.file_path = file_path
30
-
31
- async def load(self) -> ClaudeCredentials | None:
32
- """Load credentials from JSON file .
33
-
34
- Returns:
35
- Parsed credentials if found and valid, None otherwise
36
-
37
- Raises:
38
- CredentialsInvalidError: If the JSON file is invalid
39
- CredentialsStorageError: If there's an error reading the file
40
- """
41
- if not await self.exists():
42
- logger.debug("credentials_file_not_found", path=str(self.file_path))
43
- return None
44
-
45
- try:
46
- logger.debug(
47
- "credentials_load_start", source="file", path=str(self.file_path)
48
- )
49
- with self.file_path.open() as f:
50
- data = json.load(f)
51
-
52
- credentials = ClaudeCredentials.model_validate(data)
53
- logger.debug("credentials_load_completed", source="file")
54
-
55
- return credentials
56
-
57
- except json.JSONDecodeError as e:
58
- raise CredentialsInvalidError(
59
- f"Failed to parse credentials file {self.file_path}: {e}"
60
- ) from e
61
- except Exception as e:
62
- raise CredentialsStorageError(
63
- f"Error loading credentials from {self.file_path}: {e}"
64
- ) from e
65
-
66
- async def save(self, credentials: ClaudeCredentials) -> bool:
67
- """Save credentials to both keyring and JSON file.
68
-
69
- Args:
70
- credentials: Credentials to save
71
-
72
- Returns:
73
- True if saved successfully, False otherwise
74
-
75
- Raises:
76
- CredentialsStorageError: If there's an error writing the file
77
- """
78
- try:
79
- # Convert to dict with proper aliases
80
- data = credentials.model_dump(by_alias=True, mode="json")
81
-
82
- # Always save to file as well
83
- # Ensure parent directory exists
84
- self.file_path.parent.mkdir(parents=True, exist_ok=True)
85
-
86
- # Use atomic write: write to temp file then rename
87
- temp_path = self.file_path.with_suffix(".tmp")
88
-
89
- try:
90
- with temp_path.open("w") as f:
91
- json.dump(data, f, indent=2)
92
-
93
- # Set appropriate file permissions (read/write for owner only)
94
- temp_path.chmod(0o600)
95
-
96
- # Atomically replace the original file
97
- Path.replace(temp_path, self.file_path)
98
-
99
- logger.debug(
100
- "credentials_save_completed",
101
- source="file",
102
- path=str(self.file_path),
103
- )
104
- return True
105
- except Exception as e:
106
- raise
107
- finally:
108
- # Clean up temp file if it exists
109
- if temp_path.exists():
110
- with contextlib.suppress(Exception):
111
- temp_path.unlink()
112
-
113
- except Exception as e:
114
- raise CredentialsStorageError(f"Error saving credentials: {e}") from e
115
-
116
- async def exists(self) -> bool:
117
- """Check if credentials file exists.
118
-
119
- Returns:
120
- True if file exists, False otherwise
121
- """
122
- return self.file_path.exists() and self.file_path.is_file()
123
-
124
- async def delete(self) -> bool:
125
- """Delete credentials from both keyring and file.
126
-
127
- Returns:
128
- True if deleted successfully, False otherwise
129
-
130
- Raises:
131
- CredentialsStorageError: If there's an error deleting the file
132
- """
133
- deleted = False
134
-
135
- # Delete from file
136
- try:
137
- if await self.exists():
138
- self.file_path.unlink()
139
- logger.debug(
140
- "credentials_delete_completed",
141
- source="file",
142
- path=str(self.file_path),
143
- )
144
- deleted = True
145
- except Exception as e:
146
- if not deleted: # Only raise if we failed to delete from both
147
- raise CredentialsStorageError(f"Error deleting credentials: {e}") from e
148
- logger.debug("credentials_delete_partial", source="file", error=str(e))
149
-
150
- return deleted
151
-
152
- def get_location(self) -> str:
153
- """Get the storage location description.
154
-
155
- Returns:
156
- Path to the JSON file with keyring info if available
157
- """
158
- return str(self.file_path)
@@ -1,189 +0,0 @@
1
- """OS keyring storage implementation for token storage."""
2
-
3
- import json
4
-
5
- from structlog import get_logger
6
-
7
- from ccproxy.auth.exceptions import (
8
- CredentialsStorageError,
9
- )
10
- from ccproxy.auth.models import ClaudeCredentials
11
- from ccproxy.auth.storage.base import TokenStorage
12
-
13
-
14
- logger = get_logger(__name__)
15
-
16
-
17
- class KeyringTokenStorage(TokenStorage):
18
- """OS keyring storage implementation for Claude credentials."""
19
-
20
- def __init__(
21
- self, service_name: str = "claude-code-proxy", username: str = "default"
22
- ):
23
- """Initialize keyring storage.
24
-
25
- Args:
26
- service_name: Name of the service in the keyring
27
- username: Username to associate with the stored credentials
28
- """
29
- self.service_name = service_name
30
- self.username = username
31
-
32
- async def load(self) -> ClaudeCredentials | None:
33
- """Load credentials from the OS keyring.
34
-
35
- Returns:
36
- Parsed credentials if found and valid, None otherwise
37
-
38
- Raises:
39
- CredentialsStorageError: If the stored data is invalid
40
- CredentialsStorageError: If there's an error reading from keyring
41
- """
42
- try:
43
- import keyring
44
- except ImportError as e:
45
- raise CredentialsStorageError(
46
- "keyring package is required for keyring storage. "
47
- "Install it with: pip install keyring"
48
- ) from e
49
-
50
- try:
51
- logger.debug(
52
- "credentials_load_start",
53
- source="keyring",
54
- service_name=self.service_name,
55
- )
56
- password = keyring.get_password(self.service_name, self.username)
57
-
58
- if password is None:
59
- logger.debug(
60
- "credentials_not_found",
61
- source="keyring",
62
- service_name=self.service_name,
63
- )
64
- return None
65
-
66
- # Parse the stored JSON
67
- data = json.loads(password)
68
- credentials = ClaudeCredentials.model_validate(data)
69
-
70
- self._log_credential_details(credentials)
71
- return credentials
72
-
73
- except json.JSONDecodeError as e:
74
- raise CredentialsStorageError(
75
- f"Failed to parse credentials from keyring: {e}"
76
- ) from e
77
- except Exception as e:
78
- raise CredentialsStorageError(
79
- f"Error loading credentials from keyring: {e}"
80
- ) from e
81
-
82
- def _log_credential_details(self, credentials: ClaudeCredentials) -> None:
83
- """Log credential details safely."""
84
- oauth_token = credentials.claude_ai_oauth
85
- logger.debug(
86
- "credentials_load_completed",
87
- source="keyring",
88
- subscription_type=oauth_token.subscription_type,
89
- expires_at=str(oauth_token.expires_at_datetime),
90
- is_expired=oauth_token.is_expired,
91
- scopes=oauth_token.scopes,
92
- )
93
-
94
- async def save(self, credentials: ClaudeCredentials) -> bool:
95
- """Save credentials to the OS keyring.
96
-
97
- Args:
98
- credentials: Credentials to save
99
-
100
- Returns:
101
- True if saved successfully, False otherwise
102
-
103
- Raises:
104
- CredentialsStorageError: If there's an error writing to keyring
105
- """
106
- try:
107
- import keyring
108
- except ImportError as e:
109
- raise CredentialsStorageError(
110
- "keyring package is required for keyring storage. "
111
- "Install it with: pip install keyring"
112
- ) from e
113
-
114
- try:
115
- # Convert to JSON string
116
- data = credentials.model_dump(by_alias=True)
117
- json_data = json.dumps(data)
118
-
119
- # Store in keyring
120
- keyring.set_password(self.service_name, self.username, json_data)
121
-
122
- logger.debug(
123
- "credentials_save_completed",
124
- source="keyring",
125
- service_name=self.service_name,
126
- )
127
- return True
128
-
129
- except Exception as e:
130
- raise CredentialsStorageError(
131
- f"Error saving credentials to keyring: {e}"
132
- ) from e
133
-
134
- async def exists(self) -> bool:
135
- """Check if credentials exist in the keyring.
136
-
137
- Returns:
138
- True if credentials exist, False otherwise
139
- """
140
- try:
141
- import keyring
142
- except ImportError:
143
- return False
144
-
145
- try:
146
- password = keyring.get_password(self.service_name, self.username)
147
- return password is not None
148
- except Exception:
149
- return False
150
-
151
- async def delete(self) -> bool:
152
- """Delete credentials from the keyring.
153
-
154
- Returns:
155
- True if deleted successfully, False otherwise
156
-
157
- Raises:
158
- CredentialsStorageError: If there's an error deleting from keyring
159
- """
160
- try:
161
- import keyring
162
- except ImportError as e:
163
- raise CredentialsStorageError(
164
- "keyring package is required for keyring storage. "
165
- "Install it with: pip install keyring"
166
- ) from e
167
-
168
- try:
169
- if await self.exists():
170
- keyring.delete_password(self.service_name, self.username)
171
- logger.debug(
172
- "credentials_delete_completed",
173
- source="keyring",
174
- service_name=self.service_name,
175
- )
176
- return True
177
- return False
178
- except Exception as e:
179
- raise CredentialsStorageError(
180
- f"Error deleting credentials from keyring: {e}"
181
- ) from e
182
-
183
- def get_location(self) -> str:
184
- """Get the storage location description.
185
-
186
- Returns:
187
- Description of the keyring storage location
188
- """
189
- return f"OS keyring (service: {self.service_name}, user: {self.username})"
@@ -1,18 +0,0 @@
1
- """Claude SDK integration module."""
2
-
3
- from .client import ClaudeSDKClient
4
- from .converter import MessageConverter
5
- from .exceptions import ClaudeSDKError, StreamTimeoutError
6
- from .options import OptionsHandler
7
- from .parser import parse_formatted_sdk_content
8
-
9
-
10
- __all__ = [
11
- # Session Context will be imported here once created
12
- "ClaudeSDKClient",
13
- "ClaudeSDKError",
14
- "StreamTimeoutError",
15
- "MessageConverter",
16
- "OptionsHandler",
17
- "parse_formatted_sdk_content",
18
- ]
@@ -1,194 +0,0 @@
1
- """Options handling for Claude SDK interactions."""
2
-
3
- from typing import Any
4
-
5
- import structlog
6
-
7
- from ccproxy.config.settings import Settings
8
- from ccproxy.core.async_utils import patched_typing
9
-
10
-
11
- with patched_typing():
12
- from claude_code_sdk import ClaudeCodeOptions
13
-
14
- logger = structlog.get_logger(__name__)
15
-
16
-
17
- class OptionsHandler:
18
- """
19
- Handles creation and management of Claude SDK options.
20
- """
21
-
22
- def __init__(self, settings: Settings | None = None) -> None:
23
- """
24
- Initialize options handler.
25
-
26
- Args:
27
- settings: Application settings containing default Claude options
28
- """
29
- self.settings = settings
30
-
31
- def create_options(
32
- self,
33
- model: str,
34
- temperature: float | None = None,
35
- max_tokens: int | None = None,
36
- system_message: str | None = None,
37
- **additional_options: Any,
38
- ) -> ClaudeCodeOptions:
39
- """
40
- Create Claude SDK options from API parameters.
41
-
42
- Args:
43
- model: The model name
44
- temperature: Temperature for response generation
45
- max_tokens: Maximum tokens in response
46
- system_message: System message to include
47
- **additional_options: Additional options to set on the ClaudeCodeOptions instance
48
-
49
- Returns:
50
- Configured ClaudeCodeOptions instance
51
- """
52
- # Start with configured defaults if available, otherwise create fresh instance
53
- if self.settings and self.settings.claude.code_options:
54
- # Use the configured options as base - this preserves all default settings
55
- # including complex objects like mcp_servers and permission_prompt_tool_name
56
- configured_opts = self.settings.claude.code_options
57
-
58
- # Create a new instance with the same configuration
59
- # We need to extract the configuration values properly with type safety
60
-
61
- # Extract configuration values with proper types
62
- mcp_servers = (
63
- configured_opts.mcp_servers.copy()
64
- if isinstance(configured_opts.mcp_servers, dict)
65
- else {}
66
- )
67
- permission_prompt_tool_name = configured_opts.permission_prompt_tool_name
68
- max_thinking_tokens = getattr(configured_opts, "max_thinking_tokens", None)
69
- allowed_tools = getattr(configured_opts, "allowed_tools", None)
70
- disallowed_tools = getattr(configured_opts, "disallowed_tools", None)
71
- cwd = getattr(configured_opts, "cwd", None)
72
- append_system_prompt = getattr(
73
- configured_opts, "append_system_prompt", None
74
- )
75
- max_turns = getattr(configured_opts, "max_turns", None)
76
- continue_conversation = getattr(
77
- configured_opts, "continue_conversation", None
78
- )
79
- permission_mode = getattr(configured_opts, "permission_mode", None)
80
-
81
- # Build ClaudeCodeOptions with proper type handling
82
- # Start with a basic instance and set attributes individually for type safety
83
- options = ClaudeCodeOptions(
84
- mcp_servers=mcp_servers,
85
- permission_prompt_tool_name=permission_prompt_tool_name,
86
- )
87
-
88
- # Set additional attributes if they exist and are not None
89
- if max_thinking_tokens is not None:
90
- options.max_thinking_tokens = int(max_thinking_tokens)
91
- if allowed_tools is not None:
92
- options.allowed_tools = list(allowed_tools)
93
- if disallowed_tools is not None:
94
- options.disallowed_tools = list(disallowed_tools)
95
- if cwd is not None:
96
- options.cwd = cwd
97
- if append_system_prompt is not None:
98
- options.append_system_prompt = append_system_prompt
99
- if max_turns is not None:
100
- options.max_turns = max_turns
101
- if continue_conversation is not None:
102
- options.continue_conversation = bool(continue_conversation)
103
- if permission_mode is not None:
104
- options.permission_mode = permission_mode
105
- else:
106
- options = ClaudeCodeOptions()
107
-
108
- # Override the model (API parameter takes precedence)
109
- options.model = model
110
-
111
- # Apply system message if provided (this is supported by ClaudeCodeOptions)
112
- if system_message is not None:
113
- options.system_prompt = system_message
114
-
115
- # If session_id is provided via additional_options, enable continue_conversation
116
- # This ensures conversation continuity when using session IDs
117
- if additional_options.get("session_id"):
118
- options.continue_conversation = True
119
-
120
- # Note: temperature and max_tokens are API-level parameters, not ClaudeCodeOptions parameters
121
- # These are handled at the API request level, not in the options object
122
-
123
- # Handle additional options as needed
124
- for key, value in additional_options.items():
125
- if hasattr(options, key):
126
- setattr(options, key, value)
127
-
128
- return options
129
-
130
- @staticmethod
131
- def extract_system_message(messages: list[dict[str, Any]]) -> str | None:
132
- """
133
- Extract system message from Anthropic messages format.
134
-
135
- Args:
136
- messages: List of messages in Anthropic format
137
-
138
- Returns:
139
- System message content if found, None otherwise
140
- """
141
- for message in messages:
142
- if message.get("role") == "system":
143
- content = message.get("content", "")
144
- if isinstance(content, list):
145
- # Handle content blocks
146
- text_parts = []
147
- for block in content:
148
- if block.get("type") == "text":
149
- text_parts.append(block.get("text", ""))
150
- return " ".join(text_parts)
151
- return str(content)
152
- return None
153
-
154
- @staticmethod
155
- def get_supported_models() -> list[str]:
156
- """
157
- Get list of supported Claude models.
158
-
159
- Returns:
160
- List of supported model names
161
- """
162
- # Import here to avoid circular imports
163
- from ccproxy.utils.model_mapping import get_supported_claude_models
164
-
165
- # Get supported Claude models
166
- claude_models = get_supported_claude_models()
167
- return claude_models
168
-
169
- @staticmethod
170
- def validate_model(model: str) -> bool:
171
- """
172
- Validate if a model is supported.
173
-
174
- Args:
175
- model: The model name to validate
176
-
177
- Returns:
178
- True if supported, False otherwise
179
- """
180
- return model in OptionsHandler.get_supported_models()
181
-
182
- @staticmethod
183
- def get_default_options() -> dict[str, Any]:
184
- """
185
- Get default options for API parameters.
186
-
187
- Returns:
188
- Dictionary of default API parameter values
189
- """
190
- return {
191
- "model": "claude-3-5-sonnet-20241022",
192
- "temperature": 0.7,
193
- "max_tokens": 4000,
194
- }