prompture 1.9.1.dev1__tar.gz → 1.9.1.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 (505) hide show
  1. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/PKG-INFO +1 -1
  2. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/_version.py +2 -2
  3. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/agent.py +17 -6
  4. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/assistant.py +15 -3
  5. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/async_agent.py +45 -7
  6. prompture-1.9.1.dev2/prompture/drivers/_media_usage.py +118 -0
  7. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/aggregator_base.py +60 -8
  8. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_aggregator_base.py +60 -8
  9. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_base.py +6 -1
  10. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_cohere_embedding_driver.py +1 -1
  11. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_embedding_base.py +6 -0
  12. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_img_gen_base.py +6 -0
  13. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_jina_embedding_driver.py +1 -1
  14. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_mxbai_embedding_driver.py +1 -1
  15. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_nomic_embedding_driver.py +1 -1
  16. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openai_embedding_driver.py +1 -1
  17. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_video_gen_base.py +6 -0
  18. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_voyage_embedding_driver.py +1 -1
  19. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/base.py +5 -1
  20. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/cohere_embedding_driver.py +1 -1
  21. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/embedding_base.py +6 -0
  22. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/img_gen_base.py +6 -0
  23. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/jina_embedding_driver.py +1 -1
  24. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/lipsync_base.py +44 -0
  25. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/music_base.py +41 -0
  26. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/mxbai_embedding_driver.py +1 -1
  27. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/nomic_embedding_driver.py +1 -1
  28. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openai_embedding_driver.py +1 -1
  29. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/video_gen_base.py +6 -0
  30. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/voyage_embedding_driver.py +1 -1
  31. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/__init__.py +4 -1
  32. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/cost_mixin.py +5 -2
  33. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/tracker.py +63 -2
  34. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/jobs.py +8 -1
  35. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/semantic.py +2 -1
  36. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/base.py +25 -2
  37. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/chroma.py +3 -3
  38. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/faiss.py +3 -3
  39. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/pgvector.py +3 -3
  40. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/pinecone.py +3 -3
  41. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/qdrant.py +3 -3
  42. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/weaviate.py +3 -3
  43. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/nodes.py +16 -2
  44. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture.egg-info/PKG-INFO +1 -1
  45. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture.egg-info/SOURCES.txt +1 -0
  46. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/add-driver/SKILL.md +0 -0
  47. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/add-driver/references/driver-template.md +0 -0
  48. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/add-example/SKILL.md +0 -0
  49. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/add-field/SKILL.md +0 -0
  50. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/add-persona/SKILL.md +0 -0
  51. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/add-test/SKILL.md +0 -0
  52. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/add-tool/SKILL.md +0 -0
  53. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/create-pr/SKILL.md +0 -0
  54. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/run-tests/SKILL.md +0 -0
  55. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/scaffold-extraction/SKILL.md +0 -0
  56. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.claude/skills/update-pricing/SKILL.md +0 -0
  57. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.env.copy +0 -0
  58. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/FUNDING.yml +0 -0
  59. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  60. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/ISSUE_TEMPLATE/pricing_cost_mismatch.yml +0 -0
  61. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/ISSUE_TEMPLATE/provider_driver_bug.yml +0 -0
  62. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/ISSUE_TEMPLATE/schema_extraction_failure.yml +0 -0
  63. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/scripts/update_docs_version.py +0 -0
  64. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/scripts/update_wrapper_version.py +0 -0
  65. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/workflows/dev.yml +0 -0
  66. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/workflows/documentation.yml +0 -0
  67. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/workflows/pricing-freshness.yml +0 -0
  68. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/workflows/publish.yml +0 -0
  69. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.github/workflows/security.yml +0 -0
  70. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/.safety-project.ini +0 -0
  71. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/AGENTS.md +0 -0
  72. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/BREAKING_CHANGES.md +0 -0
  73. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/CLAUDE.md +0 -0
  74. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/CONTRIBUTING.md +0 -0
  75. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/LICENSE +0 -0
  76. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/MANIFEST.in +0 -0
  77. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/README.md +0 -0
  78. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/ROADMAP.md +0 -0
  79. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/SECURITY.md +0 -0
  80. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/VERSION +0 -0
  81. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/dev.ps1 +0 -0
  82. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/dev.sh +0 -0
  83. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/mypy_errors.txt +0 -0
  84. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/README.md +0 -0
  85. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_json/README.md +0 -0
  86. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_json/llm_to_json/__init__.py +0 -0
  87. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_json/pyproject.toml +0 -0
  88. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_json/test.py +0 -0
  89. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_toon/README.md +0 -0
  90. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_toon/llm_to_toon/__init__.py +0 -0
  91. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_toon/pyproject.toml +0 -0
  92. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/packages/llm_to_toon/test.py +0 -0
  93. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/__init__.py +0 -0
  94. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/_internal/__init__.py +0 -0
  95. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/_internal/json_encoder.py +0 -0
  96. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/__init__.py +0 -0
  97. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/async_conversation.py +0 -0
  98. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/async_deep_agent.py +0 -0
  99. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/conversation.py +0 -0
  100. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep/__init__.py +0 -0
  101. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep/planner.py +0 -0
  102. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep/subagents.py +0 -0
  103. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep/summarizer.py +0 -0
  104. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep/vfs.py +0 -0
  105. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep_agent.py +0 -0
  106. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep_prompts.py +0 -0
  107. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/deep_state.py +0 -0
  108. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/live_events.py +0 -0
  109. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/persona.py +0 -0
  110. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/review_loop.py +0 -0
  111. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/simulated_tools.py +0 -0
  112. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/skill_miner.py +0 -0
  113. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/skills.py +0 -0
  114. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/tool_grammars.py +0 -0
  115. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/tools_schema.py +0 -0
  116. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/agents/types.py +0 -0
  117. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/aio/__init__.py +0 -0
  118. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/bridges/__init__.py +0 -0
  119. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/bridges/tukuy_backend.py +0 -0
  120. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/checkpoints/__init__.py +0 -0
  121. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/checkpoints/core.py +0 -0
  122. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/checkpoints/stores.py +0 -0
  123. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/checkpoints/types.py +0 -0
  124. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/citations/__init__.py +0 -0
  125. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/citations/core.py +0 -0
  126. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/citations/types.py +0 -0
  127. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/cli/__init__.py +0 -0
  128. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/cli/cli.py +0 -0
  129. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/cli/formatters.py +0 -0
  130. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/cli/runner.py +0 -0
  131. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/cli/server.py +0 -0
  132. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/__init__.py +0 -0
  133. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/dedup.py +0 -0
  134. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/evol.py +0 -0
  135. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/filters.py +0 -0
  136. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/formats.py +0 -0
  137. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/schemas.py +0 -0
  138. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/seed.py +0 -0
  139. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/dataset/synth.py +0 -0
  140. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/__init__.py +0 -0
  141. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/_openai_compat.py +0 -0
  142. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/_openai_compat_stream.py +0 -0
  143. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/_prompt_cache.py +0 -0
  144. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/_prompted_tool_stream.py +0 -0
  145. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/airllm_driver.py +0 -0
  146. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/assemblyai_stt_driver.py +0 -0
  147. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_airllm_driver.py +0 -0
  148. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_assemblyai_stt_driver.py +0 -0
  149. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_azure_driver.py +0 -0
  150. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_bedrock_driver.py +0 -0
  151. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_bfl_img_gen_driver.py +0 -0
  152. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_cachibot_driver.py +0 -0
  153. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_cartesia_tts_driver.py +0 -0
  154. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_claude_driver.py +0 -0
  155. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_cohere_driver.py +0 -0
  156. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_cohere_rerank_driver.py +0 -0
  157. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_deepgram_stt_driver.py +0 -0
  158. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_deepgram_tts_driver.py +0 -0
  159. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_deepseek_driver.py +0 -0
  160. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_elevenlabs_stt_driver.py +0 -0
  161. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_elevenlabs_tts_driver.py +0 -0
  162. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_fal_img_gen_driver.py +0 -0
  163. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_fal_video_gen_driver.py +0 -0
  164. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_google_driver.py +0 -0
  165. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_google_img_gen_driver.py +0 -0
  166. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_google_vertexai_driver.py +0 -0
  167. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_grok_driver.py +0 -0
  168. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_grok_img_gen_driver.py +0 -0
  169. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_grok_video_gen_driver.py +0 -0
  170. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_groq_driver.py +0 -0
  171. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_hugging_driver.py +0 -0
  172. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_ideogram_img_gen_driver.py +0 -0
  173. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_jina_rerank_driver.py +0 -0
  174. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_kling_img_gen_driver.py +0 -0
  175. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_kling_video_gen_driver.py +0 -0
  176. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_lmstudio_driver.py +0 -0
  177. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_local_http_driver.py +0 -0
  178. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_luma_video_gen_driver.py +0 -0
  179. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_minimax_driver.py +0 -0
  180. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_minimax_video_gen_driver.py +0 -0
  181. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_mistral_driver.py +0 -0
  182. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_mistral_moderation_driver.py +0 -0
  183. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_modelscope_driver.py +0 -0
  184. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_moonshot_driver.py +0 -0
  185. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_muapi_aggregator_driver.py +0 -0
  186. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_mxbai_rerank_driver.py +0 -0
  187. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_ollama_driver.py +0 -0
  188. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_ollama_embedding_driver.py +0 -0
  189. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openai_compatible_driver.py +0 -0
  190. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openai_driver.py +0 -0
  191. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openai_img_gen_driver.py +0 -0
  192. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openai_moderation_driver.py +0 -0
  193. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openai_stt_driver.py +0 -0
  194. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openai_tts_driver.py +0 -0
  195. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_openrouter_driver.py +0 -0
  196. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_pika_video_gen_driver.py +0 -0
  197. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_registry.py +0 -0
  198. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_runway_img_gen_driver.py +0 -0
  199. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_runway_tts_driver.py +0 -0
  200. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_runway_video_gen_driver.py +0 -0
  201. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_stability_img_gen_driver.py +0 -0
  202. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_stt_base.py +0 -0
  203. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_tts_base.py +0 -0
  204. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_voyage_rerank_driver.py +0 -0
  205. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/async_zai_driver.py +0 -0
  206. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/audio_registry.py +0 -0
  207. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/azure_config.py +0 -0
  208. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/azure_driver.py +0 -0
  209. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/bedrock_driver.py +0 -0
  210. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/bfl_img_gen_driver.py +0 -0
  211. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/cachibot_driver.py +0 -0
  212. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/cartesia_tts_driver.py +0 -0
  213. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/claude_driver.py +0 -0
  214. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/cohere_driver.py +0 -0
  215. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/cohere_rerank_driver.py +0 -0
  216. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/deepgram_stt_driver.py +0 -0
  217. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/deepgram_tts_driver.py +0 -0
  218. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/deepseek_driver.py +0 -0
  219. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/driver_registry.py +0 -0
  220. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/elevenlabs_stt_driver.py +0 -0
  221. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/elevenlabs_tts_driver.py +0 -0
  222. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/embedding_registry.py +0 -0
  223. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/fal_img_gen_driver.py +0 -0
  224. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/fal_video_gen_driver.py +0 -0
  225. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/google_driver.py +0 -0
  226. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/google_img_gen_driver.py +0 -0
  227. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/google_vertexai_driver.py +0 -0
  228. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/grok_driver.py +0 -0
  229. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/grok_img_gen_driver.py +0 -0
  230. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/grok_video_gen_driver.py +0 -0
  231. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/groq_driver.py +0 -0
  232. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/hugging_driver.py +0 -0
  233. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/ideogram_img_gen_driver.py +0 -0
  234. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/img_gen_registry.py +0 -0
  235. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/jina_rerank_driver.py +0 -0
  236. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/job_runner.py +0 -0
  237. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/kling_img_gen_driver.py +0 -0
  238. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/kling_video_gen_driver.py +0 -0
  239. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/lipsync_registry.py +0 -0
  240. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/lmstudio_driver.py +0 -0
  241. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/local_http_driver.py +0 -0
  242. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/luma_video_gen_driver.py +0 -0
  243. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/media_capabilities.py +0 -0
  244. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/minimax_driver.py +0 -0
  245. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/minimax_video_gen_driver.py +0 -0
  246. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/mistral_driver.py +0 -0
  247. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/mistral_moderation_driver.py +0 -0
  248. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/modelscope_driver.py +0 -0
  249. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/moderation_base.py +0 -0
  250. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/moderation_registry.py +0 -0
  251. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/moonshot_driver.py +0 -0
  252. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/muapi_aggregator_driver.py +0 -0
  253. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/music_registry.py +0 -0
  254. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/mxbai_rerank_driver.py +0 -0
  255. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/ollama_driver.py +0 -0
  256. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/ollama_embedding_driver.py +0 -0
  257. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openai_compatible_driver.py +0 -0
  258. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openai_driver.py +0 -0
  259. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openai_img_gen_driver.py +0 -0
  260. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openai_moderation_driver.py +0 -0
  261. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openai_stt_driver.py +0 -0
  262. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openai_tts_driver.py +0 -0
  263. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/openrouter_driver.py +0 -0
  264. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/pika_video_gen_driver.py +0 -0
  265. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/provider_branding.py +0 -0
  266. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/provider_descriptors.py +0 -0
  267. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/registry.py +0 -0
  268. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/rerank_base.py +0 -0
  269. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/rerank_registry.py +0 -0
  270. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/runway_audio_transform_driver.py +0 -0
  271. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/runway_capabilities.py +0 -0
  272. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/runway_img_gen_driver.py +0 -0
  273. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/runway_tts_driver.py +0 -0
  274. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/runway_video_gen_driver.py +0 -0
  275. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/stability_img_gen_driver.py +0 -0
  276. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/stt_base.py +0 -0
  277. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/tts_base.py +0 -0
  278. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/vertex_img_gen_driver.py +0 -0
  279. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/video_gen_registry.py +0 -0
  280. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/vision_helpers.py +0 -0
  281. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/voyage_rerank_driver.py +0 -0
  282. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/drivers/zai_driver.py +0 -0
  283. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/eval/__init__.py +0 -0
  284. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/eval/base.py +0 -0
  285. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/eval/faithfulness.py +0 -0
  286. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/eval/judge.py +0 -0
  287. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/eval/pairwise.py +0 -0
  288. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/eval/self_consistency.py +0 -0
  289. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/exceptions.py +0 -0
  290. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/__init__.py +0 -0
  291. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/async_core.py +0 -0
  292. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/code_extraction.py +0 -0
  293. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/core.py +0 -0
  294. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/few_shot.py +0 -0
  295. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/fields.py +0 -0
  296. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/reasoning.py +0 -0
  297. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/strategy.py +0 -0
  298. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/streaming.py +0 -0
  299. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/tools.py +0 -0
  300. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/tukuy_bridge.py +0 -0
  301. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/extraction/validator.py +0 -0
  302. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/groups/__init__.py +0 -0
  303. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/groups/async_groups.py +0 -0
  304. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/groups/consensus.py +0 -0
  305. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/groups/debate.py +0 -0
  306. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/groups/groups.py +0 -0
  307. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/groups/types.py +0 -0
  308. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/imaging/__init__.py +0 -0
  309. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/imaging/enhance.py +0 -0
  310. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/imaging/negative.py +0 -0
  311. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/imaging/set_planner.py +0 -0
  312. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/imaging/style_presets.py +0 -0
  313. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/budget.py +0 -0
  314. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/cache.py +0 -0
  315. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/callbacks.py +0 -0
  316. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/capabilities.py +0 -0
  317. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/coding_agent_events.py +0 -0
  318. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/coding_agent_specs.py +0 -0
  319. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/coding_agents.py +0 -0
  320. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/discovery.py +0 -0
  321. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/ledger.py +0 -0
  322. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/logging.py +0 -0
  323. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/media_pricing.py +0 -0
  324. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/media_rates.json +0 -0
  325. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/model_rates.py +0 -0
  326. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/pricing.py +0 -0
  327. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/provider_env.py +0 -0
  328. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/anthropic.json +0 -0
  329. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/azure.json +0 -0
  330. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/bedrock.json +0 -0
  331. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/cerebras.json +0 -0
  332. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/cohere.json +0 -0
  333. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/deepinfra.json +0 -0
  334. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/deepseek.json +0 -0
  335. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/fireworks.json +0 -0
  336. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/google.json +0 -0
  337. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/google_vertexai.json +0 -0
  338. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/groq.json +0 -0
  339. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/jina.json +0 -0
  340. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/mistral.json +0 -0
  341. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/mixedbread.json +0 -0
  342. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/moonshot.json +0 -0
  343. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/nomic.json +0 -0
  344. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/nvidia.json +0 -0
  345. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/openai.json +0 -0
  346. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/openrouter.json +0 -0
  347. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/perplexity.json +0 -0
  348. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/sambanova.json +0 -0
  349. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/siliconflow.json +0 -0
  350. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/together.json +0 -0
  351. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/voyage.json +0 -0
  352. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/rates/xai.json +0 -0
  353. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/session.py +0 -0
  354. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/settings.py +0 -0
  355. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/infra/tukuy_backend.py +0 -0
  356. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/__init__.py +0 -0
  357. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/chunking.py +0 -0
  358. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/detect.py +0 -0
  359. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/document.py +0 -0
  360. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/__init__.py +0 -0
  361. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/base.py +0 -0
  362. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/csv_parser.py +0 -0
  363. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/docx.py +0 -0
  364. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/html.py +0 -0
  365. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/markdown.py +0 -0
  366. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/pdf.py +0 -0
  367. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/ingestion/parsers/xlsx.py +0 -0
  368. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/integrations/__init__.py +0 -0
  369. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/integrations/mcp_bridge.py +0 -0
  370. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/integrations/tukuy_bridge.py +0 -0
  371. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/kg/__init__.py +0 -0
  372. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/kg/core.py +0 -0
  373. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/kg/stores.py +0 -0
  374. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/kg/types.py +0 -0
  375. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/mcp/__init__.py +0 -0
  376. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/mcp/client.py +0 -0
  377. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/mcp/server.py +0 -0
  378. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/mcp/tools.py +0 -0
  379. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/media/__init__.py +0 -0
  380. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/media/agent_tools.py +0 -0
  381. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/media/audio.py +0 -0
  382. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/media/hosting.py +0 -0
  383. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/media/image.py +0 -0
  384. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/media/video.py +0 -0
  385. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pages/01-why-prompture.md +0 -0
  386. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pages/02-installation.md +0 -0
  387. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pages/03-quickstart.md +0 -0
  388. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pages/04-toon-input.md +0 -0
  389. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pages/05-test-harness.md +0 -0
  390. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pages/06-stability.md +0 -0
  391. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pages/07-migration.md +0 -0
  392. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/persistence/__init__.py +0 -0
  393. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/persistence/history.py +0 -0
  394. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/persistence/serialization.py +0 -0
  395. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/persistence/store.py +0 -0
  396. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pipeline/__init__.py +0 -0
  397. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pipeline/pipeline.py +0 -0
  398. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pipeline/resolver.py +0 -0
  399. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/pipeline/routing.py +0 -0
  400. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/__init__.py +0 -0
  401. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/base.py +0 -0
  402. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/__init__.py +0 -0
  403. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/_aliases.py +0 -0
  404. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/anthropic_plugin.py +0 -0
  405. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/audio_plugin.py +0 -0
  406. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/cloud_plugin.py +0 -0
  407. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/embedding_rerank_plugin.py +0 -0
  408. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/extras_plugin.py +0 -0
  409. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/google_plugin.py +0 -0
  410. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/image_plugin.py +0 -0
  411. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/local_plugin.py +0 -0
  412. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/openai_compatible_plugin.py +0 -0
  413. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/openai_plugin.py +0 -0
  414. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/builtins/video_plugin.py +0 -0
  415. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/plugins/discovery.py +0 -0
  416. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/py.typed +0 -0
  417. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/__init__.py +0 -0
  418. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/__init__.py +0 -0
  419. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/base.py +0 -0
  420. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/character.py +0 -0
  421. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/chunker_registry.py +0 -0
  422. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/contextual.py +0 -0
  423. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/markdown.py +0 -0
  424. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/recursive.py +0 -0
  425. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/chunkers/token.py +0 -0
  426. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/documents.py +0 -0
  427. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loader_registry.py +0 -0
  428. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/__init__.py +0 -0
  429. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/csv_loader.py +0 -0
  430. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/docx_loader.py +0 -0
  431. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/epub_loader.py +0 -0
  432. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/html_loader.py +0 -0
  433. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/json_loader.py +0 -0
  434. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/markdown_loader.py +0 -0
  435. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/pdf_loader.py +0 -0
  436. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/text_loader.py +0 -0
  437. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/loaders/xlsx_loader.py +0 -0
  438. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/pipeline.py +0 -0
  439. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/__init__.py +0 -0
  440. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/_fusion.py +0 -0
  441. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/base.py +0 -0
  442. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/hybrid.py +0 -0
  443. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/hyde.py +0 -0
  444. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/mmr.py +0 -0
  445. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/multi_query.py +0 -0
  446. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/retriever_registry.py +0 -0
  447. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/similarity.py +0 -0
  448. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/retrievers/step_back.py +0 -0
  449. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/__init__.py +0 -0
  450. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/rag/vectorstores/vectorstore_registry.py +0 -0
  451. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/refusal/__init__.py +0 -0
  452. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/refusal/detector.py +0 -0
  453. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/refusal/evaluator.py +0 -0
  454. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/refusal/markers.py +0 -0
  455. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/__init__.py +0 -0
  456. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/generator.py +0 -0
  457. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/templates/Dockerfile.j2 +0 -0
  458. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/templates/README.md.j2 +0 -0
  459. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/templates/config.py.j2 +0 -0
  460. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/templates/env.example.j2 +0 -0
  461. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/templates/main.py.j2 +0 -0
  462. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/templates/models.py.j2 +0 -0
  463. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/scaffold/templates/requirements.txt.j2 +0 -0
  464. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/security/__init__.py +0 -0
  465. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/security/injection.py +0 -0
  466. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/security/redaction.py +0 -0
  467. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/session_memory/__init__.py +0 -0
  468. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/session_memory/core.py +0 -0
  469. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/session_memory/stores.py +0 -0
  470. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/session_memory/types.py +0 -0
  471. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/swarm/__init__.py +0 -0
  472. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/swarm/environment.py +0 -0
  473. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/swarm/memory.py +0 -0
  474. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/swarm/scheduler.py +0 -0
  475. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/swarm/swarm.py +0 -0
  476. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/swarm/swarm_agent.py +0 -0
  477. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/swarm/types.py +0 -0
  478. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/testing/__init__.py +0 -0
  479. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/testing/driver_contract.py +0 -0
  480. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/tools/__init__.py +0 -0
  481. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/tools/code_exec.py +0 -0
  482. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/tools/web_search.py +0 -0
  483. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/__init__.py +0 -0
  484. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/architect.py +0 -0
  485. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/engine.py +0 -0
  486. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/errors.py +0 -0
  487. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/model.py +0 -0
  488. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/references.py +0 -0
  489. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/registry.py +0 -0
  490. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/scheduler.py +0 -0
  491. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture/workflow/state.py +0 -0
  492. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture.egg-info/dependency_links.txt +0 -0
  493. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture.egg-info/entry_points.txt +0 -0
  494. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture.egg-info/requires.txt +0 -0
  495. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture.egg-info/top_level.txt +0 -0
  496. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/prompture_cost_tracking.md +0 -0
  497. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/pyproject.toml +0 -0
  498. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/requirements.txt +0 -0
  499. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/scripts/check_pricing_freshness.py +0 -0
  500. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/setup.cfg +0 -0
  501. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/specs/basic_extraction.json +0 -0
  502. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/specs/schema_validation.json +0 -0
  503. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/specs/strategy_comparison.json +0 -0
  504. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/test.py +0 -0
  505. {prompture-1.9.1.dev1 → prompture-1.9.1.dev2}/test_version_diagnosis.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prompture
