springbootAI 2.3.8__tar.gz → 2.3.9__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.
- {springbootai-2.3.8 → springbootai-2.3.9}/CHANGELOG.md +9 -0
- {springbootai-2.3.8/springbootAI.egg-info → springbootai-2.3.9}/PKG-INFO +21 -7
- {springbootai-2.3.8 → springbootai-2.3.9}/README.md +20 -6
- {springbootai-2.3.8 → springbootai-2.3.9}/pyproject.toml +2 -1
- {springbootai-2.3.8 → springbootai-2.3.9/springbootAI.egg-info}/PKG-INFO +21 -7
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootAI.egg-info/SOURCES.txt +7 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/__init__.py +15 -7
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/advisors.py +55 -10
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/annotation_runtime.py +18 -6
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/autoconfig.py +53 -4
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/core.py +154 -30
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/etl.py +73 -12
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/memory.py +50 -26
- springbootai-2.3.9/springbootai/ai/providers.py +1521 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/resilience.py +22 -9
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/tools.py +100 -10
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/vectorstore.py +41 -3
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/core.py +4 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cli/scaffold.py +33 -4
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/__init__.py +4 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/bus.py +64 -12
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/config_center.py +215 -37
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/discovery.py +102 -23
- springbootai-2.3.9/springbootai/cloud/feign.py +608 -0
- springbootai-2.3.9/springbootai/cloud/gateway.py +880 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/seata.py +176 -47
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/config/spring-configuration-metadata.json +10 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/csv/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/data/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/datasource/__init__.py +1 -1
- springbootai-2.3.9/springbootai/devtools.py +243 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/__init__.py +1 -1
- springbootai-2.3.9/springbootai/logging/__init__.py +13 -0
- springbootai-2.3.9/springbootai/logging/context.py +213 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/logging/loguru_logger.py +107 -13
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/main.py +163 -46
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/mcp/client.py +11 -1
- springbootai-2.3.9/springbootai/monitoring/admin_client.py +266 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/version.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/test/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/tracing/skywalking.py +72 -27
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/tx/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/utils/banner.py +2 -2
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/validation/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/request_metrics.py +4 -4
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/swagger.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/web_context.py +67 -11
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/websocket/__init__.py +1 -1
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_ai_comprehensive.py +9 -5
- springbootai-2.3.9/tests/test_ai_enterprise_hardening.py +349 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_ai_module.py +7 -8
- springbootai-2.3.9/tests/test_ai_stream_hardening.py +461 -0
- springbootai-2.3.9/tests/test_cloud_log_safety.py +260 -0
- springbootai-2.3.9/tests/test_config_admin_hardening.py +207 -0
- springbootai-2.3.9/tests/test_devtools_lifecycle_hardening.py +193 -0
- springbootai-2.3.9/tests/test_io_http_logging_hardening.py +847 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_tracing.py +3 -6
- springbootai-2.3.8/springbootai/ai/providers.py +0 -881
- springbootai-2.3.8/springbootai/cloud/feign.py +0 -469
- springbootai-2.3.8/springbootai/cloud/gateway.py +0 -542
- springbootai-2.3.8/springbootai/devtools.py +0 -153
- springbootai-2.3.8/springbootai/logging/__init__.py +0 -1
- springbootai-2.3.8/springbootai/monitoring/admin_client.py +0 -77
- {springbootai-2.3.8 → springbootai-2.3.9}/LICENSE +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/MANIFEST.in +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/SECURITY.md +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/requirements-ai.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/requirements-langgraph.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/requirements-mcp.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/requirements.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/setup.cfg +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/setup.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootAI.egg-info/dependency_links.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootAI.egg-info/entry_points.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootAI.egg-info/requires.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootAI.egg-info/top_level.txt +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/ai/observability.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/batch.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/cache.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/cloud.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/conditional.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/data.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/enterprise.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/langchain.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/langgraph.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/lombok.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/messaging.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/annotations/security.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/aop/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/aop/aspect.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/aop/cloud_aop.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/aop/comprehensive_aop.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/aop/method_interceptor.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/aop/proxy_factory.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/batch/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cli/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cli/main.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/load_balancer.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/nacos_config.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/seata_at_proxy.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/seata_bridge.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/sentinel.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/tracer.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/cloud/transaction_store.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/config/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/config/binding.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/config/config_loader.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/config/config_monitor.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/context/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/context/application_context.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/context/bean_definition.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/context/bean_factory.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/context/lifecycle.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/context/registry.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/context/scanner.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/core/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/core/graceful_shutdown.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/core/typing_utils.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/csv/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/csv/converters.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/csv/easy_csv.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/csv/exceptions.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/csv/reader.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/csv/writer.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/data/page.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/data/repository.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/data/rest.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/data/specification.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/datasource/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/datasource/context.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/datasource/dynamic.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/event/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/event/publisher.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/converters.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/easy_excel.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/exceptions.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/reader.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/style.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/excel/writer.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/accessor.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/auto_config.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/holder.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/locale.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/locale_resolver.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/message_source.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/middleware.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/properties.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/i18n/sources.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/adapters.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/agents/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/agents/services.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/autoconfig.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/callbacks/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/callbacks/handlers.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/chains/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/chains/services.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/core.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/indexes/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/indexes/index.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/loaders/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/loaders/loaders.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/memory/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/memory/memory.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/parsers/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/parsers/parsers.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/partners.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/prompts/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/prompts/templates.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/retrievers/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/retrievers/retrievers.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/tools/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/tools/tools.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/utilities/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/utilities/utils.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/vectorstores/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langchain/vectorstores/stores.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langgraph/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langgraph/annotation_runtime.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langgraph/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langgraph/autoconfig.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langgraph/checkpoint.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langgraph/config.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/langgraph/runtime.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/mcp/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/mcp/annotation_runtime.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/mcp/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/mcp/autoconfig.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/mcp/config.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/mcp/server.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/messaging/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/messaging/kafka.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/messaging/rabbitmq.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/monitoring/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/monitoring/prometheus.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/database.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/ddl_auto.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/migration.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/mybatis_integration.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/annotations/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/annotations/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/cache/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/cache/cache.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/cache/redis_cache.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/circuit_breaker/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/circuit_breaker/circuit_breaker.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/configuration.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/core/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/core/sql_session.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/core/sql_session_factory.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/dialect/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/dialect/dialect.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/dynamic_sql/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/dynamic_sql/dynamic_sql.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/interceptor/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/interceptor/interceptor.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/mapper/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/mapper/mapper.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/metrics/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/metrics/metrics.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/pool/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/pool/connection_pool.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/security/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/security/access_control.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/security/password_encoder.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/security/sensitive_data_masker.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/security/sql_injection_detector.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/transaction/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/transaction/transaction.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/type_handler/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/type_handler/type_handler.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/xml_parser/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/orm/pymybatis/xml_parser/xml_parser.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/retry/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/retry/recovery.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/retry/retry_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/retry/retry_decorator.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/scheduling/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/scheduling/scheduler.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/security/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/security/jwt_utils.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/security/oauth2.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/security/replay_protection.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/security/secret_manager.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/security/security_aop.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/security/security_context.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/test/slicing.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/tracing/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/tx/events.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/tx/synchronization.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/utils/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/utils/bean_utils.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/utils/logger.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/utils/redis_client.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/validation/aop.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/validation/constraints.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/validation/exceptions.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/validation/validator.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/__init__.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/actuator.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/csrf.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/exception_handler.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/hateoas.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/health.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/interceptor.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/web/result.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/websocket/annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/websocket/broker.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/websocket/exceptions.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/websocket/handler.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/websocket/router.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/springbootai/websocket/session.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/sql/seata_undo_log.sql +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_actuator.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_actuator_prometheus_admin.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_ai_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_ai_declarative_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_annotation_combinations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_annotations_contract.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_aop_annotations_full.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_aop_pointcut_enhancements.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_audit_time.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_batch.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_bean_utils.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_bus.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_cache_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_cli.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_cloud_embedded_full.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_component_init_error.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_compositional_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_conditional_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_config_binding.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_config_center.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_config_center_hardening.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_config_fixes_185.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_config_monitor.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_connection_resilience.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_core.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_core_annotations_full.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_csrf.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_csv_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_data_repository.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_data_rest.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_datasource_routing.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_ddl_auto.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_declarative_aop_post_authorize_recover.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_devtools.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_di_config_event_full.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_excel_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_hateoas.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_i18n_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_ioc_lifecycle_enhancements.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_jpa_version_transient.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_kafka.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_langchain_comprehensive.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_langchain_ext.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_langchain_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_langgraph_comprehensive.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_langgraph_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_logging_config.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_lombok_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_mcp_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_metadata.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_migration.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_nacos_config.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_new_annotations.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_new_features.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_oauth2.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_optional_component_timeouts.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_orm_pymybatis_full.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_production_readiness.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_pymybatis_configuration_hardening.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_pymybatis_contract.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_request_metrics.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_retry.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_runtime_configuration_fixes.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_scaffold_hardening.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_scheduling.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_seata_at_proxy.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_seata_bridge.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_seata_durable_store.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_security.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_security_full.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_security_hardening.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_select_page.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_starter.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_startup_lifecycle.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_swagger_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_test_slicing.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_transactional_events.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_validation_module.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_web_annotations_full.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_web_file_upload.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_web_root_mapping.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_web_security_responses.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_web_static_files.py +0 -0
- {springbootai-2.3.8 → springbootai-2.3.9}/tests/test_websocket_module.py +0 -0
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.3.9] - 2026-08-28
|
|
4
|
+
|
|
5
|
+
- 加固 OpenAI 兼容接口与 Ollama 的同步/异步流式协议:校验终止帧、错误信封和畸形响应,限制事件与响应大小,并完善超时、有限重试、重定向拒绝及 SDK 重试边界。
|
|
6
|
+
- 修复 AI 异步流阻塞事件循环、请求参数覆盖受保护字段、输出 Token 上限绕过、工具调用闭环和多租户 Memory/RAG 隔离等问题。
|
|
7
|
+
- 加固 Feign、Gateway、Config Center、Admin 与 Discovery:正确释放响应、执行路由谓词和过滤器、过滤逐跳头、传播请求 ID,并增加路径、响应大小、故障回退与生命周期保护。
|
|
8
|
+
- 新增统一日志脱敏和日志注入防护,覆盖异常链、Bearer/Basic/Cookie、云事件、Nacos、Seata 与 SkyWalking,避免敏感负载进入日志或健康响应。
|
|
9
|
+
- 修复原子脚手架写入、TextReader 文件边界、DevTools 停止/重启语义、SkyWalking 显式初始化和 Banner 版本读取错误。
|
|
10
|
+
- 新增企业加固回归测试;完整测试结果为 3170 passed、11 skipped、0 failed,Bandit 中高危扫描为 0。
|
|
11
|
+
|
|
3
12
|
## [2.3.8] - 2026-08-24
|
|
4
13
|
|
|
5
14
|
- 修复配置加载的原子性与数据库 URL 优先级:请求监控不再误落到根目录 `test.db`,SQLite 运行目录会自动创建,显式 URL/驱动/数据库名称按统一优先级生效。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: springbootAI
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.9
|
|
4
4
|
Summary: Spring-style Python framework with Web, ORM, Cloud and AI integrations
|
|
5
5
|
Author-email: YuConggen <1516933915@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -216,7 +216,7 @@ SpringBootAI 是一个采用 Spring 风格注解和分层结构的 Python 应用
|
|
|
216
216
|
| AI 与编排 | 模型调用、Tools、RAG、Chain、状态图、MCP client/server | LangChain / LangGraph / 官方 MCP SDK |
|
|
217
217
|
| 生产治理 | 健康检查、Prometheus、限流熔断、追踪、Swagger | prometheus-client / OpenTelemetry / OpenAPI |
|
|
218
218
|
|
|
219
|
-
当前版本是 `2.3.
|
|
219
|
+
当前版本是 `2.3.9`;支持 Python 3.10、3.11 和 3.12,许可证为 MIT。项目仍标记为 Beta。用于公网高并发、合规敏感或支付/订单/库存等核心系统前,必须完成目标数据库、流量模型、故障恢复和安全基线验证。内嵌 Gateway 适合内部路由,不替代公网 Nginx/Kong/WAF;Seata `distributed` 对接官方 TC + TCC 回调;`at` 模式通过 ORM 拦截器自动生成 undo_log 实现自动回滚。
|
|
220
220
|
|
|
221
221
|
[新手指南](https://github.com/YUCONGGEN/springbootAI/blob/master/doc/BEGINNER_GUIDE.md) | [全部文档](https://github.com/YUCONGGEN/springbootAI/tree/master/doc) | [变更日志](https://github.com/YUCONGGEN/springbootAI/blob/master/CHANGELOG.md) | [安全报告](https://github.com/YUCONGGEN/springbootAI/blob/master/SECURITY.md) | [发布检查](https://github.com/YUCONGGEN/springbootAI/blob/master/doc/RELEASE_CHECKLIST.md)
|
|
222
222
|
|
|
@@ -347,10 +347,10 @@ SpringBootAI 是一个 **Python Web 框架**。它把 Java Spring Boot 的"注
|
|
|
347
347
|
|
|
348
348
|
| 组件 | 当前版本 |
|
|
349
349
|
|------|----------|
|
|
350
|
-
| `springbootai` 框架 API | 2.3.
|
|
351
|
-
| `springbootai.orm.pymybatis` | 2.3.
|
|
352
|
-
| `springbootai.ai` AI 模块 | 2.3.
|
|
353
|
-
| `springbootai.langchain` LangChain 模块 | 2.3.
|
|
350
|
+
| `springbootai` 框架 API | 2.3.9 |
|
|
351
|
+
| `springbootai.orm.pymybatis` | 2.3.9 |
|
|
352
|
+
| `springbootai.ai` AI 模块 | 2.3.9 |
|
|
353
|
+
| `springbootai.langchain` LangChain 模块 | 2.3.9 |
|
|
354
354
|
| Python | 3.10+ |
|
|
355
355
|
|
|
356
356
|
### 1.4 适合什么场景
|
|
@@ -937,6 +937,16 @@ class InitService:
|
|
|
937
937
|
self.connection.close()
|
|
938
938
|
```
|
|
939
939
|
|
|
940
|
+
每个 HTTP 请求都会获得 `X-Request-ID`(可通过
|
|
941
|
+
`server.request-id.header` 修改),该值会写回响应并自动进入框架日志,Feign
|
|
942
|
+
和 Gateway 也会向下游透传。日志会遮蔽 Bearer Token、API Key、密码、Cookie
|
|
943
|
+
等常见敏感字段;`logging.diagnose` 默认关闭,避免异常帧局部变量泄密。
|
|
944
|
+
|
|
945
|
+
声明式 Feign 客户端默认复用连接池,对幂等请求执行有限退避重试,并支持连接/
|
|
946
|
+
读取超时与响应大小限制。直接读取 RAG 文本文件时建议使用
|
|
947
|
+
`TextReader.from_file(path, max_bytes=...)`,文件不存在或超限会明确失败,不会把
|
|
948
|
+
错误路径误当成内联文本。
|
|
949
|
+
|
|
940
950
|
### 5.7 应用事件
|
|
941
951
|
|
|
942
952
|
```python
|
|
@@ -1895,9 +1905,13 @@ export LOG_DIR=logs
|
|
|
1895
1905
|
|
|
1896
1906
|
# AI 模块
|
|
1897
1907
|
export AI_PROVIDER=openai
|
|
1898
|
-
export AI_ALLOW_FAKE=
|
|
1908
|
+
export AI_ALLOW_FAKE=false
|
|
1899
1909
|
export OPENAI_API_KEY=sk-xxx
|
|
1900
1910
|
export OPENAI_CHAT_MODEL=gpt-4o-mini
|
|
1911
|
+
export AI_REQUEST_TIMEOUT_SECONDS=60
|
|
1912
|
+
export AI_MAX_OUTPUT_TOKENS=4096
|
|
1913
|
+
export AI_MAX_TOTAL_TOKENS=100000
|
|
1914
|
+
export AI_MAX_TOOL_ITERATIONS=5
|
|
1901
1915
|
export OLLAMA_BASE_URL=http://localhost:11434
|
|
1902
1916
|
export OLLAMA_CHAT_MODEL=llama3
|
|
1903
1917
|
|
|
@@ -54,7 +54,7 @@ SpringBootAI 是一个采用 Spring 风格注解和分层结构的 Python 应用
|
|
|
54
54
|
| AI 与编排 | 模型调用、Tools、RAG、Chain、状态图、MCP client/server | LangChain / LangGraph / 官方 MCP SDK |
|
|
55
55
|
| 生产治理 | 健康检查、Prometheus、限流熔断、追踪、Swagger | prometheus-client / OpenTelemetry / OpenAPI |
|
|
56
56
|
|
|
57
|
-
当前版本是 `2.3.
|
|
57
|
+
当前版本是 `2.3.9`;支持 Python 3.10、3.11 和 3.12,许可证为 MIT。项目仍标记为 Beta。用于公网高并发、合规敏感或支付/订单/库存等核心系统前,必须完成目标数据库、流量模型、故障恢复和安全基线验证。内嵌 Gateway 适合内部路由,不替代公网 Nginx/Kong/WAF;Seata `distributed` 对接官方 TC + TCC 回调;`at` 模式通过 ORM 拦截器自动生成 undo_log 实现自动回滚。
|
|
58
58
|
|
|
59
59
|
[新手指南](https://github.com/YUCONGGEN/springbootAI/blob/master/doc/BEGINNER_GUIDE.md) | [全部文档](https://github.com/YUCONGGEN/springbootAI/tree/master/doc) | [变更日志](https://github.com/YUCONGGEN/springbootAI/blob/master/CHANGELOG.md) | [安全报告](https://github.com/YUCONGGEN/springbootAI/blob/master/SECURITY.md) | [发布检查](https://github.com/YUCONGGEN/springbootAI/blob/master/doc/RELEASE_CHECKLIST.md)
|
|
60
60
|
|
|
@@ -185,10 +185,10 @@ SpringBootAI 是一个 **Python Web 框架**。它把 Java Spring Boot 的"注
|
|
|
185
185
|
|
|
186
186
|
| 组件 | 当前版本 |
|
|
187
187
|
|------|----------|
|
|
188
|
-
| `springbootai` 框架 API | 2.3.
|
|
189
|
-
| `springbootai.orm.pymybatis` | 2.3.
|
|
190
|
-
| `springbootai.ai` AI 模块 | 2.3.
|
|
191
|
-
| `springbootai.langchain` LangChain 模块 | 2.3.
|
|
188
|
+
| `springbootai` 框架 API | 2.3.9 |
|
|
189
|
+
| `springbootai.orm.pymybatis` | 2.3.9 |
|
|
190
|
+
| `springbootai.ai` AI 模块 | 2.3.9 |
|
|
191
|
+
| `springbootai.langchain` LangChain 模块 | 2.3.9 |
|
|
192
192
|
| Python | 3.10+ |
|
|
193
193
|
|
|
194
194
|
### 1.4 适合什么场景
|
|
@@ -775,6 +775,16 @@ class InitService:
|
|
|
775
775
|
self.connection.close()
|
|
776
776
|
```
|
|
777
777
|
|
|
778
|
+
每个 HTTP 请求都会获得 `X-Request-ID`(可通过
|
|
779
|
+
`server.request-id.header` 修改),该值会写回响应并自动进入框架日志,Feign
|
|
780
|
+
和 Gateway 也会向下游透传。日志会遮蔽 Bearer Token、API Key、密码、Cookie
|
|
781
|
+
等常见敏感字段;`logging.diagnose` 默认关闭,避免异常帧局部变量泄密。
|
|
782
|
+
|
|
783
|
+
声明式 Feign 客户端默认复用连接池,对幂等请求执行有限退避重试,并支持连接/
|
|
784
|
+
读取超时与响应大小限制。直接读取 RAG 文本文件时建议使用
|
|
785
|
+
`TextReader.from_file(path, max_bytes=...)`,文件不存在或超限会明确失败,不会把
|
|
786
|
+
错误路径误当成内联文本。
|
|
787
|
+
|
|
778
788
|
### 5.7 应用事件
|
|
779
789
|
|
|
780
790
|
```python
|
|
@@ -1733,9 +1743,13 @@ export LOG_DIR=logs
|
|
|
1733
1743
|
|
|
1734
1744
|
# AI 模块
|
|
1735
1745
|
export AI_PROVIDER=openai
|
|
1736
|
-
export AI_ALLOW_FAKE=
|
|
1746
|
+
export AI_ALLOW_FAKE=false
|
|
1737
1747
|
export OPENAI_API_KEY=sk-xxx
|
|
1738
1748
|
export OPENAI_CHAT_MODEL=gpt-4o-mini
|
|
1749
|
+
export AI_REQUEST_TIMEOUT_SECONDS=60
|
|
1750
|
+
export AI_MAX_OUTPUT_TOKENS=4096
|
|
1751
|
+
export AI_MAX_TOTAL_TOKENS=100000
|
|
1752
|
+
export AI_MAX_TOOL_ITERATIONS=5
|
|
1739
1753
|
export OLLAMA_BASE_URL=http://localhost:11434
|
|
1740
1754
|
export OLLAMA_CHAT_MODEL=llama3
|
|
1741
1755
|
|
|
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
|
|
|
12
12
|
[project]
|
|
13
13
|
# Distribution name: springbootAI (pip install springbootAI); import package: springbootai.
|
|
14
14
|
name = "springbootAI"
|
|
15
|
-
version = "2.3.
|
|
15
|
+
version = "2.3.9"
|
|
16
16
|
description = "Spring-style Python framework with Web, ORM, Cloud and AI integrations"
|
|
17
17
|
readme = "README.md"
|
|
18
18
|
license = "MIT"
|
|
@@ -256,6 +256,7 @@ full = [
|
|
|
256
256
|
|
|
257
257
|
[tool.pytest.ini_options]
|
|
258
258
|
pythonpath = [".", "examples"]
|
|
259
|
+
testpaths = ["tests"]
|
|
259
260
|
filterwarnings = [
|
|
260
261
|
# 闈欓粯 langchain_classic 寮冪敤鍛婅鍜?community sunset 鍛婅
|
|
261
262
|
# 鍘熷洜锛氭湰椤圭洰鏈夋剰閿佸畾 langchain classic (1.x) API锛岃繖浜涙槸棰勬湡鍐呯殑妗嗘灦绾у憡璀?
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: springbootAI
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.9
|
|
4
4
|
Summary: Spring-style Python framework with Web, ORM, Cloud and AI integrations
|
|
5
5
|
Author-email: YuConggen <1516933915@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -216,7 +216,7 @@ SpringBootAI 是一个采用 Spring 风格注解和分层结构的 Python 应用
|
|
|
216
216
|
| AI 与编排 | 模型调用、Tools、RAG、Chain、状态图、MCP client/server | LangChain / LangGraph / 官方 MCP SDK |
|
|
217
217
|
| 生产治理 | 健康检查、Prometheus、限流熔断、追踪、Swagger | prometheus-client / OpenTelemetry / OpenAPI |
|
|
218
218
|
|
|
219
|
-
当前版本是 `2.3.
|
|
219
|
+
当前版本是 `2.3.9`;支持 Python 3.10、3.11 和 3.12,许可证为 MIT。项目仍标记为 Beta。用于公网高并发、合规敏感或支付/订单/库存等核心系统前,必须完成目标数据库、流量模型、故障恢复和安全基线验证。内嵌 Gateway 适合内部路由,不替代公网 Nginx/Kong/WAF;Seata `distributed` 对接官方 TC + TCC 回调;`at` 模式通过 ORM 拦截器自动生成 undo_log 实现自动回滚。
|
|
220
220
|
|
|
221
221
|
[新手指南](https://github.com/YUCONGGEN/springbootAI/blob/master/doc/BEGINNER_GUIDE.md) | [全部文档](https://github.com/YUCONGGEN/springbootAI/tree/master/doc) | [变更日志](https://github.com/YUCONGGEN/springbootAI/blob/master/CHANGELOG.md) | [安全报告](https://github.com/YUCONGGEN/springbootAI/blob/master/SECURITY.md) | [发布检查](https://github.com/YUCONGGEN/springbootAI/blob/master/doc/RELEASE_CHECKLIST.md)
|
|
222
222
|
|
|
@@ -347,10 +347,10 @@ SpringBootAI 是一个 **Python Web 框架**。它把 Java Spring Boot 的"注
|
|
|
347
347
|
|
|
348
348
|
| 组件 | 当前版本 |
|
|
349
349
|
|------|----------|
|
|
350
|
-
| `springbootai` 框架 API | 2.3.
|
|
351
|
-
| `springbootai.orm.pymybatis` | 2.3.
|
|
352
|
-
| `springbootai.ai` AI 模块 | 2.3.
|
|
353
|
-
| `springbootai.langchain` LangChain 模块 | 2.3.
|
|
350
|
+
| `springbootai` 框架 API | 2.3.9 |
|
|
351
|
+
| `springbootai.orm.pymybatis` | 2.3.9 |
|
|
352
|
+
| `springbootai.ai` AI 模块 | 2.3.9 |
|
|
353
|
+
| `springbootai.langchain` LangChain 模块 | 2.3.9 |
|
|
354
354
|
| Python | 3.10+ |
|
|
355
355
|
|
|
356
356
|
### 1.4 适合什么场景
|
|
@@ -937,6 +937,16 @@ class InitService:
|
|
|
937
937
|
self.connection.close()
|
|
938
938
|
```
|
|
939
939
|
|
|
940
|
+
每个 HTTP 请求都会获得 `X-Request-ID`(可通过
|
|
941
|
+
`server.request-id.header` 修改),该值会写回响应并自动进入框架日志,Feign
|
|
942
|
+
和 Gateway 也会向下游透传。日志会遮蔽 Bearer Token、API Key、密码、Cookie
|
|
943
|
+
等常见敏感字段;`logging.diagnose` 默认关闭,避免异常帧局部变量泄密。
|
|
944
|
+
|
|
945
|
+
声明式 Feign 客户端默认复用连接池,对幂等请求执行有限退避重试,并支持连接/
|
|
946
|
+
读取超时与响应大小限制。直接读取 RAG 文本文件时建议使用
|
|
947
|
+
`TextReader.from_file(path, max_bytes=...)`,文件不存在或超限会明确失败,不会把
|
|
948
|
+
错误路径误当成内联文本。
|
|
949
|
+
|
|
940
950
|
### 5.7 应用事件
|
|
941
951
|
|
|
942
952
|
```python
|
|
@@ -1895,9 +1905,13 @@ export LOG_DIR=logs
|
|
|
1895
1905
|
|
|
1896
1906
|
# AI 模块
|
|
1897
1907
|
export AI_PROVIDER=openai
|
|
1898
|
-
export AI_ALLOW_FAKE=
|
|
1908
|
+
export AI_ALLOW_FAKE=false
|
|
1899
1909
|
export OPENAI_API_KEY=sk-xxx
|
|
1900
1910
|
export OPENAI_CHAT_MODEL=gpt-4o-mini
|
|
1911
|
+
export AI_REQUEST_TIMEOUT_SECONDS=60
|
|
1912
|
+
export AI_MAX_OUTPUT_TOKENS=4096
|
|
1913
|
+
export AI_MAX_TOTAL_TOKENS=100000
|
|
1914
|
+
export AI_MAX_TOOL_ITERATIONS=5
|
|
1901
1915
|
export OLLAMA_BASE_URL=http://localhost:11434
|
|
1902
1916
|
export OLLAMA_CHAT_MODEL=llama3
|
|
1903
1917
|
|
|
@@ -157,6 +157,7 @@ springbootai/langgraph/checkpoint.py
|
|
|
157
157
|
springbootai/langgraph/config.py
|
|
158
158
|
springbootai/langgraph/runtime.py
|
|
159
159
|
springbootai/logging/__init__.py
|
|
160
|
+
springbootai/logging/context.py
|
|
160
161
|
springbootai/logging/loguru_logger.py
|
|
161
162
|
springbootai/mcp/__init__.py
|
|
162
163
|
springbootai/mcp/annotation_runtime.py
|
|
@@ -266,7 +267,9 @@ tests/test_actuator_prometheus_admin.py
|
|
|
266
267
|
tests/test_ai_annotations.py
|
|
267
268
|
tests/test_ai_comprehensive.py
|
|
268
269
|
tests/test_ai_declarative_annotations.py
|
|
270
|
+
tests/test_ai_enterprise_hardening.py
|
|
269
271
|
tests/test_ai_module.py
|
|
272
|
+
tests/test_ai_stream_hardening.py
|
|
270
273
|
tests/test_annotation_combinations.py
|
|
271
274
|
tests/test_annotations_contract.py
|
|
272
275
|
tests/test_aop_annotations_full.py
|
|
@@ -278,9 +281,11 @@ tests/test_bus.py
|
|
|
278
281
|
tests/test_cache_annotations.py
|
|
279
282
|
tests/test_cli.py
|
|
280
283
|
tests/test_cloud_embedded_full.py
|
|
284
|
+
tests/test_cloud_log_safety.py
|
|
281
285
|
tests/test_component_init_error.py
|
|
282
286
|
tests/test_compositional_annotations.py
|
|
283
287
|
tests/test_conditional_annotations.py
|
|
288
|
+
tests/test_config_admin_hardening.py
|
|
284
289
|
tests/test_config_binding.py
|
|
285
290
|
tests/test_config_center.py
|
|
286
291
|
tests/test_config_center_hardening.py
|
|
@@ -297,10 +302,12 @@ tests/test_datasource_routing.py
|
|
|
297
302
|
tests/test_ddl_auto.py
|
|
298
303
|
tests/test_declarative_aop_post_authorize_recover.py
|
|
299
304
|
tests/test_devtools.py
|
|
305
|
+
tests/test_devtools_lifecycle_hardening.py
|
|
300
306
|
tests/test_di_config_event_full.py
|
|
301
307
|
tests/test_excel_module.py
|
|
302
308
|
tests/test_hateoas.py
|
|
303
309
|
tests/test_i18n_module.py
|
|
310
|
+
tests/test_io_http_logging_hardening.py
|
|
304
311
|
tests/test_ioc_lifecycle_enhancements.py
|
|
305
312
|
tests/test_jpa_version_transient.py
|
|
306
313
|
tests/test_kafka.py
|
|
@@ -16,7 +16,7 @@ SpringBootAI AI 模块 - 对齐 Spring AI 的 ChatClient/Advisor/ETL 抽象,
|
|
|
16
16
|
from springbootai.ai.core import (
|
|
17
17
|
Advisor, AdvisorRequest, ChatClient, ChatClientBuilder, ChatModel,
|
|
18
18
|
ChatResponse, EmbeddingModel, Generation, Message, MessageType,
|
|
19
|
-
PromptSpec,
|
|
19
|
+
PromptSpec, TokenBudgetExceededError, ToolLoopLimitExceededError,
|
|
20
20
|
)
|
|
21
21
|
from springbootai.ai.annotations import (
|
|
22
22
|
Agent, AiAdvisor, AiCache, AiClient, AiMemory, AiRetry, ContentModeration,
|
|
@@ -34,7 +34,8 @@ from springbootai.ai.vectorstore import (
|
|
|
34
34
|
SearchRequest, SimpleInMemoryVectorStore, VectorStore, cosine_similarity,
|
|
35
35
|
)
|
|
36
36
|
from springbootai.ai.etl import (
|
|
37
|
-
CharacterTextSplitter, DocumentReader,
|
|
37
|
+
CharacterTextSplitter, DocumentReader, DocumentTooLargeError,
|
|
38
|
+
TextDocument, TextReader,
|
|
38
39
|
TextSplitter, TokenTextSplitter,
|
|
39
40
|
)
|
|
40
41
|
from springbootai.ai.tools import (
|
|
@@ -42,10 +43,12 @@ from springbootai.ai.tools import (
|
|
|
42
43
|
ToolDefinition,
|
|
43
44
|
ToolExecutionPolicy,
|
|
44
45
|
ToolRegistry,
|
|
46
|
+
ToolCancellationToken,
|
|
45
47
|
)
|
|
46
48
|
from springbootai.ai.providers import (
|
|
47
49
|
FakeChatModel, FakeEmbeddingModel, OllamaChatModel, OllamaEmbeddingModel,
|
|
48
50
|
OpenAICompatChatModel, OpenAIChatModel, OpenAIEmbeddingModel,
|
|
51
|
+
ProviderProtocolError, ProviderResponseTooLargeError, ProviderStreamError,
|
|
49
52
|
)
|
|
50
53
|
from springbootai.ai.resilience import (
|
|
51
54
|
AICircuitBreaker, CircuitOpenError, TransientError, resilient_call,
|
|
@@ -54,13 +57,14 @@ from springbootai.ai.observability import AIMetrics, ai_metrics
|
|
|
54
57
|
from springbootai.ai.autoconfig import AIProperties, bind_ai_config, configure_ai
|
|
55
58
|
from springbootai.ai.annotation_runtime import ContentModerationError
|
|
56
59
|
|
|
57
|
-
__version__ = "2.3.
|
|
60
|
+
__version__ = "2.3.9"
|
|
58
61
|
|
|
59
62
|
__all__ = [
|
|
60
63
|
# core
|
|
61
64
|
"Advisor", "AdvisorRequest", "ChatClient", "ChatClientBuilder",
|
|
62
65
|
"ChatModel", "ChatResponse", "EmbeddingModel", "Generation", "Message",
|
|
63
|
-
"MessageType", "PromptSpec",
|
|
66
|
+
"MessageType", "PromptSpec", "TokenBudgetExceededError",
|
|
67
|
+
"ToolLoopLimitExceededError",
|
|
64
68
|
# annotations
|
|
65
69
|
"AiAdvisor", "AiClient", "AiMemory", "Tool", "Prompt", "RAG",
|
|
66
70
|
"StructuredOutput", "Agent", "Embedding", "VectorStore", "AiRetry",
|
|
@@ -76,14 +80,18 @@ __all__ = [
|
|
|
76
80
|
"SearchRequest", "SimpleInMemoryVectorStore", "VectorStore",
|
|
77
81
|
"cosine_similarity",
|
|
78
82
|
# etl
|
|
79
|
-
"CharacterTextSplitter", "DocumentReader", "
|
|
83
|
+
"CharacterTextSplitter", "DocumentReader", "DocumentTooLargeError",
|
|
84
|
+
"TextDocument", "TextReader",
|
|
80
85
|
"TextSplitter", "TokenTextSplitter",
|
|
81
86
|
# tools
|
|
82
|
-
"CompositeToolRegistry", "
|
|
87
|
+
"CompositeToolRegistry", "ToolCancellationToken", "ToolDefinition",
|
|
88
|
+
"ToolExecutionPolicy", "ToolRegistry",
|
|
83
89
|
# providers
|
|
84
90
|
"FakeChatModel", "FakeEmbeddingModel", "OllamaChatModel",
|
|
85
91
|
"OllamaEmbeddingModel", "OpenAICompatChatModel", "OpenAIChatModel",
|
|
86
|
-
"OpenAIEmbeddingModel",
|
|
92
|
+
"OpenAIEmbeddingModel", "ProviderProtocolError",
|
|
93
|
+
"ProviderResponseTooLargeError",
|
|
94
|
+
"ProviderStreamError",
|
|
87
95
|
# resilience
|
|
88
96
|
"AICircuitBreaker", "CircuitOpenError", "TransientError", "resilient_call",
|
|
89
97
|
# observability
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Advisor 实现 - QuestionAnswerAdvisor(RAG)与 MessageChatMemoryAdvisor(会话记忆)。
|
|
3
3
|
"""
|
|
4
|
-
|
|
4
|
+
import inspect
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
from typing import Any, Dict, List, Optional, Sequence
|
|
5
7
|
|
|
6
8
|
from springbootai.ai.core import (
|
|
7
9
|
Advisor, AdvisorRequest, ChatResponse, Message, MessageType,
|
|
@@ -25,11 +27,31 @@ class MessageChatMemoryAdvisor(Advisor):
|
|
|
25
27
|
|
|
26
28
|
@staticmethod
|
|
27
29
|
def _build_namespace(context: dict) -> str:
|
|
28
|
-
tenant = str(context.get("tenant_id", "")).strip()
|
|
29
|
-
user = str(context.get("user_id", "")).strip()
|
|
30
|
+
tenant = quote(str(context.get("tenant_id", "")).strip()[:128], safe="-_.~")
|
|
31
|
+
user = quote(str(context.get("user_id", "")).strip()[:128], safe="-_.~")
|
|
30
32
|
parts = [p for p in (tenant, user) if p]
|
|
31
33
|
return ":".join(parts) if parts else ""
|
|
32
34
|
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _call_memory(method, *args, namespace: str, **kwargs):
|
|
37
|
+
"""Call new namespaced memory APIs without silently weakening old backends."""
|
|
38
|
+
try:
|
|
39
|
+
parameters = inspect.signature(method).parameters.values()
|
|
40
|
+
supports_namespace = any(
|
|
41
|
+
p.name == "namespace" or p.kind == inspect.Parameter.VAR_KEYWORD
|
|
42
|
+
for p in parameters
|
|
43
|
+
)
|
|
44
|
+
except (TypeError, ValueError):
|
|
45
|
+
supports_namespace = False
|
|
46
|
+
if namespace and not supports_namespace:
|
|
47
|
+
raise RuntimeError(
|
|
48
|
+
"ChatMemory backend does not support request-scoped namespaces; "
|
|
49
|
+
"refusing a potentially cross-tenant memory access"
|
|
50
|
+
)
|
|
51
|
+
if supports_namespace:
|
|
52
|
+
kwargs["namespace"] = namespace
|
|
53
|
+
return method(*args, **kwargs)
|
|
54
|
+
|
|
33
55
|
def __init__(self, memory: ChatMemory, max_messages: int = 20):
|
|
34
56
|
self.memory = memory
|
|
35
57
|
self.max_messages = max_messages
|
|
@@ -44,12 +66,15 @@ class MessageChatMemoryAdvisor(Advisor):
|
|
|
44
66
|
"跳过历史注入。请在上游设置 request.context['conversation_id']。")
|
|
45
67
|
return request
|
|
46
68
|
|
|
47
|
-
#
|
|
69
|
+
# Namespace is passed per operation. Never mutate a shared memory bean:
|
|
70
|
+
# concurrent requests may belong to different tenants.
|
|
48
71
|
ns = self._build_namespace(request.context)
|
|
49
|
-
|
|
50
|
-
self.memory._namespace = ns
|
|
72
|
+
request.context["memory_namespace"] = ns
|
|
51
73
|
|
|
52
|
-
history = self.
|
|
74
|
+
history = self._call_memory(
|
|
75
|
+
self.memory.get, str(conv_id), last_n=self.max_messages,
|
|
76
|
+
namespace=ns,
|
|
77
|
+
)
|
|
53
78
|
# 历史 + 本次输入合并
|
|
54
79
|
request.messages = history + request.messages
|
|
55
80
|
return request
|
|
@@ -59,14 +84,18 @@ class MessageChatMemoryAdvisor(Advisor):
|
|
|
59
84
|
conv_id = request.context.get("conversation_id")
|
|
60
85
|
if not conv_id:
|
|
61
86
|
return response
|
|
87
|
+
ns = str(request.context.get("memory_namespace") or
|
|
88
|
+
self._build_namespace(request.context))
|
|
62
89
|
# 保存用户输入(最后一条 user 消息)
|
|
63
90
|
for msg in reversed(request.messages):
|
|
64
91
|
if msg.type == MessageType.USER:
|
|
65
|
-
self.
|
|
92
|
+
self._call_memory(
|
|
93
|
+
self.memory.add, str(conv_id), msg, namespace=ns)
|
|
66
94
|
break
|
|
67
95
|
# 保存模型回复
|
|
68
96
|
if response.output:
|
|
69
|
-
self.
|
|
97
|
+
self._call_memory(
|
|
98
|
+
self.memory.add, str(conv_id), response.output, namespace=ns)
|
|
70
99
|
return response
|
|
71
100
|
|
|
72
101
|
|
|
@@ -89,12 +118,16 @@ class QuestionAnswerAdvisor(Advisor):
|
|
|
89
118
|
prompt_template: str = "",
|
|
90
119
|
top_k: int = 4,
|
|
91
120
|
embedding_model=None,
|
|
92
|
-
harden_injection: bool = True
|
|
121
|
+
harden_injection: bool = True,
|
|
122
|
+
filter_metadata: Optional[Dict[str, Any]] = None,
|
|
123
|
+
filter_context_keys: Sequence[str] = ("tenant_id",)):
|
|
93
124
|
self.vector_store = vector_store
|
|
94
125
|
self.prompt_template = prompt_template or self.DEFAULT_PROMPT_TEMPLATE
|
|
95
126
|
self.top_k = top_k
|
|
96
127
|
self.embedding_model = embedding_model
|
|
97
128
|
self.harden_injection = harden_injection
|
|
129
|
+
self.filter_metadata = dict(filter_metadata or {})
|
|
130
|
+
self.filter_context_keys = tuple(filter_context_keys)
|
|
98
131
|
|
|
99
132
|
def advise_request(self, request: AdvisorRequest) -> AdvisorRequest:
|
|
100
133
|
# 取最后一条用户消息作为查询
|
|
@@ -110,9 +143,21 @@ class QuestionAnswerAdvisor(Advisor):
|
|
|
110
143
|
emb = None
|
|
111
144
|
if self.embedding_model:
|
|
112
145
|
emb = self.embedding_model.embed_one(query)
|
|
146
|
+
filters = dict(self.filter_metadata)
|
|
147
|
+
for key in self.filter_context_keys:
|
|
148
|
+
value = request.context.get(key)
|
|
149
|
+
if value is not None and str(value).strip():
|
|
150
|
+
filters[key] = str(value).strip()
|
|
151
|
+
# When no tenant exists, a verified user identity can still isolate a
|
|
152
|
+
# personal knowledge base. Tenant scope takes precedence by default so
|
|
153
|
+
# shared tenant documents do not require a redundant user_id field.
|
|
154
|
+
if not filters and request.context.get("user_id"):
|
|
155
|
+
filters["user_id"] = str(request.context["user_id"]).strip()
|
|
156
|
+
|
|
113
157
|
search_req = SearchRequest(
|
|
114
158
|
query=query, embedding=emb, top_k=self.top_k,
|
|
115
159
|
similarity_threshold=0.1,
|
|
160
|
+
filter_metadata=filters or None,
|
|
116
161
|
)
|
|
117
162
|
docs = self.vector_store.similarity_search(search_req)
|
|
118
163
|
if not docs:
|
|
@@ -15,7 +15,7 @@ import os
|
|
|
15
15
|
import threading
|
|
16
16
|
import time
|
|
17
17
|
from collections import OrderedDict
|
|
18
|
-
from typing import Any, Callable,
|
|
18
|
+
from typing import Any, Callable, Optional
|
|
19
19
|
|
|
20
20
|
from springbootai.ai.annotations import (
|
|
21
21
|
Agent, AiCache, AiRetry, ContentModeration, Embedding, Prompt, RAG,
|
|
@@ -449,10 +449,15 @@ def _invoke_chat(factory: Any, annotation: Prompt, query: str, values: dict[str,
|
|
|
449
449
|
system = _render(annotation.system, values)
|
|
450
450
|
if system:
|
|
451
451
|
spec.system(system)
|
|
452
|
-
|
|
452
|
+
spec.user(query)
|
|
453
|
+
for key in ("tenant_id", "user_id", "conversation_id"):
|
|
454
|
+
if values.get(key) is not None:
|
|
455
|
+
spec.param(key, values[key])
|
|
456
|
+
return spec.call()
|
|
453
457
|
|
|
454
458
|
|
|
455
|
-
def _invoke_rag(factory: Any, annotation: RAG, query: str
|
|
459
|
+
def _invoke_rag(factory: Any, annotation: RAG, query: str,
|
|
460
|
+
values: Optional[dict[str, Any]] = None) -> Any:
|
|
456
461
|
client = _resolve(factory, annotation.client)
|
|
457
462
|
store = _resolve(factory, annotation.vector_store)
|
|
458
463
|
embedding = _resolve(factory, annotation.embedding)
|
|
@@ -463,7 +468,14 @@ def _invoke_rag(factory: Any, annotation: RAG, query: str) -> Any:
|
|
|
463
468
|
store, prompt_template=annotation.prompt_template,
|
|
464
469
|
top_k=annotation.top_k, embedding_model=embedding,
|
|
465
470
|
)
|
|
466
|
-
|
|
471
|
+
spec = client.prompt().advisors(advisor).user(query)
|
|
472
|
+
# Carry only identity/session fields into AdvisorRequest. Arbitrary method
|
|
473
|
+
# arguments must never become trusted authorization context implicitly.
|
|
474
|
+
values = values or {}
|
|
475
|
+
for key in ("tenant_id", "user_id", "conversation_id"):
|
|
476
|
+
if values.get(key) is not None:
|
|
477
|
+
spec.param(key, values[key])
|
|
478
|
+
return spec.call()
|
|
467
479
|
|
|
468
480
|
|
|
469
481
|
def _invoke_agent(factory: Any, annotation: Agent, query: str) -> Any:
|
|
@@ -508,7 +520,7 @@ def apply_ai_annotations(factory: Any, instance: Any, method: Callable) -> Calla
|
|
|
508
520
|
if query is None:
|
|
509
521
|
original = method(*args, **kwargs)
|
|
510
522
|
query = _content(original)
|
|
511
|
-
result = _invoke_rag(factory, rag_ann, query)
|
|
523
|
+
result = _invoke_rag(factory, rag_ann, query, values)
|
|
512
524
|
elif agent_ann:
|
|
513
525
|
original = method(*args, **kwargs)
|
|
514
526
|
result = _invoke_agent(factory, agent_ann, _content(original))
|
|
@@ -545,7 +557,7 @@ def apply_ai_annotations(factory: Any, instance: Any, method: Callable) -> Calla
|
|
|
545
557
|
result = _invoke_chat(factory, prompt_ann, _render(prompt_ann.template, values), values)
|
|
546
558
|
elif rag_ann:
|
|
547
559
|
original = await method(*args, **kwargs)
|
|
548
|
-
result = _invoke_rag(factory, rag_ann, _content(original))
|
|
560
|
+
result = _invoke_rag(factory, rag_ann, _content(original), values)
|
|
549
561
|
elif agent_ann:
|
|
550
562
|
original = await method(*args, **kwargs)
|
|
551
563
|
result = _invoke_agent(factory, agent_ann, _content(original))
|