mirascope 2.0.0__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 (442) hide show
  1. mirascope/__init__.py +2 -11
  2. mirascope/graphs/__init__.py +22 -0
  3. mirascope/graphs/finite_state_machine.py +625 -0
  4. mirascope/llm/__init__.py +16 -101
  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 +1 -2
  10. mirascope/llm/calls/base_call.py +33 -0
  11. mirascope/llm/calls/calls.py +58 -84
  12. mirascope/llm/calls/decorator.py +120 -140
  13. mirascope/llm/clients/__init__.py +34 -0
  14. mirascope/llm/clients/anthropic/__init__.py +11 -0
  15. mirascope/llm/{providers/openai/completions → clients/anthropic}/_utils/__init__.py +0 -2
  16. mirascope/llm/{providers → clients}/anthropic/_utils/decode.py +22 -66
  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/{providers → clients}/base/__init__.py +5 -4
  21. mirascope/llm/{providers → clients}/base/_utils.py +17 -78
  22. mirascope/llm/{providers/base/base_provider.py → clients/base/client.py} +145 -468
  23. mirascope/llm/{models → clients/base}/params.py +37 -16
  24. mirascope/llm/clients/google/__init__.py +6 -0
  25. mirascope/llm/{providers/openai/responses → clients/google}/_utils/__init__.py +0 -2
  26. mirascope/llm/{providers → clients}/google/_utils/decode.py +22 -98
  27. mirascope/llm/{providers → clients}/google/_utils/encode.py +46 -168
  28. mirascope/llm/clients/google/clients.py +853 -0
  29. mirascope/llm/clients/google/model_ids.py +15 -0
  30. mirascope/llm/clients/openai/__init__.py +25 -0
  31. mirascope/llm/clients/openai/completions/__init__.py +9 -0
  32. mirascope/llm/{providers/google → clients/openai/completions}/_utils/__init__.py +0 -4
  33. mirascope/llm/{providers → clients}/openai/completions/_utils/decode.py +9 -74
  34. mirascope/llm/{providers → clients}/openai/completions/_utils/encode.py +52 -70
  35. mirascope/llm/clients/openai/completions/_utils/model_features.py +81 -0
  36. mirascope/llm/clients/openai/completions/clients.py +833 -0
  37. mirascope/llm/clients/openai/completions/model_ids.py +8 -0
  38. mirascope/llm/clients/openai/responses/__init__.py +9 -0
  39. mirascope/llm/clients/openai/responses/_utils/__init__.py +13 -0
  40. mirascope/llm/{providers → clients}/openai/responses/_utils/decode.py +14 -80
  41. mirascope/llm/{providers → clients}/openai/responses/_utils/encode.py +41 -92
  42. mirascope/llm/clients/openai/responses/_utils/model_features.py +87 -0
  43. mirascope/llm/clients/openai/responses/clients.py +832 -0
  44. mirascope/llm/clients/openai/responses/model_ids.py +8 -0
  45. mirascope/llm/clients/openai/shared/__init__.py +7 -0
  46. mirascope/llm/clients/openai/shared/_utils.py +55 -0
  47. mirascope/llm/clients/providers.py +175 -0
  48. mirascope/llm/content/__init__.py +2 -3
  49. mirascope/llm/content/tool_call.py +0 -6
  50. mirascope/llm/content/tool_output.py +5 -22
  51. mirascope/llm/context/_utils.py +6 -19
  52. mirascope/llm/exceptions.py +43 -298
  53. mirascope/llm/formatting/__init__.py +2 -19
  54. mirascope/llm/formatting/_utils.py +74 -0
  55. mirascope/llm/formatting/format.py +30 -219
  56. mirascope/llm/formatting/from_call_args.py +2 -2
  57. mirascope/llm/formatting/partial.py +7 -80
  58. mirascope/llm/formatting/types.py +64 -21
  59. mirascope/llm/mcp/__init__.py +2 -2
  60. mirascope/llm/mcp/client.py +118 -0
  61. mirascope/llm/messages/__init__.py +0 -3
  62. mirascope/llm/messages/message.py +5 -13
  63. mirascope/llm/models/__init__.py +2 -7
  64. mirascope/llm/models/models.py +139 -315
  65. mirascope/llm/prompts/__init__.py +12 -13
  66. mirascope/llm/prompts/_utils.py +43 -14
  67. mirascope/llm/prompts/decorator.py +204 -144
  68. mirascope/llm/prompts/protocols.py +59 -25
  69. mirascope/llm/responses/__init__.py +1 -9
  70. mirascope/llm/responses/_utils.py +12 -102
  71. mirascope/llm/responses/base_response.py +6 -18
  72. mirascope/llm/responses/base_stream_response.py +50 -173
  73. mirascope/llm/responses/finish_reason.py +0 -1
  74. mirascope/llm/responses/response.py +13 -34
  75. mirascope/llm/responses/root_response.py +29 -100
  76. mirascope/llm/responses/stream_response.py +31 -40
  77. mirascope/llm/tools/__init__.py +2 -9
  78. mirascope/llm/tools/_utils.py +3 -12
  79. mirascope/llm/tools/decorator.py +16 -25
  80. mirascope/llm/tools/protocols.py +4 -4
  81. mirascope/llm/tools/tool_schema.py +19 -87
  82. mirascope/llm/tools/toolkit.py +27 -35
  83. mirascope/llm/tools/tools.py +41 -135
  84. {mirascope-2.0.0.dist-info → mirascope-2.0.0a0.dist-info}/METADATA +9 -95
  85. mirascope-2.0.0a0.dist-info/RECORD +101 -0
  86. {mirascope-2.0.0.dist-info → mirascope-2.0.0a0.dist-info}/WHEEL +1 -1
  87. {mirascope-2.0.0.dist-info → mirascope-2.0.0a0.dist-info}/licenses/LICENSE +1 -1
  88. mirascope/_stubs.py +0 -363
  89. mirascope/api/__init__.py +0 -14
  90. mirascope/api/_generated/README.md +0 -207
  91. mirascope/api/_generated/__init__.py +0 -440
  92. mirascope/api/_generated/annotations/__init__.py +0 -33
  93. mirascope/api/_generated/annotations/client.py +0 -506
  94. mirascope/api/_generated/annotations/raw_client.py +0 -1414
  95. mirascope/api/_generated/annotations/types/__init__.py +0 -31
  96. mirascope/api/_generated/annotations/types/annotations_create_request_label.py +0 -5
  97. mirascope/api/_generated/annotations/types/annotations_create_response.py +0 -48
  98. mirascope/api/_generated/annotations/types/annotations_create_response_label.py +0 -5
  99. mirascope/api/_generated/annotations/types/annotations_get_response.py +0 -48
  100. mirascope/api/_generated/annotations/types/annotations_get_response_label.py +0 -5
  101. mirascope/api/_generated/annotations/types/annotations_list_request_label.py +0 -5
  102. mirascope/api/_generated/annotations/types/annotations_list_response.py +0 -21
  103. mirascope/api/_generated/annotations/types/annotations_list_response_annotations_item.py +0 -50
  104. mirascope/api/_generated/annotations/types/annotations_list_response_annotations_item_label.py +0 -5
  105. mirascope/api/_generated/annotations/types/annotations_update_request_label.py +0 -5
  106. mirascope/api/_generated/annotations/types/annotations_update_response.py +0 -48
  107. mirascope/api/_generated/annotations/types/annotations_update_response_label.py +0 -5
  108. mirascope/api/_generated/api_keys/__init__.py +0 -17
  109. mirascope/api/_generated/api_keys/client.py +0 -530
  110. mirascope/api/_generated/api_keys/raw_client.py +0 -1236
  111. mirascope/api/_generated/api_keys/types/__init__.py +0 -15
  112. mirascope/api/_generated/api_keys/types/api_keys_create_response.py +0 -28
  113. mirascope/api/_generated/api_keys/types/api_keys_get_response.py +0 -27
  114. mirascope/api/_generated/api_keys/types/api_keys_list_all_for_org_response_item.py +0 -40
  115. mirascope/api/_generated/api_keys/types/api_keys_list_response_item.py +0 -27
  116. mirascope/api/_generated/client.py +0 -211
  117. mirascope/api/_generated/core/__init__.py +0 -52
  118. mirascope/api/_generated/core/api_error.py +0 -23
  119. mirascope/api/_generated/core/client_wrapper.py +0 -46
  120. mirascope/api/_generated/core/datetime_utils.py +0 -28
  121. mirascope/api/_generated/core/file.py +0 -67
  122. mirascope/api/_generated/core/force_multipart.py +0 -16
  123. mirascope/api/_generated/core/http_client.py +0 -543
  124. mirascope/api/_generated/core/http_response.py +0 -55
  125. mirascope/api/_generated/core/jsonable_encoder.py +0 -100
  126. mirascope/api/_generated/core/pydantic_utilities.py +0 -255
  127. mirascope/api/_generated/core/query_encoder.py +0 -58
  128. mirascope/api/_generated/core/remove_none_from_dict.py +0 -11
  129. mirascope/api/_generated/core/request_options.py +0 -35
  130. mirascope/api/_generated/core/serialization.py +0 -276
  131. mirascope/api/_generated/docs/__init__.py +0 -4
  132. mirascope/api/_generated/docs/client.py +0 -91
  133. mirascope/api/_generated/docs/raw_client.py +0 -178
  134. mirascope/api/_generated/environment.py +0 -9
  135. mirascope/api/_generated/environments/__init__.py +0 -23
  136. mirascope/api/_generated/environments/client.py +0 -649
  137. mirascope/api/_generated/environments/raw_client.py +0 -1567
  138. mirascope/api/_generated/environments/types/__init__.py +0 -25
  139. mirascope/api/_generated/environments/types/environments_create_response.py +0 -24
  140. mirascope/api/_generated/environments/types/environments_get_analytics_response.py +0 -60
  141. mirascope/api/_generated/environments/types/environments_get_analytics_response_top_functions_item.py +0 -24
  142. mirascope/api/_generated/environments/types/environments_get_analytics_response_top_models_item.py +0 -22
  143. mirascope/api/_generated/environments/types/environments_get_response.py +0 -24
  144. mirascope/api/_generated/environments/types/environments_list_response_item.py +0 -24
  145. mirascope/api/_generated/environments/types/environments_update_response.py +0 -24
  146. mirascope/api/_generated/errors/__init__.py +0 -25
  147. mirascope/api/_generated/errors/bad_request_error.py +0 -14
  148. mirascope/api/_generated/errors/conflict_error.py +0 -14
  149. mirascope/api/_generated/errors/forbidden_error.py +0 -11
  150. mirascope/api/_generated/errors/internal_server_error.py +0 -10
  151. mirascope/api/_generated/errors/not_found_error.py +0 -11
  152. mirascope/api/_generated/errors/payment_required_error.py +0 -15
  153. mirascope/api/_generated/errors/service_unavailable_error.py +0 -14
  154. mirascope/api/_generated/errors/too_many_requests_error.py +0 -15
  155. mirascope/api/_generated/errors/unauthorized_error.py +0 -11
  156. mirascope/api/_generated/functions/__init__.py +0 -39
  157. mirascope/api/_generated/functions/client.py +0 -647
  158. mirascope/api/_generated/functions/raw_client.py +0 -1890
  159. mirascope/api/_generated/functions/types/__init__.py +0 -53
  160. mirascope/api/_generated/functions/types/functions_create_request_dependencies_value.py +0 -20
  161. mirascope/api/_generated/functions/types/functions_create_response.py +0 -37
  162. mirascope/api/_generated/functions/types/functions_create_response_dependencies_value.py +0 -20
  163. mirascope/api/_generated/functions/types/functions_find_by_hash_response.py +0 -39
  164. mirascope/api/_generated/functions/types/functions_find_by_hash_response_dependencies_value.py +0 -20
  165. mirascope/api/_generated/functions/types/functions_get_by_env_response.py +0 -53
  166. mirascope/api/_generated/functions/types/functions_get_by_env_response_dependencies_value.py +0 -22
  167. mirascope/api/_generated/functions/types/functions_get_response.py +0 -37
  168. mirascope/api/_generated/functions/types/functions_get_response_dependencies_value.py +0 -20
  169. mirascope/api/_generated/functions/types/functions_list_by_env_response.py +0 -25
  170. mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item.py +0 -56
  171. mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item_dependencies_value.py +0 -22
  172. mirascope/api/_generated/functions/types/functions_list_response.py +0 -21
  173. mirascope/api/_generated/functions/types/functions_list_response_functions_item.py +0 -41
  174. mirascope/api/_generated/functions/types/functions_list_response_functions_item_dependencies_value.py +0 -20
  175. mirascope/api/_generated/health/__init__.py +0 -7
  176. mirascope/api/_generated/health/client.py +0 -92
  177. mirascope/api/_generated/health/raw_client.py +0 -175
  178. mirascope/api/_generated/health/types/__init__.py +0 -8
  179. mirascope/api/_generated/health/types/health_check_response.py +0 -22
  180. mirascope/api/_generated/health/types/health_check_response_status.py +0 -5
  181. mirascope/api/_generated/organization_invitations/__init__.py +0 -33
  182. mirascope/api/_generated/organization_invitations/client.py +0 -546
  183. mirascope/api/_generated/organization_invitations/raw_client.py +0 -1519
  184. mirascope/api/_generated/organization_invitations/types/__init__.py +0 -53
  185. mirascope/api/_generated/organization_invitations/types/organization_invitations_accept_response.py +0 -34
  186. mirascope/api/_generated/organization_invitations/types/organization_invitations_accept_response_role.py +0 -7
  187. mirascope/api/_generated/organization_invitations/types/organization_invitations_create_request_role.py +0 -7
  188. mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response.py +0 -48
  189. mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response_role.py +0 -7
  190. mirascope/api/_generated/organization_invitations/types/organization_invitations_create_response_status.py +0 -7
  191. mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response.py +0 -48
  192. mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response_role.py +0 -7
  193. mirascope/api/_generated/organization_invitations/types/organization_invitations_get_response_status.py +0 -7
  194. mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item.py +0 -48
  195. mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item_role.py +0 -7
  196. mirascope/api/_generated/organization_invitations/types/organization_invitations_list_response_item_status.py +0 -7
  197. mirascope/api/_generated/organization_memberships/__init__.py +0 -19
  198. mirascope/api/_generated/organization_memberships/client.py +0 -302
  199. mirascope/api/_generated/organization_memberships/raw_client.py +0 -736
  200. mirascope/api/_generated/organization_memberships/types/__init__.py +0 -27
  201. mirascope/api/_generated/organization_memberships/types/organization_memberships_list_response_item.py +0 -33
  202. mirascope/api/_generated/organization_memberships/types/organization_memberships_list_response_item_role.py +0 -7
  203. mirascope/api/_generated/organization_memberships/types/organization_memberships_update_request_role.py +0 -7
  204. mirascope/api/_generated/organization_memberships/types/organization_memberships_update_response.py +0 -31
  205. mirascope/api/_generated/organization_memberships/types/organization_memberships_update_response_role.py +0 -7
  206. mirascope/api/_generated/organizations/__init__.py +0 -51
  207. mirascope/api/_generated/organizations/client.py +0 -869
  208. mirascope/api/_generated/organizations/raw_client.py +0 -2593
  209. mirascope/api/_generated/organizations/types/__init__.py +0 -71
  210. mirascope/api/_generated/organizations/types/organizations_create_payment_intent_response.py +0 -24
  211. mirascope/api/_generated/organizations/types/organizations_create_response.py +0 -26
  212. mirascope/api/_generated/organizations/types/organizations_create_response_role.py +0 -5
  213. mirascope/api/_generated/organizations/types/organizations_get_response.py +0 -26
  214. mirascope/api/_generated/organizations/types/organizations_get_response_role.py +0 -5
  215. mirascope/api/_generated/organizations/types/organizations_list_response_item.py +0 -26
  216. mirascope/api/_generated/organizations/types/organizations_list_response_item_role.py +0 -5
  217. mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_request_target_plan.py +0 -7
  218. mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response.py +0 -47
  219. mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response_validation_errors_item.py +0 -33
  220. mirascope/api/_generated/organizations/types/organizations_preview_subscription_change_response_validation_errors_item_resource.py +0 -7
  221. mirascope/api/_generated/organizations/types/organizations_router_balance_response.py +0 -24
  222. mirascope/api/_generated/organizations/types/organizations_subscription_response.py +0 -53
  223. mirascope/api/_generated/organizations/types/organizations_subscription_response_current_plan.py +0 -7
  224. mirascope/api/_generated/organizations/types/organizations_subscription_response_payment_method.py +0 -26
  225. mirascope/api/_generated/organizations/types/organizations_subscription_response_scheduled_change.py +0 -34
  226. mirascope/api/_generated/organizations/types/organizations_subscription_response_scheduled_change_target_plan.py +0 -7
  227. mirascope/api/_generated/organizations/types/organizations_update_response.py +0 -26
  228. mirascope/api/_generated/organizations/types/organizations_update_response_role.py +0 -5
  229. mirascope/api/_generated/organizations/types/organizations_update_subscription_request_target_plan.py +0 -7
  230. mirascope/api/_generated/organizations/types/organizations_update_subscription_response.py +0 -35
  231. mirascope/api/_generated/project_memberships/__init__.py +0 -25
  232. mirascope/api/_generated/project_memberships/client.py +0 -437
  233. mirascope/api/_generated/project_memberships/raw_client.py +0 -1039
  234. mirascope/api/_generated/project_memberships/types/__init__.py +0 -29
  235. mirascope/api/_generated/project_memberships/types/project_memberships_create_request_role.py +0 -7
  236. mirascope/api/_generated/project_memberships/types/project_memberships_create_response.py +0 -35
  237. mirascope/api/_generated/project_memberships/types/project_memberships_create_response_role.py +0 -7
  238. mirascope/api/_generated/project_memberships/types/project_memberships_list_response_item.py +0 -33
  239. mirascope/api/_generated/project_memberships/types/project_memberships_list_response_item_role.py +0 -7
  240. mirascope/api/_generated/project_memberships/types/project_memberships_update_request_role.py +0 -7
  241. mirascope/api/_generated/project_memberships/types/project_memberships_update_response.py +0 -35
  242. mirascope/api/_generated/project_memberships/types/project_memberships_update_response_role.py +0 -7
  243. mirascope/api/_generated/projects/__init__.py +0 -7
  244. mirascope/api/_generated/projects/client.py +0 -428
  245. mirascope/api/_generated/projects/raw_client.py +0 -1302
  246. mirascope/api/_generated/projects/types/__init__.py +0 -10
  247. mirascope/api/_generated/projects/types/projects_create_response.py +0 -25
  248. mirascope/api/_generated/projects/types/projects_get_response.py +0 -25
  249. mirascope/api/_generated/projects/types/projects_list_response_item.py +0 -25
  250. mirascope/api/_generated/projects/types/projects_update_response.py +0 -25
  251. mirascope/api/_generated/reference.md +0 -4915
  252. mirascope/api/_generated/tags/__init__.py +0 -19
  253. mirascope/api/_generated/tags/client.py +0 -504
  254. mirascope/api/_generated/tags/raw_client.py +0 -1288
  255. mirascope/api/_generated/tags/types/__init__.py +0 -17
  256. mirascope/api/_generated/tags/types/tags_create_response.py +0 -41
  257. mirascope/api/_generated/tags/types/tags_get_response.py +0 -41
  258. mirascope/api/_generated/tags/types/tags_list_response.py +0 -23
  259. mirascope/api/_generated/tags/types/tags_list_response_tags_item.py +0 -41
  260. mirascope/api/_generated/tags/types/tags_update_response.py +0 -41
  261. mirascope/api/_generated/token_cost/__init__.py +0 -7
  262. mirascope/api/_generated/token_cost/client.py +0 -160
  263. mirascope/api/_generated/token_cost/raw_client.py +0 -264
  264. mirascope/api/_generated/token_cost/types/__init__.py +0 -8
  265. mirascope/api/_generated/token_cost/types/token_cost_calculate_request_usage.py +0 -54
  266. mirascope/api/_generated/token_cost/types/token_cost_calculate_response.py +0 -52
  267. mirascope/api/_generated/traces/__init__.py +0 -97
  268. mirascope/api/_generated/traces/client.py +0 -1103
  269. mirascope/api/_generated/traces/raw_client.py +0 -2322
  270. mirascope/api/_generated/traces/types/__init__.py +0 -155
  271. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item.py +0 -29
  272. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource.py +0 -27
  273. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item.py +0 -23
  274. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value.py +0 -38
  275. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_array_value.py +0 -19
  276. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_kvlist_value.py +0 -22
  277. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_resource_attributes_item_value_kvlist_value_values_item.py +0 -20
  278. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item.py +0 -29
  279. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope.py +0 -31
  280. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item.py +0 -23
  281. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value.py +0 -38
  282. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_array_value.py +0 -19
  283. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_kvlist_value.py +0 -22
  284. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_scope_attributes_item_value_kvlist_value_values_item.py +0 -22
  285. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item.py +0 -48
  286. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item.py +0 -23
  287. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value.py +0 -38
  288. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_array_value.py +0 -19
  289. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_kvlist_value.py +0 -24
  290. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_attributes_item_value_kvlist_value_values_item.py +0 -22
  291. mirascope/api/_generated/traces/types/traces_create_request_resource_spans_item_scope_spans_item_spans_item_status.py +0 -20
  292. mirascope/api/_generated/traces/types/traces_create_response.py +0 -24
  293. mirascope/api/_generated/traces/types/traces_create_response_partial_success.py +0 -22
  294. mirascope/api/_generated/traces/types/traces_get_analytics_summary_response.py +0 -60
  295. mirascope/api/_generated/traces/types/traces_get_analytics_summary_response_top_functions_item.py +0 -24
  296. mirascope/api/_generated/traces/types/traces_get_analytics_summary_response_top_models_item.py +0 -22
  297. mirascope/api/_generated/traces/types/traces_get_trace_detail_by_env_response.py +0 -33
  298. mirascope/api/_generated/traces/types/traces_get_trace_detail_by_env_response_spans_item.py +0 -88
  299. mirascope/api/_generated/traces/types/traces_get_trace_detail_response.py +0 -33
  300. mirascope/api/_generated/traces/types/traces_get_trace_detail_response_spans_item.py +0 -88
  301. mirascope/api/_generated/traces/types/traces_list_by_function_hash_response.py +0 -25
  302. mirascope/api/_generated/traces/types/traces_list_by_function_hash_response_traces_item.py +0 -44
  303. mirascope/api/_generated/traces/types/traces_search_by_env_request_attribute_filters_item.py +0 -26
  304. mirascope/api/_generated/traces/types/traces_search_by_env_request_attribute_filters_item_operator.py +0 -7
  305. mirascope/api/_generated/traces/types/traces_search_by_env_request_sort_by.py +0 -7
  306. mirascope/api/_generated/traces/types/traces_search_by_env_request_sort_order.py +0 -7
  307. mirascope/api/_generated/traces/types/traces_search_by_env_response.py +0 -26
  308. mirascope/api/_generated/traces/types/traces_search_by_env_response_spans_item.py +0 -50
  309. mirascope/api/_generated/traces/types/traces_search_request_attribute_filters_item.py +0 -26
  310. mirascope/api/_generated/traces/types/traces_search_request_attribute_filters_item_operator.py +0 -7
  311. mirascope/api/_generated/traces/types/traces_search_request_sort_by.py +0 -7
  312. mirascope/api/_generated/traces/types/traces_search_request_sort_order.py +0 -5
  313. mirascope/api/_generated/traces/types/traces_search_response.py +0 -26
  314. mirascope/api/_generated/traces/types/traces_search_response_spans_item.py +0 -50
  315. mirascope/api/_generated/types/__init__.py +0 -85
  316. mirascope/api/_generated/types/already_exists_error.py +0 -22
  317. mirascope/api/_generated/types/already_exists_error_tag.py +0 -5
  318. mirascope/api/_generated/types/bad_request_error_body.py +0 -50
  319. mirascope/api/_generated/types/click_house_error.py +0 -22
  320. mirascope/api/_generated/types/database_error.py +0 -22
  321. mirascope/api/_generated/types/database_error_tag.py +0 -5
  322. mirascope/api/_generated/types/date.py +0 -3
  323. mirascope/api/_generated/types/http_api_decode_error.py +0 -27
  324. mirascope/api/_generated/types/http_api_decode_error_tag.py +0 -5
  325. mirascope/api/_generated/types/immutable_resource_error.py +0 -22
  326. mirascope/api/_generated/types/internal_server_error_body.py +0 -49
  327. mirascope/api/_generated/types/issue.py +0 -38
  328. mirascope/api/_generated/types/issue_tag.py +0 -10
  329. mirascope/api/_generated/types/not_found_error_body.py +0 -22
  330. mirascope/api/_generated/types/not_found_error_tag.py +0 -5
  331. mirascope/api/_generated/types/number_from_string.py +0 -3
  332. mirascope/api/_generated/types/permission_denied_error.py +0 -22
  333. mirascope/api/_generated/types/permission_denied_error_tag.py +0 -5
  334. mirascope/api/_generated/types/plan_limit_exceeded_error.py +0 -32
  335. mirascope/api/_generated/types/plan_limit_exceeded_error_tag.py +0 -7
  336. mirascope/api/_generated/types/pricing_unavailable_error.py +0 -23
  337. mirascope/api/_generated/types/property_key.py +0 -7
  338. mirascope/api/_generated/types/property_key_key.py +0 -25
  339. mirascope/api/_generated/types/property_key_key_tag.py +0 -5
  340. mirascope/api/_generated/types/rate_limit_error.py +0 -31
  341. mirascope/api/_generated/types/rate_limit_error_tag.py +0 -5
  342. mirascope/api/_generated/types/service_unavailable_error_body.py +0 -24
  343. mirascope/api/_generated/types/service_unavailable_error_tag.py +0 -7
  344. mirascope/api/_generated/types/stripe_error.py +0 -20
  345. mirascope/api/_generated/types/subscription_past_due_error.py +0 -31
  346. mirascope/api/_generated/types/subscription_past_due_error_tag.py +0 -7
  347. mirascope/api/_generated/types/unauthorized_error_body.py +0 -21
  348. mirascope/api/_generated/types/unauthorized_error_tag.py +0 -5
  349. mirascope/api/client.py +0 -255
  350. mirascope/api/settings.py +0 -99
  351. mirascope/llm/formatting/output_parser.py +0 -178
  352. mirascope/llm/formatting/primitives.py +0 -192
  353. mirascope/llm/mcp/mcp_client.py +0 -130
  354. mirascope/llm/messages/_utils.py +0 -34
  355. mirascope/llm/models/thinking_config.py +0 -61
  356. mirascope/llm/prompts/prompts.py +0 -487
  357. mirascope/llm/providers/__init__.py +0 -62
  358. mirascope/llm/providers/anthropic/__init__.py +0 -11
  359. mirascope/llm/providers/anthropic/_utils/__init__.py +0 -27
  360. mirascope/llm/providers/anthropic/_utils/beta_decode.py +0 -282
  361. mirascope/llm/providers/anthropic/_utils/beta_encode.py +0 -266
  362. mirascope/llm/providers/anthropic/_utils/encode.py +0 -418
  363. mirascope/llm/providers/anthropic/_utils/errors.py +0 -46
  364. mirascope/llm/providers/anthropic/beta_provider.py +0 -374
  365. mirascope/llm/providers/anthropic/model_id.py +0 -23
  366. mirascope/llm/providers/anthropic/model_info.py +0 -87
  367. mirascope/llm/providers/anthropic/provider.py +0 -479
  368. mirascope/llm/providers/google/__init__.py +0 -6
  369. mirascope/llm/providers/google/_utils/errors.py +0 -50
  370. mirascope/llm/providers/google/model_id.py +0 -22
  371. mirascope/llm/providers/google/model_info.py +0 -63
  372. mirascope/llm/providers/google/provider.py +0 -492
  373. mirascope/llm/providers/mirascope/__init__.py +0 -5
  374. mirascope/llm/providers/mirascope/_utils.py +0 -73
  375. mirascope/llm/providers/mirascope/provider.py +0 -349
  376. mirascope/llm/providers/mlx/__init__.py +0 -9
  377. mirascope/llm/providers/mlx/_utils.py +0 -141
  378. mirascope/llm/providers/mlx/encoding/__init__.py +0 -8
  379. mirascope/llm/providers/mlx/encoding/base.py +0 -72
  380. mirascope/llm/providers/mlx/encoding/transformers.py +0 -150
  381. mirascope/llm/providers/mlx/mlx.py +0 -254
  382. mirascope/llm/providers/mlx/model_id.py +0 -17
  383. mirascope/llm/providers/mlx/provider.py +0 -452
  384. mirascope/llm/providers/model_id.py +0 -16
  385. mirascope/llm/providers/ollama/__init__.py +0 -7
  386. mirascope/llm/providers/ollama/provider.py +0 -71
  387. mirascope/llm/providers/openai/__init__.py +0 -15
  388. mirascope/llm/providers/openai/_utils/__init__.py +0 -5
  389. mirascope/llm/providers/openai/_utils/errors.py +0 -46
  390. mirascope/llm/providers/openai/completions/__init__.py +0 -7
  391. mirascope/llm/providers/openai/completions/base_provider.py +0 -542
  392. mirascope/llm/providers/openai/completions/provider.py +0 -22
  393. mirascope/llm/providers/openai/model_id.py +0 -31
  394. mirascope/llm/providers/openai/model_info.py +0 -303
  395. mirascope/llm/providers/openai/provider.py +0 -441
  396. mirascope/llm/providers/openai/responses/__init__.py +0 -5
  397. mirascope/llm/providers/openai/responses/provider.py +0 -513
  398. mirascope/llm/providers/provider_id.py +0 -24
  399. mirascope/llm/providers/provider_registry.py +0 -299
  400. mirascope/llm/providers/together/__init__.py +0 -7
  401. mirascope/llm/providers/together/provider.py +0 -40
  402. mirascope/llm/responses/usage.py +0 -95
  403. mirascope/ops/__init__.py +0 -111
  404. mirascope/ops/_internal/__init__.py +0 -5
  405. mirascope/ops/_internal/closure.py +0 -1169
  406. mirascope/ops/_internal/configuration.py +0 -177
  407. mirascope/ops/_internal/context.py +0 -76
  408. mirascope/ops/_internal/exporters/__init__.py +0 -26
  409. mirascope/ops/_internal/exporters/exporters.py +0 -395
  410. mirascope/ops/_internal/exporters/processors.py +0 -104
  411. mirascope/ops/_internal/exporters/types.py +0 -165
  412. mirascope/ops/_internal/exporters/utils.py +0 -29
  413. mirascope/ops/_internal/instrumentation/__init__.py +0 -8
  414. mirascope/ops/_internal/instrumentation/llm/__init__.py +0 -8
  415. mirascope/ops/_internal/instrumentation/llm/common.py +0 -530
  416. mirascope/ops/_internal/instrumentation/llm/cost.py +0 -190
  417. mirascope/ops/_internal/instrumentation/llm/encode.py +0 -238
  418. mirascope/ops/_internal/instrumentation/llm/gen_ai_types/__init__.py +0 -38
  419. mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_input_messages.py +0 -31
  420. mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_output_messages.py +0 -38
  421. mirascope/ops/_internal/instrumentation/llm/gen_ai_types/gen_ai_system_instructions.py +0 -18
  422. mirascope/ops/_internal/instrumentation/llm/gen_ai_types/shared.py +0 -100
  423. mirascope/ops/_internal/instrumentation/llm/llm.py +0 -161
  424. mirascope/ops/_internal/instrumentation/llm/model.py +0 -1798
  425. mirascope/ops/_internal/instrumentation/llm/response.py +0 -521
  426. mirascope/ops/_internal/instrumentation/llm/serialize.py +0 -300
  427. mirascope/ops/_internal/propagation.py +0 -198
  428. mirascope/ops/_internal/protocols.py +0 -133
  429. mirascope/ops/_internal/session.py +0 -139
  430. mirascope/ops/_internal/spans.py +0 -232
  431. mirascope/ops/_internal/traced_calls.py +0 -375
  432. mirascope/ops/_internal/traced_functions.py +0 -523
  433. mirascope/ops/_internal/tracing.py +0 -353
  434. mirascope/ops/_internal/types.py +0 -13
  435. mirascope/ops/_internal/utils.py +0 -123
  436. mirascope/ops/_internal/versioned_calls.py +0 -512
  437. mirascope/ops/_internal/versioned_functions.py +0 -357
  438. mirascope/ops/_internal/versioning.py +0 -303
  439. mirascope/ops/exceptions.py +0 -21
  440. mirascope-2.0.0.dist-info/RECORD +0 -423
  441. /mirascope/llm/{providers → clients}/base/kwargs.py +0 -0
  442. /mirascope/llm/{providers → clients}/google/message.py +0 -0
