prompture 1.0.47.dev1__tar.gz → 1.0.48.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 (224) hide show
  1. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/PKG-INFO +1 -1
  2. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/_version.py +2 -2
  3. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/tools_schema.py +37 -0
  4. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_grok_driver.py +2 -20
  5. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_groq_driver.py +2 -20
  6. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_moonshot_driver.py +2 -19
  7. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_openai_driver.py +2 -20
  8. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_openrouter_driver.py +2 -19
  9. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/base.py +46 -0
  10. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/grok_driver.py +2 -21
  11. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/groq_driver.py +2 -21
  12. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/moonshot_driver.py +2 -20
  13. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/openai_driver.py +2 -21
  14. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/openrouter_driver.py +2 -20
  15. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture.egg-info/PKG-INFO +1 -1
  16. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/add-driver/SKILL.md +0 -0
  17. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/add-driver/references/driver-template.md +0 -0
  18. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/add-example/SKILL.md +0 -0
  19. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/add-field/SKILL.md +0 -0
  20. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/add-persona/SKILL.md +0 -0
  21. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/add-test/SKILL.md +0 -0
  22. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/add-tool/SKILL.md +0 -0
  23. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/run-tests/SKILL.md +0 -0
  24. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/scaffold-extraction/SKILL.md +0 -0
  25. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.claude/skills/update-pricing/SKILL.md +0 -0
  26. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.env.copy +0 -0
  27. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.github/FUNDING.yml +0 -0
  28. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.github/scripts/update_docs_version.py +0 -0
  29. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.github/scripts/update_wrapper_version.py +0 -0
  30. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.github/workflows/dev.yml +0 -0
  31. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.github/workflows/documentation.yml +0 -0
  32. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.github/workflows/publish.yml +0 -0
  33. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.github/workflows/security.yml +0 -0
  34. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/.safety-project.ini +0 -0
  35. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/CLAUDE.md +0 -0
  36. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/CONTRIBUTING.md +0 -0
  37. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/LICENSE +0 -0
  38. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/MANIFEST.in +0 -0
  39. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/README.md +0 -0
  40. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/ROADMAP.md +0 -0
  41. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/SECURITY.md +0 -0
  42. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/dev.ps1 +0 -0
  43. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/dev.sh +0 -0
  44. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/_static/custom.css +0 -0
  45. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/_templates/footer.html +0 -0
  46. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/api/core.rst +0 -0
  47. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/api/drivers.rst +0 -0
  48. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/api/field_definitions.rst +0 -0
  49. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/api/index.rst +0 -0
  50. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/api/runner.rst +0 -0
  51. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/api/tools.rst +0 -0
  52. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/api/validator.rst +0 -0
  53. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/conf.py +0 -0
  54. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/contributing.rst +0 -0
  55. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/examples.rst +0 -0
  56. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/field_definitions_reference.rst +0 -0
  57. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/index.rst +0 -0
  58. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/installation.rst +0 -0
  59. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/quickstart.rst +0 -0
  60. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/docs/source/toon_input_guide.rst +0 -0
  61. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/mypy_errors.txt +0 -0
  62. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/README.md +0 -0
  63. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_json/README.md +0 -0
  64. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_json/llm_to_json/__init__.py +0 -0
  65. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_json/pyproject.toml +0 -0
  66. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_json/test.py +0 -0
  67. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_toon/README.md +0 -0
  68. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_toon/llm_to_toon/__init__.py +0 -0
  69. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_toon/pyproject.toml +0 -0
  70. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/packages/llm_to_toon/test.py +0 -0
  71. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/__init__.py +0 -0
  72. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/__init__.py +0 -0
  73. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/agent.py +0 -0
  74. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/async_agent.py +0 -0
  75. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/async_conversation.py +0 -0
  76. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/conversation.py +0 -0
  77. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/persona.py +0 -0
  78. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/simulated_tools.py +0 -0
  79. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/skills.py +0 -0
  80. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/agents/types.py +0 -0
  81. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/aio/__init__.py +0 -0
  82. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/bridges/__init__.py +0 -0
  83. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/bridges/tukuy_backend.py +0 -0
  84. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/cli/__init__.py +0 -0
  85. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/cli/cli.py +0 -0
  86. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/cli/runner.py +0 -0
  87. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/cli/server.py +0 -0
  88. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/__init__.py +0 -0
  89. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/airllm_driver.py +0 -0
  90. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_airllm_driver.py +0 -0
  91. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_azure_driver.py +0 -0
  92. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_base.py +0 -0
  93. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_cachibot_driver.py +0 -0
  94. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_claude_driver.py +0 -0
  95. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_elevenlabs_stt_driver.py +0 -0
  96. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_elevenlabs_tts_driver.py +0 -0
  97. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_embedding_base.py +0 -0
  98. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_google_driver.py +0 -0
  99. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_google_img_gen_driver.py +0 -0
  100. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_grok_img_gen_driver.py +0 -0
  101. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_hugging_driver.py +0 -0
  102. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_img_gen_base.py +0 -0
  103. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_lmstudio_driver.py +0 -0
  104. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_local_http_driver.py +0 -0
  105. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_modelscope_driver.py +0 -0
  106. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_ollama_driver.py +0 -0
  107. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_ollama_embedding_driver.py +0 -0
  108. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_openai_embedding_driver.py +0 -0
  109. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_openai_img_gen_driver.py +0 -0
  110. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_openai_stt_driver.py +0 -0
  111. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_openai_tts_driver.py +0 -0
  112. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_registry.py +0 -0
  113. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_stability_img_gen_driver.py +0 -0
  114. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_stt_base.py +0 -0
  115. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_tts_base.py +0 -0
  116. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/async_zai_driver.py +0 -0
  117. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/audio_registry.py +0 -0
  118. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/azure_config.py +0 -0
  119. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/azure_driver.py +0 -0
  120. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/cachibot_driver.py +0 -0
  121. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/claude_driver.py +0 -0
  122. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/elevenlabs_stt_driver.py +0 -0
  123. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/elevenlabs_tts_driver.py +0 -0
  124. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/embedding_base.py +0 -0
  125. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/embedding_registry.py +0 -0
  126. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/google_driver.py +0 -0
  127. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/google_img_gen_driver.py +0 -0
  128. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/grok_img_gen_driver.py +0 -0
  129. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/hugging_driver.py +0 -0
  130. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/img_gen_base.py +0 -0
  131. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/img_gen_registry.py +0 -0
  132. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/lmstudio_driver.py +0 -0
  133. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/local_http_driver.py +0 -0
  134. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/modelscope_driver.py +0 -0
  135. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/ollama_driver.py +0 -0
  136. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/ollama_embedding_driver.py +0 -0
  137. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/openai_embedding_driver.py +0 -0
  138. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/openai_img_gen_driver.py +0 -0
  139. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/openai_stt_driver.py +0 -0
  140. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/openai_tts_driver.py +0 -0
  141. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/registry.py +0 -0
  142. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/stability_img_gen_driver.py +0 -0
  143. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/stt_base.py +0 -0
  144. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/tts_base.py +0 -0
  145. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/vision_helpers.py +0 -0
  146. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/drivers/zai_driver.py +0 -0
  147. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/exceptions.py +0 -0
  148. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/extraction/__init__.py +0 -0
  149. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/extraction/async_core.py +0 -0
  150. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/extraction/core.py +0 -0
  151. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/extraction/fields.py +0 -0
  152. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/extraction/reasoning.py +0 -0
  153. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/extraction/tools.py +0 -0
  154. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/extraction/validator.py +0 -0
  155. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/groups/__init__.py +0 -0
  156. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/groups/async_groups.py +0 -0
  157. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/groups/consensus.py +0 -0
  158. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/groups/debate.py +0 -0
  159. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/groups/groups.py +0 -0
  160. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/groups/types.py +0 -0
  161. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/__init__.py +0 -0
  162. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/budget.py +0 -0
  163. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/cache.py +0 -0
  164. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/callbacks.py +0 -0
  165. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/cost_mixin.py +0 -0
  166. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/discovery.py +0 -0
  167. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/ledger.py +0 -0
  168. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/logging.py +0 -0
  169. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/model_rates.py +0 -0
  170. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/provider_env.py +0 -0
  171. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/rates/anthropic.json +0 -0
  172. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/rates/google.json +0 -0
  173. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/rates/groq.json +0 -0
  174. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/rates/openai.json +0 -0
  175. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/rates/xai.json +0 -0
  176. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/session.py +0 -0
  177. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/settings.py +0 -0
  178. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/infra/tracker.py +0 -0
  179. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/__init__.py +0 -0
  180. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/chunking.py +0 -0
  181. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/detect.py +0 -0
  182. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/document.py +0 -0
  183. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/__init__.py +0 -0
  184. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/base.py +0 -0
  185. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/csv_parser.py +0 -0
  186. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/docx.py +0 -0
  187. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/html.py +0 -0
  188. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/markdown.py +0 -0
  189. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/pdf.py +0 -0
  190. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/ingestion/parsers/xlsx.py +0 -0
  191. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/integrations/__init__.py +0 -0
  192. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/integrations/tukuy_bridge.py +0 -0
  193. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/media/__init__.py +0 -0
  194. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/media/audio.py +0 -0
  195. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/media/image.py +0 -0
  196. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/persistence/__init__.py +0 -0
  197. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/persistence/history.py +0 -0
  198. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/persistence/serialization.py +0 -0
  199. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/persistence/store.py +0 -0
  200. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/pipeline/__init__.py +0 -0
  201. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/pipeline/pipeline.py +0 -0
  202. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/pipeline/resolver.py +0 -0
  203. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/pipeline/routing.py +0 -0
  204. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/py.typed +0 -0
  205. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/__init__.py +0 -0
  206. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/generator.py +0 -0
  207. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/templates/Dockerfile.j2 +0 -0
  208. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/templates/README.md.j2 +0 -0
  209. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/templates/config.py.j2 +0 -0
  210. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/templates/env.example.j2 +0 -0
  211. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/templates/main.py.j2 +0 -0
  212. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/templates/models.py.j2 +0 -0
  213. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture/scaffold/templates/requirements.txt.j2 +0 -0
  214. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture.egg-info/SOURCES.txt +0 -0
  215. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture.egg-info/dependency_links.txt +0 -0
  216. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture.egg-info/entry_points.txt +0 -0
  217. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture.egg-info/requires.txt +0 -0
  218. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture.egg-info/top_level.txt +0 -0
  219. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/prompture_cost_tracking.md +0 -0
  220. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/pyproject.toml +0 -0
  221. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/requirements.txt +0 -0
  222. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/setup.cfg +0 -0
  223. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/test.py +0 -0
  224. {prompture-1.0.47.dev1 → prompture-1.0.48.dev2}/test_version_diagnosis.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prompture
