kiapi 0.1.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 (465) hide show
  1. kiapi/__init__.py +3 -0
  2. kiapi/__main__.py +4 -0
  3. kiapi/api/__init__.py +26 -0
  4. kiapi/api/_constants/require_auth.py +14 -0
  5. kiapi/api/_helpers/build_job_responses.py +73 -0
  6. kiapi/api/_helpers/build_openapi.py +55 -0
  7. kiapi/api/_helpers/build_train_responses.py +21 -0
  8. kiapi/api/_helpers/get_accept.py +20 -0
  9. kiapi/api/_helpers/get_ctx.py +7 -0
  10. kiapi/api/_helpers/get_worker.py +7 -0
  11. kiapi/api/_helpers/register_capability_endpoints.py +70 -0
  12. kiapi/api/_helpers/submit_and_maybe_wait.py +113 -0
  13. kiapi/api/_settings.py +50 -0
  14. kiapi/api/_views/async_job_response.py +21 -0
  15. kiapi/api/_views/capability_model_spec.py +49 -0
  16. kiapi/api/app.py +150 -0
  17. kiapi/api/audio/acestep/_views/extract_response.py +57 -0
  18. kiapi/api/audio/acestep/_views/track_response.py +57 -0
  19. kiapi/api/audio/acestep/router.py +190 -0
  20. kiapi/api/audio/audiogen/_views/audio_response.py +46 -0
  21. kiapi/api/audio/audiogen/router.py +77 -0
  22. kiapi/api/chat/_views/chat_completion_response.py +71 -0
  23. kiapi/api/chat/router.py +253 -0
  24. kiapi/api/embedding/_views/embedding_response.py +35 -0
  25. kiapi/api/embedding/router.py +82 -0
  26. kiapi/api/files/_operations/get_file.py +14 -0
  27. kiapi/api/files/_operations/get_file_id.py +18 -0
  28. kiapi/api/files/_views/file_delete_response.py +14 -0
  29. kiapi/api/files/_views/file_list_response.py +15 -0
  30. kiapi/api/files/router.py +105 -0
  31. kiapi/api/health/_views/health_response.py +26 -0
  32. kiapi/api/health/router.py +28 -0
  33. kiapi/api/image/depthpro/_views/estimate_response.py +70 -0
  34. kiapi/api/image/depthpro/router.py +81 -0
  35. kiapi/api/image/ernie/_views/image_response.py +50 -0
  36. kiapi/api/image/ernie/router.py +181 -0
  37. kiapi/api/image/flux2/_views/image_response.py +53 -0
  38. kiapi/api/image/flux2/router.py +197 -0
  39. kiapi/api/image/ideogram4/_views/image_response.py +55 -0
  40. kiapi/api/image/ideogram4/router.py +87 -0
  41. kiapi/api/image/qwen/_views/image_response.py +47 -0
  42. kiapi/api/image/qwen/router.py +141 -0
  43. kiapi/api/image/seedvr2/_views/image_response.py +50 -0
  44. kiapi/api/image/seedvr2/router.py +83 -0
  45. kiapi/api/image/zimage/_views/image_response.py +49 -0
  46. kiapi/api/image/zimage/router.py +131 -0
  47. kiapi/api/jobs/_operations/get_job_id.py +18 -0
  48. kiapi/api/jobs/_views/job_delete_response.py +19 -0
  49. kiapi/api/jobs/_views/job_list_response.py +15 -0
  50. kiapi/api/jobs/router.py +62 -0
  51. kiapi/api/models/_schemas/openai_model_spec.py +26 -0
  52. kiapi/api/models/_views/model_list_response.py +15 -0
  53. kiapi/api/models/router.py +29 -0
  54. kiapi/api/video/ltx2/_views/__init__.py +1 -0
  55. kiapi/api/video/ltx2/_views/video_response.py +59 -0
  56. kiapi/api/video/ltx2/router.py +89 -0
  57. kiapi/api/web/_views/__init__.py +7 -0
  58. kiapi/api/web/_views/fetch_api_request.py +26 -0
  59. kiapi/api/web/_views/fetch_error_response.py +25 -0
  60. kiapi/api/web/router.py +302 -0
  61. kiapi/capabilities/__init__.py +24 -0
  62. kiapi/capabilities/_exceptions/CapabilityError.py +2 -0
  63. kiapi/capabilities/_exceptions/ValidationError.py +2 -0
  64. kiapi/capabilities/_helpers/attach_mflux_progress.py +50 -0
  65. kiapi/capabilities/_helpers/get_file_path.py +20 -0
  66. kiapi/capabilities/_helpers/resolve_file_ref.py +16 -0
  67. kiapi/capabilities/acestep/README.ja.md +174 -0
  68. kiapi/capabilities/acestep/README.md +167 -0
  69. kiapi/capabilities/acestep/__init__.py +37 -0
  70. kiapi/capabilities/acestep/_constants/description.py +122 -0
  71. kiapi/capabilities/acestep/_exceptions/ace_step_engine_error.py +2 -0
  72. kiapi/capabilities/acestep/_helpers/register.py +96 -0
  73. kiapi/capabilities/acestep/_models/acestep.py +105 -0
  74. kiapi/capabilities/acestep/_operations/handle_cover.py +23 -0
  75. kiapi/capabilities/acestep/_operations/handle_extract.py +38 -0
  76. kiapi/capabilities/acestep/_operations/handle_generate.py +18 -0
  77. kiapi/capabilities/acestep/_operations/handle_repaint.py +25 -0
  78. kiapi/capabilities/acestep/_operations/resolve_ace_step_paths.py +30 -0
  79. kiapi/capabilities/acestep/_operations/resolve_cover_params.py +21 -0
  80. kiapi/capabilities/acestep/_operations/resolve_engine.py +10 -0
  81. kiapi/capabilities/acestep/_operations/resolve_extract_params.py +24 -0
  82. kiapi/capabilities/acestep/_operations/resolve_generate_params.py +18 -0
  83. kiapi/capabilities/acestep/_operations/resolve_repaint_params.py +22 -0
  84. kiapi/capabilities/acestep/_schemas/ace_step_paths.py +29 -0
  85. kiapi/capabilities/acestep/_services/ace_step_engine.py +143 -0
  86. kiapi/capabilities/acestep/_settings.py +82 -0
  87. kiapi/capabilities/acestep/_views/ace_step_base.py +61 -0
  88. kiapi/capabilities/acestep/_views/cover_params.py +26 -0
  89. kiapi/capabilities/acestep/_views/cover_request.py +49 -0
  90. kiapi/capabilities/acestep/_views/extract_params.py +24 -0
  91. kiapi/capabilities/acestep/_views/extract_request.py +33 -0
  92. kiapi/capabilities/acestep/_views/generate_params.py +25 -0
  93. kiapi/capabilities/acestep/_views/generate_request.py +54 -0
  94. kiapi/capabilities/acestep/_views/repaint_params.py +27 -0
  95. kiapi/capabilities/acestep/_views/repaint_request.py +51 -0
  96. kiapi/capabilities/acestep/_views/track_params.py +7 -0
  97. kiapi/capabilities/acestep/worker_subprocess.py +247 -0
  98. kiapi/capabilities/audiogen/README.ja.md +49 -0
  99. kiapi/capabilities/audiogen/README.md +48 -0
  100. kiapi/capabilities/audiogen/__init__.py +25 -0
  101. kiapi/capabilities/audiogen/_constants/description.py +60 -0
  102. kiapi/capabilities/audiogen/_helpers/attach_audiogen_progress.py +27 -0
  103. kiapi/capabilities/audiogen/_helpers/register.py +42 -0
  104. kiapi/capabilities/audiogen/_helpers/validate_generate.py +14 -0
  105. kiapi/capabilities/audiogen/_models/audiogen.py +98 -0
  106. kiapi/capabilities/audiogen/_operations/handle_generate.py +27 -0
  107. kiapi/capabilities/audiogen/_operations/resolve_generate_params.py +25 -0
  108. kiapi/capabilities/audiogen/_settings.py +34 -0
  109. kiapi/capabilities/audiogen/_views/generate_params.py +14 -0
  110. kiapi/capabilities/audiogen/_views/generate_request.py +96 -0
  111. kiapi/capabilities/chat/README.ja.md +822 -0
  112. kiapi/capabilities/chat/README.md +806 -0
  113. kiapi/capabilities/chat/__init__.py +25 -0
  114. kiapi/capabilities/chat/_constants/description.py +163 -0
  115. kiapi/capabilities/chat/_helpers/register.py +67 -0
  116. kiapi/capabilities/chat/_models/qwen3_5.py +183 -0
  117. kiapi/capabilities/chat/_models/qwen3_omni.py +242 -0
  118. kiapi/capabilities/chat/_operations/apply_template.py +74 -0
  119. kiapi/capabilities/chat/_operations/completed_hermes_tool_call_text.py +9 -0
  120. kiapi/capabilities/chat/_operations/emit_streaming_response.py +297 -0
  121. kiapi/capabilities/chat/_operations/ensure_streaming_detokenizer_compat.py +49 -0
  122. kiapi/capabilities/chat/_operations/format_response.py +72 -0
  123. kiapi/capabilities/chat/_operations/handle_chat.py +25 -0
  124. kiapi/capabilities/chat/_operations/parse_hermes_tool_calls.py +63 -0
  125. kiapi/capabilities/chat/_operations/parse_json_tool_calls.py +66 -0
  126. kiapi/capabilities/chat/_operations/parse_messages.py +326 -0
  127. kiapi/capabilities/chat/_operations/resolve_chat_params.py +50 -0
  128. kiapi/capabilities/chat/_operations/stream_text_from_tokens.py +32 -0
  129. kiapi/capabilities/chat/_operations/strip_tool_calls.py +15 -0
  130. kiapi/capabilities/chat/_settings.py +74 -0
  131. kiapi/capabilities/chat/_utils/apply_parallel_tool_call_policy.py +17 -0
  132. kiapi/capabilities/chat/_utils/apply_seed.py +8 -0
  133. kiapi/capabilities/chat/_utils/load_audio_mono.py +31 -0
  134. kiapi/capabilities/chat/_utils/load_mlx_vlm.py +12 -0
  135. kiapi/capabilities/chat/_utils/warmup_params.py +26 -0
  136. kiapi/capabilities/chat/_views/chat_params.py +34 -0
  137. kiapi/capabilities/chat/_views/chat_request.py +153 -0
  138. kiapi/capabilities/depthpro/README.ja.md +131 -0
  139. kiapi/capabilities/depthpro/README.md +124 -0
  140. kiapi/capabilities/depthpro/__init__.py +23 -0
  141. kiapi/capabilities/depthpro/_constants/description.py +39 -0
  142. kiapi/capabilities/depthpro/_helpers/register.py +46 -0
  143. kiapi/capabilities/depthpro/_helpers/validate_estimate.py +32 -0
  144. kiapi/capabilities/depthpro/_models/depthpro.py +144 -0
  145. kiapi/capabilities/depthpro/_operations/handle_estimate.py +50 -0
  146. kiapi/capabilities/depthpro/_operations/is_quantize_override.py +12 -0
  147. kiapi/capabilities/depthpro/_operations/resolve_estimate_params.py +24 -0
  148. kiapi/capabilities/depthpro/_settings.py +46 -0
  149. kiapi/capabilities/depthpro/_views/estimate_params.py +21 -0
  150. kiapi/capabilities/depthpro/_views/estimate_request.py +63 -0
  151. kiapi/capabilities/embedding/README.ja.md +137 -0
  152. kiapi/capabilities/embedding/README.md +128 -0
  153. kiapi/capabilities/embedding/__init__.py +24 -0
  154. kiapi/capabilities/embedding/_constants/description.py +47 -0
  155. kiapi/capabilities/embedding/_helpers/register.py +66 -0
  156. kiapi/capabilities/embedding/_models/qwen3_text.py +53 -0
  157. kiapi/capabilities/embedding/_models/qwen3_vl.py +97 -0
  158. kiapi/capabilities/embedding/_operations/format_response.py +24 -0
  159. kiapi/capabilities/embedding/_operations/handle_embed.py +24 -0
  160. kiapi/capabilities/embedding/_operations/parse_inputs.py +108 -0
  161. kiapi/capabilities/embedding/_operations/resolve_embed_params.py +18 -0
  162. kiapi/capabilities/embedding/_settings.py +27 -0
  163. kiapi/capabilities/embedding/_utils/to_vector.py +20 -0
  164. kiapi/capabilities/embedding/_views/embed_params.py +17 -0
  165. kiapi/capabilities/embedding/_views/embed_request.py +39 -0
  166. kiapi/capabilities/ernie/README.ja.md +242 -0
  167. kiapi/capabilities/ernie/README.md +223 -0
  168. kiapi/capabilities/ernie/__init__.py +34 -0
  169. kiapi/capabilities/ernie/_constants/description.py +71 -0
  170. kiapi/capabilities/ernie/_helpers/register.py +60 -0
  171. kiapi/capabilities/ernie/_helpers/validate_edit.py +19 -0
  172. kiapi/capabilities/ernie/_helpers/validate_generate.py +8 -0
  173. kiapi/capabilities/ernie/_models/ernie.py +356 -0
  174. kiapi/capabilities/ernie/_operations/handle_edit.py +39 -0
  175. kiapi/capabilities/ernie/_operations/handle_generate.py +38 -0
  176. kiapi/capabilities/ernie/_operations/handle_train.py +77 -0
  177. kiapi/capabilities/ernie/_operations/is_quantize_override.py +16 -0
  178. kiapi/capabilities/ernie/_operations/resolve_edit_params.py +44 -0
  179. kiapi/capabilities/ernie/_operations/resolve_generate_params.py +40 -0
  180. kiapi/capabilities/ernie/_operations/resolve_lora_params.py +23 -0
  181. kiapi/capabilities/ernie/_operations/resolve_train_params.py +43 -0
  182. kiapi/capabilities/ernie/_operations/validate_common.py +33 -0
  183. kiapi/capabilities/ernie/_schemas/lora_ref.py +27 -0
  184. kiapi/capabilities/ernie/_settings.py +151 -0
  185. kiapi/capabilities/ernie/_views/edit_params.py +36 -0
  186. kiapi/capabilities/ernie/_views/edit_request.py +142 -0
  187. kiapi/capabilities/ernie/_views/generate_params.py +32 -0
  188. kiapi/capabilities/ernie/_views/generate_request.py +127 -0
  189. kiapi/capabilities/ernie/_views/train_params.py +28 -0
  190. kiapi/capabilities/ernie/_views/train_request.py +96 -0
  191. kiapi/capabilities/flux2/README.ja.md +260 -0
  192. kiapi/capabilities/flux2/README.md +241 -0
  193. kiapi/capabilities/flux2/__init__.py +36 -0
  194. kiapi/capabilities/flux2/_constants/description.py +81 -0
  195. kiapi/capabilities/flux2/_helpers/register.py +98 -0
  196. kiapi/capabilities/flux2/_helpers/validate_edit.py +12 -0
  197. kiapi/capabilities/flux2/_helpers/validate_generate.py +8 -0
  198. kiapi/capabilities/flux2/_models/flux2.py +396 -0
  199. kiapi/capabilities/flux2/_operations/handle_edit.py +44 -0
  200. kiapi/capabilities/flux2/_operations/handle_generate.py +46 -0
  201. kiapi/capabilities/flux2/_operations/handle_train.py +105 -0
  202. kiapi/capabilities/flux2/_operations/is_quantize_override.py +16 -0
  203. kiapi/capabilities/flux2/_operations/resolve_edit_params.py +43 -0
  204. kiapi/capabilities/flux2/_operations/resolve_generate_params.py +44 -0
  205. kiapi/capabilities/flux2/_operations/resolve_lora_params.py +23 -0
  206. kiapi/capabilities/flux2/_operations/resolve_train_params.py +42 -0
  207. kiapi/capabilities/flux2/_operations/role_spec.py +13 -0
  208. kiapi/capabilities/flux2/_operations/split_repo.py +11 -0
  209. kiapi/capabilities/flux2/_operations/validate_common.py +35 -0
  210. kiapi/capabilities/flux2/_schemas/lora_ref.py +27 -0
  211. kiapi/capabilities/flux2/_settings.py +181 -0
  212. kiapi/capabilities/flux2/_views/edit_params.py +36 -0
  213. kiapi/capabilities/flux2/_views/edit_request.py +145 -0
  214. kiapi/capabilities/flux2/_views/generate_params.py +36 -0
  215. kiapi/capabilities/flux2/_views/generate_request.py +150 -0
  216. kiapi/capabilities/flux2/_views/train_params.py +32 -0
  217. kiapi/capabilities/flux2/_views/train_request.py +102 -0
  218. kiapi/capabilities/ideogram4/README.ja.md +230 -0
  219. kiapi/capabilities/ideogram4/README.md +219 -0
  220. kiapi/capabilities/ideogram4/__init__.py +24 -0
  221. kiapi/capabilities/ideogram4/_constants/description.py +65 -0
  222. kiapi/capabilities/ideogram4/_helpers/register.py +44 -0
  223. kiapi/capabilities/ideogram4/_helpers/validate_generate.py +31 -0
  224. kiapi/capabilities/ideogram4/_models/ideogram4.py +120 -0
  225. kiapi/capabilities/ideogram4/_operations/handle_generate.py +30 -0
  226. kiapi/capabilities/ideogram4/_operations/is_quantize_override.py +12 -0
  227. kiapi/capabilities/ideogram4/_operations/resolve_generate_params.py +30 -0
  228. kiapi/capabilities/ideogram4/_settings.py +89 -0
  229. kiapi/capabilities/ideogram4/_views/generate_params.py +27 -0
  230. kiapi/capabilities/ideogram4/_views/generate_request.py +118 -0
  231. kiapi/capabilities/ltx2/README.ja.md +287 -0
  232. kiapi/capabilities/ltx2/README.md +274 -0
  233. kiapi/capabilities/ltx2/__init__.py +26 -0
  234. kiapi/capabilities/ltx2/_constants/description.py +81 -0
  235. kiapi/capabilities/ltx2/_helpers/register.py +58 -0
  236. kiapi/capabilities/ltx2/_helpers/validate_generate.py +42 -0
  237. kiapi/capabilities/ltx2/_models/ltx2.py +106 -0
  238. kiapi/capabilities/ltx2/_operations/detect_mode.py +19 -0
  239. kiapi/capabilities/ltx2/_operations/handle_generate.py +52 -0
  240. kiapi/capabilities/ltx2/_operations/resolve_generate_params.py +31 -0
  241. kiapi/capabilities/ltx2/_settings.py +93 -0
  242. kiapi/capabilities/ltx2/_views/generate_params.py +34 -0
  243. kiapi/capabilities/ltx2/_views/generate_request.py +151 -0
  244. kiapi/capabilities/qwen/README.ja.md +251 -0
  245. kiapi/capabilities/qwen/README.md +235 -0
  246. kiapi/capabilities/qwen/__init__.py +30 -0
  247. kiapi/capabilities/qwen/_constants/description.py +53 -0
  248. kiapi/capabilities/qwen/_helpers/register.py +60 -0
  249. kiapi/capabilities/qwen/_helpers/validate_edit.py +12 -0
  250. kiapi/capabilities/qwen/_helpers/validate_generate.py +12 -0
  251. kiapi/capabilities/qwen/_models/qwen.py +224 -0
  252. kiapi/capabilities/qwen/_operations/handle_edit.py +44 -0
  253. kiapi/capabilities/qwen/_operations/handle_generate.py +46 -0
  254. kiapi/capabilities/qwen/_operations/is_quantize_override.py +15 -0
  255. kiapi/capabilities/qwen/_operations/resolve_edit_params.py +35 -0
  256. kiapi/capabilities/qwen/_operations/resolve_generate_params.py +39 -0
  257. kiapi/capabilities/qwen/_operations/resolve_lora_params.py +23 -0
  258. kiapi/capabilities/qwen/_operations/validate_common.py +32 -0
  259. kiapi/capabilities/qwen/_schemas/lora_ref.py +27 -0
  260. kiapi/capabilities/qwen/_settings.py +107 -0
  261. kiapi/capabilities/qwen/_views/edit_params.py +36 -0
  262. kiapi/capabilities/qwen/_views/edit_request.py +138 -0
  263. kiapi/capabilities/qwen/_views/generate_params.py +37 -0
  264. kiapi/capabilities/qwen/_views/generate_request.py +149 -0
  265. kiapi/capabilities/seedvr2/README.ja.md +234 -0
  266. kiapi/capabilities/seedvr2/README.md +219 -0
  267. kiapi/capabilities/seedvr2/__init__.py +24 -0
  268. kiapi/capabilities/seedvr2/_constants/description.py +46 -0
  269. kiapi/capabilities/seedvr2/_helpers/register.py +60 -0
  270. kiapi/capabilities/seedvr2/_helpers/validate_upscale.py +52 -0
  271. kiapi/capabilities/seedvr2/_models/seedvr2.py +140 -0
  272. kiapi/capabilities/seedvr2/_operations/handle_upscale.py +42 -0
  273. kiapi/capabilities/seedvr2/_operations/is_quantize_override.py +12 -0
  274. kiapi/capabilities/seedvr2/_operations/resolve_upscale_params.py +30 -0
  275. kiapi/capabilities/seedvr2/_settings.py +74 -0
  276. kiapi/capabilities/seedvr2/_views/upscale_params.py +27 -0
  277. kiapi/capabilities/seedvr2/_views/upscale_request.py +94 -0
  278. kiapi/capabilities/web/README.ja.md +187 -0
  279. kiapi/capabilities/web/README.md +171 -0
  280. kiapi/capabilities/web/__init__.py +30 -0
  281. kiapi/capabilities/web/_constants/description.py +38 -0
  282. kiapi/capabilities/web/_exceptions/FetchError.py +24 -0
  283. kiapi/capabilities/web/_exceptions/SearchBackendError.py +11 -0
  284. kiapi/capabilities/web/_helpers/register.py +59 -0
  285. kiapi/capabilities/web/_models/crawl4ai.py +32 -0
  286. kiapi/capabilities/web/_models/searxng.py +44 -0
  287. kiapi/capabilities/web/_operations/handle_fetch.py +145 -0
  288. kiapi/capabilities/web/_operations/handle_search.py +56 -0
  289. kiapi/capabilities/web/_operations/resolve_fetch_params.py +19 -0
  290. kiapi/capabilities/web/_operations/resolve_search_params.py +34 -0
  291. kiapi/capabilities/web/_operations/resolve_searxng_config_dir.py +21 -0
  292. kiapi/capabilities/web/_services/__init__.py +1 -0
  293. kiapi/capabilities/web/_services/web_backend_process.py +144 -0
  294. kiapi/capabilities/web/_settings.py +138 -0
  295. kiapi/capabilities/web/_views/fetch_params.py +27 -0
  296. kiapi/capabilities/web/_views/fetch_request.py +29 -0
  297. kiapi/capabilities/web/_views/fetch_result.py +20 -0
  298. kiapi/capabilities/web/_views/search_params.py +43 -0
  299. kiapi/capabilities/web/_views/search_request.py +93 -0
  300. kiapi/capabilities/web/_views/search_response.py +49 -0
  301. kiapi/capabilities/web/resources/__init__.py +0 -0
  302. kiapi/capabilities/web/resources/searxng/__init__.py +0 -0
  303. kiapi/capabilities/web/resources/searxng/settings.yml +11 -0
  304. kiapi/capabilities/zimage/README.ja.md +249 -0
  305. kiapi/capabilities/zimage/README.md +231 -0
  306. kiapi/capabilities/zimage/__init__.py +34 -0
  307. kiapi/capabilities/zimage/_constants/description.py +73 -0
  308. kiapi/capabilities/zimage/_helpers/register.py +62 -0
  309. kiapi/capabilities/zimage/_helpers/validate_generate.py +37 -0
  310. kiapi/capabilities/zimage/_models/zimage.py +278 -0
  311. kiapi/capabilities/zimage/_operations/handle_generate.py +38 -0
  312. kiapi/capabilities/zimage/_operations/handle_train.py +78 -0
  313. kiapi/capabilities/zimage/_operations/is_quantize_override.py +11 -0
  314. kiapi/capabilities/zimage/_operations/resolve_generate_params.py +39 -0
  315. kiapi/capabilities/zimage/_operations/resolve_lora_params.py +23 -0
  316. kiapi/capabilities/zimage/_operations/resolve_train_params.py +38 -0
  317. kiapi/capabilities/zimage/_schemas/lora_ref.py +27 -0
  318. kiapi/capabilities/zimage/_settings.py +166 -0
  319. kiapi/capabilities/zimage/_views/generate_params.py +23 -0
  320. kiapi/capabilities/zimage/_views/generate_request.py +127 -0
  321. kiapi/capabilities/zimage/_views/train_params.py +22 -0
  322. kiapi/capabilities/zimage/_views/train_request.py +101 -0
  323. kiapi/cli/__init__.py +11 -0
  324. kiapi/cli/_helpers/dedupe_resources.py +12 -0
  325. kiapi/cli/_helpers/register_all_capabilities.py +36 -0
  326. kiapi/cli/_helpers/run_resources.py +24 -0
  327. kiapi/cli/_helpers/select_specs.py +67 -0
  328. kiapi/cli/activate/_operations/preflight_hf_access.py +129 -0
  329. kiapi/cli/activate/cli.py +37 -0
  330. kiapi/cli/check/_helpers/check_audio_acestep_turbo.py +22 -0
  331. kiapi/cli/check/_helpers/check_audio_acestep_xl_base.py +22 -0
  332. kiapi/cli/check/_helpers/check_audio_audiogen_medium.py +24 -0
  333. kiapi/cli/check/_helpers/check_chat_chat_qwen3_6_27b.py +19 -0
  334. kiapi/cli/check/_helpers/check_chat_chat_qwen3_omni.py +19 -0
  335. kiapi/cli/check/_helpers/check_embedding_embedding_qwen3_embedding_8b.py +14 -0
  336. kiapi/cli/check/_helpers/check_embedding_embedding_qwen3_vl_embedding_2b.py +19 -0
  337. kiapi/cli/check/_helpers/check_image_depthpro_base.py +21 -0
  338. kiapi/cli/check/_helpers/check_image_ernie_base.py +23 -0
  339. kiapi/cli/check/_helpers/check_image_ernie_turbo.py +23 -0
  340. kiapi/cli/check/_helpers/check_image_flux2_klein_9b.py +23 -0
  341. kiapi/cli/check/_helpers/check_image_flux2_klein_base_4b.py +23 -0
  342. kiapi/cli/check/_helpers/check_image_flux2_klein_base_9b.py +23 -0
  343. kiapi/cli/check/_helpers/check_image_ideogram4_fp8.py +23 -0
  344. kiapi/cli/check/_helpers/check_image_qwen_edit_2509.py +27 -0
  345. kiapi/cli/check/_helpers/check_image_qwen_image.py +23 -0
  346. kiapi/cli/check/_helpers/check_image_seedvr2_3b.py +23 -0
  347. kiapi/cli/check/_helpers/check_image_seedvr2_7b.py +23 -0
  348. kiapi/cli/check/_helpers/check_image_zimage_base.py +23 -0
  349. kiapi/cli/check/_helpers/check_image_zimage_turbo.py +23 -0
  350. kiapi/cli/check/_helpers/check_video_ltx2_distilled.py +26 -0
  351. kiapi/cli/check/_helpers/check_web_web_fetch.py +14 -0
  352. kiapi/cli/check/_helpers/check_web_web_search.py +14 -0
  353. kiapi/cli/check/_operations/build_check_result.py +20 -0
  354. kiapi/cli/check/_operations/check_context.py +10 -0
  355. kiapi/cli/check/_operations/create_sample_image.py +46 -0
  356. kiapi/cli/check/_schemas/check_result.py +12 -0
  357. kiapi/cli/check/cli.py +89 -0
  358. kiapi/cli/cli.py +29 -0
  359. kiapi/cli/config/cli.py +17 -0
  360. kiapi/cli/config/edit/cli.py +32 -0
  361. kiapi/cli/config/init/cli.py +33 -0
  362. kiapi/cli/config/show/cli.py +13 -0
  363. kiapi/cli/config/template/cli.py +36 -0
  364. kiapi/cli/deactivate/cli.py +49 -0
  365. kiapi/cli/run/asgi.py +16 -0
  366. kiapi/cli/run/cli.py +59 -0
  367. kiapi/cli/service/__init__.py +5 -0
  368. kiapi/cli/service/_services/service_manager.py +107 -0
  369. kiapi/cli/service/cli.py +19 -0
  370. kiapi/cli/service/install/cli.py +17 -0
  371. kiapi/cli/service/start/cli.py +22 -0
  372. kiapi/cli/service/status/cli.py +81 -0
  373. kiapi/cli/service/stop/cli.py +19 -0
  374. kiapi/cli/service/uninstall/cli.py +16 -0
  375. kiapi/cli/status/cli.py +226 -0
  376. kiapi/core/app/__init__.py +16 -0
  377. kiapi/core/app/_schemas/app_context.py +28 -0
  378. kiapi/core/app/_services/user_directory.py +59 -0
  379. kiapi/core/app/_settings.py +46 -0
  380. kiapi/core/capability/__init__.py +11 -0
  381. kiapi/core/capability/_schemas/capability_spec.py +17 -0
  382. kiapi/core/capability/_services/capability_spec_registry.py +21 -0
  383. kiapi/core/config/__init__.py +11 -0
  384. kiapi/core/config/_exceptions/user_config_error.py +2 -0
  385. kiapi/core/config/_helpers/get_user_settings_path.py +7 -0
  386. kiapi/core/config/_helpers/load_user_settings.py +54 -0
  387. kiapi/core/file/__init__.py +37 -0
  388. kiapi/core/file/_helpers/create_file_store.py +7 -0
  389. kiapi/core/file/_helpers/resolve_file_ref.py +90 -0
  390. kiapi/core/file/_schemas/file_data_url_ref.py +19 -0
  391. kiapi/core/file/_schemas/file_id_ref.py +16 -0
  392. kiapi/core/file/_schemas/file_record.py +46 -0
  393. kiapi/core/file/_schemas/file_url_ref.py +16 -0
  394. kiapi/core/file/_services/file_store.py +138 -0
  395. kiapi/core/file/_settings.py +22 -0
  396. kiapi/core/file/_types/file_id.py +2 -0
  397. kiapi/core/file/_types/file_ref.py +12 -0
  398. kiapi/core/file/_views/resolved_file_ref.py +16 -0
  399. kiapi/core/job/__init__.py +24 -0
  400. kiapi/core/job/_enums/job_status.py +9 -0
  401. kiapi/core/job/_helpers/creep_progress.py +123 -0
  402. kiapi/core/job/_models/job.py +121 -0
  403. kiapi/core/job/_services/job_store.py +33 -0
  404. kiapi/core/job/_services/progress_reporter.py +79 -0
  405. kiapi/core/job/_types/job_id.py +3 -0
  406. kiapi/core/job/_types/job_result.py +5 -0
  407. kiapi/core/job/_types/job_type.py +4 -0
  408. kiapi/core/logging/__init__.py +14 -0
  409. kiapi/core/logging/_helpers/get_log_level.py +8 -0
  410. kiapi/core/logging/_helpers/setup_logger.py +14 -0
  411. kiapi/core/logging/_settings.py +34 -0
  412. kiapi/core/logging/_types/log_level.py +3 -0
  413. kiapi/core/memory/__init__.py +21 -0
  414. kiapi/core/memory/_exceptions/memory_budget_error.py +2 -0
  415. kiapi/core/memory/_helpers/create_memory_manager.py +17 -0
  416. kiapi/core/memory/_operations/log_memory_limit.py +29 -0
  417. kiapi/core/memory/_operations/resolve_effective_memory_limit_gb.py +13 -0
  418. kiapi/core/memory/_operations/resolve_framework_strategy.py +42 -0
  419. kiapi/core/memory/_schemas/framework_strategy.py +14 -0
  420. kiapi/core/memory/_schemas/memory_stats.py +24 -0
  421. kiapi/core/memory/_schemas/resident_model.py +14 -0
  422. kiapi/core/memory/_schemas/resident_model_stats.py +49 -0
  423. kiapi/core/memory/_services/memory_manager.py +257 -0
  424. kiapi/core/memory/_settings.py +36 -0
  425. kiapi/core/memory/_types/framework_name.py +4 -0
  426. kiapi/core/memory/_types/resident_key.py +4 -0
  427. kiapi/core/model/__init__.py +36 -0
  428. kiapi/core/model/_exceptions/unknown_model_error.py +2 -0
  429. kiapi/core/model/_schemas/model_spec.py +145 -0
  430. kiapi/core/model/_services/model_registry.py +85 -0
  431. kiapi/core/model/_types/model_alias.py +2 -0
  432. kiapi/core/model/_types/model_domain.py +6 -0
  433. kiapi/core/model/_types/model_family.py +5 -0
  434. kiapi/core/model/_types/model_key.py +8 -0
  435. kiapi/core/model/_types/model_name.py +4 -0
  436. kiapi/core/model/_types/model_repo.py +3 -0
  437. kiapi/core/net/__init__.py +16 -0
  438. kiapi/core/net/_exceptions/unsafe_url_error.py +7 -0
  439. kiapi/core/net/_helpers/verify_public_url.py +68 -0
  440. kiapi/core/net/_settings.py +28 -0
  441. kiapi/core/setup/__init__.py +25 -0
  442. kiapi/core/setup/_exceptions/setup_required_error.py +2 -0
  443. kiapi/core/setup/_schemas/docker_image_resource.py +37 -0
  444. kiapi/core/setup/_schemas/hf_snapshot_resource.py +50 -0
  445. kiapi/core/setup/_schemas/local_path_resource.py +43 -0
  446. kiapi/core/setup/_schemas/python_package_resource.py +58 -0
  447. kiapi/core/setup/_schemas/python_venv_resource.py +63 -0
  448. kiapi/core/setup/_schemas/setup_status.py +7 -0
  449. kiapi/core/setup/_schemas/url_file_resource.py +43 -0
  450. kiapi/core/setup/_services/setup_manager.py +331 -0
  451. kiapi/core/setup/_types/setup_resource.py +21 -0
  452. kiapi/core/setup/_types/setup_target.py +11 -0
  453. kiapi/core/workdir/__init__.py +8 -0
  454. kiapi/core/workdir/_helpers/create_work_dir.py +11 -0
  455. kiapi/core/workdir/_settings.py +21 -0
  456. kiapi/core/worker/__init__.py +23 -0
  457. kiapi/core/worker/_helpers/create_worker.py +9 -0
  458. kiapi/core/worker/_services/worker.py +165 -0
  459. kiapi/core/worker/_settings.py +36 -0
  460. kiapi/core/worker/_types/job_thunk.py +6 -0
  461. kiapi-0.1.0.dist-info/METADATA +337 -0
  462. kiapi-0.1.0.dist-info/RECORD +465 -0
  463. kiapi-0.1.0.dist-info/WHEEL +4 -0
  464. kiapi-0.1.0.dist-info/entry_points.txt +2 -0
  465. kiapi-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,331 @@
1
+ import shutil
2
+ import subprocess
3
+ import sys
4
+ import tempfile
5
+ import urllib.request
6
+ from pathlib import Path
7
+
8
+ from huggingface_hub import scan_cache_dir, snapshot_download
9
+
10
+ from .._exceptions.setup_required_error import SetupRequiredError
11
+ from .._schemas.docker_image_resource import DockerImageResource
12
+ from .._schemas.hf_snapshot_resource import HfSnapshotResource
13
+ from .._schemas.local_path_resource import LocalPathResource
14
+ from .._schemas.python_package_resource import PythonPackageResource
15
+ from .._schemas.python_venv_resource import PythonVenvResource
16
+ from .._schemas.setup_status import SetupStatus
17
+ from .._schemas.url_file_resource import UrlFileResource
18
+ from .._types.setup_resource import SetupResource
19
+ from .._types.setup_target import SetupTarget
20
+
21
+
22
+ class SetupManager:
23
+ def status(self, resource: SetupResource) -> SetupStatus:
24
+ if isinstance(resource, HfSnapshotResource):
25
+ return self._hf_status(resource)
26
+ if isinstance(resource, DockerImageResource):
27
+ return self._docker_status(resource)
28
+ if isinstance(resource, LocalPathResource):
29
+ path = Path(resource.path).expanduser()
30
+ if path.exists():
31
+ return SetupStatus(True, str(path))
32
+ return SetupStatus(False, f"missing: {path}")
33
+ if isinstance(resource, UrlFileResource):
34
+ path = Path(resource.path).expanduser()
35
+ if path.exists() and path.stat().st_size > 0:
36
+ return SetupStatus(True, str(path))
37
+ return SetupStatus(False, f"missing: {path}")
38
+ if isinstance(resource, PythonVenvResource):
39
+ return self._python_venv_status(resource)
40
+ if isinstance(resource, PythonPackageResource):
41
+ return self._python_package_status(resource)
42
+
43
+ def activate(self, resource: SetupResource) -> SetupStatus:
44
+ if isinstance(resource, HfSnapshotResource):
45
+ snapshot_path = snapshot_download(
46
+ repo_id=resource.repo,
47
+ revision=resource.revision,
48
+ local_dir=resource.local_dir,
49
+ )
50
+ return SetupStatus(True, str(snapshot_path))
51
+ if isinstance(resource, DockerImageResource):
52
+ self._docker("pull", resource.image)
53
+ return self.status(resource)
54
+ if isinstance(resource, LocalPathResource):
55
+ return self.status(resource)
56
+ if isinstance(resource, UrlFileResource):
57
+ file_path = Path(resource.path).expanduser()
58
+ file_path.parent.mkdir(parents=True, exist_ok=True)
59
+ if not file_path.exists():
60
+ with tempfile.NamedTemporaryFile(
61
+ dir=file_path.parent, delete=False
62
+ ) as tmp_file:
63
+ tmp_path = Path(tmp_file.name)
64
+ try:
65
+ urllib.request.urlretrieve(resource.url, tmp_path)
66
+ tmp_path.replace(file_path)
67
+ finally:
68
+ tmp_path.unlink(missing_ok=True)
69
+ return self.status(resource)
70
+ if isinstance(resource, PythonVenvResource):
71
+ return self._python_venv_activate(resource)
72
+ if isinstance(resource, PythonPackageResource):
73
+ return self._python_package_activate(resource)
74
+
75
+ def deactivate(self, resource: SetupResource) -> SetupStatus:
76
+ if isinstance(resource, HfSnapshotResource):
77
+ return self._hf_deactivate(resource)
78
+ if isinstance(resource, DockerImageResource):
79
+ self._docker("image", "rm", resource.image)
80
+ return self.status(resource)
81
+ if isinstance(resource, LocalPathResource):
82
+ path = Path(resource.path).expanduser()
83
+ if path.exists():
84
+ if path.is_dir():
85
+ shutil.rmtree(path)
86
+ else:
87
+ path.unlink()
88
+ return self.status(resource)
89
+ if isinstance(resource, UrlFileResource):
90
+ Path(resource.path).expanduser().unlink(missing_ok=True)
91
+ return self.status(resource)
92
+ if isinstance(resource, PythonVenvResource):
93
+ path = Path(resource.path).expanduser()
94
+ if path.exists():
95
+ shutil.rmtree(path)
96
+ return self.status(resource)
97
+ if isinstance(resource, PythonPackageResource):
98
+ return self._python_package_deactivate(resource)
99
+
100
+ def ensure_ready(self, spec: SetupTarget) -> None:
101
+ missing = [
102
+ resource
103
+ for resource in spec.setup_resources
104
+ if not self.status(resource).ready
105
+ ]
106
+ if not missing:
107
+ return
108
+
109
+ labels = ", ".join(resource.label for resource in missing)
110
+ repos = " ".join(f"--repo {resource.label}" for resource in missing)
111
+ raise SetupRequiredError(
112
+ f"model {spec.name!r} is not activated; missing: {labels}. "
113
+ f"Run: kiapi activate {repos}"
114
+ )
115
+
116
+ def _hf_status(self, resource: HfSnapshotResource) -> SetupStatus:
117
+ if resource.local_dir is not None:
118
+ local_path = Path(resource.local_dir).expanduser()
119
+ if local_path.exists() and any(local_path.iterdir()):
120
+ return SetupStatus(True, str(local_path))
121
+ return SetupStatus(False, f"missing: {local_path}")
122
+
123
+ try:
124
+ snapshot_path = snapshot_download(
125
+ repo_id=resource.repo,
126
+ revision=resource.revision,
127
+ local_dir=resource.local_dir,
128
+ local_files_only=True,
129
+ )
130
+ except Exception as exc:
131
+ return SetupStatus(False, str(exc))
132
+ return SetupStatus(True, str(snapshot_path))
133
+
134
+ def _hf_deactivate(self, resource: HfSnapshotResource) -> SetupStatus:
135
+ if resource.local_dir is not None:
136
+ path = Path(resource.local_dir).expanduser()
137
+ if path.exists():
138
+ shutil.rmtree(path)
139
+ return self.status(resource)
140
+
141
+ info = scan_cache_dir()
142
+ revisions: list[str] = []
143
+ for repo in info.repos:
144
+ if repo.repo_id != resource.repo:
145
+ continue
146
+ for revision in repo.revisions:
147
+ revisions.append(revision.commit_hash)
148
+
149
+ if revisions:
150
+ strategy = info.delete_revisions(*revisions)
151
+ strategy.execute()
152
+
153
+ return self.status(resource)
154
+
155
+ def _docker_status(self, resource: DockerImageResource) -> SetupStatus:
156
+ try:
157
+ self._docker("image", "inspect", resource.image)
158
+ except subprocess.CalledProcessError as exc:
159
+ detail = (exc.stderr or exc.stdout or str(exc)).strip()
160
+ return SetupStatus(False, detail)
161
+ return SetupStatus(True, "present")
162
+
163
+ def _docker(self, *args: str) -> subprocess.CompletedProcess[str]:
164
+ return subprocess.run(
165
+ ["docker", *args],
166
+ check=True,
167
+ text=True,
168
+ capture_output=True,
169
+ )
170
+
171
+ def _python_venv_status(self, resource: PythonVenvResource) -> SetupStatus:
172
+ python_path = self._python_venv_python_path(resource)
173
+ if not python_path.exists():
174
+ return SetupStatus(False, f"missing: {python_path}")
175
+ try:
176
+ self._run_python_import(python_path, resource.import_name)
177
+ except subprocess.CalledProcessError as exc:
178
+ detail = (exc.stderr or exc.stdout or str(exc)).strip()
179
+ return SetupStatus(False, detail)
180
+ return SetupStatus(True, str(python_path))
181
+
182
+ def _python_venv_activate(self, resource: PythonVenvResource) -> SetupStatus:
183
+ state = self.status(resource)
184
+ if state.ready:
185
+ return state
186
+
187
+ path = Path(resource.path).expanduser()
188
+ python_path = self._python_venv_python_path(resource)
189
+ if not python_path.exists():
190
+ self._create_python_venv(path, resource.python)
191
+ self._install_python_packages(python_path, resource.packages)
192
+ return self.status(resource)
193
+
194
+ def _python_venv_python_path(self, resource: PythonVenvResource) -> Path:
195
+ return Path(resource.path).expanduser() / "bin" / "python"
196
+
197
+ def _run_python_import(self, python_path: Path, import_name: str) -> None:
198
+ subprocess.run(
199
+ [str(python_path), "-c", f"import {import_name}"],
200
+ check=True,
201
+ text=True,
202
+ capture_output=True,
203
+ )
204
+
205
+ def _python_package_status(self, resource: PythonPackageResource) -> SetupStatus:
206
+ try:
207
+ self._run_python_package_verify(resource)
208
+ except subprocess.CalledProcessError as exc:
209
+ detail = (exc.stderr or exc.stdout or str(exc)).strip()
210
+ return SetupStatus(False, detail)
211
+ return SetupStatus(True, resource.import_name)
212
+
213
+ def _python_package_activate(self, resource: PythonPackageResource) -> SetupStatus:
214
+ state = self.status(resource)
215
+ if state.ready:
216
+ return state
217
+
218
+ self._install_python_packages(Path(sys.executable), (resource.spec,))
219
+ return self.status(resource)
220
+
221
+ def _python_package_deactivate(
222
+ self, resource: PythonPackageResource
223
+ ) -> SetupStatus:
224
+ self._uninstall_python_package(Path(sys.executable), resource.package)
225
+ return self.status(resource)
226
+
227
+ def _run_python_package_verify(self, resource: PythonPackageResource) -> None:
228
+ code = "\n".join(
229
+ [
230
+ "import importlib",
231
+ f"module = importlib.import_module({resource.import_name!r})",
232
+ f"attrs = {list(resource.verify_attrs)!r}",
233
+ "missing = [attr for attr in attrs if not hasattr(module, attr)]",
234
+ "if missing:",
235
+ " raise RuntimeError(f'missing attrs: {missing}')",
236
+ ]
237
+ )
238
+ subprocess.run(
239
+ [sys.executable, "-c", code],
240
+ check=True,
241
+ text=True,
242
+ capture_output=True,
243
+ )
244
+
245
+ def _create_python_venv(self, path: Path, python: str) -> None:
246
+ if shutil.which("uv"):
247
+ subprocess.run(
248
+ ["uv", "venv", "--python", python, str(path)],
249
+ check=True,
250
+ text=True,
251
+ capture_output=True,
252
+ )
253
+ return
254
+
255
+ python_bin = self._resolve_python_executable(python)
256
+ subprocess.run(
257
+ [str(python_bin), "-m", "venv", str(path)],
258
+ check=True,
259
+ text=True,
260
+ capture_output=True,
261
+ )
262
+
263
+ def _install_python_packages(
264
+ self, python_path: Path, packages: tuple[str, ...]
265
+ ) -> None:
266
+ if shutil.which("uv"):
267
+ subprocess.run(
268
+ ["uv", "pip", "install", "--python", str(python_path), *packages],
269
+ check=True,
270
+ text=True,
271
+ capture_output=True,
272
+ )
273
+ return
274
+
275
+ subprocess.run(
276
+ [str(python_path), "-m", "pip", "install", *packages],
277
+ check=True,
278
+ text=True,
279
+ capture_output=True,
280
+ )
281
+
282
+ def _uninstall_python_package(self, python_path: Path, package: str) -> None:
283
+ if shutil.which("uv"):
284
+ subprocess.run(
285
+ ["uv", "pip", "uninstall", "--python", str(python_path), package],
286
+ check=True,
287
+ text=True,
288
+ capture_output=True,
289
+ )
290
+ return
291
+
292
+ subprocess.run(
293
+ [str(python_path), "-m", "pip", "uninstall", "-y", package],
294
+ check=True,
295
+ text=True,
296
+ capture_output=True,
297
+ )
298
+
299
+ def _resolve_python_executable(self, python: str) -> Path:
300
+ candidates = [python]
301
+ if python.startswith("3."):
302
+ candidates.append(f"python{python}")
303
+ candidates.extend(["python3", sys.executable])
304
+
305
+ for candidate in candidates:
306
+ executable = (
307
+ shutil.which(candidate) if candidate != sys.executable else candidate
308
+ )
309
+ if executable and self._python_matches_requirement(
310
+ Path(executable), python
311
+ ):
312
+ return Path(executable)
313
+
314
+ raise RuntimeError(f"Python {python} executable was not found")
315
+
316
+ def _python_matches_requirement(self, python_path: Path, python: str) -> bool:
317
+ if not python.startswith("3."):
318
+ return True
319
+
320
+ code = "\n".join(
321
+ [
322
+ "import sys",
323
+ f"raise SystemExit(0 if sys.version_info[:2] == {tuple(map(int, python.split('.')))!r} else 1)",
324
+ ]
325
+ )
326
+ result = subprocess.run(
327
+ [str(python_path), "-c", code],
328
+ text=True,
329
+ capture_output=True,
330
+ )
331
+ return result.returncode == 0
@@ -0,0 +1,21 @@
1
+ from typing import Annotated
2
+
3
+ from pydantic import Field
4
+
5
+ from .._schemas.docker_image_resource import DockerImageResource
6
+ from .._schemas.hf_snapshot_resource import HfSnapshotResource
7
+ from .._schemas.local_path_resource import LocalPathResource
8
+ from .._schemas.python_package_resource import PythonPackageResource
9
+ from .._schemas.python_venv_resource import PythonVenvResource
10
+ from .._schemas.url_file_resource import UrlFileResource
11
+
12
+ SetupResource = Annotated[
13
+ HfSnapshotResource
14
+ | DockerImageResource
15
+ | LocalPathResource
16
+ | UrlFileResource
17
+ | PythonPackageResource
18
+ | PythonVenvResource,
19
+ Field(discriminator="kind"),
20
+ ]
21
+ """A resource that must be activated before a model can run, tagged by ``kind``."""
@@ -0,0 +1,11 @@
1
+ from typing import Protocol
2
+
3
+ from .setup_resource import SetupResource
4
+
5
+
6
+ class SetupTarget(Protocol):
7
+ @property
8
+ def name(self) -> str: ...
9
+
10
+ @property
11
+ def setup_resources(self) -> tuple[SetupResource, ...]: ...
@@ -0,0 +1,8 @@
1
+ from ._helpers.create_work_dir import create_work_dir
2
+ from ._settings import WorkDirSettings, settings_manager
3
+
4
+ __all__ = [
5
+ "WorkDirSettings",
6
+ "create_work_dir",
7
+ "settings_manager",
8
+ ]
@@ -0,0 +1,11 @@
1
+ import tempfile
2
+ from pathlib import Path
3
+
4
+ from .._settings import settings_manager
5
+
6
+
7
+ def create_work_dir(purpose: str) -> Path:
8
+ root = Path(settings_manager.get_settings().tmp_root).expanduser()
9
+ parent = root / purpose
10
+ parent.mkdir(parents=True, exist_ok=True)
11
+ return Path(tempfile.mkdtemp(dir=parent))
@@ -0,0 +1,21 @@
1
+ from pydantic import Field
2
+ from pydantic_settings import BaseSettings, SettingsConfigDict
3
+ from pydantic_settings_manager import SettingsManager
4
+
5
+
6
+ class WorkDirSettings(BaseSettings):
7
+ """Settings for per-request temporary work directories."""
8
+
9
+ model_config = SettingsConfigDict(env_prefix="KIAPI_")
10
+
11
+ tmp_root: str = Field(
12
+ default="/tmp/kiapi/work",
13
+ title="Temporary work directory root",
14
+ description=(
15
+ "Root directory for temporary work files created while handling requests.\n"
16
+ "Each operation creates a purpose-specific child directory under this root."
17
+ ),
18
+ )
19
+
20
+
21
+ settings_manager = SettingsManager(WorkDirSettings)
@@ -0,0 +1,23 @@
1
+ """The single-flight worker: one dedicated thread runs every job, one at a time
2
+ (MLX thread-affinity + sound memory budgeting). See :mod:`._services.worker`.
3
+
4
+ Public surface (unchanged from the former ``core/worker.py``): :class:`Worker`,
5
+ :data:`JobThunk`.
6
+ """
7
+
8
+ from ._helpers.create_worker import create_worker
9
+ from ._services.worker import Worker
10
+ from ._settings import WorkerSettings, settings_manager
11
+ from ._types.job_thunk import JobThunk
12
+
13
+ __all__ = [
14
+ # ._types
15
+ "JobThunk",
16
+ # ._services
17
+ "Worker",
18
+ # ._settings
19
+ "WorkerSettings",
20
+ # ._helpers
21
+ "create_worker",
22
+ "settings_manager",
23
+ ]
@@ -0,0 +1,9 @@
1
+ from kiapi.core.app import AppContext
2
+
3
+ from .._services.worker import Worker
4
+ from .._settings import settings_manager
5
+
6
+
7
+ def create_worker(ctx: AppContext) -> Worker:
8
+ settings = settings_manager.get_settings()
9
+ return Worker(settings, ctx)
@@ -0,0 +1,165 @@
1
+ """The single-flight worker — kiapi's one hard rule: only one job runs at a time.
2
+
3
+ All heavy work (model load, eviction, warmup, every generation, across every
4
+ capability) runs on ONE dedicated thread (``ThreadPoolExecutor(max_workers=1)``).
5
+ This is required for MLX correctness (arrays/streams are thread-affine) AND it is
6
+ what makes the global memory budget sound: the model being acquired for the
7
+ running job is the only one generating, so budgeting just its peak headroom is
8
+ correct (see core/memory). Concurrent HTTP requests are accepted and simply queue.
9
+
10
+ If you need real parallelism, run multiple kiapi processes, each scoped to a
11
+ subset of capabilities with its own slice of the memory budget.
12
+
13
+ A job's work is supplied as a JobThunk. The worker drives the job's lifecycle
14
+ (running → succeeded/failed) and resolves the caller's future. Sync callers await
15
+ the future (with a timeout); async callers drop it and poll the job store.
16
+ """
17
+
18
+ import asyncio
19
+ import logging
20
+ import traceback
21
+ from concurrent.futures import ThreadPoolExecutor
22
+
23
+ from kiapi.core.app import AppContext
24
+ from kiapi.core.job import Job, ProgressReporter
25
+ from kiapi.core.model import ModelKey
26
+ from kiapi.core.setup import SetupRequiredError
27
+
28
+ from .._settings import WorkerSettings
29
+ from .._types.job_thunk import JobThunk
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ class Worker:
35
+ def __init__(
36
+ self,
37
+ settings: WorkerSettings,
38
+ ctx: AppContext,
39
+ ) -> None:
40
+ self.settings: WorkerSettings = settings
41
+ self.ctx: AppContext = ctx
42
+ self.queue: asyncio.Queue[tuple[Job, JobThunk, asyncio.Future]] = (
43
+ asyncio.Queue()
44
+ )
45
+ self.executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix="kiapi")
46
+ self.warm = False
47
+ self._task: asyncio.Task | None = None
48
+ self._ttl_task: asyncio.Task | None = None
49
+
50
+ def start(self) -> None:
51
+ self._task = asyncio.create_task(self._run(), name="kiapi-worker")
52
+ if self.settings.ttl_sweep_interval_s > 0:
53
+ self._ttl_task = asyncio.create_task(
54
+ self._ttl_loop(), name="kiapi-ttl-sweep"
55
+ )
56
+
57
+ async def stop(self) -> None:
58
+ if self._task is not None:
59
+ self._task.cancel()
60
+ if self._ttl_task is not None:
61
+ self._ttl_task.cancel()
62
+ # Free resident models on the worker thread, then tear it down.
63
+ try:
64
+ loop = asyncio.get_running_loop()
65
+ await loop.run_in_executor(self.executor, self.ctx.memory_manager.shutdown)
66
+ except Exception:
67
+ traceback.print_exc()
68
+ self.executor.shutdown(wait=False, cancel_futures=True)
69
+
70
+ async def submit(self, job: Job, fn: JobThunk) -> asyncio.Future:
71
+ loop = asyncio.get_running_loop()
72
+ fut: asyncio.Future = loop.create_future()
73
+ await self.queue.put((job, fn, fut))
74
+ return fut
75
+
76
+ async def _run(self) -> None:
77
+ loop = asyncio.get_running_loop()
78
+ while True:
79
+ job, fn, fut = await self.queue.get()
80
+ job.mark_running()
81
+ # Bind a reporter for this job so capability code can push coarse
82
+ # progress via ProgressReporter.current(); run_bound installs it on
83
+ # the worker thread, where the thunk actually executes.
84
+ reporter = ProgressReporter(job)
85
+ try:
86
+ result, artifacts = await loop.run_in_executor(
87
+ self.executor, reporter.run_bound, fn
88
+ )
89
+ job.mark_succeeded(result, artifacts)
90
+ if not fut.done():
91
+ fut.set_result(result)
92
+ except Exception as exc:
93
+ traceback.print_exc()
94
+ job.mark_failed(str(exc))
95
+ if not fut.done():
96
+ fut.set_exception(exc)
97
+
98
+ async def _ttl_loop(self) -> None:
99
+ """The sweep runs on the worker thread (shared executor), so it serializes
100
+ with generations and respects MLX thread-affinity — it frees models past
101
+ their TTL even when no requests arrive."""
102
+ loop = asyncio.get_running_loop()
103
+ interval = self.settings.ttl_sweep_interval_s
104
+ while True:
105
+ await asyncio.sleep(interval)
106
+ try:
107
+ freed = await loop.run_in_executor(
108
+ self.executor, self.ctx.memory_manager.sweep_expired
109
+ )
110
+ if freed:
111
+ logger.info("idle sweep freed: %s", freed)
112
+ except Exception:
113
+ traceback.print_exc()
114
+
115
+ async def warmup(self) -> None:
116
+ """Each model is loaded + primed on the worker thread; acquire evicts as
117
+ needed to respect the memory budget."""
118
+ model_names = self.settings.warmup_models
119
+ if not model_names:
120
+ self.warm = True
121
+ return
122
+ loop = asyncio.get_running_loop()
123
+ for name in model_names:
124
+ try:
125
+ await loop.run_in_executor(self.executor, self._warm_one, name)
126
+ except Exception:
127
+ traceback.print_exc()
128
+ self.warm = True
129
+
130
+ def _warm_one(self, name: ModelKey) -> None:
131
+ """Runs on the worker thread."""
132
+ from kiapi.core.model import model_registry
133
+
134
+ # A warmup name is a model name; find which family owns it.
135
+ spec = None
136
+ for family in model_registry.families():
137
+ try:
138
+ spec = model_registry.resolve(family, name)
139
+ break
140
+ except Exception:
141
+ continue
142
+ if spec is None:
143
+ logger.warning("unknown warmup model %r; skipping", name)
144
+ return
145
+ if not spec.resident:
146
+ # Transient providers (e.g. video) load/free per call — nothing to
147
+ # keep resident. Prime via the module's own warmup if it has one.
148
+ warm = getattr(spec.module, "warmup", None)
149
+ if warm is not None:
150
+ try:
151
+ self.ctx.ensure_model_ready(spec)
152
+ except SetupRequiredError as exc:
153
+ logger.warning("skipping warmup for %s: %s", spec.name, exc)
154
+ return
155
+ warm(None)
156
+ return
157
+ try:
158
+ self.ctx.ensure_model_ready(spec)
159
+ except SetupRequiredError as exc:
160
+ logger.warning("skipping warmup for %s: %s", spec.name, exc)
161
+ return
162
+ payload = self.ctx.memory_manager.acquire(spec)
163
+ warm = getattr(spec.module, "warmup", None)
164
+ if warm is not None:
165
+ warm(payload)
@@ -0,0 +1,36 @@
1
+ from pydantic import Field
2
+ from pydantic_settings import BaseSettings, SettingsConfigDict
3
+ from pydantic_settings_manager import SettingsManager
4
+
5
+ from kiapi.core.model import ModelKey
6
+
7
+
8
+ class WorkerSettings(BaseSettings):
9
+ """Settings for the single worker queue, TTL sweeping, and startup warmup."""
10
+
11
+ model_config = SettingsConfigDict(
12
+ env_prefix="KIAPI_",
13
+ extra="ignore",
14
+ )
15
+
16
+ ttl_sweep_interval_s: float = Field(
17
+ default=60.0,
18
+ title="TTL sweep interval seconds",
19
+ description=(
20
+ "Interval for background checks of resident models that exceeded their idle TTL.\n"
21
+ "Set to 0.0 to completely disable the background sweep."
22
+ ),
23
+ )
24
+
25
+ warmup_models: list[ModelKey] = Field(
26
+ default_factory=list,
27
+ title="Startup warmup models",
28
+ description=(
29
+ "List of model keys to preload when the server starts.\n"
30
+ "Each item uses the model registry key format. An empty list keeps "
31
+ "models lazily loaded."
32
+ ),
33
+ )
34
+
35
+
36
+ settings_manager = SettingsManager(WorkerSettings)
@@ -0,0 +1,6 @@
1
+ from collections.abc import Callable
2
+
3
+ from kiapi.core.file import FileID
4
+ from kiapi.core.job import JobResult
5
+
6
+ type JobThunk = Callable[[], tuple[JobResult, list[FileID]]]