@@ -1,173 +1,32 @@
1
1
  """The `llm.format` decorator for defining response formats as classes."""
2
2
 
3
- from __future__ import annotations
4
-
5
3
  import inspect
6
- import json
7
- from dataclasses import dataclass
8
- from typing import Any, Generic, cast
9
4
 
10
- from ..tools import FORMAT_TOOL_NAME, ToolFn, ToolParameterSchema, ToolSchema
11
5
  from ..types import NoneType
12
- from .output_parser import OutputParser, is_output_parser
13
- from .primitives import create_wrapper_model, is_primitive_type
14
- from .types import FormattableT, FormattingMode, HasFormattingInstructions
15
-
16
- TOOL_MODE_INSTRUCTIONS = f"""Always respond to the user's query using the {FORMAT_TOOL_NAME} tool for structured output."""
17
-
18
-
19
- JSON_MODE_INSTRUCTIONS = (
20
- "Respond only with valid JSON that matches this exact schema:\n{json_schema}"
21
- )
22
-
23
-
24
- @dataclass(kw_only=True)
25
- class Format(Generic[FormattableT]):
26
- """Class representing a structured output format for LLM responses.
27
-
28
- A `Format` contains metadata needed to describe a structured output type
29
- to the LLM, including the expected schema. This class is not instantiated directly,
30
- but is created by calling `llm.format`, or is automatically generated by LLM
31
- providers when a `Formattable` is passed to a call method.
32
-
33
- Example:
34
-
35
- ```python
36
- from mirascope import llm
37
-
38
- class Book:
39
- title: str
40
- author: str
41
-
42
- print(llm.format(Book, mode="tool"))
43
- ```
44
- """
45
-
46
- name: str
47
- """The name of the response format."""
48
-
49
- description: str | None
50
- """A description of the response format, if available."""
51
-
52
- schema: dict[str, object]
53
- """JSON schema representation of the structured output format."""
54
-
55
- mode: FormattingMode
56
- """The decorator-provided mode of the response format.
57
-
58
- Determines how the LLM call may be modified in order to extract the expected format.
59
- """
60
-
61
- formattable: type[FormattableT] | OutputParser[FormattableT]
62
- """The formattable type or custom output parser.
63
-
64
- Can be one of:
65
- - type[BaseModel]: A Pydantic model class for structured output
66
- - PrimitiveType: A primitive type (str, int, list, etc.) for simple output
67
- - OutputParser[FormattableT]: A custom parser created with @llm.output_parser
68
-
69
- The type determines how the response will be parsed in response.parse().
70
- OutputParser uses Any for the response type since it works with any response.
71
- """
72
-
73
- @property
74
- def formatting_instructions(self) -> str | None:
75
- """The formatting instructions that will be added to the LLM system prompt.
76
-
77
- If the format has a custom `OutputParser`, its formatting instructions will be used.
78
- Otherwise, if the format type has a `formatting_instructions` class method,
79
- the output of that call will be used. Otherwise, instructions may be
80
- auto-generated based on the formatting mode.
81
- """
82
- if is_output_parser(self.formattable) or isinstance(
83
- self.formattable, HasFormattingInstructions
84
- ):
85
- return self.formattable.formatting_instructions()
86
-
87
- if self.mode == "tool":
88
- return TOOL_MODE_INSTRUCTIONS
89
- elif self.mode == "json":
90
- json_schema = json.dumps(self.schema, indent=2)
91
- instructions = JSON_MODE_INSTRUCTIONS.format(json_schema=json_schema)
92
- return inspect.cleandoc(instructions)
93
- elif self.mode == "parser":
94
- return None # pragma: no cover
95
-
96
- def create_tool_schema(
97
- self,
98
- ) -> ToolSchema[ToolFn[..., None]]:
99
- """Generate a `ToolSchema` for parsing this format.
100
-
101
- Returns:
102
- `ToolSchema` for the format tool
103
- """
104
-
105
- schema_dict: dict[str, Any] = self.schema.copy()
106
- schema_dict["type"] = "object"
107
-
108
- properties = schema_dict.get("properties")
109
- if not properties or not isinstance(properties, dict):
110
- properties = {} # pragma: no cover
111
- properties = cast(dict[str, Any], properties)
112
- required: list[str] = list(properties.keys())
113
-
114
- description = (
115
- f"Use this tool to extract data in {self.name} format for a final response."
116
- )
117
- if self.description:
118
- description += "\n" + self.description
119
-
120
- parameters = ToolParameterSchema(
121
- properties=properties,
122
- required=required,
123
- additionalProperties=False,
124
- )
125
- if "$defs" in schema_dict and isinstance(schema_dict["$defs"], dict):
126
- parameters.defs = schema_dict["$defs"]
127
-
128
- def _unused_format_fn() -> None:
129
- raise TypeError(
130
- "Format tool function should not be called."
131
- ) # pragma: no cover
132
-
133
- return ToolSchema(
134
- fn=cast(ToolFn[..., None], _unused_format_fn),
135
- name=FORMAT_TOOL_NAME,
136
- description=description,
137
- parameters=parameters,
138
- strict=None, # Provider determines whether to use strict mode.
139
- )
6
+ from ._utils import default_formatting_instructions
7
+ from .types import Format, FormattableT, FormattingMode, HasFormattingInstructions
140
8
 
