iatoolkit 2.29.1__tar.gz → 2.31.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.
Files changed (250) hide show
  1. {iatoolkit-2.29.1/src/iatoolkit.egg-info → iatoolkit-2.31.0}/PKG-INFO +1 -1
  2. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/__init__.py +1 -1
  3. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/core.py +14 -0
  4. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/vs_repo.py +71 -7
  5. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/configuration_service.py +17 -0
  6. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/inference_service.py +58 -3
  7. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/knowledge_base_service.py +4 -1
  8. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/tool_service.py +3 -0
  9. iatoolkit-2.31.0/src/iatoolkit/services/warmup_service.py +234 -0
  10. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/rag_api_view.py +6 -0
  11. {iatoolkit-2.29.1 → iatoolkit-2.31.0/src/iatoolkit.egg-info}/PKG-INFO +1 -1
  12. iatoolkit-2.29.1/src/iatoolkit/services/warmup_service.py +0 -108
  13. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/LICENSE +0 -0
  14. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/LICENSE_COMMUNITY.md +0 -0
  15. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/pyproject.toml +0 -0
  16. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/readme.md +0 -0
  17. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/requirements.txt +0 -0
  18. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/setup.cfg +0 -0
  19. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/base_company.py +0 -0
  20. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/cli_commands.py +0 -0
  21. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/__init__.py +0 -0
  22. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/exceptions.py +0 -0
  23. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
  24. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
  25. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
  26. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
  27. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/memory_lint_trigger.py +0 -0
  28. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
  29. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
  30. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
  31. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/model_registry.py +0 -0
  32. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/routes.py +0 -0
  33. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/secret_resolver.py +0 -0
  34. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/session_manager.py +0 -0
  35. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/common/util.py +0 -0
  36. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/company_registry.py +0 -0
  37. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/__init__.py +0 -0
  38. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
  39. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/channel_business_identity.prompt +0 -0
  40. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/channel_conversation_continuity.prompt +0 -0
  41. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/channel_response_style.prompt +0 -0
  42. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
  43. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
  44. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
  45. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
  46. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
  47. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
  48. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
  49. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
  50. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
  51. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
  52. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
  53. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
  54. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
  55. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
  56. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
  57. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_core.prompt +0 -0
  58. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
  59. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_mysql_casting.prompt +0 -0
  60. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_mysql_json.prompt +0 -0
  61. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_redshift_basics.prompt +0 -0
  62. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_redshift_types.prompt +0 -0
  63. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/sql_rules.prompt +0 -0
  64. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
  65. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
  66. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
  67. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/__init__.py +0 -0
  68. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
  69. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/call_service.py +0 -0
  70. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  71. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  72. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  73. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  74. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  75. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  76. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  77. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
  78. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
  79. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
  80. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/inference_handler.py +0 -0
  81. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
  82. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_gateway_resolver.py +0 -0
  83. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
  84. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
  85. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
  86. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
  87. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
  88. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
  89. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
  90. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_proxy.py +0 -0
  91. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/llm_response.py +0 -0
  92. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  93. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/locales/en.yaml +0 -0
  94. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/locales/es.yaml +0 -0
  95. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/__init__.py +0 -0
  96. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
  97. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/database_manager.py +0 -0
  98. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/document_repo.py +0 -0
  99. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
  100. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
  101. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/knowledge_wiki_repo.py +0 -0
  102. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  103. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/mcp_token_repo.py +0 -0
  104. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/memory_repo.py +0 -0
  105. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/models.py +0 -0
  106. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
  107. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
  108. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
  109. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
  110. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/runtime_logging.py +0 -0
  111. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/__init__.py +0 -0
  112. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/api_key_service.py +0 -0
  113. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
  114. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/auth_service.py +0 -0
  115. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/benchmark_service.py +0 -0
  116. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/branding_service.py +0 -0
  117. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/company_context_service.py +0 -0
  118. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/context_builder_service.py +0 -0
  119. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
  120. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/embedding_service.py +0 -0
  121. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/excel_service.py +0 -0
  122. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/file_processor_service.py +0 -0
  123. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/history_manager_service.py +0 -0
  124. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/http_tool_service.py +0 -0
  125. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/i18n_service.py +0 -0
  126. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/jwt_service.py +0 -0
  127. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/language_service.py +0 -0
  128. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/license_service.py +0 -0
  129. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/llm_client_service.py +0 -0
  130. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/mail_service.py +0 -0
  131. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/markdown_wiki_service.py +0 -0
  132. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/mcp_token_service.py +0 -0
  133. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/memory_compiler_service.py +0 -0
  134. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/memory_lint_service.py +0 -0
  135. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
  136. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/memory_service.py +0 -0
  137. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/memory_wiki_service.py +0 -0
  138. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
  139. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/noop_memory_lint_trigger.py +0 -0
  140. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
  141. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
  142. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
  143. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
  144. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
  145. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
  146. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
  147. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
  148. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
  149. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
  150. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/parsers/validator.py +0 -0
  151. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/pdf_service.py +0 -0
  152. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/profile_service.py +0 -0
  153. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
  154. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/prompt_service.py +0 -0
  155. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/query_service.py +0 -0
  156. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
  157. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
  158. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/sql_service.py +0 -0
  159. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/sql_source_service.py +0 -0
  160. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/storage_service.py +0 -0
  161. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/structured_output_service.py +0 -0
  162. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
  163. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/system_tools.py +0 -0
  164. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/telemetry_service.py +0 -0
  165. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/tenant_wiki_service.py +0 -0
  166. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/tool_output_contract.py +0 -0
  167. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
  168. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
  169. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
  170. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
  171. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
  172. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
  173. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
  174. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
  175. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/services/web_search_service.py +0 -0
  176. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  177. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
  178. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
  179. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
  180. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  181. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
  182. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
  183. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
  184. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_main.js +0 -0
  185. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
  186. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
  187. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
  188. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
  189. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
  190. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
  191. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
  192. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
  193. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/styles/documents.css +0 -0
  194. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
  195. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
  196. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
  197. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/_company_header.html +0 -0
  198. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/_login_widget.html +0 -0
  199. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/account.html +0 -0
  200. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/base.html +0 -0
  201. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/change_password.html +0 -0
  202. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/chat.html +0 -0
  203. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
  204. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/chat_modals.html +0 -0
  205. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/error.html +0 -0
  206. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/forgot_password.html +0 -0
  207. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
  208. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
  209. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
  210. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/pdf/base.html +0 -0
  211. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
  212. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/pdf/report.html +0 -0
  213. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
  214. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/templates/signup.html +0 -0
  215. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/__init__.py +0 -0
  216. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/account_view.py +0 -0
  217. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
  218. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/base_login_view.py +0 -0
  219. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/categories_api_view.py +0 -0
  220. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/change_password_view.py +0 -0
  221. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
  222. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/chat_view.py +0 -0
  223. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
  224. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
  225. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
  226. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
  227. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
  228. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/history_api_view.py +0 -0
  229. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/home_view.py +0 -0
  230. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
  231. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
  232. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
  233. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/login_view.py +0 -0
  234. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/logout_api_view.py +0 -0
  235. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/memory_api_view.py +0 -0
  236. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/profile_api_view.py +0 -0
  237. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
  238. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
  239. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
  240. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
  241. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/signup_view.py +0 -0
  242. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/static_page_view.py +0 -0
  243. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/tool_api_view.py +0 -0
  244. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
  245. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/users_api_view.py +0 -0
  246. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit/views/verify_user_view.py +0 -0
  247. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit.egg-info/SOURCES.txt +0 -0
  248. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  249. {iatoolkit-2.29.1 → iatoolkit-2.31.0}/src/iatoolkit.egg-info/requires.txt +0 -0
  250. {iatoolkit-2.29.1 → iatoolkit-2.31.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.29.1
3
+ Version: 2.31.0
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
- __version__ = "2.29.1"
6
+ __version__ = "2.31.0"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -115,6 +115,7 @@ class IAToolkit:
115
115
  self._setup_request_globals()
116
116
  self._setup_context_processors()
117
117
  self._sync_system_tools_on_boot()
118
+ self._run_configured_startup_warmup()
118
119
 
119
120
  # register data sources
120
121
  if start:
@@ -149,6 +150,19 @@ class IAToolkit:
149
150
  except Exception as exc:
150
151
  logging.warning("⚠️ Unable to sync system tools on boot: %s", exc)
151
152
 
153
+ def _run_configured_startup_warmup(self):
154
+ from iatoolkit.services.warmup_service import WarmupService
155
+
156
+ try:
157
+ warmup_service = self._injector.get(WarmupService)
158
+ warmed_companies = warmup_service.warmup_startup_configured_companies(trigger="core_startup")
159
+ if warmed_companies:
160
+ logging.info("🔥 Startup warm-up completed for companies=%s", warmed_companies)
161
+ else:
162
+ logging.info("🔥 Startup warm-up skipped: no embedding provider enabled warmup_on_startup.")
163
+ except Exception:
164
+ logging.exception("⚠️ Startup warm-up failed.")
165
+
152
166
  def _get_config_value(self, key: str, default=None):
153
167
  # get a value from the config dict or the environment variable
154
168
  return self.config.get(key, os.getenv(key, default))
@@ -7,6 +7,7 @@ import ast
7
7
  import json
8
8
  import logging
9
9
  import re
10
+ from time import perf_counter
10
11
  from typing import Dict, List
11
12
 
12
13
  from sqlalchemy import text
@@ -86,6 +87,7 @@ class VSRepo:
86
87
  n_results=5,
87
88
  metadata_filter=None,
88
89
  collection_ids: List[int] | None = None,
90
+ include_urls: bool = True,
89
91
  ) -> list[Dict]:
