iatoolkit 2.4.1__tar.gz → 2.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. {iatoolkit-2.4.1/src/iatoolkit.egg-info → iatoolkit-2.5.1}/PKG-INFO +2 -1
  2. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/pyproject.toml +1 -1
  3. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/requirements.txt +1 -0
  4. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/__init__.py +1 -1
  5. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/core.py +2 -0
  6. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +10 -1
  7. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +16 -0
  8. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_providers/openai_adapter.py +11 -3
  9. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +8 -0
  10. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_proxy.py +64 -31
  11. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/locales/en.yaml +7 -0
  12. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/locales/es.yaml +7 -0
  13. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/configuration_service.py +66 -0
  14. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/llm_client_service.py +55 -1
  15. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/prompt_service.py +10 -0
  16. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/query_service.py +54 -0
  17. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/system_prompt_catalog.py +6 -2
  18. iatoolkit-2.5.1/src/iatoolkit/services/telemetry_service.py +484 -0
  19. {iatoolkit-2.4.1 → iatoolkit-2.5.1/src/iatoolkit.egg-info}/PKG-INFO +2 -1
  20. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit.egg-info/SOURCES.txt +20 -19
  21. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit.egg-info/requires.txt +1 -0
  22. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/LICENSE +0 -0
  23. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/LICENSE_COMMUNITY.md +0 -0
  24. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/readme.md +0 -0
  25. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/setup.cfg +0 -0
  26. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/base_company.py +0 -0
  27. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/cli_commands.py +0 -0
  28. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/__init__.py +0 -0
  29. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/exceptions.py +0 -0
  30. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/__init__.py +0 -0
  31. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
  32. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
  33. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
  34. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/memory_lint_trigger.py +0 -0
  35. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
  36. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
  37. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
  38. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/model_registry.py +0 -0
  39. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/routes.py +0 -0
  40. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/secret_resolver.py +0 -0
  41. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/session_manager.py +0 -0
  42. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/common/util.py +0 -0
  43. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/company_registry.py +0 -0
  44. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/config/__init__.py +0 -0
  45. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
  46. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/chat_state_rules.prompt +0 -0
  47. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/chat_user_profile.prompt +0 -0
  48. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/core_identity.prompt +0 -0
  49. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/email_output.prompt +0 -0
  50. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/file_download_output.prompt +0 -0
  51. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/format_styles.prompt +0 -0
  52. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/html_structures.prompt +0 -0
  53. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/links_documents.prompt +0 -0
  54. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/memory_usage.prompt +0 -0
  55. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/multimodal_basics.prompt +0 -0
  56. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/output_basics.prompt +0 -0
  57. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/presentation_formatting.prompt +0 -0
  58. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/query_main.prompt +0 -0
  59. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/sql_aggregation_scope.prompt +0 -0
  60. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/sql_casting.prompt +0 -0
  61. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/sql_core.prompt +0 -0
  62. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/sql_jsonb.prompt +0 -0
  63. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/sql_rules.prompt +0 -0
  64. {iatoolkit-2.4.1/src/iatoolkit → iatoolkit-2.5.1/src/iatoolkit/config}/system_prompts/tool_html_passthrough.prompt +0 -0
  65. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
  66. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
  67. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/__init__.py +0 -0
  68. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
  69. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/call_service.py +0 -0
  70. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  71. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  72. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  73. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  74. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  75. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  76. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  77. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/google_auth_client.py +0 -0
  78. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/google_chat_app.py +0 -0
  79. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
  80. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/inference_handler.py +0 -0
  81. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
  82. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
  83. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
  84. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
  85. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/llm_response.py +0 -0
  86. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  87. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/__init__.py +0 -0
  88. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/api_key_repo.py +0 -0
  89. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/database_manager.py +0 -0
  90. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/document_repo.py +0 -0
  91. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
  92. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
  93. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  94. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/memory_repo.py +0 -0
  95. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/models.py +0 -0
  96. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/profile_repo.py +0 -0
  97. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
  98. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
  99. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
  100. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/repositories/vs_repo.py +0 -0
  101. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/__init__.py +0 -0
  102. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/api_key_service.py +0 -0
  103. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/attachment_policy_service.py +0 -0
  104. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/auth_service.py +0 -0
  105. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/benchmark_service.py +0 -0
  106. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/branding_service.py +0 -0
  107. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/company_context_service.py +0 -0
  108. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/context_builder_service.py +0 -0
  109. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/dispatcher_service.py +0 -0
  110. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/embedding_service.py +0 -0
  111. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/excel_service.py +0 -0
  112. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/file_processor_service.py +0 -0
  113. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/history_manager_service.py +0 -0
  114. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/http_tool_service.py +0 -0
  115. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/i18n_service.py +0 -0
  116. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/inference_service.py +0 -0
  117. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/jwt_service.py +0 -0
  118. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/knowledge_base_service.py +0 -0
  119. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/language_service.py +0 -0
  120. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/license_service.py +0 -0
  121. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/mail_service.py +0 -0
  122. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/memory_compiler_service.py +0 -0
  123. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/memory_lint_service.py +0 -0
  124. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
  125. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/memory_service.py +0 -0
  126. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/memory_wiki_service.py +0 -0
  127. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
  128. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/noop_memory_lint_trigger.py +0 -0
  129. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/__init__.py +0 -0
  130. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/contracts.py +0 -0
  131. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
  132. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
  133. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
  134. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
  135. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
  136. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
  137. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
  138. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
  139. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/parsers/validator.py +0 -0
  140. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/pdf_service.py +0 -0
  141. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/profile_service.py +0 -0
  142. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/prompt_resource_service.py +0 -0
  143. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
  144. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/sql_dataset_service.py +0 -0
  145. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/sql_service.py +0 -0
  146. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/sql_source_service.py +0 -0
  147. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/storage_service.py +0 -0
  148. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/structured_output_service.py +0 -0
  149. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/system_tools.py +0 -0
  150. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/tool_service.py +0 -0
  151. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/user_feedback_service.py +0 -0
  152. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/user_session_context_service.py +0 -0
  153. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/visual_kb_service.py +0 -0
  154. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/visual_tool_service.py +0 -0
  155. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/warmup_service.py +0 -0
  156. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/web_search/__init__.py +0 -0
  157. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
  158. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
  159. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
  160. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/services/web_search_service.py +0 -0
  161. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  162. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
  163. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
  164. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
  165. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  166. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_help_content.js +0 -0
  167. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_history_button.js +0 -0
  168. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
  169. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_main.js +0 -0
  170. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
  171. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
  172. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
  173. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
  174. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
  175. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
  176. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/styles/chat_modal.css +0 -0
  177. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/styles/chat_public.css +0 -0
  178. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/styles/documents.css +0 -0
  179. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/styles/landing_page.css +0 -0
  180. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/styles/llm_output.css +0 -0
  181. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/static/styles/onboarding.css +0 -0
  182. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/system_prompts/__init__.py +0 -0
  183. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/_company_header.html +0 -0
  184. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/_login_widget.html +0 -0
  185. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/base.html +0 -0
  186. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/change_password.html +0 -0
  187. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/chat.html +0 -0
  188. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
  189. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/chat_modals.html +0 -0
  190. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/error.html +0 -0
  191. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/forgot_password.html +0 -0
  192. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/home_hosted_default.html +0 -0
  193. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
  194. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/onboarding_shell.html +0 -0
  195. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/pdf/base.html +0 -0
  196. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/pdf/letter.html +0 -0
  197. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/pdf/report.html +0 -0
  198. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/pdf/simple.html +0 -0
  199. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/templates/signup.html +0 -0
  200. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/__init__.py +0 -0
  201. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/api_key_api_view.py +0 -0
  202. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/base_login_view.py +0 -0
  203. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/categories_api_view.py +0 -0
  204. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/change_password_view.py +0 -0
  205. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
  206. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/chat_view.py +0 -0
  207. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/configuration_api_view.py +0 -0
  208. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/connectors_api_view.py +0 -0
  209. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/embedding_api_view.py +0 -0
  210. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/forgot_password_view.py +0 -0
  211. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/help_content_api_view.py +0 -0
  212. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/history_api_view.py +0 -0
  213. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/home_view.py +0 -0
  214. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/init_context_api_view.py +0 -0
  215. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/llmquery_api_view.py +0 -0
  216. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/load_document_api_view.py +0 -0
  217. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/login_view.py +0 -0
  218. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/logout_api_view.py +0 -0
  219. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/memory_api_view.py +0 -0
  220. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/profile_api_view.py +0 -0
  221. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/prompt_api_view.py +0 -0
  222. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
  223. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
  224. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/rag_api_view.py +0 -0
  225. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/root_redirect_view.py +0 -0
  226. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/signup_view.py +0 -0
  227. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/static_page_view.py +0 -0
  228. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/tool_api_view.py +0 -0
  229. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
  230. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/users_api_view.py +0 -0
  231. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit/views/verify_user_view.py +0 -0
  232. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  233. {iatoolkit-2.4.1 → iatoolkit-2.5.1}/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.4.1
