iatoolkit 2.4.0__tar.gz → 2.5.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.
- {iatoolkit-2.4.0/src/iatoolkit.egg-info → iatoolkit-2.5.0}/PKG-INFO +2 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/pyproject.toml +1 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/requirements.txt +1 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/__init__.py +1 -1
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/html_structures.prompt +1 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/config/system_prompts_pack.yaml +0 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/core.py +2 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_proxy.py +35 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/locales/en.yaml +10 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/locales/es.yaml +10 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/configuration_service.py +180 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/knowledge_base_service.py +17 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/llm_client_service.py +51 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/prompt_service.py +10 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/query_service.py +54 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/system_prompt_catalog.py +6 -2
- iatoolkit-2.5.0/src/iatoolkit/services/telemetry_service.py +418 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/rag_api_view.py +73 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0/src/iatoolkit.egg-info}/PKG-INFO +2 -1
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit.egg-info/SOURCES.txt +20 -19
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit.egg-info/requires.txt +1 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/LICENSE +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/LICENSE_COMMUNITY.md +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/readme.md +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/setup.cfg +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/base_company.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/cli_commands.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/exceptions.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/memory_lint_trigger.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/model_registry.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/routes.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/secret_resolver.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/session_manager.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/common/util.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/company_registry.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/config/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/chat_state_rules.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/chat_user_profile.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/core_identity.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/email_output.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/file_download_output.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/format_styles.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/links_documents.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/memory_usage.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/multimodal_basics.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/output_basics.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/presentation_formatting.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/query_main.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/sql_aggregation_scope.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/sql_casting.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/sql_core.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/sql_jsonb.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/sql_rules.prompt +0 -0
- {iatoolkit-2.4.0/src/iatoolkit → iatoolkit-2.5.0/src/iatoolkit/config}/system_prompts/tool_html_passthrough.prompt +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/call_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/inference_handler.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/llm_response.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/database_manager.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/document_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/memory_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/models.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/api_key_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/auth_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/benchmark_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/branding_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/company_context_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/context_builder_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/embedding_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/excel_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/file_processor_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/history_manager_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/http_tool_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/i18n_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/inference_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/jwt_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/language_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/license_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/mail_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/memory_compiler_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/memory_lint_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/memory_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/memory_wiki_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/noop_memory_lint_trigger.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/parsers/validator.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/pdf_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/profile_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/sql_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/sql_source_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/storage_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/structured_output_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/system_tools.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/tool_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/warmup_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/services/web_search_service.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_main.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/styles/documents.css +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/system_prompts/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/_company_header.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/_login_widget.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/base.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/change_password.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/chat.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/chat_modals.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/error.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/forgot_password.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/pdf/base.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/pdf/report.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/templates/signup.html +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/__init__.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/base_login_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/categories_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/change_password_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/chat_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/history_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/home_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/login_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/logout_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/memory_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/profile_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/signup_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/static_page_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/tool_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/users_api_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit/views/verify_user_view.py +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
- {iatoolkit-2.4.0 → iatoolkit-2.5.0}/src/iatoolkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iatoolkit
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: IAToolkit
|
|
5
5
|
Author: Fernando Libedinsky
|
|
6
6
|
License-Expression: MIT
|
|
@@ -12,6 +12,7 @@ Requires-Dist: bcrypt==4.2.1
|
|
|
12
12
|
Requires-Dist: anthropic>=0.83.0
|
|
13
13
|
Requires-Dist: boto3==1.36.22
|
|
14
14
|
Requires-Dist: botocore==1.36.22
|
|
15
|
+
Requires-Dist: braintrust>=0.17.0
|
|
15
16
|
Requires-Dist: build==1.2.2.post1
|
|
16
17
|
Requires-Dist: click==8.1.8
|
|
17
18
|
Requires-Dist: cryptography==44.0.3
|
|
@@ -29,4 +29,4 @@ version = { attr = "iatoolkit.__version__" }
|
|
|
29
29
|
dependencies = { file = ["requirements.txt"] }
|
|
30
30
|
|
|
31
31
|
[tool.setuptools.package-data]
|
|
32
|
-
iatoolkit = ["
|
|
32
|
+
iatoolkit = ["templates/**/*", "static/**/*", "locales/*.yaml", "config/*.yaml", "config/system_prompts/*.prompt"]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
### HTML estructurado
|
|
2
2
|
|
|
3
3
|
#### Tablas
|
|
4
|
-
- Usa como base `table table-striped table-hover
|
|
4
|
+
- Usa como base `table table-striped table-hover` de Bootstrap como mínimo.
|
|
5
5
|
- Si una columna contiene RUT, fecha, id certificado o valores similares, usa
|
|
6
6
|
clase `nowrap` en el `<th>` y en el `<td>` correspondiente cuando aplique.
|
|
7
7
|
- Si una columna debe ir centrada o alineada a la derecha, agrega
|
|
@@ -402,6 +402,7 @@ class IAToolkit:
|
|
|
402
402
|
from iatoolkit.services.i18n_service import I18nService
|
|
403
403
|
from iatoolkit.services.language_service import LanguageService
|
|
404
404
|
from iatoolkit.services.configuration_service import ConfigurationService
|
|
405
|
+
from iatoolkit.services.telemetry_service import TelemetryService
|
|
405
406
|
from iatoolkit.services.embedding_service import EmbeddingService
|
|
406
407
|
from iatoolkit.services.history_manager_service import HistoryManagerService
|
|
407
408
|
from iatoolkit.services.tool_service import ToolService
|
|
@@ -443,6 +444,7 @@ class IAToolkit:
|
|
|
443
444
|
binder.bind(I18nService, to=I18nService)
|
|
444
445
|
binder.bind(LanguageService, to=LanguageService)
|
|
445
446
|
binder.bind(ConfigurationService, to=ConfigurationService)
|
|
447
|
+
binder.bind(TelemetryService, to=TelemetryService)
|
|
446
448
|
binder.bind(EmbeddingService, to=EmbeddingService)
|
|
447
449
|
binder.bind(HistoryManagerService, to=HistoryManagerService)
|
|
448
450
|
binder.bind(ToolService, to=ToolService)
|
|
@@ -86,6 +86,7 @@ class LLMProxy:
|
|
|
86
86
|
company_short_name=company_short_name,
|
|
87
87
|
model=model,
|
|
88
88
|
)
|
|
89
|
+
model_config = self.configuration_service.get_llm_model_config(company_short_name, model) or {}
|
|
89
90
|
provider_config = self.configuration_service.get_llm_provider_config(company_short_name, provider) or {}
|
|
90
91
|
|
|
91
92
|
adapter = self._get_or_create_adapter(
|
|
@@ -98,6 +99,11 @@ class LLMProxy:
|
|
|
98
99
|
provider_config=provider_config,
|
|
99
100
|
request_kwargs=kwargs,
|
|
100
101
|
)
|
|
102
|
+
request_kwargs = self._apply_model_request_overrides(
|
|
103
|
+
provider=provider,
|
|
104
|
+
model_config=model_config,
|
|
105
|
+
request_kwargs=request_kwargs,
|
|
106
|
+
)
|
|
101
107
|
|
|
102
108
|
# Delegate to the adapter (OpenAI, Gemini, DeepSeek, xAI, Anthropic, etc.)
|
|
103
109
|
return adapter.create_response(model=model, input=input, **request_kwargs)
|
|
@@ -218,6 +224,35 @@ class LLMProxy:
|
|
|
218
224
|
|
|
219
225
|
return effective_kwargs
|
|
220
226
|
|
|
227
|
+
def _apply_model_request_overrides(
|
|
228
|
+
self,
|
|
229
|
+
provider: str,
|
|
230
|
+
model_config: Dict[str, Any],
|
|
231
|
+
request_kwargs: Dict[str, Any],
|
|
232
|
+
) -> Dict[str, Any]:
|
|
233
|
+
effective_kwargs = dict(request_kwargs or {})
|
|
234
|
+
|
|
235
|
+
if provider != self.PROVIDER_OPENROUTER or not isinstance(model_config, dict):
|
|
236
|
+
return effective_kwargs
|
|
237
|
+
|
|
238
|
+
model_runtime_config = model_config.get("config")
|
|
239
|
+
if not isinstance(model_runtime_config, dict):
|
|
240
|
+
return effective_kwargs
|
|
241
|
+
|
|
242
|
+
openrouter_provider = model_runtime_config.get("routing")
|
|
243
|
+
if not isinstance(openrouter_provider, dict) or not openrouter_provider:
|
|
244
|
+
return effective_kwargs
|
|
245
|
+
|
|
246
|
+
existing_provider = effective_kwargs.get("provider")
|
|
247
|
+
if isinstance(existing_provider, dict):
|
|
248
|
+
merged_provider = dict(openrouter_provider)
|
|
249
|
+
merged_provider.update(existing_provider)
|
|
250
|
+
effective_kwargs["provider"] = merged_provider
|
|
251
|
+
elif existing_provider is None:
|
|
252
|
+
effective_kwargs["provider"] = dict(openrouter_provider)
|
|
253
|
+
|
|
254
|
+
return effective_kwargs
|
|
255
|
+
|
|
221
256
|
# -------------------------------------------------------------------------
|
|
222
257
|
# Client cache
|
|
223
258
|
# -------------------------------------------------------------------------
|
|
@@ -69,6 +69,11 @@ ui:
|
|
|
69
69
|
primary_input: "Primary Input"
|
|
70
70
|
prompt_args: "Prompt Arguments (Client Data)"
|
|
71
71
|
llm_output: "LLM Output (Raw JSON)"
|
|
72
|
+
telemetry_label: "Telemetry"
|
|
73
|
+
telemetry_open_trace: "Open Trace"
|
|
74
|
+
telemetry_not_recorded: "Not recorded"
|
|
75
|
+
telemetry_disabled: "Disabled"
|
|
76
|
+
telemetry_unknown_provider: "unknown provider"
|
|
72
77
|
|
|
73
78
|
login_widget:
|
|
74
79
|
title: "Sign In"
|
|
@@ -1041,6 +1046,8 @@ ui:
|
|
|
1041
1046
|
store_response_default: "Provider default"
|
|
1042
1047
|
store_response_true: "Yes"
|
|
1043
1048
|
store_response_false: "No"
|
|
1049
|
+
telemetry_enabled_label: "LLM Telemetry"
|
|
1050
|
+
telemetry_enabled_help: "Send this agent's LLM runs to the company telemetry backend when telemetry is enabled in company configuration."
|
|
1044
1051
|
tools_title: "Tool Selection"
|
|
1045
1052
|
tools_mode_label: "Tools Mode"
|
|
1046
1053
|
tools_mode_inherit: "Automatic"
|
|
@@ -1286,6 +1293,9 @@ ui:
|
|
|
1286
1293
|
status_failed: "Failed"
|
|
1287
1294
|
created_at: "Created"
|
|
1288
1295
|
date_range: "Date range"
|
|
1296
|
+
metadata_field: "Metadata field"
|
|
1297
|
+
metadata_value: "Metadata value"
|
|
1298
|
+
select_metadata_field: "Select a field"
|
|
1289
1299
|
delete_confirmation: "Delete File?"
|
|
1290
1300
|
delete_message: "This action cannot be undone. The file will be permanently removed."
|
|
1291
1301
|
delete_button: "Delete"
|
|
@@ -70,6 +70,11 @@ ui:
|
|
|
70
70
|
primary_input: "Entrada Principal"
|
|
71
71
|
prompt_args: "Argumentos del Prompt (Client Data)"
|
|
72
72
|
llm_output: "Salida LLM (JSON Crudo)"
|
|
73
|
+
telemetry_label: "Telemetría"
|
|
74
|
+
telemetry_open_trace: "Abrir traza"
|
|
75
|
+
telemetry_not_recorded: "No registrada"
|
|
76
|
+
telemetry_disabled: "Deshabilitada"
|
|
77
|
+
telemetry_unknown_provider: "provider desconocido"
|
|
73
78
|
|
|
74
79
|
|
|
75
80
|
login_widget:
|
|
@@ -1044,6 +1049,8 @@ ui:
|
|
|
1044
1049
|
store_response_default: "Por defecto del provider"
|
|
1045
1050
|
store_response_true: "Sí"
|
|
1046
1051
|
store_response_false: "No"
|
|
1052
|
+
telemetry_enabled_label: "Telemetría LLM"
|
|
1053
|
+
telemetry_enabled_help: "Envía las ejecuciones LLM de este agente al backend de telemetría de la empresa cuando la telemetría esté habilitada en la configuración de la compañía."
|
|
1047
1054
|
tools_title: "Selección de Tools"
|
|
1048
1055
|
tools_mode_label: "Modo de Tools"
|
|
1049
1056
|
tools_mode_inherit: "Automático"
|
|
@@ -1290,6 +1297,9 @@ ui:
|
|
|
1290
1297
|
status_failed: "Fallido"
|
|
1291
1298
|
created_at: "Creado"
|
|
1292
1299
|
date_range: "Rango de fechas"
|
|
1300
|
+
metadata_field: "Campo metadata"
|
|
1301
|
+
metadata_value: "Valor metadata"
|
|
1302
|
+
select_metadata_field: "Selecciona un campo"
|
|
1293
1303
|
delete_confirmation: "¿Eliminar archivo?"
|
|
1294
1304
|
delete_message: "Esta acción no se puede deshacer. El archivo se eliminará permanentemente."
|
|
1295
1305
|
delete_button: "Eliminar"
|
|
@@ -52,6 +52,49 @@ class ConfigurationService:
|
|
|
52
52
|
return {}
|
|
53
53
|
return {"id": model_id}
|
|
54
54
|
|
|
55
|
+
@staticmethod
|
|
56
|
+
def _validate_openrouter_provider_preferences(add_error, section: str, provider_cfg) -> None:
|
|
57
|
+
if not isinstance(provider_cfg, dict):
|
|
58
|
+
add_error(section, "Must be a dictionary.")
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
for list_key in ("order", "only", "ignore"):
|
|
62
|
+
if list_key not in provider_cfg:
|
|
63
|
+
continue
|
|
64
|
+
raw_value = provider_cfg.get(list_key)
|
|
65
|
+
if not isinstance(raw_value, list) or any(not isinstance(item, str) or not item.strip() for item in raw_value):
|
|
66
|
+
add_error(f"{section}.{list_key}", "Must be a list of non-empty strings.")
|
|
67
|
+
|
|
68
|
+
for bool_key in ("allow_fallbacks", "require_parameters", "zdr"):
|
|
69
|
+
if bool_key in provider_cfg and not isinstance(provider_cfg.get(bool_key), bool):
|
|
70
|
+
add_error(f"{section}.{bool_key}", "Must be a boolean.")
|
|
71
|
+
|
|
72
|
+
if "data_collection" in provider_cfg:
|
|
73
|
+
data_collection = str(provider_cfg.get("data_collection") or "").strip().lower()
|
|
74
|
+
if data_collection not in {"allow", "deny"}:
|
|
75
|
+
add_error(f"{section}.data_collection", "Must be 'allow' or 'deny'.")
|
|
76
|
+
|
|
77
|
+
if "sort" in provider_cfg:
|
|
78
|
+
sort_value = provider_cfg.get("sort")
|
|
79
|
+
if isinstance(sort_value, str):
|
|
80
|
+
if sort_value.strip().lower() not in {"price", "throughput", "latency"}:
|
|
81
|
+
add_error(
|
|
82
|
+
f"{section}.sort",
|
|
83
|
+
"Must be one of: ['latency', 'price', 'throughput'], or a dictionary."
|
|
84
|
+
)
|
|
85
|
+
elif isinstance(sort_value, dict):
|
|
86
|
+
sort_by = str(sort_value.get("by") or "").strip().lower()
|
|
87
|
+
if sort_by and sort_by not in {"price", "throughput", "latency"}:
|
|
88
|
+
add_error(f"{section}.sort.by", "Must be one of: ['latency', 'price', 'throughput'].")
|
|
89
|
+
partition = sort_value.get("partition")
|
|
90
|
+
if partition is not None and str(partition).strip().lower() not in {"provider", "model", "none"}:
|
|
91
|
+
add_error(f"{section}.sort.partition", "Must be one of: ['model', 'none', 'provider'].")
|
|
92
|
+
else:
|
|
93
|
+
add_error(
|
|
94
|
+
f"{section}.sort",
|
|
95
|
+
"Must be one of: ['latency', 'price', 'throughput'], or a dictionary."
|
|
96
|
+
)
|
|
97
|
+
|
|
55
98
|
def load_configuration(self, company_short_name: str):
|
|
56
99
|
"""
|
|
57
100
|
Main entry point for configuring a company instance.
|
|
@@ -365,15 +408,43 @@ class ConfigurationService:
|
|
|
365
408
|
for index, model_entry in enumerate(llm_available_models):
|
|
366
409
|
normalized_model = self._normalize_model_entry(model_entry)
|
|
367
410
|
provider = str(normalized_model.get("provider") or "").strip().lower()
|
|
411
|
+
model_specific_config = normalized_model.get("config")
|
|
368
412
|
if provider and provider not in supported_llm_providers:
|
|
369
413
|
add_error(
|
|
370
414
|
f"llm.available_models[{index}].provider",
|
|
371
415
|
f"Unsupported provider '{provider}'. Must be one of: {sorted(supported_llm_providers)}."
|
|
372
416
|
)
|
|
417
|
+
if model_specific_config is not None and not isinstance(model_specific_config, dict):
|
|
418
|
+
add_error(f"llm.available_models[{index}].config", "Must be a dictionary.")
|
|
373
419
|
if provider == "openai_compatible":
|
|
374
420
|
openai_compatible_in_use = True
|
|
375
421
|
if provider == "openrouter":
|
|
376
422
|
openrouter_in_use = True
|
|
423
|
+
if isinstance(model_specific_config, dict):
|
|
424
|
+
if "routing" in model_specific_config:
|
|
425
|
+
self._validate_openrouter_provider_preferences(
|
|
426
|
+
add_error,
|
|
427
|
+
f"llm.available_models[{index}].config.routing",
|
|
428
|
+
model_specific_config.get("routing"),
|
|
429
|
+
)
|
|
430
|
+
if "openrouter_provider" in model_specific_config:
|
|
431
|
+
add_error(
|
|
432
|
+
f"llm.available_models[{index}].config.openrouter_provider",
|
|
433
|
+
"Unsupported key. Use 'config.routing' instead.",
|
|
434
|
+
)
|
|
435
|
+
elif isinstance(model_specific_config, dict) and (
|
|
436
|
+
"routing" in model_specific_config or "openrouter_provider" in model_specific_config
|
|
437
|
+
):
|
|
438
|
+
if "routing" in model_specific_config:
|
|
439
|
+
add_error(
|
|
440
|
+
f"llm.available_models[{index}].config.routing",
|
|
441
|
+
"Only supported when the model provider is 'openrouter'.",
|
|
442
|
+
)
|
|
443
|
+
if "openrouter_provider" in model_specific_config:
|
|
444
|
+
add_error(
|
|
445
|
+
f"llm.available_models[{index}].config.openrouter_provider",
|
|
446
|
+
"Unsupported key. Use 'config.routing' instead.",
|
|
447
|
+
)
|
|
377
448
|
|
|
378
449
|
providers_cfg = config.get("llm", {}).get("providers")
|
|
379
450
|
if providers_cfg is not None and not isinstance(providers_cfg, dict):
|
|
@@ -450,6 +521,56 @@ class ConfigurationService:
|
|
|
450
521
|
if raw_x_title is not None and (not isinstance(raw_x_title, str) or not raw_x_title.strip()):
|
|
451
522
|
add_error("llm.openrouter.x_title", "Must be a non-empty string.")
|
|
452
523
|
|
|
524
|
+
telemetry_cfg = config.get("llm", {}).get("telemetry")
|
|
525
|
+
if telemetry_cfg is not None:
|
|
526
|
+
if not isinstance(telemetry_cfg, dict):
|
|
527
|
+
add_error("llm.telemetry", "Must be a dictionary.")
|
|
528
|
+
else:
|
|
529
|
+
telemetry_enabled = telemetry_cfg.get("enabled", False)
|
|
530
|
+
if not isinstance(telemetry_enabled, bool):
|
|
531
|
+
add_error("llm.telemetry.enabled", "Must be a boolean.")
|
|
532
|
+
|
|
533
|
+
telemetry_provider = telemetry_cfg.get("provider")
|
|
534
|
+
normalized_telemetry_provider = ""
|
|
535
|
+
if telemetry_provider is not None:
|
|
536
|
+
if not isinstance(telemetry_provider, str) or not telemetry_provider.strip():
|
|
537
|
+
add_error("llm.telemetry.provider", "Must be a non-empty string.")
|
|
538
|
+
else:
|
|
539
|
+
normalized_telemetry_provider = telemetry_provider.strip().lower()
|
|
540
|
+
if normalized_telemetry_provider not in {"braintrust"}:
|
|
541
|
+
add_error(
|
|
542
|
+
"llm.telemetry.provider",
|
|
543
|
+
"Unsupported provider. Must be 'braintrust'.",
|
|
544
|
+
)
|
|
545
|
+
elif telemetry_enabled:
|
|
546
|
+
add_error("llm.telemetry.provider", "Missing required key: 'provider'.")
|
|
547
|
+
|
|
548
|
+
if normalized_telemetry_provider == "braintrust":
|
|
549
|
+
braintrust_cfg = telemetry_cfg.get("braintrust")
|
|
550
|
+
if not isinstance(braintrust_cfg, dict):
|
|
551
|
+
add_error("llm.telemetry.braintrust", "Must be a dictionary.")
|
|
552
|
+
else:
|
|
553
|
+
if telemetry_enabled:
|
|
554
|
+
project = braintrust_cfg.get("project")
|
|
555
|
+
if not isinstance(project, str) or not project.strip():
|
|
556
|
+
add_error("llm.telemetry.braintrust.project", "Must be a non-empty string.")
|
|
557
|
+
|
|
558
|
+
api_key = braintrust_cfg.get("api_key")
|
|
559
|
+
if not isinstance(api_key, str) or not api_key.strip():
|
|
560
|
+
add_error("llm.telemetry.braintrust.api_key", "Must be a non-empty string.")
|
|
561
|
+
|
|
562
|
+
api_url = braintrust_cfg.get("api_url")
|
|
563
|
+
if api_url is not None:
|
|
564
|
+
if not isinstance(api_url, str) or not api_url.strip():
|
|
565
|
+
add_error("llm.telemetry.braintrust.api_url", "Must be a non-empty string.")
|
|
566
|
+
else:
|
|
567
|
+
parsed = urlparse(api_url.strip())
|
|
568
|
+
if parsed.scheme.lower() not in {"http", "https"} or not parsed.netloc:
|
|
569
|
+
add_error(
|
|
570
|
+
"llm.telemetry.braintrust.api_url",
|
|
571
|
+
"Must be an absolute HTTP or HTTPS URL.",
|
|
572
|
+
)
|
|
573
|
+
|
|
453
574
|
# 3. Embedding Provider
|
|
454
575
|
if isinstance(config.get("embedding_provider"), dict):
|
|
455
576
|
if not config.get("embedding_provider", {}).get("provider"):
|
|
@@ -607,6 +728,7 @@ class ConfigurationService:
|
|
|
607
728
|
"text_verbosity",
|
|
608
729
|
"prompt_version",
|
|
609
730
|
"prompt_variant",
|
|
731
|
+
"telemetry_enabled",
|
|
610
732
|
}
|
|
611
733
|
unknown_option_keys = sorted(
|
|
612
734
|
key for key in llm_request_options.keys() if key not in allowed_option_keys
|
|
@@ -653,6 +775,15 @@ class ConfigurationService:
|
|
|
653
775
|
"Must be a non-empty string.",
|
|
654
776
|
)
|
|
655
777
|
|
|
778
|
+
if "telemetry_enabled" in llm_request_options and not isinstance(
|
|
779
|
+
llm_request_options.get("telemetry_enabled"),
|
|
780
|
+
bool,
|
|
781
|
+
):
|
|
782
|
+
add_error(
|
|
783
|
+
f"prompts[{i}].llm_request_options.telemetry_enabled",
|
|
784
|
+
"Must be a boolean.",
|
|
785
|
+
)
|
|
786
|
+
|
|
656
787
|
tool_policy = prompt.get("tool_policy")
|
|
657
788
|
if tool_policy is not None:
|
|
658
789
|
if not isinstance(tool_policy, dict):
|
|
@@ -752,6 +883,49 @@ class ConfigurationService:
|
|
|
752
883
|
if not isinstance(docling_config, dict):
|
|
753
884
|
add_error("knowledge_base.docling", "Must be a dictionary.")
|
|
754
885
|
|
|
886
|
+
metadata_search_fields = kb_config.get("metadata_search_fields")
|
|
887
|
+
if metadata_search_fields is not None:
|
|
888
|
+
if not isinstance(metadata_search_fields, list):
|
|
889
|
+
add_error("knowledge_base.metadata_search_fields", "Must be a list.")
|
|
890
|
+
else:
|
|
891
|
+
for i, item in enumerate(metadata_search_fields):
|
|
892
|
+
if isinstance(item, str):
|
|
893
|
+
if not item.strip():
|
|
894
|
+
add_error(
|
|
895
|
+
f"knowledge_base.metadata_search_fields[{i}]",
|
|
896
|
+
"Metadata field name cannot be empty."
|
|
897
|
+
)
|
|
898
|
+
elif isinstance(item, dict):
|
|
899
|
+
key = item.get("key")
|
|
900
|
+
if not isinstance(key, str) or not key.strip():
|
|
901
|
+
add_error(
|
|
902
|
+
f"knowledge_base.metadata_search_fields[{i}].key",
|
|
903
|
+
"Missing required key: 'key' (non-empty string)."
|
|
904
|
+
)
|
|
905
|
+
label = item.get("label")
|
|
906
|
+
if label is not None and (not isinstance(label, str) or not label.strip()):
|
|
907
|
+
add_error(
|
|
908
|
+
f"knowledge_base.metadata_search_fields[{i}].label",
|
|
909
|
+
"Must be a non-empty string if provided."
|
|
910
|
+
)
|
|
911
|
+
match = item.get("match")
|
|
912
|
+
if match is not None:
|
|
913
|
+
if not isinstance(match, str):
|
|
914
|
+
add_error(
|
|
915
|
+
f"knowledge_base.metadata_search_fields[{i}].match",
|
|
916
|
+
"Must be a string if provided."
|
|
917
|
+
)
|
|
918
|
+
elif match.strip().lower() not in {"exact", "contains"}:
|
|
919
|
+
add_error(
|
|
920
|
+
f"knowledge_base.metadata_search_fields[{i}].match",
|
|
921
|
+
"Must be one of: ['contains', 'exact']."
|
|
922
|
+
)
|
|
923
|
+
else:
|
|
924
|
+
add_error(
|
|
925
|
+
f"knowledge_base.metadata_search_fields[{i}]",
|
|
926
|
+
"Each metadata search field must be a string or an object with keys like {key, label, match}."
|
|
927
|
+
)
|
|
928
|
+
|
|
755
929
|
prod_connector = kb_config.get("connectors", {}).get("production", {})
|
|
756
930
|
if prod_connector.get("type") == "s3":
|
|
757
931
|
for key in ["bucket", "prefix"]:
|
|
@@ -996,6 +1170,12 @@ class ConfigurationService:
|
|
|
996
1170
|
provider_cfg = providers_cfg.get(candidate)
|
|
997
1171
|
return dict(provider_cfg) if isinstance(provider_cfg, dict) else {}
|
|
998
1172
|
|
|
1173
|
+
def get_llm_telemetry_config(self, company_short_name: str) -> dict:
|
|
1174
|
+
self._ensure_config_loaded(company_short_name)
|
|
1175
|
+
llm_config = self._loaded_configs[company_short_name].get("llm") or {}
|
|
1176
|
+
telemetry_cfg = llm_config.get("telemetry")
|
|
1177
|
+
return dict(telemetry_cfg) if isinstance(telemetry_cfg, dict) else {}
|
|
1178
|
+
|
|
999
1179
|
|
|
1000
1180
|
def _load_and_merge_configs(self, company_short_name: str) -> dict:
|
|
1001
1181
|
"""
|
|
@@ -14,7 +14,7 @@ from iatoolkit.services.storage_service import StorageService
|
|
|
14
14
|
from iatoolkit.services.parsers.parsing_service import ParsingService
|
|
15
15
|
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
|
16
16
|
from iatoolkit.services.visual_kb_service import VisualKnowledgeBaseService
|
|
17
|
-
from sqlalchemy import desc
|
|
17
|
+
from sqlalchemy import desc, func
|
|
18
18
|
from typing import Any
|
|
19
19
|
import json
|
|
20
20
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
@@ -564,6 +564,9 @@ class KnowledgeBaseService:
|
|
|
564
564
|
filename_keyword: Optional[str] = None,
|
|
565
565
|
from_date: Optional[datetime] = None,
|
|
566
566
|
to_date: Optional[datetime] = None,
|
|
567
|
+
metadata_key: Optional[str] = None,
|
|
568
|
+
metadata_value: Optional[str] = None,
|
|
569
|
+
metadata_match_mode: Optional[str] = None,
|
|
567
570
|
limit: int = 100,
|
|
568
571
|
offset: int = 0) -> List[Document]:
|
|
569
572
|
"""
|
|
@@ -577,6 +580,9 @@ class KnowledgeBaseService:
|
|
|
577
580
|
filename_keyword: Optional substring to search in filename.
|
|
578
581
|
from_date: Optional start date filter (created_at).
|
|
579
582
|
to_date: Optional end date filter (created_at).
|
|
583
|
+
metadata_key: Optional top-level metadata field name inside Document.meta.
|
|
584
|
+
metadata_value: Optional metadata field value to filter by.
|
|
585
|
+
metadata_match_mode: Optional metadata match mode: 'exact' or 'contains'.
|
|
580
586
|
limit: Pagination limit.
|
|
581
587
|
offset: Pagination offset.
|
|
582
588
|
|
|
@@ -613,6 +619,16 @@ class KnowledgeBaseService:
|
|
|
613
619
|
if to_date:
|
|
614
620
|
query = query.filter(Document.created_at <= to_date)
|
|
615
621
|
|
|
622
|
+
normalized_metadata_key = str(metadata_key or "").strip()
|
|
623
|
+
normalized_metadata_value = str(metadata_value or "").strip().lower()
|
|
624
|
+
normalized_match_mode = str(metadata_match_mode or "contains").strip().lower()
|
|
625
|
+
if normalized_metadata_key and normalized_metadata_value:
|
|
626
|
+
meta_value_expr = func.lower(func.coalesce(Document.meta[normalized_metadata_key].as_string(), ""))
|
|
627
|
+
if normalized_match_mode == "exact":
|
|
628
|
+
query = query.filter(meta_value_expr == normalized_metadata_value)
|
|
629
|
+
else:
|
|
630
|
+
query = query.filter(meta_value_expr.like(f"%{normalized_metadata_value}%"))
|
|
631
|
+
|
|
616
632
|
# Apply sorting (newest first) and pagination
|
|
617
633
|
query = query.order_by(desc(Document.created_at))
|
|
618
634
|
query = query.limit(limit).offset(offset)
|
|
@@ -23,6 +23,7 @@ from typing import Dict, Optional, List, Any
|
|
|
23
23
|
from iatoolkit.services.dispatcher_service import Dispatcher
|
|
24
24
|
from iatoolkit.services.storage_service import StorageService
|
|
25
25
|
from iatoolkit.services.structured_output_service import StructuredOutputService
|
|
26
|
+
from iatoolkit.services.telemetry_service import NoopTelemetryService
|
|
26
27
|
|
|
27
28
|
CONTEXT_ERROR_MESSAGE = 'Tu consulta supera el límite de contexto, utiliza el boton de recarga de contexto.'
|
|
28
29
|
|
|
@@ -36,7 +37,8 @@ class llmClient:
|
|
|
36
37
|
llm_proxy: LLMProxy,
|
|
37
38
|
model_registry: ModelRegistry,
|
|
38
39
|
storage_service: StorageService,
|
|
39
|
-
util: Utility
|
|
40
|
+
util: Utility,
|
|
41
|
+
telemetry_service=None,
|
|
40
42
|
):
|
|
41
43
|
self.llmquery_repo = llmquery_repo
|
|
42
44
|
self.llm_proxy = llm_proxy
|
|
@@ -44,6 +46,7 @@ class llmClient:
|
|
|
44
46
|
self.storage_service = storage_service
|
|
45
47
|
self.util = util
|
|
46
48
|
self._dispatcher = None # Cache for the lazy-loaded dispatcher
|
|
49
|
+
self._telemetry_service = telemetry_service
|
|
47
50
|
|
|
48
51
|
# Lazy init to avoid network/bootstrap failures during app startup.
|
|
49
52
|
self.encoding = None
|
|
@@ -62,6 +65,18 @@ class llmClient:
|
|
|
62
65
|
self._dispatcher = current_iatoolkit().get_injector().get(Dispatcher)
|
|
63
66
|
return self._dispatcher
|
|
64
67
|
|
|
68
|
+
@property
|
|
69
|
+
def telemetry_service(self):
|
|
70
|
+
if self._telemetry_service is None:
|
|
71
|
+
try:
|
|
72
|
+
from iatoolkit import current_iatoolkit
|
|
73
|
+
from iatoolkit.services.telemetry_service import TelemetryService
|
|
74
|
+
|
|
75
|
+
self._telemetry_service = current_iatoolkit().get_injector().get(TelemetryService)
|
|
76
|
+
except Exception:
|
|
77
|
+
self._telemetry_service = NoopTelemetryService()
|
|
78
|
+
return self._telemetry_service
|
|
79
|
+
|
|
65
80
|
|
|
66
81
|
def invoke(self,
|
|
67
82
|
company: Company,
|
|
@@ -81,6 +96,7 @@ class llmClient:
|
|
|
81
96
|
task_id: Optional[int] = None,
|
|
82
97
|
execution_metadata: Optional[Dict[str, Any]] = None,
|
|
83
98
|
request_metadata: Optional[Dict[str, str]] = None,
|
|
99
|
+
telemetry_request: Optional[Dict[str, Any]] = None,
|
|
84
100
|
response_contract: Optional[Dict[str, Any]] = None
|
|
85
101
|
) -> dict:
|
|
86
102
|
|
|
@@ -102,6 +118,7 @@ class llmClient:
|
|
|
102
118
|
)
|
|
103
119
|
text_payload = request_params["text"]
|
|
104
120
|
reasoning_payload = request_params["reasoning"]
|
|
121
|
+
telemetry_execution = self.telemetry_service.start_execution(telemetry_request)
|
|
105
122
|
|
|
106
123
|
try:
|
|
107
124
|
start_time = time.time()
|
|
@@ -285,6 +302,22 @@ class llmClient:
|
|
|
285
302
|
answer_time=stats['response_time']
|
|
286
303
|
)
|
|
287
304
|
self.llmquery_repo.add_query(query)
|
|
305
|
+
telemetry_execution.finalize(
|
|
306
|
+
query_id=query.id,
|
|
307
|
+
success=decoded_response.get('status', False),
|
|
308
|
+
answer_preview=decoded_response.get('answer', ''),
|
|
309
|
+
metrics={
|
|
310
|
+
"total_tokens": combined_stats.get("total_tokens"),
|
|
311
|
+
"response_time": combined_stats.get("response_time"),
|
|
312
|
+
"sql_retry_count": combined_stats.get("sql_retry_count"),
|
|
313
|
+
},
|
|
314
|
+
)
|
|
315
|
+
telemetry_stats = telemetry_execution.build_stats()
|
|
316
|
+
if telemetry_stats:
|
|
317
|
+
query.stats = dict(query.stats or {})
|
|
318
|
+
query.stats["telemetry"] = telemetry_stats
|
|
319
|
+
self.llmquery_repo.commit()
|
|
320
|
+
combined_stats = dict(query.stats or {})
|
|
288
321
|
logging.info(f"finish llm call in {int(time.time() - start_time)} secs..")
|
|
289
322
|
if function_calls:
|
|
290
323
|
logging.info(f"time within the function calls {f_call_time:.1f} secs.")
|
|
@@ -312,9 +345,17 @@ class llmClient:
|
|
|
312
345
|
except SQLAlchemyError as db_error:
|
|
313
346
|
# rollback
|
|
314
347
|
self.llmquery_repo.session.rollback()
|
|
348
|
+
telemetry_execution.finalize(
|
|
349
|
+
success=False,
|
|
350
|
+
error_message=str(db_error),
|
|
351
|
+
)
|
|
315
352
|
logging.error(f"Error de base de datos: {str(db_error)}")
|
|
316
353
|
raise db_error
|
|
317
354
|
except OperationalError as e:
|
|
355
|
+
telemetry_execution.finalize(
|
|
356
|
+
success=False,
|
|
357
|
+
error_message=str(e),
|
|
358
|
+
)
|
|
318
359
|
logging.error(f"Operational error: {str(e)}")
|
|
319
360
|
raise e
|
|
320
361
|
except Exception as e:
|
|
@@ -331,6 +372,15 @@ class llmClient:
|
|
|
331
372
|
function_calls=f_calls,
|
|
332
373
|
)
|
|
333
374
|
self.llmquery_repo.add_query(query)
|
|
375
|
+
telemetry_execution.finalize(
|
|
376
|
+
query_id=query.id,
|
|
377
|
+
success=False,
|
|
378
|
+
error_message=error_message,
|
|
379
|
+
)
|
|
380
|
+
telemetry_stats = telemetry_execution.build_stats()
|
|
381
|
+
if telemetry_stats:
|
|
382
|
+
query.stats = {"telemetry": telemetry_stats}
|
|
383
|
+
self.llmquery_repo.commit()
|
|
334
384
|
|
|
335
385
|
# in case of context error
|
|
336
386
|
if "context_length_exceeded" in str(e):
|
|
@@ -345,6 +345,7 @@ class PromptService:
|
|
|
345
345
|
"text_verbosity",
|
|
346
346
|
"prompt_version",
|
|
347
347
|
"prompt_variant",
|
|
348
|
+
"telemetry_enabled",
|
|
348
349
|
}
|
|
349
350
|
unknown_keys = sorted(
|
|
350
351
|
key for key in llm_request_options.keys() if key not in allowed_keys
|
|
@@ -422,6 +423,15 @@ class PromptService:
|
|
|
422
423
|
)
|
|
423
424
|
normalized_options["prompt_variant"] = candidate_prompt_variant
|
|
424
425
|
|
|
426
|
+
raw_telemetry_enabled = llm_request_options.get("telemetry_enabled")
|
|
427
|
+
if raw_telemetry_enabled is not None:
|
|
428
|
+
if not isinstance(raw_telemetry_enabled, bool):
|
|
429
|
+
raise IAToolkitException(
|
|
430
|
+
IAToolkitException.ErrorType.INVALID_PARAMETER,
|
|
431
|
+
"llm_request_options.telemetry_enabled must be a boolean.",
|
|
432
|
+
)
|
|
433
|
+
normalized_options["telemetry_enabled"] = raw_telemetry_enabled
|
|
434
|
+
|
|
425
435
|
return normalized_options
|
|
426
436
|
|
|
427
437
|
def get_prompts(self, company_short_name: str, include_all: bool = False) -> dict:
|