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,269 +0,0 @@
1
- """Message models for Anthropic Messages API endpoint."""
2
-
3
- from typing import TYPE_CHECKING, Annotated, Any, Literal
4
-
5
- from pydantic import BaseModel, ConfigDict, Field, field_validator
6
-
7
- from .claude_sdk import SDKContentBlock
8
- from .requests import Message, ToolDefinition, Usage
9
-
10
-
11
- if TYPE_CHECKING:
12
- pass
13
- from .types import ServiceTier, StopReason, ToolChoiceType
14
-
15
-
16
- class SystemMessage(BaseModel):
17
- """System message content block."""
18
-
19
- type: Annotated[Literal["text"], Field(description="Content type")] = "text"
20
- text: Annotated[str, Field(description="System message text")]
21
-
22
-
23
- class ThinkingConfig(BaseModel):
24
- """Configuration for extended thinking process."""
25
-
26
- type: Annotated[Literal["enabled"], Field(description="Enable thinking mode")] = (
27
- "enabled"
28
- )
29
- budget_tokens: Annotated[
30
- int, Field(description="Token budget for thinking process", ge=1024)
31
- ]
32
-
33
-
34
- class MetadataParams(BaseModel):
35
- """Metadata about the request."""
36
-
37
- user_id: Annotated[
38
- str | None,
39
- Field(description="External identifier for the user", max_length=256),
40
- ] = None
41
-
42
- model_config = ConfigDict(extra="allow") # Allow additional fields in metadata
43
-
44
-
45
- class ToolChoiceParams(BaseModel):
46
- """Tool choice configuration."""
47
-
48
- type: Annotated[ToolChoiceType, Field(description="How the model should use tools")]
49
- name: Annotated[
50
- str | None, Field(description="Specific tool name (when type is 'tool')")
51
- ] = None
52
- disable_parallel_tool_use: Annotated[
53
- bool, Field(description="Disable parallel tool use")
54
- ] = False
55
-
56
-
57
- class MessageCreateParams(BaseModel):
58
- """Request parameters for creating messages via Anthropic Messages API."""
59
-
60
- # Required fields
61
- model: Annotated[
62
- str,
63
- Field(
64
- description="The model to use for the message",
65
- pattern=r"^claude-.*",
66
- ),
67
- ]
68
- messages: Annotated[
69
- list[Message],
70
- Field(
71
- description="Array of messages in the conversation",
72
- min_length=1,
73
- ),
74
- ]
75
- max_tokens: Annotated[
76
- int,
77
- Field(
78
- description="Maximum number of tokens to generate",
79
- ge=1,
80
- le=200000,
81
- ),
82
- ]
83
-
84
- # Optional Anthropic API fields
85
- system: Annotated[
86
- str | list[SystemMessage] | None,
87
- Field(description="System prompt to provide context and instructions"),
88
- ] = None
89
- temperature: Annotated[
90
- float | None,
91
- Field(
92
- description="Sampling temperature between 0.0 and 1.0",
93
- ge=0.0,
94
- le=1.0,
95
- ),
96
- ] = None
97
- top_p: Annotated[
98
- float | None,
99
- Field(
100
- description="Nucleus sampling parameter",
101
- ge=0.0,
102
- le=1.0,
103
- ),
104
- ] = None
105
- top_k: Annotated[
106
- int | None,
107
- Field(
108
- description="Top-k sampling parameter",
109
- ge=0,
110
- ),
111
- ] = None
112
- stop_sequences: Annotated[
113
- list[str] | None,
114
- Field(
115
- description="Custom sequences where the model should stop generating",
116
- max_length=4,
117
- ),
118
- ] = None
119
- stop_reason: Annotated[
120
- list[str] | None,
121
- Field(
122
- description="Custom sequences where the model should stop generating",
123
- max_length=4,
124
- ),
125
- ] = None
126
- stream: Annotated[
127
- bool | None,
128
- Field(description="Whether to stream the response"),
129
- ] = False
130
- metadata: Annotated[
131
- MetadataParams | None,
132
- Field(description="Metadata about the request, including optional user_id"),
133
- ] = None
134
- tools: Annotated[
135
- list[ToolDefinition] | None,
136
- Field(description="Available tools/functions for the model to use"),
137
- ] = None
138
- tool_choice: Annotated[
139
- ToolChoiceParams | None,
140
- Field(description="How the model should use the provided tools"),
141
- ] = None
142
- service_tier: Annotated[
143
- ServiceTier | None,
144
- Field(description="Request priority level"),
145
- ] = None
146
- thinking: Annotated[
147
- ThinkingConfig | None,
148
- Field(description="Configuration for extended thinking process"),
149
- ] = None
150
-
151
- @field_validator("model")
152
- @classmethod
153
- def validate_model(cls, v: str) -> str:
154
- """Validate that the model is a supported Claude model."""
155
- supported_models = {
156
- "claude-opus-4-20250514",
157
- "claude-sonnet-4-20250514",
158
- "claude-3-7-sonnet-20250219",
159
- "claude-3-5-sonnet-20241022",
160
- "claude-3-5-sonnet-20240620",
161
- "claude-3-5-haiku-20241022",
162
- "claude-3-opus-20240229",
163
- "claude-3-sonnet-20240229",
164
- "claude-3-haiku-20240307",
165
- "claude-3-5-sonnet",
166
- "claude-3-5-haiku",
167
- "claude-3-opus",
168
- "claude-3-sonnet",
169
- "claude-3-haiku",
170
- }
171
-
172
- if v not in supported_models and not v.startswith("claude-"):
173
- raise ValueError(f"Model {v} is not supported")
174
-
175
- return v
176
-
177
- @field_validator("messages")
178
- @classmethod
179
- def validate_messages(cls, v: list[Message]) -> list[Message]:
180
- """Validate message alternation and content."""
181
- if not v:
182
- raise ValueError("At least one message is required")
183
-
184
- # First message must be from user
185
- if v[0].role != "user":
186
- raise ValueError("First message must be from user")
187
-
188
- # Check for proper alternation
189
- for i in range(1, len(v)):
190
- if v[i].role == v[i - 1].role:
191
- raise ValueError("Messages must alternate between user and assistant")
192
-
193
- return v
194
-
195
- @field_validator("stop_sequences")
196
- @classmethod
197
- def validate_stop_sequences(cls, v: list[str] | None) -> list[str] | None:
198
- """Validate stop sequences."""
199
- if v is not None:
200
- if len(v) > 4:
201
- raise ValueError("Maximum 4 stop sequences allowed")
202
- for seq in v:
203
- if len(seq) > 100:
204
- raise ValueError("Stop sequences must be 100 characters or less")
205
- return v
206
-
207
- model_config = ConfigDict(extra="forbid", validate_assignment=True)
208
-
209
-
210
- class TextContentBlock(BaseModel):
211
- """Text content block."""
212
-
213
- type: Literal["text"]
214
- text: str
215
-
216
-
217
- class ToolUseContentBlock(BaseModel):
218
- """Tool use content block."""
219
-
220
- type: Literal["tool_use"]
221
- id: str
222
- name: str
223
- input: dict[str, Any]
224
-
225
-
226
- class ThinkingContentBlock(BaseModel):
227
- """Thinking content block."""
228
-
229
- type: Literal["thinking"]
230
- thinking: str
231
- signature: str | None = None
232
-
233
-
234
- MessageContentBlock = Annotated[
235
- TextContentBlock | ToolUseContentBlock | ThinkingContentBlock,
236
- Field(discriminator="type"),
237
- ]
238
-
239
-
240
- CCProxyContentBlock = MessageContentBlock | SDKContentBlock
241
-
242
-
243
- class MessageResponse(BaseModel):
244
- """Response model for Anthropic Messages API endpoint."""
245
-
246
- id: Annotated[str, Field(description="Unique identifier for the message")]
247
- type: Annotated[Literal["message"], Field(description="Response type")] = "message"
248
- role: Annotated[Literal["assistant"], Field(description="Message role")] = (
249
- "assistant"
250
- )
251
- content: Annotated[
252
- list[CCProxyContentBlock],
253
- Field(description="Array of content blocks in the response"),
254
- ]
255
- model: Annotated[str, Field(description="The model used for the response")]
256
- stop_reason: Annotated[
257
- StopReason | None, Field(description="Reason why the model stopped generating")
258
- ] = None
259
- stop_sequence: Annotated[
260
- str | None,
261
- Field(description="The stop sequence that triggered stopping (if applicable)"),
262
- ] = None
263
- usage: Annotated[Usage, Field(description="Token usage information")]
264
- container: Annotated[
265
- dict[str, Any] | None,
266
- Field(description="Information about container used in the request"),
267
- ] = None
268
-
269
- model_config = ConfigDict(extra="forbid", validate_assignment=True)
@@ -1,107 +0,0 @@
1
- """Request models for Claude Proxy API Server compatible with Anthropic's API format."""
2
-
3
- from typing import Annotated, Any, Literal
4
-
5
- from pydantic import BaseModel, ConfigDict, Field
6
-
7
-
8
- class ImageSource(BaseModel):
9
- """Image source data."""
10
-
11
- type: Annotated[Literal["base64", "url"], Field(description="Source type")]
12
- media_type: Annotated[
13
- str, Field(description="Media type (e.g., image/jpeg, image/png)")
14
- ]
15
- data: Annotated[str | None, Field(description="Base64 encoded image data")] = None
16
- url: Annotated[str | None, Field(description="Image URL")] = None
17
-
18
- model_config = ConfigDict(extra="forbid")
19
-
20
-
21
- class ImageContent(BaseModel):
22
- """Image content block for multimodal messages."""
23
-
24
- type: Annotated[Literal["image"], Field(description="Content type")] = "image"
25
- source: Annotated[
26
- ImageSource,
27
- Field(description="Image source data with type (base64 or url) and media_type"),
28
- ]
29
-
30
-
31
- class TextContent(BaseModel):
32
- """Text content block for messages."""
33
-
34
- type: Annotated[Literal["text"], Field(description="Content type")] = "text"
35
- text: Annotated[str, Field(description="The text content")]
36
-
37
-
38
- MessageContent = TextContent | ImageContent | str
39
-
40
-
41
- class Message(BaseModel):
42
- """Individual message in the conversation."""
43
-
44
- role: Annotated[
45
- Literal["user", "assistant"],
46
- Field(description="The role of the message sender"),
47
- ]
48
- content: Annotated[
49
- str | list[MessageContent], Field(description="The content of the message")
50
- ]
51
-
52
-
53
- class FunctionDefinition(BaseModel):
54
- """Function definition for tool calling."""
55
-
56
- name: Annotated[str, Field(description="Function name")]
57
- description: Annotated[str, Field(description="Function description")]
58
- parameters: Annotated[
59
- dict[str, Any], Field(description="JSON Schema for function parameters")
60
- ]
61
-
62
- model_config = ConfigDict(extra="forbid")
63
-
64
-
65
- class ToolDefinition(BaseModel):
66
- """Tool definition for function calling."""
67
-
68
- type: Annotated[Literal["function"], Field(description="Tool type")] = "function"
69
- function: Annotated[
70
- FunctionDefinition,
71
- Field(description="Function definition with name, description, and parameters"),
72
- ]
73
-
74
-
75
- class Usage(BaseModel):
76
- """Token usage information."""
77
-
78
- input_tokens: Annotated[int, Field(description="Number of input tokens")] = 0
79
- output_tokens: Annotated[int, Field(description="Number of output tokens")] = 0
80
- cache_creation_input_tokens: Annotated[
81
- int | None, Field(description="Number of tokens used for cache creation")
82
- ] = None
83
- cache_read_input_tokens: Annotated[
84
- int | None, Field(description="Number of tokens read from cache")
85
- ] = None
86
-
87
-
88
- class CodexMessage(BaseModel):
89
- """Message format for Codex requests."""
90
-
91
- role: Annotated[Literal["user", "assistant"], Field(description="Message role")]
92
- content: Annotated[str, Field(description="Message content")]
93
-
94
-
95
- class CodexRequest(BaseModel):
96
- """OpenAI Codex completion request model."""
97
-
98
- model: Annotated[str, Field(description="Model name (e.g., gpt-5)")] = "gpt-5"
99
- instructions: Annotated[
100
- str | None, Field(description="System instructions for the model")
101
- ] = None
102
- messages: Annotated[list[CodexMessage], Field(description="Conversation messages")]
103
- stream: Annotated[bool, Field(description="Whether to stream the response")] = True
104
-
105
- model_config = ConfigDict(
106
- extra="allow"
107
- ) # Allow additional fields for compatibility
@@ -1,270 +0,0 @@
1
- """Response models for Claude Proxy API Server compatible with Anthropic's API format."""
2
-
3
- from typing import Annotated, Any, Literal
4
-
5
- from pydantic import BaseModel, ConfigDict, Field
6
-
7
- from .requests import Usage
8
-
9
-
10
- class ToolCall(BaseModel):
11
- """Tool call made by the model."""
12
-
13
- id: Annotated[str, Field(description="Unique identifier for the tool call")]
14
- type: Annotated[Literal["function"], Field(description="Tool call type")] = (
15
- "function"
16
- )
17
- function: Annotated[
18
- dict[str, Any],
19
- Field(description="Function call details including name and arguments"),
20
- ]
21
-
22
-
23
- class ToolUse(BaseModel):
24
- """Tool use content block."""
25
-
26
- type: Annotated[Literal["tool_use"], Field(description="Content type")] = "tool_use"
27
- id: Annotated[str, Field(description="Unique identifier for the tool use")]
28
- name: Annotated[str, Field(description="Name of the tool being used")]
29
- input: Annotated[dict[str, Any], Field(description="Input parameters for the tool")]
30
-
31
-
32
- class TextResponse(BaseModel):
33
- """Text response content block."""
34
-
35
- type: Annotated[Literal["text"], Field(description="Content type")] = "text"
36
- text: Annotated[str, Field(description="The generated text content")]
37
-
38
-
39
- ResponseContent = TextResponse | ToolUse
40
-
41
-
42
- class Choice(BaseModel):
43
- """Individual choice in a non-streaming response."""
44
-
45
- index: Annotated[int, Field(description="Index of the choice")]
46
- message: Annotated[dict[str, Any], Field(description="The generated message")]
47
- finish_reason: Annotated[
48
- str | None, Field(description="Reason why the model stopped generating")
49
- ] = None
50
-
51
- model_config = ConfigDict(extra="forbid")
52
-
53
-
54
- class StreamingChoice(BaseModel):
55
- """Individual choice in a streaming response."""
56
-
57
- index: Annotated[int, Field(description="Index of the choice")]
58
- delta: Annotated[
59
- dict[str, Any], Field(description="The incremental message content")
60
- ]
61
- finish_reason: Annotated[
62
- str | None, Field(description="Reason why the model stopped generating")
63
- ] = None
64
-
65
- model_config = ConfigDict(extra="forbid")
66
-
67
-
68
- class ChatCompletionResponse(BaseModel):
69
- """Response model for Claude chat completions compatible with Anthropic's API."""
70
-
71
- id: Annotated[str, Field(description="Unique identifier for the response")]
72
- type: Annotated[Literal["message"], Field(description="Response type")] = "message"
73
- role: Annotated[Literal["assistant"], Field(description="Message role")] = (
74
- "assistant"
75
- )
76
- content: Annotated[
77
- list[ResponseContent],
78
- Field(description="Array of content blocks in the response"),
79
- ]
80
- model: Annotated[str, Field(description="The model used for the response")]
81
- stop_reason: Annotated[
82
- str | None, Field(description="Reason why the model stopped generating")
83
- ] = None
84
- stop_sequence: Annotated[
85
- str | None,
86
- Field(description="The stop sequence that triggered stopping (if applicable)"),
87
- ] = None
88
- usage: Annotated[Usage, Field(description="Token usage information")]
89
-
90
- model_config = ConfigDict(extra="forbid", validate_assignment=True)
91
-
92
-
93
- class StreamingChatCompletionResponse(BaseModel):
94
- """Streaming response model for Claude chat completions."""
95
-
96
- id: Annotated[str, Field(description="Unique identifier for the response")]
97
- type: Annotated[
98
- Literal[
99
- "message_start",
100
- "message_delta",
101
- "message_stop",
102
- "content_block_start",
103
- "content_block_delta",
104
- "content_block_stop",
105
- "ping",
106
- ],
107
- Field(description="Type of streaming event"),
108
- ]
109
- message: Annotated[
110
- dict[str, Any] | None, Field(description="Message data for message events")
111
- ] = None
112
- index: Annotated[int | None, Field(description="Index of the content block")] = None
113
- content_block: Annotated[
114
- dict[str, Any] | None, Field(description="Content block data")
115
- ] = None
116
- delta: Annotated[
117
- dict[str, Any] | None, Field(description="Delta data for incremental updates")
118
- ] = None
119
- usage: Annotated[Usage | None, Field(description="Token usage information")] = None
120
-
121
- model_config = ConfigDict(extra="forbid", validate_assignment=True)
122
-
123
-
124
- class ErrorResponse(BaseModel):
125
- """Error response model."""
126
-
127
- type: Annotated[Literal["error"], Field(description="Response type")] = "error"
128
- error: Annotated[
129
- dict[str, Any], Field(description="Error details including type and message")
130
- ]
131
-
132
- model_config = ConfigDict(extra="forbid")
133
-
134
-
135
- class APIError(BaseModel):
136
- """API error details."""
137
-
138
- type: Annotated[str, Field(description="Error type")]
139
- message: Annotated[str, Field(description="Error message")]
140
-
141
- model_config = ConfigDict(
142
- extra="forbid", validate_by_alias=True, validate_by_name=True
143
- )
144
-
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
- class PermissionToolPendingResponse(BaseModel):
180
- """Response model for pending permission tool requests requiring user confirmation."""
181
-
182
- behavior: Annotated[
183
- Literal["pending"], Field(description="Permission behavior")
184
- ] = "pending"
185
- confirmation_id: Annotated[
186
- str,
187
- Field(
188
- description="Unique identifier for the confirmation request",
189
- alias="confirmationId",
190
- ),
191
- ]
192
- message: Annotated[
193
- str,
194
- Field(
195
- description="Instructions for retrying the request after user confirmation"
196
- ),
197
- ] = "User confirmation required. Please retry with the same confirmation_id."
198
-
199
- model_config = ConfigDict(extra="forbid", populate_by_name=True)
200
-
201
-
202
- PermissionToolResponse = (
203
- PermissionToolAllowResponse
204
- | PermissionToolDenyResponse
205
- | PermissionToolPendingResponse
206
- )
207
-
208
-
209
- class RateLimitError(APIError):
210
- """Rate limit error."""
211
-
212
- type: Annotated[Literal["rate_limit_error"], Field(description="Error type")] = (
213
- "rate_limit_error"
214
- )
215
-
216
-
217
- class InvalidRequestError(APIError):
218
- """Invalid request error."""
219
-
220
- type: Annotated[
221
- Literal["invalid_request_error"], Field(description="Error type")
222
- ] = "invalid_request_error"
223
-
224
-
225
- class AuthenticationError(APIError):
226
- """Authentication error."""
227
-
228
- type: Annotated[
229
- Literal["authentication_error"], Field(description="Error type")
230
- ] = "authentication_error"
231
-
232
-
233
- class NotFoundError(APIError):
234
- """Not found error."""
235
-
236
- type: Annotated[Literal["not_found_error"], Field(description="Error type")] = (
237
- "not_found_error"
238
- )
239
-
240
-
241
- class OverloadedError(APIError):
242
- """Overloaded error."""
243
-
244
- type: Annotated[Literal["overloaded_error"], Field(description="Error type")] = (
245
- "overloaded_error"
246
- )
247
-
248
-
249
- class InternalServerError(APIError):
250
- """Internal server error."""
251
-
252
- type: Annotated[
253
- Literal["internal_server_error"], Field(description="Error type")
254
- ] = "internal_server_error"
255
-
256
-
257
- class CodexResponse(BaseModel):
258
- """OpenAI Codex completion response model."""
259
-
260
- id: Annotated[str, Field(description="Response ID")]
261
- model: Annotated[str, Field(description="Model used for completion")]
262
- content: Annotated[str, Field(description="Generated content")]
263
- finish_reason: Annotated[
264
- str | None, Field(description="Reason the response finished")
265
- ] = None
266
- usage: Annotated[Usage | None, Field(description="Token usage information")] = None
267
-
268
- model_config = ConfigDict(
269
- extra="allow"
270
- ) # Allow additional fields for compatibility