fastapi-startkit 0.50.0__tar.gz → 0.52.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/PKG-INFO +62 -1
  2. fastapi_startkit-0.52.0/README.md +58 -0
  3. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/pyproject.toml +5 -3
  4. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/__init__.py +10 -10
  5. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/agent.py +99 -0
  6. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/ai.py +108 -0
  7. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/judge.py +34 -0
  8. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/pipeline.py +22 -2
  9. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/recording.py +182 -0
  10. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/runner.py +321 -0
  11. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/state.py +88 -0
  12. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/testing.py +596 -0
  13. fastapi_startkit-0.52.0/src/fastapi_startkit/ai/types.py +5 -0
  14. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/application.py +2 -0
  15. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/configuration/Configuration.py +1 -1
  16. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/container/container.py +4 -7
  17. fastapi_startkit-0.52.0/src/fastapi_startkit/events/__init__.py +13 -0
  18. fastapi_startkit-0.52.0/src/fastapi_startkit/events/dispatcher.py +141 -0
  19. fastapi_startkit-0.52.0/src/fastapi_startkit/events/fake.py +79 -0
  20. fastapi_startkit-0.52.0/src/fastapi_startkit/events/helpers.py +19 -0
  21. fastapi_startkit-0.52.0/src/fastapi_startkit/events/listener.py +16 -0
  22. fastapi_startkit-0.52.0/src/fastapi_startkit/events/provider.py +31 -0
  23. fastapi_startkit-0.52.0/src/fastapi_startkit/facades/Event.py +5 -0
  24. fastapi_startkit-0.52.0/src/fastapi_startkit/facades/Event.pyi +41 -0
  25. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/__init__.py +1 -0
  26. fastapi_startkit-0.52.0/src/fastapi_startkit/fastapi/__init__.py +15 -0
  27. fastapi_startkit-0.52.0/src/fastapi_startkit/fastapi/events.py +29 -0
  28. fastapi_startkit-0.52.0/src/fastapi_startkit/fastapi/middleware.py +54 -0
  29. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/providers/fastapi_provider.py +13 -1
  30. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/loader/Loader.py +1 -1
  31. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/collection/Collection.py +15 -2
  32. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/connections/factory.py +35 -14
  33. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/attribute.py +5 -0
  34. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/builder.py +72 -10
  35. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/model.py +47 -17
  36. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsToMany.py +28 -45
  37. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/MorphMany.py +23 -21
  38. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/MorphOne.py +21 -17
  39. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/MorphToMany.py +12 -8
  40. fastapi_startkit-0.52.0/src/fastapi_startkit/py.typed +0 -0
  41. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/support/providers/provider.py +3 -2
  42. fastapi_startkit-0.50.0/src/fastapi_startkit/ai/agent.py +0 -299
  43. fastapi_startkit-0.50.0/src/fastapi_startkit/ai/fakes.py +0 -53
  44. fastapi_startkit-0.50.0/src/fastapi_startkit/ai/model_builder.py +0 -47
  45. fastapi_startkit-0.50.0/src/fastapi_startkit/ai/response.py +0 -93
  46. fastapi_startkit-0.50.0/src/fastapi_startkit/ai/runner.py +0 -59
  47. fastapi_startkit-0.50.0/src/fastapi_startkit/ai/testing.py +0 -190
  48. fastapi_startkit-0.50.0/src/fastapi_startkit/fastapi/__init__.py +0 -6
  49. fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/.gitignore +0 -2
  50. fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/CACHEDIR.TAG +0 -4
  51. fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/README.md +0 -8
  52. fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/lastfailed +0 -3
  53. fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/nodeids +0 -1
  54. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/.DS_Store +0 -0
  55. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/__init__.py +0 -0
  56. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/audio.py +0 -0
  57. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/audio_factory.py +0 -0
  58. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/config/ai.py +0 -0
  59. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/config/config.py +0 -0
  60. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/decorators.py +0 -0
  61. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/document.py +0 -0
  62. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/image.py +0 -0
  63. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/image_factory.py +0 -0
  64. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/lab.py +0 -0
  65. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/providers/__init__.py +0 -0
  66. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/ai/providers/ai_provider.py +0 -0
  67. /fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm/config/__init__.py → /fastapi_startkit-0.52.0/src/fastapi_startkit/ai/tinker.py +0 -0
  68. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/__init__.py +0 -0
  69. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/auth.py +0 -0
  70. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/channels.py +0 -0
  71. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/config.py +0 -0
  72. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/drivers/__init__.py +0 -0
  73. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/drivers/log_driver.py +0 -0
  74. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/drivers/reverb_driver.py +0 -0
  75. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/event.py +0 -0
  76. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/helpers.py +0 -0
  77. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/manager.py +0 -0
  78. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/provider.py +0 -0
  79. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/reverb/__init__.py +0 -0
  80. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/reverb/channel_manager.py +0 -0
  81. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/reverb/connection.py +0 -0
  82. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/reverb/server.py +0 -0
  83. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/stubs/__init__.py +0 -0
  84. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/broadcasting/stubs/channels.py +0 -0
  85. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/carbon/__init__.py +0 -0
  86. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/carbon/carbon.py +0 -0
  87. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/config/__init__.py +0 -0
  88. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/config/app.py +0 -0
  89. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/configuration/__init__.py +0 -0
  90. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/configuration/config.py +0 -0
  91. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/configuration/helpers.py +0 -0
  92. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/configuration/providers/ConfigurationProvider.py +0 -0
  93. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/configuration/providers/__init__.py +0 -0
  94. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/console/__init__.py +0 -0
  95. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/console/application.py +0 -0
  96. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/console/can_override_config.py +0 -0
  97. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/console/can_override_default_options.py +0 -0
  98. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/console/command.py +0 -0
  99. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/console/publish_command.py +0 -0
  100. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/container/__init__.py +0 -0
  101. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/environment/__init__.py +0 -0
  102. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/environment/environment.py +0 -0
  103. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/exceptions/__init__.py +0 -0
  104. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/exceptions/exceptions.py +0 -0
  105. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/exceptions/handler.py +0 -0
  106. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/AI.py +0 -0
  107. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/AI.pyi +0 -0
  108. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Cache.py +0 -0
  109. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Config.py +0 -0
  110. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Config.pyi +0 -0
  111. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Dump.py +0 -0
  112. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Dump.pyi +0 -0
  113. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Facade.py +0 -0
  114. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Gate.py +0 -0
  115. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Gate.pyi +0 -0
  116. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Hash.py +0 -0
  117. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Hash.pyi +0 -0
  118. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Loader.py +0 -0
  119. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Loader.pyi +0 -0
  120. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Mail.py +0 -0
  121. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Mail.pyi +0 -0
  122. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Notification.py +0 -0
  123. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Notification.pyi +0 -0
  124. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Queue.py +0 -0
  125. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Queue.pyi +0 -0
  126. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/RateLimiter.py +0 -0
  127. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/RateLimiter.pyi +0 -0
  128. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Request.py +0 -0
  129. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Request.pyi +0 -0
  130. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Response.py +0 -0
  131. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Response.pyi +0 -0
  132. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Session.py +0 -0
  133. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Session.pyi +0 -0
  134. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Url.py +0 -0
  135. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Url.pyi +0 -0
  136. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/View.py +0 -0
  137. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/View.pyi +0 -0
  138. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Vite.py +0 -0
  139. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/facades/Vite.pyi +0 -0
  140. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/commands/__init__.py +0 -0
  141. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/commands/serve_command.py +0 -0
  142. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/config/__init__.py +0 -0
  143. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/config/fastapi.py +0 -0
  144. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/exceptions.py +0 -0
  145. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/requests/model.py +0 -0
  146. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/routers/router.py +0 -0
  147. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/testing/__init__.py +0 -0
  148. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/testing/assertable_json.py +0 -0
  149. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/testing/test_case.py +0 -0
  150. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/fastapi/testing/test_response.py +0 -0
  151. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/foundation/app_provider.py +0 -0
  152. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/inertia/__init__.py +0 -0
  153. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/inertia/constant.py +0 -0
  154. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/inertia/context.py +0 -0
  155. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/inertia/inertia.py +0 -0
  156. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/inertia/middleware.py +0 -0
  157. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/inertia/props/props.py +0 -0
  158. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/inertia/provider.py +0 -0
  159. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/jsonapi/__init__.py +0 -0
  160. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/jsonapi/response.py +0 -0
  161. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/loader/__init__.py +0 -0
  162. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/ChannelFactory.py +0 -0
  163. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/__init__.py +0 -0
  164. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/BaseChannel.py +0 -0
  165. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/DailyChannel.py +0 -0
  166. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/MultiBaseChannel.py +0 -0
  167. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/SingleChannel.py +0 -0
  168. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/SlackChannel.py +0 -0
  169. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/StackChannel.py +0 -0
  170. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/SyslogChannel.py +0 -0
  171. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/TerminalChannel.py +0 -0
  172. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/channels/__init__.py +0 -0
  173. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/config/__init__.py +0 -0
  174. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/config/channels.py +0 -0
  175. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/config/logging.py +0 -0
  176. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/drivers/BaseDriver.py +0 -0
  177. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/drivers/LogSingleDriver.py +0 -0
  178. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/drivers/LogSlackDriver.py +0 -0
  179. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/drivers/LogSyslogDriver.py +0 -0
  180. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py +0 -0
  181. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/drivers/__init__.py +0 -0
  182. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/factory.py +0 -0
  183. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/file.py +0 -0
  184. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/handler.py +0 -0
  185. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/listeners.py +0 -0
  186. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/logger.py +0 -0
  187. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/managers/LoggingManager.py +0 -0
  188. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/managers/__init__.py +0 -0
  189. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/providers/__init__.py +0 -0
  190. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/logging/providers/log_provider.py +0 -0
  191. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/__init__.py +0 -0
  192. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/collection/__init__.py +0 -0
  193. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/DBMigrateCommand.py +0 -0
  194. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/DBSeedCommand.py +0 -0
  195. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py +0 -0
  196. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelCommand.py +0 -0
  197. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelDocstringCommand.py +0 -0
  198. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MakeObserverCommand.py +0 -0
  199. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MakeSeedCommand.py +0 -0
  200. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py +0 -0
  201. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRefreshCommand.py +0 -0
  202. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MigrateResetCommand.py +0 -0
  203. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRollbackCommand.py +0 -0
  204. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/MigrateStatusCommand.py +0 -0
  205. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py +0 -0
  206. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/__init__.py +0 -0
  207. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub +0 -0
  208. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_seed.stub +0 -0
  209. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/stubs/model.stub +0 -0
  210. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/stubs/observer.stub +0 -0
  211. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub +0 -0
  212. {fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm/helpers → fastapi_startkit-0.52.0/src/fastapi_startkit/masoniteorm/config}/__init__.py +0 -0
  213. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/config/config.py +0 -0
  214. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/config/database.py +0 -0
  215. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/connections/connection.py +0 -0
  216. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/connections/manager.py +0 -0
  217. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py +0 -0
  218. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/connections/postgres_connection.py +0 -0
  219. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/connections/sqlite_connection.py +0 -0
  220. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/exceptions.py +0 -0
  221. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/expressions/__init__.py +0 -0
  222. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/expressions/expressions.py +0 -0
  223. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/facades/DB.py +0 -0
  224. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/facades/Schema.py +0 -0
  225. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/facades/__init__.py +0 -0
  226. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/factory/__init__.py +0 -0
  227. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/factory/factory.py +0 -0
  228. {fastapi_startkit-0.50.0/src/fastapi_startkit/masoniteorm/query → fastapi_startkit-0.52.0/src/fastapi_startkit/masoniteorm/helpers}/__init__.py +0 -0
  229. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/helpers/misc.py +0 -0
  230. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/migrations/Migration.py +0 -0
  231. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/migrations/Migrator.py +0 -0
  232. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/migrations/__init__.py +0 -0
  233. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/MigrationModel.py +0 -0
  234. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/__init__.py +0 -0
  235. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/caster.py +0 -0
  236. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/fields.py +0 -0
  237. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/observer.py +0 -0
  238. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/pivot.py +0 -0
  239. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/registry.py +0 -0
  240. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/models/relationship.py +0 -0
  241. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/observers/ObservesEvents.py +0 -0
  242. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/observers/__init__.py +0 -0
  243. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/pagination/BasePaginator.py +0 -0
  244. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/pagination/LengthAwarePaginator.py +0 -0
  245. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/pagination/SimplePaginator.py +0 -0
  246. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/pagination/__init__.py +0 -0
  247. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py +0 -0
  248. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/providers/__init__.py +0 -0
  249. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/EagerLoadMixin.py +0 -0
  250. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/EagerRelation.py +0 -0
  251. {fastapi_startkit-0.50.0/src/fastapi_startkit/mcp/providers → fastapi_startkit-0.52.0/src/fastapi_startkit/masoniteorm/query}/__init__.py +0 -0
  252. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/grammars/BaseGrammar.py +0 -0
  253. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/grammars/MSSQLGrammar.py +0 -0
  254. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/grammars/MySQLGrammar.py +0 -0
  255. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/grammars/PostgresGrammar.py +0 -0
  256. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/grammars/SQLiteGrammar.py +0 -0
  257. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/grammars/__init__.py +0 -0
  258. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/processors/MSSQLPostProcessor.py +0 -0
  259. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/processors/MySQLPostProcessor.py +0 -0
  260. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/processors/PostgresPostProcessor.py +0 -0
  261. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/processors/SQLitePostProcessor.py +0 -0
  262. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/processors/__init__.py +0 -0
  263. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/query/support.py +0 -0
  264. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/BaseRelationship.py +0 -0
  265. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py +0 -0
  266. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/HasMany.py +0 -0
  267. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/HasManyThrough.py +0 -0
  268. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/HasOne.py +0 -0
  269. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/HasOneThrough.py +0 -0
  270. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/MorphTo.py +0 -0
  271. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/relationships/__init__.py +0 -0
  272. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/Blueprint.py +0 -0
  273. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/Column.py +0 -0
  274. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/ColumnDiff.py +0 -0
  275. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/Constraint.py +0 -0
  276. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/ForeignKeyConstraint.py +0 -0
  277. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/Index.py +0 -0
  278. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/Table.py +0 -0
  279. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/TableDiff.py +0 -0
  280. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/__init__.py +0 -0
  281. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MSSQLPlatform.py +0 -0
  282. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MySQLPlatform.py +0 -0
  283. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/platforms/Platform.py +0 -0
  284. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/platforms/PostgresPlatform.py +0 -0
  285. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/platforms/SQLitePlatform.py +0 -0
  286. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/platforms/__init__.py +0 -0
  287. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/schema/schema.py +0 -0
  288. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/seeders/Seeder.py +0 -0
  289. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/seeders/__init__.py +0 -0
  290. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/stubs/create-migration.html +0 -0
  291. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/stubs/table-migration.html +0 -0
  292. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/testing/__init__.py +0 -0
  293. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/masoniteorm/testing/transaction.py +0 -0
  294. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/__init__.py +0 -0
  295. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/argument.py +0 -0
  296. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/prompt.py +0 -0
  297. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/protocol.py +0 -0
  298. /fastapi_startkit-0.50.0/src/fastapi_startkit/py.typed → /fastapi_startkit-0.52.0/src/fastapi_startkit/mcp/providers/__init__.py +0 -0
  299. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/providers/mcp_provider.py +0 -0
  300. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/request.py +0 -0
  301. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/resource.py +0 -0
  302. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/response.py +0 -0
  303. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/server.py +0 -0
  304. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/mcp/tool.py +0 -0
  305. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/process/__init__.py +0 -0
  306. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/process/exception.py +0 -0
  307. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/process/fake.py +0 -0
  308. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/process/process.py +0 -0
  309. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/process/result.py +0 -0
  310. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/__init__.py +0 -0
  311. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/adapters/__init__.py +0 -0
  312. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/adapters/base.py +0 -0
  313. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/adapters/claude.py +0 -0
  314. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/adapters/gemini.py +0 -0
  315. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/commands/__init__.py +0 -0
  316. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/commands/skills.py +0 -0
  317. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/parser.py +0 -0
  318. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/provider.py +0 -0
  319. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/registry.py +0 -0
  320. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/database/SKILL.md +0 -0
  321. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/fastapi/SKILL.md +0 -0
  322. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/inertia/SKILL.md +0 -0
  323. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/__init__.py +0 -0
  324. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/config/__init__.py +0 -0
  325. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/config/storage.py +0 -0
  326. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/data/mime.types +0 -0
  327. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/drivers/__init__.py +0 -0
  328. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/drivers/fake.py +0 -0
  329. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/drivers/local.py +0 -0
  330. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/drivers/s3.py +0 -0
  331. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/file.py +0 -0
  332. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/filestream.py +0 -0
  333. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/helper.py +0 -0
  334. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/providers/provider.py +0 -0
  335. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/storage/storage.py +0 -0
  336. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/support/__init__.py +0 -0
  337. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/support/collection.py +0 -0
  338. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/support/dataclass.py +0 -0
  339. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/support/providers/__init__.py +0 -0
  340. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/support/string.py +0 -0
  341. {fastapi_startkit-0.50.0/src/fastapi_startkit/utils → fastapi_startkit-0.52.0/src/fastapi_startkit/support}/structures.py +0 -0
  342. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/support/uri.py +0 -0
  343. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/testing/__init__.py +0 -0
  344. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/testing/test_case.py +0 -0
  345. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/__init__.py +0 -0
  346. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/config/vite.py +0 -0
  347. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/exceptions.py +0 -0
  348. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/providers/provider.py +0 -0
  349. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/stubs/package.json +0 -0
  350. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/stubs/resources/css/app.css +0 -0
  351. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/stubs/resources/js/app.ts +0 -0
  352. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/stubs/resources/templates/index.html +0 -0
  353. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/stubs/tsconfig.json +0 -0
  354. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/stubs/vite.config.ts +0 -0
  355. {fastapi_startkit-0.50.0 → fastapi_startkit-0.52.0}/src/fastapi_startkit/vite/vite.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastapi-startkit