3
+ Version: 2.5.1
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 = ["system_prompts/*.prompt", "templates/**/*", "static/**/*", "locales/*.yaml", "config/*.yaml"]
32
+ iatoolkit = ["templates/**/*", "static/**/*", "locales/*.yaml", "config/*.yaml", "config/system_prompts/*.prompt"]
@@ -2,6 +2,7 @@ bcrypt==4.2.1
2
2
  anthropic>=0.83.0
3
3
  boto3==1.36.22
4
4
  botocore==1.36.22
5
+ braintrust>=0.17.0
5
6
  build==1.2.2.post1
6
7
  click==8.1.8
7
8
  cryptography==44.0.3
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
- __version__ = "2.4.1"
6
+ __version__ = "2.5.1"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -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)
@@ -33,7 +33,8 @@ class AnthropicAdapter:
33
33
  images: Optional[List[Dict]] = None,
34
34
  attachments: Optional[List[Dict]] = None,
35
35
  store: Optional[bool] = None,
36
- metadata: Optional[Dict[str, str]] = None) -> LLMResponse:
36
+ metadata: Optional[Dict[str, str]] = None,
37
+ telemetry_execution: Any = None) -> LLMResponse:
37
38
  """
38
39
  Calls Anthropic Messages API and maps the response to common LLMResponse.
39
40
 
@@ -76,6 +77,8 @@ class AnthropicAdapter:
76
77
  if tool_choice_payload:
77
78
  params["tool_choice"] = tool_choice_payload
78
79
 
80
+ self._record_telemetry_input(telemetry_execution, params)
81
+
79
82
  anthropic_response = self.client.messages.create(**params)
80
83
  return self._map_anthropic_response(anthropic_response, model)
81
84
 
@@ -87,6 +90,12 @@ class AnthropicAdapter:
87
90
  error_message
88
91
  ) from e
89
92
 
93
+ @staticmethod
94
+ def _record_telemetry_input(telemetry_execution: Any, payload: Dict[str, Any]) -> None:
95
+ record_input = getattr(telemetry_execution, "record_input", None)
96
+ if callable(record_input):
97
+ record_input(payload)
98
+
90
99
  def _prepare_messages(self, input_items: List[Dict], images: List[Dict]) -> tuple[Optional[str], List[Dict]]:
91
100
  system_parts: List[str] = []
92
101
  messages: List[Dict] = []
@@ -53,6 +53,7 @@ class GeminiAdapter:
53
53
  attachments: Optional[List[Dict]] = None,
54
54
  store: Optional[bool] = None,
55
55
  metadata: Optional[Dict[str, str]] = None,
56
+ telemetry_execution: Any = None,
56
57
  ) -> LLMResponse:
57
58
  try:
58
59
  _ = store
@@ -105,6 +106,15 @@ class GeminiAdapter:
105
106
  else:
106
107
  raise
107
108
 
109
+ self._record_telemetry_input(
110
+ telemetry_execution,
111
+ {
112
+ "model": model,
113
+ "contents": contents,
114
+ "config": dict(config_kwargs),
115
+ },
116
+ )
117
+
108
118
  # call the new SDK
109
119
  response = self.client.models.generate_content(
110
120
  model=model,
@@ -144,6 +154,12 @@ class GeminiAdapter:
144
154
 
145
155
  raise IAToolkitException(IAToolkitException.ErrorType.LLM_ERROR, error_message)
146
156
 
157
+ @staticmethod
158
+ def _record_telemetry_input(telemetry_execution: Any, payload: Dict[str, Any]) -> None:
159
+ record_input = getattr(telemetry_execution, "record_input", None)
160
+ if callable(record_input):
161
+ record_input(payload)
162
+
147
163
  def _extract_system_and_filter_input(self, input_list: List[Dict]) -> tuple[Optional[str], List[Dict]]:
148
164
  """Extrae el mensaje de sistema para usarlo en system_instruction."""
149
165
  system_parts = []
@@ -4,10 +4,9 @@
4
4
  # IAToolkit is open source software.
5
5
 
6
6
  import logging
7
- from typing import Dict, List, Optional
7
+ from typing import Any, Dict, List, Optional
8
8
  from iatoolkit.infra.llm_response import LLMResponse, ToolCall, Usage
9
9
  from iatoolkit.common.exceptions import IAToolkitException
10
- from typing import List
11
10
  import mimetypes
12
11
  import re
13
12
  import base64
@@ -31,7 +30,8 @@ class OpenAIAdapter:
31
30
  images: Optional[List[Dict]] = None,
32
31
  attachments: Optional[List[Dict]] = None,
33
32
  store: Optional[bool] = None,
34
- metadata: Optional[Dict[str, str]] = None) -> LLMResponse:
33
+ metadata: Optional[Dict[str, str]] = None,
34
+ telemetry_execution: Any = None) -> LLMResponse:
35
35
  """Llamada a la API de OpenAI y mapeo a estructura común"""
36
36
  try:
37
37
  # Handle multimodal input if images are present
@@ -64,6 +64,8 @@ class OpenAIAdapter:
64
64
  if tool_choice_payload is not None:
65
65
  params['tool_choice'] = tool_choice_payload
66
66
 
67
+ self._record_telemetry_input(telemetry_execution, params)
68
+
67
69
  # Llamar a la API de OpenAI
68
70
  openai_response = self.client.responses.create(**params)
69
71
 
@@ -76,6 +78,12 @@ class OpenAIAdapter:
76
78
 
77
79
  raise IAToolkitException(IAToolkitException.ErrorType.LLM_ERROR, error_message)
78
80
 
81
+ @staticmethod
82
+ def _record_telemetry_input(telemetry_execution: Any, payload: Dict[str, Any]) -> None:
83
+ record_input = getattr(telemetry_execution, "record_input", None)
84
+ if callable(record_input):
85
+ record_input(payload)
86
+
79
87
  @staticmethod
80
88
  def _map_tool_choice(tool_choice: str, tools_payload: List[Dict]) -> Optional[Dict | str]:
81
89
  if tool_choice in ("", None, "auto"):
@@ -48,6 +48,7 @@ class OpenAICompatibleChatAdapter:
48
48
  text = kwargs.get("text") or {}
49
49
  reasoning = kwargs.get("reasoning")
50
50
  metadata = kwargs.get("metadata")
51
+ telemetry_execution = kwargs.get("telemetry_execution")
51
52
 
52
53
  try:
53
54
  messages: List[Dict[str, Any]] = []
@@ -111,6 +112,7 @@ class OpenAICompatibleChatAdapter:
111
112
  call_kwargs["parallel_tool_calls"] = bool(kwargs.get("parallel_tool_calls"))
112
113
 
113
114
  self._extend_call_kwargs(call_kwargs, kwargs)
115
+ self._record_telemetry_input(telemetry_execution, call_kwargs)
114
116
 
115
117
  logging.debug(
116
118
  "[%sAdapter] Calling chat.completions API with %s messages.",
@@ -130,6 +132,12 @@ class OpenAICompatibleChatAdapter:
130
132
  f"{self.provider_label} error: {ex}"
131
133
  ) from ex
132
134
 
135
+ @staticmethod
136
+ def _record_telemetry_input(telemetry_execution: Any, payload: Dict[str, Any]) -> None:
137
+ record_input = getattr(telemetry_execution, "record_input", None)
138
+ if callable(record_input):
139
+ record_input(payload)
140
+
133
141
  def _extend_call_kwargs(self, call_kwargs: Dict[str, Any], kwargs: Dict[str, Any]) -> None:
134
142
  _ = call_kwargs
135
143
  _ = kwargs
@@ -17,6 +17,7 @@ from iatoolkit.infra.llm_response import LLMResponse
17
17
  from iatoolkit.common.model_registry import ModelRegistry
18
18
  from iatoolkit.common.interfaces.secret_provider import SecretProvider
19
19
  from iatoolkit.common.secret_resolver import resolve_secret
20
+ from iatoolkit.services.telemetry_service import NoopTelemetryService
20
21
 
21
22
  from openai import OpenAI, Timeout # For OpenAI and xAI (OpenAI-compatible)
22
23
 
@@ -53,6 +54,7 @@ class LLMProxy:
53
54
  configuration_service: ConfigurationService,
54
55
  model_registry: ModelRegistry,
55
56
  secret_provider: SecretProvider,
57
+ telemetry_service=None,
56
58
  ):
57
59
  """
