prompture 1.0.56.dev1__tar.gz → 1.0.56.dev2__tar.gz

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 (256) hide show
  1. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.env.copy +4 -0
  2. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/CLAUDE.md +18 -3
  3. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/PKG-INFO +79 -7
  4. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/README.md +78 -6
  5. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/_version.py +2 -2
  6. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/__init__.py +32 -0
  7. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_img_gen_driver.py +11 -5
  8. prompture-1.0.56.dev2/prompture/drivers/async_runway_img_gen_driver.py +137 -0
  9. prompture-1.0.56.dev2/prompture/drivers/async_runway_tts_driver.py +167 -0
  10. prompture-1.0.56.dev2/prompture/drivers/async_runway_video_gen_driver.py +132 -0
  11. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_img_gen_driver.py +42 -6
  12. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/provider_descriptors.py +29 -0
  13. prompture-1.0.56.dev2/prompture/drivers/runway_audio_transform_driver.py +251 -0
  14. prompture-1.0.56.dev2/prompture/drivers/runway_capabilities.py +190 -0
  15. prompture-1.0.56.dev2/prompture/drivers/runway_img_gen_driver.py +345 -0
  16. prompture-1.0.56.dev2/prompture/drivers/runway_tts_driver.py +225 -0
  17. prompture-1.0.56.dev2/prompture/drivers/runway_video_gen_driver.py +386 -0
  18. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/discovery.py +30 -0
  19. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/settings.py +4 -0
  20. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/PKG-INFO +79 -7
  21. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/SOURCES.txt +8 -0
  22. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-driver/SKILL.md +0 -0
  23. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-driver/references/driver-template.md +0 -0
  24. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-example/SKILL.md +0 -0
  25. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-field/SKILL.md +0 -0
  26. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-persona/SKILL.md +0 -0
  27. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-test/SKILL.md +0 -0
  28. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-tool/SKILL.md +0 -0
  29. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/create-pr/SKILL.md +0 -0
  30. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/run-tests/SKILL.md +0 -0
  31. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/scaffold-extraction/SKILL.md +0 -0
  32. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/update-pricing/SKILL.md +0 -0
  33. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/FUNDING.yml +0 -0
  34. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  35. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/pricing_cost_mismatch.yml +0 -0
  36. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/provider_driver_bug.yml +0 -0
  37. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/schema_extraction_failure.yml +0 -0
  38. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/scripts/update_docs_version.py +0 -0
  39. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/scripts/update_wrapper_version.py +0 -0
  40. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/dev.yml +0 -0
  41. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/documentation.yml +0 -0
  42. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/pricing-freshness.yml +0 -0
  43. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/publish.yml +0 -0
  44. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/security.yml +0 -0
  45. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.safety-project.ini +0 -0
  46. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/AGENTS.md +0 -0
  47. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/BREAKING_CHANGES.md +0 -0
  48. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/CONTRIBUTING.md +0 -0
  49. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/LICENSE +0 -0
  50. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/MANIFEST.in +0 -0
  51. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/ROADMAP.md +0 -0
  52. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/SECURITY.md +0 -0
  53. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/dev.ps1 +0 -0
  54. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/dev.sh +0 -0
  55. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/mypy_errors.txt +0 -0
  56. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/README.md +0 -0
  57. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/README.md +0 -0
  58. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/llm_to_json/__init__.py +0 -0
  59. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/pyproject.toml +0 -0
  60. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/test.py +0 -0
  61. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/README.md +0 -0
  62. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/llm_to_toon/__init__.py +0 -0
  63. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/pyproject.toml +0 -0
  64. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/test.py +0 -0
  65. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/__init__.py +0 -0
  66. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/__init__.py +0 -0
  67. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/agent.py +0 -0
  68. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/async_agent.py +0 -0
  69. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/async_conversation.py +0 -0
  70. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/conversation.py +0 -0
  71. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/persona.py +0 -0
  72. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/simulated_tools.py +0 -0
  73. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/skills.py +0 -0
  74. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/tools_schema.py +0 -0
  75. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/types.py +0 -0
  76. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/aio/__init__.py +0 -0
  77. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/bridges/__init__.py +0 -0
  78. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/bridges/tukuy_backend.py +0 -0
  79. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/__init__.py +0 -0
  80. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/cli.py +0 -0
  81. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/formatters.py +0 -0
  82. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/runner.py +0 -0
  83. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/server.py +0 -0
  84. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/airllm_driver.py +0 -0
  85. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_airllm_driver.py +0 -0
  86. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_azure_driver.py +0 -0
  87. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_base.py +0 -0
  88. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_cachibot_driver.py +0 -0
  89. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_claude_driver.py +0 -0
  90. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_elevenlabs_stt_driver.py +0 -0
  91. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_elevenlabs_tts_driver.py +0 -0
  92. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_embedding_base.py +0 -0
  93. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_google_driver.py +0 -0
  94. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_google_img_gen_driver.py +0 -0
  95. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_google_vertexai_driver.py +0 -0
  96. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_grok_driver.py +0 -0
  97. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_grok_img_gen_driver.py +0 -0
  98. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_grok_video_gen_driver.py +0 -0
  99. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_groq_driver.py +0 -0
  100. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_hugging_driver.py +0 -0
  101. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_img_gen_base.py +0 -0
  102. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_lmstudio_driver.py +0 -0
  103. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_local_http_driver.py +0 -0
  104. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_modelscope_driver.py +0 -0
  105. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_moonshot_driver.py +0 -0
  106. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_ollama_driver.py +0 -0
  107. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_ollama_embedding_driver.py +0 -0
  108. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_driver.py +0 -0
  109. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_embedding_driver.py +0 -0
  110. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_stt_driver.py +0 -0
  111. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_tts_driver.py +0 -0
  112. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openrouter_driver.py +0 -0
  113. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_registry.py +0 -0
  114. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_stability_img_gen_driver.py +0 -0
  115. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_stt_base.py +0 -0
  116. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_tts_base.py +0 -0
  117. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_video_gen_base.py +0 -0
  118. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_zai_driver.py +0 -0
  119. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/audio_registry.py +0 -0
  120. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/azure_config.py +0 -0
  121. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/azure_driver.py +0 -0
  122. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/base.py +0 -0
  123. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/cachibot_driver.py +0 -0
  124. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/claude_driver.py +0 -0
  125. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/driver_registry.py +0 -0
  126. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/elevenlabs_stt_driver.py +0 -0
  127. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/elevenlabs_tts_driver.py +0 -0
  128. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/embedding_base.py +0 -0
  129. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/embedding_registry.py +0 -0
  130. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/google_driver.py +0 -0
  131. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/google_img_gen_driver.py +0 -0
  132. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/google_vertexai_driver.py +0 -0
  133. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/grok_driver.py +0 -0
  134. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/grok_img_gen_driver.py +0 -0
  135. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/grok_video_gen_driver.py +0 -0
  136. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/groq_driver.py +0 -0
  137. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/hugging_driver.py +0 -0
  138. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/img_gen_base.py +0 -0
  139. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/img_gen_registry.py +0 -0
  140. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/lmstudio_driver.py +0 -0
  141. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/local_http_driver.py +0 -0
  142. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/modelscope_driver.py +0 -0
  143. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/moonshot_driver.py +0 -0
  144. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/ollama_driver.py +0 -0
  145. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/ollama_embedding_driver.py +0 -0
  146. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_driver.py +0 -0
  147. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_embedding_driver.py +0 -0
  148. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_stt_driver.py +0 -0
  149. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_tts_driver.py +0 -0
  150. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openrouter_driver.py +0 -0
  151. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/registry.py +0 -0
  152. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/stability_img_gen_driver.py +0 -0
  153. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/stt_base.py +0 -0
  154. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/tts_base.py +0 -0
  155. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/video_gen_base.py +0 -0
  156. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/video_gen_registry.py +0 -0
  157. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/vision_helpers.py +0 -0
  158. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/zai_driver.py +0 -0
  159. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/exceptions.py +0 -0
  160. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/__init__.py +0 -0
  161. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/async_core.py +0 -0
  162. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/core.py +0 -0
  163. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/fields.py +0 -0
  164. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/reasoning.py +0 -0
  165. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/strategy.py +0 -0
  166. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/tools.py +0 -0
  167. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/tukuy_bridge.py +0 -0
  168. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/validator.py +0 -0
  169. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/__init__.py +0 -0
  170. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/async_groups.py +0 -0
  171. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/consensus.py +0 -0
  172. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/debate.py +0 -0
  173. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/groups.py +0 -0
  174. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/types.py +0 -0
  175. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/__init__.py +0 -0
  176. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/budget.py +0 -0
  177. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/cache.py +0 -0
  178. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/callbacks.py +0 -0
  179. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/capabilities.py +0 -0
  180. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/cost_mixin.py +0 -0
  181. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/ledger.py +0 -0
  182. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/logging.py +0 -0
  183. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/model_rates.py +0 -0
  184. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/pricing.py +0 -0
  185. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/provider_env.py +0 -0
  186. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/anthropic.json +0 -0
  187. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/azure.json +0 -0
  188. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/google.json +0 -0
  189. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/google_vertexai.json +0 -0
  190. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/groq.json +0 -0
  191. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/moonshot.json +0 -0
  192. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/openai.json +0 -0
  193. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/openrouter.json +0 -0
  194. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/xai.json +0 -0
  195. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/session.py +0 -0
  196. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/tracker.py +0 -0
  197. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/tukuy_backend.py +0 -0
  198. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/__init__.py +0 -0
  199. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/chunking.py +0 -0
  200. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/detect.py +0 -0
  201. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/document.py +0 -0
  202. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/__init__.py +0 -0
  203. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/base.py +0 -0
  204. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/csv_parser.py +0 -0
  205. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/docx.py +0 -0
  206. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/html.py +0 -0
  207. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/markdown.py +0 -0
  208. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/pdf.py +0 -0
  209. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/xlsx.py +0 -0
  210. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/integrations/__init__.py +0 -0
  211. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/integrations/tukuy_bridge.py +0 -0
  212. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/__init__.py +0 -0
  213. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/audio.py +0 -0
  214. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/image.py +0 -0
  215. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/video.py +0 -0
  216. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/01-why-prompture.md +0 -0
  217. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/02-installation.md +0 -0
  218. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/03-quickstart.md +0 -0
  219. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/04-toon-input.md +0 -0
  220. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/05-test-harness.md +0 -0
  221. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/06-stability.md +0 -0
  222. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/07-migration.md +0 -0
  223. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/__init__.py +0 -0
  224. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/history.py +0 -0
  225. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/serialization.py +0 -0
  226. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/store.py +0 -0
  227. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/__init__.py +0 -0
  228. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/pipeline.py +0 -0
  229. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/resolver.py +0 -0
  230. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/routing.py +0 -0
  231. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/py.typed +0 -0
  232. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/__init__.py +0 -0
  233. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/generator.py +0 -0
  234. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/Dockerfile.j2 +0 -0
  235. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/README.md.j2 +0 -0
  236. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/config.py.j2 +0 -0
  237. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/env.example.j2 +0 -0
  238. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/main.py.j2 +0 -0
  239. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/models.py.j2 +0 -0
  240. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/requirements.txt.j2 +0 -0
  241. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/testing/__init__.py +0 -0
  242. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/testing/driver_contract.py +0 -0
  243. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/dependency_links.txt +0 -0
  244. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/entry_points.txt +0 -0
  245. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/requires.txt +0 -0
  246. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/top_level.txt +0 -0
  247. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture_cost_tracking.md +0 -0
  248. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/pyproject.toml +0 -0
  249. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/requirements.txt +0 -0
  250. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/scripts/check_pricing_freshness.py +0 -0
  251. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/setup.cfg +0 -0
  252. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/specs/basic_extraction.json +0 -0
  253. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/specs/schema_validation.json +0 -0
  254. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/specs/strategy_comparison.json +0 -0
  255. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/test.py +0 -0
  256. {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/test_version_diagnosis.py +0 -0
@@ -90,3 +90,7 @@ AIRLLM_COMPRESSION=
90
90
 
91
91
  # ─── Stability AI (image generation) ────────────────────────────────────────
92
92
  STABILITY_API_KEY=
93
+
94
+ # ─── Runway (image / video / audio) ─────────────────────────────────────────
95
+ # Either RUNWAY_API_KEY or RUNWAYML_API_SECRET is accepted.
96
+ RUNWAY_API_KEY=
@@ -61,15 +61,15 @@ Configuration is in `pyproject.toml` under `[tool.ruff]`.
61
61
  ### Module Layout
62
62
 
63
63
  - **`prompture/core.py`** — Primary business logic. All extraction functions live here: `ask_for_json()` (low-level schema enforcement), `extract_and_jsonify()` / `manual_extract_and_jsonify()` (text-to-JSON), `extract_with_model()` / `stepwise_extract_with_model()` (Pydantic-based), `extract_from_data()` / `extract_from_pandas()` (TOON input), `render_output()` (raw text formatting).
64
- - **`prompture/drivers/`** — One module per LLM provider (openai, claude, google, groq, grok, azure, ollama, lmstudio, openrouter, local_http, huggingface, airllm). Each driver implements `generate(prompt, options)` returning a standardized response with token/cost metadata.
64
+ - **`prompture/drivers/`** — One module per provider × modality. LLM drivers (openai, claude, google, groq, grok, azure, ollama, lmstudio, openrouter, local_http, huggingface, airllm, moonshot, modelscope, zai, cachibot, …) implement `generate(prompt, options)`; non-LLM drivers implement modality-specific methods (`generate_image`, `generate_video`, `synthesize`, etc.). Each provider also has an `async_*` sibling. Registration is centralized in `provider_descriptors.py` via `ProviderDescriptor` with lazy `DriverSpec.cls_path` resolution.
65
65
  - **`prompture/drivers/__init__.py`** — Central `DRIVER_REGISTRY` dict mapping provider name to factory lambda. `get_driver_for_model("provider/model")` parses the string and instantiates the right driver. `get_driver("provider")` is the legacy interface.
66
66
  - **`prompture/tools.py`** — Utilities: JSON/TOON text cleanup, type conversion (shorthand numbers, multilingual booleans, datetimes), field schema generation.
67
67
  - **`prompture/logging.py`** — Library logging configuration: `JSONFormatter` for structured JSON-lines output, `configure_logging()` for enabling library-level logging via Python stdlib `logging`.
68
68
  - **`prompture/callbacks.py`** — `DriverCallbacks` dataclass with `on_request`, `on_response`, `on_error` hooks for driver-level observability.
69
69
  - **`prompture/session.py`** — `UsageSession` dataclass for tracking token counts, costs, and errors across multiple driver calls.
70
70
  - **`prompture/field_definitions.py`** — Thread-safe global field registry with 50+ predefined fields, template variable substitution (`{{current_year}}`, `{{current_date}}`), and Pydantic Field generation via `field_from_registry()`.
71
- - **`prompture/settings.py`** — Pydantic-settings `Settings` class loading provider API keys/endpoints from `.env`.
72
- - **`prompture/discovery.py`** — `get_available_models()` auto-detects models from configured providers (static pricing tables + dynamic Ollama endpoint query).
71
+ - **`prompture/infra/settings.py`** — Pydantic-settings `Settings` class loading provider API keys/endpoints from `.env`.
72
+ - **`prompture/infra/discovery.py`** — `get_available_models()` plus per-modality helpers (`get_available_image_gen_models`, `get_available_video_gen_models`, `get_available_audio_models`). Auto-detects models from configured providers via static `*_PRICING` / `KNOWN_MODELS` tables, dynamic provider listing endpoints (Ollama, ElevenLabs), and models.dev capability fallback.
73
73
  - **`prompture/runner.py`** — Spec-driven test suite runner for cross-model comparison.
74
74
  - **`prompture/validator.py`** — JSON schema validation via jsonschema with fallback.
75
75
 
@@ -80,6 +80,21 @@ Configuration is in `pyproject.toml` under `[tool.ruff]`.
80
80
  - **Output formats**: JSON (default) and TOON (experimental, for compact output). Controlled via `output_format` parameter.
81
81
  - **TOON input conversion** uses `python-toon` and `tukuy` packages to reduce token usage by 45-60% when sending structured data to LLMs.
82
82
 
83
+ ### Multi-Modal Drivers
84
+
85
+ Beyond LLMs, drivers exist for adjacent modalities. Each modality has its own base class, registry, and factory:
86
+
87
+ - **Image generation** (`ImageGenDriver` / `img_gen_registry.get_img_gen_driver_for_model`) — OpenAI DALL-E + GPT image, Google Imagen, Grok, Stability AI, Runway.
88
+ - **Video generation** (`VideoGenDriver` / `video_gen_registry.get_video_gen_driver_for_model`) — Grok Imagine Video; Runway (text/image/video → video via a single driver, mode auto-detected from options).
89
+ - **TTS** (`TTSDriver` / `audio_registry.get_tts_driver_for_model`) — OpenAI, ElevenLabs, Runway (TTS + sound effects).
90
+ - **STT** (`STTDriver` / `audio_registry.get_stt_driver_for_model`) — OpenAI Whisper, ElevenLabs.
91
+ - **Embeddings** (`EmbeddingDriver`) — OpenAI, Ollama.
92
+ - **Standalone helpers** (not modality-registered) — `RunwayAudioTransformDriver` for voice dubbing / isolation / speech-to-speech; instantiated directly.
93
+
94
+ **Runway is the only provider spanning image + video + TTS + sound-effects + voice transforms under one API key** (`RUNWAY_API_KEY` or `RUNWAYML_API_SECRET`). Per-model capabilities live in `prompture/drivers/runway_capabilities.py` (`RUNWAY_MODEL_INFO`, `get_runway_model_info`, `get_runway_models_by_op`, `get_runway_models_by_modality`) — use this when you need to answer "which models support text_to_video?" without instantiating drivers.
95
+
96
+ Discovery for non-LLM modalities: `infra/discovery.py` exposes `get_available_image_gen_models`, `get_available_video_gen_models`, `get_available_audio_models(modality="tts" | "stt" | None)`.
97
+
83
98
  ### Testing
84
99
 
85
100
  Tests live in `tests/`. Integration tests that call live LLMs are marked with `@pytest.mark.integration` and skipped by default. The default test model is set in `tests/conftest.py` as `DEFAULT_MODEL`. Shared fixtures and assertion helpers (`assert_valid_usage_metadata`, `assert_jsonify_response_structure`) are in `conftest.py`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prompture
3
- Version: 1.0.56.dev1
3
+ Version: 1.0.56.dev2
4
4
  Summary: Ask LLMs to return structured JSON and run cross-model tests. API-first.
5
5
  Author-email: Juan Denis <juan@vene.co>
6
6
  License-Expression: MIT
@@ -95,8 +95,8 @@ print(person.name) # Maria
95
95
  ## Key Features
96
96
 
97
97
  - **Structured output** — JSON schema enforcement and direct Pydantic model population
98
- - **17+ providers** — OpenAI, Claude, Google, Groq, Grok, Azure, Ollama, LM Studio, OpenRouter, HuggingFace, Moonshot, ModelScope, Z.ai, Vertex AI, AirLLM, CachiBot, and generic HTTP
99
- - **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability), video generation (Grok Imagine Video), text-to-speech, and speech-to-text (Whisper, ElevenLabs)
98
+ - **18+ providers** — OpenAI, Claude, Google, Groq, Grok, Azure, Ollama, LM Studio, OpenRouter, HuggingFace, Moonshot, ModelScope, Z.ai, Vertex AI, AirLLM, CachiBot, Runway, and generic HTTP
99
+ - **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability, Runway), video generation (Grok Imagine Video, Runway text/image/video → video), text-to-speech (OpenAI, ElevenLabs, Runway), sound effects, voice dubbing / isolation / conversion (Runway), and speech-to-text (Whisper, ElevenLabs)
100
100
  - **Multi-model fallback** — Try a list of models in sequence with per-attempt cost, token, and capability accounting