3
- Version: 1.0.47.dev1
3
+ Version: 1.0.48.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
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.0.47.dev1'
32
- __version_tuple__ = version_tuple = (1, 0, 47, 'dev1')
31
+ __version__ = version = '1.0.48.dev2'
32
+ __version_tuple__ = version_tuple = (1, 0, 48, 'dev2')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -22,6 +22,7 @@ Example::
22
22
  from __future__ import annotations
23
23
 
24
24
  import inspect
25
+ import json
25
26
  import logging
26
27
  from dataclasses import dataclass, field
27
28
  from typing import Any, Callable, get_type_hints
@@ -470,6 +471,36 @@ class ToolRegistry:
470
471
  """Join all tool descriptions into a single plain-text block."""
471
472
  return "\n\n".join(td.to_prompt_format() for td in self._tools.values())
472
473
 
474
+ # ------------------------------------------------------------------
475
+ # Argument validation
476
+ # ------------------------------------------------------------------
477
+
478
+ @staticmethod
479
+ def _validate_arguments(td: ToolDefinition, arguments: dict[str, Any]) -> str | None:
480
+ """Return an LLM-friendly error message if required arguments are missing, else ``None``."""
481
+ schema = td.parameters
482
+ if not schema or not isinstance(schema, dict):
483
+ return None
484
+ required = schema.get("required", [])
485
+ properties = schema.get("properties", {})
486
+ missing = [p for p in required if p not in arguments]
487
+ if not missing:
488
+ return None
489
+ parts = []
490
+ for p in missing:
491
+ prop = properties.get(p, {})
492
+ ptype = prop.get("type", "any")
493
+ desc = prop.get("description", "")
494
+ detail = f" - {p} ({ptype})"
495
+ if desc:
496
+ detail += f": {desc}"
497
+ parts.append(detail)
498
+ return (
499
+ f"Missing required argument(s) for '{td.name}'. "
500
+ f"You must provide:\n" + "\n".join(parts) + "\n"
501
+ f"You sent: {json.dumps(arguments) if arguments else '{} (empty)'}"
502
+ )
503
+
473
504
  # ------------------------------------------------------------------
