iatoolkit 2.7.2__tar.gz → 2.9.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 (237) hide show
  1. {iatoolkit-2.7.2/src/iatoolkit.egg-info → iatoolkit-2.9.0}/PKG-INFO +1 -1
  2. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/__init__.py +1 -1
  3. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/routes.py +4 -0
  4. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/core.py +4 -0
  5. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/locales/en.yaml +61 -1
  6. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/locales/es.yaml +61 -0
  7. iatoolkit-2.9.0/src/iatoolkit/repositories/mcp_personal_access_token_repo.py +63 -0
  8. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/models.py +28 -0
  9. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/knowledge_base_service.py +66 -0
  10. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/llm_client_service.py +5 -0
  11. iatoolkit-2.9.0/src/iatoolkit/services/mcp_personal_access_token_service.py +166 -0
  12. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/query_service.py +3 -0
  13. iatoolkit-2.9.0/src/iatoolkit/templates/account.html +604 -0
  14. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/chat.html +11 -2
  15. iatoolkit-2.9.0/src/iatoolkit/views/account_view.py +178 -0
  16. {iatoolkit-2.7.2 → iatoolkit-2.9.0/src/iatoolkit.egg-info}/PKG-INFO +1 -1
  17. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit.egg-info/SOURCES.txt +4 -0
  18. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/LICENSE +0 -0
  19. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/LICENSE_COMMUNITY.md +0 -0
  20. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/pyproject.toml +0 -0
  21. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/readme.md +0 -0
  22. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/requirements.txt +0 -0
  23. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/setup.cfg +0 -0
  24. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/base_company.py +0 -0
  25. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/cli_commands.py +0 -0
  26. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/__init__.py +0 -0
  27. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/exceptions.py +0 -0
  28. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
  29. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
  30. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
  31. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
  32. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/memory_lint_trigger.py +0 -0
  33. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
  34. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
  35. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
  36. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/model_registry.py +0 -0
  37. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/secret_resolver.py +0 -0
  38. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/session_manager.py +0 -0
  39. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/common/util.py +0 -0
  40. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/company_registry.py +0 -0
  41. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/__init__.py +0 -0
  42. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
  43. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
  44. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
  45. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
  46. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
  47. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
  48. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
  49. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
  50. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
  51. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
  52. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
  53. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
  54. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
  55. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
  56. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
  57. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
  58. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/sql_core.prompt +0 -0
  59. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
  60. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/sql_rules.prompt +0 -0
  61. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
  62. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
  63. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
  64. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/__init__.py +0 -0
  65. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
  66. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/call_service.py +0 -0
  67. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  68. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  69. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  70. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  71. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  72. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  73. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  74. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
  75. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
  76. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
  77. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/inference_handler.py +0 -0
  78. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
  79. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
  80. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
  81. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
  82. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
  83. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
  84. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
  85. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
  86. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_proxy.py +0 -0
  87. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/llm_response.py +0 -0
  88. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  89. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/__init__.py +0 -0
  90. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
  91. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/database_manager.py +0 -0
  92. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/document_repo.py +0 -0
  93. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
  94. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
  95. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  96. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/memory_repo.py +0 -0
  97. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
  98. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
  99. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
  100. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
  101. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
  102. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/__init__.py +0 -0
  103. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/api_key_service.py +0 -0
  104. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
  105. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/auth_service.py +0 -0
  106. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/benchmark_service.py +0 -0
  107. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/branding_service.py +0 -0
  108. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/company_context_service.py +0 -0
  109. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/configuration_service.py +0 -0
  110. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/context_builder_service.py +0 -0
  111. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
  112. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/embedding_service.py +0 -0
  113. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/excel_service.py +0 -0
  114. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/file_processor_service.py +0 -0
  115. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/history_manager_service.py +0 -0
  116. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/http_tool_service.py +0 -0
  117. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/i18n_service.py +0 -0
  118. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/inference_service.py +0 -0
  119. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/jwt_service.py +0 -0
  120. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/language_service.py +0 -0
  121. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/license_service.py +0 -0
  122. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/mail_service.py +0 -0
  123. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/memory_compiler_service.py +0 -0
  124. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/memory_lint_service.py +0 -0
  125. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
  126. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/memory_service.py +0 -0
  127. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/memory_wiki_service.py +0 -0
  128. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
  129. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/noop_memory_lint_trigger.py +0 -0
  130. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
  131. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
  132. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
  133. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
  134. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
  135. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
  136. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
  137. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
  138. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
  139. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
  140. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/parsers/validator.py +0 -0
  141. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/pdf_service.py +0 -0
  142. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/profile_service.py +0 -0
  143. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
  144. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/prompt_service.py +0 -0
  145. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
  146. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
  147. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/sql_service.py +0 -0
  148. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/sql_source_service.py +0 -0
  149. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/storage_service.py +0 -0
  150. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/structured_output_service.py +0 -0
  151. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
  152. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/system_tools.py +0 -0
  153. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/telemetry_service.py +0 -0
  154. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/tool_service.py +0 -0
  155. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
  156. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
  157. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
  158. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
  159. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/warmup_service.py +0 -0
  160. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
  161. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
  162. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
  163. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
  164. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/services/web_search_service.py +0 -0
  165. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  166. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
  167. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
  168. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
  169. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  170. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
  171. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
  172. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
  173. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_main.js +0 -0
  174. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
  175. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
  176. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
  177. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
  178. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
  179. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
  180. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
  181. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
  182. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/styles/documents.css +0 -0
  183. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
  184. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
  185. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
  186. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/system_prompts/__init__.py +0 -0
  187. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/_company_header.html +0 -0
  188. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/_login_widget.html +0 -0
  189. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/base.html +0 -0
  190. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/change_password.html +0 -0
  191. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
  192. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/chat_modals.html +0 -0
  193. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/error.html +0 -0
  194. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/forgot_password.html +0 -0
  195. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
  196. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
  197. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
  198. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/pdf/base.html +0 -0
  199. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
  200. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/pdf/report.html +0 -0
  201. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
  202. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/templates/signup.html +0 -0
  203. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/__init__.py +0 -0
  204. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
  205. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/base_login_view.py +0 -0
  206. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/categories_api_view.py +0 -0
  207. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/change_password_view.py +0 -0
  208. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
  209. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/chat_view.py +0 -0
  210. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
  211. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
  212. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
  213. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
  214. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
  215. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/history_api_view.py +0 -0
  216. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/home_view.py +0 -0
  217. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
  218. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
  219. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
  220. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/login_view.py +0 -0
  221. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/logout_api_view.py +0 -0
  222. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/memory_api_view.py +0 -0
  223. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/profile_api_view.py +0 -0
  224. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
  225. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
  226. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
  227. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/rag_api_view.py +0 -0
  228. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
  229. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/signup_view.py +0 -0
  230. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/static_page_view.py +0 -0
  231. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/tool_api_view.py +0 -0
  232. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
  233. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/users_api_view.py +0 -0
  234. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit/views/verify_user_view.py +0 -0
  235. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  236. {iatoolkit-2.7.2 → iatoolkit-2.9.0}/src/iatoolkit.egg-info/requires.txt +0 -0
  237. {iatoolkit-2.7.2 → iatoolkit-2.9.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.7.2
3
+ Version: 2.9.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.7.2"
6
+ __version__ = "2.9.0"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -39,6 +39,7 @@ def register_views(app):
39
39
  from iatoolkit.views.logout_api_view import LogoutApiView
40
40
  from iatoolkit.views.home_view import HomeView
41
41
  from iatoolkit.views.chat_view import ChatView
42
+ from iatoolkit.views.account_view import AccountView
42
43
  from iatoolkit.views.static_page_view import StaticPageView
43
44
  from iatoolkit.views.root_redirect_view import RootRedirectView
44
45
  from iatoolkit.views.users_api_view import UsersApiView
@@ -69,6 +70,9 @@ def register_views(app):
69
70
  # Chat Route (Direct Access)
70
71
  app.add_url_rule('/<company_short_name>/chat',
71
72
  view_func=ChatView.as_view('chat'))
73
+ app.add_url_rule('/<company_short_name>/account',
74
+ view_func=AccountView.as_view('account'),
75
+ methods=['GET', 'POST'])
72
76
 
73
77
  # this endpoint is called when onboarding_shell finish the context load
74
78
  app.add_url_rule(
@@ -355,6 +355,7 @@ class IAToolkit:
355
355
  from iatoolkit.repositories.profile_repo import ProfileRepo
356
356
  from iatoolkit.repositories.llm_query_repo import LLMQueryRepo
357
357
  from iatoolkit.repositories.memory_repo import MemoryRepo
358
+ from iatoolkit.repositories.mcp_personal_access_token_repo import McpPersonalAccessTokenRepo
358
359
  from iatoolkit.repositories.sql_dataset_repo import SqlDatasetRepo
359
360
  from iatoolkit.repositories.sql_source_repo import SqlSourceRepo
360
361
  from iatoolkit.repositories.vs_repo import VSRepo
@@ -371,6 +372,7 @@ class IAToolkit:
371
372
  binder.bind(ProfileRepo, to=ProfileRepo)
372
373
  binder.bind(LLMQueryRepo, to=LLMQueryRepo)
373
374
  binder.bind(MemoryRepo, to=MemoryRepo)
375
+ binder.bind(McpPersonalAccessTokenRepo, to=McpPersonalAccessTokenRepo)
374
376
  binder.bind(SqlDatasetRepo, to=SqlDatasetRepo)
375
377
  binder.bind(SqlSourceRepo, to=SqlSourceRepo)
376
378
  binder.bind(VSRepo, to=VSRepo)
@@ -403,6 +405,7 @@ class IAToolkit:
403
405
  from iatoolkit.services.mail_service import MailService
404
406
  from iatoolkit.services.memory_compiler_service import MemoryCompilerService
405
407
  from iatoolkit.services.memory_service import MemoryService
408
+ from iatoolkit.services.mcp_personal_access_token_service import McpPersonalAccessTokenService
406
409
  from iatoolkit.services.memory_wiki_service import MemoryWikiService
407
410
  from iatoolkit.services.profile_service import ProfileService
408
411
  from iatoolkit.services.jwt_service import JWTService
@@ -446,6 +449,7 @@ class IAToolkit:
446
449
  binder.bind(MemoryWikiService, to=MemoryWikiService)
447
450
  binder.bind(MemoryCompilerService, to=MemoryCompilerService)
448
451
  binder.bind(MemoryService, to=MemoryService)
452
+ binder.bind(McpPersonalAccessTokenService, to=McpPersonalAccessTokenService)
449
453
  binder.bind(ProfileService, to=ProfileService)
450
454
  binder.bind(JWTService, to=JWTService)
451
455
  binder.bind(SqlDatasetService, to=SqlDatasetService)
@@ -54,6 +54,8 @@ ui:
54
54
  task_reconciliation_requeued: "Requeued"
55
55
  task_reconciliation_normalized: "Normalized"
56
56
  task_reconciliation_failed: "Recovered As Failed"
57
+ source_mcp: "MCP"
58
+ source_standard_ui: "Standard UI"
57
59
 
58
60
  inspector:
59
61
  title: "Interaction Inspector"
@@ -68,6 +70,7 @@ ui:
68
70
  performance: "Performance"
69
71
  latency: "Latency"
70
72
  tokens: "Total Tokens"
73
+ source: "Source"
71
74
  tools_executed: "Tools Executed"
72
75
  no_tools: "No tools used in this session."
73
76
  primary_input: "Primary Input"
@@ -131,6 +134,59 @@ ui:
131
134
  prompts_available: "Available prompts"
132
135
  init_context: "Initializing the context ..."
133
136
 
137
+ account:
138
+ title: "My Account"
139
+ back_to_chat: "Back to chat"
140
+ menu_general: "General"
141
+ menu_mcp_tokens: "MCP Tokens"
142
+ general_title: "Personal settings"
143
+ general_description: "Manage your personal access, integrations, and the settings connected to your account."
144
+ general_tag: "Personal workspace"
145
+ general_profile_label: "Profile"
146
+ general_tokens_label: "Integrations"
147
+ general_tokens_title: "MCP access tokens"
148
+ general_tokens_description: "Create and manage bearer tokens for MCP clients that do not complete the OAuth flow directly."
149
+ general_tokens_action: "Open MCP tokens"
150
+ mcp_tokens_create_title: "Create MCP token"
151
+ mcp_tokens_create_description: "Generate a personal access token for MCP clients that require a bearer token."
152
+ mcp_tokens_list_title: "MCP access tokens"
153
+ mcp_tokens_count_suffix: "tokens"
154
+ mcp_tokens_empty: "You have not created any MCP tokens yet."
155
+ mcp_connection_title: "Connection snippets"
156
+ mcp_connection_description: "Use these snippets with MCP clients that connect through a fixed bearer token instead of completing OAuth in-app."
157
+ mcp_connection_tag: "Ready to paste"
158
+ mcp_connection_server_url: "Server URL"
159
+ mcp_connection_json_label: "JSON config"
160
+ mcp_connection_copy_url_button: "Copy URL"
161
+ mcp_connection_copy_json_button: "Copy JSON"
162
+ mcp_connection_url_copy_success: "Server URL copied."
163
+ mcp_connection_json_copy_success: "JSON config copied."
164
+ mcp_connection_copy_error: "Could not copy the MCP connection snippet."
165
+ mcp_connection_placeholder_help: "Replace <YOUR_MCP_TOKEN> with one of your active MCP personal access tokens."
166
+ mcp_token_name: "Token name"
167
+ mcp_token_name_placeholder: "Claude Desktop, PyCharm, Codex..."
168
+ mcp_token_expiry_days: "Expires in (days)"
169
+ mcp_token_created_at: "Created"
170
+ mcp_token_expires_at: "Expires"
171
+ mcp_token_last_used_at: "Last used"
172
+ mcp_token_status: "Status"
173
+ mcp_token_actions: "Actions"
174
+ mcp_token_status_active: "Active"
175
+ mcp_token_status_revoked: "Revoked"
176
+ mcp_token_status_expired: "Expired"
177
+ mcp_token_create_button: "Create token"
178
+ mcp_token_copy_button: "Copy"
179
+ mcp_token_copy_success: "Token copied."
180
+ mcp_token_copy_error: "Could not copy the token."
181
+ mcp_token_revoke_button: "Revoke"
182
+ mcp_token_created_title: "Copy this token now"
183
+ mcp_token_created_help: "For security reasons, this token is shown only once."
184
+ mcp_token_created_token_label: "Bearer token"
185
+ mcp_token_created_json_label: "Ready-to-paste JSON config"
186
+ mcp_token_created_flash: "MCP token created."
187
+ mcp_token_revoked_flash: "MCP token revoked."
188
+ mcp_token_unknown_action: "Unknown account action."
189
+
134
190
  memory:
135
191
  title: "Memory"
136
192
  capture_title: "Save something"
@@ -1417,8 +1473,12 @@ errors:
1417
1473
  authentication_required: "Authentication required. No session cookie or API Key provided."
1418
1474
  invalid_api_key: "Invalid or inactive API Key."
1419
1475
  api_key_name_required: "api_key_name parameter is required."
1420
-
1421
1476
  no_user_identifier_api: "No user_identifier provided for API call."
1477
+ mcp_pat_name_required: "Token name is required."
1478
+ mcp_pat_name_exists: "A token with that name already exists."
1479
+ mcp_pat_expiry_invalid: "Invalid expiration value."
1480
+ mcp_pat_invalid: "Invalid, expired, or revoked MCP token."
1481
+ mcp_pat_not_found: "MCP token not found."
1422
1482
  no_company_permissions: "Do not have permissions to admin this company."
1423
1483
  templates:
1424
1484
  company_not_found: "Company not found."
@@ -55,6 +55,8 @@ ui:
55
55
  task_reconciliation_requeued: "Reencoladas"
56
56
  task_reconciliation_normalized: "Normalizadas"
57
57
  task_reconciliation_failed: "Recuperadas como fallidas"
58
+ source_mcp: "MCP"
59
+ source_standard_ui: "UI estándar"
58
60
 
59
61
  inspector:
60
62
  title: "Inspector de Interacción"
@@ -69,6 +71,7 @@ ui:
69
71
  performance: "Rendimiento"
70
72
  latency: "Latencia"
71
73
  tokens: "Tokens Totales"
74
+ source: "Origen"
72
75
  tools_executed: "Herramientas Ejecutadas"
73
76
  no_tools: "No se usaron herramientas en esta sesión."
74
77
  primary_input: "Entrada Principal"
@@ -132,6 +135,59 @@ ui:
132
135
  prompts_available: "Prompts disponibles"
133
136
  init_context: "Inicializando el contexto de la IA ..."
134
137
 
138
+ account:
139
+ title: "Mi cuenta"
140
+ back_to_chat: "Volver al chat"
141
+ menu_general: "General"
142
+ menu_mcp_tokens: "Tokens MCP"
143
+ general_title: "Configuración personal"
144
+ general_description: "Administra tu acceso personal, tus integraciones y la configuración asociada a tu cuenta."
145
+ general_tag: "Espacio personal"
146
+ general_profile_label: "Perfil"
147
+ general_tokens_label: "Integraciones"
148
+ general_tokens_title: "Tokens de acceso MCP"
149
+ general_tokens_description: "Crea y administra bearer tokens para clientes MCP que no completan el flujo OAuth directamente."
150
+ general_tokens_action: "Abrir tokens MCP"
151
+ mcp_tokens_create_title: "Crear token MCP"
152
+ mcp_tokens_create_description: "Genera un token de acceso personal para clientes MCP que requieren un bearer token."
153
+ mcp_tokens_list_title: "Tokens de acceso MCP"
154
+ mcp_tokens_count_suffix: "tokens"
155
+ mcp_tokens_empty: "Todavía no has creado tokens MCP."
156
+ mcp_connection_title: "Snippets de conexión"
157
+ mcp_connection_description: "Usa estos snippets con clientes MCP que se conectan con un bearer token fijo en vez de completar OAuth dentro de la app."
158
+ mcp_connection_tag: "Listo para pegar"
159
+ mcp_connection_server_url: "URL del servidor"
160
+ mcp_connection_json_label: "Configuración JSON"
161
+ mcp_connection_copy_url_button: "Copiar URL"
162
+ mcp_connection_copy_json_button: "Copiar JSON"
163
+ mcp_connection_url_copy_success: "URL del servidor copiada."
164
+ mcp_connection_json_copy_success: "Configuración JSON copiada."
165
+ mcp_connection_copy_error: "No se pudo copiar el snippet de conexión MCP."
166
+ mcp_connection_placeholder_help: "Reemplaza <YOUR_MCP_TOKEN> por uno de tus tokens MCP activos."
167
+ mcp_token_name: "Nombre del token"
168
+ mcp_token_name_placeholder: "Claude Desktop, PyCharm, Codex..."
169
+ mcp_token_expiry_days: "Expira en (días)"
170
+ mcp_token_created_at: "Creado"
171
+ mcp_token_expires_at: "Expira"
172
+ mcp_token_last_used_at: "Último uso"
173
+ mcp_token_status: "Estado"
174
+ mcp_token_actions: "Acciones"
175
+ mcp_token_status_active: "Activo"
176
+ mcp_token_status_revoked: "Revocado"
177
+ mcp_token_status_expired: "Expirado"
178
+ mcp_token_create_button: "Crear token"
179
+ mcp_token_copy_button: "Copiar"
180
+ mcp_token_copy_success: "Token copiado."
181
+ mcp_token_copy_error: "No se pudo copiar el token."
182
+ mcp_token_revoke_button: "Revocar"
183
+ mcp_token_created_title: "Copia este token ahora"
184
+ mcp_token_created_help: "Por seguridad, este token se muestra solo una vez."
185
+ mcp_token_created_token_label: "Bearer token"
186
+ mcp_token_created_json_label: "Configuración JSON lista para pegar"
187
+ mcp_token_created_flash: "Token MCP creado."
188
+ mcp_token_revoked_flash: "Token MCP revocado."
189
+ mcp_token_unknown_action: "Acción de cuenta desconocida."
190
+
135
191
  memory:
136
192
  title: "Memoria"
137
193
  capture_title: "Guardar algo"
@@ -1420,6 +1476,11 @@ errors:
1420
1476
  no_user_identifier_api: "No se proporcionó user_identifier para la llamada a la API."
1421
1477
  no_company_permissions: "No tiene permisos para administrar esta empresa."
1422
1478
  api_key_name_required: "el parametro api_key_name es requerido."
1479
+ mcp_pat_name_required: "El nombre del token es obligatorio."
1480
+ mcp_pat_name_exists: "Ya existe un token con ese nombre."
1481
+ mcp_pat_expiry_invalid: "El valor de expiración es inválido."
1482
+ mcp_pat_invalid: "Token MCP inválido, expirado o revocado."
1483
+ mcp_pat_not_found: "Token MCP no encontrado."
1423
1484
 
1424
1485
  templates:
1425
1486
  company_not_found: "Empresa no encontrada."
@@ -0,0 +1,63 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+
5
+ from injector import inject
6
+
7
+ from iatoolkit.repositories.database_manager import DatabaseManager
8
+ from iatoolkit.repositories.models import McpPersonalAccessToken
9
+
10
+
11
+ class McpPersonalAccessTokenRepo:
12
+ @inject
13
+ def __init__(self, db_manager: DatabaseManager):
14
+ self.db_manager = db_manager
15
+ self.session = db_manager.get_session()
16
+
17
+ def create_token(self, token: McpPersonalAccessToken) -> McpPersonalAccessToken:
18
+ self.session.add(token)
19
+ self.session.commit()
20
+ return token
21
+
22
+ def save_token(self, token: McpPersonalAccessToken) -> McpPersonalAccessToken:
23
+ self.session.add(token)
24
+ self.session.commit()
25
+ return token
26
+
27
+ def rollback(self) -> None:
28
+ self.session.rollback()
29
+
30
+ def list_tokens_for_user(self, company_id: int, user_identifier: str) -> list[McpPersonalAccessToken]:
31
+ return (
32
+ self.session.query(McpPersonalAccessToken)
33
+ .filter_by(company_id=company_id, user_identifier=user_identifier)
34
+ .order_by(McpPersonalAccessToken.created_at.desc())
35
+ .all()
36
+ )
37
+
38
+ def get_token_by_id(self, company_id: int, user_identifier: str, token_id: int) -> McpPersonalAccessToken | None:
39
+ return (
40
+ self.session.query(McpPersonalAccessToken)
41
+ .filter_by(company_id=company_id, user_identifier=user_identifier, id=token_id)
42
+ .first()
43
+ )
44
+
45
+ def get_token_by_name(self, company_id: int, user_identifier: str, name: str) -> McpPersonalAccessToken | None:
46
+ return (
47
+ self.session.query(McpPersonalAccessToken)
48
+ .filter_by(company_id=company_id, user_identifier=user_identifier, name=name)
49
+ .first()
50
+ )
51
+
52
+ def get_active_token_by_hash(self, company_id: int, token_hash: str) -> McpPersonalAccessToken | None:
53
+ now = datetime.now()
54
+ return (
55
+ self.session.query(McpPersonalAccessToken)
56
+ .filter(
57
+ McpPersonalAccessToken.company_id == company_id,
58
+ McpPersonalAccessToken.token_hash == token_hash,
59
+ McpPersonalAccessToken.revoked_at.is_(None),
60
+ McpPersonalAccessToken.expires_at > now,
61
+ )
62
+ .first()
63
+ )
@@ -153,6 +153,11 @@ class Company(Base):
153
153
  back_populates="company",
154
154
  cascade="all, delete-orphan",
155
155
  )
156
+ mcp_personal_access_tokens = relationship(
157
+ "McpPersonalAccessToken",
158
+ back_populates="company",
159
+ cascade="all, delete-orphan",
160
+ )
156
161
  memory_items = relationship(
157
162
  "MemoryItem",
158
163
  back_populates="company",
@@ -698,6 +703,29 @@ class SqlDataset(Base):
698
703
  return {column.key: getattr(self, column.key) for column in class_mapper(self.__class__).columns}
699
704
 
700
705
 
706
+ class McpPersonalAccessToken(Base):
707
+ __tablename__ = "iat_mcp_personal_access_tokens"
708
+
709
+ id = Column(Integer, primary_key=True, autoincrement=True)
710
+ company_id = Column(Integer, ForeignKey(f"{ORM_SCHEMA}.iat_companies.id", ondelete="CASCADE"), nullable=False, index=True)
711
+ user_identifier = Column(String, nullable=False, index=True)
712
+ name = Column(String, nullable=False)
713
+ token_hash = Column(String(64), nullable=False, unique=True, index=True)
714
+ created_at = Column(DateTime, default=datetime.now, nullable=False)
715
+ expires_at = Column(DateTime, nullable=False)
716
+ revoked_at = Column(DateTime, nullable=True)
717
+ last_used_at = Column(DateTime, nullable=True)
718
+
719
+ __table_args__ = (
720
+ UniqueConstraint("company_id", "user_identifier", "name", name="uix_mcp_pat_company_user_name"),
721
+ )
722
+
723
+ company = relationship("Company", back_populates="mcp_personal_access_tokens")
724
+
725
+ def to_dict(self):
726
+ return {column.key: getattr(self, column.key) for column in class_mapper(self.__class__).columns}
727
+
728
+
701
729
  class AccessLog(Base):
702
730
  # Modelo ORM para registrar cada intento de acceso a la plataforma.
703
731
  __tablename__ = 'iat_access_log'
@@ -24,6 +24,7 @@ import os
24
24
  from typing import List, Optional, Union
25
25
  from datetime import datetime
26
26
  from injector import inject
27
+ import mimetypes
27
28
 
28
29
 
29
30
  class KnowledgeBaseService:
@@ -661,6 +662,71 @@ class KnowledgeBaseService:
661
662
  )
662
663
  return int(query.order_by(None).count() or 0)
663
664
 
665
+ def get_document_descriptor(
666
+ self,
667
+ company_short_name: str,
668
+ document_id: int,
669
+ collection_name: str | None = None,
670
+ ) -> dict:
671
+ """
672
+ Resolves a document descriptor suitable for MCP/API download workflows.
673
+
674
+ Validates tenant ownership and, when provided, that the document belongs
675
+ to the requested collection.
676
+ """
677
+ if not company_short_name or not document_id:
678
+ raise IAToolkitException(
679
+ IAToolkitException.ErrorType.INVALID_PARAMETER,
680
+ "company_short_name and document_id are required.",
681
+ )
682
+
683
+ document = self.document_repo.get_by_id(document_id)
684
+ if not document:
685
+ raise IAToolkitException(
686
+ IAToolkitException.ErrorType.DOCUMENT_NOT_FOUND,
687
+ f"Document '{document_id}' not found.",
688
+ )
689
+
690
+ document_company_short_name = str(getattr(getattr(document, "company", None), "short_name", "") or "").strip()
691
+ if document_company_short_name != company_short_name:
692
+ raise IAToolkitException(
693
+ IAToolkitException.ErrorType.INVALID_OPERATION,
694
+ f"Document '{document_id}' does not belong to company '{company_short_name}'.",
695
+ )
696
+
697
+ normalized_collection_name = str(collection_name or "").strip().lower() or None
698
+ document_collection_name = str(
699
+ getattr(getattr(document, "collection_type", None), "name", "") or ""
700
+ ).strip().lower() or None
701
+ if normalized_collection_name and document_collection_name != normalized_collection_name:
702
+ raise IAToolkitException(
703
+ IAToolkitException.ErrorType.INVALID_OPERATION,
704
+ f"Document '{document_id}' does not belong to collection '{collection_name}'.",
705
+ )
706
+
707
+ mime_type, _ = mimetypes.guess_type(str(document.filename or "").strip())
708
+ download_url = None
709
+ content_available = bool(document.storage_key)
710
+ if content_available:
711
+ download_url = self.storage_service.generate_presigned_url(
712
+ company_short_name,
713
+ document.storage_key,
714
+ )
715
+
716
+ return {
717
+ "document_id": document.id,
718
+ "company_short_name": company_short_name,
719
+ "collection_name": document_collection_name,
720
+ "filename": document.filename,
721
+ "mime_type": mime_type or "application/octet-stream",
722
+ "storage_key": document.storage_key,
723
+ "download_url": download_url,
724
+ "content_available": content_available,
725
+ "status": document.status.value if hasattr(document.status, "value") else str(document.status),
726
+ "metadata": document.meta or {},
727
+ "created_at": document.created_at.isoformat() if document.created_at else None,
728
+ }
729
+
664
730
  def get_document_content(self, document_id: int) -> tuple[bytes, str]:
665
731
  """
666
732
  Retrieves the raw content of a document and its filename.
@@ -306,7 +306,12 @@ class llmClient:
306
306
  combined_stats = self.add_stats(stats, stats_fcall)
307
307
  if isinstance(execution_metadata, dict):
308
308
  combined_stats = dict(combined_stats or {})
309
+ request_source = str(execution_metadata.get("request_source") or "").strip().lower()
310
+ if request_source:
311
+ combined_stats["request_source"] = request_source
309
312
  for key, value in execution_metadata.items():
313
+ if key == "request_source":
314
+ continue
310
315
  if value is not None:
311
316
  combined_stats[key] = value
312
317
 
@@ -0,0 +1,166 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import secrets
5
+ from datetime import datetime, timedelta
6
+
7
+ from injector import inject
8
+ from sqlalchemy.exc import IntegrityError
9
+
10
+ from iatoolkit.repositories.mcp_personal_access_token_repo import McpPersonalAccessTokenRepo
11
+ from iatoolkit.repositories.models import McpPersonalAccessToken
12
+ from iatoolkit.repositories.profile_repo import ProfileRepo
13
+ from iatoolkit.services.i18n_service import I18nService
14
+
15
+
16
+ class McpPersonalAccessTokenService:
17
+ TOKEN_PREFIX = "iatmcp_"
18
+ DEFAULT_EXPIRY_DAYS = 30
19
+ MAX_EXPIRY_DAYS = 365
20
+
21
+ @inject
22
+ def __init__(
23
+ self,
24
+ i18n_service: I18nService,
25
+ profile_repo: ProfileRepo,
26
+ token_repo: McpPersonalAccessTokenRepo,
27
+ ):
28
+ self.i18n_service = i18n_service
29
+ self.profile_repo = profile_repo
30
+ self.token_repo = token_repo
31
+
32
+ def list_tokens(self, company_short_name: str, user_identifier: str) -> dict:
33
+ company, error = self._get_company(company_short_name)
34
+ if error:
35
+ return error
36
+
37
+ tokens = self.token_repo.list_tokens_for_user(company.id, user_identifier)
38
+ return {"data": [self._token_to_dict(item) for item in tokens]}
39
+
40
+ def create_token(
41
+ self,
42
+ company_short_name: str,
43
+ user_identifier: str,
44
+ *,
45
+ name: str,
46
+ expires_in_days: int | None = None,
47
+ ) -> dict:
48
+ company, error = self._get_company(company_short_name)
49
+ if error:
50
+ return error
51
+
52
+ normalized_name = str(name or "").strip()
53
+ if not normalized_name:
54
+ return {"error": self.i18n_service.t("errors.auth.mcp_pat_name_required"), "status_code": 400}
55
+
56
+ expiry_days = self._normalize_expiry_days(expires_in_days)
57
+ if expiry_days is None:
58
+ return {"error": self.i18n_service.t("errors.auth.mcp_pat_expiry_invalid"), "status_code": 400}
59
+
60
+ existing = self.token_repo.get_token_by_name(company.id, user_identifier, normalized_name)
61
+ if existing and existing.revoked_at is None and existing.expires_at > datetime.now():
62
+ return {"error": self.i18n_service.t("errors.auth.mcp_pat_name_exists"), "status_code": 409}
63
+
64
+ raw_token = self._generate_raw_token()
65
+ expires_at = datetime.now() + timedelta(days=expiry_days)
66
+ try:
67
+ if existing:
68
+ existing.token_hash = self._hash_token(raw_token)
69
+ existing.created_at = datetime.now()
70
+ existing.expires_at = expires_at
71
+ existing.revoked_at = None
72
+ existing.last_used_at = None
73
+ created = self.token_repo.save_token(existing)
74
+ else:
75
+ token = McpPersonalAccessToken(
76
+ company_id=company.id,
77
+ user_identifier=user_identifier,
78
+ name=normalized_name,
79
+ token_hash=self._hash_token(raw_token),
80
+ expires_at=expires_at,
81
+ )
82
+ created = self.token_repo.create_token(token)
83
+ except IntegrityError:
84
+ self.token_repo.rollback()
85
+ return {"error": self.i18n_service.t("errors.auth.mcp_pat_name_exists"), "status_code": 409}
86
+ payload = self._token_to_dict(created)
87
+ payload["token"] = raw_token
88
+ return {"data": payload}
89
+
90
+ def revoke_token(self, company_short_name: str, user_identifier: str, token_id: int) -> dict:
91
+ company, error = self._get_company(company_short_name)
92
+ if error:
93
+ return error
94
+
95
+ token = self.token_repo.get_token_by_id(company.id, user_identifier, token_id)
96
+ if not token:
97
+ return {"error": self.i18n_service.t("errors.auth.mcp_pat_not_found"), "status_code": 404}
98
+
99
+ if token.revoked_at is None:
100
+ token.revoked_at = datetime.now()
101
+ self.token_repo.save_token(token)
102
+
103
+ return {"data": self._token_to_dict(token)}
104
+
105
+ def authenticate_token(self, company_short_name: str, raw_token: str) -> dict:
106
+ company, error = self._get_company(company_short_name)
107
+ if error:
108
+ return error
109
+
110
+ normalized_token = str(raw_token or "").strip()
111
+ if not normalized_token:
112
+ return {"error": self.i18n_service.t("errors.auth.mcp_pat_invalid"), "status_code": 401}
113
+
114
+ token_hash = self._hash_token(normalized_token)
115
+ token = self.token_repo.get_active_token_by_hash(company.id, token_hash)
116
+ if not token:
117
+ return {"error": self.i18n_service.t("errors.auth.mcp_pat_invalid"), "status_code": 401}
118
+
119
+ token.last_used_at = datetime.now()
120
+ self.token_repo.save_token(token)
121
+ return {
122
+ "success": True,
123
+ "company_short_name": company.short_name,
124
+ "user_identifier": token.user_identifier,
125
+ "token_id": token.id,
126
+ }
127
+
128
+ def _get_company(self, company_short_name: str):
129
+ company = self.profile_repo.get_company_by_short_name(company_short_name)
130
+ if not company:
131
+ return None, {
132
+ "error": self.i18n_service.t("errors.company_not_found", company_short_name=company_short_name),
133
+ "status_code": 404,
134
+ }
135
+ return company, None
136
+
137
+ def _token_to_dict(self, token: McpPersonalAccessToken) -> dict:
138
+ return {
139
+ "id": token.id,
140
+ "name": token.name,
141
+ "user_identifier": token.user_identifier,
142
+ "created_at": token.created_at.isoformat() if token.created_at else None,
143
+ "expires_at": token.expires_at.isoformat() if token.expires_at else None,
144
+ "revoked_at": token.revoked_at.isoformat() if token.revoked_at else None,
145
+ "last_used_at": token.last_used_at.isoformat() if token.last_used_at else None,
146
+ "is_active": token.revoked_at is None and token.expires_at > datetime.now(),
147
+ }
148
+
149
+ def _normalize_expiry_days(self, raw_value: int | None) -> int | None:
150
+ if raw_value in (None, ""):
151
+ return self.DEFAULT_EXPIRY_DAYS
152
+ try:
153
+ expiry_days = int(raw_value)
154
+ except (TypeError, ValueError):
155
+ return None
156
+ if expiry_days <= 0 or expiry_days > self.MAX_EXPIRY_DAYS:
157
+ return None
158
+ return expiry_days
159
+
160
+ @classmethod
161
+ def _hash_token(cls, raw_token: str) -> str:
162
+ return hashlib.sha256(str(raw_token or "").encode("utf-8")).hexdigest()
163
+
164
+ @classmethod
165
+ def _generate_raw_token(cls) -> str:
166
+ return f"{cls.TOKEN_PREFIX}{secrets.token_urlsafe(32)}"
@@ -1393,6 +1393,9 @@ class QueryService:
1393
1393
  request_metadata = self._resolve_prompt_request_metadata(prompt_output_contract)
1394
1394
 
1395
1395
  execution_metadata = {"tool_router": tool_router_metrics}
1396
+ request_source = str((client_data if isinstance(client_data, dict) else {}).get("source") or "").strip().lower() or None
1397
+ if request_source:
1398
+ execution_metadata["request_source"] = request_source
1396
1399
  if memory_lookup_decision.reason:
1397
1400
  execution_metadata["tool_policy"] = {
1398
1401
  "tool_choice_override": tool_choice_override,