90
92
  """
91
93
  search documents similar to the query for a company
@@ -95,40 +97,75 @@ class VSRepo:
95
97
  query_text: query text
96
98
  n_results: max number of results to return
97
99
  metadata_filter: (e.g., {"document_type": "certificate"})
100
+ include_urls: Generate storage URLs for returned chunks when true.
98
101
 
99
102
  Returns:
100
103
  list of documents matching the query and filters
101
104
  """
105
+ query_started_at = perf_counter()
106
+ embedding_started_at = perf_counter()
102
107
  # Generate the embedding with the query text for the specific company
103
108
  try:
104
109
  query_embedding = self.embedding_service.embed_text(company_short_name, query_text)
105
110
  except Exception as e:
106
- logging.error(f"error while creating text embedding: {str(e)}")
111
+ logging.error(
112
+ "RAG vector query embedding failed: company=%s duration_ms=%s error=%s",
113
+ company_short_name,
114
+ round((perf_counter() - embedding_started_at) * 1000),
115
+ str(e),
116
+ )
107
117
  raise IAToolkitException(IAToolkitException.ErrorType.EMBEDDING_ERROR,
108
118
  f"embedding error: {str(e)}")
119
+ embedding_duration_ms = round((perf_counter() - embedding_started_at) * 1000)
120
+ try:
121
+ embedding_dimensions = len(query_embedding)
122
+ except TypeError as exc:
123
+ raise IAToolkitException(
124
+ IAToolkitException.ErrorType.EMBEDDING_ERROR,
125
+ "embedding error: query embedding has no dimensions",
126
+ ) from exc
127
+ if embedding_dimensions < 1 or embedding_dimensions > 2000:
128
+ raise IAToolkitException(
129
+ IAToolkitException.ErrorType.EMBEDDING_ERROR,
130
+ f"embedding error: unsupported query embedding dimensions ({embedding_dimensions})",
131
+ )
109
132
 
110
133
  sql_query, params = None, None
111
134
  try:
112
135
  # Get company ID from its short name for the SQL query
136
+ company_lookup_started_at = perf_counter()
113
137
  company = self.session.query(Company).filter(Company.short_name == company_short_name).one_or_none()
138
+ company_lookup_duration_ms = round((perf_counter() - company_lookup_started_at) * 1000)
114
139
  if not company:
115
140
  raise IAToolkitException(IAToolkitException.ErrorType.VECTOR_STORE_ERROR,
116
141
  f"Company with short name '{company_short_name}' not found.")
117
142
 
143
+ distance_metric = "l2"
144
+ distance_expression = (
145
+ f"iat_vsdocs.embedding::vector({embedding_dimensions}) "
146
+ f"<-> CAST(:query_embedding AS vector({embedding_dimensions}))"
147
+ )
148
+
118
149
  # build the SQL query
119
- sql_query_parts = ["""
150
+ sql_query_parts = [f"""
120
151
  SELECT iat_vsdocs.id, \
121
152
  iat_documents.filename, \
122
153
  iat_vsdocs.text, \
123
154
  iat_documents.storage_key, \
124
155
  iat_documents.meta,
125
156
  iat_documents.id, \
126
- iat_vsdocs.meta
157
+ iat_vsdocs.meta,
158
+ ({distance_expression}) AS distance
127
159
  FROM iat_vsdocs, \
128
160
  iat_documents
129
161
  WHERE iat_vsdocs.company_id = :company_id
130
162
  AND iat_vsdocs.document_id = iat_documents.id \
131
163
  """]
164
+ # The literal dimension lets PostgreSQL prove that a matching partial
165
+ # pgvector expression index can satisfy the nearest-neighbor order.
166
+ sql_query_parts.append(
167
+ f" AND vector_dims(iat_vsdocs.embedding) = {embedding_dimensions}"
168
+ )
132
169
 
133
170
  # query parameters
134
171
  params = {
@@ -166,15 +203,18 @@ class VSRepo:
166
203
  sql_query = "".join(sql_query_parts)
167
204
 
168
205
  # add sorting and limit of results
169
- sql_query += " ORDER BY embedding <-> CAST(:query_embedding AS VECTOR) LIMIT :n_results"
206
+ sql_query += " ORDER BY distance ASC LIMIT :n_results"
170
207
 
171
208
  logging.debug(f"Executing SQL query: {sql_query}")
172
209
  logging.debug(f"With parameters: {params}")
173
210
 
174
211
  # execute the query
212
+ vector_sql_started_at = perf_counter()
213
+ self.session.execute(text("SET LOCAL hnsw.iterative_scan = strict_order"))
214
+ self.session.execute(text("SET LOCAL hnsw.ef_search = 100"))
175
215
  result = self.session.execute(text(sql_query), params)
176
-
177
216
  rows = result.fetchall()
217
+ vector_sql_duration_ms = round((perf_counter() - vector_sql_started_at) * 1000)
178
218
  vs_documents = []
179
219
 
180
220
  for row in rows:
@@ -182,10 +222,12 @@ class VSRepo:
182
222
  doc_meta = row[4] if len(row) > 4 and row[4] is not None else {}
183
223
  chunk_meta = row[6] if len(row) > 6 and row[6] is not None else {}
184
224
 
225
+ distance = float(row[7]) if len(row) > 7 and row[7] is not None else None
226
+
185
227
  # get the url of the document
186
228
  storage_key = row[3] if len(row) > 3 and row[3] is not None else None
187
229
  url = None
188
- if storage_key:
230
+ if include_urls and storage_key:
189
231
  url = self.storage_service.generate_presigned_url(company_short_name, storage_key)
190
232
 
191
233
  vs_documents.append(
@@ -196,10 +238,26 @@ class VSRepo:
196
238
  'text': row[2],
197
239
  'meta': doc_meta,
198
240
  'chunk_meta': chunk_meta,
199
- 'url': url
241
+ 'url': url,
242
+ 'distance': distance,
243
+ 'distance_metric': distance_metric,
244
+ 'score': self._score_from_l2_distance(distance),
200
245
  }
201
246
  )
202
247
 
248
+ logging.info(
249
+ "RAG vector query completed: company=%s collection_ids=%s dimensions=%s n_results=%s rows=%s "
250
+ "embedding_ms=%s company_lookup_ms=%s vector_sql_ms=%s total_ms=%s",
251
+ company_short_name,
252
+ normalized_collection_ids,
253
+ embedding_dimensions,
254
+ n_results,
255
+ len(rows),
256
+ embedding_duration_ms,
257
+ company_lookup_duration_ms,
258
+ vector_sql_duration_ms,
259
+ round((perf_counter() - query_started_at) * 1000),
260
+ )
203
261
  return vs_documents
204
262
 
205
263
  except Exception as e:
@@ -386,6 +444,12 @@ class VSRepo:
386
444
 
387
445
  return sql_parts, params
388
446
 
447
+ @staticmethod
448
+ def _score_from_l2_distance(distance: float | None) -> float | None:
449
+ if distance is None:
450
+ return None
451
+ return 1 / (1 + distance)
452
+
389
453
  @staticmethod
390
454
  def _normalize_metadata_filter_input(metadata_filter):
391
455
  if metadata_filter is None:
@@ -717,6 +717,23 @@ class ConfigurationService:
717
717
  add_error("embedding_provider", "Missing required key: 'provider'")
718
718
  if not config.get("embedding_provider", {}).get("model"):
719
719
  add_error("embedding_provider", "Missing required key: 'model'")
720
+ if (
721
+ "warmup_on_startup" in config.get("embedding_provider", {})
722
+ and not isinstance(config.get("embedding_provider", {}).get("warmup_on_startup"), bool)
723
+ ):
724
+ add_error("embedding_provider.warmup_on_startup", "Must be a boolean.")
725
+
726
+ embedding_providers_cfg = config.get("embedding_providers")
727
+ if embedding_providers_cfg is not None:
728
+ if not isinstance(embedding_providers_cfg, dict):
729
+ add_error("embedding_providers", "Section must be a dictionary.")
730
+ else:
731
+ for provider_key, provider_cfg in embedding_providers_cfg.items():
732
+ if not isinstance(provider_cfg, dict):
733
+ add_error(f"embedding_providers.{provider_key}", "Provider configuration must be a dictionary.")
734
+ continue
735
+ if "warmup_on_startup" in provider_cfg and not isinstance(provider_cfg.get("warmup_on_startup"), bool):
736
+ add_error(f"embedding_providers.{provider_key}.warmup_on_startup", "Must be a boolean.")
720
737
 
721
738
  # 3b. Visual Embedding Provider (Optional)
722
739
  if config.get("visual_embedding_provider"):
@@ -310,16 +310,47 @@ class InferenceService:
310
310
  attempt: int,
311
311
  delay_seconds: float,
312
312
  reason: str,
313
+ attempt_duration_seconds: float | None = None,
314
+ elapsed_seconds: float | None = None,
313
315
  suppress_error_logging: bool = False
314
316
  ) -> None:
315
317
  log_fn = logging.debug if suppress_error_logging else logging.warning
318
+ if attempt_duration_seconds is None or elapsed_seconds is None:
319
+ log_fn(
320
+ "Inference request retry %s scheduled in %.1fs: %s",
321
+ attempt,
322
+ delay_seconds,
323
+ reason,
324
+ )
325
+ return
326
+
316
327
  log_fn(
317
- "Inference request retry %s scheduled in %.1fs: %s",
328
+ "Inference request retry %s scheduled in %.1fs after %.1fs attempt (elapsed %.1fs): %s",
318
329
  attempt,
319
330
  delay_seconds,
331
+ attempt_duration_seconds,
332
+ elapsed_seconds,
320
333
  reason,
321
334
  )
322
335
 
336
+ def _timeout_for_attempt(
337
+ self,
338
+ *,
339
+ timeout: tuple[float, float],
340
+ deadline: float | None,
341
+ attempt: int,
342
+ ) -> tuple[float, float] | None:
343
+ if deadline is None or attempt == 1:
344
+ return timeout
345
+
346
+ remaining_seconds = deadline - time.monotonic()
347
+ if remaining_seconds <= 0:
348
+ return None
349
+
350
+ connect_timeout, read_timeout = timeout
351
+ bounded_timeout = max(0.1, remaining_seconds)
352
+ return min(connect_timeout, bounded_timeout), min(read_timeout, bounded_timeout)
353
+
323
354
  def _call_endpoint(
324
355
  self,
325
356
  url: str,
@@ -334,28 +365,44 @@ class InferenceService:
334
365
  "Authorization": f"Bearer {api_key}",
335
366
  "Content-Type": "application/json",
336
367
  }
337
- deadline = time.monotonic() + retry_budget_seconds if retry_budget_seconds > 0 else None
368
+ started_at = time.monotonic()
369
+ deadline = started_at + retry_budget_seconds if retry_budget_seconds > 0 else None
338
370
  attempt = 1
339
371
  delay_seconds = self.DEFAULT_RETRY_INITIAL_DELAY_SECONDS
340
372
 
341
373
  while True:
374
+ attempt_timeout = self._timeout_for_attempt(timeout=timeout, deadline=deadline, attempt=attempt)
375
+ if attempt_timeout is None:
376
+ error_msg = "Inference retry budget exhausted before next attempt."
377
+ if not suppress_error_logging:
378
+ logging.error(error_msg)
379
+ raise ValueError(error_msg)
380
+
381
+ attempt_started_at = time.monotonic()
342
382
  try:
343
383
  resp, status = self.call_service.post(
344
384
  url,
345
385
  json_dict=payload,
346
386
  headers=headers,
347
- timeout=timeout
387
+ timeout=attempt_timeout
348
388
  )
349
389
  except Exception as exc:
390
+ attempt_duration = time.monotonic() - attempt_started_at
350
391
  next_delay = self._next_retry_delay(delay_seconds=delay_seconds, deadline=deadline)
351
392
  if self._is_retryable_request_exception(exc) and next_delay is not None:
352
393
  self._log_retry_attempt(
353
394
  attempt=attempt,
354
395
  delay_seconds=next_delay,
355
396
  reason=str(exc),
397
+ attempt_duration_seconds=attempt_duration,
398
+ elapsed_seconds=time.monotonic() - started_at,
356
399
  suppress_error_logging=suppress_error_logging,
357
400
  )
358
401
  time.sleep(next_delay)
402
+ if deadline is not None and time.monotonic() >= deadline:
403
+ if not suppress_error_logging:
404
+ logging.error(f"Failed to call inference endpoint: {exc}")
405
+ raise
359
406
  attempt += 1
360
407
  delay_seconds = min(delay_seconds * 2, self.DEFAULT_RETRY_MAX_DELAY_SECONDS)
361
408
  continue
@@ -367,6 +414,7 @@ class InferenceService:
367
414
  if status == 200:
368
415
  return resp
369
416
 
417
+ attempt_duration = time.monotonic() - attempt_started_at
370
418
  error_msg = f"Inference Endpoint Error {status}"
371
419
  if isinstance(resp, dict) and 'error' in resp:
372
420
  error_msg += f": {resp['error']}"
@@ -377,9 +425,16 @@ class InferenceService:
377
425
  attempt=attempt,
378
426
  delay_seconds=next_delay,
379
427
  reason=error_msg,
428
+ attempt_duration_seconds=attempt_duration,
429
+ elapsed_seconds=time.monotonic() - started_at,
380
430
  suppress_error_logging=suppress_error_logging,
381
431
  )
382
432
  time.sleep(next_delay)
433
+ if deadline is not None and time.monotonic() >= deadline:
434
+ if not suppress_error_logging:
435
+ logging.error(f"{error_msg} | Payload keys: {list(payload.keys())}")
436
+ logging.error(f"Failed to call inference endpoint: {error_msg}")
437
+ raise ValueError(error_msg)
383
438
  attempt += 1
384
439
  delay_seconds = min(delay_seconds * 2, self.DEFAULT_RETRY_MAX_DELAY_SECONDS)
385
440
  continue
@@ -488,7 +488,8 @@ class KnowledgeBaseService:
488
488
  query: str,
489
489
  n_results: int = 5,
490
490
  collection: str | list[str] | None = None,
491
- metadata_filter: dict = None
491
+ metadata_filter: dict = None,
492
+ include_urls: bool = True,
492
493
  ):
493
494
  """
494
495
  Performs a semantic search and returns the list of Document objects (chunks).
@@ -500,6 +501,7 @@ class KnowledgeBaseService:
500
501
  n_results: Max number of chunks to retrieve.
501
502
  metadata_filter: Optional filter for document metadata.
502
503
  collection: Optional collection name or list of collection names.
504
+ include_urls: Generate storage URLs for returned chunks when true.
503
505
 
504
506
  Returns:
505
507
  List of Document objects found.
@@ -532,6 +534,7 @@ class KnowledgeBaseService:
532
534
  n_results=n_results,
533
535
  metadata_filter=metadata_filter,
534
536
  collection_ids=collection_ids,
537
+ include_urls=include_urls,
535
538
  )