474
505
  # Execution
475
506
  # ------------------------------------------------------------------
@@ -483,6 +514,9 @@ class ToolRegistry:
483
514
  td = self._tools.get(name)
484
515
  if td is None:
485
516
  raise KeyError(f"Tool not registered: {name!r}")
517
+ error = self._validate_arguments(td, arguments)
518
+ if error:
519
+ return error
486
520
  return td.function(**arguments)
487
521
 
488
522
  async def aexecute(self, name: str, arguments: dict[str, Any]) -> Any:
@@ -500,6 +534,9 @@ class ToolRegistry:
500
534
  td = self._tools.get(name)
501
535
  if td is None:
502
536
  raise KeyError(f"Tool not registered: {name!r}")
537
+ error = self._validate_arguments(td, arguments)
538
+ if error:
539
+ return error
503
540
  # Prefer dedicated async wrapper (set by tukuy bridge)
504
541
  async_fn = getattr(td.function, "_async_fn", None)
505
542
  if async_fn is not None:
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import json
6
5
  import logging
7
6
  import os
8
7
  from typing import Any
@@ -11,6 +10,7 @@ import httpx
11
10
 
12
11
  from ..infra.cost_mixin import CostMixin
13
12
  from .async_base import AsyncDriver
13
+ from .base import _parse_tool_arguments
14
14
  from .grok_driver import GrokDriver
15
15
 
16
16
  logger = logging.getLogger(__name__)
@@ -181,25 +181,7 @@ class AsyncGrokDriver(CostMixin, AsyncDriver):
181
181
 
182
182
  tool_calls_out: list[dict[str, Any]] = []
183
183
  for tc in choice["message"].get("tool_calls", []):
184
- try:
185
- args = json.loads(tc["function"]["arguments"])
186
- except (json.JSONDecodeError, TypeError):
187
- raw = tc["function"].get("arguments")
188
- if stop_reason == "length":
189
- logger.warning(
190
- "Tool arguments for %s were truncated due to max_tokens limit. "
191
- "Increase max_tokens in options to allow longer tool outputs. "
192
- "Truncated arguments: %r",
193
- tc["function"]["name"],
194
- raw[:200] if raw else raw,
195
- )
196
- else:
197
- logger.warning(
198
- "Failed to parse tool arguments for %s: %r",
199
- tc["function"]["name"],
200
- raw,
201
- )
202
- args = {}
184
+ args = _parse_tool_arguments(tc["function"]["arguments"], tc["function"]["name"], stop_reason)
203
185
  tool_calls_out.append(
204
186
  {
205
187
  "id": tc["id"],
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import json
6
5
  import logging
7
6
  import os
8
7
  from typing import Any
@@ -14,6 +13,7 @@ except Exception:
14
13
 
15
14
  from ..infra.cost_mixin import CostMixin
16
15
  from .async_base import AsyncDriver
16
+ from .base import _parse_tool_arguments
17
17
  from .groq_driver import GroqDriver
18
18
 
19
19
  logger = logging.getLogger(__name__)
@@ -159,25 +159,7 @@ class AsyncGroqDriver(CostMixin, AsyncDriver):
159
159
  tool_calls_out: list[dict[str, Any]] = []
160
160
  if choice.message.tool_calls:
161
161
  for tc in choice.message.tool_calls:
162
- try:
163
- args = json.loads(tc.function.arguments)
164
- except (json.JSONDecodeError, TypeError):
165
- raw = tc.function.arguments
166
- if stop_reason == "length":
167
- logger.warning(
168
- "Tool arguments for %s were truncated due to max_tokens limit. "
169
- "Increase max_tokens in options to allow longer tool outputs. "
170
- "Truncated arguments: %r",
171
- tc.function.name,
172
- raw[:200] if raw else raw,
173
- )
174
- else:
175
- logger.warning(
176
- "Failed to parse tool arguments for %s: %r",
177
- tc.function.name,
178
- raw,
179
- )
180
- args = {}
162
+ args = _parse_tool_arguments(tc.function.arguments, tc.function.name, stop_reason)
181
163
  tool_calls_out.append(
182
164
  {
183
165
  "id": tc.id,
@@ -19,6 +19,7 @@ import httpx
19
19
 
20
20
  from ..infra.cost_mixin import CostMixin, prepare_strict_schema
21
21
  from .async_base import AsyncDriver
22
+ from .base import _parse_tool_arguments
22
23
  from .moonshot_driver import MoonshotDriver
23
24
 
24
25
  logger = logging.getLogger("prompture.drivers.moonshot")
@@ -297,25 +298,7 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
297
298
 
298
299
  tool_calls_out: list[dict[str, Any]] = []
299
300
  for tc in message.get("tool_calls", []):
300
- try:
301
- args = json.loads(tc["function"]["arguments"])
302
- except (json.JSONDecodeError, TypeError):
303
- raw = tc["function"].get("arguments")
304
- if stop_reason == "length":
305
- logger.warning(
306
- "Tool arguments for %s were truncated due to max_tokens limit. "
307
- "Increase max_tokens in options to allow longer tool outputs. "
308
- "Truncated arguments: %r",
309
- tc["function"]["name"],
310
- raw[:200] if raw else raw,
311
- )
312
- else:
313
- logger.warning(
314
- "Failed to parse tool arguments for %s: %r",
315
- tc["function"]["name"],
316
- raw,
317
- )
318
- args = {}
301
+ args = _parse_tool_arguments(tc["function"]["arguments"], tc["function"]["name"], stop_reason)
319
302
  tool_calls_out.append(
320
303
  {
321
304
  "id": tc["id"],
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import json
6
5
  import logging
7
6
  import os
8
7
  from collections.abc import AsyncIterator
@@ -15,6 +14,7 @@ except Exception:
15
14
 
16
15
  from ..infra.cost_mixin import CostMixin, prepare_strict_schema
17
16
  from .async_base import AsyncDriver
17
+ from .base import _parse_tool_arguments
18
18
  from .openai_driver import OpenAIDriver
19
19
 
20
20
  logger = logging.getLogger(__name__)
@@ -176,25 +176,7 @@ class AsyncOpenAIDriver(CostMixin, AsyncDriver):
176
176
  tool_calls_out: list[dict[str, Any]] = []
177
177
  if choice.message.tool_calls:
178
178
  for tc in choice.message.tool_calls:
179
- try:
180
- args = json.loads(tc.function.arguments)
181
- except (json.JSONDecodeError, TypeError):
182
- raw = tc.function.arguments
183
- if stop_reason == "length":
184
- logger.warning(
185
- "Tool arguments for %s were truncated due to max_tokens limit. "
186
- "Increase max_tokens in options to allow longer tool outputs. "
187
- "Truncated arguments: %r",
188
- tc.function.name,
189
- raw[:200] if raw else raw,
190
- )
191
- else:
192
- logger.warning(
193
- "Failed to parse tool arguments for %s: %r",
194
- tc.function.name,
195
- raw,
196
- )
197
- args = {}
179
+ args = _parse_tool_arguments(tc.function.arguments, tc.function.name, stop_reason)
198
180
  tool_calls_out.append(
199
181
  {
200
182
  "id": tc.id,
@@ -12,6 +12,7 @@ import httpx
12
12
 
13
13
  from ..infra.cost_mixin import CostMixin, prepare_strict_schema
14
14
  from .async_base import AsyncDriver
15
+ from .base import _parse_tool_arguments
15
16
  from .openrouter_driver import OpenRouterDriver
16
17
 
17
18
  logger = logging.getLogger(__name__)
@@ -204,25 +205,7 @@ class AsyncOpenRouterDriver(CostMixin, AsyncDriver):
204
205
 
205
206
  tool_calls_out: list[dict[str, Any]] = []
206
207
  for tc in choice["message"].get("tool_calls", []):
207
- try:
208
- args = json.loads(tc["function"]["arguments"])
209
- except (json.JSONDecodeError, TypeError):
210
- raw = tc["function"].get("arguments")
211
- if stop_reason == "length":
212
- logger.warning(
213
- "Tool arguments for %s were truncated due to max_tokens limit. "
214
- "Increase max_tokens in options to allow longer tool outputs. "
215
- "Truncated arguments: %r",
216
- tc["function"]["name"],
217
- raw[:200] if raw else raw,
218
- )
219
- else:
220
- logger.warning(
221
- "Failed to parse tool arguments for %s: %r",
222
- tc["function"]["name"],
223
- raw,
224
- )
225
- args = {}
208
+ args = _parse_tool_arguments(tc["function"]["arguments"], tc["function"]["name"], stop_reason)
226
209
  tool_calls_out.append(
227
210
  {
228
211
  "id": tc["id"],
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json
5
6
  import logging
6
7
  import time
7
8
  from abc import ABC, abstractmethod
@@ -20,6 +21,51 @@ from ..infra.callbacks import DriverCallbacks
20
21
  logger = logging.getLogger("prompture.driver")
21
22
 
22
23
 
24
+ # ------------------------------------------------------------------
25
+ # Shared tool-argument parser for OpenAI-compatible drivers
26
+ # ------------------------------------------------------------------
27
+
28
+
29
+ def _parse_tool_arguments(raw_args: Any, tool_name: str, stop_reason: str | None = None) -> dict[str, Any]:
30
+ """Parse tool call arguments, handling both string and dict formats.
31
+
32
+ Some providers return ``arguments`` as a JSON string, others as an
33
+ already-parsed dict. Calling ``json.loads()`` on a dict raises
34
+ ``TypeError`` which previously caused a silent fallback to ``{}``.
35
+ """
36
+ if isinstance(raw_args, dict):
37
+ return raw_args
38
+ if isinstance(raw_args, str):
39
+ try:
40
+ parsed = json.loads(raw_args)
41
+ return parsed if isinstance(parsed, dict) else {}
42
+ except json.JSONDecodeError:
43
+ if stop_reason == "length":
44
+ logger.warning(
45
+ "Tool arguments for %s were truncated due to max_tokens limit. "
46
+ "Increase max_tokens in options to allow longer tool outputs. "
47
+ "Truncated arguments: %r",
48
+ tool_name,
49
+ raw_args[:200] if raw_args else raw_args,
50
+ )
51
+ else:
52
+ logger.warning(
53
+ "Failed to parse tool arguments for %s: %r",
54
+ tool_name,
55
+ raw_args[:200] if raw_args else raw_args,
56
+ )
57
+ return {}
58
+ if raw_args is None:
59
+ return {}
60
+ logger.warning(
61
+ "Unexpected argument type %s for tool %s: %r",
62
+ type(raw_args).__name__,
63
+ tool_name,
64
+ raw_args,
65
+ )
66
+ return {}
67
+
68
+
23
69
  # ------------------------------------------------------------------
24
70
  # Shared helper for OpenAI-compatible /v1/models endpoints
25
71
  # ------------------------------------------------------------------
@@ -2,7 +2,6 @@
2
2
  Requires the `requests` package. Uses GROK_API_KEY env var.
3
3
  """
4
4
 
5
- import json
6
5
  import logging
7
6
  import os
8
7
  from typing import Any
@@ -10,7 +9,7 @@ from typing import Any
10
9
  import requests
11
10
 
12
11
  from ..infra.cost_mixin import CostMixin
13
- from .base import Driver
12
+ from .base import Driver, _parse_tool_arguments
14
13
 
15
14
  logger = logging.getLogger(__name__)
16
15
 
@@ -245,25 +244,7 @@ class GrokDriver(CostMixin, Driver):
245
244
 
246
245
  tool_calls_out: list[dict[str, Any]] = []
247
246
  for tc in choice["message"].get("tool_calls", []):
248
- try:
249
- args = json.loads(tc["function"]["arguments"])
250
- except (json.JSONDecodeError, TypeError):
251
- raw = tc["function"].get("arguments")
252
- if stop_reason == "length":
253
- logger.warning(
254
- "Tool arguments for %s were truncated due to max_tokens limit. "
255
- "Increase max_tokens in options to allow longer tool outputs. "
256
- "Truncated arguments: %r",
257
- tc["function"]["name"],
258
- raw[:200] if raw else raw,
259
- )
260
- else:
261
- logger.warning(
262
- "Failed to parse tool arguments for %s: %r",
263
- tc["function"]["name"],
264
- raw,
265
- )
266
- args = {}
247
+ args = _parse_tool_arguments(tc["function"]["arguments"], tc["function"]["name"], stop_reason)
267
248
  tool_calls_out.append(
268
249
  {
269
250
  "id": tc["id"],
@@ -2,7 +2,6 @@
2
2
  Requires the `groq` package. Uses GROQ_API_KEY env var.
3
3
  """
4
4
 
5
- import json
6
5
  import logging
7
6
  import os
8
7
  from typing import Any
@@ -13,7 +12,7 @@ except Exception:
13
12
  groq = None # type: ignore[assignment]
14
13
 
15
14
  from ..infra.cost_mixin import CostMixin
16
- from .base import Driver
15
+ from .base import Driver, _parse_tool_arguments
17
16
 
18
17
  logger = logging.getLogger(__name__)
19
18
 
@@ -203,25 +202,7 @@ class GroqDriver(CostMixin, Driver):
203
202
  tool_calls_out: list[dict[str, Any]] = []
204
203
  if choice.message.tool_calls:
205
204
  for tc in choice.message.tool_calls:
206
- try:
207
- args = json.loads(tc.function.arguments)
208
- except (json.JSONDecodeError, TypeError):
209
- raw = tc.function.arguments
210
- if stop_reason == "length":
211
- logger.warning(
212
- "Tool arguments for %s were truncated due to max_tokens limit. "
213
- "Increase max_tokens in options to allow longer tool outputs. "
214
- "Truncated arguments: %r",
215
- tc.function.name,
216
- raw[:200] if raw else raw,
217
- )
218
- else:
219
- logger.warning(
220
- "Failed to parse tool arguments for %s: %r",
221
- tc.function.name,
222
- raw,
223
- )
224
- args = {}
205
+ args = _parse_tool_arguments(tc.function.arguments, tc.function.name, stop_reason)
225
206
  tool_calls_out.append(
226
207
  {
227
208
  "id": tc.id,
@@ -18,7 +18,7 @@ from typing import Any
18
18
  import requests
19
19
 
20
20
  from ..infra.cost_mixin import CostMixin, prepare_strict_schema
21
- from .base import Driver
21
+ from .base import Driver, _parse_tool_arguments
22
22
 
23
23
  logger = logging.getLogger("prompture.drivers.moonshot")
24
24
 
@@ -416,25 +416,7 @@ class MoonshotDriver(CostMixin, Driver):
416
416
 
417
417
  tool_calls_out: list[dict[str, Any]] = []
418
418
  for tc in message.get("tool_calls", []):
419
- try:
420
- args = json.loads(tc["function"]["arguments"])
421
- except (json.JSONDecodeError, TypeError):
422
- raw = tc["function"].get("arguments")
423
- if stop_reason == "length":
424
- logger.warning(
425
- "Tool arguments for %s were truncated due to max_tokens limit. "
426
- "Increase max_tokens in options to allow longer tool outputs. "
427
- "Truncated arguments: %r",
428
- tc["function"]["name"],
429
- raw[:200] if raw else raw,
430
- )
431
- else:
432
- logger.warning(
433
- "Failed to parse tool arguments for %s: %r",
434
- tc["function"]["name"],
435
- raw,
436
- )
437
- args = {}
419
+ args = _parse_tool_arguments(tc["function"]["arguments"], tc["function"]["name"], stop_reason)
438
420
  tool_calls_out.append(
439
421
  {
440
422
  "id": tc["id"],
@@ -2,7 +2,6 @@
2
2
  Requires the `openai` package. Uses OPENAI_API_KEY env var.
3
3
  """
4
4
 
5
- import json
6
5
  import logging
7
6
  import os
8
7
  from collections.abc import Iterator
@@ -14,7 +13,7 @@ except Exception:
14
13
  OpenAI = None # type: ignore[misc, assignment]
15
14
 
16
15
  from ..infra.cost_mixin import CostMixin, prepare_strict_schema
17
- from .base import Driver
16
+ from .base import Driver, _parse_tool_arguments
18
17
 
19
18
  logger = logging.getLogger(__name__)
20
19
 
@@ -234,25 +233,7 @@ class OpenAIDriver(CostMixin, Driver):
234
233
  tool_calls_out: list[dict[str, Any]] = []
235
234
  if choice.message.tool_calls:
236
235
  for tc in choice.message.tool_calls:
237
- try:
238
- args = json.loads(tc.function.arguments)
239
- except (json.JSONDecodeError, TypeError):
240
- raw = tc.function.arguments
241
- if stop_reason == "length":
242
- logger.warning(
243
- "Tool arguments for %s were truncated due to max_tokens limit. "
244
- "Increase max_tokens in options to allow longer tool outputs. "
245
- "Truncated arguments: %r",
246
- tc.function.name,
247
- raw[:200] if raw else raw,
248
- )
249
- else:
250
- logger.warning(
251
- "Failed to parse tool arguments for %s: %r",
252
- tc.function.name,
253
- raw,
254
- )
255
- args = {}
236
+ args = _parse_tool_arguments(tc.function.arguments, tc.function.name, stop_reason)
256
237
  tool_calls_out.append(
257
238
  {
258
239
  "id": tc.id,
@@ -12,7 +12,7 @@ from typing import Any
12
12
  import requests
13
13
 
14
14
  from ..infra.cost_mixin import CostMixin, prepare_strict_schema
15
- from .base import Driver
15
+ from .base import Driver, _parse_tool_arguments
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
@@ -281,25 +281,7 @@ class OpenRouterDriver(CostMixin, Driver):
281
281
 
282
282
  tool_calls_out: list[dict[str, Any]] = []
283
283
  for tc in choice["message"].get("tool_calls", []):
284
- try:
285
- args = json.loads(tc["function"]["arguments"])
286
- except (json.JSONDecodeError, TypeError):
287
- raw = tc["function"].get("arguments")
288
- if stop_reason == "length":
289
- logger.warning(
290
- "Tool arguments for %s were truncated due to max_tokens limit. "
291
- "Increase max_tokens in options to allow longer tool outputs. "
292
- "Truncated arguments: %r",
293
- tc["function"]["name"],
294
- raw[:200] if raw else raw,
295
- )
296
- else:
297
- logger.warning(
298
- "Failed to parse tool arguments for %s: %r",
299
- tc["function"]["name"],
300
- raw,
301
- )
302
- args = {}
284
+ args = _parse_tool_arguments(tc["function"]["arguments"], tc["function"]["name"], stop_reason)
303
285
  tool_calls_out.append(
304
286
  {
305
287
  "id": tc["id"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prompture
3
- Version: 1.0.47.dev1
3
+ Version: 1.0.48.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
File without changes
File without changes
File without changes