3
- Version: 0.50.0
3
+ Version: 0.52.0
4
4
  Summary: A modular, provider-driven framework for building async Python web applications with FastAPI — bundling a service container, configuration system, an async-first ORM, facades, and a Cleo-powered console.
5
5
  Keywords: fastapi,framework,async,web,asgi,orm,sqlalchemy,pydantic,ioc-container,dependency-injection,service-provider,cli,console,configuration,microservices,starter-kit,boilerplate
6
6
  Author: Bedram Tamang
@@ -22,6 +22,7 @@ Requires-Dist: dotenv>=0.9.9
22
22
  Requires-Dist: pydantic>=2.12.5
23
23
  Requires-Dist: langchain>=1.0.0 ; extra == 'ai'
24
24
  Requires-Dist: langchain-core>=1.0.0 ; extra == 'ai'
25
+ Requires-Dist: langgraph>=1.0.0 ; extra == 'ai'
25
26
  Requires-Dist: faker>=40.13.0 ; extra == 'database'
26
27
  Requires-Dist: sqlalchemy[asyncio]>=2.0.38 ; extra == 'database'
27
28
  Requires-Dist: fastapi[standard]>=0.124.4 ; extra == 'fastapi'
@@ -46,3 +47,63 @@ Provides-Extra: mysql
46
47
  Provides-Extra: postgres
