fastapi-startkit 0.51.0__tar.gz → 0.53.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 (354) hide show
  1. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/PKG-INFO +2 -1
  2. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/pyproject.toml +3 -2
  3. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/__init__.py +10 -10
  4. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/agent.py +99 -0
  5. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/ai.py +108 -0
  6. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/judge.py +34 -0
  7. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/pipeline.py +22 -2
  8. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/recording.py +182 -0
  9. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/runner.py +321 -0
  10. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/state.py +88 -0
  11. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/testing.py +596 -0
  12. fastapi_startkit-0.53.0/src/fastapi_startkit/ai/types.py +5 -0
  13. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/application.py +5 -6
  14. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/Configuration.py +1 -1
  15. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/loader/Loader.py +1 -1
  16. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/collection/Collection.py +15 -2
  17. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/builder.py +18 -8
  18. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/model.py +10 -13
  19. fastapi_startkit-0.53.0/src/fastapi_startkit/py.typed +0 -0
  20. fastapi_startkit-0.51.0/src/fastapi_startkit/ai/agent.py +0 -299
  21. fastapi_startkit-0.51.0/src/fastapi_startkit/ai/fakes.py +0 -53
  22. fastapi_startkit-0.51.0/src/fastapi_startkit/ai/model_builder.py +0 -47
  23. fastapi_startkit-0.51.0/src/fastapi_startkit/ai/response.py +0 -93
  24. fastapi_startkit-0.51.0/src/fastapi_startkit/ai/runner.py +0 -59
  25. fastapi_startkit-0.51.0/src/fastapi_startkit/ai/testing.py +0 -190
  26. fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/.gitignore +0 -2
  27. fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/CACHEDIR.TAG +0 -4
  28. fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/README.md +0 -8
  29. fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/lastfailed +0 -3
  30. fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/nodeids +0 -1
  31. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/README.md +0 -0
  32. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/.DS_Store +0 -0
  33. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/__init__.py +0 -0
  34. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/audio.py +0 -0
  35. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/audio_factory.py +0 -0
  36. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/config/ai.py +0 -0
  37. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/config/config.py +0 -0
  38. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/decorators.py +0 -0
  39. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/document.py +0 -0
  40. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/image.py +0 -0
  41. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/image_factory.py +0 -0
  42. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/lab.py +0 -0
  43. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/providers/__init__.py +0 -0
  44. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/providers/ai_provider.py +0 -0
  45. /fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm/config/__init__.py → /fastapi_startkit-0.53.0/src/fastapi_startkit/ai/tinker.py +0 -0
  46. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/__init__.py +0 -0
  47. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/auth.py +0 -0
  48. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/channels.py +0 -0
  49. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/config.py +0 -0
  50. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/drivers/__init__.py +0 -0
  51. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/drivers/log_driver.py +0 -0
  52. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/drivers/reverb_driver.py +0 -0
  53. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/event.py +0 -0
  54. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/helpers.py +0 -0
  55. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/manager.py +0 -0
  56. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/provider.py +0 -0
  57. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/__init__.py +0 -0
  58. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/channel_manager.py +0 -0
  59. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/connection.py +0 -0
  60. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/server.py +0 -0
  61. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/stubs/__init__.py +0 -0
  62. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/stubs/channels.py +0 -0
  63. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/carbon/__init__.py +0 -0
  64. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/carbon/carbon.py +0 -0
  65. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/config/__init__.py +0 -0
  66. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/config/app.py +0 -0
  67. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/__init__.py +0 -0
  68. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/config.py +0 -0
  69. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/helpers.py +0 -0
  70. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/providers/ConfigurationProvider.py +0 -0
  71. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/providers/__init__.py +0 -0
  72. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/__init__.py +0 -0
  73. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/application.py +0 -0
  74. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/can_override_config.py +0 -0
  75. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/can_override_default_options.py +0 -0
  76. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/command.py +0 -0
  77. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/publish_command.py +0 -0
  78. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/container/__init__.py +0 -0
  79. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/container/container.py +0 -0
  80. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/environment/__init__.py +0 -0
  81. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/environment/environment.py +0 -0
  82. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/__init__.py +0 -0
  83. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/dispatcher.py +0 -0
  84. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/fake.py +0 -0
  85. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/helpers.py +0 -0
  86. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/listener.py +0 -0
  87. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/provider.py +0 -0
  88. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/exceptions/__init__.py +0 -0
  89. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/exceptions/exceptions.py +0 -0
  90. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/exceptions/handler.py +0 -0
  91. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/AI.py +0 -0
  92. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/AI.pyi +0 -0
  93. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Cache.py +0 -0
  94. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Config.py +0 -0
  95. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Config.pyi +0 -0
  96. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Dump.py +0 -0
  97. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Dump.pyi +0 -0
  98. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Event.py +0 -0
  99. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Event.pyi +0 -0
  100. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Facade.py +0 -0
  101. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Gate.py +0 -0
  102. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Gate.pyi +0 -0
  103. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Hash.py +0 -0
  104. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Hash.pyi +0 -0
  105. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Loader.py +0 -0
  106. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Loader.pyi +0 -0
  107. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Mail.py +0 -0
  108. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Mail.pyi +0 -0
  109. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Notification.py +0 -0
  110. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Notification.pyi +0 -0
  111. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Queue.py +0 -0
  112. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Queue.pyi +0 -0
  113. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/RateLimiter.py +0 -0
  114. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/RateLimiter.pyi +0 -0
  115. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Request.py +0 -0
  116. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Request.pyi +0 -0
  117. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Response.py +0 -0
  118. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Response.pyi +0 -0
  119. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Session.py +0 -0
  120. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Session.pyi +0 -0
  121. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Url.py +0 -0
  122. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Url.pyi +0 -0
  123. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/View.py +0 -0
  124. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/View.pyi +0 -0
  125. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Vite.py +0 -0
  126. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Vite.pyi +0 -0
  127. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/__init__.py +0 -0
  128. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/__init__.py +0 -0
  129. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/commands/__init__.py +0 -0
  130. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/commands/serve_command.py +0 -0
  131. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/config/__init__.py +0 -0
  132. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/config/fastapi.py +0 -0
  133. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/events.py +0 -0
  134. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/exceptions.py +0 -0
  135. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/middleware.py +0 -0
  136. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/providers/fastapi_provider.py +0 -0
  137. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/requests/model.py +0 -0
  138. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/routers/router.py +0 -0
  139. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/__init__.py +0 -0
  140. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/assertable_json.py +0 -0
  141. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/test_case.py +0 -0
  142. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/test_response.py +0 -0
  143. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/foundation/app_provider.py +0 -0
  144. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/__init__.py +0 -0
  145. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/constant.py +0 -0
  146. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/context.py +0 -0
  147. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/inertia.py +0 -0
  148. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/middleware.py +0 -0
  149. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/props/props.py +0 -0
  150. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/provider.py +0 -0
  151. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/jsonapi/__init__.py +0 -0
  152. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/jsonapi/response.py +0 -0
  153. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/loader/__init__.py +0 -0
  154. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/ChannelFactory.py +0 -0
  155. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/__init__.py +0 -0
  156. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/BaseChannel.py +0 -0
  157. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/DailyChannel.py +0 -0
  158. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/MultiBaseChannel.py +0 -0
  159. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/SingleChannel.py +0 -0
  160. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/SlackChannel.py +0 -0
  161. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/StackChannel.py +0 -0
  162. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/SyslogChannel.py +0 -0
  163. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/TerminalChannel.py +0 -0
  164. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/__init__.py +0 -0
  165. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/config/__init__.py +0 -0
  166. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/config/channels.py +0 -0
  167. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/config/logging.py +0 -0
  168. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/BaseDriver.py +0 -0
  169. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogSingleDriver.py +0 -0
  170. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogSlackDriver.py +0 -0
  171. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogSyslogDriver.py +0 -0
  172. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py +0 -0
  173. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/__init__.py +0 -0
  174. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/factory.py +0 -0
  175. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/file.py +0 -0
  176. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/handler.py +0 -0
  177. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/listeners.py +0 -0
  178. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/logger.py +0 -0
  179. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/managers/LoggingManager.py +0 -0
  180. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/managers/__init__.py +0 -0
  181. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/providers/__init__.py +0 -0
  182. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/providers/log_provider.py +0 -0
  183. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/__init__.py +0 -0
  184. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/collection/__init__.py +0 -0
  185. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/DBMigrateCommand.py +0 -0
  186. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/DBSeedCommand.py +0 -0
  187. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py +0 -0
  188. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelCommand.py +0 -0
  189. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelDocstringCommand.py +0 -0
  190. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeObserverCommand.py +0 -0
  191. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeSeedCommand.py +0 -0
  192. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py +0 -0
  193. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRefreshCommand.py +0 -0
  194. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateResetCommand.py +0 -0
  195. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRollbackCommand.py +0 -0
  196. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateStatusCommand.py +0 -0
  197. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py +0 -0
  198. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/__init__.py +0 -0
  199. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub +0 -0
  200. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_seed.stub +0 -0
  201. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/model.stub +0 -0
  202. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/observer.stub +0 -0
  203. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub +0 -0
  204. {fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm/helpers → fastapi_startkit-0.53.0/src/fastapi_startkit/masoniteorm/config}/__init__.py +0 -0
  205. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/config/config.py +0 -0
  206. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/config/database.py +0 -0
  207. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/connection.py +0 -0
  208. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/factory.py +0 -0
  209. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/manager.py +0 -0
  210. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py +0 -0
  211. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/postgres_connection.py +0 -0
  212. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/sqlite_connection.py +0 -0
  213. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/exceptions.py +0 -0
  214. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/expressions/__init__.py +0 -0
  215. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/expressions/expressions.py +0 -0
  216. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/facades/DB.py +0 -0
  217. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/facades/Schema.py +0 -0
  218. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/facades/__init__.py +0 -0
  219. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/factory/__init__.py +0 -0
  220. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/factory/factory.py +0 -0
  221. {fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm/query → fastapi_startkit-0.53.0/src/fastapi_startkit/masoniteorm/helpers}/__init__.py +0 -0
  222. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/helpers/misc.py +0 -0
  223. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/migrations/Migration.py +0 -0
  224. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/migrations/Migrator.py +0 -0
  225. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/migrations/__init__.py +0 -0
  226. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/MigrationModel.py +0 -0
  227. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/__init__.py +0 -0
  228. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/attribute.py +0 -0
  229. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/caster.py +0 -0
  230. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/fields.py +0 -0
  231. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/observer.py +0 -0
  232. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/pivot.py +0 -0
  233. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/registry.py +0 -0
  234. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/relationship.py +0 -0
  235. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/observers/ObservesEvents.py +0 -0
  236. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/observers/__init__.py +0 -0
  237. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/BasePaginator.py +0 -0
  238. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/LengthAwarePaginator.py +0 -0
  239. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/SimplePaginator.py +0 -0
  240. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/__init__.py +0 -0
  241. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py +0 -0
  242. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/providers/__init__.py +0 -0
  243. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/EagerLoadMixin.py +0 -0
  244. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/EagerRelation.py +0 -0
  245. {fastapi_startkit-0.51.0/src/fastapi_startkit/mcp/providers → fastapi_startkit-0.53.0/src/fastapi_startkit/masoniteorm/query}/__init__.py +0 -0
  246. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/BaseGrammar.py +0 -0
  247. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/MSSQLGrammar.py +0 -0
  248. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/MySQLGrammar.py +0 -0
  249. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/PostgresGrammar.py +0 -0
  250. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/SQLiteGrammar.py +0 -0
  251. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/__init__.py +0 -0
  252. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/MSSQLPostProcessor.py +0 -0
  253. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/MySQLPostProcessor.py +0 -0
  254. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/PostgresPostProcessor.py +0 -0
  255. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/SQLitePostProcessor.py +0 -0
  256. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/__init__.py +0 -0
  257. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/support.py +0 -0
  258. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/BaseRelationship.py +0 -0
  259. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py +0 -0
  260. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsToMany.py +0 -0
  261. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasMany.py +0 -0
  262. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasManyThrough.py +0 -0
  263. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasOne.py +0 -0
  264. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasOneThrough.py +0 -0
  265. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphMany.py +0 -0
  266. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphOne.py +0 -0
  267. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphTo.py +0 -0
  268. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphToMany.py +0 -0
  269. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/__init__.py +0 -0
  270. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Blueprint.py +0 -0
  271. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Column.py +0 -0
  272. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/ColumnDiff.py +0 -0
  273. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Constraint.py +0 -0
  274. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/ForeignKeyConstraint.py +0 -0
  275. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Index.py +0 -0
  276. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Table.py +0 -0
  277. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/TableDiff.py +0 -0
  278. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/__init__.py +0 -0
  279. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MSSQLPlatform.py +0 -0
  280. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MySQLPlatform.py +0 -0
  281. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/Platform.py +0 -0
  282. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/PostgresPlatform.py +0 -0
  283. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/SQLitePlatform.py +0 -0
  284. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/__init__.py +0 -0
  285. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/schema.py +0 -0
  286. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/seeders/Seeder.py +0 -0
  287. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/seeders/__init__.py +0 -0
  288. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/stubs/create-migration.html +0 -0
  289. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/stubs/table-migration.html +0 -0
  290. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/testing/__init__.py +0 -0
  291. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/testing/transaction.py +0 -0
  292. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/__init__.py +0 -0
  293. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/argument.py +0 -0
  294. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/prompt.py +0 -0
  295. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/protocol.py +0 -0
  296. /fastapi_startkit-0.51.0/src/fastapi_startkit/py.typed → /fastapi_startkit-0.53.0/src/fastapi_startkit/mcp/providers/__init__.py +0 -0
  297. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/providers/mcp_provider.py +0 -0
  298. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/request.py +0 -0
  299. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/resource.py +0 -0
  300. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/response.py +0 -0
  301. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/server.py +0 -0
  302. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/tool.py +0 -0
  303. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/__init__.py +0 -0
  304. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/exception.py +0 -0
  305. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/fake.py +0 -0
  306. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/process.py +0 -0
  307. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/result.py +0 -0
  308. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/__init__.py +0 -0
  309. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/__init__.py +0 -0
  310. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/base.py +0 -0
  311. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/claude.py +0 -0
  312. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/gemini.py +0 -0
  313. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/commands/__init__.py +0 -0
  314. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/commands/skills.py +0 -0
  315. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/parser.py +0 -0
  316. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/provider.py +0 -0
  317. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/registry.py +0 -0
  318. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/database/SKILL.md +0 -0
  319. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/fastapi/SKILL.md +0 -0
  320. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/inertia/SKILL.md +0 -0
  321. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/__init__.py +0 -0
  322. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/config/__init__.py +0 -0
  323. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/config/storage.py +0 -0
  324. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/data/mime.types +0 -0
  325. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/__init__.py +0 -0
  326. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/fake.py +0 -0
  327. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/local.py +0 -0
  328. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/s3.py +0 -0
  329. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/file.py +0 -0
  330. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/filestream.py +0 -0
  331. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/helper.py +0 -0
  332. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/providers/provider.py +0 -0
  333. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/storage.py +0 -0
  334. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/__init__.py +0 -0
  335. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/collection.py +0 -0
  336. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/dataclass.py +0 -0
  337. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/providers/__init__.py +0 -0
  338. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/providers/provider.py +0 -0
  339. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/string.py +0 -0
  340. {fastapi_startkit-0.51.0/src/fastapi_startkit/utils → fastapi_startkit-0.53.0/src/fastapi_startkit/support}/structures.py +0 -0
  341. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/uri.py +0 -0
  342. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/testing/__init__.py +0 -0
  343. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/testing/test_case.py +0 -0
  344. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/__init__.py +0 -0
  345. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/config/vite.py +0 -0
  346. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/exceptions.py +0 -0
  347. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/providers/provider.py +0 -0
  348. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/package.json +0 -0
  349. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/resources/css/app.css +0 -0
  350. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/resources/js/app.ts +0 -0
  351. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/resources/templates/index.html +0 -0
  352. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/tsconfig.json +0 -0
  353. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/vite.config.ts +0 -0
  354. {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.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.51.0
3
+ Version: 0.53.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'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fastapi-startkit"
3
- version = "0.51.0"
3
+ version = "0.53.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
5
  readme = "README.md"
6
6
  keywords = [
@@ -87,6 +87,7 @@ inertia = [
87
87
  ai = [
88
88
  "langchain>=1.0.0",
89
89
  "langchain-core>=1.0.0",
90
+ "langgraph>=1.0.0",
90
91
  ]
91
92
 
92
93
  [dependency-groups]
@@ -130,7 +131,7 @@ exclude = [
130
131
  "**/__pycache__",
131
132
  "**/.venv",
132
133
  ]
133
- typeCheckingMode = "basic"
134
+ typeCheckingMode = "standard"
134
135
  pythonVersion = "3.12"
135
136
 
136
137
  [tool.pytest.ini_options]
@@ -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