3
- Version: 1.9.1.dev1
3
+ Version: 1.9.1.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
@@ -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.9.1.dev1'
22
- __version_tuple__ = version_tuple = (1, 9, 1, 'dev1')
21
+ __version__ = version = '1.9.1.dev2'
22
+ __version_tuple__ = version_tuple = (1, 9, 1, 'dev2')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -133,7 +133,9 @@ def _get_first_param_name(fn: Callable[..., Any]) -> str:
133
133
  return ""
134
134
 
135
135
 
136
- def _parse_simulated_tool_call(content: str) -> tuple[str, dict[str, Any]] | None:
136
+ def _parse_simulated_tool_call(
137
+ content: str, known_tools: Any | None = None
138
+ ) -> tuple[str, dict[str, Any]] | None:
137
139
  """Recognise a prompted (simulated) tool call recorded as assistant text.
138
140
 
139
141
  Drivers without ``supports_tool_use`` go through
@@ -154,10 +156,17 @@ def _parse_simulated_tool_call(content: str) -> tuple[str, dict[str, Any]] | Non
154
156
  return None
155
157
  if not isinstance(obj, dict):
156
158
  return None
157
- # Explicit discriminator, or the inferred shape parse_simulated_response
158
- # also accepts when the model omits "type".
159
- if obj.get("type") != "tool_call" and not ("name" in obj and "arguments" in obj):
160
- return None
159
+ if obj.get("type") != "tool_call":
160
+ # Inferred shape (no discriminator), which parse_simulated_response
161
+ # also accepts when the model omits "type".
162
+ if not ("name" in obj and "arguments" in obj):
163
+ return None
164
+ # A structured ANSWER can legitimately carry name+arguments keys (a
165
+ # schema echo, a function description). When the caller can tell us
166
+ # which tools exist, only reclassify when the name matches one —
167
+ # otherwise the model's final output would silently vanish.
168
+ if known_tools is not None and obj.get("name") not in known_tools:
169
+ return None
161
170
  name = obj.get("name")
162
171
  args = obj.get("arguments", {})
163
172
  if not isinstance(name, str) or not name or not isinstance(args, dict):
@@ -1176,7 +1185,9 @@ class Agent(Generic[DepsType]):
1176
1185
  )
1177
1186
  all_tool_calls.append({"name": name, "arguments": args, "id": tc.get("id", "")})
1178
1187
  else:
1179
- simulated = _parse_simulated_tool_call(content)
1188
+ simulated = _parse_simulated_tool_call(
1189
+ content, known_tools=(self._tools.names if self._tools else None)
1190
+ )
1180
1191
  if simulated is not None:
1181
1192
  # Prompted tool call: same step shape as the native path
1182
1193
  # so a host sees one run, not two dialects.
@@ -384,13 +384,25 @@ class Assistant:
384
384
  ) -> AssistantResult:
385
385
  agent = self._build_async_agent(call_vars=call_vars)
386
386
  result: AgentResult = await agent.run(prompt, deps=deps)
387
+ # AgentResult.usage is a DICT (prompt_tokens/completion_tokens/cost) —
388
+ # getattr on a dict returns the default, so the attribute-style reads
389
+ # left cost_usd/input_tokens/output_tokens permanently None on the LLM
390
+ # backend and every host that trusted them recorded $0.00 forever.
387
391
  usage = getattr(result, "usage", None)
392
+ if isinstance(usage, dict):
393
+ cost_usd = usage.get("cost")
394
+ input_tokens = usage.get("prompt_tokens")
395
+ output_tokens = usage.get("completion_tokens")
396
+ else:
397
+ cost_usd = getattr(usage, "total_cost_usd", None) if usage else None
398
+ input_tokens = getattr(usage, "input_tokens", None) if usage else None
399
+ output_tokens = getattr(usage, "output_tokens", None) if usage else None
388
400
  return AssistantResult(
389
401
  output=getattr(result, "output", "") or "",
390
402
  backend="llm",
391
- cost_usd=getattr(usage, "total_cost_usd", None) if usage else None,
392
- input_tokens=getattr(usage, "input_tokens", None) if usage else None,
393
- output_tokens=getattr(usage, "output_tokens", None) if usage else None,
403
+ cost_usd=cost_usd,
404
+ input_tokens=input_tokens,
405
+ output_tokens=output_tokens,
394
406
  session_id=None,
395
407
  raw=result,
396
408
  )
@@ -56,7 +56,7 @@ _DEFAULT_MAX_AGENT_DEPTH = 5
56
56
 
57
57
  # Share the same ContextVar with the sync Agent so depth tracking crosses
58
58
  # agent boundaries (e.g. a sync Agent calling an AsyncAgent as a tool).
59
- from .agent import _agent_depth
59
+ from .agent import _agent_depth, _parse_simulated_tool_call
60
60
 
61
61
  # ------------------------------------------------------------------
62
62
  # Helpers
@@ -1150,8 +1150,15 @@ class AsyncAgent(Generic[DepsType]):
1150
1150
  for rec in tool_timings or []:
1151
1151
  timings_by_name.setdefault(rec.get("name", ""), []).append(rec)
1152
1152
 
1153
+ # Name of a simulated tool call awaiting its result, which the prompted
1154
+ # loop records as the next user message rather than a "tool" message.
1155
+ pending_sim_tool: str | None = None
1156
+
1153
1157
  for msg in messages:
1154
1158
  role = msg.get("role", "")
1159
+ # Claim (and clear) any simulated call left by the previous message.
1160
+ sim_tool = pending_sim_tool
1161
+ pending_sim_tool = None
1155
1162
  # Extract usage from message meta if present
1156
1163
  msg_meta = msg.get("meta")
1157
1164
  step_usage = None
@@ -1204,14 +1211,45 @@ class AsyncAgent(Generic[DepsType]):
1204
1211
  )
1205
1212
  all_tool_calls.append({"name": name, "arguments": args, "id": tc.get("id", "")})
1206
1213
  else:
1207
- steps.append(
1208
- AgentStep(
1209
- step_type=StepType.output,
1210
- timestamp=now,
1211
- content=content,
1212
- usage=step_usage,
1214
+ simulated = _parse_simulated_tool_call(
1215
+ content, known_tools=(self._tools.names if self._tools else None)
1216
+ )
1217
+ if simulated is not None:
1218
+ # Prompted tool call: same step shape as the native path
1219
+ # so a host sees one run, not two dialects.
1220
+ sim_name, sim_args = simulated
1221
+ steps.append(
1222
+ AgentStep(
1223
+ step_type=StepType.tool_call,
1224
+ timestamp=now,
1225
+ content="",
1226
+ tool_name=sim_name,
1227
+ tool_args=sim_args,
1228
+ usage=step_usage,
1229
+ )
1213
1230
  )
1231
+ all_tool_calls.append({"name": sim_name, "arguments": sim_args, "id": ""})
1232
+ pending_sim_tool = sim_name
1233
+ else:
1234
+ steps.append(
1235
+ AgentStep(
1236
+ step_type=StepType.output,
1237
+ timestamp=now,
1238
+ content=content,
1239
+ usage=step_usage,
1240
+ )
1241
+ )
1242
+
1243
+ elif role == "user" and sim_tool is not None:
1244
+ # The prompted loop stores a tool result as a user message.
1245
+ steps.append(
1246
+ AgentStep(
1247
+ step_type=StepType.tool_result,
1248
+ timestamp=now,
1249
+ content=msg.get("content", "") or "",
1250
+ tool_name=sim_tool,
1214
1251
  )
1252
+ )
1215
1253
 
1216
1254
  elif role == "tool":
1217
1255
  tool_call_id = msg.get("tool_call_id")
@@ -0,0 +1,118 @@
1
+ """Shared usage recording for media driver hook wrappers.
2
+
3
+ Media calls bill per image / second / job rather than per token, so the text
4
+ drivers' ``_auto_record_usage`` doesn't fit — but the spend is just as real,
5
+ and until this helper existed it never reached the usage tracker: media cost
6
+ lived only on the immediate response ``meta`` and vanished unless the caller
7
+ kept it. Every media ``*_with_hooks`` wrapper now records one
8
+ :class:`~prompture.infra.tracker.UsageEvent` (zero tokens, ``cost`` from meta,
9
+ unit count in ``metadata``) through the same global tracker as text calls, so
10
+ sinks and the SQLite ledger see the whole picture.
11
+
12
+ Fire-and-forget, mirroring the text bases: recording must never break the
13
+ generation it measures.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Any
19
+
20
+
21
+ def record_embedding_driver_usage(
22
+ driver: Any,
23
+ meta: dict[str, Any] | None,
24
+ elapsed_ms: float,
25
+ *,
26
+ text_count: int,
27
+ status: str = "success",
28
+ error: Exception | None = None,
29
+ ) -> None:
30
+ """Record one embedding call as a usage event. Never raises.
31
+
32
+ Embeddings are input-only, so the token count lands on both
33
+ ``prompt_tokens`` and ``total_tokens``.
34
+ """
35
+ try:
36
+ from ..infra.ledger import _resolve_api_key_hash
37
+ from ..infra.tracker import UsageEvent, get_tracker
38
+
39
+ tracker = get_tracker()
40
+ if not tracker._enabled:
41
+ return
42
+
43
+ meta = meta or {}
44
+ driver_name = str(meta.get("model_name") or getattr(driver, "model", driver.__class__.__name__))
45
+
46
+ if "/" in driver_name:
47
+ provider, model = driver_name.split("/", 1)
48
+ else:
49
+ cls_name = driver.__class__.__name__.removeprefix("Async")
50
+ provider = cls_name.removesuffix("Driver").lower()
51
+ model = driver_name
52
+
53
+ model_name = f"{provider}/{model}" if provider else model
54
+ tokens = int(meta.get("total_tokens") or 0)
55
+
56
+ event = UsageEvent(
57
+ model_name=model_name,
58
+ provider=provider,
59
+ api_key_hash=_resolve_api_key_hash(model_name),
60
+ prompt_tokens=tokens,
61
+ total_tokens=tokens,
62
+ cost=float(meta.get("cost") or 0.0),
63
+ elapsed_ms=elapsed_ms,
64
+ status=status,
65
+ error_type=type(error).__name__ if error else None,
66
+ metadata={"modality": "embedding", "count": text_count},
67
+ )
68
+ tracker.record(event)
69
+ except Exception:
70
+ pass # fire-and-forget
71
+
72
+
73
+ def record_media_usage(
74
+ driver: Any,
75
+ meta: dict[str, Any] | None,
76
+ elapsed_ms: float,
77
+ *,
78
+ modality: str,
79
+ count_key: str,
80
+ status: str = "success",
81
+ error: Exception | None = None,
82
+ ) -> None:
83
+ """Record one media generation as a usage event. Never raises."""
84
+ try:
85
+ from ..infra.ledger import _resolve_api_key_hash
86
+ from ..infra.tracker import UsageEvent, get_tracker
87
+
88
+ tracker = get_tracker()
89
+ if not tracker._enabled:
90
+ return
91
+
92
+ meta = meta or {}
93
+ driver_name = str(meta.get("model_name") or getattr(driver, "model", driver.__class__.__name__))
94
+
95
+ if "/" in driver_name:
96
+ provider, model = driver_name.split("/", 1)
97
+ else:
98
+ # Same class-name fallback as the text bases, Async prefix stripped
99
+ # so async twins attribute to the same provider.
100
+ cls_name = driver.__class__.__name__.removeprefix("Async")
101
+ provider = cls_name.removesuffix("Driver").lower()
102
+ model = driver_name
103
+
104
+ model_name = f"{provider}/{model}" if provider else model
105
+
106
+ event = UsageEvent(
107
+ model_name=model_name,
108
+ provider=provider,
109
+ api_key_hash=_resolve_api_key_hash(model_name),
110
+ cost=float(meta.get("cost") or 0.0),
111
+ elapsed_ms=elapsed_ms,
112
+ status=status,
113
+ error_type=type(error).__name__ if error else None,
114
+ metadata={"modality": modality, "count": int(meta.get(count_key) or 0)},
115
+ )
116
+ tracker.record(event)
117
+ except Exception:
118
+ pass # fire-and-forget
@@ -194,7 +194,12 @@ class AggregatorClient:
194
194
  return file_url