536
539
 
537
540
  return chunk_list
@@ -374,6 +374,9 @@ class ToolService:
374
374
  "page": page,
375
375
  "caption_text": caption,
376
376
  "document_id": item.get("document_id"),
377
+ "distance": item.get("distance"),
378
+ "distance_metric": item.get("distance_metric"),
379
+ "score": item.get("score"),
377
380
  }
378
381
  lines.append(json.dumps(header, ensure_ascii=False))
379
382
  text_content = (item.get("text") or "").strip()
@@ -0,0 +1,234 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ from __future__ import annotations
7
+
8
+ import logging
9
+ import time
10
+ from injector import inject
11
+
12
+ from iatoolkit.common.interfaces.secret_provider import SecretProvider
13
+ from iatoolkit.common.secret_resolver import resolve_secret
14
+ from iatoolkit.company_registry import get_registered_companies
15
+ from iatoolkit.services.configuration_service import ConfigurationService
16
+ from iatoolkit.services.embedding_service import EmbeddingService
17
+
18
+
19
+ class WarmupService:
20
+ """
21
+ Lightweight warm-up orchestrator.
22
+ Keep it simple: no shared state, no locking, no dedup.
23
+ """
24
+
25
+ @inject
26
+ def __init__(self,
27
+ config_service: ConfigurationService,
28
+ embedding_service: EmbeddingService,
29
+ secret_provider: SecretProvider):
30
+ self.config_service = config_service
31
+ self.embedding_service = embedding_service
32
+ self.secret_provider = secret_provider
33
+
34
+ def warmup_company(self, company_short_name: str, trigger: str = "manual"):
35
+ start = time.perf_counter()
36
+ try:
37
+ self._warmup_remote_text_embeddings(company_short_name)
38
+ elapsed_ms = (time.perf_counter() - start) * 1000
39
+ logging.info(
40
+ "🔥 Warm-up done for company='%s' trigger='%s' in %.2f ms",
41
+ company_short_name,
42
+ trigger,
43
+ elapsed_ms
44
+ )
45
+ except Exception as e:
46
+ elapsed_ms = (time.perf_counter() - start) * 1000
47
+ logging.debug(
48
+ "⚠️ Warm-up failed for company='%s' trigger='%s' in %.2f ms: %s",
49
+ company_short_name,
50
+ trigger,
51
+ elapsed_ms,
52
+ e
53
+ )
54
+
55
+ def warmup_registered_companies(self, trigger: str = "manual"):
56
+ for company_short_name in get_registered_companies().keys():
57
+ self.warmup_company(company_short_name, trigger=trigger)
58
+
59
+ def warmup_startup_configured_companies(self, trigger: str = "startup") -> list[str]:
60
+ warmed_companies: list[str] = []
61
+ for company_short_name in get_registered_companies().keys():
62
+ profiles = self._get_remote_text_embedding_profiles(company_short_name, startup_only=True)
63
+ if not profiles:
64
+ logging.info(
65
+ "Startup warm-up skipped for company='%s': no embedding provider enabled warmup_on_startup.",
66
+ company_short_name,
67
+ )
68
+ continue
69
+
70
+ logging.info(
71
+ "Startup warm-up starting for company='%s' profiles=%s trigger='%s'.",
72
+ company_short_name,
73
+ self._format_profile_labels(profiles),
74
+ trigger,
75
+ )
76
+ warmed_profiles = self._warmup_remote_text_embeddings(
77
+ company_short_name,
78
+ startup_only=True,
79
+ profiles=profiles,
80
+ )
81
+ if not warmed_profiles:
82
+ logging.warning(
83
+ "Startup warm-up attempted but no embedding profiles warmed for company='%s' profiles=%s.",
84
+ company_short_name,
85
+ self._format_profile_labels(profiles),
86
+ )
87
+ continue
88
+
89
+ logging.info(
90
+ "Startup warm-up warmed company='%s' profiles=%s.",
91
+ company_short_name,
92
+ self._format_profile_labels(warmed_profiles),
93
+ )
94
+ warmed_companies.append(company_short_name)
95
+
96
+ return warmed_companies
97
+
98
+ def is_startup_warmup_enabled(self, company_short_name: str) -> bool:
99
+ return bool(self._get_remote_text_embedding_profiles(company_short_name, startup_only=True))
100
+
101
+ def _warmup_remote_text_embeddings(
102
+ self,
103
+ company_short_name: str,
104
+ startup_only: bool = False,
105
+ profiles: list[tuple[str, str, str]] | None = None,
106
+ ) -> list[tuple[str, str, str]]:
107
+ if profiles is None:
108
+ profiles = self._get_remote_text_embedding_profiles(company_short_name, startup_only=startup_only)
109
+ if not profiles:
110
+ logging.debug(
111
+ "Warm-up skipped for company='%s': no remote embedding inference configured.",
112
+ company_short_name
113
+ )
114
+ return []
115
+
116
+ warmed_profiles = []
117
+ for model_type, config_section, tool_name in profiles:
118
+ try:
119
+ # Prime the remote model/container and download/cache model weights.
120
+ self.embedding_service.embed_text(
121
+ company_short_name,
122
+ "hello",
123
+ model_type=model_type,
124
+ suppress_error_logging=True,
125
+ )
126
+ logging.debug(
127
+ "Warm-up primed remote embedding profile company='%s' section='%s' model_type='%s' tool='%s'.",
128
+ company_short_name,
129
+ config_section,
130
+ model_type,
131
+ tool_name,
132
+ )
133
+ warmed_profiles.append((model_type, config_section, tool_name))
134
+ except Exception as e:
135
+ log_fn = logging.warning if startup_only else logging.debug
136
+ log_fn(
137
+ "Warm-up failed for remote embedding profile company='%s' section='%s' model_type='%s' tool='%s': %s",
138
+ company_short_name,
139
+ config_section,
140
+ model_type,
141
+ tool_name,
142
+ e,
143
+ )
144
+
145
+ return warmed_profiles
146
+
147
+ @staticmethod
148
+ def _format_profile_labels(profiles: list[tuple[str, str, str]]) -> list[str]:
149
+ return [
150
+ f"{config_section}:{model_type}:{tool_name}"
151
+ for model_type, config_section, tool_name in profiles
152
+ ]
153
+
154
+ def _uses_remote_text_inference(self, company_short_name: str) -> bool:
155
+ return bool(self._get_remote_text_embedding_profiles(company_short_name))
156
+
157
+ def _get_remote_text_embedding_profiles(
158
+ self,
159
+ company_short_name: str,
160
+ startup_only: bool = False,
161
+ ) -> list[tuple[str, str, str]]:
162
+ profiles: list[tuple[str, str, str, dict]] = []
163
+
164
+ embedding_cfg = self.config_service.get_configuration(company_short_name, "embedding_provider") or {}
165
+ if isinstance(embedding_cfg, dict):
166
+ profiles.append(("text", "embedding_provider", embedding_cfg.get("tool_name") or "text_embeddings", embedding_cfg))
167
+
168
+ embedding_providers = self.config_service.get_configuration(company_short_name, "embedding_providers") or {}
169
+ if isinstance(embedding_providers, dict):
170
+ for model_type, embedding_provider_cfg in embedding_providers.items():
171
+ if not isinstance(embedding_provider_cfg, dict):
172
+ continue
173
+ normalized_model_type = str(model_type or "").strip()
174
+ if not normalized_model_type:
175
+ continue
176
+ profiles.append((
177
+ normalized_model_type,
178
+ f"embedding_providers.{normalized_model_type}",
179
+ embedding_provider_cfg.get("tool_name") or normalized_model_type,
180
+ embedding_provider_cfg,
181
+ ))
182
+
183
+ inference_tools = self.config_service.get_configuration(company_short_name, "inference_tools") or {}
184
+ if not isinstance(inference_tools, dict):
185
+ return []
186
+
187
+ remote_profiles = [
188
+ (model_type, config_section, str(tool_name or "").strip())
189
+ for model_type, config_section, tool_name, embedding_cfg in profiles
190
+ if self._is_remote_embedding_profile(company_short_name, embedding_cfg, inference_tools, str(tool_name or "").strip())
191
+ and (not startup_only or bool(embedding_cfg.get("warmup_on_startup")))
192
+ ]
193
+
194
+ # Leave the default text profile warm last. It is the profile used by rag_search.
195
+ return sorted(remote_profiles, key=lambda item: 1 if item[0] == "text" else 0)
196
+
197
+ def _is_remote_embedding_profile(
198
+ self,
199
+ company_short_name: str,
200
+ embedding_cfg: dict,
201
+ inference_tools: dict,
202
+ tool_name: str,
203
+ ) -> bool:
204
+ provider = (embedding_cfg.get("provider") or "").strip().lower()
205
+ if provider != "huggingface":
206
+ return False
207
+
208
+ if not tool_name:
209
+ return False
210
+
211
+ defaults = inference_tools.get("_defaults") or {}
212
+ if not isinstance(defaults, dict):
213
+ defaults = {}
214
+
215
+ tool_cfg = inference_tools.get(tool_name) or {}
216
+ if not isinstance(tool_cfg, dict):
217
+ return False
218
+
219
+ resolved_cfg = {**defaults, **tool_cfg}
220
+ endpoint_url = (resolved_cfg.get("endpoint_url") or "").strip()
221
+ if not endpoint_url:
222
+ endpoint_url_secret_ref = (resolved_cfg.get("endpoint_url_secret_ref") or "").strip()
223
+ if endpoint_url_secret_ref:
224
+ endpoint_url = (
225
+ resolve_secret(self.secret_provider, company_short_name, endpoint_url_secret_ref, default="") or ""
226
+ ).strip()
227
+ if not endpoint_url:
228
+ endpoint_url_env = (resolved_cfg.get("endpoint_url_env") or "").strip()
229
+ if endpoint_url_env:
230
+ endpoint_url = (
231
+ resolve_secret(self.secret_provider, company_short_name, endpoint_url_env, default="") or ""
232
+ ).strip()
233
+
234
+ return bool(endpoint_url)
@@ -499,6 +499,9 @@ class RagApiView(MethodView):
499
499
  "text": item.get("text"),
500
500
  "chunk_meta": item.get("chunk_meta") or {},
501
501
  "document_meta": item.get("meta") or {},
502
+ "distance": item.get("distance"),
503
+ "distance_metric": item.get("distance_metric"),
504
+ "score": item.get("score"),
502
505
  })
503
506
  return normalized
504
507
 
@@ -537,6 +540,9 @@ class RagApiView(MethodView):
537
540
  "chunk_id": item.get("chunk_id"),
538
541
  "source_type": (item.get("chunk_meta") or {}).get("source_type"),
539
542
  "page": (item.get("chunk_meta") or {}).get("page") or (item.get("chunk_meta") or {}).get("page_start"),
543
+ "distance": item.get("distance"),
544
+ "distance_metric": item.get("distance_metric"),
545
+ "score": item.get("score"),
540
546
  }
541
547
  lines.append(json.dumps(header, ensure_ascii=False))
542
548
  if item.get("text"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 2.29.1
3
+ Version: 2.31.0
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT