mirascope 1.25.7__py3-none-any.whl → 2.0.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. mirascope/__init__.py +3 -59
  2. mirascope/graphs/__init__.py +22 -0
  3. mirascope/{experimental/graphs → graphs}/finite_state_machine.py +70 -159
  4. mirascope/llm/__init__.py +206 -16
  5. mirascope/llm/agents/__init__.py +15 -0
  6. mirascope/llm/agents/agent.py +97 -0
  7. mirascope/llm/agents/agent_template.py +45 -0
  8. mirascope/llm/agents/decorator.py +176 -0
  9. mirascope/llm/calls/__init__.py +16 -0
  10. mirascope/llm/calls/base_call.py +33 -0
  11. mirascope/llm/calls/calls.py +315 -0
  12. mirascope/llm/calls/decorator.py +255 -0
  13. mirascope/llm/clients/__init__.py +34 -0
  14. mirascope/llm/clients/anthropic/__init__.py +11 -0
  15. mirascope/llm/clients/anthropic/_utils/__init__.py +13 -0
  16. mirascope/llm/clients/anthropic/_utils/decode.py +244 -0
  17. mirascope/llm/clients/anthropic/_utils/encode.py +243 -0
  18. mirascope/llm/clients/anthropic/clients.py +819 -0
  19. mirascope/llm/clients/anthropic/model_ids.py +8 -0
  20. mirascope/llm/clients/base/__init__.py +15 -0
  21. mirascope/llm/clients/base/_utils.py +192 -0
  22. mirascope/llm/clients/base/client.py +1256 -0
  23. mirascope/llm/clients/base/kwargs.py +12 -0
  24. mirascope/llm/clients/base/params.py +93 -0
  25. mirascope/llm/clients/google/__init__.py +6 -0
  26. mirascope/llm/clients/google/_utils/__init__.py +13 -0
  27. mirascope/llm/clients/google/_utils/decode.py +231 -0
  28. mirascope/llm/clients/google/_utils/encode.py +279 -0
  29. mirascope/llm/clients/google/clients.py +853 -0
  30. mirascope/llm/clients/google/message.py +7 -0
  31. mirascope/llm/clients/google/model_ids.py +15 -0
  32. mirascope/llm/clients/openai/__init__.py +25 -0
  33. mirascope/llm/clients/openai/completions/__init__.py +9 -0
  34. mirascope/llm/clients/openai/completions/_utils/__init__.py +13 -0
  35. mirascope/llm/clients/openai/completions/_utils/decode.py +187 -0
  36. mirascope/llm/clients/openai/completions/_utils/encode.py +358 -0
  37. mirascope/llm/clients/openai/completions/_utils/model_features.py +81 -0
  38. mirascope/llm/clients/openai/completions/clients.py +833 -0
  39. mirascope/llm/clients/openai/completions/model_ids.py +8 -0
  40. mirascope/llm/clients/openai/responses/__init__.py +9 -0
  41. mirascope/llm/clients/openai/responses/_utils/__init__.py +13 -0
  42. mirascope/llm/clients/openai/responses/_utils/decode.py +194 -0
  43. mirascope/llm/clients/openai/responses/_utils/encode.py +333 -0
  44. mirascope/llm/clients/openai/responses/_utils/model_features.py +87 -0
  45. mirascope/llm/clients/openai/responses/clients.py +832 -0
  46. mirascope/llm/clients/openai/responses/model_ids.py +8 -0
  47. mirascope/llm/clients/openai/shared/__init__.py +7 -0
  48. mirascope/llm/clients/openai/shared/_utils.py +55 -0
  49. mirascope/llm/clients/providers.py +175 -0
  50. mirascope/llm/content/__init__.py +70 -0
  51. mirascope/llm/content/audio.py +173 -0
  52. mirascope/llm/content/document.py +94 -0
  53. mirascope/llm/content/image.py +206 -0
  54. mirascope/llm/content/text.py +47 -0
  55. mirascope/llm/content/thought.py +58 -0
  56. mirascope/llm/content/tool_call.py +63 -0
  57. mirascope/llm/content/tool_output.py +26 -0
  58. mirascope/llm/context/__init__.py +6 -0
  59. mirascope/llm/context/_utils.py +28 -0
  60. mirascope/llm/context/context.py +24 -0
  61. mirascope/llm/exceptions.py +105 -0
  62. mirascope/llm/formatting/__init__.py +22 -0
  63. mirascope/llm/formatting/_utils.py +74 -0
  64. mirascope/llm/formatting/format.py +104 -0
  65. mirascope/llm/formatting/from_call_args.py +30 -0
  66. mirascope/llm/formatting/partial.py +58 -0
  67. mirascope/llm/formatting/types.py +109 -0
  68. mirascope/llm/mcp/__init__.py +5 -0
  69. mirascope/llm/mcp/client.py +118 -0
  70. mirascope/llm/messages/__init__.py +32 -0
  71. mirascope/llm/messages/message.py +182 -0
  72. mirascope/llm/models/__init__.py +16 -0
  73. mirascope/llm/models/models.py +1243 -0
  74. mirascope/llm/prompts/__init__.py +33 -0
  75. mirascope/llm/prompts/_utils.py +60 -0
  76. mirascope/llm/prompts/decorator.py +286 -0
  77. mirascope/llm/prompts/protocols.py +99 -0
  78. mirascope/llm/responses/__init__.py +57 -0
  79. mirascope/llm/responses/_utils.py +56 -0
  80. mirascope/llm/responses/base_response.py +91 -0
  81. mirascope/llm/responses/base_stream_response.py +697 -0
  82. mirascope/llm/responses/finish_reason.py +27 -0
  83. mirascope/llm/responses/response.py +345 -0
  84. mirascope/llm/responses/root_response.py +177 -0
  85. mirascope/llm/responses/stream_response.py +572 -0
  86. mirascope/llm/responses/streams.py +363 -0
  87. mirascope/llm/tools/__init__.py +40 -0
  88. mirascope/llm/tools/_utils.py +25 -0
  89. mirascope/llm/tools/decorator.py +175 -0
  90. mirascope/llm/tools/protocols.py +96 -0
  91. mirascope/llm/tools/tool_schema.py +246 -0
  92. mirascope/llm/tools/toolkit.py +152 -0
  93. mirascope/llm/tools/tools.py +169 -0
  94. mirascope/llm/types/__init__.py +22 -0
  95. mirascope/llm/types/dataclass.py +9 -0
  96. mirascope/llm/types/jsonable.py +44 -0
  97. mirascope/llm/types/type_vars.py +19 -0
  98. mirascope-2.0.0a0.dist-info/METADATA +117 -0
  99. mirascope-2.0.0a0.dist-info/RECORD +101 -0
  100. mirascope/beta/__init__.py +0 -3
  101. mirascope/beta/openai/__init__.py +0 -17
  102. mirascope/beta/openai/realtime/__init__.py +0 -13
  103. mirascope/beta/openai/realtime/_utils/__init__.py +0 -3
  104. mirascope/beta/openai/realtime/_utils/_audio.py +0 -74
  105. mirascope/beta/openai/realtime/_utils/_protocols.py +0 -50
  106. mirascope/beta/openai/realtime/realtime.py +0 -500
  107. mirascope/beta/openai/realtime/recording.py +0 -98
  108. mirascope/beta/openai/realtime/tool.py +0 -113
  109. mirascope/beta/rag/__init__.py +0 -24
  110. mirascope/beta/rag/base/__init__.py +0 -22
  111. mirascope/beta/rag/base/chunkers/__init__.py +0 -2
  112. mirascope/beta/rag/base/chunkers/base_chunker.py +0 -37
  113. mirascope/beta/rag/base/chunkers/text_chunker.py +0 -33
  114. mirascope/beta/rag/base/config.py +0 -8
  115. mirascope/beta/rag/base/document.py +0 -11
  116. mirascope/beta/rag/base/embedders.py +0 -35
  117. mirascope/beta/rag/base/embedding_params.py +0 -18
  118. mirascope/beta/rag/base/embedding_response.py +0 -30
  119. mirascope/beta/rag/base/query_results.py +0 -7
  120. mirascope/beta/rag/base/vectorstore_params.py +0 -18
  121. mirascope/beta/rag/base/vectorstores.py +0 -37
  122. mirascope/beta/rag/chroma/__init__.py +0 -11
  123. mirascope/beta/rag/chroma/types.py +0 -62
  124. mirascope/beta/rag/chroma/vectorstores.py +0 -121
  125. mirascope/beta/rag/cohere/__init__.py +0 -11
  126. mirascope/beta/rag/cohere/embedders.py +0 -87
  127. mirascope/beta/rag/cohere/embedding_params.py +0 -29
  128. mirascope/beta/rag/cohere/embedding_response.py +0 -29
  129. mirascope/beta/rag/cohere/py.typed +0 -0
  130. mirascope/beta/rag/openai/__init__.py +0 -11
  131. mirascope/beta/rag/openai/embedders.py +0 -144
  132. mirascope/beta/rag/openai/embedding_params.py +0 -18
  133. mirascope/beta/rag/openai/embedding_response.py +0 -14
  134. mirascope/beta/rag/openai/py.typed +0 -0
  135. mirascope/beta/rag/pinecone/__init__.py +0 -19
  136. mirascope/beta/rag/pinecone/types.py +0 -143
  137. mirascope/beta/rag/pinecone/vectorstores.py +0 -148
  138. mirascope/beta/rag/weaviate/__init__.py +0 -6
  139. mirascope/beta/rag/weaviate/types.py +0 -92
  140. mirascope/beta/rag/weaviate/vectorstores.py +0 -103
  141. mirascope/core/__init__.py +0 -109
  142. mirascope/core/anthropic/__init__.py +0 -31
  143. mirascope/core/anthropic/_call.py +0 -67
  144. mirascope/core/anthropic/_call_kwargs.py +0 -13
  145. mirascope/core/anthropic/_thinking.py +0 -70
  146. mirascope/core/anthropic/_utils/__init__.py +0 -16
  147. mirascope/core/anthropic/_utils/_convert_common_call_params.py +0 -25
  148. mirascope/core/anthropic/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -21
  149. mirascope/core/anthropic/_utils/_convert_message_params.py +0 -102
  150. mirascope/core/anthropic/_utils/_get_json_output.py +0 -31
  151. mirascope/core/anthropic/_utils/_handle_stream.py +0 -113
  152. mirascope/core/anthropic/_utils/_message_param_converter.py +0 -154
  153. mirascope/core/anthropic/_utils/_setup_call.py +0 -146
  154. mirascope/core/anthropic/call_params.py +0 -44
  155. mirascope/core/anthropic/call_response.py +0 -226
  156. mirascope/core/anthropic/call_response_chunk.py +0 -152
  157. mirascope/core/anthropic/dynamic_config.py +0 -40
  158. mirascope/core/anthropic/py.typed +0 -0
  159. mirascope/core/anthropic/stream.py +0 -204
  160. mirascope/core/anthropic/tool.py +0 -101
  161. mirascope/core/azure/__init__.py +0 -31
  162. mirascope/core/azure/_call.py +0 -67
  163. mirascope/core/azure/_call_kwargs.py +0 -13
  164. mirascope/core/azure/_utils/__init__.py +0 -14
  165. mirascope/core/azure/_utils/_convert_common_call_params.py +0 -26
  166. mirascope/core/azure/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -21
  167. mirascope/core/azure/_utils/_convert_message_params.py +0 -121
  168. mirascope/core/azure/_utils/_get_credential.py +0 -33
  169. mirascope/core/azure/_utils/_get_json_output.py +0 -27
  170. mirascope/core/azure/_utils/_handle_stream.py +0 -130
  171. mirascope/core/azure/_utils/_message_param_converter.py +0 -117
  172. mirascope/core/azure/_utils/_setup_call.py +0 -183
  173. mirascope/core/azure/call_params.py +0 -59
  174. mirascope/core/azure/call_response.py +0 -215
  175. mirascope/core/azure/call_response_chunk.py +0 -105
  176. mirascope/core/azure/dynamic_config.py +0 -30
  177. mirascope/core/azure/py.typed +0 -0
  178. mirascope/core/azure/stream.py +0 -147
  179. mirascope/core/azure/tool.py +0 -93
  180. mirascope/core/base/__init__.py +0 -86
  181. mirascope/core/base/_call_factory.py +0 -256
  182. mirascope/core/base/_create.py +0 -253
  183. mirascope/core/base/_extract.py +0 -175
  184. mirascope/core/base/_extract_with_tools.py +0 -189
  185. mirascope/core/base/_partial.py +0 -95
  186. mirascope/core/base/_utils/__init__.py +0 -92
  187. mirascope/core/base/_utils/_base_message_param_converter.py +0 -22
  188. mirascope/core/base/_utils/_base_type.py +0 -26
  189. mirascope/core/base/_utils/_convert_base_model_to_base_tool.py +0 -48
  190. mirascope/core/base/_utils/_convert_base_type_to_base_tool.py +0 -24
  191. mirascope/core/base/_utils/_convert_function_to_base_tool.py +0 -139
  192. mirascope/core/base/_utils/_convert_messages_to_message_params.py +0 -178
  193. mirascope/core/base/_utils/_convert_provider_finish_reason_to_finish_reason.py +0 -20
  194. mirascope/core/base/_utils/_default_tool_docstring.py +0 -6
  195. mirascope/core/base/_utils/_extract_tool_return.py +0 -42
  196. mirascope/core/base/_utils/_fn_is_async.py +0 -24
  197. mirascope/core/base/_utils/_format_template.py +0 -32
  198. mirascope/core/base/_utils/_get_audio_type.py +0 -18
  199. mirascope/core/base/_utils/_get_common_usage.py +0 -20
  200. mirascope/core/base/_utils/_get_create_fn_or_async_create_fn.py +0 -137
  201. mirascope/core/base/_utils/_get_document_type.py +0 -7
  202. mirascope/core/base/_utils/_get_dynamic_configuration.py +0 -69
  203. mirascope/core/base/_utils/_get_fields_from_call_args.py +0 -34
  204. mirascope/core/base/_utils/_get_fn_args.py +0 -23
  205. mirascope/core/base/_utils/_get_image_dimensions.py +0 -39
  206. mirascope/core/base/_utils/_get_image_type.py +0 -26
  207. mirascope/core/base/_utils/_get_metadata.py +0 -17
  208. mirascope/core/base/_utils/_get_possible_user_message_param.py +0 -21
  209. mirascope/core/base/_utils/_get_prompt_template.py +0 -28
  210. mirascope/core/base/_utils/_get_template_values.py +0 -51
  211. mirascope/core/base/_utils/_get_template_variables.py +0 -38
  212. mirascope/core/base/_utils/_get_unsupported_tool_config_keys.py +0 -10
  213. mirascope/core/base/_utils/_is_prompt_template.py +0 -24
  214. mirascope/core/base/_utils/_json_mode_content.py +0 -17
  215. mirascope/core/base/_utils/_messages_decorator.py +0 -121
  216. mirascope/core/base/_utils/_parse_content_template.py +0 -323
  217. mirascope/core/base/_utils/_parse_prompt_messages.py +0 -63
  218. mirascope/core/base/_utils/_pil_image_to_bytes.py +0 -13
  219. mirascope/core/base/_utils/_protocols.py +0 -901
  220. mirascope/core/base/_utils/_setup_call.py +0 -79
  221. mirascope/core/base/_utils/_setup_extract_tool.py +0 -30
  222. mirascope/core/base/call_kwargs.py +0 -13
  223. mirascope/core/base/call_params.py +0 -36
  224. mirascope/core/base/call_response.py +0 -338
  225. mirascope/core/base/call_response_chunk.py +0 -130
  226. mirascope/core/base/dynamic_config.py +0 -82
  227. mirascope/core/base/from_call_args.py +0 -30
  228. mirascope/core/base/merge_decorators.py +0 -59
  229. mirascope/core/base/message_param.py +0 -175
  230. mirascope/core/base/messages.py +0 -116
  231. mirascope/core/base/metadata.py +0 -13
  232. mirascope/core/base/prompt.py +0 -497
  233. mirascope/core/base/response_model_config_dict.py +0 -9
  234. mirascope/core/base/stream.py +0 -479
  235. mirascope/core/base/stream_config.py +0 -11
  236. mirascope/core/base/structured_stream.py +0 -296
  237. mirascope/core/base/tool.py +0 -214
  238. mirascope/core/base/toolkit.py +0 -176
  239. mirascope/core/base/types.py +0 -344
  240. mirascope/core/bedrock/__init__.py +0 -34
  241. mirascope/core/bedrock/_call.py +0 -68
  242. mirascope/core/bedrock/_call_kwargs.py +0 -12
  243. mirascope/core/bedrock/_types.py +0 -104
  244. mirascope/core/bedrock/_utils/__init__.py +0 -14
  245. mirascope/core/bedrock/_utils/_convert_common_call_params.py +0 -39
  246. mirascope/core/bedrock/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -23
  247. mirascope/core/bedrock/_utils/_convert_message_params.py +0 -111
  248. mirascope/core/bedrock/_utils/_get_json_output.py +0 -30
  249. mirascope/core/bedrock/_utils/_handle_stream.py +0 -104
  250. mirascope/core/bedrock/_utils/_message_param_converter.py +0 -172
  251. mirascope/core/bedrock/_utils/_setup_call.py +0 -258
  252. mirascope/core/bedrock/call_params.py +0 -38
  253. mirascope/core/bedrock/call_response.py +0 -248
  254. mirascope/core/bedrock/call_response_chunk.py +0 -111
  255. mirascope/core/bedrock/dynamic_config.py +0 -37
  256. mirascope/core/bedrock/py.typed +0 -0
  257. mirascope/core/bedrock/stream.py +0 -154
  258. mirascope/core/bedrock/tool.py +0 -100
  259. mirascope/core/cohere/__init__.py +0 -30
  260. mirascope/core/cohere/_call.py +0 -67
  261. mirascope/core/cohere/_call_kwargs.py +0 -11
  262. mirascope/core/cohere/_types.py +0 -20
  263. mirascope/core/cohere/_utils/__init__.py +0 -14
  264. mirascope/core/cohere/_utils/_convert_common_call_params.py +0 -26
  265. mirascope/core/cohere/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -24
  266. mirascope/core/cohere/_utils/_convert_message_params.py +0 -32
  267. mirascope/core/cohere/_utils/_get_json_output.py +0 -30
  268. mirascope/core/cohere/_utils/_handle_stream.py +0 -35
  269. mirascope/core/cohere/_utils/_message_param_converter.py +0 -54
  270. mirascope/core/cohere/_utils/_setup_call.py +0 -150
  271. mirascope/core/cohere/call_params.py +0 -62
  272. mirascope/core/cohere/call_response.py +0 -205
  273. mirascope/core/cohere/call_response_chunk.py +0 -125
  274. mirascope/core/cohere/dynamic_config.py +0 -32
  275. mirascope/core/cohere/py.typed +0 -0
  276. mirascope/core/cohere/stream.py +0 -113
  277. mirascope/core/cohere/tool.py +0 -93
  278. mirascope/core/costs/__init__.py +0 -5
  279. mirascope/core/costs/_anthropic_calculate_cost.py +0 -219
  280. mirascope/core/costs/_azure_calculate_cost.py +0 -11
  281. mirascope/core/costs/_bedrock_calculate_cost.py +0 -15
  282. mirascope/core/costs/_cohere_calculate_cost.py +0 -44
  283. mirascope/core/costs/_gemini_calculate_cost.py +0 -67
  284. mirascope/core/costs/_google_calculate_cost.py +0 -427
  285. mirascope/core/costs/_groq_calculate_cost.py +0 -156
  286. mirascope/core/costs/_litellm_calculate_cost.py +0 -11
  287. mirascope/core/costs/_mistral_calculate_cost.py +0 -64
  288. mirascope/core/costs/_openai_calculate_cost.py +0 -416
  289. mirascope/core/costs/_vertex_calculate_cost.py +0 -67
  290. mirascope/core/costs/_xai_calculate_cost.py +0 -104
  291. mirascope/core/costs/calculate_cost.py +0 -86
  292. mirascope/core/gemini/__init__.py +0 -40
  293. mirascope/core/gemini/_call.py +0 -67
  294. mirascope/core/gemini/_call_kwargs.py +0 -12
  295. mirascope/core/gemini/_utils/__init__.py +0 -14
  296. mirascope/core/gemini/_utils/_convert_common_call_params.py +0 -39
  297. mirascope/core/gemini/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -23
  298. mirascope/core/gemini/_utils/_convert_message_params.py +0 -156
  299. mirascope/core/gemini/_utils/_get_json_output.py +0 -35
  300. mirascope/core/gemini/_utils/_handle_stream.py +0 -33
  301. mirascope/core/gemini/_utils/_message_param_converter.py +0 -209
  302. mirascope/core/gemini/_utils/_setup_call.py +0 -149
  303. mirascope/core/gemini/call_params.py +0 -52
  304. mirascope/core/gemini/call_response.py +0 -216
  305. mirascope/core/gemini/call_response_chunk.py +0 -100
  306. mirascope/core/gemini/dynamic_config.py +0 -26
  307. mirascope/core/gemini/stream.py +0 -120
  308. mirascope/core/gemini/tool.py +0 -104
  309. mirascope/core/google/__init__.py +0 -29
  310. mirascope/core/google/_call.py +0 -67
  311. mirascope/core/google/_call_kwargs.py +0 -13
  312. mirascope/core/google/_utils/__init__.py +0 -14
  313. mirascope/core/google/_utils/_convert_common_call_params.py +0 -38
  314. mirascope/core/google/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -27
  315. mirascope/core/google/_utils/_convert_message_params.py +0 -297
  316. mirascope/core/google/_utils/_get_json_output.py +0 -37
  317. mirascope/core/google/_utils/_handle_stream.py +0 -58
  318. mirascope/core/google/_utils/_message_param_converter.py +0 -200
  319. mirascope/core/google/_utils/_setup_call.py +0 -201
  320. mirascope/core/google/_utils/_validate_media_type.py +0 -58
  321. mirascope/core/google/call_params.py +0 -22
  322. mirascope/core/google/call_response.py +0 -255
  323. mirascope/core/google/call_response_chunk.py +0 -135
  324. mirascope/core/google/dynamic_config.py +0 -26
  325. mirascope/core/google/stream.py +0 -199
  326. mirascope/core/google/tool.py +0 -146
  327. mirascope/core/groq/__init__.py +0 -30
  328. mirascope/core/groq/_call.py +0 -67
  329. mirascope/core/groq/_call_kwargs.py +0 -13
  330. mirascope/core/groq/_utils/__init__.py +0 -14
  331. mirascope/core/groq/_utils/_convert_common_call_params.py +0 -26
  332. mirascope/core/groq/_utils/_convert_message_params.py +0 -112
  333. mirascope/core/groq/_utils/_get_json_output.py +0 -27
  334. mirascope/core/groq/_utils/_handle_stream.py +0 -123
  335. mirascope/core/groq/_utils/_message_param_converter.py +0 -89
  336. mirascope/core/groq/_utils/_setup_call.py +0 -132
  337. mirascope/core/groq/call_params.py +0 -52
  338. mirascope/core/groq/call_response.py +0 -213
  339. mirascope/core/groq/call_response_chunk.py +0 -104
  340. mirascope/core/groq/dynamic_config.py +0 -29
  341. mirascope/core/groq/py.typed +0 -0
  342. mirascope/core/groq/stream.py +0 -135
  343. mirascope/core/groq/tool.py +0 -80
  344. mirascope/core/litellm/__init__.py +0 -28
  345. mirascope/core/litellm/_call.py +0 -67
  346. mirascope/core/litellm/_utils/__init__.py +0 -5
  347. mirascope/core/litellm/_utils/_setup_call.py +0 -109
  348. mirascope/core/litellm/call_params.py +0 -10
  349. mirascope/core/litellm/call_response.py +0 -24
  350. mirascope/core/litellm/call_response_chunk.py +0 -14
  351. mirascope/core/litellm/dynamic_config.py +0 -8
  352. mirascope/core/litellm/py.typed +0 -0
  353. mirascope/core/litellm/stream.py +0 -86
  354. mirascope/core/litellm/tool.py +0 -13
  355. mirascope/core/mistral/__init__.py +0 -36
  356. mirascope/core/mistral/_call.py +0 -65
  357. mirascope/core/mistral/_call_kwargs.py +0 -19
  358. mirascope/core/mistral/_utils/__init__.py +0 -14
  359. mirascope/core/mistral/_utils/_convert_common_call_params.py +0 -24
  360. mirascope/core/mistral/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -22
  361. mirascope/core/mistral/_utils/_convert_message_params.py +0 -122
  362. mirascope/core/mistral/_utils/_get_json_output.py +0 -34
  363. mirascope/core/mistral/_utils/_handle_stream.py +0 -139
  364. mirascope/core/mistral/_utils/_message_param_converter.py +0 -176
  365. mirascope/core/mistral/_utils/_setup_call.py +0 -164
  366. mirascope/core/mistral/call_params.py +0 -36
  367. mirascope/core/mistral/call_response.py +0 -205
  368. mirascope/core/mistral/call_response_chunk.py +0 -105
  369. mirascope/core/mistral/dynamic_config.py +0 -33
  370. mirascope/core/mistral/py.typed +0 -0
  371. mirascope/core/mistral/stream.py +0 -120
  372. mirascope/core/mistral/tool.py +0 -81
  373. mirascope/core/openai/__init__.py +0 -31
  374. mirascope/core/openai/_call.py +0 -67
  375. mirascope/core/openai/_call_kwargs.py +0 -13
  376. mirascope/core/openai/_utils/__init__.py +0 -14
  377. mirascope/core/openai/_utils/_convert_common_call_params.py +0 -26
  378. mirascope/core/openai/_utils/_convert_message_params.py +0 -148
  379. mirascope/core/openai/_utils/_get_json_output.py +0 -31
  380. mirascope/core/openai/_utils/_handle_stream.py +0 -138
  381. mirascope/core/openai/_utils/_message_param_converter.py +0 -105
  382. mirascope/core/openai/_utils/_setup_call.py +0 -155
  383. mirascope/core/openai/call_params.py +0 -92
  384. mirascope/core/openai/call_response.py +0 -273
  385. mirascope/core/openai/call_response_chunk.py +0 -139
  386. mirascope/core/openai/dynamic_config.py +0 -34
  387. mirascope/core/openai/py.typed +0 -0
  388. mirascope/core/openai/stream.py +0 -185
  389. mirascope/core/openai/tool.py +0 -101
  390. mirascope/core/py.typed +0 -0
  391. mirascope/core/vertex/__init__.py +0 -45
  392. mirascope/core/vertex/_call.py +0 -62
  393. mirascope/core/vertex/_call_kwargs.py +0 -12
  394. mirascope/core/vertex/_utils/__init__.py +0 -14
  395. mirascope/core/vertex/_utils/_convert_common_call_params.py +0 -37
  396. mirascope/core/vertex/_utils/_convert_finish_reason_to_common_finish_reasons.py +0 -23
  397. mirascope/core/vertex/_utils/_convert_message_params.py +0 -171
  398. mirascope/core/vertex/_utils/_get_json_output.py +0 -36
  399. mirascope/core/vertex/_utils/_handle_stream.py +0 -33
  400. mirascope/core/vertex/_utils/_message_param_converter.py +0 -133
  401. mirascope/core/vertex/_utils/_setup_call.py +0 -160
  402. mirascope/core/vertex/call_params.py +0 -24
  403. mirascope/core/vertex/call_response.py +0 -206
  404. mirascope/core/vertex/call_response_chunk.py +0 -99
  405. mirascope/core/vertex/dynamic_config.py +0 -28
  406. mirascope/core/vertex/stream.py +0 -119
  407. mirascope/core/vertex/tool.py +0 -101
  408. mirascope/core/xai/__init__.py +0 -28
  409. mirascope/core/xai/_call.py +0 -67
  410. mirascope/core/xai/_utils/__init__.py +0 -5
  411. mirascope/core/xai/_utils/_setup_call.py +0 -113
  412. mirascope/core/xai/call_params.py +0 -10
  413. mirascope/core/xai/call_response.py +0 -16
  414. mirascope/core/xai/call_response_chunk.py +0 -14
  415. mirascope/core/xai/dynamic_config.py +0 -8
  416. mirascope/core/xai/py.typed +0 -0
  417. mirascope/core/xai/stream.py +0 -57
  418. mirascope/core/xai/tool.py +0 -13
  419. mirascope/experimental/graphs/__init__.py +0 -5
  420. mirascope/integrations/__init__.py +0 -16
  421. mirascope/integrations/_middleware_factory.py +0 -403
  422. mirascope/integrations/langfuse/__init__.py +0 -3
  423. mirascope/integrations/langfuse/_utils.py +0 -114
  424. mirascope/integrations/langfuse/_with_langfuse.py +0 -70
  425. mirascope/integrations/logfire/__init__.py +0 -3
  426. mirascope/integrations/logfire/_utils.py +0 -225
  427. mirascope/integrations/logfire/_with_logfire.py +0 -63
  428. mirascope/integrations/otel/__init__.py +0 -10
  429. mirascope/integrations/otel/_utils.py +0 -270
  430. mirascope/integrations/otel/_with_hyperdx.py +0 -60
  431. mirascope/integrations/otel/_with_otel.py +0 -59
  432. mirascope/integrations/tenacity.py +0 -14
  433. mirascope/llm/_call.py +0 -401
  434. mirascope/llm/_context.py +0 -384
  435. mirascope/llm/_override.py +0 -3639
  436. mirascope/llm/_protocols.py +0 -500
  437. mirascope/llm/_response_metaclass.py +0 -31
  438. mirascope/llm/call_response.py +0 -158
  439. mirascope/llm/call_response_chunk.py +0 -66
  440. mirascope/llm/stream.py +0 -162
  441. mirascope/llm/tool.py +0 -64
  442. mirascope/mcp/__init__.py +0 -7
  443. mirascope/mcp/_utils.py +0 -288
  444. mirascope/mcp/client.py +0 -167
  445. mirascope/mcp/server.py +0 -356
  446. mirascope/mcp/tools.py +0 -110
  447. mirascope/py.typed +0 -0
  448. mirascope/retries/__init__.py +0 -11
  449. mirascope/retries/fallback.py +0 -131
  450. mirascope/retries/tenacity.py +0 -50
  451. mirascope/tools/__init__.py +0 -37
  452. mirascope/tools/base.py +0 -98
  453. mirascope/tools/system/__init__.py +0 -0
  454. mirascope/tools/system/_docker_operation.py +0 -166
  455. mirascope/tools/system/_file_system.py +0 -267
  456. mirascope/tools/web/__init__.py +0 -0
  457. mirascope/tools/web/_duckduckgo.py +0 -111
  458. mirascope/tools/web/_httpx.py +0 -125
  459. mirascope/tools/web/_parse_url_content.py +0 -94
  460. mirascope/tools/web/_requests.py +0 -54
  461. mirascope/v0/__init__.py +0 -43
  462. mirascope/v0/anthropic.py +0 -54
  463. mirascope/v0/base/__init__.py +0 -12
  464. mirascope/v0/base/calls.py +0 -118
  465. mirascope/v0/base/extractors.py +0 -122
  466. mirascope/v0/base/ops_utils.py +0 -207
  467. mirascope/v0/base/prompts.py +0 -48
  468. mirascope/v0/base/types.py +0 -14
  469. mirascope/v0/base/utils.py +0 -21
  470. mirascope/v0/openai.py +0 -54
  471. mirascope-1.25.7.dist-info/METADATA +0 -169
  472. mirascope-1.25.7.dist-info/RECORD +0 -378
  473. {mirascope-1.25.7.dist-info → mirascope-2.0.0a0.dist-info}/WHEEL +0 -0
  474. {mirascope-1.25.7.dist-info → mirascope-2.0.0a0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,206 @@
1
+ """The `Image` content class."""
2
+
3
+ import base64
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+ from typing import Literal, get_args
7
+
8
+ import httpx
9
+
10
+ ImageMimeType = Literal[
11
+ "image/png",
12
+ "image/jpeg",
13
+ "image/webp",
14
+ "image/gif",
15
+ "image/heic",
16
+ "image/heif",
17
+ ] # TODO: add e2e tests for every supported type
18
+
19
+ MIME_TYPES = get_args(ImageMimeType)
20
+
21
+ # Maximum image size in bytes (20MB)
22
+ MAX_IMAGE_SIZE = 20 * 1024 * 1024
23
+
24
+
25
+ def infer_image_type(image_data: bytes) -> ImageMimeType:
26
+ """Get the MIME type of an image from its raw bytes.
27
+
28
+ Raises:
29
+ ValueError: If the image type cannot be determined or data is too small
30
+ """
31
+ if len(image_data) < 12:
32
+ raise ValueError("Image data too small to determine type (minimum 12 bytes)")
33
+
34
+ if image_data.startswith(b"\xff\xd8\xff"):
35
+ return "image/jpeg"
36
+ elif image_data.startswith(b"\x89PNG\r\n\x1a\n"):
37
+ return "image/png"
38
+ elif image_data.startswith(b"GIF87a") or image_data.startswith(b"GIF89a"):
39
+ return "image/gif"
40
+ elif image_data.startswith(b"RIFF") and image_data[8:12] == b"WEBP":
41
+ return "image/webp"
42
+ elif image_data[4:12] in (
43
+ b"ftypmif1",
44
+ b"ftypmsf1",
45
+ b"ftypheic",
46
+ b"ftypheix",
47
+ b"ftyphevc",
48
+ b"ftyphevx",
49
+ ):
50
+ subtype = image_data[8:12]
51
+ if subtype in (b"heic", b"heix"):
52
+ return "image/heic"
53
+ elif subtype in (b"mif1", b"msf1", b"hevc", b"hevx"):
54
+ return "image/heif"
55
+ raise ValueError("Unsupported image type")
56
+
57
+
58
+ @dataclass(kw_only=True)
59
+ class Base64ImageSource:
60
+ """Image data represented as a base64 encoded string."""
61
+
62
+ type: Literal["base64_image_source"]
63
+
64
+ data: str
65
+ """The image data, as a base64 encoded string."""
66
+
67
+ mime_type: ImageMimeType
68
+ """The mime type of the image (e.g. image/png)."""
69
+
70
+
71
+ def _process_image_bytes(data: bytes, max_size: int) -> Base64ImageSource:
72
+ """Validate and process image bytes into a Base64ImageSource.
73
+
74
+ Args:
75
+ data: Raw image bytes
76
+ max_size: Maximum allowed size in bytes
77
+
78
+ Returns:
79
+ A Base64ImageSource with validated and encoded data
80
+
81
+ Raises:
82
+ ValueError: If data size exceeds max_size
83
+ """
84
+ size = len(data)
85
+ if size > max_size:
86
+ raise ValueError(
87
+ f"Image size ({size} bytes) exceeds maximum allowed size ({max_size} bytes)"
88
+ )
89
+
90
+ mime_type = infer_image_type(data)
91
+ encoded_data = base64.b64encode(data).decode("utf-8")
92
+ return Base64ImageSource(
93
+ type="base64_image_source",
94
+ data=encoded_data,
95
+ mime_type=mime_type,
96
+ )
97
+
98
+
99
+ @dataclass(kw_only=True)
100
+ class URLImageSource:
101
+ """Image data referenced via external URL."""
102
+
103
+ type: Literal["url_image_source"]
104
+
105
+ url: str
106
+ """The url of the image (e.g. https://example.com/sazed.png)."""
107
+
108
+
109
+ @dataclass(kw_only=True)
110
+ class Image:
111
+ """Image content for a message.
112
+
113
+ Images can be included in messages to provide visual context. This can be
114
+ used for both input (e.g., user uploading an image) and output (e.g., model
115
+ generating an image).
116
+ """
117
+
118
+ type: Literal["image"] = "image"
119
+
120
+ source: Base64ImageSource | URLImageSource
121
+
122
+ @classmethod
123
+ def from_url(cls, url: str) -> "Image":
124
+ """Create an `Image` reference from a URL, without downloading it.
125
+
126
+ Args:
127
+ url: The URL of the image
128
+
129
+ Returns:
130
+ An `Image` with a `URLImageSource`
131
+ """
132
+ return cls(source=URLImageSource(type="url_image_source", url=url))
133
+
134
+ @classmethod
135
+ def download(cls, url: str, *, max_size: int = MAX_IMAGE_SIZE) -> "Image":
136
+ """Download and encode an image from a URL.
137
+
138
+ Args:
139
+ url: The URL of the image to download
140
+ max_size: Maximum allowed image size in bytes (default: 20MB)
141
+
142
+ Returns:
143
+ An `Image` with a `Base64ImageSource`
144
+
145
+ Raises:
146
+ ValueError: If the downloaded image exceeds max_size
147
+ """
148
+ response = httpx.get(url, follow_redirects=True)
149
+ response.raise_for_status()
150
+ return cls(source=_process_image_bytes(response.content, max_size))
151
+
152
+ @classmethod
153
+ async def download_async(
154
+ cls, url: str, *, max_size: int = MAX_IMAGE_SIZE
155
+ ) -> "Image":
156
+ """Asynchronously download and encode an image from a URL.
157
+
158
+ Args:
159
+ url: The URL of the image to download
160
+ max_size: Maximum allowed image size in bytes (default: 20MB)
161
+
162
+ Returns:
163
+ An `Image` with a `Base64ImageSource`
164
+
165
+ Raises:
166
+ ValueError: If the downloaded image exceeds max_size
167
+ """
168
+ async with httpx.AsyncClient() as client:
169
+ response = await client.get(url, follow_redirects=True)
170
+ response.raise_for_status()
171
+ return cls(source=_process_image_bytes(response.content, max_size))
172
+
173
+ @classmethod
174
+ def from_file(cls, file_path: str, *, max_size: int = MAX_IMAGE_SIZE) -> "Image":
175
+ """Create an `Image` from a file path.
176
+
177
+ Args:
178
+ file_path: Path to the image file
179
+ max_size: Maximum allowed image size in bytes (default: 20MB)
180
+
181
+ Raises:
182
+ FileNotFoundError: If the file does not exist
183
+ ValueError: If the file size exceeds max_size
184
+ """
185
+ path = Path(file_path)
186
+ file_size = path.stat().st_size
187
+ if file_size > max_size:
188
+ raise ValueError(
189
+ f"Image file size ({file_size} bytes) exceeds maximum allowed size ({max_size} bytes)"
190
+ )
191
+ with open(path, "rb") as f:
192
+ image_bytes = f.read()
193
+ return cls(source=_process_image_bytes(image_bytes, max_size))
194
+
195
+ @classmethod
196
+ def from_bytes(cls, data: bytes, *, max_size: int = MAX_IMAGE_SIZE) -> "Image":
197
+ """Create an `Image` from raw bytes.
198
+
199
+ Args:
200
+ data: Raw image bytes
201
+ max_size: Maximum allowed image size in bytes (default: 20MB)
202
+
203
+ Raises:
204
+ ValueError: If the data size exceeds max_size
205
+ """
206
+ return cls(source=_process_image_bytes(data, max_size))
@@ -0,0 +1,47 @@
1
+ """The `Text` content class."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Literal
5
+
6
+
7
+ @dataclass(kw_only=True)
8
+ class Text:
9
+ """Text content for a message."""
10
+
11
+ type: Literal["text"] = "text"
12
+
13
+ text: str
14
+ """The text content."""
15
+
16
+
17
+ @dataclass(kw_only=True)
18
+ class TextStartChunk:
19
+ """Represents the start of a text chunk stream."""
20
+
21
+ type: Literal["text_start_chunk"] = "text_start_chunk"
22
+
23
+ content_type: Literal["text"] = "text"
24
+ """The type of content reconstructed by this chunk."""
25
+
26
+
27
+ @dataclass(kw_only=True)
28
+ class TextChunk:
29
+ """Represents an incremental text chunk in a stream."""
30
+
31
+ type: Literal["text_chunk"] = "text_chunk"
32
+
33
+ content_type: Literal["text"] = "text"
34
+ """The type of content reconstructed by this chunk."""
35
+
36
+ delta: str
37
+ """The incremental text added in this chunk."""
38
+
39
+
40
+ @dataclass(kw_only=True)
41
+ class TextEndChunk:
42
+ """Represents the end of a text chunk stream."""
43
+
44
+ type: Literal["text_end_chunk"] = "text_end_chunk"
45
+
46
+ content_type: Literal["text"] = "text"
47
+ """The type of content reconstructed by this chunk."""
@@ -0,0 +1,58 @@
1
+ """The `Thought` content class and its streaming chunks.
2
+
3
+ The `Thought` is an interpretable / readable summary of the models' reasoning
4
+ process. This may be a summary generated by a summarizer model that is distinct from
5
+ the reasoning model, or for some models it may be the raw output of the model's thinking
6
+ process.
7
+ """
8
+
9
+ from dataclasses import dataclass
10
+ from typing import Literal
11
+
12
+
13
+ @dataclass(kw_only=True)
14
+ class Thought:
15
+ """Thinking content for a message.
16
+
17
+ Represents the thinking or thought process of the assistant. These generally are
18
+ summaries of the model's reasoning process, rather than the direct reasoning tokens,
19
+ although this behavior is model and provider specific.
20
+ """
21
+
22
+ type: Literal["thought"] = "thought"
23
+
24
+ thought: str
25
+ """The thoughts or reasoning of the assistant."""
26
+
27
+
28
+ @dataclass(kw_only=True)
29
+ class ThoughtStartChunk:
30
+ """Represents the start of a thought chunk stream."""
31
+
32
+ type: Literal["thought_start_chunk"] = "thought_start_chunk"
33
+
34
+ content_type: Literal["thought"] = "thought"
35
+ """The type of content reconstructed by this chunk."""
36
+
37
+
38
+ @dataclass(kw_only=True)
39
+ class ThoughtChunk:
40
+ """Represents an incremental thought chunk in a stream."""
41
+
42
+ type: Literal["thought_chunk"] = "thought_chunk"
43
+
44
+ content_type: Literal["thought"] = "thought"
45
+ """The type of content reconstructed by this chunk."""
46
+
47
+ delta: str
48
+ """The incremental thoughts added in this chunk."""
49
+
50
+
51
+ @dataclass(kw_only=True)
52
+ class ThoughtEndChunk:
53
+ """Represents the end of a thought chunk stream."""
54
+
55
+ type: Literal["thought_end_chunk"] = "thought_end_chunk"
56
+
57
+ content_type: Literal["thought"] = "thought"
58
+ """The type of content reconstructed by this chunk."""
@@ -0,0 +1,63 @@
1
+ """The `ToolCall` content class."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Literal
5
+
6
+
7
+ @dataclass(kw_only=True)
8
+ class ToolCall:
9
+ """Tool call content for a message.
10
+
11
+ Represents a request from the assistant to call a tool. This is part of
12
+ an assistant message's content.
13
+ """
14
+
15
+ type: Literal["tool_call"] = "tool_call"
16
+
17
+ id: str
18
+ """A unique identifier for this tool call."""
19
+
20
+ name: str
21
+ """The name of the tool to call."""
22
+
23
+ args: str
24
+ """The arguments to pass to the tool, stored as stringified json."""
25
+
26
+
27
+ @dataclass(kw_only=True)
28
+ class ToolCallStartChunk:
29
+ """Represents the start of a tool call chunk stream."""
30
+
31
+ type: Literal["tool_call_start_chunk"] = "tool_call_start_chunk"
32
+
33
+ content_type: Literal["tool_call"] = "tool_call"
34
+ """The type of content reconstructed by this chunk."""
35
+
36
+ id: str
37
+ """A unique identifier for this tool call."""
38
+
39
+ name: str
40
+ """The name of the tool to call."""
41
+
42
+
43
+ @dataclass(kw_only=True)
44
+ class ToolCallChunk:
45
+ """Represents an incremental tool call chunk in a stream."""
46
+
47
+ type: Literal["tool_call_chunk"] = "tool_call_chunk"
48
+
49
+ content_type: Literal["tool_call"] = "tool_call"
50
+ """The type of content reconstructed by this chunk."""
51
+
52
+ delta: str
53
+ """The incremental json args added in this chunk."""
54
+
55
+
56
+ @dataclass(kw_only=True)
57
+ class ToolCallEndChunk:
58
+ """Represents the end of a tool call chunk stream."""
59
+
60
+ type: Literal["tool_call_end_chunk"] = "tool_call_end_chunk"
61
+
62
+ content_type: Literal["tool_call"] = "tool_call"
63
+ """The type of content reconstructed by this chunk."""
@@ -0,0 +1,26 @@
1
+ """The `ToolOutput` content class."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Generic, Literal
5
+
6
+ from ..types import JsonableT
7
+
8
+
9
+ @dataclass(kw_only=True)
10
+ class ToolOutput(Generic[JsonableT]):
11
+ """Tool output content for a message.
12
+
13
+ Represents the output from a tool call. This is part of a user message's
14
+ content, typically following a tool call from the assistant.
15
+ """
16
+
17
+ type: Literal["tool_output"] = "tool_output"
18
+
19
+ id: str
20
+ """The ID of the tool call that this output is for."""
21
+
22
+ name: str
23
+ """The name of the tool that created this output."""
24
+
25
+ value: JsonableT
26
+ """The output value from the tool call."""
@@ -0,0 +1,6 @@
1
+ """The Context module for providing context to LLM calls during generation."""
2
+
3
+ from . import _utils
4
+ from .context import Context, DepsT
5
+
6
+ __all__ = ["Context", "DepsT", "_utils"]
@@ -0,0 +1,28 @@
1
+ import inspect
2
+ from collections.abc import Callable
3
+ from typing import get_origin
4
+
5
+ from .context import Context
6
+
7
+
8
+ def first_param_is_context(fn: Callable) -> bool:
9
+ """Returns whether the first argument to a function is `ctx: Context`.
10
+
11
+ Also returns true if the first argument is a subclass of `Context`.
12
+ Skips the first argument if it is `self` or `cls`.
13
+ """
14
+ sig = inspect.signature(fn)
15
+ params = list(sig.parameters.values())
16
+ if not params:
17
+ return False
18
+
19
+ if params[0].name in ("self", "cls") and len(params) > 1:
20
+ first_param = params[1]
21
+ else:
22
+ first_param = params[0]
23
+
24
+ type_is_context = get_origin(first_param.annotation) is Context
25
+ subclass_of_context = isinstance(first_param.annotation, type) and issubclass(
26
+ first_param.annotation, Context
27
+ )
28
+ return first_param.name == "ctx" and (type_is_context or subclass_of_context)
@@ -0,0 +1,24 @@
1
+ """Context for LLM calls."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Generic
5
+ from typing_extensions import TypeVar
6
+
7
+ DepsT = TypeVar("DepsT")
8
+ """Type variable for dependency injection in `llm.Context`.
9
+
10
+ This TypeVar is used throughout the LLM module to represent the type of
11
+ dependencies that are present in `llm.Context`.
12
+ """
13
+
14
+
15
+ @dataclass(kw_only=True)
16
+ class Context(Generic[DepsT]):
17
+ """Context for LLM calls.
18
+
19
+ This class provides a context for LLM calls, including the model,
20
+ parameters, and any dependencies needed for the call.
21
+ """
22
+
23
+ deps: DepsT
24
+ """The dependencies needed for a call."""
@@ -0,0 +1,105 @@
1
+ """Mirascope exception hierarchy for unified error handling across providers."""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from .clients import ModelId, Provider
7
+ from .formatting import FormattingMode
8
+
9
+
10
+ class MirascopeError(Exception):
11
+ """Base exception for all Mirascope errors."""
12
+
13
+ original_exception: Exception | None
14
+
15
+
16
+ class APIError(MirascopeError):
17
+ """Base class for API-related errors."""
18
+
19
+ status_code: int | None
20
+
21
+
22
+ class ConnectionError(MirascopeError):
23
+ """Raised when unable to connect to the API (network issues, timeouts)."""
24
+
25
+
26
+ class AuthenticationError(APIError):
27
+ """Raised for authentication failures (401, invalid API keys)."""
28
+
29
+
30
+ class PermissionError(APIError):
31
+ """Raised for permission/authorization failures (403)."""
32
+
33
+
34
+ class BadRequestError(APIError):
35
+ """Raised for malformed requests (400, 422)."""
36
+
37
+
38
+ class NotFoundError(APIError):
39
+ """Raised when requested resource is not found (404)."""
40
+
41
+
42
+ class ToolNotFoundError(MirascopeError):
43
+ """Raised if a tool_call cannot be converted to any corresponding tool."""
44
+
45
+
46
+ class FeatureNotSupportedError(MirascopeError):
47
+ """Raised if a Mirascope feature is unsupported by chosen provider.
48
+
49
+ If compatibility is model-specific, then `model_id` should be specified.
50
+ If the feature is not supported by the provider at all, then it may be `None`."""
51
+
52
+ provider: "Provider"
53
+ model_id: "ModelId | None"
54
+ feature: str
55
+
56
+ def __init__(
57
+ self,
58
+ feature: str,
59
+ provider: "Provider",
60
+ model_id: "ModelId | None" = None,
61
+ message: str | None = None,
62
+ ) -> None:
63
+ if message is None:
64
+ model_msg = f" for model '{model_id}'" if model_id is not None else ""
65
+ message = f"Feature '{feature}' is not supported by provider '{provider}'{model_msg}"
66
+ super().__init__(message)
67
+ self.feature = feature
68
+ self.provider = provider
69
+ self.model_id = model_id
70
+
71
+
72
+ class FormattingModeNotSupportedError(FeatureNotSupportedError):
73
+ """Raised when trying to use a formatting mode that is not supported by the chosen model."""
74
+
75
+ formatting_mode: "FormattingMode"
76
+
77
+ def __init__(
78
+ self,
79
+ formatting_mode: "FormattingMode",
80
+ provider: "Provider",
81
+ model_id: "ModelId | None" = None,
82
+ message: str | None = None,
83
+ ) -> None:
84
+ if message is None:
85
+ model_msg = f" for model '{model_id}'" if model_id is not None else ""
86
+ message = f"Formatting mode '{formatting_mode}' is not supported by provider '{provider}'{model_msg}"
87
+ super().__init__(
88
+ feature=f"formatting_mode:{formatting_mode}",
89
+ provider=provider,
90
+ model_id=model_id,
91
+ message=message,
92
+ )
93
+ self.formatting_mode = formatting_mode
94
+
95
+
96
+ class RateLimitError(APIError):
97
+ """Raised when rate limits are exceeded (429)."""
98
+
99
+
100
+ class ServerError(APIError):
101
+ """Raised for server-side errors (500+)."""
102
+
103
+
104
+ class TimeoutError(MirascopeError):
105
+ """Raised when requests timeout or deadline exceeded."""
@@ -0,0 +1,22 @@
1
+ """Response formatting interfaces for structuring LLM outputs.
2
+
3
+ This module provides a way to define structured output formats for LLM responses.
4
+ The `@format` decorator can be applied to classes to specify how LLM
5
+ outputs should be structured and parsed.
6
+ """
7
+
8
+ from .format import format, resolve_format
9
+ from .from_call_args import FromCallArgs
10
+ from .partial import Partial
11
+ from .types import Format, FormattableT, FormattingMode
12
+
13
+ __all__ = [
14
+ "Format",
15
+ "FormattableT",
16
+ "FormattableT",
17
+ "FormattingMode",
18
+ "FromCallArgs",
19
+ "Partial",
20
+ "format",
21
+ "resolve_format",
22
+ ]
@@ -0,0 +1,74 @@
1
+ """Utilities for the formatting module."""
2
+
3
+ import inspect
4
+ import json
5
+
6
+ from ..tools import FORMAT_TOOL_NAME, ToolParameterSchema, ToolSchema
7
+ from .types import Format, FormattableT, FormattingMode
8
+
9
+ TOOL_MODE_INSTRUCTIONS = f"""Always respond to the user's query using the {FORMAT_TOOL_NAME} tool for structured output."""
10
+
11
+
12
+ JSON_MODE_INSTRUCTIONS = (
13
+ "Respond only with valid JSON that matches this exact schema:\n{json_schema}"
14
+ )
15
+
16
+
17
+ def default_formatting_instructions(
18
+ schema: dict[str, object], mode: FormattingMode
19
+ ) -> str | None:
20
+ """Generate formatting instructions for the given mode and format info."""
21
+
22
+ if mode == "tool":
23
+ return TOOL_MODE_INSTRUCTIONS
24
+ elif mode == "json":
25
+ json_schema = json.dumps(schema, indent=2)
26
+ instructions = JSON_MODE_INSTRUCTIONS.format(json_schema=json_schema)
27
+ return inspect.cleandoc(instructions)
28
+
29
+
30
+ def create_tool_schema(format: Format[FormattableT]) -> ToolSchema:
31
+ """Convert a `Format` to a `ToolSchema` for format parsing.
32
+
33
+ Args:
34
+ format: The `Format` instance containing schema and metadata
35
+
36
+ Returns:
37
+ `ToolSchema` for the format tool
38
+ """
39
+
40
+ schema_dict = format.schema.copy()
41
+ schema_dict["type"] = "object"
42
+
43
+ properties = schema_dict.get("properties")
44
+ if not properties or not isinstance(properties, dict):
45
+ properties = {} # pragma: no cover
46
+ required = list(properties.keys())
47
+
48
+ description = (
49
+ f"Use this tool to extract data in {format.name} format for a final response."
50
+ )
51
+ if format.description:
52
+ description += "\n" + format.description
53
+
54
+ parameters = ToolParameterSchema(
55
+ properties=properties,
56
+ required=required,
57
+ additionalProperties=False,
58
+ )
59
+ if "$defs" in schema_dict and isinstance(schema_dict["$defs"], dict):
60
+ parameters.defs = schema_dict["$defs"]
61
+
62
+ def _unused_format_fn() -> None:
63
+ raise TypeError(
64
+ "Format tool function should not be called."
65
+ ) # pragma: no cover
66
+
67
+ tool_schema = ToolSchema.__new__(ToolSchema)
68
+ tool_schema.fn = _unused_format_fn
69
+ tool_schema.name = FORMAT_TOOL_NAME
70
+ tool_schema.description = description
71
+ tool_schema.parameters = parameters
72
+ tool_schema.strict = True
73
+
74
+ return tool_schema