195
195
 
196
196
  # ── Job handle / resume ──
197
- def _make_handle(self, slug: str, request_id: str, modality: str) -> JobHandle:
197
+ def _make_handle(
198
+ self, slug: str, request_id: str, modality: str, *, pricing: dict[str, Any] | None = None
199
+ ) -> JobHandle:
200
+ # `pricing` captures the quote inputs (n / duration / resolution) at
201
+ # submit time, so a resume from another process can still price the
202
+ # job — the provider result carries none of them.
198
203
  return JobHandle(
199
204
  task_id=request_id,
200
205
  provider=self.PROVIDER,
@@ -204,6 +209,7 @@ class AggregatorClient:
204
209
  endpoint=self.endpoint,
205
210
  polling_url=self.result_url(request_id),
206
211
  submitted_at=time.time(),
212
+ extra={"pricing": pricing} if pricing else {},
207
213
  )
208
214
 
209
215
  def get_job_status(self, handle: JobHandle) -> str:
@@ -229,11 +235,23 @@ class AggregatorClient:
229
235
  MediaAsset(kind=kind, url=u, model=handle.model, provenance={"request_id": handle.task_id})
230
236
  for u in self.extract_urls(raw)
231
237
  ]
238
+ meta: dict[str, Any] = {"request_id": handle.task_id, "model_name": f"{self.PROVIDER}/{handle.model}"}
239
+ if status == JobStatus.COMPLETED.value:
240
+ # Price from the quote inputs captured at submit time (handle.extra)
241
+ # — without this, every async job reported zero cost at every
242
+ # stage of its lifecycle.
243
+ pricing = (handle.extra or {}).get("pricing") or {}
244
+ meta["cost"] = self._media_cost(
245
+ handle.model,
246
+ n=int(pricing.get("n") or max(len(assets), 1)),
247
+ duration_seconds=float(pricing.get("duration_seconds") or 0.0),
248
+ resolution=pricing.get("resolution"),
249
+ )
232
250
  return JobResult(
233
251
  handle=handle.with_status(status),
234
252
  status=status,
235
253
  assets=assets,
236
- meta={"request_id": handle.task_id, "model_name": f"{self.PROVIDER}/{handle.model}"},
254
+ meta=meta,
237
255
  raw=raw,
238
256
  )