141
9
 
142
10
  def format(
143
- formattable: type[FormattableT] | OutputParser[FormattableT] | None,
11
+ formattable: type[FormattableT] | None,
144
12
  *,
145
13
  mode: FormattingMode,
146
14
  ) -> Format[FormattableT] | None:
147
- """Returns a `Format` that describes structured output or custom parsing.
148
-
149
- This function converts a Formattable type (e.g. Pydantic `BaseModel` or primitive type)
150
- or an `OutputParser` into a `Format` object that describes how the output should be
151
- formatted and parsed. Calling `llm.format` is optional, as all the APIs that expect
152
- a `Format` can also take the Formattable type or `OutputParser` directly. However,
153
- calling `llm.format` is necessary in order to specify the formatting mode for
154
- `BaseModel`/primitive types.
15
+ """Returns a `Format` that describes structured output for a Formattable type.
155
16
 
156
- Primitive types are automatically wrapped in a `BaseModel` with an "output" field
157
- for schema generation, then unwrapped during parsing.
17
+ This function converts a Formattable type (e.g. Pydantic BaseModel) into a `Format`
18
+ object that describes how the object should be formatted. Calling `llm.format`
19
+ is optional, as all the APIs that expect a `Format` can also take the Formattable
20
+ type directly. However, calling `llm.format` is necessary in order to specify the
21
+ formatting mode that will be used.
158
22
 
