unique_toolkit 1.68.13__tar.gz → 1.69.1__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.
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/PKG-INFO +3 -1
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/pyproject.toml +4 -1
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +260 -5
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/history_manager/loop_token_reducer.py +13 -11
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/runners/qwen/qwen_runner.py +7 -6
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py +4 -4
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/fast_api_factory.py +15 -0
- unique_toolkit-1.69.1/unique_toolkit/monitoring/__init__.py +39 -0
- unique_toolkit-1.69.1/unique_toolkit/monitoring/middleware.py +90 -0
- unique_toolkit-1.69.1/unique_toolkit/monitoring/registry.py +107 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/README.md +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/_base_service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/_time_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/api_calling/human_verification_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/base_model_type_attribute.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/chunk_relevancy_sorter/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/chunk_relevancy_sorter/exception.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/chunk_relevancy_sorter/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/README.md +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/__main__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/cli.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/differ.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/exporter.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/models.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/registry.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/config_checker/validator.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/default_language_model.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/docx_generator/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/docx_generator/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/docx_generator/pandoc_converter.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/docx_generator/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/docx_generator/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/endpoint_builder.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/endpoint_requestor.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/event_bus.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/exception.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/execution.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/endpoint_builder.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/endpoint_requestor.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/README.md +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/agent.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/examples/data.csv +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/examples/example_usage.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/exceptions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/exceptions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/system_prompt.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/user_prompt.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/default_template.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/exceptions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/experimental/write_up_agent/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/feature_flags/schema.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/pydantic/rjsf_tags.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/pydantic_helpers.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/referencing.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/string_utilities.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/tests/test_referencing.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/tests/test_string_utilities.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/token/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/token/image_token_counting.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/token/token_counting.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/token/tokenizers/deepseek/tokenizer.json +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/token/tokenizers/qwen/tokenizer.json +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/files.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/image/encode.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/jinja/helpers.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/jinja/render.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/jinja/schema.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/jinja/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/structured_output/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/structured_output/schema.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/utils/write_configuration.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/validate_required_values.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/_common/validators.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/system_prompt.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/user_prompt.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/context_relevancy/schema.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/context_relevancy/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/evaluation_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/exception.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/hallucination/constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/hallucination/prompts/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/hallucination/prompts/system_prompt.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/hallucination/prompts/user_prompt.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/hallucination/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/hallucination/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/output_parser.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/tests/fixtures.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/tests/test_config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/tests/test_hallucination_constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/tests/test_hallucination_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/tests/test_output_parser.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/tests/test_prompt_loaders.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/evaluation/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/feature_flags/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/feature_flags/feature_flags.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/history_manager/history_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/history_manager/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/_iteration_handler_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/_responses_iteration_handler_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/_responses_stream_handler_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/_stream_handler_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/base.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/middleware/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/middleware/planning/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/middleware/planning/planning.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/middleware/planning/schema.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/runners/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/runners/basic.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/runners/mistral/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/runners/mistral/mistral_runner.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/runners/qwen/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/loop_runner/runners/qwen/helpers.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/message_log_manager/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/message_log_manager/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/postprocessor/postprocessor_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/reference_manager/reference_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/responses_api/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/responses_api/postprocessors/code_display.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/responses_api/stream_handler.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/thinking_manager/thinking_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/evaluation/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/display.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/references.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/prompts.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/response_watcher/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/tool/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/tool/_memory.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/tool/_schema.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/tool/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/tool/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/a2a/tool/test/test_service_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/agent_chunks_hanlder.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/experimental/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/experimental/open_file_tool/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/experimental/open_file_tool/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/experimental/open_file_tool/runtime.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/experimental/open_file_tool/tool.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/factory.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/mcp/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/mcp/manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/mcp/models.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/base.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/code_display.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/generated_files.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/openai_builtin/manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/test/test_mcp_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/tool.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/tool_manager.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/tool_progress_reporter.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/utils/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/utils/source_handling/schema.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic_table/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic_table/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic_table/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/dev_util.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/init_logging.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/init_sdk.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/performance/async_tasks.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/performance/async_wrapper.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/unique_settings.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/verification.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/app/webhook.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/cancellation.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/deprecated/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/functions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/rendering.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/responses_api.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/state.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/chat/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/content/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/content/constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/content/functions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/content/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/content/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/content/smart_rules.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/content/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/README.md +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/augmented/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/augmented/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/base.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/basic/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/basic/config.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/basic/prompt.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/data_extraction/basic/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/elicitation/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/elicitation/constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/elicitation/exceptions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/elicitation/functions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/elicitation/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/elicitation/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/embedding/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/embedding/constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/embedding/functions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/embedding/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/embedding/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/embedding/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/langchain/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/openai/client.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/framework_utilities/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/_responses_api_utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/builder.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/default_language_model.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/functions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/infos.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/prompt.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/reference.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/stream_transform.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/language_model/utils.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/protocols/support.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/services/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/services/chat_service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/services/factory.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/services/knowledge_base.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/short_term_memory/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/short_term_memory/constants.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/short_term_memory/functions.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/short_term_memory/schemas.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/short_term_memory/service.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/smart_rules/__init__.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/smart_rules/compile.py +0 -0
- {unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/test_utilities/events.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-toolkit
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.69.1
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Cedric Klinkert, Martin Fadler, Sadique Sheik, Fabian Schläpfer, Pascal Hauri, Ejiroghene Oki-Peter, Rami Azouz, Ricardo Visini, Sanzio Monti
|
|
6
6
|
Author-email: Cedric Klinkert <cedric.klinkert@unique.ch>, Martin Fadler <martin.fadler@unique.ch>, Sadique Sheik <sadique@unique.ch>, Fabian Schläpfer <fabian@unique.ch>, Pascal Hauri <pascal@unique.ch>, Ejiroghene Oki-Peter <oki-peter.ejiroghene@unique.ai>, Rami Azouz <rami.ext@unique.ch>, Ricardo Visini <ricardo.visini@unique.ch>, Sanzio Monti <sanzio.monti@unique.ai>
|
|
@@ -38,9 +38,11 @@ Requires-Dist: openai>=1.105.0,<2 ; extra == 'langchain'
|
|
|
38
38
|
Requires-Dist: langchain>=1.0.0,<2 ; extra == 'langchain'
|
|
39
39
|
Requires-Dist: langchain-openai>=0.3.28 ; extra == 'langchain'
|
|
40
40
|
Requires-Dist: langchain-core>=1.0.0,<2 ; extra == 'langchain'
|
|
41
|
+
Requires-Dist: prometheus-client>=0.24.1,<1 ; extra == 'monitoring'
|
|
41
42
|
Requires-Python: >=3.12
|
|
42
43
|
Provides-Extra: fastapi
|
|
43
44
|
Provides-Extra: langchain
|
|
45
|
+
Provides-Extra: monitoring
|
|
44
46
|
Description-Content-Type: text/markdown
|
|
45
47
|
|
|
46
48
|
# Unique Toolkit
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_toolkit"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.69.1"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -57,6 +57,9 @@ fastapi = [
|
|
|
57
57
|
"starlette>=0.49.1",
|
|
58
58
|
"uvicorn>=0.37.0,<0.38",
|
|
59
59
|
]
|
|
60
|
+
monitoring = [
|
|
61
|
+
"prometheus_client>=0.24.1,<1",
|
|
62
|
+
]
|
|
60
63
|
|
|
61
64
|
[build-system]
|
|
62
65
|
requires = ["uv_build>=0.8.14,<0.9.0"]
|
|
@@ -6,7 +6,7 @@ import mimetypes
|
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
from enum import StrEnum
|
|
8
8
|
from itertools import groupby
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
9
|
+
from typing import TYPE_CHECKING, Iterator
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from unique_toolkit.content.schemas import ContentChunk
|
|
@@ -77,7 +77,7 @@ class ChatHistoryWithContent(RootModel):
|
|
|
77
77
|
|
|
78
78
|
return cls(root=grouped_elements)
|
|
79
79
|
|
|
80
|
-
def __iter__(self):
|
|
80
|
+
def __iter__(self) -> Iterator[ChatMessageWithContents]:
|
|
81
81
|
return iter(self.root)
|
|
82
82
|
|
|
83
83
|
def __getitem__(self, item):
|
|
@@ -94,7 +94,7 @@ def get_chat_history_with_contents(
|
|
|
94
94
|
id=user_message.id,
|
|
95
95
|
chat_id=chat_id,
|
|
96
96
|
text=user_message.text,
|
|
97
|
-
|
|
97
|
+
original_text=user_message.original_text,
|
|
98
98
|
role=ChatRole.USER,
|
|
99
99
|
gpt_request=None,
|
|
100
100
|
created_at=datetime.fromisoformat(user_message.created_at),
|
|
@@ -118,6 +118,41 @@ def get_chat_history_with_contents(
|
|
|
118
118
|
)
|
|
119
119
|
|
|
120
120
|
|
|
121
|
+
async def get_chat_history_with_contents_async(
|
|
122
|
+
*,
|
|
123
|
+
user_message: ChatEventUserMessage,
|
|
124
|
+
chat_id: str,
|
|
125
|
+
chat_history: list[ChatMessage],
|
|
126
|
+
content_service: ContentService,
|
|
127
|
+
) -> ChatHistoryWithContent:
|
|
128
|
+
last_user_message = ChatMessage(
|
|
129
|
+
id=user_message.id,
|
|
130
|
+
chat_id=chat_id,
|
|
131
|
+
text=user_message.text,
|
|
132
|
+
original_text=user_message.original_text,
|
|
133
|
+
role=ChatRole.USER,
|
|
134
|
+
gpt_request=None,
|
|
135
|
+
created_at=datetime.fromisoformat(user_message.created_at),
|
|
136
|
+
)
|
|
137
|
+
if len(chat_history) > 0 and last_user_message.id == chat_history[-1].id:
|
|
138
|
+
pass
|
|
139
|
+
else:
|
|
140
|
+
chat_history.append(last_user_message)
|
|
141
|
+
|
|
142
|
+
chat_contents = await content_service.search_contents_async(
|
|
143
|
+
where={
|
|
144
|
+
"ownerId": {
|
|
145
|
+
"equals": chat_id,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return ChatHistoryWithContent.from_chat_history_and_contents(
|
|
151
|
+
chat_history,
|
|
152
|
+
chat_contents,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
121
156
|
def download_encoded_images(
|
|
122
157
|
contents: list[Content],
|
|
123
158
|
content_service: ContentService,
|
|
@@ -141,6 +176,30 @@ def download_encoded_images(
|
|
|
141
176
|
return base64_encoded_images
|
|
142
177
|
|
|
143
178
|
|
|
179
|
+
async def download_encoded_images_async(
|
|
180
|
+
*,
|
|
181
|
+
contents: list[Content],
|
|
182
|
+
content_service: ContentService,
|
|
183
|
+
chat_id: str,
|
|
184
|
+
) -> list[str]:
|
|
185
|
+
base64_encoded_images = []
|
|
186
|
+
for im in contents:
|
|
187
|
+
if FileUtils.is_image_content(im.key):
|
|
188
|
+
try:
|
|
189
|
+
file_bytes = await content_service.download_content_to_bytes_async(
|
|
190
|
+
content_id=im.id,
|
|
191
|
+
chat_id=chat_id,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
mime_type, _ = mimetypes.guess_type(im.key)
|
|
195
|
+
encoded_string = base64.b64encode(file_bytes).decode("utf-8")
|
|
196
|
+
image_string = f"data:{mime_type};base64," + encoded_string
|
|
197
|
+
base64_encoded_images.append(image_string)
|
|
198
|
+
except Exception as e:
|
|
199
|
+
_LOGGER.warning("Failed to download image %s: %s", im.key, e)
|
|
200
|
+
return base64_encoded_images
|
|
201
|
+
|
|
202
|
+
|
|
144
203
|
class FileContentSerialization(StrEnum):
|
|
145
204
|
NONE = "none"
|
|
146
205
|
FILE_NAME = "file_name"
|
|
@@ -212,6 +271,49 @@ def _append_element_to_builder(
|
|
|
212
271
|
)
|
|
213
272
|
|
|
214
273
|
|
|
274
|
+
async def _append_element_to_builder_async(
|
|
275
|
+
builder: MessagesBuilder,
|
|
276
|
+
*,
|
|
277
|
+
c: ChatMessageWithContents,
|
|
278
|
+
text: str,
|
|
279
|
+
include_images: ImageContentInclusion,
|
|
280
|
+
file_content_serialization_type: FileContentSerialization,
|
|
281
|
+
content_service: ContentService,
|
|
282
|
+
chat_id: str,
|
|
283
|
+
) -> None:
|
|
284
|
+
if len(c.contents) > 0:
|
|
285
|
+
file_contents = [co for co in c.contents if FileUtils.is_file_content(co.key)]
|
|
286
|
+
image_contents = [co for co in c.contents if FileUtils.is_image_content(co.key)]
|
|
287
|
+
content = (
|
|
288
|
+
text
|
|
289
|
+
+ "\n\n"
|
|
290
|
+
+ file_content_serialization(
|
|
291
|
+
file_contents,
|
|
292
|
+
file_content_serialization_type,
|
|
293
|
+
)
|
|
294
|
+
).strip()
|
|
295
|
+
if include_images and len(image_contents) > 0:
|
|
296
|
+
builder.image_message_append(
|
|
297
|
+
content=content,
|
|
298
|
+
images=await download_encoded_images_async(
|
|
299
|
+
contents=image_contents,
|
|
300
|
+
content_service=content_service,
|
|
301
|
+
chat_id=chat_id,
|
|
302
|
+
),
|
|
303
|
+
role=map_chat_llm_message_role[c.role],
|
|
304
|
+
)
|
|
305
|
+
else:
|
|
306
|
+
builder.message_append(
|
|
307
|
+
role=map_chat_llm_message_role[c.role],
|
|
308
|
+
content=content,
|
|
309
|
+
)
|
|
310
|
+
else:
|
|
311
|
+
builder.message_append(
|
|
312
|
+
role=map_chat_llm_message_role[c.role],
|
|
313
|
+
content=text,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
|
|
215
317
|
def get_full_history_with_contents(
|
|
216
318
|
user_message: ChatEventUserMessage,
|
|
217
319
|
chat_id: str,
|
|
@@ -228,7 +330,7 @@ def get_full_history_with_contents(
|
|
|
228
330
|
)
|
|
229
331
|
|
|
230
332
|
builder = LanguageModelMessages([]).builder()
|
|
231
|
-
for c in grouped_elements:
|
|
333
|
+
for c in grouped_elements.root:
|
|
232
334
|
# LanguageModelUserMessage has no field original_text
|
|
233
335
|
text = c.original_text if c.original_text else c.content
|
|
234
336
|
if text is None:
|
|
@@ -249,6 +351,43 @@ def get_full_history_with_contents(
|
|
|
249
351
|
return builder.build()
|
|
250
352
|
|
|
251
353
|
|
|
354
|
+
async def get_full_history_with_contents_async(
|
|
355
|
+
*,
|
|
356
|
+
user_message: ChatEventUserMessage,
|
|
357
|
+
chat_id: str,
|
|
358
|
+
chat_service: ChatService,
|
|
359
|
+
content_service: ContentService,
|
|
360
|
+
include_images: ImageContentInclusion = ImageContentInclusion.ALL,
|
|
361
|
+
file_content_serialization_type: FileContentSerialization = FileContentSerialization.FILE_NAME,
|
|
362
|
+
) -> LanguageModelMessages:
|
|
363
|
+
grouped_elements = await get_chat_history_with_contents_async(
|
|
364
|
+
user_message=user_message,
|
|
365
|
+
chat_id=chat_id,
|
|
366
|
+
chat_history=await chat_service.get_full_history_async(),
|
|
367
|
+
content_service=content_service,
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
builder = LanguageModelMessages([]).builder()
|
|
371
|
+
for c in grouped_elements.root:
|
|
372
|
+
text = c.original_text if c.original_text else c.content
|
|
373
|
+
if text is None:
|
|
374
|
+
if c.role == ChatRole.USER:
|
|
375
|
+
raise ValueError(
|
|
376
|
+
"Content or original_text of LanguageModelMessages should exist.",
|
|
377
|
+
)
|
|
378
|
+
text = ""
|
|
379
|
+
await _append_element_to_builder_async(
|
|
380
|
+
builder=builder,
|
|
381
|
+
c=c,
|
|
382
|
+
text=text,
|
|
383
|
+
include_images=include_images,
|
|
384
|
+
file_content_serialization_type=file_content_serialization_type,
|
|
385
|
+
content_service=content_service,
|
|
386
|
+
chat_id=chat_id,
|
|
387
|
+
)
|
|
388
|
+
return builder.build()
|
|
389
|
+
|
|
390
|
+
|
|
252
391
|
def get_full_history_with_contents_and_tool_calls(
|
|
253
392
|
*,
|
|
254
393
|
user_message: ChatEventUserMessage,
|
|
@@ -307,7 +446,7 @@ def get_full_history_with_contents_and_tool_calls(
|
|
|
307
446
|
)
|
|
308
447
|
|
|
309
448
|
builder = LanguageModelMessages([]).builder()
|
|
310
|
-
for c in grouped_elements:
|
|
449
|
+
for c in grouped_elements.root:
|
|
311
450
|
text = c.original_text if c.original_text else c.content
|
|
312
451
|
if text is None:
|
|
313
452
|
if c.role == ChatRole.USER:
|
|
@@ -391,6 +530,122 @@ def get_full_history_with_contents_and_tool_calls(
|
|
|
391
530
|
return builder.build(), max_source_number, source_map
|
|
392
531
|
|
|
393
532
|
|
|
533
|
+
async def get_full_history_with_contents_and_tool_calls_async(
|
|
534
|
+
*,
|
|
535
|
+
user_message: ChatEventUserMessage,
|
|
536
|
+
chat_id: str,
|
|
537
|
+
chat_service: ChatService,
|
|
538
|
+
content_service: ContentService,
|
|
539
|
+
include_images: ImageContentInclusion = ImageContentInclusion.ALL,
|
|
540
|
+
file_content_serialization_type: FileContentSerialization = FileContentSerialization.FILE_NAME,
|
|
541
|
+
) -> tuple[LanguageModelMessages, int, dict[int, "ContentChunk"]]:
|
|
542
|
+
"""Async version of get_full_history_with_contents_and_tool_calls."""
|
|
543
|
+
from unique_toolkit.agentic.history_manager.utils import (
|
|
544
|
+
build_source_map_from_tool_calls,
|
|
545
|
+
compute_max_source_number_from_tool_calls,
|
|
546
|
+
)
|
|
547
|
+
from unique_toolkit.content.schemas import (
|
|
548
|
+
ContentChunk as ContentChunk, # noqa: F811
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
chat_history = await chat_service.get_full_history_async()
|
|
552
|
+
|
|
553
|
+
assistant_message_ids = [
|
|
554
|
+
msg.id for msg in chat_history if msg.role == ChatRole.ASSISTANT and msg.id
|
|
555
|
+
]
|
|
556
|
+
all_tool_calls: list[ChatMessageTool] = []
|
|
557
|
+
tool_calls_by_message: dict[str, list[ChatMessageTool]] = {}
|
|
558
|
+
if assistant_message_ids:
|
|
559
|
+
try:
|
|
560
|
+
all_tool_calls = await chat_service.get_message_tools_async(
|
|
561
|
+
message_ids=assistant_message_ids,
|
|
562
|
+
)
|
|
563
|
+
for tc in all_tool_calls:
|
|
564
|
+
if tc.message_id:
|
|
565
|
+
tool_calls_by_message.setdefault(tc.message_id, []).append(tc)
|
|
566
|
+
except Exception:
|
|
567
|
+
_LOGGER.warning(
|
|
568
|
+
"Failed to batch-load tool calls, falling back to empty", exc_info=True
|
|
569
|
+
)
|
|
570
|
+
max_source_number = compute_max_source_number_from_tool_calls(all_tool_calls)
|
|
571
|
+
source_map: dict[int, ContentChunk] = build_source_map_from_tool_calls(
|
|
572
|
+
all_tool_calls
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
grouped_elements = await get_chat_history_with_contents_async(
|
|
576
|
+
user_message=user_message,
|
|
577
|
+
chat_id=chat_id,
|
|
578
|
+
chat_history=chat_history,
|
|
579
|
+
content_service=content_service,
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
builder = LanguageModelMessages([]).builder()
|
|
583
|
+
for c in grouped_elements.root:
|
|
584
|
+
text = c.original_text if c.original_text else c.content
|
|
585
|
+
if text is None:
|
|
586
|
+
if c.role == ChatRole.USER:
|
|
587
|
+
raise ValueError(
|
|
588
|
+
"Content or original_text of LanguageModelMessages should exist.",
|
|
589
|
+
)
|
|
590
|
+
text = ""
|
|
591
|
+
|
|
592
|
+
if c.role == ChatRole.ASSISTANT and c.id and c.id in tool_calls_by_message:
|
|
593
|
+
tc_records = sorted(
|
|
594
|
+
tool_calls_by_message[c.id],
|
|
595
|
+
key=lambda tc: (tc.round_index, tc.sequence_index),
|
|
596
|
+
)
|
|
597
|
+
if tc_records:
|
|
598
|
+
for _round, round_group in groupby(
|
|
599
|
+
tc_records, key=lambda tc: tc.round_index
|
|
600
|
+
):
|
|
601
|
+
round_tcs = list(round_group)
|
|
602
|
+
round_tcs_with_response = [
|
|
603
|
+
tc
|
|
604
|
+
for tc in round_tcs
|
|
605
|
+
if tc.response and tc.response.content is not None
|
|
606
|
+
]
|
|
607
|
+
if not round_tcs_with_response:
|
|
608
|
+
continue
|
|
609
|
+
fns = [
|
|
610
|
+
LanguageModelFunction(
|
|
611
|
+
id=tc.external_tool_call_id,
|
|
612
|
+
name=tc.function_name,
|
|
613
|
+
arguments=tc.arguments,
|
|
614
|
+
)
|
|
615
|
+
for tc in round_tcs_with_response
|
|
616
|
+
]
|
|
617
|
+
builder.messages.append(
|
|
618
|
+
LanguageModelAssistantMessage.from_functions(tool_calls=fns)
|
|
619
|
+
)
|
|
620
|
+
for fn, tc in zip(fns, round_tcs_with_response):
|
|
621
|
+
builder.messages.append(
|
|
622
|
+
LanguageModelToolMessage(
|
|
623
|
+
tool_call_id=fn.id,
|
|
624
|
+
content=tc.response.content, # type: ignore[union-attr]
|
|
625
|
+
name=tc.function_name,
|
|
626
|
+
)
|
|
627
|
+
)
|
|
628
|
+
|
|
629
|
+
had_tool_calls = (
|
|
630
|
+
c.role == ChatRole.ASSISTANT
|
|
631
|
+
and c.id is not None
|
|
632
|
+
and c.id in tool_calls_by_message
|
|
633
|
+
)
|
|
634
|
+
if had_tool_calls and not text:
|
|
635
|
+
continue
|
|
636
|
+
|
|
637
|
+
await _append_element_to_builder_async(
|
|
638
|
+
builder=builder,
|
|
639
|
+
c=c,
|
|
640
|
+
text=text,
|
|
641
|
+
include_images=include_images,
|
|
642
|
+
file_content_serialization_type=file_content_serialization_type,
|
|
643
|
+
content_service=content_service,
|
|
644
|
+
chat_id=chat_id,
|
|
645
|
+
)
|
|
646
|
+
return builder.build(), max_source_number, source_map
|
|
647
|
+
|
|
648
|
+
|
|
394
649
|
def get_full_history_as_llm_messages(
|
|
395
650
|
chat_service: ChatService,
|
|
396
651
|
) -> LanguageModelMessages:
|
|
@@ -10,8 +10,8 @@ from unique_toolkit._common.token.token_counting import (
|
|
|
10
10
|
from unique_toolkit._common.validators import LMI
|
|
11
11
|
from unique_toolkit.agentic.history_manager.history_construction_with_contents import (
|
|
12
12
|
FileContentSerialization,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
get_full_history_with_contents_and_tool_calls_async,
|
|
14
|
+
get_full_history_with_contents_async,
|
|
15
15
|
)
|
|
16
16
|
from unique_toolkit.agentic.history_manager.utils import serialize_tool_content_json
|
|
17
17
|
from unique_toolkit.agentic.reference_manager.reference_manager import ReferenceManager
|
|
@@ -312,19 +312,21 @@ class LoopTokenReducer:
|
|
|
312
312
|
else FileContentSerialization.FILE_NAME
|
|
313
313
|
)
|
|
314
314
|
if self._enable_tool_call_persistence:
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
315
|
+
(
|
|
316
|
+
full_history,
|
|
317
|
+
max_src,
|
|
318
|
+
src_map,
|
|
319
|
+
) = await get_full_history_with_contents_and_tool_calls_async(
|
|
320
|
+
user_message=self._user_message,
|
|
321
|
+
chat_id=self._chat_id,
|
|
322
|
+
chat_service=self._chat_service,
|
|
323
|
+
content_service=self._content_service,
|
|
324
|
+
file_content_serialization_type=file_content_serialization_type,
|
|
323
325
|
)
|
|
324
326
|
self._max_db_source_number = max_src
|
|
325
327
|
self._db_source_map = src_map
|
|
326
328
|
else:
|
|
327
|
-
full_history =
|
|
329
|
+
full_history = await get_full_history_with_contents_async(
|
|
328
330
|
user_message=self._user_message,
|
|
329
331
|
chat_id=self._chat_id,
|
|
330
332
|
chat_service=self._chat_service,
|
|
@@ -65,7 +65,7 @@ class QwenLoopIterationRunner(BasicLoopIterationRunner):
|
|
|
65
65
|
loop_runner_kwargs=kwargs,
|
|
66
66
|
prepare_loop_runner_kwargs=_prepare,
|
|
67
67
|
)
|
|
68
|
-
return self._process_response(response)
|
|
68
|
+
return await self._process_response(response)
|
|
69
69
|
|
|
70
70
|
async def _handle_last_iteration(
|
|
71
71
|
self, **kwargs: Unpack[_LoopIterationRunnerKwargs]
|
|
@@ -78,22 +78,23 @@ class QwenLoopIterationRunner(BasicLoopIterationRunner):
|
|
|
78
78
|
last_iteration_instruction=self._last_iteration_instruction,
|
|
79
79
|
)
|
|
80
80
|
response = await super()._handle_last_iteration(**kwargs)
|
|
81
|
-
return self._process_response(response)
|
|
81
|
+
return await self._process_response(response)
|
|
82
82
|
|
|
83
83
|
async def _handle_normal_iteration(
|
|
84
84
|
self, **kwargs: Unpack[_LoopIterationRunnerKwargs]
|
|
85
85
|
) -> LanguageModelStreamResponse:
|
|
86
86
|
response = await super()._handle_normal_iteration(**kwargs)
|
|
87
|
-
return self._process_response(response)
|
|
87
|
+
return await self._process_response(response)
|
|
88
88
|
|
|
89
|
-
def _process_response(
|
|
89
|
+
async def _process_response(
|
|
90
90
|
self, response: LanguageModelStreamResponse
|
|
91
91
|
) -> LanguageModelStreamResponse:
|
|
92
|
-
|
|
92
|
+
message_text = response.message.text or ""
|
|
93
|
+
if "</tool_call>" == message_text.strip():
|
|
93
94
|
_LOGGER.warning(
|
|
94
95
|
"Response contains only <tool_call>. This is not allowed. Returning empty response."
|
|
95
96
|
)
|
|
96
|
-
self._chat_service.
|
|
97
|
+
await self._chat_service.modify_assistant_message_async(content="")
|
|
97
98
|
response.message.text = ""
|
|
98
99
|
|
|
99
100
|
return response
|
{unique_toolkit-1.68.13 → unique_toolkit-1.69.1}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py
RENAMED
|
@@ -377,7 +377,10 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
377
377
|
async def _call_mcp_tool_via_sdk(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
378
378
|
"""Call MCP tool via SDK to public API"""
|
|
379
379
|
try:
|
|
380
|
-
|
|
380
|
+
self.logger.info(
|
|
381
|
+
f"Calling MCP tool {self.name} with arguments: {arguments}"
|
|
382
|
+
)
|
|
383
|
+
result = await unique_sdk.MCP.call_tool_async(
|
|
381
384
|
user_id=self._event.user_id,
|
|
382
385
|
company_id=self._event.company_id,
|
|
383
386
|
name=self.name,
|
|
@@ -386,9 +389,6 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
386
389
|
arguments=arguments,
|
|
387
390
|
)
|
|
388
391
|
|
|
389
|
-
self.logger.info(
|
|
390
|
-
f"Calling MCP tool {self.name} with arguments: {arguments}"
|
|
391
|
-
)
|
|
392
392
|
self.logger.debug(f"Result: {result}")
|
|
393
393
|
|
|
394
394
|
return result
|
|
@@ -63,6 +63,21 @@ def build_unique_custom_app(
|
|
|
63
63
|
"""Health check endpoint."""
|
|
64
64
|
return JSONResponse(content={"status": "healthy", "service": title})
|
|
65
65
|
|
|
66
|
+
from unique_toolkit.monitoring import _MONITORING_AVAILABLE
|
|
67
|
+
|
|
68
|
+
if _MONITORING_AVAILABLE:
|
|
69
|
+
from starlette.responses import Response as StarletteResponse
|
|
70
|
+
|
|
71
|
+
from unique_toolkit.monitoring import get_metrics
|
|
72
|
+
|
|
73
|
+
@app.get(path="/metrics")
|
|
74
|
+
async def metrics_endpoint() -> StarletteResponse:
|
|
75
|
+
"""Prometheus metrics endpoint."""
|
|
76
|
+
return StarletteResponse(
|
|
77
|
+
content=get_metrics(),
|
|
78
|
+
media_type="text/plain; version=0.0.4; charset=utf-8",
|
|
79
|
+
)
|
|
80
|
+
|
|
66
81
|
@app.post(path=webhook_path)
|
|
67
82
|
async def webhook_handler(
|
|
68
83
|
request: Request, background_tasks: BackgroundTasks
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
try:
|
|
2
|
+
from prometheus_client import CollectorRegistry # noqa: F401
|
|
3
|
+
|
|
4
|
+
_MONITORING_AVAILABLE = True
|
|
5
|
+
except ImportError:
|
|
6
|
+
_MONITORING_AVAILABLE = False
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _check_monitoring_available() -> None:
|
|
10
|
+
if not _MONITORING_AVAILABLE:
|
|
11
|
+
raise ImportError(
|
|
12
|
+
"prometheus_client is not installed. "
|
|
13
|
+
"Install it with: pip install unique_toolkit[monitoring]"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if _MONITORING_AVAILABLE:
|
|
18
|
+
from unique_toolkit.monitoring.middleware import MetricsMiddleware
|
|
19
|
+
from unique_toolkit.monitoring.registry import (
|
|
20
|
+
REGISTRY,
|
|
21
|
+
MetricNamespace,
|
|
22
|
+
get_metrics,
|
|
23
|
+
metric_scope,
|
|
24
|
+
track_execution,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"REGISTRY",
|
|
29
|
+
"MetricNamespace",
|
|
30
|
+
"MetricsMiddleware",
|
|
31
|
+
"get_metrics",
|
|
32
|
+
"metric_scope",
|
|
33
|
+
"track_execution",
|
|
34
|
+
"_MONITORING_AVAILABLE",
|
|
35
|
+
]
|
|
36
|
+
else:
|
|
37
|
+
|
|
38
|
+
def __getattr__(name: str):
|
|
39
|
+
_check_monitoring_available()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from prometheus_client import Counter, Gauge, Histogram
|
|
6
|
+
|
|
7
|
+
from .registry import REGISTRY
|
|
8
|
+
|
|
9
|
+
_http_requests_total = Counter(
|
|
10
|
+
"http_requests_total",
|
|
11
|
+
"Total HTTP requests",
|
|
12
|
+
["method", "path", "status_code"],
|
|
13
|
+
registry=REGISTRY,
|
|
14
|
+
)
|
|
15
|
+
_http_request_duration_seconds = Histogram(
|
|
16
|
+
"http_request_duration_seconds",
|
|
17
|
+
"HTTP request duration",
|
|
18
|
+
["method", "path"],
|
|
19
|
+
registry=REGISTRY,
|
|
20
|
+
)
|
|
21
|
+
_http_requests_in_progress = Gauge(
|
|
22
|
+
"http_requests_in_progress",
|
|
23
|
+
"In-flight HTTP requests",
|
|
24
|
+
["method"],
|
|
25
|
+
registry=REGISTRY,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
_DEFAULT_EXCLUDED_PATHS = frozenset({"/health", "/metrics", "/"})
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class MetricsMiddleware:
|
|
32
|
+
"""ASGI middleware that tracks HTTP request metrics.
|
|
33
|
+
|
|
34
|
+
Works with any ASGI app (FastAPI, Quart, Starlette).
|
|
35
|
+
|
|
36
|
+
Handles:
|
|
37
|
+
- Non-HTTP scopes (WebSocket, lifespan) — passed through, not tracked
|
|
38
|
+
- Excluded paths (health, metrics) — passed through, not tracked
|
|
39
|
+
- App exceptions — duration + error still recorded, in-progress gauge cleaned up
|
|
40
|
+
- Streaming responses — status captured from first http.response.start message
|
|
41
|
+
|
|
42
|
+
Usage::
|
|
43
|
+
|
|
44
|
+
# FastAPI
|
|
45
|
+
app.add_middleware(MetricsMiddleware)
|
|
46
|
+
|
|
47
|
+
# Quart
|
|
48
|
+
app.asgi_app = MetricsMiddleware(app.asgi_app)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, app, excluded_paths: set[str] | None = None):
|
|
52
|
+
self.app = app
|
|
53
|
+
self._excluded_paths = (
|
|
54
|
+
excluded_paths if excluded_paths is not None else _DEFAULT_EXCLUDED_PATHS
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
async def __call__(self, scope, receive, send):
|
|
58
|
+
# Pass through non-HTTP (WebSocket, lifespan)
|
|
59
|
+
if scope["type"] != "http":
|
|
60
|
+
return await self.app(scope, receive, send)
|
|
61
|
+
|
|
62
|
+
path = scope.get("path", "/")
|
|
63
|
+
|
|
64
|
+
# Pass through excluded paths (health checks, metrics endpoint)
|
|
65
|
+
if path in self._excluded_paths:
|
|
66
|
+
return await self.app(scope, receive, send)
|
|
67
|
+
|
|
68
|
+
method = scope.get("method", "UNKNOWN")
|
|
69
|
+
status_code = "500" # Default if app crashes before sending response
|
|
70
|
+
|
|
71
|
+
_http_requests_in_progress.labels(method=method).inc()
|
|
72
|
+
start = time.perf_counter()
|
|
73
|
+
|
|
74
|
+
async def send_wrapper(message):
|
|
75
|
+
nonlocal status_code
|
|
76
|
+
if message["type"] == "http.response.start":
|
|
77
|
+
status_code = str(message["status"])
|
|
78
|
+
await send(message)
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
await self.app(scope, receive, send_wrapper)
|
|
82
|
+
finally:
|
|
83
|
+
duration = time.perf_counter() - start
|
|
84
|
+
_http_requests_in_progress.labels(method=method).dec()
|
|
85
|
+
_http_request_duration_seconds.labels(method=method, path=path).observe(
|
|
86
|
+
duration
|
|
87
|
+
)
|
|
88
|
+
_http_requests_total.labels(
|
|
89
|
+
method=method, path=path, status_code=status_code
|
|
90
|
+
).inc()
|