239
257
 
@@ -250,6 +268,32 @@ class AggregatorClient:
250
268
  resolution=resolution,
251
269
  )
252
270
 
271
+ def _effective_duration(self, slug: str, options: dict[str, Any]) -> float:
272
+ """The duration the provider will actually bill for.
273
+
274
+ An explicit ``duration`` option wins; otherwise the model's declared
275
+ capability default — the provider runs its default clip length and
276
+ bills for it whether or not the caller passed the option, so pricing
277
+ with 0 was quoting $0 for real spend.
278
+ """
279
+ raw = options.get("duration")
280
+ if raw:
281
+ try:
282
+ return float(raw)
283
+ except (TypeError, ValueError):
284
+ pass
285
+ try:
286
+ from .media_capabilities import get_model_schema
287
+
288
+ info = get_model_schema(f"{self.PROVIDER}/{slug}")
289
+ spec = (info.inputs or {}).get("duration") if info else None
290
+ default = getattr(spec, "default", None)
291
+ if default:
292
+ return float(default)
293
+ except Exception:
294
+ pass
295
+ return 0.0
296
+
253
297
  # ── Media input resolution (for conditioned ops: i2i / i2v / lipsync) ──
254
298
  def _coerce_media_url(self, source: Any, *, explicit: str | None = None, filename: str = "input.bin") -> str | None:
255
299
  """Resolve a media input to a hosted URL.
@@ -321,7 +365,9 @@ class AggregatorImageDriver(AggregatorClient, ImageGenDriver):
321
365
  def _pending_image(
322
366
  self, slug: str, request_id: str, submitted: dict[str, Any], options: dict[str, Any]
323
367
  ) -> dict[str, Any]:
324
- handle = self._make_handle(slug, request_id, "image")
368
+ handle = self._make_handle(
369
+ slug, request_id, "image", pricing={"n": int(options.get("n") or 1)}
370
+ )
325
371
  return {
326
372
  "images": [],
327
373
  "meta": {
@@ -399,9 +445,13 @@ class AggregatorVideoDriver(AggregatorClient, VideoGenDriver):
399
445
  slug = options.get("model", self.model)
400
446
  payload = self.build_video_payload(prompt, options)
401
447
  request_id, submitted = self._submit(slug, payload)
448
+ duration = self._effective_duration(slug, options)
402
449
 
403
450
  if request_id is not None and not options.get("poll", True):
404
- handle = self._make_handle(slug, request_id, "video")
451
+ handle = self._make_handle(
452
+ slug, request_id, "video",
453
+ pricing={"n": 1, "duration_seconds": duration, "resolution": options.get("resolution")},
454
+ )
405
455
  return {
406
456
  "videos": [],
407
457
  "meta": {
@@ -428,7 +478,6 @@ class AggregatorVideoDriver(AggregatorClient, VideoGenDriver):
428
478
  )
429
479
  )
430
480
  videos = [video_from_url(u) for u in self.extract_urls(result)]
431
- duration = float(options.get("duration", 0) or 0)
432
481
  cost = self._media_cost(slug, n=1, duration_seconds=duration, resolution=options.get("resolution"))
433
482
  return {
434
483
  "videos": videos,
@@ -509,8 +558,12 @@ class AggregatorLipsyncDriver(AggregatorClient, LipsyncDriver):
509
558
  payload = self.build_lipsync_payload(options, audio_url=audio_url, image_url=image_url, video_url=video_url)
510
559
 
511
560
  request_id, submitted = self._submit(slug, payload)
561
+ duration = self._effective_duration(slug, options)
512
562
  if request_id is not None and not options.get("poll", True):
513
- handle = self._make_handle(slug, request_id, "lipsync")
563
+ handle = self._make_handle(
564
+ slug, request_id, "lipsync",
565
+ pricing={"n": 1, "duration_seconds": duration},
566
+ )
514
567
  return {
515
568
  "videos": [],
516
569
  "meta": {
@@ -535,7 +588,6 @@ class AggregatorLipsyncDriver(AggregatorClient, LipsyncDriver):
535
588
  )
536
589
  )
537
590
  videos = [video_from_url(u) for u in self.extract_urls(result)]
538
- duration = float(options.get("duration", 0) or 0)
539
591
  cost = self._media_cost(slug, n=1, duration_seconds=duration)
540
592
  return {
541
593
  "videos": videos,
@@ -604,7 +656,7 @@ class AggregatorMusicDriver(AggregatorClient, MusicGenDriver):
604
656
  request_id, submitted = self._submit(slug, payload)
605
657
 
606
658
  if request_id is not None and not options.get("poll", True):
607
- handle = self._make_handle(slug, request_id, "music")
659
+ handle = self._make_handle(slug, request_id, "music", pricing={"n": 1})
608
660
  return {
609
661
  "audio": [],
610
662
  "meta": {
@@ -149,7 +149,12 @@ class AsyncAggregatorClient:
149
149
  raise RuntimeError(f"{self.PROVIDER} upload returned no URL: {dj}")
150
150
  return file_url
151
151
 
152
- def _make_handle(self, slug: str, request_id: str, modality: str) -> JobHandle:
152
+ def _make_handle(
153
+ self, slug: str, request_id: str, modality: str, *, pricing: dict[str, Any] | None = None
154
+ ) -> JobHandle:
155
+ # `pricing` captures the quote inputs (n / duration / resolution) at
156
+ # submit time, so a resume from another process can still price the
157
+ # job — the provider result carries none of them.
153
158
  return JobHandle(
154
159
  task_id=request_id,
155
160
  provider=self.PROVIDER,
@@ -159,6 +164,7 @@ class AsyncAggregatorClient:
159
164
  endpoint=self.endpoint,
160
165
  polling_url=self.result_url(request_id),
161
166
  submitted_at=time.time(),
167
+ extra={"pricing": pricing} if pricing else {},
162
168
  )
163
169
 
164
170
  async def get_job_status(self, handle: JobHandle) -> str:
@@ -187,11 +193,23 @@ class AsyncAggregatorClient:
187
193
  MediaAsset(kind=kind, url=u, model=handle.model, provenance={"request_id": handle.task_id})
188
194
  for u in self.extract_urls(raw)
189
195
  ]
196
+ meta: dict[str, Any] = {"request_id": handle.task_id, "model_name": f"{self.PROVIDER}/{handle.model}"}
197
+ if status == JobStatus.COMPLETED.value:
198
+ # Price from the quote inputs captured at submit time (handle.extra)
199
+ # — without this, every async job reported zero cost at every
200
+ # stage of its lifecycle.
201
+ pricing = (handle.extra or {}).get("pricing") or {}
202
+ meta["cost"] = self._media_cost(
203
+ handle.model,
204
+ n=int(pricing.get("n") or max(len(assets), 1)),
205
+ duration_seconds=float(pricing.get("duration_seconds") or 0.0),
206
+ resolution=pricing.get("resolution"),
207
+ )
190
208
  return JobResult(
191
209
  handle=handle.with_status(status),
192
210
  status=status,
193
211
  assets=assets,
194
- meta={"request_id": handle.task_id, "model_name": f"{self.PROVIDER}/{handle.model}"},
212
+ meta=meta,
195
213
  raw=raw,
196
214
  )
197
215
 
@@ -202,6 +220,32 @@ class AsyncAggregatorClient:
202
220
 
203
221
  return estimate_media_cost(f"{self.PROVIDER}/{slug}", n=n, duration_seconds=duration_seconds, resolution=resolution)
204
222
 
223
+ def _effective_duration(self, slug: str, options: dict[str, Any]) -> float:
224
+ """The duration the provider will actually bill for.
225
+
226
+ An explicit ``duration`` option wins; otherwise the model's declared
227
+ capability default — the provider runs its default clip length and
228
+ bills for it whether or not the caller passed the option, so pricing
229
+ with 0 was quoting $0 for real spend.
230
+ """
231
+ raw = options.get("duration")
232
+ if raw:
233
+ try:
234
+ return float(raw)
235
+ except (TypeError, ValueError):
236
+ pass
237
+ try:
238
+ from .media_capabilities import get_model_schema
239
+
240
+ info = get_model_schema(f"{self.PROVIDER}/{slug}")
241
+ spec = (info.inputs or {}).get("duration") if info else None
242
+ default = getattr(spec, "default", None)
243
+ if default:
244
+ return float(default)
245
+ except Exception:
246
+ pass
247
+ return 0.0
248
+
205
249
  async def _coerce_media_url(
206
250
  self, source: Any, *, explicit: str | None = None, filename: str = "input.bin"
207
251
  ) -> str | None:
@@ -268,7 +312,9 @@ class AsyncAggregatorImageDriver(AsyncAggregatorClient, AsyncImageGenDriver):
268
312
  if request_id is None:
269
313
  return self._finalize_image(slug, None, submitted, options)
270
314
  if not options.get("poll", True):
271
- handle = self._make_handle(slug, request_id, "image")
315
+ handle = self._make_handle(
316
+ slug, request_id, "image", pricing={"n": int(options.get("n") or 1)}
317
+ )
272
318
  return {
273
319
  "images": [],
274
320
  "meta": {
@@ -335,10 +381,14 @@ class AsyncAggregatorVideoDriver(AsyncAggregatorClient, AsyncVideoGenDriver):
335
381
  self._require_key()
336
382
  slug = options.get("model", self.model)
337
383
  payload = self.build_video_payload(prompt, options)
384
+ duration = self._effective_duration(slug, options)
338
385
  async with httpx.AsyncClient(timeout=120.0) as client:
339
386
  request_id, submitted = await self._submit(client, slug, payload)
340
387
  if request_id is not None and not options.get("poll", True):
341
- handle = self._make_handle(slug, request_id, "video")
388
+ handle = self._make_handle(
389
+ slug, request_id, "video",
390
+ pricing={"n": 1, "duration_seconds": duration, "resolution": options.get("resolution")},
391
+ )
342
392
  return {
343
393
  "videos": [],
344
394
  "meta": {
@@ -365,7 +415,6 @@ class AsyncAggregatorVideoDriver(AsyncAggregatorClient, AsyncVideoGenDriver):
365
415
  )
366
416
  )
367
417
  videos = [video_from_url(u) for u in self.extract_urls(result)]
368
- duration = float(options.get("duration", 0) or 0)
369
418
  cost = self._media_cost(slug, n=1, duration_seconds=duration, resolution=options.get("resolution"))
370
419
  return {
371
420
  "videos": videos,
@@ -441,10 +490,14 @@ class AsyncAggregatorLipsyncDriver(AsyncAggregatorClient, AsyncLipsyncDriver):
441
490
  category = "video" if video_url else "image"
442
491
  payload = self.build_lipsync_payload(options, audio_url=audio_url, image_url=image_url, video_url=video_url)
443
492
 
493
+ duration = self._effective_duration(slug, options)
444
494
  async with httpx.AsyncClient(timeout=120.0) as client:
445
495
  request_id, submitted = await self._submit(client, slug, payload)
446
496
  if request_id is not None and not options.get("poll", True):
447
- handle = self._make_handle(slug, request_id, "lipsync")
497
+ handle = self._make_handle(
498
+ slug, request_id, "lipsync",
499
+ pricing={"n": 1, "duration_seconds": duration},
500
+ )
448
501
  return {
449
502
  "videos": [],
450
503
  "meta": {
@@ -469,7 +522,6 @@ class AsyncAggregatorLipsyncDriver(AsyncAggregatorClient, AsyncLipsyncDriver):
469
522
  )
470
523
  )
471
524
  videos = [video_from_url(u) for u in self.extract_urls(result)]
472
- duration = float(options.get("duration", 0) or 0)
473
525
  cost = self._media_cost(slug, n=1, duration_seconds=duration)
474
526
  return {
475
527
  "videos": videos,
@@ -534,7 +586,7 @@ class AsyncAggregatorMusicDriver(AsyncAggregatorClient, AsyncMusicGenDriver):
534
586
  async with httpx.AsyncClient(timeout=120.0) as client:
535
587
  request_id, submitted = await self._submit(client, slug, payload)
536
588
  if request_id is not None and not options.get("poll", True):
537
- handle = self._make_handle(slug, request_id, "music")
589
+ handle = self._make_handle(slug, request_id, "music", pricing={"n": 1})
538
590
  return {
539
591
  "audio": [],
540
592
  "meta": {
@@ -286,7 +286,12 @@ class AsyncDriver(ABC):
286
286
  if "/" in driver_name:
287
287
  provider, model = driver_name.split("/", 1)
288
288
  else:
289
- provider = self.__class__.__name__.replace("AsyncDriver", "").replace("Driver", "").lower()
289
+ # Class-name fallback. Strip the Async prefix first:
290
+ # AsyncClaudeDriver is still the "claude" provider, and
291
+ # "asyncclaude" vs "claude" would split one provider's
292
+ # spend into two rows.
293
+ cls_name = self.__class__.__name__.removeprefix("Async")
294
+ provider = cls_name.removesuffix("Driver").lower()
290
295
  model = driver_name
291
296
 
292
297
  model_name = f"{provider}/{model}" if provider else model
@@ -102,7 +102,7 @@ class AsyncCohereEmbeddingDriver(EmbeddingCostMixin, AsyncEmbeddingDriver):
102
102
  "dimensions": actual_dims,
103
103
  "total_tokens": total_tokens,
104
104
  "input_tokens": total_tokens,
105
- "cost": round(cost, 6),
105
+ "cost": round(cost, 12),
106
106
  "raw_response": last_resp,
107
107
  },
108
108
  }
@@ -7,6 +7,7 @@ import time
7
7
  from typing import Any
8
8
 
9
9
  from ..infra.callbacks import DriverCallbacks
10
+ from ._media_usage import record_embedding_driver_usage
10
11
 
11
12
  logger = logging.getLogger("prompture.async_embedding_driver")
12
13
 
@@ -54,6 +55,10 @@ class AsyncEmbeddingDriver:
54
55
  "on_error",
55
56
  {"error": exc, "text_count": len(texts), "options": options, "driver": driver_name},
56
57
  )
58
+ record_embedding_driver_usage(
59
+ self, {}, (time.perf_counter() - t0) * 1000,
60
+ text_count=len(texts), status="error", error=exc,
61
+ )
57
62
  raise
58
63
  elapsed_ms = (time.perf_counter() - t0) * 1000
59
64
  meta = resp.get("meta", {})
@@ -75,6 +80,7 @@ class AsyncEmbeddingDriver:
75
80
  "elapsed_ms": elapsed_ms,
76
81
  },
77
82
  )
83
+ record_embedding_driver_usage(self, meta, elapsed_ms, text_count=len(texts))
78
84
  return resp
79
85
 
80
86
  # ------------------------------------------------------------------
@@ -7,6 +7,7 @@ import time
7
7
  from typing import Any
8
8
 
9
9
  from ..infra.callbacks import DriverCallbacks
10
+ from ._media_usage import record_media_usage
10
11
 
11
12
  logger = logging.getLogger("prompture.async_img_gen_driver")
12
13
 
@@ -59,6 +60,10 @@ class AsyncImageGenDriver:
59
60
  "on_error",
60
61
  {"error": exc, "prompt_length": len(prompt), "options": options, "driver": driver_name},
61
62
  )
63
+ record_media_usage(
64
+ self, {}, (time.perf_counter() - t0) * 1000,
65
+ modality="image", count_key="image_count", status="error", error=exc,
66
+ )
62
67
  raise
63
68
  elapsed_ms = (time.perf_counter() - t0) * 1000
64
69
  meta = resp.get("meta", {})
@@ -78,6 +83,7 @@ class AsyncImageGenDriver:
78
83
  "elapsed_ms": elapsed_ms,
79
84
  },
80
85
  )
86
+ record_media_usage(self, meta, elapsed_ms, modality="image", count_key="image_count")
81
87
  return resp
82
88
 
83
89
  # ------------------------------------------------------------------
@@ -90,7 +90,7 @@ class AsyncJinaEmbeddingDriver(EmbeddingCostMixin, AsyncEmbeddingDriver):
90
90
  "dimensions": actual_dims,
91
91
  "total_tokens": total_tokens,
92
92
  "input_tokens": total_tokens,
93
- "cost": round(cost, 6),
93
+ "cost": round(cost, 12),
94
94
  "raw_response": last_resp,
95
95
  },
96
96
  }