101
101
  - **Strategy cascade** — Auto-selects between provider-native JSON mode, tool-call extraction, and prompted repair so extraction works on any model
102
102
  - **TOON input conversion** — 45-60% token savings when sending structured data via [Token-Oriented Object Notation](https://github.com/jhd3197/python-toon)
@@ -191,17 +191,20 @@ Model strings use `"provider/model"` format. The provider prefix routes to the c
191
191
  | `huggingface` | `hf/model-name` | Free (local) |
192
192
  | `airllm` | `airllm/Qwen2-7B` | Free (local) |
193
193
  | `local_http` | `local_http/self-hosted` | Free |
194
+ | `runway` | `runway/gen4.5` (video), `runway/gpt_image_2` (image), `runway/eleven_multilingual_v2` (TTS) | Automatic |
194
195
 
195
- Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`) route to their canonical providers.
196
+ Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`, `runwayml`) route to their canonical providers.
196
197
 
197
198
  ## Multi-Modal
198
199
 
199
200
  Beyond text LLMs, Prompture exposes drivers for adjacent modalities under the same `provider/model` routing:
200
201
 
201
202
  - **Embeddings** — OpenAI (`text-embedding-3-*`) and Ollama (`nomic-embed-text`)
202
- - **Image generation** — OpenAI DALL-E, Google Imagen, Grok, Stability AI
203
- - **Video generation** — Grok Imagine Video (`grok-imagine-video`) with text-to-video, image-to-video, reference images, and polling
204
- - **Text-to-speech** — OpenAI (`tts-1`) and ElevenLabs
203
+ - **Image generation** — OpenAI DALL-E + GPT image, Google Imagen, Grok, Stability AI, Runway (`gen4_image`, `gen4_image_turbo`, `gpt_image_2`, `gemini_image3_pro`, `gemini_2.5_flash`)
204
+ - **Video generation** — Grok Imagine Video; Runway text/image/video → video (`gen4.5`, `gen4_turbo`, `gen3a_turbo`, `gen4_aleph`, `veo3`, `veo3.1`, `veo3.1_fast`)
205
+ - **Text-to-speech** — OpenAI (`tts-1`), ElevenLabs, Runway (`eleven_multilingual_v2`)
206
+ - **Sound effects** — Runway (`eleven_text_to_sound_v2`)
207
+ - **Audio transforms** — Runway voice dubbing, voice isolation, speech-to-speech (`RunwayAudioTransformDriver`)
205
208
  - **Speech-to-text** — OpenAI Whisper and ElevenLabs
