iatoolkit 2.72.2__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.
- {iatoolkit-2.72.2/src/iatoolkit.egg-info → iatoolkit-2.73.0}/PKG-INFO +1 -1
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/__init__.py +1 -1
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/access.py +59 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/locales/en.yaml +1 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/locales/es.yaml +1 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/knowledge_wiki_repo.py +12 -3
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/memory_repo.py +12 -3
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/models.py +7 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_compiler_service.py +38 -13
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_service.py +79 -11
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_sources.py +7 -3
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_wiki_service.py +47 -10
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/tenant_wiki_service.py +56 -8
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/wiki_page_view.py +3 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0/src/iatoolkit.egg-info}/PKG-INFO +1 -1
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/LICENSE +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/LICENSE_COMMUNITY.md +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/pyproject.toml +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/readme.md +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/setup.cfg +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/base_company.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/cli_commands.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/bridge_validation.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/company_paths.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/exceptions.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/memory_tools.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/model_registry.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/routes.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/search_terms.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/secret_resolver.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/session_manager.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/text_splitter.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/url_safety.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/common/util.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/company_registry.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_compiler.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_correction.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_document_ingest.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_image_ingest.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_meeting_ingest.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents/memory_question_review.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_agents_pack.yaml +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/channel_business_identity.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/channel_conversation_continuity.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/channel_response_style.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_core.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_mysql_casting.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_mysql_json.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_redshift_basics.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_redshift_types.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/sql_rules.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/core.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/call_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/inference_handler.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_gateway_resolver.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_proxy.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/llm_response.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/advisory_lock.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/bridge_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/database_manager.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/document_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/mcp_token_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/memory_question_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/memory_usage_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/runtime_logging.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/api_key_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/auth_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/branding_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/company_context_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/configuration_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/context_builder_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/embedding_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/excel_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/file_processor_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/history_manager_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/http_tool_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/i18n_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/inference_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/jwt_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/knowledge_base_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/language_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/license_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/llm_client_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/mail_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/markdown_wiki_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/mcp_token_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_question_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/memory_usage_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/operator_identity_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/parsers/validator.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/pdf_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/profile_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/prompt_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/query_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/resource_access_scope.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/sql_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/sql_source_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/storage_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/structured_output_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/system_agent_catalog.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/system_agent_runner.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/system_tools.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/telemetry_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/tool_output_contract.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/tool_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/warmup_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/web_search_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/services/wiki_page_index_service.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/images/favicon.ico +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/images/favicon.png +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_header_navigation.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_main.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/account.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/documents.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/static/styles/wiki_page.css +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/_chat_header.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/_company_header.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/_login_widget.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/account.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/base.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/change_password.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/chat.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/chat_modals.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/error.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/forgot_password.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/login_global.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/base.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/report.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/signup.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/templates/wiki_page.html +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/__init__.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/account_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/base_login_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/categories_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/change_password_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/chat_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/history_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/home_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/login_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/logout_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/memory_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/profile_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/rag_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/signup_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/static_page_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/tool_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/users_api_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit/views/verify_user_view.py +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit.egg-info/SOURCES.txt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit.egg-info/requires.txt +0 -0
- {iatoolkit-2.72.2 → iatoolkit-2.73.0}/src/iatoolkit.egg-info/top_level.txt +0 -0
|
@@ -224,6 +224,65 @@ def sql_table_filter(company_short_name: str, user_identifier: str | None):
|
|
|
224
224
|
return allowed
|
|
225
225
|
|
|
226
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
|
+
|
|
227
286
|
def person_can(company_short_name: str, auth_result: dict | None, level: int, resource_type: str = "company",
|
|
228
287
|
resource_key: str | None = None) -> bool:
|
|
229
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
|
-
|
|
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)
|
|
@@ -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
|
|
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]
|
|
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(
|
|
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:
|
|
@@ -32,6 +32,7 @@ from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
|
32
32
|
from iatoolkit.services.memory_compiler_service import MemoryCompilerService
|
|
33
33
|
from iatoolkit.services.memory_wiki_service import MemoryWikiService
|
|
34
34
|
from iatoolkit.services.storage_service import StorageService
|
|
35
|
+
from iatoolkit.common import access
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class MemoryService:
|
|
@@ -110,7 +111,9 @@ class MemoryService:
|
|
|
110
111
|
capture_text: str | None = None,
|
|
111
112
|
new_items: list[dict] | None = None,
|
|
112
113
|
title: str | None = None,
|
|
113
|
-
meta: dict | None = None
|
|
114
|
+
meta: dict | None = None,
|
|
115
|
+
audience_key: str | None = None) -> dict:
|
|
116
|
+
"""`audience_key` (BL-010, Fase 3): who may see what it teaches; None is the whole company."""
|
|
114
117
|
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
115
118
|
if not company:
|
|
116
119
|
return {"status": "error", "error_message": "company not found"}
|
|
@@ -123,6 +126,7 @@ class MemoryService:
|
|
|
123
126
|
title=(title or capture_text or "")[:200] or None,
|
|
124
127
|
status=MemoryCaptureStatus.PENDING,
|
|
125
128
|
meta=dict(meta or {}),
|
|
129
|
+
audience_key=audience_key or None,
|
|
126
130
|
)
|
|
127
131
|
self.memory_repo.create_capture(capture)
|
|
128
132
|
|
|
@@ -166,7 +170,8 @@ class MemoryService:
|
|
|
166
170
|
path: str = "",
|
|
167
171
|
author: str | None = None,
|
|
168
172
|
source_meta: dict | None = None,
|
|
169
|
-
kind: str | None = None
|
|
173
|
+
kind: str | None = None,
|
|
174
|
+
audience_key: str | None = None) -> dict:
|
|
170
175
|
"""
|
|
171
176
|
A RAG document that feeds the wiki (BL-014), queued as a capture so the
|
|
172
177
|
compiler reads it whole, part by part (`memory_document_ingest`; a
|
|
@@ -177,10 +182,14 @@ class MemoryService:
|
|
|
177
182
|
reads the document's fragments from the RAG when it gets to it.
|
|
178
183
|
"""
|
|
179
184
|
label = str(label or "").strip() or f"Documento {document_id}"
|
|
185
|
+
# A document of a restricted folder teaches only that folder's audience (BL-010, Fase 3).
|
|
186
|
+
if audience_key is None:
|
|
187
|
+
audience_key = access.audience_for_folder(company_short_name, (source_meta or {}).get("folder_id"))
|
|
180
188
|
return self.save_capture(
|
|
181
189
|
company_short_name=company_short_name,
|
|
182
190
|
user_identifier=author or self.DOCUMENT_SOURCE_IDENTITY,
|
|
183
191
|
title=label,
|
|
192
|
+
audience_key=audience_key,
|
|
184
193
|
new_items=[{
|
|
185
194
|
"item_type": "file",
|
|
186
195
|
"title": label,
|
|
@@ -216,13 +225,17 @@ class MemoryService:
|
|
|
216
225
|
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
217
226
|
if not company:
|
|
218
227
|
return {"status": "error", "error_message": "company not found"}
|
|
219
|
-
|
|
228
|
+
page_ids = self.memory_repo.list_page_ids_for_document(company.id, document_id)
|
|
229
|
+
if not page_ids:
|
|
220
230
|
return {"status": "skipped", "reason": "no page cites this document"}
|
|
221
231
|
label = str(label or "").strip() or f"Documento {document_id}"
|
|
232
|
+
# The pages that cite it share an audience: the mark runs in it.
|
|
233
|
+
first_page = self.memory_wiki_service.get_page(company_short_name, page_ids[0]) or {}
|
|
222
234
|
return self.save_capture(
|
|
223
235
|
company_short_name=company_short_name,
|
|
224
236
|
user_identifier=removed_by or self.DOCUMENT_SOURCE_IDENTITY,
|
|
225
237
|
title=label,
|
|
238
|
+
audience_key=first_page.get("audience_key"),
|
|
226
239
|
new_items=[{
|
|
227
240
|
"item_type": "note",
|
|
228
241
|
"title": label,
|
|
@@ -335,6 +348,46 @@ class MemoryService:
|
|
|
335
348
|
"capture": self.serialize_capture(capture, refreshed_items, company_short_name=company_short_name),
|
|
336
349
|
}
|
|
337
350
|
|
|
351
|
+
@staticmethod
|
|
352
|
+
def audiences_for(company_short_name: str, user_identifier: str | None) -> list | None:
|
|
353
|
+
"""The audiences a person may read (BL-010, Fase 3): the whole company (None) plus the
|
|
354
|
+
restricted ones they see; None when nothing is filtered (administration, core alone)."""
|
|
355
|
+
if not access.Access.registered():
|
|
356
|
+
return None
|
|
357
|
+
visible = access.visible_audiences(company_short_name, user_identifier)
|
|
358
|
+
return None if visible is None else [None, *visible]
|
|
359
|
+
|
|
360
|
+
def restrict_document_pages(self, company_short_name: str, document_ids, audience_key: str) -> int:
|
|
361
|
+
"""A folder became restricted (BL-010, Fase 3): the company pages that cite its documents
|
|
362
|
+
move to its audience, so what they say stops reaching the whole company. The page keeps
|
|
363
|
+
its path; how many moved is returned."""
|
|
364
|
+
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
365
|
+
if not company or not audience_key:
|
|
366
|
+
return 0
|
|
367
|
+
page_ids = set()
|
|
368
|
+
for document_id in {int(d) for d in document_ids or [] if d}:
|
|
369
|
+
page_ids.update(self.memory_repo.list_page_ids_for_document(company.id, document_id))
|
|
370
|
+
moved = 0
|
|
371
|
+
for page_id in sorted(page_ids):
|
|
372
|
+
page = self.memory_wiki_service.get_page(company_short_name, page_id, audience_keys=[None])
|
|
373
|
+
if page is None:
|
|
374
|
+
continue
|
|
375
|
+
if self.memory_wiki_service.set_page_audience(company_short_name, page_id, audience_key):
|
|
376
|
+
moved += 1
|
|
377
|
+
if moved:
|
|
378
|
+
logging.info("Memoria: %s company pages of %s moved to audience %s", moved, company_short_name, audience_key)
|
|
379
|
+
return moved
|
|
380
|
+
|
|
381
|
+
def delete_audience_pages(self, company_short_name: str, audience_key: str, deleted_by: str | None = None) -> int:
|
|
382
|
+
"""The audience is gone (its folder was deleted): its pages go with it. How many were deleted."""
|
|
383
|
+
if not audience_key:
|
|
384
|
+
return 0
|
|
385
|
+
deleted = 0
|
|
386
|
+
for page in self.memory_wiki_service.list_audience_pages(company_short_name, audience_key):
|
|
387
|
+
result = self.memory_wiki_service.delete_page(company_short_name, page=page, edited_by=deleted_by)
|
|
388
|
+
deleted += 1 if result.get("status") == "success" else 0
|
|
389
|
+
return deleted
|
|
390
|
+
|
|
338
391
|
def get_memory_dashboard(self, company_short_name: str, user_identifier: str) -> dict:
|
|
339
392
|
"""What the chat's Memoria panel shows: the user's own captures and the company's pages."""
|
|
340
393
|
self._compile_on_demand(company_short_name)
|
|
@@ -351,11 +404,16 @@ class MemoryService:
|
|
|
351
404
|
"status": "success",
|
|
352
405
|
"captures": serialized_captures,
|
|
353
406
|
"recent_items": serialized_captures,
|
|
354
|
-
"pages": self.list_pages(company_short_name),
|
|
407
|
+
"pages": self.list_pages(company_short_name, user_identifier=user_identifier),
|
|
355
408
|
}
|
|
356
409
|
|
|
357
|
-
def list_pages(self, company_short_name: str
|
|
358
|
-
|
|
410
|
+
def list_pages(self, company_short_name: str, user_identifier: str | None = None,
|
|
411
|
+
audience_keys: list | None = None) -> list[dict]:
|
|
412
|
+
"""The pages; with a person, those of the audiences they may read."""
|
|
413
|
+
if audience_keys is None and user_identifier:
|
|
414
|
+
audience_keys = self.audiences_for(company_short_name, user_identifier)
|
|
415
|
+
return [self.serialize_page(entry)
|
|
416
|
+
for entry in self.memory_wiki_service.list_pages(company_short_name, audience_keys=audience_keys)]
|
|
359
417
|
|
|
360
418
|
def search_pages(self,
|
|
361
419
|
company_short_name: str,
|
|
@@ -368,9 +426,11 @@ class MemoryService:
|
|
|
368
426
|
if not company:
|
|
369
427
|
return {"status": "error", "results": [], "error_message": "company not found"}
|
|
370
428
|
|
|
429
|
+
audiences = self.audiences_for(company_short_name, user_identifier)
|
|
371
430
|
results = []
|
|
372
431
|
source_items_by_page_id = {}
|
|
373
|
-
for entry in self.memory_wiki_service.search_pages(company_short_name, query, limit=limit
|
|
432
|
+
for entry in self.memory_wiki_service.search_pages(company_short_name, query, limit=limit,
|
|
433
|
+
audience_keys=audiences):
|
|
374
434
|
page_id = entry.get("id")
|
|
375
435
|
source_items = self._load_page_source_items(company.id, page_id)
|
|
376
436
|
source_items_by_page_id[page_id] = source_items
|
|
@@ -399,6 +459,7 @@ class MemoryService:
|
|
|
399
459
|
normalized_query=normalized_query,
|
|
400
460
|
query_tokens=self._tokenize(query),
|
|
401
461
|
limit=limit,
|
|
462
|
+
audience_keys=audiences,
|
|
402
463
|
)
|
|
403
464
|
|
|
404
465
|
response = {
|
|
@@ -441,7 +502,9 @@ class MemoryService:
|
|
|
441
502
|
if not company:
|
|
442
503
|
return {"status": "error", "error_message": "company not found"}
|
|
443
504
|
|
|
444
|
-
page
|
|
505
|
+
# A page of an audience the person may not read is "not found" (BL-010, Fase 3).
|
|
506
|
+
page = self.memory_wiki_service.get_page(company_short_name, page_id,
|
|
507
|
+
audience_keys=self.audiences_for(company_short_name, user_identifier))
|
|
445
508
|
if not page:
|
|
446
509
|
return {"status": "error", "error_message": "page not found"}
|
|
447
510
|
|
|
@@ -489,12 +552,16 @@ class MemoryService:
|
|
|
489
552
|
text = str(instruction or "").strip()
|
|
490
553
|
if not text:
|
|
491
554
|
return {"status": "error", "error_message": "write what to correct or add"}
|
|
492
|
-
|
|
555
|
+
page = self.memory_wiki_service.get_page(company_short_name, page_id,
|
|
556
|
+
audience_keys=self.audiences_for(company_short_name, user_identifier))
|
|
557
|
+
if not page:
|
|
493
558
|
return {"status": "error", "error_message": "page not found"}
|
|
494
559
|
response = self.save_capture(
|
|
495
560
|
company_short_name=company_short_name,
|
|
496
561
|
user_identifier=user_identifier,
|
|
497
562
|
capture_text=text,
|
|
563
|
+
# A correction lives in its page's audience (BL-010, Fase 3).
|
|
564
|
+
audience_key=page.get("audience_key"),
|
|
498
565
|
title=f"Corrección: {text}"[:200],
|
|
499
566
|
new_items=[{"item_type": "note", "content_text": text, "source_meta": {"origin": "page_correction"}}],
|
|
500
567
|
meta={
|
|
@@ -782,8 +849,9 @@ class MemoryService:
|
|
|
782
849
|
company_id: int,
|
|
783
850
|
normalized_query: str,
|
|
784
851
|
query_tokens: list[str],
|
|
785
|
-
limit: int
|
|
786
|
-
|
|
852
|
+
limit: int,
|
|
853
|
+
audience_keys: list | None = None) -> list[dict]:
|
|
854
|
+
items = self.memory_repo.list_recent_items(company_id, limit=max(limit * 12, 60), audience_keys=audience_keys)
|
|
787
855
|
ranked = []
|
|
788
856
|
for item in items:
|
|
789
857
|
score = self._score_memory_item_match(normalized_query, query_tokens, item)
|
|
@@ -20,8 +20,10 @@ over three services. A source now declares, in one place:
|
|
|
20
20
|
version is read; "add": both stay, as two people saying things);
|
|
21
21
|
- `on_removal`: what its removal does ("mark_obsolete": its lines are marked,
|
|
22
22
|
never erased; "none");
|
|
23
|
-
- `visibility`: who may read what it teaches
|
|
24
|
-
|
|
23
|
+
- `visibility`: who may read what it teaches: "company" (people, corrections in the
|
|
24
|
+
page's audience) or "folder" (a document: its folder's audience when restricted).
|
|
25
|
+
The capture carries the audience (`audience_key`) and the compiler writes it only
|
|
26
|
+
into pages of that audience (BL-010, Fase 3).
|
|
25
27
|
|
|
26
28
|
A new source registers here (`MemorySourceRegistry.register`) instead of adding
|
|
27
29
|
another branch to the compiler.
|
|
@@ -36,6 +38,8 @@ VERSION_ADD = "add"
|
|
|
36
38
|
REMOVAL_MARK_OBSOLETE = "mark_obsolete"
|
|
37
39
|
REMOVAL_NONE = "none"
|
|
38
40
|
VISIBILITY_COMPANY = "company"
|
|
41
|
+
# What it teaches is for its folder's audience when the folder is restricted (BL-010, Fase 3).
|
|
42
|
+
VISIBILITY_FOLDER = "folder"
|
|
39
43
|
|
|
40
44
|
|
|
41
45
|
@dataclass(frozen=True)
|
|
@@ -93,7 +97,7 @@ def register_core_sources(*, compiler_agent: str, correction_agent: str, documen
|
|
|
93
97
|
MemorySourceRegistry.register(MemorySource(
|
|
94
98
|
key="document", mode=document_mode, handler="_ingest_document", agent=document_agent,
|
|
95
99
|
kind_agents={meeting_kind: meeting_agent},
|
|
96
|
-
on_new_version=VERSION_REPLACE, on_removal=REMOVAL_MARK_OBSOLETE,
|
|
100
|
+
on_new_version=VERSION_REPLACE, on_removal=REMOVAL_MARK_OBSOLETE, visibility=VISIBILITY_FOLDER,
|
|
97
101
|
description="A document of a Memoria folder (Drive or uploaded), or a meeting transcript.",
|
|
98
102
|
))
|
|
99
103
|
MemorySourceRegistry.register(MemorySource(
|