unique_toolkit 1.59.1__tar.gz → 1.60.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/PKG-INFO +2 -2
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/pyproject.toml +2 -2
- unique_toolkit-1.60.0/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +412 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/history_manager/history_manager.py +121 -6
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/history_manager/loop_token_reducer.py +143 -15
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/functions.py +159 -27
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/schemas.py +51 -9
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/chat_service.py +81 -7
- unique_toolkit-1.59.1/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +0 -266
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/README.md +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/_base_service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/_time_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/api_calling/human_verification_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/base_model_type_attribute.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/exception.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/README.md +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/__main__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/cli.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/differ.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/exporter.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/models.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/registry.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/validator.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/default_language_model.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/pandoc_converter.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/endpoint_builder.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/endpoint_requestor.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/event_bus.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/exception.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/execution.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/endpoint_builder.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/endpoint_requestor.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/README.md +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/agent.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/examples/data.csv +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/examples/example_usage.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/exceptions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/exceptions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/system_prompt.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/user_prompt.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/default_template.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/exceptions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/feature_flags/schema.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/pydantic/rjsf_tags.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/pydantic_helpers.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/referencing.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/string_utilities.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/tests/test_referencing.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/tests/test_string_utilities.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/image_token_counting.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/token_counting.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/tokenizers/deepseek/tokenizer.json +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/tokenizers/qwen/tokenizer.json +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/files.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/image/encode.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/helpers.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/render.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/schema.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/structured_output/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/structured_output/schema.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/write_configuration.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/validate_required_values.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/validators.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/system_prompt.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/user_prompt.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/schema.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/evaluation_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/exception.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/system_prompt.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/user_prompt.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/output_parser.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/fixtures.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_hallucination_constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_hallucination_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_output_parser.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_prompt_loaders.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/feature_flags/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/feature_flags/feature_flags.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/history_manager/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_iteration_handler_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_responses_iteration_handler_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_responses_stream_handler_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_stream_handler_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/base.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/planning/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/planning/planning.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/planning/schema.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/basic.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/mistral/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/mistral/mistral_runner.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/qwen/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/qwen/helpers.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/qwen/qwen_runner.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/message_log_manager/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/message_log_manager/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/postprocessor/postprocessor_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/reference_manager/reference_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/postprocessors/code_display.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/stream_handler.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/thinking_manager/thinking_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/display.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/references.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/prompts.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/response_watcher/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/_memory.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/_schema.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/test/test_service_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/agent_chunks_hanlder.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/factory.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/models.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/base.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/code_display.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/generated_files.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/test/test_mcp_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/tool.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/tool_manager.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/tool_progress_reporter.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/schema.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic_table/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic_table/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic_table/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/dev_util.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/fast_api_factory.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/init_logging.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/init_sdk.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/performance/async_tasks.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/performance/async_wrapper.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/unique_settings.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/verification.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/webhook.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/cancellation.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/deprecated/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/rendering.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/responses_api.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/state.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/functions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/smart_rules.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/README.md +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/augmented/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/augmented/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/base.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/config.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/prompt.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/exceptions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/functions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/functions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/langchain/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/openai/client.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/_responses_api_utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/builder.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/default_language_model.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/functions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/infos.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/prompt.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/reference.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/stream_transform.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/utils.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/protocols/support.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/factory.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/knowledge_base.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/constants.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/functions.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/schemas.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/service.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/smart_rules/__init__.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/smart_rules/compile.py +0 -0
- {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/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.60.0
|
|
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>
|
|
@@ -16,7 +16,7 @@ Requires-Dist: sseclient>=0.0.27,<0.0.28
|
|
|
16
16
|
Requires-Dist: openai>=1.105.0,<2
|
|
17
17
|
Requires-Dist: platformdirs>=4.0.0,<5
|
|
18
18
|
Requires-Dist: pillow>=12.1.1
|
|
19
|
-
Requires-Dist: unique-sdk>=0.10.
|
|
19
|
+
Requires-Dist: unique-sdk>=0.10.85,<0.11
|
|
20
20
|
Requires-Dist: jambo>=0.1.2,<0.2
|
|
21
21
|
Requires-Dist: jinja2>=3.1.6,<4
|
|
22
22
|
Requires-Dist: docxtpl>=0.20.1,<0.21
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_toolkit"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.60.0"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -28,7 +28,7 @@ dependencies = [
|
|
|
28
28
|
"openai>=1.105.0,<2",
|
|
29
29
|
"platformdirs>=4.0.0,<5",
|
|
30
30
|
"pillow>=12.1.1",
|
|
31
|
-
"unique-sdk>=0.10.
|
|
31
|
+
"unique-sdk>=0.10.85,<0.11",
|
|
32
32
|
"jambo>=0.1.2,<0.2",
|
|
33
33
|
"jinja2>=3.1.6,<4",
|
|
34
34
|
"docxtpl>=0.20.1,<0.21",
|
unique_toolkit-1.60.0/unique_toolkit/agentic/history_manager/history_construction_with_contents.py
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import logging
|
|
5
|
+
import mimetypes
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from enum import StrEnum
|
|
8
|
+
from itertools import groupby
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from pydantic import RootModel
|
|
16
|
+
|
|
17
|
+
from unique_toolkit._common.token.token_counting import (
|
|
18
|
+
num_tokens_per_language_model_message,
|
|
19
|
+
)
|
|
20
|
+
from unique_toolkit._common.utils import files as FileUtils
|
|
21
|
+
from unique_toolkit.app import ChatEventUserMessage
|
|
22
|
+
from unique_toolkit.chat.schemas import ChatMessage, ChatMessageTool
|
|
23
|
+
from unique_toolkit.chat.schemas import ChatMessageRole as ChatRole
|
|
24
|
+
from unique_toolkit.chat.service import ChatService
|
|
25
|
+
from unique_toolkit.content.schemas import Content
|
|
26
|
+
from unique_toolkit.content.service import ContentService
|
|
27
|
+
from unique_toolkit.language_model import LanguageModelMessageRole as LLMRole
|
|
28
|
+
from unique_toolkit.language_model.infos import EncoderName, LanguageModelInfo
|
|
29
|
+
from unique_toolkit.language_model.schemas import (
|
|
30
|
+
LanguageModelAssistantMessage,
|
|
31
|
+
LanguageModelFunction,
|
|
32
|
+
LanguageModelMessages,
|
|
33
|
+
LanguageModelToolMessage,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
_LOGGER = logging.getLogger(__name__)
|
|
37
|
+
|
|
38
|
+
map_chat_llm_message_role = {
|
|
39
|
+
ChatRole.USER: LLMRole.USER,
|
|
40
|
+
ChatRole.ASSISTANT: LLMRole.ASSISTANT,
|
|
41
|
+
ChatRole.SYSTEM: LLMRole.SYSTEM,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ChatMessageWithContents(ChatMessage):
|
|
46
|
+
contents: list[Content] = []
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ChatHistoryWithContent(RootModel):
|
|
50
|
+
root: list[ChatMessageWithContents]
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def from_chat_history_and_contents(
|
|
54
|
+
cls,
|
|
55
|
+
chat_history: list[ChatMessage],
|
|
56
|
+
chat_contents: list[Content],
|
|
57
|
+
):
|
|
58
|
+
combined = chat_contents + chat_history
|
|
59
|
+
combined.sort(key=lambda x: x.created_at or datetime.min)
|
|
60
|
+
|
|
61
|
+
grouped_elements = []
|
|
62
|
+
content_container = []
|
|
63
|
+
|
|
64
|
+
# Content is collected and added to the next chat message
|
|
65
|
+
for c in combined:
|
|
66
|
+
if isinstance(c, ChatMessage):
|
|
67
|
+
grouped_elements.append(
|
|
68
|
+
ChatMessageWithContents(
|
|
69
|
+
contents=content_container.copy(),
|
|
70
|
+
**c.model_dump(),
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
content_container.clear()
|
|
74
|
+
else:
|
|
75
|
+
content_container.append(c)
|
|
76
|
+
|
|
77
|
+
return cls(root=grouped_elements)
|
|
78
|
+
|
|
79
|
+
def __iter__(self):
|
|
80
|
+
return iter(self.root)
|
|
81
|
+
|
|
82
|
+
def __getitem__(self, item):
|
|
83
|
+
return self.root[item]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_chat_history_with_contents(
|
|
87
|
+
user_message: ChatEventUserMessage,
|
|
88
|
+
chat_id: str,
|
|
89
|
+
chat_history: list[ChatMessage],
|
|
90
|
+
content_service: ContentService,
|
|
91
|
+
) -> ChatHistoryWithContent:
|
|
92
|
+
last_user_message = ChatMessage(
|
|
93
|
+
id=user_message.id,
|
|
94
|
+
chat_id=chat_id,
|
|
95
|
+
text=user_message.text,
|
|
96
|
+
originalText=user_message.original_text,
|
|
97
|
+
role=ChatRole.USER,
|
|
98
|
+
gpt_request=None,
|
|
99
|
+
created_at=datetime.fromisoformat(user_message.created_at),
|
|
100
|
+
)
|
|
101
|
+
if len(chat_history) > 0 and last_user_message.id == chat_history[-1].id:
|
|
102
|
+
pass
|
|
103
|
+
else:
|
|
104
|
+
chat_history.append(last_user_message)
|
|
105
|
+
|
|
106
|
+
chat_contents = content_service.search_contents(
|
|
107
|
+
where={
|
|
108
|
+
"ownerId": {
|
|
109
|
+
"equals": chat_id,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return ChatHistoryWithContent.from_chat_history_and_contents(
|
|
115
|
+
chat_history,
|
|
116
|
+
chat_contents,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def download_encoded_images(
|
|
121
|
+
contents: list[Content],
|
|
122
|
+
content_service: ContentService,
|
|
123
|
+
chat_id: str,
|
|
124
|
+
) -> list[str]:
|
|
125
|
+
base64_encoded_images = []
|
|
126
|
+
for im in contents:
|
|
127
|
+
if FileUtils.is_image_content(im.key):
|
|
128
|
+
try:
|
|
129
|
+
file_bytes = content_service.download_content_to_bytes(
|
|
130
|
+
content_id=im.id,
|
|
131
|
+
chat_id=chat_id,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
mime_type, _ = mimetypes.guess_type(im.key)
|
|
135
|
+
encoded_string = base64.b64encode(file_bytes).decode("utf-8")
|
|
136
|
+
image_string = f"data:{mime_type};base64," + encoded_string
|
|
137
|
+
base64_encoded_images.append(image_string)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
print(e)
|
|
140
|
+
return base64_encoded_images
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class FileContentSerialization(StrEnum):
|
|
144
|
+
NONE = "none"
|
|
145
|
+
FILE_NAME = "file_name"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class ImageContentInclusion(StrEnum):
|
|
149
|
+
NONE = "none"
|
|
150
|
+
ALL = "all"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def file_content_serialization(
|
|
154
|
+
file_contents: list[Content],
|
|
155
|
+
file_content_serialization: FileContentSerialization,
|
|
156
|
+
) -> str:
|
|
157
|
+
match file_content_serialization:
|
|
158
|
+
case FileContentSerialization.NONE:
|
|
159
|
+
return ""
|
|
160
|
+
case FileContentSerialization.FILE_NAME:
|
|
161
|
+
file_names = [
|
|
162
|
+
f"- Uploaded file: {f.key} at {f.created_at}" for f in file_contents
|
|
163
|
+
]
|
|
164
|
+
return "\n".join(
|
|
165
|
+
[
|
|
166
|
+
"Files Uploaded to Chat can be accessed by internal search tool if available:\n",
|
|
167
|
+
]
|
|
168
|
+
+ file_names,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _append_element_to_builder(
|
|
173
|
+
builder: MessagesBuilder,
|
|
174
|
+
c: ChatMessageWithContents,
|
|
175
|
+
text: str,
|
|
176
|
+
include_images: ImageContentInclusion,
|
|
177
|
+
file_content_serialization_type: FileContentSerialization,
|
|
178
|
+
content_service: ContentService,
|
|
179
|
+
chat_id: str,
|
|
180
|
+
) -> None:
|
|
181
|
+
if len(c.contents) > 0:
|
|
182
|
+
file_contents = [co for co in c.contents if FileUtils.is_file_content(co.key)]
|
|
183
|
+
image_contents = [co for co in c.contents if FileUtils.is_image_content(co.key)]
|
|
184
|
+
content = (
|
|
185
|
+
text
|
|
186
|
+
+ "\n\n"
|
|
187
|
+
+ file_content_serialization(
|
|
188
|
+
file_contents,
|
|
189
|
+
file_content_serialization_type,
|
|
190
|
+
)
|
|
191
|
+
).strip()
|
|
192
|
+
if include_images and len(image_contents) > 0:
|
|
193
|
+
builder.image_message_append(
|
|
194
|
+
content=content,
|
|
195
|
+
images=download_encoded_images(
|
|
196
|
+
contents=image_contents,
|
|
197
|
+
content_service=content_service,
|
|
198
|
+
chat_id=chat_id,
|
|
199
|
+
),
|
|
200
|
+
role=map_chat_llm_message_role[c.role],
|
|
201
|
+
)
|
|
202
|
+
else:
|
|
203
|
+
builder.message_append(
|
|
204
|
+
role=map_chat_llm_message_role[c.role],
|
|
205
|
+
content=content,
|
|
206
|
+
)
|
|
207
|
+
else:
|
|
208
|
+
builder.message_append(
|
|
209
|
+
role=map_chat_llm_message_role[c.role],
|
|
210
|
+
content=text,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def get_full_history_with_contents(
|
|
215
|
+
user_message: ChatEventUserMessage,
|
|
216
|
+
chat_id: str,
|
|
217
|
+
chat_service: ChatService,
|
|
218
|
+
content_service: ContentService,
|
|
219
|
+
include_images: ImageContentInclusion = ImageContentInclusion.ALL,
|
|
220
|
+
file_content_serialization_type: FileContentSerialization = FileContentSerialization.FILE_NAME,
|
|
221
|
+
) -> LanguageModelMessages:
|
|
222
|
+
grouped_elements = get_chat_history_with_contents(
|
|
223
|
+
user_message=user_message,
|
|
224
|
+
chat_id=chat_id,
|
|
225
|
+
chat_history=chat_service.get_full_history(),
|
|
226
|
+
content_service=content_service,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
builder = LanguageModelMessages([]).builder()
|
|
230
|
+
for c in grouped_elements:
|
|
231
|
+
# LanguageModelUserMessage has no field original_text
|
|
232
|
+
text = c.original_text if c.original_text else c.content
|
|
233
|
+
if text is None:
|
|
234
|
+
if c.role == ChatRole.USER:
|
|
235
|
+
raise ValueError(
|
|
236
|
+
"Content or original_text of LanguageModelMessages should exist.",
|
|
237
|
+
)
|
|
238
|
+
text = ""
|
|
239
|
+
_append_element_to_builder(
|
|
240
|
+
builder=builder,
|
|
241
|
+
c=c,
|
|
242
|
+
text=text,
|
|
243
|
+
include_images=include_images,
|
|
244
|
+
file_content_serialization_type=file_content_serialization_type,
|
|
245
|
+
content_service=content_service,
|
|
246
|
+
chat_id=chat_id,
|
|
247
|
+
)
|
|
248
|
+
return builder.build()
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def get_full_history_with_contents_and_tool_calls(
|
|
252
|
+
*,
|
|
253
|
+
user_message: ChatEventUserMessage,
|
|
254
|
+
chat_id: str,
|
|
255
|
+
chat_service: ChatService,
|
|
256
|
+
content_service: ContentService,
|
|
257
|
+
include_images: ImageContentInclusion = ImageContentInclusion.ALL,
|
|
258
|
+
file_content_serialization_type: FileContentSerialization = FileContentSerialization.FILE_NAME,
|
|
259
|
+
) -> LanguageModelMessages:
|
|
260
|
+
"""Build the full LLM message history, including persisted tool call rounds."""
|
|
261
|
+
chat_history = chat_service.get_full_history()
|
|
262
|
+
|
|
263
|
+
assistant_message_ids = [
|
|
264
|
+
msg.id for msg in chat_history if msg.role == ChatRole.ASSISTANT and msg.id
|
|
265
|
+
]
|
|
266
|
+
tool_calls_by_message: dict[str, list[ChatMessageTool]] = {}
|
|
267
|
+
if assistant_message_ids:
|
|
268
|
+
try:
|
|
269
|
+
all_tool_calls = chat_service.get_message_tools(
|
|
270
|
+
message_ids=assistant_message_ids,
|
|
271
|
+
)
|
|
272
|
+
for tc in all_tool_calls:
|
|
273
|
+
if tc.message_id:
|
|
274
|
+
tool_calls_by_message.setdefault(tc.message_id, []).append(tc)
|
|
275
|
+
except Exception:
|
|
276
|
+
_LOGGER.warning(
|
|
277
|
+
"Failed to batch-load tool calls, falling back to empty", exc_info=True
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
grouped_elements = get_chat_history_with_contents(
|
|
281
|
+
user_message=user_message,
|
|
282
|
+
chat_id=chat_id,
|
|
283
|
+
chat_history=chat_history,
|
|
284
|
+
content_service=content_service,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
builder = LanguageModelMessages([]).builder()
|
|
288
|
+
for c in grouped_elements:
|
|
289
|
+
text = c.original_text if c.original_text else c.content
|
|
290
|
+
if text is None:
|
|
291
|
+
if c.role == ChatRole.USER:
|
|
292
|
+
raise ValueError(
|
|
293
|
+
"Content or original_text of LanguageModelMessages should exist.",
|
|
294
|
+
)
|
|
295
|
+
text = ""
|
|
296
|
+
|
|
297
|
+
if c.role == ChatRole.ASSISTANT and c.id and c.id in tool_calls_by_message:
|
|
298
|
+
tc_records = sorted(
|
|
299
|
+
tool_calls_by_message[c.id],
|
|
300
|
+
key=lambda tc: (tc.round_index, tc.sequence_index),
|
|
301
|
+
)
|
|
302
|
+
if tc_records:
|
|
303
|
+
for _round, round_group in groupby(
|
|
304
|
+
tc_records, key=lambda tc: tc.round_index
|
|
305
|
+
):
|
|
306
|
+
round_tcs = list(round_group)
|
|
307
|
+
# Only include tool calls that have a response; without a
|
|
308
|
+
# matching LanguageModelToolMessage the assistant message
|
|
309
|
+
# would reference a tool_call_id that never gets a reply,
|
|
310
|
+
# which LLM APIs (e.g. OpenAI) reject.
|
|
311
|
+
round_tcs_with_response = [
|
|
312
|
+
tc
|
|
313
|
+
for tc in round_tcs
|
|
314
|
+
if tc.response and tc.response.content is not None
|
|
315
|
+
]
|
|
316
|
+
if not round_tcs_with_response:
|
|
317
|
+
continue
|
|
318
|
+
# Build LanguageModelFunction objects first so we can read
|
|
319
|
+
# back the post-validator id: the randomize_id validator
|
|
320
|
+
# replaces an empty string with a UUID, and we must use
|
|
321
|
+
# the same id in the LanguageModelToolMessage so the
|
|
322
|
+
# tool_call_id references match.
|
|
323
|
+
fns = [
|
|
324
|
+
LanguageModelFunction(
|
|
325
|
+
id=tc.external_tool_call_id,
|
|
326
|
+
name=tc.function_name,
|
|
327
|
+
arguments=tc.arguments,
|
|
328
|
+
)
|
|
329
|
+
for tc in round_tcs_with_response
|
|
330
|
+
]
|
|
331
|
+
builder.messages.append(
|
|
332
|
+
LanguageModelAssistantMessage.from_functions(tool_calls=fns)
|
|
333
|
+
)
|
|
334
|
+
for fn, tc in zip(fns, round_tcs_with_response):
|
|
335
|
+
builder.messages.append(
|
|
336
|
+
LanguageModelToolMessage(
|
|
337
|
+
tool_call_id=fn.id,
|
|
338
|
+
content=tc.response.content, # type: ignore[union-attr]
|
|
339
|
+
name=tc.function_name,
|
|
340
|
+
)
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# Drop empty assistant messages that had tool calls.
|
|
344
|
+
# When a turn consists only of tool-call rounds (e.g. the loop was
|
|
345
|
+
# cancelled before producing a final prose response), the DB message
|
|
346
|
+
# ends up with text == "". The full turn is already captured by the
|
|
347
|
+
# interleaved ASSISTANT(tool_calls) + TOOL messages emitted above, so
|
|
348
|
+
# appending an empty ASSISTANT message here would waste tokens and can
|
|
349
|
+
# be misread by LLM APIs as a conversation boundary.
|
|
350
|
+
# Note: get_full_history_with_contents does NOT drop this message — it
|
|
351
|
+
# has no tool-call context and treats the empty message as benign.
|
|
352
|
+
had_tool_calls = (
|
|
353
|
+
c.role == ChatRole.ASSISTANT
|
|
354
|
+
and c.id is not None
|
|
355
|
+
and c.id in tool_calls_by_message
|
|
356
|
+
)
|
|
357
|
+
if had_tool_calls and not text:
|
|
358
|
+
continue
|
|
359
|
+
|
|
360
|
+
_append_element_to_builder(
|
|
361
|
+
builder=builder,
|
|
362
|
+
c=c,
|
|
363
|
+
text=text,
|
|
364
|
+
include_images=include_images,
|
|
365
|
+
file_content_serialization_type=file_content_serialization_type,
|
|
366
|
+
content_service=content_service,
|
|
367
|
+
chat_id=chat_id,
|
|
368
|
+
)
|
|
369
|
+
return builder.build()
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def get_full_history_as_llm_messages(
|
|
373
|
+
chat_service: ChatService,
|
|
374
|
+
) -> LanguageModelMessages:
|
|
375
|
+
chat_history = chat_service.get_full_history()
|
|
376
|
+
|
|
377
|
+
map_chat_llm_message_role = {
|
|
378
|
+
ChatRole.USER: LLMRole.USER,
|
|
379
|
+
ChatRole.ASSISTANT: LLMRole.ASSISTANT,
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
builder = LanguageModelMessages([]).builder()
|
|
383
|
+
for c in chat_history:
|
|
384
|
+
builder.message_append(
|
|
385
|
+
role=map_chat_llm_message_role[c.role],
|
|
386
|
+
content=c.content or "",
|
|
387
|
+
)
|
|
388
|
+
return builder.build()
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def limit_to_token_window(
|
|
392
|
+
messages: LanguageModelMessages,
|
|
393
|
+
token_limit: int,
|
|
394
|
+
model_info: LanguageModelInfo | None = None,
|
|
395
|
+
encoding_name: EncoderName = EncoderName.O200K_BASE,
|
|
396
|
+
) -> LanguageModelMessages:
|
|
397
|
+
if model_info is not None:
|
|
398
|
+
encode = model_info.get_encoder()
|
|
399
|
+
else:
|
|
400
|
+
encode = encoding_name.get_encoder()
|
|
401
|
+
|
|
402
|
+
token_per_message_reversed = num_tokens_per_language_model_message(
|
|
403
|
+
messages,
|
|
404
|
+
encode=encode,
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
to_take: list[bool] = (np.cumsum(token_per_message_reversed) < token_limit).tolist()
|
|
408
|
+
to_take.reverse()
|
|
409
|
+
|
|
410
|
+
return LanguageModelMessages(
|
|
411
|
+
root=[m for m, tt in zip(messages, to_take, strict=False) if tt],
|
|
412
|
+
)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
1
3
|
from logging import Logger
|
|
2
4
|
from typing import Annotated, Awaitable, Callable
|
|
3
5
|
|
|
@@ -13,6 +15,7 @@ from unique_toolkit.agentic.reference_manager.reference_manager import Reference
|
|
|
13
15
|
from unique_toolkit.agentic.tools.config import get_configuration_dict
|
|
14
16
|
from unique_toolkit.agentic.tools.schemas import ToolCallResponse
|
|
15
17
|
from unique_toolkit.app.schemas import ChatEvent
|
|
18
|
+
from unique_toolkit.chat.schemas import ChatMessageTool, ChatMessageToolResponse
|
|
16
19
|
from unique_toolkit.language_model.default_language_model import DEFAULT_GPT_4o
|
|
17
20
|
from unique_toolkit.language_model.infos import LanguageModelInfo
|
|
18
21
|
from unique_toolkit.language_model.schemas import (
|
|
@@ -61,6 +64,13 @@ class HistoryManagerConfig(BaseModel):
|
|
|
61
64
|
description="The fraction of the max input tokens that will be reserved for the history.",
|
|
62
65
|
)
|
|
63
66
|
|
|
67
|
+
percent_for_tool_call_history: float = Field(
|
|
68
|
+
default=0.0,
|
|
69
|
+
ge=0.0,
|
|
70
|
+
lt=1.0,
|
|
71
|
+
description="The fraction of the max input tokens reserved for tool call rounds. 0 disables.",
|
|
72
|
+
)
|
|
73
|
+
|
|
64
74
|
language_model: LMI = LanguageModelInfo.from_name(DEFAULT_GPT_4o)
|
|
65
75
|
|
|
66
76
|
@property
|
|
@@ -70,6 +80,13 @@ class HistoryManagerConfig(BaseModel):
|
|
|
70
80
|
* self.percent_of_max_tokens_for_history,
|
|
71
81
|
)
|
|
72
82
|
|
|
83
|
+
@property
|
|
84
|
+
def max_tool_call_history_tokens(self) -> int:
|
|
85
|
+
return int(
|
|
86
|
+
self.language_model.token_limits.token_limit_input
|
|
87
|
+
* self.percent_for_tool_call_history,
|
|
88
|
+
)
|
|
89
|
+
|
|
73
90
|
uploaded_content_config: (
|
|
74
91
|
Annotated[
|
|
75
92
|
UploadedContentConfig,
|
|
@@ -118,14 +135,13 @@ class HistoryManager:
|
|
|
118
135
|
has_uploaded_content_config=bool(self._config.uploaded_content_config),
|
|
119
136
|
language_model=self._language_model,
|
|
120
137
|
reference_manager=reference_manager,
|
|
138
|
+
max_tokens_for_tool_call_history=self._config.max_tool_call_history_tokens,
|
|
121
139
|
)
|
|
122
140
|
self._tool_call_result_history: list[ToolCallResponse] = []
|
|
123
141
|
self._tool_calls: list[LanguageModelFunction] = []
|
|
124
142
|
self._loop_history: list[LanguageModelMessage] = []
|
|
125
143
|
self._source_enumerator = 0
|
|
126
|
-
self._collected_tool_response_image_urls: list[
|
|
127
|
-
tuple[str, str]
|
|
128
|
-
] = [] # (url, tool_call_id)
|
|
144
|
+
self._collected_tool_response_image_urls: list[tuple[str, str]] = []
|
|
129
145
|
|
|
130
146
|
def add_tool_call(self, tool_call: LanguageModelFunction) -> None:
|
|
131
147
|
self._tool_calls.append(tool_call)
|
|
@@ -191,9 +207,7 @@ class HistoryManager:
|
|
|
191
207
|
if tool_response.system_reminder:
|
|
192
208
|
content += f"\n\n{tool_response.system_reminder}"
|
|
193
209
|
|
|
194
|
-
#
|
|
195
|
-
# Tool result images are attached to the user message so the model sees them. This is the only way to get the images from tool to the model as of 17.2.26.
|
|
196
|
-
|
|
210
|
+
# Append the result to the history
|
|
197
211
|
return LanguageModelToolMessage(
|
|
198
212
|
content=content,
|
|
199
213
|
tool_call_id=tool_response.id, # type: ignore
|
|
@@ -252,3 +266,104 @@ class HistoryManager:
|
|
|
252
266
|
LanguageModelAssistantMessage(content=assistant_message_text)
|
|
253
267
|
)
|
|
254
268
|
return LanguageModelMessages(history)
|
|
269
|
+
|
|
270
|
+
def extract_message_tools(self) -> list[ChatMessageTool]:
|
|
271
|
+
"""Convert the in-memory loop history into persistable ChatMessageTool records."""
|
|
272
|
+
records: list[ChatMessageTool] = []
|
|
273
|
+
round_index = 0
|
|
274
|
+
i = 0
|
|
275
|
+
while i < len(self._loop_history):
|
|
276
|
+
msg = self._loop_history[i]
|
|
277
|
+
if isinstance(msg, LanguageModelAssistantMessage) and msg.tool_calls:
|
|
278
|
+
for seq_index, tc in enumerate(msg.tool_calls):
|
|
279
|
+
response_content = None
|
|
280
|
+
for j in range(i + 1, len(self._loop_history)):
|
|
281
|
+
candidate = self._loop_history[j]
|
|
282
|
+
if (
|
|
283
|
+
isinstance(candidate, LanguageModelToolMessage)
|
|
284
|
+
and candidate.tool_call_id == tc.id
|
|
285
|
+
):
|
|
286
|
+
response_content = (
|
|
287
|
+
candidate.content
|
|
288
|
+
if isinstance(candidate.content, str)
|
|
289
|
+
else None
|
|
290
|
+
)
|
|
291
|
+
break
|
|
292
|
+
|
|
293
|
+
response = (
|
|
294
|
+
ChatMessageToolResponse(content=response_content)
|
|
295
|
+
if response_content is not None
|
|
296
|
+
else None
|
|
297
|
+
)
|
|
298
|
+
records.append(
|
|
299
|
+
ChatMessageTool(
|
|
300
|
+
external_tool_call_id=tc.id or "",
|
|
301
|
+
function_name=tc.function.name,
|
|
302
|
+
arguments=tc.function.arguments,
|
|
303
|
+
round_index=round_index,
|
|
304
|
+
sequence_index=seq_index,
|
|
305
|
+
response=response,
|
|
306
|
+
)
|
|
307
|
+
)
|
|
308
|
+
round_index += 1
|
|
309
|
+
i += 1
|
|
310
|
+
return records
|
|
311
|
+
|
|
312
|
+
@staticmethod
|
|
313
|
+
def compact_message_tools(
|
|
314
|
+
*,
|
|
315
|
+
records: list[ChatMessageTool],
|
|
316
|
+
assistant_text: str | None,
|
|
317
|
+
) -> list[ChatMessageTool]:
|
|
318
|
+
"""Strip uncited source items from tool response content before persistence."""
|
|
319
|
+
if not assistant_text:
|
|
320
|
+
return records
|
|
321
|
+
|
|
322
|
+
cited: set[int] = {
|
|
323
|
+
int(m)
|
|
324
|
+
for m in re.findall(r"\[source(\d+)\]", assistant_text, re.IGNORECASE)
|
|
325
|
+
}
|
|
326
|
+
if not cited:
|
|
327
|
+
return records
|
|
328
|
+
|
|
329
|
+
return [
|
|
330
|
+
record.model_copy(
|
|
331
|
+
update={
|
|
332
|
+
"response": record.response.model_copy(
|
|
333
|
+
update={
|
|
334
|
+
"content": _strip_uncited_sources_from_content(
|
|
335
|
+
record.response.content, cited
|
|
336
|
+
)
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
if record.response and record.response.content
|
|
342
|
+
else record
|
|
343
|
+
for record in records
|
|
344
|
+
]
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _strip_uncited_sources_from_content(content: str, cited: set[int]) -> str:
|
|
348
|
+
"""Filter a tool response content string to only keep cited source items.
|
|
349
|
+
|
|
350
|
+
The content is expected to be a JSON array of
|
|
351
|
+
``{"source_number": N, "content": "..."}`` dicts. Items whose
|
|
352
|
+
``source_number`` is not in *cited* are removed. If the content is
|
|
353
|
+
not in the expected JSON format it is returned unchanged.
|
|
354
|
+
"""
|
|
355
|
+
try:
|
|
356
|
+
data = json.loads(content)
|
|
357
|
+
except (json.JSONDecodeError, TypeError):
|
|
358
|
+
return content
|
|
359
|
+
|
|
360
|
+
if not isinstance(data, list):
|
|
361
|
+
return content
|
|
362
|
+
|
|
363
|
+
if not data or not any(
|
|
364
|
+
isinstance(item, dict) and "source_number" in item for item in data
|
|
365
|
+
):
|
|
366
|
+
return content
|
|
367
|
+
|
|
368
|
+
filtered = [item for item in data if item.get("source_number") in cited]
|
|
369
|
+
return json.dumps(filtered)
|