47
48
  Provides-Extra: sqlite
48
49
  Provides-Extra: vite
50
+ Description-Content-Type: text/markdown
51
+
52
+ # FastAPI Startkit
53
+
54
+ [![codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework/graph/badge.svg)](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework)
55
+ [![PyPI version](https://img.shields.io/pypi/v/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
56
+ [![Python versions](https://img.shields.io/pypi/pyversions/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
57
+
58
+ A modular, provider-driven framework for building Python applications with FastAPI. It bundles a
59
+ service container, configuration system, an async-first ORM, facades, and a Cleo-powered console into
60
+ a single cohesive foundation.
61
+
62
+ ## Installation
63
+
64
+ ```bash
65
+ pip install fastapi-startkit
66
+ ```
67
+
68
+ Optional extras enable additional capabilities:
69
+
70
+ ```bash
71
+ fastapi-startkit[fastapi] # FastAPI + Starlette
72
+ fastapi-startkit[database] # SQLAlchemy async ORM
73
+ fastapi-startkit[vite] # Jinja2 for Vite integration
74
+ ```
75
+
76
+ ## Features
77
+
78
+ - **Service container** — IoC container with `bind`/`make`/`resolve` auto-wiring and lifecycle hooks.
79
+ - **Configuration** — dataclass-based config sourced from the environment with dotted-key access.
80
+ - **Providers** — two-phase (`register` / `boot`) service registration.
81
+ - **Routing** — a `Router` wrapper around FastAPI's `APIRouter` with a `resource()` CRUD shortcut.
82
+ - **ORM** — async-first Masonite ORM fork on SQLAlchemy async, with relationships and migrations.
83
+ - **Facades** — static-like access to container-resolved services (`Config`, `Auth`, ...).
84
+ - **Console** — Cleo-based CLI (`artisan`) for migrations, seeders, and code generation.
85
+
86
+ ## Documentation
87
+
88
+ Full documentation is available at
89
+ [fastapi-startkit.github.io](https://fastapi-startkit.github.io).
90
+
91
+ ## Development
92
+
93
+ ```bash
94
+ # Install dependencies
95
+ uv sync --group dev --extra database --extra sqlite --extra fastapi --extra vite --extra postgres
96
+
97
+ # Run the test suite
98
+ uv run pytest tests/ -v
99
+
100
+ # Run tests with coverage
101
+ uv run pytest --cov --cov-report=term-missing
102
+ ```
103
+
104
+ Coverage is collected in CI and reported to
105
+ [Codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework).
106
+
107
+ ## License
108
+
109
+ See the repository root for license details.
@@ -0,0 +1,58 @@
1
+ # FastAPI Startkit
2
+
3
+ [![codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework/graph/badge.svg)](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework)
4
+ [![PyPI version](https://img.shields.io/pypi/v/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
6
+
7
+ A modular, provider-driven framework for building Python applications with FastAPI. It bundles a
8
+ service container, configuration system, an async-first ORM, facades, and a Cleo-powered console into
9
+ a single cohesive foundation.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install fastapi-startkit
15
+ ```
16
+
17
+ Optional extras enable additional capabilities:
18
+
19
+ ```bash
20
+ fastapi-startkit[fastapi] # FastAPI + Starlette
21
+ fastapi-startkit[database] # SQLAlchemy async ORM
22
+ fastapi-startkit[vite] # Jinja2 for Vite integration
23
+ ```
24
+
25
+ ## Features
26
+
27
+ - **Service container** — IoC container with `bind`/`make`/`resolve` auto-wiring and lifecycle hooks.
28
+ - **Configuration** — dataclass-based config sourced from the environment with dotted-key access.
29
+ - **Providers** — two-phase (`register` / `boot`) service registration.
30
+ - **Routing** — a `Router` wrapper around FastAPI's `APIRouter` with a `resource()` CRUD shortcut.
31
+ - **ORM** — async-first Masonite ORM fork on SQLAlchemy async, with relationships and migrations.
32
+ - **Facades** — static-like access to container-resolved services (`Config`, `Auth`, ...).
33
+ - **Console** — Cleo-based CLI (`artisan`) for migrations, seeders, and code generation.
34
+
35
+ ## Documentation
36
+
37
+ Full documentation is available at
38
+ [fastapi-startkit.github.io](https://fastapi-startkit.github.io).
39
+
40
+ ## Development
41
+
42
+ ```bash
43
+ # Install dependencies
44
+ uv sync --group dev --extra database --extra sqlite --extra fastapi --extra vite --extra postgres
45
+
46
+ # Run the test suite
47
+ uv run pytest tests/ -v
48
+
49
+ # Run tests with coverage
50
+ uv run pytest --cov --cov-report=term-missing
51
+ ```
52
+
53
+ Coverage is collected in CI and reported to
54
+ [Codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework).
55
+
56
+ ## License
57
+
58
+ See the repository root for license details.
@@ -1,7 +1,8 @@
1
1
  [project]
2
2
  name = "fastapi-startkit"
3
- version = "0.50.0"
3
+ version = "0.52.0"
4
4
  description = "A modular, provider-driven framework for building async Python web applications with FastAPI — bundling a service container, configuration system, an async-first ORM, facades, and a Cleo-powered console."
5
+ readme = "README.md"
5
6
  keywords = [
6
7
  "fastapi",
7
8
  "framework",
@@ -86,6 +87,7 @@ inertia = [
86
87
  ai = [
87
88
  "langchain>=1.0.0",
88
89
  "langchain-core>=1.0.0",
90
+ "langgraph>=1.0.0",
89
91
  ]
90
92
 
91
93
  [dependency-groups]
@@ -129,7 +131,7 @@ exclude = [
129
131
  "**/__pycache__",
130
132
  "**/.venv",
131
133
  ]
132
- typeCheckingMode = "basic"
134
+ typeCheckingMode = "standard"
133
135
  pythonVersion = "3.12"
134
136
 
135
137
  [tool.pytest.ini_options]
@@ -148,7 +150,7 @@ omit = [
148
150
  [tool.coverage.report]
149
151
  show_missing = true
150
152
  skip_covered = false
151
- fail_under = 68
153
+ fail_under = 80
152
154
  exclude_lines = [
153
155
  "pragma: no cover",
154
156
  "if TYPE_CHECKING:",
@@ -6,31 +6,31 @@ from .config.config import AnthropicConfig, ElevenLabsConfig, GoogleConfig, Open
6
6
  from .config.ai import AIConfig
7
7
  from .decorators import max_steps, max_tokens, model, provider, timeout, top_p
8
8
  from .document import Document
9
- from .fakes import fake_chat_model
10
9
  from .image import Image, ImageResponse
11
10
  from .image_factory import ImageFactory
11
+ from .ai import Ai
12
+ from .judge import JudgeAgent
12
13
  from .providers.ai_provider import AIProvider
13
- from .response import AgentResponse, AgentSnapshot
14
- from .testing import AgentBinding, FakeAgent, NoFakeResponse, RecordingAgent
14
+ from . import state
15
+ from .testing import AgentFake, AgentRecordFake, AssertToolCall
15
16
 
16
17
  __all__ = [
17
18
  "Agent",
19
+ "Ai",
18
20
  "Middleware",
19
- "AgentBinding",
20
- "AgentResponse",
21
- "AgentSnapshot",
21
+ "AgentFake",
22
+ "state",
22
23
  "AIConfig",
23
24
  "AIProvider",
24
25
  "AnthropicConfig",
25
- "FakeAgent",
26
- "NoFakeResponse",
27
- "RecordingAgent",
26
+ "JudgeAgent",
27
+ "AgentRecordFake",
28
+ "AssertToolCall",
28
29
  "Audio",
29
30
  "AudioResponse",
30
31
  "AudioFactory",
31
32
  "Document",
32
33
  "ElevenLabsConfig",
33
- "fake_chat_model",
34
34
  "GoogleConfig",
35
35
  "Image",
36
36
  "ImageFactory",
@@ -0,0 +1,99 @@
1
+ from __future__ import annotations
2
+
3
+ import functools
4
+ from typing import TYPE_CHECKING, AsyncIterator, Callable, Generic, Optional, Type, TypeVar
5
+
6
+ from .document import Document
7
+ from .runner import BaseRunner, Runner
8
+
9
+ if TYPE_CHECKING:
10
+ from langchain_core.tools import BaseTool
11
+
12
+ from .testing import AgentFake, AgentRecordFake
13
+ from .types import Middleware
14
+
15
+ _R = TypeVar("_R")
16
+
17
+
18
+ class _hybridmethod(Generic[_R]):
19
+ """A method callable on the class (bound to a freshly built instance) or on an
20
+ existing instance (bound to that instance). Lets ``Agent.record()`` and
21
+ ``Agent(state, config).record()`` both work, the latter keeping its state."""
22
+
23
+ def __init__(self, func: Callable[..., _R]) -> None:
24
+ self._func = func
25
+
26
+ def __get__(self, instance: object, owner: type) -> Callable[..., _R]:
27
+ target = instance if instance is not None else owner()
28
+ return functools.partial(self._func, target)
29
+
30
+
31
+ class Agent:
32
+ provider: str | None = None
33
+ model: str | None = None
34
+ max_steps: int = 10
35
+ max_tokens: int = 4096
36
+ timeout: float = 30.0
37
+ top_p: float = 1.0
38
+ temperature: float | None = None
39
+ tool_choice: str | None = None
40
+
41
+ def messages(self) -> list[dict]:
42
+ return []
43
+
44
+ def instructions(self) -> str | None:
45
+ return None
46
+
47
+ def schema(self) -> Optional[Type]:
48
+ return None
49
+
50
+ def tools(self) -> list[BaseTool]:
51
+ return []
52
+
53
+ def middleware(self) -> list[Middleware]:
54
+ return []
55
+
56
+ def provider_options(self) -> dict:
57
+ return {}
58
+
59
+ async def prompt(
60
+ self,
61
+ message: str,
62
+ *,
63
+ model: str | None = None,
64
+ attachments: list[Document] | None = None,
65
+ provider_options: dict | None = None,
66
+ ) -> dict:
67
+ """Returns the turn as ``{"messages": [HumanMessage, AIMessage, ToolMessage,
68
+ ...]}`` — the same state langchain's ``create_agent().invoke()`` yields —
69
+ plus ``"structured_response"`` when the agent defines a schema()."""
70
+ return await self.runner().run(message, model=model, attachments=attachments, provider_options=provider_options)
71
+
72
+ async def stream(
73
+ self,
74
+ message: str,
75
+ *,
76
+ model: str | None = None,
77
+ provider_options: dict | None = None,
78
+ ) -> AsyncIterator[dict]:
79
+ """Yields StandardStreamEvent dicts — the same shape LangChain's
80
+ astream_events produces: on_chat_model_(start|stream|end) for the model
81
+ turn (data.chunk carries each AIMessageChunk) and on_tool_(start|end)
82
+ around each tool execution."""
83
+ async for chunk in self.runner().stream(message, model=model, provider_options=provider_options):
84
+ yield chunk
85
+
86
+ def runner(self) -> BaseRunner:
87
+ return Runner(self)
88
+
89
+ @classmethod
90
+ def fake(cls, responses: list) -> "AgentFake":
91
+ from .testing import AgentFake
92
+
93
+ return AgentFake(cls, responses)
94
+
95
+ @_hybridmethod
96
+ def record(self, cassette: str | None = None, messages: list | None = None) -> "AgentRecordFake":
97
+ from .testing import AgentRecordFake
98
+
99
+ return AgentRecordFake(self, cassette, messages)
@@ -0,0 +1,108 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from .lab import Lab
6
+
7
+ if TYPE_CHECKING:
8
+ from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
9
+
10
+ from .agent import Agent
11
+
12
+
13
+ class Ai:
14
+ _fakes: dict[str, GenericFakeChatModel] = {}
15
+
16
+ def __init__(self) -> None:
17
+ pass
18
+
19
+ @staticmethod
20
+ def _key(agent: "Agent | str") -> str:
21
+ return agent if isinstance(agent, str) else type(agent).__name__
22
+
23
+ @classmethod
24
+ def fake(cls, agent: "Agent | str", messages: list) -> Any:
25
+ from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
26
+ from langchain_core.messages import AIMessage
27
+
28
+ turns = [message if hasattr(message, "content") else AIMessage(content=str(message)) for message in messages]
29
+ model = GenericFakeChatModel(messages=iter(turns))
30
+ cls._fakes[cls._key(agent)] = model
31
+ return model
32
+
33
+ @classmethod
34
+ def has_fake_model_for(cls, agent: "Agent | str") -> bool:
35
+ return cls._key(agent) in cls._fakes
36
+
37
+ @classmethod
38
+ def get_fake_model_for(cls, agent: "Agent | str") -> Any:
39
+ return cls._fakes[cls._key(agent)]
40
+
41
+ @classmethod
42
+ def forget(cls, agent: "Agent | str") -> None:
43
+ cls._fakes.pop(cls._key(agent), None)
44
+
45
+ @classmethod
46
+ def reset_fakes(cls) -> None:
47
+ cls._fakes.clear()
48
+
49
+ def get_model_for(
50
+ self,
51
+ agent: "Agent",
52
+ model: str | None = None,
53
+ provider_options: dict | None = None,
54
+ ) -> Any:
55
+ if self.has_fake_model_for(agent):
56
+ return self.get_fake_model_for(agent)
57
+ return self.build(agent, model, provider_options)
58
+
59
+ def build(
60
+ self,
61
+ agent: "Agent",
62
+ model: str | None = None,
63
+ provider_options: dict | None = None,
64
+ ) -> Any:
65
+ from langchain.chat_models import init_chat_model # noqa: PLC0415
66
+
67
+ lab = Lab.get_provider(agent.provider)
68
+ kwargs: dict[str, Any] = {"model_provider": lab.get_provider_key()}
69
+
70
+ api_key = lab.get_api_key()
71
+ if api_key:
72
+ kwargs["api_key"] = api_key
73
+ if agent.max_tokens:
74
+ kwargs["max_tokens"] = agent.max_tokens
75
+ if agent.top_p != 1.0:
76
+ kwargs["top_p"] = agent.top_p
77
+ if agent.temperature is not None:
78
+ kwargs["temperature"] = agent.temperature
79
+ if agent.timeout:
80
+ kwargs["timeout"] = agent.timeout
81
+
82
+ kwargs.update(self._resolve_provider_options(agent, provider_options))
83
+
84
+ chat_model = init_chat_model(self._resolve_model(agent, model), **kwargs)
85
+
86
+ tools = list(agent.tools())
87
+ if tools:
88
+ if agent.tool_choice:
89
+ chat_model = chat_model.bind_tools(tools, tool_choice=agent.tool_choice)
90
+ else:
91
+ chat_model = chat_model.bind_tools(tools)
92
+
93
+ schema = agent.schema()
94
+ if schema is not None:
95
+ chat_model = chat_model.with_structured_output(schema, include_raw=True)
96
+
97
+ return chat_model
98
+
99
+ def _resolve_model(self, agent: "Agent", override: str | None = None) -> str:
100
+ return Lab.get_provider(agent.provider).get_model(override or agent.model or None)
101
+
102
+ def _resolve_provider_options(self, agent: "Agent", override: dict | None = None) -> dict:
103
+ options = dict(agent.provider_options().get(agent.provider, {}))
104
+ if override:
105
+ provider_specific = override.get(agent.provider, override)
106
+ if isinstance(provider_specific, dict):
107
+ options.update(provider_specific)
108
+ return options
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from .agent import Agent
6
+
7
+
8
+ class Verdict(BaseModel):
9
+ passed: bool
10
+ reasoning: str = ""
11
+
12
+
13
+ class JudgeAgent(Agent):
14
+ """Grades a response against a natural-language expectation.
15
+
16
+ A plain ``Agent`` whose ``schema()`` is a ``Verdict`` model, so the JSON
17
+ reply is parsed into a typed result through the standard structured-output
18
+ path — no hand-rolled verdict parsing. Set ``.model``/``.provider`` like
19
+ any other agent; it's fakeable via ``fake()`` and replayable via
20
+ ``record()`` for free.
21
+ """
22
+
23
+ def instructions(self) -> str:
24
+ return (
25
+ "You are grading whether an AI agent's response satisfies an expectation. "
26
+ 'Reply with strict JSON only, no prose: {"passed": true|false, "reasoning": "<one sentence>"}'
27
+ )
28
+
29
+ def schema(self):
30
+ return Verdict
31
+
32
+ async def judge(self, expectation: str, content: str) -> dict:
33
+ state = await self.prompt(f"Expectation: {expectation}\n\nResponse to grade:\n{content}")
34
+ return state["structured_response"].model_dump()
@@ -40,13 +40,33 @@ class Response:
40
40
  await result
41
41
  return final
42
42
 
43
+ @staticmethod
44
+ def _merge(accumulated: Any, chunk: Any) -> Any:
45
+ # Stream events (astream_events shape) merge into joined text for the
46
+ # after-hooks: model chunks and tool outputs contribute their text, the
47
+ # start/end envelopes add nothing. Any other dict (e.g. a
48
+ # structured-output result carrying "raw"/"parsed") passes through whole.
49
+ if isinstance(chunk, dict) and "event" in chunk:
50
+ data = chunk.get("data") or {}
51
+ if chunk["event"] == "on_chat_model_stream":
52
+ text = getattr(data.get("chunk"), "content", "") or ""
53
+ elif chunk["event"] == "on_tool_end":
54
+ text = getattr(data.get("output"), "content", "") or ""
55
+ else:
56
+ text = ""
57
+ text = text if isinstance(text, str) else str(text)
58
+ if accumulated is None:
59
+ return text or None
60
+ return accumulated + text
61
+ return chunk if accumulated is None else accumulated + chunk
62
+
43
63
  def __aiter__(self) -> AsyncIterator:
44
64
  async def _it() -> AsyncIterator:
45
65
  accumulated = None
46
66
  finished = False
47
67
  try:
48
68
  async for chunk in self._source():
49
- accumulated = chunk if accumulated is None else accumulated + chunk
69
+ accumulated = self._merge(accumulated, chunk)
50
70
  yield chunk
51
71
  finished = True
52
72
  await self._finish(accumulated)
@@ -63,7 +83,7 @@ class Response:
63
83
  async def _run() -> Any:
64
84
  accumulated = None
65
85
  async for chunk in self._source():
66
- accumulated = chunk if accumulated is None else accumulated + chunk
86
+ accumulated = self._merge(accumulated, chunk)
67
87
  return await self._finish(accumulated)
68
88
 
69
89
  return _run().__await__()
@@ -0,0 +1,182 @@
1
+ """Ordered per-turn recording format for ``Agent.record()`` cassettes.
2
+
3
+ A recorded turn is an ordered list of message dicts that captures the full
4
+ interaction for one user input — the human prompt, every model turn (with its
5
+ token ``uses`` and ``response_time``), and every tool call (with the tool's
6
+ response and its own ``response_time``). Persisting the whole ordered exchange —
7
+ rather than only the final answer — lets recordings be replayed and inspected
8
+ faithfully.
9
+
10
+ [
11
+ {"type": "human", "content": "suggest me jobs"},
12
+ {"type": "ai", "tool_calls": [...], "uses": {...}, "response_time": 12.0},
13
+ {"type": "tool_response", "content_type": "json", "content": "[...]", "response_time": 5.0},
14
+ {"type": "ai", "content": "Here is a job...", "uses": {...}, "response_time": 8.0},
15
+ ]
16
+
17
+ ``response_time`` is milliseconds; ``uses`` mirrors LangChain ``usage_metadata``
18
+ as ``input_token`` / ``output_token`` / ``cache_token`` / ``total_token``.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ from typing import Any
25
+
26
+ from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, ToolMessage
27
+
28
+
29
+ def _infer_content_type(content: str) -> str:
30
+ try:
31
+ json.loads(content)
32
+ except (ValueError, TypeError):
33
+ return "text"
34
+ return "json"
35
+
36
+
37
+ def uses_from_usage_metadata(meta: dict | None) -> dict:
38
+ """Map a LangChain ``usage_metadata`` dict onto the cassette ``uses`` shape."""
39
+ meta = meta or {}
40
+ details = meta.get("input_token_details") or {}
41
+ return {
42
+ "input_token": meta.get("input_tokens", 0),
43
+ "output_token": meta.get("output_tokens", 0),
44
+ "cache_token": details.get("cache_read", 0),
45
+ "total_token": meta.get("total_tokens", 0),
46
+ }
47
+
48
+
49
+ def is_transcript(value: Any) -> bool:
50
+ """True when ``value`` is a new-format ordered transcript (list of typed entries)."""
51
+ return isinstance(value, list) and bool(value) and isinstance(value[0], dict) and "type" in value[0]
52
+
53
+
54
+ def human(content: str) -> dict:
55
+ """Build a ``human`` transcript entry."""
56
+ return {"type": "human", "content": content}
57
+
58
+
59
+ def ai(
60
+ content: str = "",
61
+ tool_calls: list[dict] | None = None,
62
+ uses: dict | None = None,
63
+ response_time: float = 0.0,
64
+ chunks: list[str] | None = None,
65
+ ) -> dict:
66
+ """Build an ``ai`` transcript entry (a model turn: answer and/or tool calls)."""
67
+ entry: dict[str, Any] = {"type": "ai"}
68
+ if content:
69
+ entry["content"] = content
70
+ if tool_calls:
71
+ entry["tool_calls"] = tool_calls
72
+ entry["uses"] = uses or {}
73
+ entry["response_time"] = response_time
74
+ if chunks is not None:
75
+ entry["chunks"] = chunks
76
+ return entry
77
+
78
+
79
+ def tool_response(content: str, response_time: float = 0.0, content_type: str | None = None) -> dict:
80
+ """Build a ``tool_response`` transcript entry (a tool's output)."""
81
+ return {
82
+ "type": "tool_response",
83
+ "content_type": content_type or _infer_content_type(content),
84
+ "content": content,
85
+ "response_time": response_time,
86
+ }
87
+
88
+
89
+ def usage_metadata_from_uses(uses: dict) -> dict:
90
+ """Map a cassette ``uses`` dict back onto LangChain ``usage_metadata``."""
91
+ return {
92
+ "input_tokens": uses.get("input_token", 0),
93
+ "output_tokens": uses.get("output_token", 0),
94
+ "total_tokens": uses.get("total_token", 0),
95
+ "input_token_details": {"cache_read": uses.get("cache_token", 0)},
96
+ }
97
+
98
+
99
+ def _as_text(content: Any) -> str:
100
+ return content if isinstance(content, str) else str(content)
101
+
102
+
103
+ def entries_from_messages(messages: list[BaseMessage]) -> list[dict]:
104
+ """Convert a turn's AI/tool LangChain messages into cassette entries.
105
+
106
+ Human (and system) messages are skipped — the cassette turn opens with its
107
+ own ``human`` entry. ``response_time`` is read from ``additional_kwargs``,
108
+ where the runner stamps it on every AI and tool message."""
109
+ entries: list[dict] = []
110
+ for message in messages or []:
111
+ kind = getattr(message, "type", "")
112
+ response_time = (getattr(message, "additional_kwargs", None) or {}).get("response_time", 0.0)
113
+ if kind == "ai":
114
+ entries.append(
115
+ ai(
116
+ content=_as_text(message.content),
117
+ tool_calls=list(getattr(message, "tool_calls", None) or []),
118
+ uses=uses_from_usage_metadata(getattr(message, "usage_metadata", None)),
119
+ response_time=response_time,
120
+ )
121
+ )
122
+ elif kind == "tool":
123
+ entries.append(tool_response(content=_as_text(message.content), response_time=response_time))
124
+ return entries
125
+
126
+
127
+ def messages_from_transcript(transcript: list[dict]) -> list[BaseMessage]:
128
+ """Rebuild the turn's LangChain messages from cassette entries, so a replayed
129
+ response carries the same ``messages`` a live run produces. Cassette entries
130
+ don't store the tool's name/call id, so those stay empty on replay."""
131
+ messages: list[BaseMessage] = []
132
+ for entry in transcript:
133
+ kind = entry.get("type")
134
+ if kind == "human":
135
+ messages.append(HumanMessage(content=entry.get("content", "")))
136
+ elif kind == "ai":
137
+ uses = entry.get("uses") or {}
138
+ messages.append(
139
+ AIMessage(
140
+ content=entry.get("content", ""),
141
+ tool_calls=entry.get("tool_calls") or [],
142
+ additional_kwargs={"response_time": entry.get("response_time", 0.0)},
143
+ usage_metadata=usage_metadata_from_uses(uses) if uses else None,
144
+ )
145
+ )
146
+ elif kind == "tool_response":
147
+ messages.append(
148
+ ToolMessage(
149
+ content=entry.get("content", ""),
150
+ tool_call_id="",
151
+ additional_kwargs={"response_time": entry.get("response_time", 0.0)},
152
+ )
153
+ )
154
+ return messages
155
+
156
+
157
+ def to_state(transcript: list[dict]) -> dict:
158
+ """Reconstruct a turn's ``{"messages": [...]}`` state from cassette entries,
159
+ so a replayed turn has the same shape a live run returns."""
160
+ return {"messages": messages_from_transcript(transcript)}
161
+
162
+
163
+ def accumulate_uses(messages: list, totals: dict) -> None:
164
+ """Add every AI message's token usage in a turn's ``messages`` into ``totals``
165
+ (keys: input, output, cache, total)."""
166
+ for message in messages or []:
167
+ if getattr(message, "type", "") != "ai":
168
+ continue
169
+ uses = uses_from_usage_metadata(getattr(message, "usage_metadata", None))
170
+ totals["input"] += uses["input_token"]
171
+ totals["output"] += uses["output_token"]
172
+ totals["cache"] += uses["cache_token"]
173
+ totals["total"] += uses["total_token"]
174
+
175
+
176
+ def chunks_from_transcript(transcript: list[dict]) -> list[str]:
177
+ """Collect streamed chunks recorded on the turn's ``ai`` messages."""
178
+ chunks: list[str] = []
179
+ for entry in transcript:
180
+ if entry.get("type") == "ai" and entry.get("chunks"):
181
+ chunks.extend(entry["chunks"])
182
+ return chunks