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.
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/PKG-INFO +2 -1
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/pyproject.toml +3 -2
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/__init__.py +10 -10
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/agent.py +99 -0
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/ai.py +108 -0
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/judge.py +34 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/pipeline.py +22 -2
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/recording.py +182 -0
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/runner.py +321 -0
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/state.py +88 -0
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/testing.py +596 -0
- fastapi_startkit-0.53.0/src/fastapi_startkit/ai/types.py +5 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/application.py +5 -6
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/Configuration.py +1 -1
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/loader/Loader.py +1 -1
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/collection/Collection.py +15 -2
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/builder.py +18 -8
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/model.py +10 -13
- fastapi_startkit-0.53.0/src/fastapi_startkit/py.typed +0 -0
- fastapi_startkit-0.51.0/src/fastapi_startkit/ai/agent.py +0 -299
- fastapi_startkit-0.51.0/src/fastapi_startkit/ai/fakes.py +0 -53
- fastapi_startkit-0.51.0/src/fastapi_startkit/ai/model_builder.py +0 -47
- fastapi_startkit-0.51.0/src/fastapi_startkit/ai/response.py +0 -93
- fastapi_startkit-0.51.0/src/fastapi_startkit/ai/runner.py +0 -59
- fastapi_startkit-0.51.0/src/fastapi_startkit/ai/testing.py +0 -190
- fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/.gitignore +0 -2
- fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/CACHEDIR.TAG +0 -4
- fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/README.md +0 -8
- fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/lastfailed +0 -3
- fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/nodeids +0 -1
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/README.md +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/.DS_Store +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/audio.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/audio_factory.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/config/ai.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/config/config.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/decorators.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/document.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/image.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/image_factory.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/lab.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/providers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/ai/providers/ai_provider.py +0 -0
- /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
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/auth.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/channels.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/config.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/drivers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/drivers/log_driver.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/drivers/reverb_driver.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/event.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/helpers.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/manager.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/channel_manager.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/connection.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/reverb/server.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/stubs/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/broadcasting/stubs/channels.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/carbon/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/carbon/carbon.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/config/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/config/app.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/config.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/helpers.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/providers/ConfigurationProvider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/configuration/providers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/application.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/can_override_config.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/can_override_default_options.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/command.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/console/publish_command.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/container/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/container/container.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/environment/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/environment/environment.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/dispatcher.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/fake.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/helpers.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/listener.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/events/provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/exceptions/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/exceptions/exceptions.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/exceptions/handler.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/AI.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/AI.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Cache.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Config.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Config.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Dump.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Dump.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Event.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Event.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Facade.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Gate.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Gate.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Hash.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Hash.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Loader.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Loader.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Mail.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Mail.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Notification.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Notification.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Queue.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Queue.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/RateLimiter.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/RateLimiter.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Request.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Request.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Response.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Response.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Session.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Session.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Url.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Url.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/View.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/View.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Vite.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/Vite.pyi +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/facades/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/commands/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/commands/serve_command.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/config/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/config/fastapi.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/events.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/exceptions.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/middleware.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/providers/fastapi_provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/requests/model.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/routers/router.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/assertable_json.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/test_case.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/fastapi/testing/test_response.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/foundation/app_provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/constant.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/context.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/inertia.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/middleware.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/props/props.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/inertia/provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/jsonapi/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/jsonapi/response.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/loader/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/ChannelFactory.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/BaseChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/DailyChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/MultiBaseChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/SingleChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/SlackChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/StackChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/SyslogChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/TerminalChannel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/channels/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/config/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/config/channels.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/config/logging.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/BaseDriver.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogSingleDriver.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogSlackDriver.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogSyslogDriver.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/drivers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/factory.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/file.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/handler.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/listeners.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/logger.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/managers/LoggingManager.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/managers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/providers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/logging/providers/log_provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/collection/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/DBMigrateCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/DBSeedCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelDocstringCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeObserverCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MakeSeedCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRefreshCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateResetCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRollbackCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/MigrateStatusCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_seed.stub +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/model.stub +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/observer.stub +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub +0 -0
- {fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm/helpers → fastapi_startkit-0.53.0/src/fastapi_startkit/masoniteorm/config}/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/config/config.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/config/database.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/connection.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/factory.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/manager.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/postgres_connection.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/connections/sqlite_connection.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/exceptions.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/expressions/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/expressions/expressions.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/facades/DB.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/facades/Schema.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/facades/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/factory/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/factory/factory.py +0 -0
- {fastapi_startkit-0.51.0/src/fastapi_startkit/masoniteorm/query → fastapi_startkit-0.53.0/src/fastapi_startkit/masoniteorm/helpers}/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/helpers/misc.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/migrations/Migration.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/migrations/Migrator.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/migrations/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/MigrationModel.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/attribute.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/caster.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/fields.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/observer.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/pivot.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/registry.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/models/relationship.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/observers/ObservesEvents.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/observers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/BasePaginator.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/LengthAwarePaginator.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/SimplePaginator.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/pagination/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/providers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/EagerLoadMixin.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/EagerRelation.py +0 -0
- {fastapi_startkit-0.51.0/src/fastapi_startkit/mcp/providers → fastapi_startkit-0.53.0/src/fastapi_startkit/masoniteorm/query}/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/BaseGrammar.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/MSSQLGrammar.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/MySQLGrammar.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/PostgresGrammar.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/SQLiteGrammar.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/grammars/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/MSSQLPostProcessor.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/MySQLPostProcessor.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/PostgresPostProcessor.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/SQLitePostProcessor.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/processors/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/query/support.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/BaseRelationship.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsToMany.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasMany.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasManyThrough.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasOne.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/HasOneThrough.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphMany.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphOne.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphTo.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/MorphToMany.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/relationships/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Blueprint.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Column.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/ColumnDiff.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Constraint.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/ForeignKeyConstraint.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Index.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/Table.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/TableDiff.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MSSQLPlatform.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MySQLPlatform.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/Platform.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/PostgresPlatform.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/SQLitePlatform.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/platforms/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/schema/schema.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/seeders/Seeder.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/seeders/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/stubs/create-migration.html +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/stubs/table-migration.html +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/testing/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/masoniteorm/testing/transaction.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/argument.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/prompt.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/protocol.py +0 -0
- /fastapi_startkit-0.51.0/src/fastapi_startkit/py.typed → /fastapi_startkit-0.53.0/src/fastapi_startkit/mcp/providers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/providers/mcp_provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/request.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/resource.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/response.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/server.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/mcp/tool.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/exception.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/fake.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/process.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/process/result.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/base.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/claude.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/adapters/gemini.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/commands/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/commands/skills.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/parser.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/registry.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/database/SKILL.md +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/fastapi/SKILL.md +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/inertia/SKILL.md +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/config/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/config/storage.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/data/mime.types +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/fake.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/local.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/drivers/s3.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/file.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/filestream.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/helper.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/providers/provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/storage/storage.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/collection.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/dataclass.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/providers/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/providers/provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/string.py +0 -0
- {fastapi_startkit-0.51.0/src/fastapi_startkit/utils → fastapi_startkit-0.53.0/src/fastapi_startkit/support}/structures.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/support/uri.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/testing/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/testing/test_case.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/__init__.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/config/vite.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/exceptions.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/providers/provider.py +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/package.json +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/resources/css/app.css +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/resources/js/app.ts +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/resources/templates/index.html +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/tsconfig.json +0 -0
- {fastapi_startkit-0.51.0 → fastapi_startkit-0.53.0}/src/fastapi_startkit/vite/stubs/vite.config.ts +0 -0
- {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.
|
|
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.
|
|
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 = "
|
|
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 .
|
|
14
|
-
from .testing import
|
|
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
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"AgentSnapshot",
|
|
21
|
+
"AgentFake",
|
|
22
|
+
"state",
|
|
22
23
|
"AIConfig",
|
|
23
24
|
"AIProvider",
|
|
24
25
|
"AnthropicConfig",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
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 =
|
|
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 =
|
|
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
|