58
60
  Init a new instance of the proxy. It can be a base factory or a working instance with configured clients.
@@ -62,10 +64,23 @@ class LLMProxy:
62
64
  self.configuration_service = configuration_service
63
65
  self.model_registry = model_registry
64
66
  self.secret_provider = secret_provider
67
+ self._telemetry_service = telemetry_service
65
68
 
66
69
  # adapter cache by (provider, api_key, base_url)
67
70
  self.adapters: Dict[Tuple[Any, ...], Any] = {}
68
71
 
72
+ @property
73
+ def telemetry_service(self):
74
+ if self._telemetry_service is None:
75
+ try:
76
+ from iatoolkit import current_iatoolkit
77
+ from iatoolkit.services.telemetry_service import TelemetryService
78
+
79
+ self._telemetry_service = current_iatoolkit().get_injector().get(TelemetryService)
80
+ except Exception:
81
+ self._telemetry_service = NoopTelemetryService()
82
+ return self._telemetry_service
83
+
69
84
  # -------------------------------------------------------------------------
70
85
  # Public API
71
86
  # -------------------------------------------------------------------------
@@ -81,6 +96,9 @@ class LLMProxy:
81
96
  "company_short_name is required in kwargs to resolve LLM credentials."
82
97
  )
83
98
 