206
209
 
207
210
  ```python
@@ -235,6 +238,61 @@ For local smoke tests without waiting on the render, pass `{"poll": False}` to g
235
238
 
236
239
  Runnable example: `python examples/grok_video_generation_example.py`.
237
240
 
241
+ ### Runway
242
+
243
+ Runway is a single API surface covering image, video, and audio. One key (`RUNWAY_API_KEY`, or `RUNWAYML_API_SECRET`) unlocks all of it:
244
+
245
+ ```python
246
+ from prompture.drivers.img_gen_registry import get_img_gen_driver_for_model
247
+ from prompture.drivers.video_gen_registry import get_video_gen_driver_for_model
248
+ from prompture.drivers.audio_registry import get_tts_driver_for_model
249
+ from prompture.drivers import RunwayAudioTransformDriver
250
+
251
+ # Image — text_to_image, optionally with reference images
252
+ img = get_img_gen_driver_for_model("runway/gpt_image_2").generate_image(
253
+ "A cinematic wide shot of a neon-lit Tokyo alleyway at night in the rain",
254
+ {"ratio": "1920:1080", "quality": "high"},
255
+ )
256
+
257
+ # Video — one driver, three modes (auto-detected from inputs)
258
+ vid = get_video_gen_driver_for_model("runway/gen4.5").generate_video(
259
+ "wide cinematic shot of a rocket launching from desert dunes",
260
+ {"ratio": "1280:720", "duration": 5}, # text_to_video
261
+ )
262
+ # Pass `image=...` → image_to_video; `video=...` → video_to_video (gen4_aleph).
263
+
264
+ # Speech and sound effects
265
+ tts = get_tts_driver_for_model("runway/eleven_multilingual_v2").synthesize(
266
+ "Hello from Runway via Prompture.", {"voice": "Maya"},
267
+ )
268
+ sfx = get_tts_driver_for_model("runway/eleven_text_to_sound_v2").synthesize(
269
+ "Heavy tropical rain on a metal roof", {"duration": 5},
270
+ )
271
+
272
+ # Voice transforms (audio in → audio out, not a registered modality)
273
+ dub = RunwayAudioTransformDriver().dub("https://.../speech.mp3", target_lang="es")
274
+ ```
275
+
276
+ Inspect any model's capabilities (operations, endpoints, cost) as data — no need to instantiate the driver:
277
+
278
+ ```python
279
+ from prompture.drivers import get_runway_model_info, get_runway_models_by_op
280
+
281
+ get_runway_model_info("gen4.5")
282
+ # {'modality': 'video',
283
+ # 'operations': ['text_to_video', 'image_to_video'],
284
+ # 'endpoints': ['/v1/text_to_video', '/v1/image_to_video'],
285
+ # 'cost': '$0.12 per second'}
286
+
287
+ get_runway_models_by_op("text_to_video")
288
+ # ['gen4.5', 'veo3', 'veo3.1', 'veo3.1_fast']
289
+ ```
290
+
291
+ Runnable examples:
292
+ - `python examples/runway_image_generation_example.py`
293
+ - `python examples/runway_video_generation_example.py`
294
+ - `python examples/runway_audio_example.py`
295
+
238
296
  ## Usage
239
297
 
240
298
  ### One-Shot Pydantic Extraction
@@ -508,6 +566,20 @@ for model in models:
508
566
  print(model) # "openai/gpt-4", "ollama/llama3:latest", ...
509
567
  ```
510
568
 
569
+ For non-LLM modalities, use the matching helper:
570
+
571
+ ```python
572
+ from prompture.infra.discovery import (
573
+ get_available_image_gen_models,
574
+ get_available_video_gen_models,
575
+ get_available_audio_models,
576
+ )
577
+
578
+ get_available_image_gen_models() # ['runway/gpt_image_2', 'openai/dall-e-3', ...]
579
+ get_available_video_gen_models() # ['runway/gen4.5', 'runway/gen4_aleph', ...]
580
+ get_available_audio_models(modality="tts") # ['runway/eleven_multilingual_v2', ...]
581
+ ```
582
+
511
583
  ### Logging and Debugging
512
584
 
513
585
  ```python
@@ -31,8 +31,8 @@ print(person.name) # Maria
31
31
  ## Key Features
32
32
 
33
33
  - **Structured output** — JSON schema enforcement and direct Pydantic model population
34
- - **17+ providers** — OpenAI, Claude, Google, Groq, Grok, Azure, Ollama, LM Studio, OpenRouter, HuggingFace, Moonshot, ModelScope, Z.ai, Vertex AI, AirLLM, CachiBot, and generic HTTP
35
- - **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability), video generation (Grok Imagine Video), text-to-speech, and speech-to-text (Whisper, ElevenLabs)
34
+ - **18+ providers** — OpenAI, Claude, Google, Groq, Grok, Azure, Ollama, LM Studio, OpenRouter, HuggingFace, Moonshot, ModelScope, Z.ai, Vertex AI, AirLLM, CachiBot, Runway, and generic HTTP
35
+ - **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability, Runway), video generation (Grok Imagine Video, Runway text/image/video → video), text-to-speech (OpenAI, ElevenLabs, Runway), sound effects, voice dubbing / isolation / conversion (Runway), and speech-to-text (Whisper, ElevenLabs)
36
36
  - **Multi-model fallback** — Try a list of models in sequence with per-attempt cost, token, and capability accounting
37
37
  - **Strategy cascade** — Auto-selects between provider-native JSON mode, tool-call extraction, and prompted repair so extraction works on any model
38
38
  - **TOON input conversion** — 45-60% token savings when sending structured data via [Token-Oriented Object Notation](https://github.com/jhd3197/python-toon)
@@ -127,17 +127,20 @@ Model strings use `"provider/model"` format. The provider prefix routes to the c
127
127
  | `huggingface` | `hf/model-name` | Free (local) |
128
128
  | `airllm` | `airllm/Qwen2-7B` | Free (local) |
129
129
  | `local_http` | `local_http/self-hosted` | Free |
130
+ | `runway` | `runway/gen4.5` (video), `runway/gpt_image_2` (image), `runway/eleven_multilingual_v2` (TTS) | Automatic |
130
131
 
131
- Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`) route to their canonical providers.
132
+ Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`, `runwayml`) route to their canonical providers.
132
133
 
133
134
  ## Multi-Modal
134
135
 
135
136
  Beyond text LLMs, Prompture exposes drivers for adjacent modalities under the same `provider/model` routing:
136
137
 
137
138
  - **Embeddings** — OpenAI (`text-embedding-3-*`) and Ollama (`nomic-embed-text`)
138
- - **Image generation** — OpenAI DALL-E, Google Imagen, Grok, Stability AI
139
- - **Video generation** — Grok Imagine Video (`grok-imagine-video`) with text-to-video, image-to-video, reference images, and polling
140
- - **Text-to-speech** — OpenAI (`tts-1`) and ElevenLabs
139
+ - **Image generation** — OpenAI DALL-E + GPT image, Google Imagen, Grok, Stability AI, Runway (`gen4_image`, `gen4_image_turbo`, `gpt_image_2`, `gemini_image3_pro`, `gemini_2.5_flash`)
140
+ - **Video generation** — Grok Imagine Video; Runway text/image/video → video (`gen4.5`, `gen4_turbo`, `gen3a_turbo`, `gen4_aleph`, `veo3`, `veo3.1`, `veo3.1_fast`)
141
+ - **Text-to-speech** — OpenAI (`tts-1`), ElevenLabs, Runway (`eleven_multilingual_v2`)
142
+ - **Sound effects** — Runway (`eleven_text_to_sound_v2`)
143
+ - **Audio transforms** — Runway voice dubbing, voice isolation, speech-to-speech (`RunwayAudioTransformDriver`)
141
144
  - **Speech-to-text** — OpenAI Whisper and ElevenLabs
142
145
 
143
146
  ```python
@@ -171,6 +174,61 @@ For local smoke tests without waiting on the render, pass `{"poll": False}` to g
171
174
 
172
175
  Runnable example: `python examples/grok_video_generation_example.py`.
173
176
 
177
+ ### Runway
178
+
179
+ Runway is a single API surface covering image, video, and audio. One key (`RUNWAY_API_KEY`, or `RUNWAYML_API_SECRET`) unlocks all of it:
180
+
181
+ ```python
182
+ from prompture.drivers.img_gen_registry import get_img_gen_driver_for_model
183
+ from prompture.drivers.video_gen_registry import get_video_gen_driver_for_model
184
+ from prompture.drivers.audio_registry import get_tts_driver_for_model
185
+ from prompture.drivers import RunwayAudioTransformDriver
186
+
187
+ # Image — text_to_image, optionally with reference images
188
+ img = get_img_gen_driver_for_model("runway/gpt_image_2").generate_image(
189
+ "A cinematic wide shot of a neon-lit Tokyo alleyway at night in the rain",
190
+ {"ratio": "1920:1080", "quality": "high"},
191
+ )
192
+
193
+ # Video — one driver, three modes (auto-detected from inputs)
194
+ vid = get_video_gen_driver_for_model("runway/gen4.5").generate_video(
195
+ "wide cinematic shot of a rocket launching from desert dunes",
196
+ {"ratio": "1280:720", "duration": 5}, # text_to_video
197
+ )
198
+ # Pass `image=...` → image_to_video; `video=...` → video_to_video (gen4_aleph).
199
+
200
+ # Speech and sound effects
201
+ tts = get_tts_driver_for_model("runway/eleven_multilingual_v2").synthesize(
202
+ "Hello from Runway via Prompture.", {"voice": "Maya"},
203
+ )
204
+ sfx = get_tts_driver_for_model("runway/eleven_text_to_sound_v2").synthesize(
205
+ "Heavy tropical rain on a metal roof", {"duration": 5},
206
+ )
207
+
208
+ # Voice transforms (audio in → audio out, not a registered modality)
209
+ dub = RunwayAudioTransformDriver().dub("https://.../speech.mp3", target_lang="es")
210
+ ```
211
+
212
+ Inspect any model's capabilities (operations, endpoints, cost) as data — no need to instantiate the driver:
213
+
214
+ ```python
215
+ from prompture.drivers import get_runway_model_info, get_runway_models_by_op
216
+
217
+ get_runway_model_info("gen4.5")
218
+ # {'modality': 'video',
219
+ # 'operations': ['text_to_video', 'image_to_video'],
220
+ # 'endpoints': ['/v1/text_to_video', '/v1/image_to_video'],
221
+ # 'cost': '$0.12 per second'}
222
+
223
+ get_runway_models_by_op("text_to_video")
224
+ # ['gen4.5', 'veo3', 'veo3.1', 'veo3.1_fast']
225
+ ```
226
+
227
+ Runnable examples:
228
+ - `python examples/runway_image_generation_example.py`
229
+ - `python examples/runway_video_generation_example.py`
230
+ - `python examples/runway_audio_example.py`
231
+
174
232
  ## Usage
175
233
 
176
234
  ### One-Shot Pydantic Extraction
@@ -444,6 +502,20 @@ for model in models:
444
502
  print(model) # "openai/gpt-4", "ollama/llama3:latest", ...
445
503
  ```
446
504
 
505
+ For non-LLM modalities, use the matching helper:
506
+
507
+ ```python
508
+ from prompture.infra.discovery import (
509
+ get_available_image_gen_models,
510
+ get_available_video_gen_models,
511
+ get_available_audio_models,
512
+ )
513
+
514
+ get_available_image_gen_models() # ['runway/gpt_image_2', 'openai/dall-e-3', ...]
515
+ get_available_video_gen_models() # ['runway/gen4.5', 'runway/gen4_aleph', ...]
516
+ get_available_audio_models(modality="tts") # ['runway/eleven_multilingual_v2', ...]
517
+ ```
518
+
447
519
  ### Logging and Debugging
448
520
 
449
521
  ```python
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.0.56.dev1'
22
- __version_tuple__ = version_tuple = (1, 0, 56, 'dev1')
21
+ __version__ = version = '1.0.56.dev2'
22
+ __version_tuple__ = version_tuple = (1, 0, 56, 'dev2')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -57,6 +57,9 @@ from .async_openai_img_gen_driver import AsyncOpenAIImageGenDriver
57
57
  from .async_openai_stt_driver import AsyncOpenAISTTDriver
58
58
  from .async_openai_tts_driver import AsyncOpenAITTSDriver
59
59
  from .async_openrouter_driver import AsyncOpenRouterDriver
60
+ from .async_runway_img_gen_driver import AsyncRunwayImageGenDriver
61
+ from .async_runway_tts_driver import AsyncRunwayTTSDriver
62
+ from .async_runway_video_gen_driver import AsyncRunwayVideoGenDriver
60
63
  from .async_stability_img_gen_driver import AsyncStabilityImageGenDriver
61
64
  from .async_stt_base import AsyncSTTDriver
62
65
  from .async_tts_base import AsyncTTSDriver
@@ -164,6 +167,22 @@ from .registry import (
164
167
  unregister_tts_driver,
165
168
  unregister_video_gen_driver,
166
169
  )
170
+ from .runway_audio_transform_driver import RunwayAudioTransformDriver
171
+ from .runway_capabilities import (
172
+ ALL_MODALITIES as RUNWAY_ALL_MODALITIES,
173
+ )
174
+ from .runway_capabilities import (
175
+ ALL_OPERATIONS as RUNWAY_ALL_OPERATIONS,
176
+ )
177
+ from .runway_capabilities import (
178
+ RUNWAY_MODEL_INFO,
179
+ get_runway_model_info,
180
+ get_runway_models_by_modality,
181
+ get_runway_models_by_op,
182
+ )
183
+ from .runway_img_gen_driver import RunwayImageGenDriver
184
+ from .runway_tts_driver import RunwayTTSDriver
185
+ from .runway_video_gen_driver import RunwayVideoGenDriver
167
186
  from .stability_img_gen_driver import StabilityImageGenDriver
168
187
  from .stt_base import STTDriver
169
188
  from .tts_base import TTSDriver
@@ -448,6 +467,9 @@ __all__ = [
448
467
  "PROVIDER_DRIVER_MAP",
449
468
  # Provider name mapping
450
469
  "PROVIDER_NAME_MAP",
470
+ "RUNWAY_ALL_MODALITIES",
471
+ "RUNWAY_ALL_OPERATIONS",
472
+ "RUNWAY_MODEL_INFO",
451
473
  # Sync LLM drivers
452
474
  "AirLLMDriver",
453
475
  # Async LLM drivers
@@ -483,6 +505,9 @@ __all__ = [
483
505
  "AsyncOpenAISTTDriver",
484
506
  "AsyncOpenAITTSDriver",
485
507
  "AsyncOpenRouterDriver",
508
+ "AsyncRunwayImageGenDriver",
509
+ "AsyncRunwayTTSDriver",
510
+ "AsyncRunwayVideoGenDriver",
486
511
  "AsyncSTTDriver",
487
512
  "AsyncStabilityImageGenDriver",
488
513
  "AsyncTTSDriver",
@@ -519,6 +544,10 @@ __all__ = [
519
544
  "OpenAISTTDriver",
520
545
  "OpenAITTSDriver",
521
546
  "OpenRouterDriver",
547
+ "RunwayAudioTransformDriver",
548
+ "RunwayImageGenDriver",
549
+ "RunwayTTSDriver",
550
+ "RunwayVideoGenDriver",
522
551
  # STT/TTS base classes
523
552
  "STTDriver",
524
553
  "StabilityImageGenDriver",
@@ -554,6 +583,9 @@ __all__ = [
554
583
  "get_embedding_driver_for_model",
555
584
  "get_img_gen_driver_factory",
556
585
  "get_img_gen_driver_for_model",
586
+ "get_runway_model_info",
587
+ "get_runway_models_by_modality",
588
+ "get_runway_models_by_op",
557
589
  "get_stt_driver_factory",
558
590
  "get_stt_driver_for_model",
559
591
  "get_tts_driver_factory",
@@ -48,15 +48,18 @@ class AsyncOpenAIImageGenDriver(ImageCostMixin, AsyncImageGenDriver):
48
48
  raise RuntimeError("openai package (>=1.0.0) is not installed")
49
49
 
50
50
  model = options.get("model", self.model)
51
+ is_gpt_image = model.startswith("gpt-image")
52
+ is_dalle3 = "dall-e-3" in model
53
+
51
54
  size = options.get("size", "1024x1024")
52
- quality = options.get("quality", "standard")
55
+ default_quality = "high" if is_gpt_image else "standard"
56
+ quality = options.get("quality", default_quality)
53
57
  n = options.get("n", 1)
54
58
  style = options.get("style", "vivid")
55
59
 
56
60
  images = []
57
61
  revised_prompt = None
58
62
 
59
- is_dalle3 = "dall-e-3" in model
60
63
  batch_size = 1 if is_dalle3 else n
61
64
 
62
65
  remaining = n
@@ -68,11 +71,14 @@ class AsyncOpenAIImageGenDriver(ImageCostMixin, AsyncImageGenDriver):
68
71
  "prompt": prompt,
69
72
  "n": batch_n,
70
73
  "size": size,
71
- "response_format": "b64_json",
72
74
  }
73
- if is_dalle3:
75
+ if is_gpt_image:
74
76
  kwargs["quality"] = quality
75
- kwargs["style"] = style
77
+ else:
78
+ kwargs["response_format"] = "b64_json"
79
+ if is_dalle3:
80
+ kwargs["quality"] = quality
81
+ kwargs["style"] = style
76
82
 
77
83
  resp = await self.client.images.generate(**kwargs)
78
84
 
@@ -0,0 +1,137 @@
1
+ """Async Runway image generation driver. Mirrors :mod:`runway_img_gen_driver`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import logging
7
+ import os
8
+ import time
9
+ from typing import Any
10
+
11
+ import httpx
12
+
13
+ from ..infra.cost_mixin import ImageCostMixin
14
+ from .async_img_gen_base import AsyncImageGenDriver
15
+ from .runway_img_gen_driver import (
16
+ _API_VERSION,
17
+ _DEFAULT_ENDPOINT,
18
+ _TERMINAL_FAIL,
19
+ _TERMINAL_OK,
20
+ RunwayImageGenDriver,
21
+ _format_error,
22
+ _get_runway_api_key,
23
+ )
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ class AsyncRunwayImageGenDriver(ImageCostMixin, AsyncImageGenDriver):
29
+ """Async image generation via Runway ``POST /v1/text_to_image``."""
30
+
31
+ supports_multiple = RunwayImageGenDriver.supports_multiple
32
+ supports_size_variants = RunwayImageGenDriver.supports_size_variants
33
+ supported_sizes = RunwayImageGenDriver.supported_sizes
34
+ max_images = RunwayImageGenDriver.max_images
35
+
36
+ KNOWN_MODELS = RunwayImageGenDriver.KNOWN_MODELS
37
+ IMAGE_PRICING = RunwayImageGenDriver.IMAGE_PRICING
38
+
39
+ def __init__(
40
+ self,
41
+ api_key: str | None = None,
42
+ model: str = "gen4_image",
43
+ endpoint: str | None = None,
44
+ ):
45
+ self.api_key = _get_runway_api_key(api_key)
46
+ self.model = model
47
+ self.endpoint = (
48
+ endpoint or os.getenv("RUNWAY_ENDPOINT") or _DEFAULT_ENDPOINT
49
+ ).rstrip("/")
50
+
51
+ @classmethod
52
+ def list_models(cls, *, api_key: str | None = None, **kw: object) -> list[str] | None:
53
+ key = _get_runway_api_key(api_key)
54
+ if not key:
55
+ return None
56
+ return list(cls.KNOWN_MODELS)
57
+
58
+ def _headers(self) -> dict[str, str]:
59
+ return {
60
+ "Authorization": f"Bearer {self.api_key}",
61
+ "X-Runway-Version": _API_VERSION,
62
+ "Content-Type": "application/json",
63
+ "Accept": "application/json",
64
+ }
65
+
66
+ async def generate_image(self, prompt: str, options: dict[str, Any]) -> dict[str, Any]:
67
+ if not self.api_key:
68
+ raise RuntimeError(
69
+ "RUNWAY_API_KEY (or RUNWAYML_API_SECRET) is not configured"
70
+ )
71
+
72
+ # Reuse the sync driver's body-building logic to avoid duplication.
73
+ builder = RunwayImageGenDriver.__new__(RunwayImageGenDriver)
74
+ builder.model = self.model
75
+ model, body = builder._build_body(prompt, options)
76
+ headers = self._headers()
77
+
78
+ async with httpx.AsyncClient(timeout=120.0) as client:
79
+ resp = await client.post(
80
+ f"{self.endpoint}/v1/text_to_image", headers=headers, json=body
81
+ )
82
+ if resp.status_code >= 400:
83
+ raise RuntimeError(
84
+ f"Runway text_to_image failed: {_format_error(resp.status_code, resp)}"
85
+ )
86
+ task = resp.json()
87
+ task_id = task.get("id")
88
+ if not task_id:
89
+ raise RuntimeError(f"Runway response missing task id: {task}")
90
+
91
+ if not options.get("poll", True):
92
+ return RunwayImageGenDriver._pending_response(
93
+ builder, task_id, model, body, task
94
+ )
95
+
96
+ final = await self._poll_until_done(
97
+ client,
98
+ task_id,
99
+ headers=headers,
100
+ poll_interval=float(options.get("poll_interval", 5)),
101
+ timeout_seconds=float(options.get("timeout", 600)),
102
+ )
103
+
104
+ return RunwayImageGenDriver._build_success_response(
105
+ builder, final, model, body, options
106
+ )
107
+
108
+ async def _poll_until_done(
109
+ self,
110
+ client: httpx.AsyncClient,
111
+ task_id: str,
112
+ *,
113
+ headers: dict[str, str],
114
+ poll_interval: float,
115
+ timeout_seconds: float,
116
+ ) -> dict[str, Any]:
117
+ deadline = time.monotonic() + timeout_seconds
118
+ while True:
119
+ r = await client.get(
120
+ f"{self.endpoint}/v1/tasks/{task_id}", headers=headers
121
+ )
122
+ if r.status_code >= 400:
123
+ raise RuntimeError(
124
+ f"Runway task poll failed: {_format_error(r.status_code, r)}"
125
+ )
126
+ data = r.json()
127
+ status = data.get("status")
128
+ if status in _TERMINAL_OK:
129
+ return data
130
+ if status in _TERMINAL_FAIL:
131
+ failure = data.get("failure") or data.get("failureCode") or status
132
+ raise RuntimeError(f"Runway task {task_id} {status}: {failure}")
133
+ if time.monotonic() >= deadline:
134
+ raise TimeoutError(
135
+ f"Runway task {task_id} timed out (status={status})"
136
+ )
137
+ await asyncio.sleep(poll_interval)