159
23
  Args:
160
- formattable: The type or parser to format:
161
- - BaseModel type: Uses structured output with JSON schema
162
- - Primitive type: Wrapped in schema for structured output
163
- - OutputParser: Uses custom parsing with instructions
164
- mode: The format mode to use (required):
24
+ mode: The format mode to use, one of the following:
165
25
  - "strict": Use model strict structured outputs, or fail if unavailable.
166
26
  - "tool": Use forced tool calling with a special tool that represents a
167
27
  formatted response.
168
28
  - "json": Use provider json mode if available, or modify prompt to request
169
29
  json if not.
170
- - "parser": Must be used for OutputParser types.
171
30
 
172
31
  The Formattable type may provide custom formatting instructions via a
173
32
  `formatting_instructions(cls)` classmethod. If that method is present, it will be called,
@@ -178,44 +37,34 @@ def format(
178
37
  you can add the `formatting_instructions` classmethod and have it return `None`.
179
38
 
180
39
  Returns:
181
- A `Format` object describing the format type or parser.
40
+ A `Format` object describing the Formattable type.
182
41
 
183
42
  Example:
184
- Using with a BaseModel:
43
+ Using with an LLM call:
185
44
 
186
45
  ```python
187
46
  from pydantic import BaseModel
47
+
188
48
  from mirascope import llm
189
49
 
50
+
190
51
  class Book(BaseModel):
191
52
  title: str
192
53
  author: str
193
54
 
194
55
  format = llm.format(Book, mode="strict")
195
56
 
196
- @llm.call("openai/gpt-5-mini", format=format)
57
+ @llm.call(
58
+ provider="openai:completions",
59
+ model_id="gpt-4o-mini",
60
+ format=format,
61
+ )
197
62
  def recommend_book(genre: str):
198
63
  return f"Recommend a {genre} book."
199
64
 
200
65
  response = recommend_book("fantasy")
201
66
  book: Book = response.parse()
202
- ```
203
-
204
- Example:
205
-
206
- Using with an `OutputParser`:
207
-
208
- ```python
209
- @llm.output_parser(
210
- formatting_instructions="Return XML: <book><title>...</title></book>"
211
- )
212
- def parse_book_xml(response: llm.AnyResponse) -> Book:
213
- # ... parsing logic ...
214
- return Book(...)
215
-
216
- @llm.call("openai/gpt-5-mini", format=parse_book_xml)
217
- def recommend_book(genre: str):
218
- return f"Recommend a {genre} book."
67
+ print(f"{book.title} by {book.author}")
219
68
  ```
220
69
  """
221
70
  # TODO: Add caching or memoization to this function (e.g. functools.lru_cache)
@@ -223,71 +72,33 @@ def format(
223
72
  if formattable is None or formattable is NoneType:
224
73
  return None
225
74
 
226
- if is_output_parser(formattable):
227
- if mode != "parser":
228
- raise ValueError(f"mode must be 'parser' for OutputParser, got '{mode}'")
229
- return Format[Any](
230
- name=formattable.__name__,
231
- description=formattable.__doc__,
232
- schema={},
233
- mode="parser",
234
- formattable=formattable,
235
- )
236
-
237
- if is_primitive_type(formattable):
238
- wrapper_model = create_wrapper_model(formattable)
239
- schema = wrapper_model.model_json_schema()
240
- name = (
241
- formattable.__name__
242
- if hasattr(formattable, "__name__")
243
- else str(formattable)
244
- )
245
-
246
- return Format[FormattableT](
247
- name=name,
248
- description=None,
249
- schema=schema,
250
- mode=mode,
251
- formattable=formattable,
252
- )
253
-
254
75
  description = None
255
76
  if formattable.__doc__:
256
77
  description = inspect.cleandoc(formattable.__doc__)
257
78
 
258
79
  schema = formattable.model_json_schema()
80
+ formatting_instructions = None
81
+ if isinstance(formattable, HasFormattingInstructions):
82
+ formatting_instructions = formattable.formatting_instructions()
83
+ else:
84
+ formatting_instructions = default_formatting_instructions(schema, mode)
259
85
 
260
86
  return Format[FormattableT](
261
87
  name=formattable.__name__,
262
88
  description=description,
263
89
  schema=schema,
264
90
  mode=mode,
91
+ formatting_instructions=formatting_instructions,
265
92
  formattable=formattable,
266
93
  )
267
94
 
268
95
 
269
96
  def resolve_format(
270
- formattable: (
271
- type[FormattableT] | Format[FormattableT] | OutputParser[FormattableT] | None
272
- ),
97
+ formattable: type[FormattableT] | Format[FormattableT] | None,
273
98
  default_mode: FormattingMode,
274
99
  ) -> Format[FormattableT] | None:
275
- """Resolve a `Format` (or None) from a possible `Format`, Formattable, or `OutputParser`.
276
-
277
- Args:
278
- formattable: The format specification:
279
- - Format: Returned as-is
280
- - BaseModel/primitive type: Converted to Format with default_mode
281
- - OutputParser: Converted to Format with mode='parser'
282
- default_mode: The mode to use for BaseModel/primitive types.
283
-
284
- Returns:
285
- A Format object or None.
286
- """
100
+ """Resolve a `Format` (or None) from a possible `Format` or Formattable."""
287
101
  if isinstance(formattable, Format):
288
102
  return formattable
289
-
290
- if is_output_parser(formattable):
291
- return format(formattable, mode="parser")
292
-
293
- return format(formattable, mode=default_mode)
103
+ else:
104
+ return format(formattable, mode=default_mode)
@@ -20,8 +20,8 @@ class FromCallArgs:
20
20
 
21
21
 
22
22
  @llm.call(
23
- provider_id="openai",
24
- model_id="openai/gpt-5-mini",
23
+ provider="openai:completions",
24
+ model_id="gpt-4o-mini",
25
25
  format=Book,
26
26
  )
27
27
  def summarize_book(title: str, author: str):
@@ -8,16 +8,10 @@ serves as an acknowledgment of the original author's contribution to this projec
8
8
  --------------------------------------------------------------------------------
9
9
  """
10
10
 
11
- import inspect
12
- from typing import Any, Generic, NoReturn, Union, cast, get_args, get_origin
13
-
14
- from pydantic import BaseModel, create_model
11
+ from typing import Generic, NoReturn
15
12
 
16
13
  from .format import FormattableT
17
14
 
18
- # Cache for generated partial models to avoid recreation
19
- _partial_model_cache: dict[type[Any], type[Any]] = {}
20
-
21
15
 
22
16
  class Partial(Generic[FormattableT]):
23
17
  """Generate a new class with all attributes optionals.
@@ -40,9 +34,7 @@ class Partial(Generic[FormattableT]):
40
34
  Raises:
41
35
  TypeError: Direct instantiation not allowed.
42
36
  """
43
- raise TypeError(
44
- "Cannot instantiate abstract Partial class."
45
- ) # pragma: no cover
37
+ raise TypeError("Cannot instantiate abstract Partial class.")
46
38
 
47
39
  def __init_subclass__(
48
40
  cls,
@@ -54,78 +46,13 @@ class Partial(Generic[FormattableT]):
54
46
  Raises:
55
47
  TypeError: Subclassing not allowed.
56
48
  """
57
- raise TypeError(f"Cannot subclass {cls.__module__}.Partial") # pragma: no cover
49
+ raise TypeError(f"Cannot subclass {cls.__module__}.Partial")
58
50
 
59
51
  def __class_getitem__(
60
52
  cls,
61
53
  wrapped_class: type[FormattableT],
62
54
  ) -> type[FormattableT]:
63
- """Convert model to a partial model with all fields being optionals.
64
-
65
- Recursively converts all fields in a Pydantic BaseModel to optional,
66
- handling nested models and generic types like list[Book].
67
-
68
- Args:
69
- wrapped_class: The BaseModel class to make partial
70
-
71
- Returns:
72
- A new BaseModel class with all fields optional (or original if not BaseModel)
73
-
74
- Example:
75
- >>> class Author(BaseModel):
76
- ... first_name: str
77
- ... last_name: str
78
- >>> class Book(BaseModel):
79
- ... title: str
80
- ... author: Author
81
- >>> PartialBook = Partial[Book]
82
- >>> partial = PartialBook(title="The Name")
83
- >>> partial.author # None
84
- """
85
- # Return non-BaseModel types unchanged
86
- if not (
87
- inspect.isclass(wrapped_class) and issubclass(wrapped_class, BaseModel)
88
- ):
89
- return wrapped_class
90
-
91
- # Check cache to avoid regenerating
92
- if wrapped_class in _partial_model_cache:
93
- return cast(type[FormattableT], _partial_model_cache[wrapped_class])
94
-
95
- # Recursively make all fields optional
96
- partial_fields: dict[str, Any] = {}
97
- for field_name, field_info in wrapped_class.model_fields.items():
98
- field_type = field_info.annotation
99
-
100
- # Recursively handle nested BaseModel fields
101
- if inspect.isclass(field_type) and issubclass(field_type, BaseModel):
102
- field_type = Partial[field_type]
103
-
104
- # Handle generic types with BaseModel args (e.g., list[Book], dict[str, Book])
105
- origin = get_origin(field_type)
106
- if origin is not None:
107
- args = get_args(field_type)
108
- # Recursively convert BaseModel args to partial
109
- new_args = tuple(
110
- Partial[arg]
111
- if inspect.isclass(arg) and issubclass(arg, BaseModel)
112
- else arg
113
- for arg in args
114
- )
115
- # Reconstruct generic type with new args
116
- if new_args != args:
117
- field_type = origin[new_args]
118
-
119
- # Make field optional with None default
120
- optional_type = Union[field_type, None] # noqa: UP007
121
- partial_fields[field_name] = (optional_type, None)
122
-
123
- # Create new model with "Partial" prefix
124
- partial_model = create_model(
125
- f"Partial{wrapped_class.__name__}", __base__=BaseModel, **partial_fields
126
- )
127
-
128
- # Cache the generated model
129
- _partial_model_cache[wrapped_class] = partial_model
130
-
131
- return cast(type[FormattableT], partial_model)
55
+ """Convert model to a partial model with all fields being optionals."""
56
+ # TODO: Implement proper partial model generation
57
+ # For now, return the original class to avoid import errors
58
+ return wrapped_class
@@ -1,26 +1,18 @@
1
1
  """Type for the formatting module."""
2
2
 
3
- from typing import Literal, Protocol, runtime_checkable
3
+ from dataclasses import dataclass
4
+ from typing import Generic, Literal, Protocol, runtime_checkable
4
5
  from typing_extensions import TypeVar
5
6
 
6
7
  from pydantic import BaseModel
7
8
 
8
- from .primitives import PrimitiveType
9
-
10
- FormattableT = TypeVar(
11
- "FormattableT", bound=BaseModel | PrimitiveType | None, default=None
12
- )
9
+ # TODO: Support primitive types (e.g. `format=list[Book]`)
10
+ FormattableT = TypeVar("FormattableT", bound=BaseModel | None, default=None)
13
11
  """Type variable for structured response format types.
14
12
 
15
13
  This TypeVar represents the type of structured output format that LLM responses
16
- can be parsed into, or None if no format is specified.
17
-
18
- Supported format types:
19
- - Pydantic BaseModel subclasses
20
- - Primitive types: str, int, float, bool, bytes, list, set, tuple, dict
21
- - Generic collections: list[Book], dict[str, int], etc.
22
- - Union, Literal, and Annotated types
23
- - Enum types
14
+ can be parsed into, or None if no format is specified.
15
+ If format is specified, it must extend Pydantic BaseModel.
24
16
  """
25
17
 
26
18
 
@@ -28,14 +20,15 @@ FormattingMode = Literal[
28
20
  "strict",
29
21
  "json",
30
22
  "tool",
31
- "parser",
32
23
  ]
33
24
  """Available modes for response format generation.
34
25
 
35
26
  - "strict": Use strict mode for structured outputs, asking the LLM to strictly adhere
36
27
  to a given JSON schema. Not all providers or models support it, and may not be
37
- compatible with tool calling. When making a call using this mode, an
38
- `llm.FeatureNotSupportedError` error may be raised if the mode is unsupported.
28
+ compatible with tool calling. When making a call using this mode, an
29
+ `llm.FormattingModeNotSupportedError` error may be raised (if "strict" mode is wholly
30
+ unsupported), or an `llm.FeatureNotSupportedError` may be raised (if trying to use
31
+ strict along with tools and that is unsupported).
39
32
 
40
33
  - "json": Use JSON mode for structured outputs. In contrast to strict mode, we ask the
41
34
  LLM to output JSON as text, though without guarantees that the model will output
@@ -50,14 +43,64 @@ FormattingMode = Literal[
50
43
  content (abstracting over the tool call). If other tools are present, they will
51
44
  be handled as regular tool calls.
52
45
 
53
- - "parser": Use custom parsing with formatting instructions. No schema generation or
54
- structured output features. The LLM receives only formatting instructions and the
55
- response is parsed using a custom parser function created with `@llm.output_parser`.
56
-
57
46
  Note: When `llm.format` is not used, the provider will automatically choose a mode at call time.
58
47
  """
59
48
 
60
49
 
50
+ @dataclass(kw_only=True)
51
+ class Format(Generic[FormattableT]):
52
+ """Class representing a structured output format for LLM responses.
53
+
54
+ A `Format` contains metadata needed to describe a structured output type
55
+ to the LLM, including the expected schema. This class is not instantiated directly,
56
+ but is created by calling `llm.format`, or is automatically generated by LLM
57
+ providers when a `Formattable` is passed to a call method.
58
+
59
+ Example:
60
+
61
+ ```python
62
+ from mirascope import llm
63
+
64
+ class Book:
65
+ title: str
66
+ author: str
67
+
68
+ print(llm.format(Book, mode="tool"))
69
+ ```
70
+ """
71
+
72
+ name: str
73
+ """The name of the response format."""
74
+
75
+ description: str | None
76
+ """A description of the response format, if available."""
77
+
78
+ schema: dict[str, object]
79
+ """JSON schema representation of the structured output format."""
80
+
81
+ mode: FormattingMode
82
+ """The decorator-provided mode of the response format.
83
+
84
+ Determines how the LLM call may be modified in order to extract the expected format.
85
+ """
86
+
87
+ formatting_instructions: str | None
88
+ """The formatting instructions that will be added to the LLM system prompt.
89
+
90
+ If the format type has a `formatting_instructions` class method, the output of that
91
+ call will be used for instructions. Otherwise, instructions may be auto-generated
92
+ based on the formatting mode.
93
+ """
94
+
95
+ formattable: type[FormattableT]
96
+ """The `Formattable` type that this `Format` describes.
97
+
98
+ While the `FormattbleT` typevar allows for `None`, a `Format` will never be
99
+ constructed when the `FormattableT` is `None`, so you may treat this as
100
+ a `RequiredFormattableT` in practice.
101
+ """
102
+
103
+
61
104
  @runtime_checkable
62
105
  class HasFormattingInstructions(Protocol):
63
106
  """Protocol for classes that have been decorated with `@format()`."""
@@ -1,5 +1,5 @@
1
1
  """MCP compatibility module."""
2
2
 
3
- from .mcp_client import MCPClient, sse_client, stdio_client, streamable_http_client
3
+ from .client import MCPClient, sse_client, stdio_client, streamablehttp_client
4
4
 
5
- __all__ = ["MCPClient", "sse_client", "stdio_client", "streamable_http_client"]
5
+ __all__ = ["MCPClient", "sse_client", "stdio_client", "streamablehttp_client"]
@@ -0,0 +1,118 @@
1
+ import contextlib
2
+ from collections.abc import AsyncIterator, Callable
3
+ from datetime import timedelta
4
+
5
+ import httpx
6
+ from mcp import ClientSession
7
+ from mcp.client.session import ListRootsFnT, SamplingFnT
8
+ from mcp.client.sse import sse_client as mcp_sse_client
9
+ from mcp.client.stdio import StdioServerParameters
10
+ from mcp.client.streamable_http import (
11
+ streamablehttp_client as mcp_streamablehttp_client,
12
+ )
13
+ from mcp.shared._httpx_utils import McpHttpClientFactory
14
+
15
+ from ..tools import AsyncTool
16
+
17
+
18
+ class MCPClient:
19
+ """Mirascope wrapper around a MCP ClientSession.
20
+
21
+ It provides a way to get MCP results that are pre-converted into Mirascope-friendly
22
+ types.
23
+
24
+ The underlying MCP ClientSession may be accessed by .session if needed.
25
+ """
26
+
27
+ def __init__(self, session: ClientSession) -> None:
28
+ self._session = session
29
+
30
+ @property
31
+ def session(self) -> ClientSession:
32
+ """Access the underlying MCP ClientSession if needed."""
33
+ return self._session
34
+
35
+ async def list_tools(self) -> list[AsyncTool]:
36
+ """List all tools available on the MCP server.
37
+
38
+ Returns:
39
+ A list of dynamically created `llm.Tool`s.
40
+ """
41
+ raise NotImplementedError()
42
+
43
+
44
+ @contextlib.asynccontextmanager
45
+ async def streamablehttp_client(
46
+ url: str,
47
+ headers: dict[str, str] | None = None,
48
+ timeout: float | timedelta | None = None,
49
+ sse_read_timeout: float | timedelta | None = None,
50
+ terminate_on_close: bool = True,
51
+ httpx_client_factory: McpHttpClientFactory | None = None,
52
+ auth: httpx.Auth | None = None,
53
+ ) -> AsyncIterator[MCPClient]:
54
+ """Create a Mirascope MCPClient using StreamableHTTP."""
55
+ kwargs = {}
56
+ if headers is not None:
57
+ kwargs["headers"] = headers
58
+ if timeout is not None:
59
+ kwargs["timeout"] = timeout
60
+ if sse_read_timeout is not None:
61
+ kwargs["sse_read_timeout"] = sse_read_timeout
62
+ if httpx_client_factory is not None:
63
+ kwargs["httpx_client_factory"] = httpx_client_factory
64
+ if auth is not None:
65
+ kwargs["auth"] = auth
66
+
67
+ async with (
68
+ mcp_streamablehttp_client(
69
+ url,
70
+ terminate_on_close=terminate_on_close,
71
+ **kwargs,
72
+ ) as (read, write, get_session_id),
73
+ ClientSession(
74
+ read,
75
+ write,
76
+ ) as session,
77
+ ):
78
+ await session.initialize()
79
+ yield MCPClient(session)
80
+
81
+
82
+ @contextlib.asynccontextmanager
83
+ async def stdio_client(
84
+ server_parameters: StdioServerParameters,
85
+ read_stream_exception_handler: Callable[[Exception], None] | None = None,
86
+ ) -> AsyncIterator[MCPClient]:
87
+ """Create a Mirascope MCPClient using stdio."""
88
+
89
+ async with (
90
+ ClientSession(None, None) as session, # pyright: ignore [reportArgumentType]
91
+ ):
92
+ raise NotImplementedError()
93
+ await session.initialize()
94
+ yield MCPClient(session)
95
+
96
+
97
+ @contextlib.asynccontextmanager
98
+ async def sse_client(
99
+ url: str,
100
+ list_roots_callback: ListRootsFnT | None = None,
101
+ read_timeout_seconds: timedelta | None = None,
102
+ sampling_callback: SamplingFnT | None = None,
103
+ session: ClientSession | None = None,
104
+ ) -> AsyncIterator[MCPClient]:
105
+ """Create a Mirascope MCPClient using sse."""
106
+
107
+ async with (
108
+ mcp_sse_client(url) as (read, write),
109
+ ClientSession(
110
+ read,
111
+ write,
112
+ read_timeout_seconds=read_timeout_seconds,
113
+ sampling_callback=sampling_callback,
114
+ list_roots_callback=list_roots_callback,
115
+ ) as session,
116
+ ):
117
+ await session.initialize()
118
+ yield MCPClient(session)