99
+ telemetry_request = kwargs.pop("telemetry_request", None)
100
+ telemetry_execution = kwargs.pop("telemetry_execution", None)
101
+
84
102
  # Determine the provider based on the model name
85
103
  provider = self._resolve_provider_for_company_model(
86
104
  company_short_name=company_short_name,
@@ -92,6 +110,7 @@ class LLMProxy:
92
110
  adapter = self._get_or_create_adapter(
93
111
  provider=provider,
94
112
  company_short_name=company_short_name,
113
+ telemetry_request=telemetry_request,
95
114
  )
96
115
 
97
116
  request_kwargs = self._apply_provider_request_overrides(
@@ -104,6 +123,8 @@ class LLMProxy:
104
123
  model_config=model_config,
105
124
  request_kwargs=request_kwargs,
106
125
  )
126
+ if telemetry_execution is not None:
127
+ request_kwargs["telemetry_execution"] = telemetry_execution
107
128
 
108
129
  # Delegate to the adapter (OpenAI, Gemini, DeepSeek, xAI, Anthropic, etc.)
109
130
  return adapter.create_response(model=model, input=input, **request_kwargs)
@@ -146,7 +167,12 @@ class LLMProxy:
146
167
  # Adapter management
147
168
  # -------------------------------------------------------------------------
148
169
 
149
- def _get_or_create_adapter(self, provider: str, company_short_name: str) -> Any:
170
+ def _get_or_create_adapter(
171
+ self,
172
+ provider: str,
173
+ company_short_name: str,
174
+ telemetry_request: Dict[str, Any] | None = None,
175
+ ) -> Any:
150
176
  """
151
177
  Return an adapter instance for the given provider.
152
178
  If none exists yet, create it using a cached or new low-level client.
@@ -158,6 +184,24 @@ class LLMProxy:
158
184
  connect_timeout_seconds = client_config["connect_timeout_seconds"]
159
185
  read_timeout_seconds = client_config["read_timeout_seconds"]
160
186
  max_retries = client_config["max_retries"]
187
+ client = self._get_or_create_client(
188
+ provider,
189
+ api_key,
190
+ base_url=base_url,
191
+ default_headers=default_headers,
192
+ connect_timeout_seconds=connect_timeout_seconds,
193
+ read_timeout_seconds=read_timeout_seconds,
194
+ max_retries=max_retries,
195
+ )
196
+
197
+ wrapped_client = self.telemetry_service.wrap_client_for_request(
198
+ llm_provider=provider,
199
+ client=client,
200
+ request=telemetry_request,
201
+ )
202
+ if wrapped_client is not client:
203
+ return self._build_adapter(provider, wrapped_client)
204
+
161
205
  adapter_cache_key = (
162
206
  provider,
163
207
  api_key or "",
@@ -168,42 +212,31 @@ class LLMProxy:
168
212
  max_retries,
169
213
  )
170
214
 
171
- # If already created for this provider+key, just return it
172
215
  if adapter_cache_key in self.adapters and self.adapters[adapter_cache_key] is not None:
173
216
  return self.adapters[adapter_cache_key]
174
217
 
175
- # Otherwise, create low-level client from configuration
176
- client = self._get_or_create_client(
177
- provider,
178
- api_key,
179
- base_url=base_url,
180
- default_headers=default_headers,
181
- connect_timeout_seconds=connect_timeout_seconds,
182
- read_timeout_seconds=read_timeout_seconds,
183
- max_retries=max_retries,
184
- )
218
+ adapter = self._build_adapter(provider, client)
219
+ self.adapters[adapter_cache_key] = adapter
220
+ return adapter
185
221
 
186
- # Wrap client with the correct adapter
222
+ def _build_adapter(self, provider: str, client: Any) -> Any:
187
223
  if provider == self.PROVIDER_OPENAI:
188
- adapter = OpenAIAdapter(client)
189
- elif provider == self.PROVIDER_GEMINI:
190
- adapter = GeminiAdapter(client)
191
- elif provider == self.PROVIDER_DEEPSEEK:
192
- adapter = DeepseekAdapter(client)
193
- elif provider == self.PROVIDER_OPENAI_COMPATIBLE:
194
- adapter = OpenAICompatibleChatAdapter(client, provider_label="OpenAI-compatible")
195
- elif provider == self.PROVIDER_OPENROUTER:
196
- adapter = OpenRouterAdapter(client)
197
- elif provider == self.PROVIDER_ANTHROPIC:
198
- adapter = AnthropicAdapter(client)
199
- else:
200
- raise IAToolkitException(
201
- IAToolkitException.ErrorType.MODEL,
202
- f"Provider not supported in _get_or_create_adapter: {provider}"
203
- )
224
+ return OpenAIAdapter(client)
225
+ if provider == self.PROVIDER_GEMINI:
226
+ return GeminiAdapter(client)
227
+ if provider == self.PROVIDER_DEEPSEEK:
228
+ return DeepseekAdapter(client)
229
+ if provider == self.PROVIDER_OPENAI_COMPATIBLE:
230
+ return OpenAICompatibleChatAdapter(client, provider_label="OpenAI-compatible")
231
+ if provider == self.PROVIDER_OPENROUTER:
232
+ return OpenRouterAdapter(client)
233
+ if provider == self.PROVIDER_ANTHROPIC:
234
+ return AnthropicAdapter(client)
204
235
 
205
- self.adapters[adapter_cache_key] = adapter
206
- return adapter
236
+ raise IAToolkitException(
237
+ IAToolkitException.ErrorType.MODEL,
238
+ f"Provider not supported in _get_or_create_adapter: {provider}"
239
+ )
207
240
 
208
241
  def _apply_provider_request_overrides(
209
242
  self,
@@ -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"
@@ -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"
@@ -521,6 +521,56 @@ class ConfigurationService:
521
521
  if raw_x_title is not None and (not isinstance(raw_x_title, str) or not raw_x_title.strip()):
522
522
  add_error("llm.openrouter.x_title", "Must be a non-empty string.")
523
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
+
524
574
  # 3. Embedding Provider
525
575
  if isinstance(config.get("embedding_provider"), dict):
526
576
  if not config.get("embedding_provider", {}).get("provider"):
@@ -678,6 +728,7 @@ class ConfigurationService:
678
728
  "text_verbosity",
679
729
  "prompt_version",
680
730
  "prompt_variant",
731
+ "telemetry_enabled",
681
732
  }
682
733
  unknown_option_keys = sorted(
683
734
  key for key in llm_request_options.keys() if key not in allowed_option_keys
@@ -724,6 +775,15 @@ class ConfigurationService:
724
775
  "Must be a non-empty string.",
725
776
  )
726
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
+
727
787
  tool_policy = prompt.get("tool_policy")
728
788
  if tool_policy is not None:
729
789
  if not isinstance(tool_policy, dict):
@@ -1110,6 +1170,12 @@ class ConfigurationService:
1110
1170
  provider_cfg = providers_cfg.get(candidate)
1111
1171
  return dict(provider_cfg) if isinstance(provider_cfg, dict) else {}
1112
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
+
1113
1179
 
1114
1180
  def _load_and_merge_configs(self, company_short_name: str) -> dict:
1115
1181
  """
@@ -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()
@@ -138,6 +155,8 @@ class llmClient:
138
155
  attachments=active_attachments,
139
156
  store=store,
140
157
  metadata=request_metadata,
158
+ telemetry_request=telemetry_request,
159
+ telemetry_execution=telemetry_execution,
141
160
  )
142
161
  stats = self.get_stats(response)
143
162
 
@@ -246,6 +265,8 @@ class llmClient:
246
265
  attachments=active_attachments,
247
266
  store=store,
248
267
  metadata=request_metadata,
268
+ telemetry_request=telemetry_request,
269
+ telemetry_execution=telemetry_execution,
249
270
  )
250
271
  stats_fcall = self.add_stats(stats_fcall, self.get_stats(response))
251
272
 
@@ -285,6 +306,22 @@ class llmClient:
285
306
  answer_time=stats['response_time']
286
307
  )
287
308
  self.llmquery_repo.add_query(query)
309
+ telemetry_execution.finalize(
310
+ query_id=query.id,
311
+ success=decoded_response.get('status', False),
312
+ answer_preview=decoded_response.get('answer', ''),
313
+ metrics={
314
+ "total_tokens": combined_stats.get("total_tokens"),
315
+ "response_time": combined_stats.get("response_time"),
316
+ "sql_retry_count": combined_stats.get("sql_retry_count"),
317
+ },
318
+ )
319
+ telemetry_stats = telemetry_execution.build_stats()
320
+ if telemetry_stats:
321
+ query.stats = dict(query.stats or {})
322
+ query.stats["telemetry"] = telemetry_stats
323
+ self.llmquery_repo.commit()
324
+ combined_stats = dict(query.stats or {})
288
325
  logging.info(f"finish llm call in {int(time.time() - start_time)} secs..")
289
326
  if function_calls:
290
327
  logging.info(f"time within the function calls {f_call_time:.1f} secs.")
@@ -312,9 +349,17 @@ class llmClient:
312
349
  except SQLAlchemyError as db_error:
313
350
  # rollback
314
351
  self.llmquery_repo.session.rollback()
352
+ telemetry_execution.finalize(
353
+ success=False,
354
+ error_message=str(db_error),
355
+ )
315
356
  logging.error(f"Error de base de datos: {str(db_error)}")
316
357
  raise db_error
317
358
  except OperationalError as e:
359
+ telemetry_execution.finalize(
360
+ success=False,
361
+ error_message=str(e),
362
+ )
318
363
  logging.error(f"Operational error: {str(e)}")
319
364
  raise e
320
365
  except Exception as e:
@@ -331,6 +376,15 @@ class llmClient:
331
376
  function_calls=f_calls,
332
377
  )
333
378
  self.llmquery_repo.add_query(query)
379
+ telemetry_execution.finalize(
380
+ query_id=query.id,
381
+ success=False,
382
+ error_message=error_message,
383
+ )
384
+ telemetry_stats = telemetry_execution.build_stats()
385
+ if telemetry_stats:
386
+ query.stats = {"telemetry": telemetry_stats}
387
+ self.llmquery_repo.commit()
334
388
 
335
389
  # in case of context error
336
390
  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: