iatoolkit 2.72.1__tar.gz → 2.73.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 (279) hide show
  1. {iatoolkit-2.72.1/src/iatoolkit.egg-info → iatoolkit-2.73.0}/PKG-INFO +1 -1
  2. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/__init__.py +1 -1
  3. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/access.py +91 -0
  4. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/locales/en.yaml +1 -0
  5. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/locales/es.yaml +1 -0
  6. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/knowledge_wiki_repo.py +12 -3
  7. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/memory_repo.py +12 -3
  8. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/models.py +7 -0
  9. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/company_context_service.py +17 -3
  10. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/context_builder_service.py +5 -1
  11. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/knowledge_base_service.py +5 -1
  12. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_compiler_service.py +38 -13
  13. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_service.py +79 -11
  14. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_sources.py +7 -3
  15. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_wiki_service.py +47 -10
  16. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/query_service.py +19 -0
  17. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/resource_access_scope.py +42 -0
  18. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/tenant_wiki_service.py +56 -8
  19. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/user_session_context_service.py +12 -0
  20. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/rag_api_view.py +55 -2
  21. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/wiki_page_view.py +3 -0
  22. {iatoolkit-2.72.1 → iatoolkit-2.73.0/src/iatoolkit.egg-info}/PKG-INFO +1 -1
  23. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/LICENSE +0 -0
  24. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/LICENSE_COMMUNITY.md +0 -0
  25. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/pyproject.toml +0 -0
  26. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/readme.md +0 -0
  27. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/setup.cfg +0 -0
  28. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/base_company.py +0 -0
  29. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/cli_commands.py +0 -0
  30. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/__init__.py +0 -0
  31. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/bridge_validation.py +0 -0
  32. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/company_paths.py +0 -0
  33. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/exceptions.py +0 -0
  34. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
  35. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
  36. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
  37. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
  38. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
  39. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
  40. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
  41. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/memory_tools.py +0 -0
  42. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/model_registry.py +0 -0
  43. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/routes.py +0 -0
  44. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/search_terms.py +0 -0
  45. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/secret_resolver.py +0 -0
  46. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/session_manager.py +0 -0
  47. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/text_splitter.py +0 -0
  48. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/url_safety.py +0 -0
  49. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/common/util.py +0 -0
  50. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/company_registry.py +0 -0
  51. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/__init__.py +0 -0
  52. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
  53. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_compiler.prompt +0 -0
  54. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_correction.prompt +0 -0
  55. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_document_ingest.prompt +0 -0
  56. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_image_ingest.prompt +0 -0
  57. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_meeting_ingest.prompt +0 -0
  58. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_question_review.prompt +0 -0
  59. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents_pack.yaml +0 -0
  60. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/channel_business_identity.prompt +0 -0
  61. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/channel_conversation_continuity.prompt +0 -0
  62. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/channel_response_style.prompt +0 -0
  63. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
  64. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
  65. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
  66. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
  67. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
  68. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
  69. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
  70. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
  71. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
  72. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
  73. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
  74. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
  75. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
  76. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
  77. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
  78. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_core.prompt +0 -0
  79. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
  80. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_mysql_casting.prompt +0 -0
  81. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_mysql_json.prompt +0 -0
  82. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_redshift_basics.prompt +0 -0
  83. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_redshift_types.prompt +0 -0
  84. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_rules.prompt +0 -0
  85. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
  86. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
  87. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
  88. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/core.py +0 -0
  89. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/__init__.py +0 -0
  90. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
  91. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/call_service.py +0 -0
  92. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  93. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  94. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  95. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  96. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  97. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  98. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  99. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
  100. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
  101. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
  102. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/inference_handler.py +0 -0
  103. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
  104. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_gateway_resolver.py +0 -0
  105. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
  106. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
  107. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
  108. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
  109. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
  110. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
  111. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
  112. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_proxy.py +0 -0
  113. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_response.py +0 -0
  114. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  115. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/__init__.py +0 -0
  116. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/advisory_lock.py +0 -0
  117. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
  118. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/bridge_repo.py +0 -0
  119. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/database_manager.py +0 -0
  120. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/document_repo.py +0 -0
  121. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
  122. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
  123. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  124. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/mcp_token_repo.py +0 -0
  125. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/memory_question_repo.py +0 -0
  126. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/memory_usage_repo.py +0 -0
  127. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
  128. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
  129. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
  130. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
  131. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
  132. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/runtime_logging.py +0 -0
  133. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/__init__.py +0 -0
  134. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/api_key_service.py +0 -0
  135. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
  136. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/auth_service.py +0 -0
  137. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/branding_service.py +0 -0
  138. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/configuration_service.py +0 -0
  139. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
  140. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/embedding_service.py +0 -0
  141. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/excel_service.py +0 -0
  142. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/file_processor_service.py +0 -0
  143. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/history_manager_service.py +0 -0
  144. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/http_tool_service.py +0 -0
  145. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/i18n_service.py +0 -0
  146. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/inference_service.py +0 -0
  147. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/jwt_service.py +0 -0
  148. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/language_service.py +0 -0
  149. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/license_service.py +0 -0
  150. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/llm_client_service.py +0 -0
  151. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/mail_service.py +0 -0
  152. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/markdown_wiki_service.py +0 -0
  153. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/mcp_token_service.py +0 -0
  154. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
  155. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_question_service.py +0 -0
  156. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_usage_service.py +0 -0
  157. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
  158. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/operator_identity_service.py +0 -0
  159. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
  160. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
  161. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
  162. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
  163. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
  164. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
  165. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
  166. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
  167. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
  168. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
  169. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/validator.py +0 -0
  170. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/pdf_service.py +0 -0
  171. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/profile_service.py +0 -0
  172. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
  173. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/prompt_service.py +0 -0
  174. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
  175. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
  176. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/sql_service.py +0 -0
  177. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/sql_source_service.py +0 -0
  178. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/storage_service.py +0 -0
  179. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/structured_output_service.py +0 -0
  180. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/system_agent_catalog.py +0 -0
  181. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/system_agent_runner.py +0 -0
  182. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
  183. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/system_tools.py +0 -0
  184. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/telemetry_service.py +0 -0
  185. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/tool_output_contract.py +0 -0
  186. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/tool_service.py +0 -0
  187. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
  188. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
  189. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
  190. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/warmup_service.py +0 -0
  191. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
  192. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
  193. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
  194. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
  195. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search_service.py +0 -0
  196. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/services/wiki_page_index_service.py +0 -0
  197. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/images/favicon.ico +0 -0
  198. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/images/favicon.png +0 -0
  199. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  200. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
  201. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
  202. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
  203. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  204. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_header_navigation.js +0 -0
  205. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
  206. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
  207. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
  208. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_main.js +0 -0
  209. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
  210. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
  211. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
  212. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
  213. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
  214. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/account.css +0 -0
  215. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
  216. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
  217. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
  218. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/documents.css +0 -0
  219. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
  220. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
  221. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
  222. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/wiki_page.css +0 -0
  223. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/_chat_header.html +0 -0
  224. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/_company_header.html +0 -0
  225. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/_login_widget.html +0 -0
  226. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/account.html +0 -0
  227. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/base.html +0 -0
  228. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/change_password.html +0 -0
  229. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/chat.html +0 -0
  230. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
  231. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/chat_modals.html +0 -0
  232. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/error.html +0 -0
  233. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/forgot_password.html +0 -0
  234. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
  235. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/login_global.html +0 -0
  236. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
  237. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
  238. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/base.html +0 -0
  239. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
  240. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/report.html +0 -0
  241. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
  242. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/signup.html +0 -0
  243. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/templates/wiki_page.html +0 -0
  244. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/__init__.py +0 -0
  245. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/account_view.py +0 -0
  246. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
  247. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/base_login_view.py +0 -0
  248. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/categories_api_view.py +0 -0
  249. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/change_password_view.py +0 -0
  250. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
  251. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/chat_view.py +0 -0
  252. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
  253. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
  254. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
  255. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
  256. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
  257. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/history_api_view.py +0 -0
  258. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/home_view.py +0 -0
  259. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
  260. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
  261. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
  262. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/login_view.py +0 -0
  263. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/logout_api_view.py +0 -0
  264. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/memory_api_view.py +0 -0
  265. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/profile_api_view.py +0 -0
  266. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
  267. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
  268. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
  269. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
  270. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/signup_view.py +0 -0
  271. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/static_page_view.py +0 -0
  272. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/tool_api_view.py +0 -0
  273. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
  274. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/users_api_view.py +0 -0
  275. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit/views/verify_user_view.py +0 -0
  276. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit.egg-info/SOURCES.txt +0 -0
  277. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  278. {iatoolkit-2.72.1 → iatoolkit-2.73.0}/src/iatoolkit.egg-info/requires.txt +0 -0
  279. {iatoolkit-2.72.1 → iatoolkit-2.73.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.72.1
3
+ Version: 2.73.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.72.1"
6
+ __version__ = "2.73.0"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -192,6 +192,97 @@ def filter_llm_models(company_short_name: str, user_identifier: str | None, defa
192
192
  return default_model, allowed
193
193
 
194
194
 
195
+ def stamp(company_short_name: str) -> str | None:
196
+ """A value that changes whenever the company's groups, members or grants change.
197
+
198
+ A person's chat context is built once and cached; when this changes, it is rebuilt
199
+ so the tools, SQL schema and collections it describes follow the new access."""
200
+ decider = Access._decider
201
+ hook = getattr(decider, "stamp", None) if decider is not None else None
202
+ if not callable(hook):
203
+ return None
204
+ try:
205
+ return hook(company_short_name)
206
+ except Exception as exc:
207
+ logging.warning("Access stamp of %s not read: %s", company_short_name, exc)
208
+ return None
209
+
210
+
211
+ def sql_table_filter(company_short_name: str, user_identifier: str | None):
212
+ """`fn(database, table) -> bool` for the SQL schema shown to this person, or None.
213
+
214
+ Some SQL sources hold resources of their own (enterprise's knowledge tables): the
215
+ decider names their resource type, and each table needs level 1 over it."""
216
+ decider = Access._decider
217
+ hook = getattr(decider, "sql_table_resource", None) if decider is not None else None
218
+ if not user_identifier or not callable(hook):
219
+ return None
220
+
221
+ def allowed(database: str, table: str) -> bool:
222
+ resource_type = hook(company_short_name, database)
223
+ return not resource_type or can(company_short_name, user_identifier, USE, resource_type, table)
224
+ return allowed
225
+
226
+
227
+ # ---------------------------------------------------------------------- audiences
228
+ # Who may see a piece of Memoria content (BL-010, Fase 3). An audience key is None
229
+ # (the whole company) or names what decides it: "memory_folder:<id>", "group:<key>".
230
+
231
+ def audience_visible(company_short_name: str, user_identifier: str | None, audience_key: str | None) -> bool:
232
+ if not audience_key:
233
+ return True
234
+ decider = Access._decider
235
+ hook = getattr(decider, "audience_visible", None) if decider is not None else None
236
+ if not callable(hook):
237
+ return True
238
+ try:
239
+ return bool(hook(company_short_name, user_identifier, audience_key))
240
+ except Exception as exc:
241
+ logging.warning("Audience %s for %s not resolved: %s", audience_key, user_identifier, exc)
242
+ return False
243
+
244
+
245
+ def visible_audiences(company_short_name: str, user_identifier: str | None) -> list[str] | None:
246
+ """The restricted audiences a person sees; None when they see every one (or nothing is restricted).
247
+
248
+ The whole company's content (audience None) is always visible besides these."""
249
+ decider = Access._decider
250
+ hook = getattr(decider, "visible_audiences", None) if decider is not None else None
251
+ if not callable(hook):
252
+ return None
253
+ try:
254
+ return hook(company_short_name, user_identifier)
255
+ except Exception as exc:
256
+ logging.warning("Visible audiences of %s not resolved: %s", user_identifier, exc)
257
+ return []
258
+
259
+
260
+ def audience_label(company_short_name: str, audience_key: str | None) -> str | None:
261
+ """The name people see for an audience (the folder's or group's name); None for the whole company."""
262
+ if not audience_key:
263
+ return None
264
+ decider = Access._decider
265
+ hook = getattr(decider, "audience_label", None) if decider is not None else None
266
+ try:
267
+ return (hook(company_short_name, audience_key) if callable(hook) else None) or audience_key
268
+ except Exception:
269
+ return audience_key
270
+
271
+
272
+ def audience_for_folder(company_short_name: str, folder_id) -> str | None:
273
+ """The audience new content from a Memoria folder takes: its own when the folder is restricted."""
274
+ decider = Access._decider
275
+ hook = getattr(decider, "audience_for_folder", None) if decider is not None else None
276
+ if not callable(hook) or folder_id in (None, ""):
277
+ return None
278
+ try:
279
+ return hook(company_short_name, folder_id)
280
+ except Exception as exc:
281
+ # Unknown: the folder's own audience, the restrictive side.
282
+ logging.warning("Audience of folder %s not resolved: %s", folder_id, exc)
283
+ return f"memory_folder:{folder_id}"
284
+
285
+
195
286
  def person_can(company_short_name: str, auth_result: dict | None, level: int, resource_type: str = "company",
196
287
  resource_key: str | None = None) -> bool:
197
288
  """A signed-in person's access, from an AuthService result.
@@ -794,6 +794,7 @@ ui:
794
794
  access_add_group: "Add group"
795
795
  access_reset: "Back to company access"
796
796
  access_saved: "Access updated."
797
+ access_memory_restricted: "What Memoria knows from this folder ({count} pages) is now seen only by those with access to it."
797
798
  access_group: "Group"
798
799
  access_level: "Level"
799
800
  team_invite_user: "Invite user"
@@ -808,6 +808,7 @@ ui:
808
808
  access_add_group: "Agregar grupo"
809
809
  access_reset: "Volver al acceso de la empresa"
810
810
  access_saved: "Acceso actualizado."
811
+ access_memory_restricted: "Lo que Memoria sabe de esta carpeta ({count} páginas) ahora solo lo ven quienes tienen acceso a ella."
811
812
  access_group: "Grupo"
812
813
  access_level: "Nivel"
813
814
  team_invite_user: "Invitar usuario"
@@ -299,7 +299,7 @@ class KnowledgeWikiRepo:
299
299
  RRF_K = 60
300
300
 
301
301
  def hybrid_search_pages(self, wiki_ids: list[int], query_text: str, query_embedding: list[float] | None,
302
- candidates: int = 40) -> list[tuple[int, float]]:
302
+ candidates: int = 40, audience_keys: list | None = None) -> list[tuple[int, float]]:
303
303
  """
304
304
  (page_id, rrf_score) of the best pages of these wikis, best first: by
305
305
  words (Postgres full text, 'simple', terms OR'ed, the GIN index) and, when
@@ -313,6 +313,15 @@ class KnowledgeWikiRepo:
313
313
  tsquery = "replace(plainto_tsquery('simple'::regconfig, :text_terms)::text, ' & ', ' | ')::tsquery"
314
314
  params = {"wiki_ids": list(wiki_ids), "text_terms": query_text or "", "candidates": int(candidates),
315
315
  "archived": KnowledgeWikiPageStatus.ARCHIVED.name}
316
+ # Audiences (BL-010, Fase 3): only pages whose audience is listed, None being the
317
+ # whole company. Filtered here, before the limit, not after the ranking.
318
+ audience_sql = ""
319
+ if audience_keys is not None:
320
+ keys = [k for k in audience_keys if k]
321
+ clauses = (["p.audience_key IS NULL"] if None in audience_keys else []) + \
322
+ (["p.audience_key = ANY(:audience_keys)"] if keys else [])
323
+ audience_sql = f" AND ({' OR '.join(clauses) or 'FALSE'})"
324
+ params["audience_keys"] = keys
316
325
  branches = [f"""
317
326
  SELECT page_id, ROW_NUMBER() OVER (ORDER BY text_rank DESC, page_id ASC) AS rank
318
327
  FROM (
@@ -320,7 +329,7 @@ class KnowledgeWikiRepo:
320
329
  FROM iat_knowledge_wiki_page_index i
321
330
  JOIN iat_knowledge_wiki_pages p ON p.id = i.page_id,
322
331
  (SELECT {tsquery} AS q) terms
323
- WHERE i.wiki_id = ANY(:wiki_ids) AND p.status::text <> :archived
332
+ WHERE i.wiki_id = ANY(:wiki_ids) AND p.status::text <> :archived{audience_sql}
324
333
  AND {tsvector} @@ terms.q
325
334
  ORDER BY text_rank DESC
326
335
  LIMIT :candidates
@@ -336,7 +345,7 @@ class KnowledgeWikiRepo:
336
345
  i.embedding::vector({dims}) <=> CAST(:query_embedding AS vector({dims})) AS distance
337
346
  FROM iat_knowledge_wiki_page_index i
338
347
  JOIN iat_knowledge_wiki_pages p ON p.id = i.page_id
339
- WHERE i.wiki_id = ANY(:wiki_ids) AND p.status::text <> :archived
348
+ WHERE i.wiki_id = ANY(:wiki_ids) AND p.status::text <> :archived{audience_sql}
340
349
  AND i.embedding IS NOT NULL AND vector_dims(i.embedding) = {dims}
341
350
  ORDER BY distance ASC
342
351
  LIMIT :candidates
@@ -109,12 +109,21 @@ class MemoryRepo:
109
109
  .all()
110
110
  )
111
111
 
112
- def list_recent_items(self, company_id: int, limit: int = 25) -> list[MemoryItem]:
112
+ def list_recent_items(self, company_id: int, limit: int = 25, audience_keys: list | None = None) -> list[MemoryItem]:
113
+ """The company's latest items; with `audience_keys`, only those of captures of those
114
+ audiences (None in the list is the whole company; BL-010, Fase 3)."""
113
115
  if not company_id:
114
116
  return []
117
+ query = self.session.query(MemoryItem).filter(MemoryItem.company_id == company_id)
118
+ if audience_keys is not None:
119
+ from sqlalchemy import false, or_
120
+ keys = [k for k in audience_keys if k]
121
+ clauses = ([MemoryCapture.audience_key.is_(None)] if None in audience_keys else []) + \
122
+ ([MemoryCapture.audience_key.in_(keys)] if keys else [])
123
+ query = query.join(MemoryCapture, MemoryCapture.id == MemoryItem.capture_id) \
124
+ .filter(or_(*clauses) if clauses else false())
115
125
  return (
116
- self.session.query(MemoryItem)
117
- .filter_by(company_id=company_id)
126
+ query
118
127
  .order_by(MemoryItem.created_at.desc(), MemoryItem.id.desc())
119
128
  .limit(limit)
120
129
  .all()
@@ -527,6 +527,10 @@ class MemoryCapture(Base):
527
527
  title = Column(String, nullable=True)
528
528
  status = Column(Enum(MemoryCaptureStatus), nullable=False, default=MemoryCaptureStatus.PENDING)
529
529
  meta = Column(JSON_NATIVE, nullable=True)
530
+ # Who may see what this capture teaches (BL-010, Fase 3): NULL is the whole company,
531
+ # "memory_folder:<id>" a folder with its own access. The compiler writes it only into
532
+ # pages of the same audience. Migration: migrations/2026-10-18-memoria-audiencia.sql
533
+ audience_key = Column(String(255), nullable=True)
530
534
  compile_error = Column(Text, nullable=True)
531
535
  last_compiled_at = Column(DateTime, nullable=True)
532
536
  created_at = Column(DateTime, default=datetime.now, nullable=False)
@@ -859,6 +863,9 @@ class KnowledgeWikiPage(Base):
859
863
  # An empty list denies the page under access control, which is why the sync
860
864
  # writes them from the wiki's access manifest and never from frontmatter.
861
865
  access_tags = Column(JSON_NATIVE, nullable=False, default=list)
866
+ # A Memoria page's audience (BL-010, Fase 3): NULL is the whole company. A page never
867
+ # mixes audiences. Migration: migrations/2026-10-18-memoria-audiencia.sql
868
+ audience_key = Column(String(255), nullable=True)
862
869
  owner = Column(String, nullable=True)
863
870
  source_meta = Column(JSON_NATIVE, nullable=False, default=dict)
864
871
  last_synced_at = Column(DateTime, nullable=True)
@@ -53,6 +53,7 @@ class CompanyContextService:
53
53
  include_yaml_context: bool = True,
54
54
  selected_context_files: List[str] | None = None,
55
55
  allowed_databases: List[str] | None = None,
56
+ table_filter=None,
56
57
  ) -> dict[str, str]:
57
58
  """
58
59
  Builds the full context by aggregating three sources:
@@ -81,7 +82,8 @@ class CompanyContextService:
81
82
  try:
82
83
  # allowed_databases: the sources this person may query (BL-010); None is all.
83
84
  sql_context, db_tables = self._get_sql_enriched_context(company_short_name,
84
- allowed_databases=allowed_databases)
85
+ allowed_databases=allowed_databases,
86
+ table_filter=table_filter)
85
87
  sql_context = sql_context.strip()
86
88
  sql_source_table_scopes = self._get_sql_source_table_scopes(company_short_name)
87
89
  except Exception as e:
@@ -138,11 +140,13 @@ class CompanyContextService:
138
140
  )
139
141
  return files
140
142
 
141
- def get_sql_context(self, company_short_name: str, allowed_databases: List[str] | None = None) -> str:
143
+ def get_sql_context(self, company_short_name: str, allowed_databases: List[str] | None = None,
144
+ table_filter=None) -> str:
142
145
  try:
143
146
  sql_context, _ = self._get_sql_enriched_context(
144
147
  company_short_name,
145
148
  allowed_databases=allowed_databases,
149
+ table_filter=table_filter,
146
150
  )
147
151
  return sql_context
148
152
  except Exception as e:
@@ -177,7 +181,8 @@ class CompanyContextService:
177
181
  return False
178
182
  return bool(cls._table_name_candidates(table_name) & allowed_tables)
179
183
 
180
- def _get_sql_enriched_context(self, company_short_name: str, allowed_databases: List[str] | None = None):
184
+ def _get_sql_enriched_context(self, company_short_name: str, allowed_databases: List[str] | None = None,
185
+ table_filter=None):
181
186
  """
182
187
  Generates the SQL context for the LLM using the enriched schema logic.
183
188
  It iterates over configured databases, fetches their enriched structure,
@@ -221,6 +226,15 @@ class CompanyContextService:
221
226
  }
222
227
  if not enriched_structure:
223
228
  continue
229
+ if table_filter is not None:
230
+ # Tables the person may not query (enterprise's knowledge tables, BL-010).
231
+ enriched_structure = {
232
+ table_name: table_data
233
+ for table_name, table_data in enriched_structure.items()
234
+ if table_filter(db_name, table_name)
235
+ }
236
+ if not enriched_structure:
237
+ continue
224
238
 
225
239
  # 2. Build Header for this Database
226
240
  dialect = self.sql_service.get_database_dialect(company_short_name, db_name)
@@ -19,6 +19,7 @@ from iatoolkit.services.prompt_service import PromptService
19
19
  from iatoolkit.services.structured_output_service import StructuredOutputService
20
20
  from iatoolkit.common.util import Utility
21
21
  from iatoolkit.repositories.models import Company, PromptResourceType
22
+ from iatoolkit.common import access
22
23
 
23
24
 
24
25
  class ContextBuilderService:
@@ -227,7 +228,8 @@ class ContextBuilderService:
227
228
  # sources and collections this person may use (BL-010, Fase 2).
228
229
  allowed_databases, allowed_collections = self._access_restrictions(company_short_name, user_identifier)
229
230
  company_context_blocks = self.company_context_service.get_company_context_blocks(
230
- company_short_name, allowed_databases=allowed_databases)
231
+ company_short_name, allowed_databases=allowed_databases,
232
+ table_filter=access.sql_table_filter(company_short_name, user_identifier))
231
233
  collection_context = "" if allowed_collections == [] else self._build_collection_context(
232
234
  company_short_name, collection_names=allowed_collections)
233
235
 
@@ -386,6 +388,7 @@ class ContextBuilderService:
386
388
  sql_context = self.company_context_service.get_sql_context(
387
389
  company_short_name,
388
390
  allowed_databases=sql_sources,
391
+ table_filter=access.sql_table_filter(company_short_name, user_identifier),
389
392
  )
390
393
 
391
394
  collection_context = ""
@@ -399,6 +402,7 @@ class ContextBuilderService:
399
402
  company_context_blocks = self.company_context_service.get_company_context_blocks(
400
403
  company_short_name,
401
404
  allowed_databases=allowed_databases,
405
+ table_filter=access.sql_table_filter(company_short_name, user_identifier),
402
406
  include_sql_context=bool(company_context_policy.get("sql_context")),
403
407
  include_yaml_context=bool(company_context_policy.get("yaml_context")),
404
408
  )
@@ -610,7 +610,11 @@ class KnowledgeBaseService:
610
610
  else:
611
611
  query = query.filter(Document.status == status)
612
612
 
613
- if collection:
613
+ if isinstance(collection, (list, tuple, set)):
614
+ # Several collections: those a person may see (BL-010). An empty list is none.
615
+ names = [str(c).strip().lower() for c in collection if str(c or "").strip()]
616
+ query = query.join(Document.collection_type).filter(func.lower(CollectionType.name).in_(names or [""]))
617
+ elif collection:
614
618
  normalized_collection = str(collection).strip().lower()
615
619
  query = query.join(Document.collection_type).filter(
616
620
  func.lower(CollectionType.name) == normalized_collection
@@ -26,11 +26,12 @@ from iatoolkit.repositories.models import (
26
26
  Company, MemoryCapture, MemoryCaptureStatus, MemoryConflict, MemoryItem, MemoryItemStatus, MemoryItemType, VSDoc,
27
27
  )
28
28
  from iatoolkit.repositories.profile_repo import ProfileRepo
29
- from iatoolkit.services.memory_sources import MemorySourceRegistry, register_core_sources
29
+ from iatoolkit.services.memory_sources import VISIBILITY_FOLDER, MemorySourceRegistry, register_core_sources
30
30
  from iatoolkit.services.memory_wiki_service import MemoryWikiService
31
31
  from iatoolkit.services.storage_service import StorageService
32
32
  from iatoolkit.services.system_agent_runner import SystemAgentDisabled, SystemAgentRunner
33
33
  from iatoolkit.services.tenant_wiki_service import TenantWikiService
34
+ from iatoolkit.common import access
34
35
 
35
36
 
36
37
  class MemoryCompilerService:
@@ -222,6 +223,14 @@ class MemoryCompilerService:
222
223
  def _compile_single_capture(self, company: Company, capture: MemoryCapture, items: list[MemoryItem]) -> bool:
223
224
  """Reads the capture with the step its source declares (memory_sources)."""
224
225
  source = MemorySourceRegistry.for_capture(dict(capture.meta or {}))
226
+ if source.visibility == VISIBILITY_FOLDER and not getattr(capture, "audience_key", None):
227
+ # A document saved before its folder was restricted (or before audiences
228
+ # existed) takes the folder's audience now: the restrictive side.
229
+ folder_id = (dict(capture.meta or {}).get("source") or {}).get("folder_id")
230
+ audience = access.audience_for_folder(company.short_name, folder_id)
231
+ if audience:
232
+ capture.audience_key = audience
233
+ self.memory_repo.save_capture(capture)
225
234
  return getattr(self, source.handler)(company, capture, items)
226
235
 
227
236
  def _compile_person_capture(self, company: Company, capture: MemoryCapture, items: list[MemoryItem]) -> bool:
@@ -244,6 +253,7 @@ class MemoryCompilerService:
244
253
  compiled,
245
254
  candidates,
246
255
  edited_by=capture.user_identifier,
256
+ audience_key=self._audience(capture)[0],
247
257
  default_title=self._default_page_title(capture, items),
248
258
  revision_metadata={
249
259
  "source": self.COMPILER_SOURCE,
@@ -282,7 +292,8 @@ class MemoryCompilerService:
282
292
  *,
283
293
  edited_by: str,
284
294
  default_title: str,
285
- revision_metadata: dict) -> dict:
295
+ revision_metadata: dict,
296
+ audience_key: str | None = None) -> dict:
286
297
  """Creates or updates the page the model returned; the wiki's response (it may say the page changed)."""
287
298
  target = self._resolve_target(compiled, candidates)
288
299
  title = str(compiled.get("title") or (target or {}).get("title") or default_title).strip()
@@ -298,6 +309,7 @@ class MemoryCompilerService:
298
309
  edited_by=edited_by,
299
310
  change_summary=change_summary,
300
311
  revision_metadata=revision_metadata,
312
+ audience_key=audience_key,
301
313
  )
302
314
  return self.memory_wiki_service.update_page(
303
315
  company.short_name,
@@ -356,7 +368,7 @@ class MemoryCompilerService:
356
368
  touched: list[int] = []
357
369
  for index, (part_text, read) in enumerate(readers, start=1):
358
370
  for attempt in range(1, self.MAX_SAVE_ATTEMPTS + 1):
359
- candidates = self._document_candidates(company, source, part_text, touched)
371
+ candidates = self._document_candidates(company, source, part_text, touched, capture)
360
372
  answer = read(candidates)
361
373
  if answer is None:
362
374
  raise RuntimeError(f"the model could not read part {index} of {len(readers)}")
@@ -367,6 +379,7 @@ class MemoryCompilerService:
367
379
  response = self._write_page(
368
380
  company, compiled, candidates,
369
381
  edited_by=capture.user_identifier,
382
+ audience_key=self._audience(capture)[0],
370
383
  default_title=label,
371
384
  revision_metadata=revision_metadata,
372
385
  )
@@ -535,30 +548,35 @@ class MemoryCompilerService:
535
548
  parts.append("\n\n".join(current))
536
549
  return parts
537
550
 
538
- def _document_candidates(self, company: Company, source: dict, part_text: str, touched: list[int]) -> list[dict]:
551
+ def _document_candidates(self, company: Company, source: dict, part_text: str, touched: list[int],
552
+ capture: MemoryCapture | None = None) -> list[dict]:
539
553
  """The pages this document already wrote first, then the ones its part is most likely about."""
554
+ audience = self._audience(capture) if capture is not None else [None]
540
555
  ordered: list[int] = list(touched)
541
556
  card = source.get("card") or {}
542
557
  query = " ".join(part for part in (
543
558
  str(source.get("label") or ""), str(card.get("summary") or ""), part_text[:300],
544
559
  ) if part).strip()
545
560
  if query:
546
- for result in self.memory_wiki_service.search_pages(company.short_name, query, limit=self.MAX_CANDIDATE_PAGES):
561
+ for result in self.memory_wiki_service.search_pages(company.short_name, query, limit=self.MAX_CANDIDATE_PAGES,
562
+ audience_keys=audience):
547
563
  if result.get("id") not in ordered:
548
564
  ordered.append(result.get("id"))
549
565
  candidates = []
550
566
  for page_id in ordered[:self.MAX_CANDIDATE_PAGES + len(touched)]:
551
- page = self.memory_wiki_service.get_page(company.short_name, page_id)
567
+ page = self.memory_wiki_service.get_page(company.short_name, page_id, audience_keys=audience)
552
568
  if page:
553
569
  candidates.append(page)
554
570
  return candidates
555
571
 
556
- def _wiki_context(self, company: Company, candidates: list[dict]) -> dict:
572
+ def _wiki_context(self, company: Company, candidates: list[dict], capture: MemoryCapture | None = None) -> dict:
557
573
  return {
558
574
  "wiki_schema": str(self.memory_wiki_service.read_schema() or "")[:7000],
559
575
  "page_index": [
560
576
  {"page_id": entry.get("id"), "title": entry.get("title"), "summary": entry.get("summary")}
561
- for entry in (self.memory_wiki_service.list_pages(company.short_name) or [])[:self.MAX_INDEX_ENTRIES_IN_PROMPT]
577
+ for entry in (self.memory_wiki_service.list_pages(
578
+ company.short_name, audience_keys=self._audience(capture) if capture is not None else [None]) or []
579
+ )[:self.MAX_INDEX_ENTRIES_IN_PROMPT]
562
580
  ],
563
581
  "candidate_pages": [
564
582
  {"page_id": page.get("id"), "title": page.get("title"),
@@ -576,7 +594,7 @@ class MemoryCompilerService:
576
594
  captured_on: str):
577
595
  return self._ingest_with_llm(
578
596
  company, capture, self._agent_for(capture) or self.DOCUMENT_AGENT,
579
- {"source": source, "part": part, "captured_on": captured_on, **self._wiki_context(company, candidates)},
597
+ {"source": source, "part": part, "captured_on": captured_on, **self._wiki_context(company, candidates, capture)},
580
598
  question=f"Read memory document {source.get('label')} (part {part['index']} of {part['total']})",
581
599
  )
582
600
 
@@ -589,7 +607,7 @@ class MemoryCompilerService:
589
607
  captured_on: str):
590
608
  return self._ingest_with_llm(
591
609
  company, capture, self.IMAGE_AGENT,
592
- {"source": source, "captured_on": captured_on, **self._wiki_context(company, candidates)},
610
+ {"source": source, "captured_on": captured_on, **self._wiki_context(company, candidates, capture)},
593
611
  question=f"Look at memory image {source.get('label')}",
594
612
  images=images,
595
613
  )
@@ -776,6 +794,11 @@ class MemoryCompilerService:
776
794
  capture.last_compiled_at = datetime.now()
777
795
  self.memory_repo.save_capture(capture)
778
796
 
797
+ @staticmethod
798
+ def _audience(capture: MemoryCapture) -> list:
799
+ """The one audience a capture compiles into (BL-010, Fase 3): it sees and writes only its pages."""
800
+ return [getattr(capture, "audience_key", None) or None]
801
+
779
802
  def _load_candidate_pages(self, company: Company, capture: MemoryCapture, items: list[MemoryItem]) -> list[dict]:
780
803
  """Pages the capture most likely belongs to, read in full (markdown and checksum)."""
781
804
  ordered_ids: list[int] = []
@@ -788,15 +811,17 @@ class MemoryCompilerService:
788
811
  for page_id in self.memory_repo.list_page_ids_for_items([item.id for item in items if getattr(item, "id", None)]):
789
812
  add(page_id)
790
813
  query = self._memory_capture_query(capture, items)
814
+ audience = self._audience(capture)
791
815
  if query:
792
- for result in self.memory_wiki_service.search_pages(company.short_name, query, limit=self.MAX_CANDIDATE_PAGES):
816
+ for result in self.memory_wiki_service.search_pages(company.short_name, query, limit=self.MAX_CANDIDATE_PAGES,
817
+ audience_keys=audience):
793
818
  add(result.get("id"))
794
819
 
795
820
  candidates = []
796
821
  for page_id in ordered_ids:
797
822
  if len(candidates) >= self.MAX_CANDIDATE_PAGES:
798
823
  break
799
- page = self.memory_wiki_service.get_page(company.short_name, page_id)
824
+ page = self.memory_wiki_service.get_page(company.short_name, page_id, audience_keys=audience)
800
825
  if page:
801
826
  candidates.append(page)
802
827
  return candidates
@@ -827,7 +852,7 @@ class MemoryCompilerService:
827
852
  author=author,
828
853
  captured_on=captured_on,
829
854
  wiki_schema=self.memory_wiki_service.read_schema(),
830
- index_entries=self.memory_wiki_service.list_pages(company.short_name),
855
+ index_entries=self.memory_wiki_service.list_pages(company.short_name, audience_keys=self._audience(capture)),
831
856
  )
832
857
  native_pdf_attachments = self._build_capture_native_pdf_attachments(company.short_name, items)
833
858
  try: