iatoolkit 2.54.1__tar.gz → 2.56.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.54.1/src/iatoolkit.egg-info → iatoolkit-2.56.0}/PKG-INFO +1 -1
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/__init__.py +1 -1
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +17 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/routes.py +9 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_tools_pack.yaml +6 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/locales/en.yaml +25 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/locales/es.yaml +25 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/auth_service.py +78 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/configuration_service.py +8 -2
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/profile_service.py +131 -10
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/system_tools.py +5 -2
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/_login_widget.html +4 -0
- iatoolkit-2.56.0/src/iatoolkit/templates/login_global.html +76 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/signup.html +3 -1
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/home_view.py +7 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/login_view.py +131 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/signup_view.py +48 -13
- {iatoolkit-2.54.1 → iatoolkit-2.56.0/src/iatoolkit.egg-info}/PKG-INFO +1 -1
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit.egg-info/SOURCES.txt +1 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/LICENSE +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/LICENSE_COMMUNITY.md +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/pyproject.toml +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/readme.md +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/setup.cfg +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/base_company.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/cli_commands.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/bridge_validation.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/exceptions.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/memory_lint_trigger.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/model_registry.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/secret_resolver.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/session_manager.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/text_splitter.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/url_safety.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/util.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/company_registry.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/channel_business_identity.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/channel_conversation_continuity.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/channel_response_style.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_core.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_mysql_casting.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_mysql_json.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_redshift_basics.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_redshift_types.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/sql_rules.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/core.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/call_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/inference_handler.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_gateway_resolver.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_proxy.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/llm_response.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/bridge_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/database_manager.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/document_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/knowledge_wiki_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/mcp_token_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/memory_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/models.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/runtime_logging.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/api_key_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/branding_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/company_context_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/context_builder_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/embedding_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/excel_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/file_processor_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/history_manager_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/http_tool_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/i18n_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/inference_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/jwt_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/knowledge_base_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/language_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/license_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/llm_client_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/mail_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/markdown_wiki_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/mcp_token_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/memory_compiler_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/memory_lint_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/memory_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/memory_wiki_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/noop_memory_lint_trigger.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/operator_identity_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/parsers/validator.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/pdf_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/prompt_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/query_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/sql_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/sql_source_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/storage_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/structured_output_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/telemetry_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/tenant_wiki_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/tool_output_contract.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/tool_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/warmup_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/services/web_search_service.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_header_navigation.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_main.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/account.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/documents.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/_chat_header.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/_company_header.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/account.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/base.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/change_password.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/chat.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/chat_modals.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/error.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/forgot_password.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/pdf/base.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/pdf/report.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/__init__.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/account_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/base_login_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/categories_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/change_password_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/chat_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/history_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/logout_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/memory_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/profile_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/rag_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/static_page_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/tool_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/users_api_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/views/verify_user_view.py +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit.egg-info/requires.txt +0 -0
- {iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit.egg-info/top_level.txt +0 -0
{iatoolkit-2.54.1 → iatoolkit-2.56.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py
RENAMED
|
@@ -31,3 +31,20 @@ class SignupPolicyResolver(ABC):
|
|
|
31
31
|
invite_token: str | None = None,
|
|
32
32
|
) -> SignupPolicyDecision:
|
|
33
33
|
"""Evaluates whether the email can sign up for the target company."""
|
|
34
|
+
|
|
35
|
+
def requires_invitation(self, company_short_name: str) -> bool:
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
def invitation_email(self, company_short_name: str, invite_token: str | None) -> str | None:
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
def claim_signup(
|
|
42
|
+
self,
|
|
43
|
+
company_short_name: str,
|
|
44
|
+
email: str,
|
|
45
|
+
invite_token: str | None = None,
|
|
46
|
+
*,
|
|
47
|
+
verified_email: bool = False,
|
|
48
|
+
) -> bool:
|
|
49
|
+
"""Claim an invitation in the same transaction that creates membership."""
|
|
50
|
+
return True
|
|
@@ -33,6 +33,8 @@ def register_views(app):
|
|
|
33
33
|
LoginView,
|
|
34
34
|
GoogleLoginStartView,
|
|
35
35
|
GoogleLoginCallbackView,
|
|
36
|
+
GlobalLoginView,
|
|
37
|
+
GlobalGoogleLoginStartView,
|
|
36
38
|
FinalizeContextView,
|
|
37
39
|
)
|
|
38
40
|
from iatoolkit.views.configuration_api_view import ConfigurationApiView, ValidateConfigurationApiView
|
|
@@ -74,6 +76,13 @@ def register_views(app):
|
|
|
74
76
|
view_func=GoogleLoginCallbackView.as_view('login_google_callback')
|
|
75
77
|
)
|
|
76
78
|
|
|
79
|
+
# company-less login: identifies the person, the caller picks the company
|
|
80
|
+
app.add_url_rule('/auth/login', view_func=GlobalLoginView.as_view('global_login'))
|
|
81
|
+
app.add_url_rule(
|
|
82
|
+
'/auth/login/google',
|
|
83
|
+
view_func=GlobalGoogleLoginStartView.as_view('global_login_google_start')
|
|
84
|
+
)
|
|
85
|
+
|
|
77
86
|
# Chat Route (Direct Access)
|
|
78
87
|
app.add_url_rule('/<company_short_name>/chat',
|
|
79
88
|
view_func=ChatView.as_view('chat'))
|
|
@@ -129,8 +129,11 @@ tools:
|
|
|
129
129
|
- function_name: iat_send_email
|
|
130
130
|
description: iatoolkit mail system. envia mails cuando un usuario lo solicita.
|
|
131
131
|
# Sends a real email: simulated, never sent, when an evaluation replays an agent.
|
|
132
|
+
# Not destructive (it changes nothing that existed) and not open-world for MCP
|
|
133
|
+
# annotations: it goes through the tenant's own mail service.
|
|
132
134
|
execution_config:
|
|
133
135
|
side_effects: true
|
|
136
|
+
destructive: false
|
|
134
137
|
routing_profile:
|
|
135
138
|
tags:
|
|
136
139
|
- email
|
|
@@ -559,6 +562,9 @@ tools:
|
|
|
559
562
|
- metadata_filter
|
|
560
563
|
- function_name: iat_web_search
|
|
561
564
|
description: Realiza una búsqueda web externa para obtener información pública actualizada.
|
|
565
|
+
# Reaches the public internet: openWorldHint in MCP annotations.
|
|
566
|
+
execution_config:
|
|
567
|
+
open_world: true
|
|
562
568
|
routing_profile:
|
|
563
569
|
tags:
|
|
564
570
|
- web
|
|
@@ -274,6 +274,10 @@ ui:
|
|
|
274
274
|
pending_review: "Pending review"
|
|
275
275
|
revoked: "Revoked"
|
|
276
276
|
|
|
277
|
+
global_login:
|
|
278
|
+
title: "Sign in to IAToolkit"
|
|
279
|
+
intro: "Sign in with the account you use in IAToolkit. You will choose the company next."
|
|
280
|
+
|
|
277
281
|
login_widget:
|
|
278
282
|
title: "Sign In"
|
|
279
283
|
welcome_message: "Enter your credentials or register to access this platform."
|
|
@@ -287,6 +291,7 @@ ui:
|
|
|
287
291
|
forgot_password_link: "Forgot your password?"
|
|
288
292
|
no_account_prompt: "Don't have an account?"
|
|
289
293
|
signup_link: "Sign Up"
|
|
294
|
+
invitation_prompt: "Need access? Ask your administrator for an invitation."
|
|
290
295
|
|
|
291
296
|
signup:
|
|
292
297
|
title: "Create an Account"
|
|
@@ -607,6 +612,25 @@ ui:
|
|
|
607
612
|
status_closed: "Closed"
|
|
608
613
|
admin:
|
|
609
614
|
workspace: "Workspace"
|
|
615
|
+
team_invitations: "Invitations"
|
|
616
|
+
team_invite_user: "Invite user"
|
|
617
|
+
team_invite_none: "No invitations yet."
|
|
618
|
+
team_invite_loading: "Loading invitations..."
|
|
619
|
+
team_invite_email: "Email"
|
|
620
|
+
team_invite_pending: "Pending"
|
|
621
|
+
team_invite_accepted: "Accepted"
|
|
622
|
+
team_invite_expired: "Expired"
|
|
623
|
+
team_invite_revoked_status: "Revoked"
|
|
624
|
+
team_invite_status: "Status"
|
|
625
|
+
team_invite_invited_by: "Invited by"
|
|
626
|
+
team_invite_expires: "Expires"
|
|
627
|
+
team_invite_revoke: "Revoke"
|
|
628
|
+
team_invite_revoked: "Invitation revoked."
|
|
629
|
+
team_invite_load_error: "Could not load invitations."
|
|
630
|
+
team_invite_revoke_error: "Could not revoke invitation."
|
|
631
|
+
team_policy_note: "Choose domain access or require an invitation for each new member."
|
|
632
|
+
team_policy_static_note: "Signup policies are enforced when the company runs in hosted mode."
|
|
633
|
+
team_policy_invite_only: "Invitation only"
|
|
610
634
|
configuration: "Configuration"
|
|
611
635
|
error: "Error"
|
|
612
636
|
company_config: "Company Configuration (company.yaml)"
|
|
@@ -2582,6 +2606,7 @@ errors:
|
|
|
2582
2606
|
user_already_registered: "The user with email '{email}' already exists in this company."
|
|
2583
2607
|
password_mismatch: "The passwords do not match. Please try again."
|
|
2584
2608
|
signup_not_allowed: "Signup is not allowed for this company. Please contact an administrator."
|
|
2609
|
+
invitation_required: "A valid invitation is required to join this company. Ask your administrator for a new link."
|
|
2585
2610
|
change_password:
|
|
2586
2611
|
token_expired: "The password change link has expired. Please request a new one."
|
|
2587
2612
|
password_mismatch: "The passwords do not match. Please try again."
|
|
@@ -288,6 +288,10 @@ ui:
|
|
|
288
288
|
revoked: "Revocado"
|
|
289
289
|
|
|
290
290
|
|
|
291
|
+
global_login:
|
|
292
|
+
title: "Iniciar sesión en IAToolkit"
|
|
293
|
+
intro: "Ingresa con la cuenta que usas en IAToolkit. Después podrás elegir la empresa."
|
|
294
|
+
|
|
291
295
|
login_widget:
|
|
292
296
|
title: "Iniciar Sesión"
|
|
293
297
|
welcome_message: "Ingresa tus credenciales o registrate para acceder a la plataforma."
|
|
@@ -301,6 +305,7 @@ ui:
|
|
|
301
305
|
forgot_password_link: "¿Olvidaste tu contraseña?"
|
|
302
306
|
no_account_prompt: "¿No tienes una cuenta?"
|
|
303
307
|
signup_link: "Regístrate"
|
|
308
|
+
invitation_prompt: "¿Necesitas acceso? Solicita una invitación al administrador."
|
|
304
309
|
|
|
305
310
|
signup:
|
|
306
311
|
title: "Crear una Cuenta"
|
|
@@ -621,6 +626,25 @@ ui:
|
|
|
621
626
|
status_closed: "Cerrada"
|
|
622
627
|
admin:
|
|
623
628
|
workspace: "Recursos"
|
|
629
|
+
team_invitations: "Invitaciones"
|
|
630
|
+
team_invite_user: "Invitar usuario"
|
|
631
|
+
team_invite_none: "Todavía no hay invitaciones."
|
|
632
|
+
team_invite_loading: "Cargando invitaciones..."
|
|
633
|
+
team_invite_email: "Correo"
|
|
634
|
+
team_invite_pending: "Pendiente"
|
|
635
|
+
team_invite_accepted: "Aceptada"
|
|
636
|
+
team_invite_expired: "Vencida"
|
|
637
|
+
team_invite_revoked_status: "Revocada"
|
|
638
|
+
team_invite_status: "Estado"
|
|
639
|
+
team_invite_invited_by: "Invitado por"
|
|
640
|
+
team_invite_expires: "Vence"
|
|
641
|
+
team_invite_revoke: "Revocar"
|
|
642
|
+
team_invite_revoked: "Invitación revocada."
|
|
643
|
+
team_invite_load_error: "No se pudieron cargar las invitaciones."
|
|
644
|
+
team_invite_revoke_error: "No se pudo revocar la invitación."
|
|
645
|
+
team_policy_note: "Permite el acceso por dominio o exige una invitación para cada nuevo miembro."
|
|
646
|
+
team_policy_static_note: "Las políticas de registro se aplican cuando la empresa funciona en modo alojado."
|
|
647
|
+
team_policy_invite_only: "Solo con invitación"
|
|
624
648
|
configuration: "Configuración"
|
|
625
649
|
error: "Error"
|
|
626
650
|
company_config: "Configuración Empresa (company.yaml)"
|
|
@@ -2601,6 +2625,7 @@ errors:
|
|
|
2601
2625
|
user_already_registered: "El usuario con email '{email}' ya existe en esta empresa."
|
|
2602
2626
|
password_mismatch: "Las contraseñas no coinciden. Por favor, inténtalo de nuevo."
|
|
2603
2627
|
signup_not_allowed: "El registro no está habilitado para esta empresa. Contacta a un administrador."
|
|
2628
|
+
invitation_required: "Necesitas una invitación vigente para unirte a esta empresa. Solicita un nuevo enlace al administrador."
|
|
2604
2629
|
change_password:
|
|
2605
2630
|
token_expired: "El enlace de cambio de contraseña ha expirado. Por favor, solicita uno nuevo."
|
|
2606
2631
|
password_mismatch: "Las contraseñas no coinciden. Por favor, inténtalo nuevamente."
|
|
@@ -22,6 +22,8 @@ class AuthService:
|
|
|
22
22
|
Centralized service for handling authentication for all incoming requests.
|
|
23
23
|
It determines the user's identity based on either a Flask session cookie or an API Key.
|
|
24
24
|
"""
|
|
25
|
+
# access-log scope for logins that are not tied to a company
|
|
26
|
+
GLOBAL_ACCESS_SCOPE = '*'
|
|
25
27
|
|
|
26
28
|
@inject
|
|
27
29
|
def __init__(self, profile_service: ProfileService,
|
|
@@ -186,6 +188,82 @@ class AuthService:
|
|
|
186
188
|
|
|
187
189
|
return auth_response
|
|
188
190
|
|
|
191
|
+
def login_global_local_user(self, email: str, password: str) -> dict:
|
|
192
|
+
# company-less login: authenticates the person, the company is chosen later
|
|
193
|
+
auth_response = self.profile_service.authenticate_local_credentials(email=email, password=password)
|
|
194
|
+
if not auth_response.get('success'):
|
|
195
|
+
self.log_access(
|
|
196
|
+
company_short_name=self.GLOBAL_ACCESS_SCOPE,
|
|
197
|
+
user_identifier=email,
|
|
198
|
+
auth_type='local',
|
|
199
|
+
outcome='failure',
|
|
200
|
+
reason_code='INVALID_CREDENTIALS',
|
|
201
|
+
)
|
|
202
|
+
return auth_response
|
|
203
|
+
|
|
204
|
+
self.profile_service.set_global_identity(auth_response['user_identifier'], 'local')
|
|
205
|
+
self.log_access(
|
|
206
|
+
company_short_name=self.GLOBAL_ACCESS_SCOPE,
|
|
207
|
+
auth_type='local',
|
|
208
|
+
outcome='success',
|
|
209
|
+
user_identifier=auth_response['user_identifier'],
|
|
210
|
+
)
|
|
211
|
+
return auth_response
|
|
212
|
+
|
|
213
|
+
def login_global_google_user(self, code: str, state: str, nonce: str, redirect_uri: str) -> dict:
|
|
214
|
+
try:
|
|
215
|
+
google_identity = self.google_auth_client.exchange_code_for_identity(
|
|
216
|
+
code=code,
|
|
217
|
+
state=state,
|
|
218
|
+
nonce=nonce,
|
|
219
|
+
redirect_uri=redirect_uri,
|
|
220
|
+
)
|
|
221
|
+
except GoogleAuthError as exc:
|
|
222
|
+
self.log_access(
|
|
223
|
+
company_short_name=self.GLOBAL_ACCESS_SCOPE,
|
|
224
|
+
auth_type='google',
|
|
225
|
+
outcome='failure',
|
|
226
|
+
reason_code=exc.reason_code,
|
|
227
|
+
)
|
|
228
|
+
return {
|
|
229
|
+
'success': False,
|
|
230
|
+
'reason_code': exc.reason_code,
|
|
231
|
+
'message': self.i18n_service.t(exc.message_key),
|
|
232
|
+
}
|
|
233
|
+
except Exception:
|
|
234
|
+
logging.exception("Unexpected Google auth client failure in company-less login.")
|
|
235
|
+
self.log_access(
|
|
236
|
+
company_short_name=self.GLOBAL_ACCESS_SCOPE,
|
|
237
|
+
auth_type='google',
|
|
238
|
+
outcome='failure',
|
|
239
|
+
reason_code='GOOGLE_AUTH_UNEXPECTED_ERROR',
|
|
240
|
+
)
|
|
241
|
+
return {
|
|
242
|
+
'success': False,
|
|
243
|
+
'reason_code': 'GOOGLE_AUTH_UNEXPECTED_ERROR',
|
|
244
|
+
'message': self.i18n_service.t('errors.auth.google_login_failed'),
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
auth_response = self.profile_service.identify_google_user(google_identity)
|
|
248
|
+
if not auth_response.get('success'):
|
|
249
|
+
self.log_access(
|
|
250
|
+
company_short_name=self.GLOBAL_ACCESS_SCOPE,
|
|
251
|
+
auth_type='google',
|
|
252
|
+
outcome='failure',
|
|
253
|
+
reason_code=auth_response.get('reason_code', 'GOOGLE_LOGIN_FAILED'),
|
|
254
|
+
user_identifier=google_identity.email,
|
|
255
|
+
)
|
|
256
|
+
return auth_response
|
|
257
|
+
|
|
258
|
+
self.profile_service.set_global_identity(auth_response['user_identifier'], 'google')
|
|
259
|
+
self.log_access(
|
|
260
|
+
company_short_name=self.GLOBAL_ACCESS_SCOPE,
|
|
261
|
+
auth_type='google',
|
|
262
|
+
outcome='success',
|
|
263
|
+
user_identifier=auth_response['user_identifier'],
|
|
264
|
+
)
|
|
265
|
+
return auth_response
|
|
266
|
+
|
|
189
267
|
def verify(self, anonymous: bool = False, company_short_name: str = None) -> dict:
|
|
190
268
|
"""
|
|
191
269
|
Verifies the current request and identifies the user.
|
|
@@ -794,8 +794,14 @@ class ConfigurationService:
|
|
|
794
794
|
if execution_config is not None:
|
|
795
795
|
if not isinstance(execution_config, dict):
|
|
796
796
|
add_error(f"tools[{i}].execution_config", "Must be a dictionary.")
|
|
797
|
-
|
|
798
|
-
|
|
797
|
+
else:
|
|
798
|
+
# side_effects drives evaluations; destructive / open_world / title
|
|
799
|
+
# feed the MCP tool annotations.
|
|
800
|
+
for flag in ("side_effects", "destructive", "open_world"):
|
|
801
|
+
if flag in execution_config and not isinstance(execution_config[flag], bool):
|
|
802
|
+
add_error(f"tools[{i}].execution_config.{flag}", "Must be true or false.")
|
|
803
|
+
if "title" in execution_config and not isinstance(execution_config["title"], str):
|
|
804
|
+
add_error(f"tools[{i}].execution_config.title", "Must be a string.")
|
|
799
805
|
|
|
800
806
|
# 6. Prompts
|
|
801
807
|
prompt_list, categories_config = self._get_prompt_config(config)
|
|
@@ -21,6 +21,7 @@ import random
|
|
|
21
21
|
import re
|
|
22
22
|
import string
|
|
23
23
|
import logging
|
|
24
|
+
import time
|
|
24
25
|
from html import escape
|
|
25
26
|
from datetime import datetime
|
|
26
27
|
from typing import List, Dict
|
|
@@ -30,6 +31,8 @@ from iatoolkit.services.signup_policy_resolver import AllowAllSignupPolicyResolv
|
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
class ProfileService:
|
|
34
|
+
GLOBAL_IDENTITY_SESSION_KEY = 'global_identity'
|
|
35
|
+
|
|
33
36
|
@inject
|
|
34
37
|
def __init__(self,
|
|
35
38
|
i18n_service: I18nService,
|
|
@@ -65,6 +68,16 @@ class ProfileService:
|
|
|
65
68
|
except Exception as rollback_error:
|
|
66
69
|
logging.warning(f"ProfileService rollback failed: {rollback_error}")
|
|
67
70
|
|
|
71
|
+
def signup_invitation_context(
|
|
72
|
+
self, company_short_name: str, invite_token: str | None,
|
|
73
|
+
) -> tuple[bool, str | None]:
|
|
74
|
+
required = self.signup_policy_resolver.requires_invitation(company_short_name)
|
|
75
|
+
email = (
|
|
76
|
+
self.signup_policy_resolver.invitation_email(company_short_name, invite_token)
|
|
77
|
+
if invite_token else None
|
|
78
|
+
)
|
|
79
|
+
return required, email
|
|
80
|
+
|
|
68
81
|
@staticmethod
|
|
69
82
|
def _normalize_name_value(value: str | None, fallback: str) -> str:
|
|
70
83
|
text = str(value or "").strip()
|
|
@@ -159,22 +172,110 @@ class ProfileService:
|
|
|
159
172
|
if not str(user.last_name or "").strip():
|
|
160
173
|
user.last_name = last_name
|
|
161
174
|
|
|
162
|
-
def
|
|
175
|
+
def _check_local_credentials(self, email: str, password: str) -> tuple[User | None, dict | None]:
|
|
176
|
+
# check if user exists
|
|
177
|
+
user = self.profile_repo.get_user_by_email(email)
|
|
178
|
+
if not user:
|
|
179
|
+
return None, {'success': False, 'message': self.i18n_service.t('errors.auth.user_not_found')}
|
|
180
|
+
|
|
181
|
+
if self._is_google_auth_user(user):
|
|
182
|
+
return None, {
|
|
183
|
+
'success': False,
|
|
184
|
+
'message': self.i18n_service.t('errors.auth.google_account_requires_google_login')
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# check the encrypted password
|
|
188
|
+
if not user.password or not check_password_hash(user.password, password):
|
|
189
|
+
return None, {'success': False, 'message': self.i18n_service.t('errors.auth.invalid_password')}
|
|
190
|
+
|
|
191
|
+
return user, None
|
|
192
|
+
|
|
193
|
+
def authenticate_local_credentials(self, email: str, password: str) -> dict:
|
|
194
|
+
"""
|
|
195
|
+
Checks email and password without tying the user to a company and
|
|
196
|
+
without opening a company session. Used by the company-less login,
|
|
197
|
+
where the company is chosen afterwards among the user's memberships.
|
|
198
|
+
"""
|
|
163
199
|
try:
|
|
164
|
-
|
|
200
|
+
user, error = self._check_local_credentials(email, password)
|
|
201
|
+
if error:
|
|
202
|
+
return error
|
|
203
|
+
|
|
204
|
+
if not user.verified:
|
|
205
|
+
return {'success': False,
|
|
206
|
+
"message": self.i18n_service.t('errors.services.account_not_verified')}
|
|
207
|
+
|
|
208
|
+
return {'success': True, 'user_identifier': user.email}
|
|
209
|
+
except Exception as e:
|
|
210
|
+
self._safe_rollback()
|
|
211
|
+
logging.error(f"Error in authenticate_local_credentials: {e}")
|
|
212
|
+
return {'success': False, "message": str(e)}
|
|
213
|
+
|
|
214
|
+
def identify_google_user(self, google_identity: GoogleIdentity) -> dict:
|
|
215
|
+
"""
|
|
216
|
+
Resolves an existing user from a Google identity without creating the
|
|
217
|
+
user, linking the Google account or adding a company membership: the
|
|
218
|
+
company-less login only lets in people who already belong somewhere.
|
|
219
|
+
"""
|
|
220
|
+
email = str(google_identity.email or "").strip().lower()
|
|
221
|
+
if not email or not google_identity.email_verified:
|
|
222
|
+
return {
|
|
223
|
+
"success": False,
|
|
224
|
+
"message": self.i18n_service.t('errors.auth.google_email_not_verified'),
|
|
225
|
+
"reason_code": "GOOGLE_EMAIL_NOT_VERIFIED",
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
user = self.profile_repo.get_user_by_google_sub(google_identity.subject)
|
|
229
|
+
if user:
|
|
230
|
+
if str(user.email or "").strip().lower() != email:
|
|
231
|
+
return {
|
|
232
|
+
"success": False,
|
|
233
|
+
"message": self.i18n_service.t('errors.auth.google_account_email_changed'),
|
|
234
|
+
"reason_code": "GOOGLE_EMAIL_CHANGED",
|
|
235
|
+
}
|
|
236
|
+
else:
|
|
165
237
|
user = self.profile_repo.get_user_by_email(email)
|
|
166
238
|
if not user:
|
|
167
|
-
return {'success': False, 'message': self.i18n_service.t('errors.auth.user_not_found')}
|
|
168
|
-
|
|
169
|
-
if self._is_google_auth_user(user):
|
|
170
239
|
return {
|
|
171
|
-
|
|
172
|
-
|
|
240
|
+
"success": False,
|
|
241
|
+
"message": self.i18n_service.t('errors.auth.user_not_found'),
|
|
242
|
+
"reason_code": "USER_NOT_FOUND",
|
|
243
|
+
}
|
|
244
|
+
if self._is_google_auth_user(user) and user.google_sub and user.google_sub != google_identity.subject:
|
|
245
|
+
return {
|
|
246
|
+
"success": False,
|
|
247
|
+
"message": self.i18n_service.t('errors.auth.google_account_conflict'),
|
|
248
|
+
"reason_code": "GOOGLE_ACCOUNT_CONFLICT",
|
|
173
249
|
}
|
|
174
250
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
251
|
+
return {"success": True, "user_identifier": user.email}
|
|
252
|
+
|
|
253
|
+
def set_global_identity(self, user_identifier: str, auth_method: str):
|
|
254
|
+
"""
|
|
255
|
+
Records who authenticated through the company-less login. It is not a
|
|
256
|
+
company session: no profile is built and no company page trusts it.
|
|
257
|
+
"""
|
|
258
|
+
SessionManager.set_permanent(True)
|
|
259
|
+
SessionManager.set(self.GLOBAL_IDENTITY_SESSION_KEY, {
|
|
260
|
+
'user_identifier': user_identifier,
|
|
261
|
+
'auth_method': auth_method,
|
|
262
|
+
'authenticated_at': int(time.time()),
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
def get_global_identity(self) -> dict | None:
|
|
266
|
+
identity = SessionManager.get(self.GLOBAL_IDENTITY_SESSION_KEY)
|
|
267
|
+
if not isinstance(identity, dict) or not identity.get('user_identifier'):
|
|
268
|
+
return None
|
|
269
|
+
return identity
|
|
270
|
+
|
|
271
|
+
def clear_global_identity(self):
|
|
272
|
+
SessionManager.remove(self.GLOBAL_IDENTITY_SESSION_KEY)
|
|
273
|
+
|
|
274
|
+
def login(self, company_short_name: str, email: str, password: str) -> dict:
|
|
275
|
+
try:
|
|
276
|
+
user, error = self._check_local_credentials(email, password)
|
|
277
|
+
if error:
|
|
278
|
+
return error
|
|
178
279
|
|
|
179
280
|
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
180
281
|
if not company:
|
|
@@ -488,6 +589,7 @@ class ProfileService:
|
|
|
488
589
|
)
|
|
489
590
|
policy_metadata = dict(policy_decision.metadata or {})
|
|
490
591
|
if not policy_decision.allowed:
|
|
592
|
+
self._safe_rollback()
|
|
491
593
|
logging.info(
|
|
492
594
|
"Google login blocked by signup policy. company=%s email=%s policy=%s metadata=%s",
|
|
493
595
|
company_short_name,
|
|
@@ -506,6 +608,15 @@ class ProfileService:
|
|
|
506
608
|
"message": message,
|
|
507
609
|
"reason_code": "SIGNUP_NOT_ALLOWED",
|
|
508
610
|
}
|
|
611
|
+
if not self.signup_policy_resolver.claim_signup(
|
|
612
|
+
company_short_name, email, verified_email=True,
|
|
613
|
+
):
|
|
614
|
+
self._safe_rollback()
|
|
615
|
+
return {
|
|
616
|
+
"success": False,
|
|
617
|
+
"message": self.i18n_service.t('errors.signup.signup_not_allowed'),
|
|
618
|
+
"reason_code": "SIGNUP_NOT_ALLOWED",
|
|
619
|
+
}
|
|
509
620
|
user.companies.append(company)
|
|
510
621
|
provisioning_outcome = "company_associated" if user.id is not None else provisioning_outcome
|
|
511
622
|
persisted = True
|
|
@@ -664,6 +775,11 @@ class ProfileService:
|
|
|
664
775
|
return {"error": self.i18n_service.t('errors.signup.user_already_registered', email=email)}
|
|
665
776
|
else:
|
|
666
777
|
# add new company to existing user
|
|
778
|
+
if not self.signup_policy_resolver.claim_signup(
|
|
779
|
+
company_short_name, email, invite_token,
|
|
780
|
+
):
|
|
781
|
+
self._safe_rollback()
|
|
782
|
+
return {"error": self.i18n_service.t('errors.signup.signup_not_allowed')}
|
|
667
783
|
existing_user.companies.append(company)
|
|
668
784
|
self.profile_repo.save_user(existing_user)
|
|
669
785
|
self._promote_bootstrap_owner_if_needed(company, existing_user)
|
|
@@ -699,6 +815,11 @@ class ProfileService:
|
|
|
699
815
|
)
|
|
700
816
|
|
|
701
817
|
# associate new company to user
|
|
818
|
+
if not self.signup_policy_resolver.claim_signup(
|
|
819
|
+
company_short_name, email, invite_token,
|
|
820
|
+
):
|
|
821
|
+
self._safe_rollback()
|
|
822
|
+
return {"error": self.i18n_service.t('errors.signup.signup_not_allowed')}
|
|
702
823
|
new_user.companies.append(company)
|
|
703
824
|
|
|
704
825
|
# and create in the database
|
|
@@ -60,8 +60,11 @@ def _validate_system_tool_entry(entry: dict, index: int) -> dict:
|
|
|
60
60
|
if execution_config is not None:
|
|
61
61
|
if not isinstance(execution_config, dict):
|
|
62
62
|
raise ValueError(f"tools[{index}].execution_config must be an object")
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
for flag in ("side_effects", "destructive", "open_world"):
|
|
64
|
+
if flag in execution_config and not isinstance(execution_config[flag], bool):
|
|
65
|
+
raise ValueError(f"tools[{index}].execution_config.{flag} must be a boolean")
|
|
66
|
+
if "title" in execution_config and not isinstance(execution_config["title"], str):
|
|
67
|
+
raise ValueError(f"tools[{index}].execution_config.title must be a string")
|
|
65
68
|
|
|
66
69
|
normalized = {
|
|
67
70
|
"function_name": function_name,
|
|
@@ -54,10 +54,14 @@
|
|
|
54
54
|
|
|
55
55
|
<!-- 3. Nueva Sección de Registro más Atractiva -->
|
|
56
56
|
<div class="mt-4 pt-3 text-center" style="border-top: 1px solid #e0e0e0;">
|
|
57
|
+
{% if signup_invitation_required|default(false) %}
|
|
58
|
+
<span class="text-muted small">{{ t('ui.login_widget.invitation_prompt') }}</span>
|
|
59
|
+
{% else %}
|
|
57
60
|
<span class="text-muted small">{{ t('ui.login_widget.no_account_prompt') }}</span>
|
|
58
61
|
<a href="{{ url_for('signup', company_short_name=company_short_name, lang=current_lang) }}" id="signup-link"
|
|
59
62
|
class="fw-bold ms-1 text-decoration-none" style="color: var(--brand-primary-color);">
|
|
60
63
|
{{ t('ui.login_widget.signup_link') }}</a>
|
|
64
|
+
{% endif %}
|
|
61
65
|
</div>
|
|
62
66
|
|
|
63
67
|
<!-- 4. Enlace de Recuperación de Contraseña (más sutil) -->
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ t('ui.global_login.title') }}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block styles %}
|
|
6
|
+
<style>
|
|
7
|
+
/* No company yet, so no company branding: the page wears IAToolkit's own. */
|
|
8
|
+
:root {
|
|
9
|
+
--brand-primary-color: #4A55A2;
|
|
10
|
+
--brand-secondary-color: #3A448A;
|
|
11
|
+
--brand-text-on-primary: #ffffff;
|
|
12
|
+
}
|
|
13
|
+
body { background: linear-gradient(180deg, #ffffff 0%, #f1f3fb 100%); min-height: 100vh; }
|
|
14
|
+
.iat-brand { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 1.35rem; color: #1d2541; text-decoration: none; }
|
|
15
|
+
.iat-brand-mark { display: inline-grid; place-items: center; width: 32px; height: 32px; border-radius: 8px; background: #4A55A2; color: #fff; }
|
|
16
|
+
/* Self-contained: this page does not load the company-home stylesheet. */
|
|
17
|
+
.global-login .branded-form-container { background: #fff; border-radius: 12px; padding: 32px; border-top: 4px solid #4A55A2; box-shadow: 0 8px 28px rgba(29, 37, 65, .10); }
|
|
18
|
+
.global-login .btn-branded-primary { background: #4A55A2; border: 1px solid #4A55A2; color: #fff; }
|
|
19
|
+
.global-login .btn-branded-primary:hover { background: #3A448A; border-color: #3A448A; color: #fff; }
|
|
20
|
+
.global-login .form-control:focus { border-color: #4A55A2; box-shadow: 0 0 0 .2rem rgba(74, 85, 162, .18); }
|
|
21
|
+
</style>
|
|
22
|
+
{% endblock %}
|
|
23
|
+
|
|
24
|
+
{% block content %}
|
|
25
|
+
<div class="container my-5 global-login">
|
|
26
|
+
<div class="text-center mb-4">
|
|
27
|
+
<span class="iat-brand">
|
|
28
|
+
<span class="iat-brand-mark" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M6 1l1.2 3.6L11 6 7.2 7.4 6 11 4.8 7.4 1 6l3.8-1.4z"/><path d="M12 9l.7 1.8 1.8.7-1.8.7L12 14l-.7-1.8-1.8-.7 1.8-.7z"/></svg></span>
|
|
29
|
+
<span>IAToolkit</span>
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="row justify-content-center">
|
|
33
|
+
<div class="col-md-6 col-lg-5">
|
|
34
|
+
<div class="branded-form-container">
|
|
35
|
+
<div class="text-center mb-4">
|
|
36
|
+
<h1 class="h4 fw-bold">{{ t('ui.global_login.title') }}</h1>
|
|
37
|
+
<p class="text-muted widget-intro-text">{{ t('ui.global_login.intro') }}</p>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
{% if google_login_enabled|default(false) %}
|
|
41
|
+
<a href="{{ url_for('global_login_google_start', lang=lang, next=login_next) }}"
|
|
42
|
+
class="btn btn-outline-secondary w-100 fw-semibold py-2 d-flex align-items-center justify-content-center gap-2">
|
|
43
|
+
<i class="bi bi-google"></i>
|
|
44
|
+
{{ t('ui.login_widget.google_button') }}
|
|
45
|
+
</a>
|
|
46
|
+
|
|
47
|
+
<div class="d-flex align-items-center gap-3 my-4">
|
|
48
|
+
<div class="flex-grow-1" style="height: 1px; background: #e0e0e0;"></div>
|
|
49
|
+
<span class="text-muted text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.08em;">
|
|
50
|
+
{{ t('ui.login_widget.or_continue_with') }}
|
|
51
|
+
</span>
|
|
52
|
+
<div class="flex-grow-1" style="height: 1px; background: #e0e0e0;"></div>
|
|
53
|
+
</div>
|
|
54
|
+
{% endif %}
|
|
55
|
+
|
|
56
|
+
<form id="global-login-form" action="{{ url_for('global_login', lang=lang) }}" method="post">
|
|
57
|
+
{% if login_next %}<input type="hidden" name="next" value="{{ login_next }}">{% endif %}
|
|
58
|
+
<input type="hidden" name="lang" value="{{ lang }}">
|
|
59
|
+
<div class="mb-3">
|
|
60
|
+
<label for="email" class="form-label d-block">{{ t('ui.signup.email_label') }}</label>
|
|
61
|
+
<input type="email" id="email" name="email" class="form-control"
|
|
62
|
+
required value="{{ form_data.email if form_data is defined else '' }}">
|
|
63
|
+
</div>
|
|
64
|
+
<div class="mb-3">
|
|
65
|
+
<label for="password" class="form-label d-block">{{ t('ui.signup.password_label') }}</label>
|
|
66
|
+
<input type="password" id="password" name="password" class="form-control" required>
|
|
67
|
+
</div>
|
|
68
|
+
<button type="submit" class="btn btn-branded-primary w-100 fw-bold py-2">
|
|
69
|
+
{{ t('ui.login_widget.login_button') }}
|
|
70
|
+
</button>
|
|
71
|
+
</form>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
{% endblock %}
|
|
@@ -39,11 +39,13 @@
|
|
|
39
39
|
{% endif %}
|
|
40
40
|
|
|
41
41
|
<form action="{{ url_for('signup', company_short_name=company_short_name) }}" method="post">
|
|
42
|
+
{% if invite_token %}<input type="hidden" name="invite_token" value="{{ invite_token }}">{% endif %}
|
|
42
43
|
<div class="mb-3">
|
|
43
44
|
<label for="email" class="form-label text-secondary">{{ t('ui.signup.email_label') }}</label>
|
|
44
45
|
<input type="email" autocomplete="off" id="email" name="email"
|
|
45
46
|
class="form-control" required
|
|
46
|
-
value="{{ form_data.email if form_data else '' }}"
|
|
47
|
+
value="{{ invited_email or (form_data.email if form_data else '') }}"
|
|
48
|
+
{% if invited_email %}readonly{% endif %}>
|
|
47
49
|
</div>
|
|
48
50
|
|
|
49
51
|
<div class="row">
|
|
@@ -36,6 +36,11 @@ class HomeView(MethodView):
|
|
|
36
36
|
self._trigger_warmup(company_short_name, "home_pre_login")
|
|
37
37
|
|
|
38
38
|
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
39
|
+
invitation_context = self.profile_service.signup_invitation_context(company_short_name, None)
|
|
40
|
+
login_context = (
|
|
41
|
+
{"signup_invitation_required": True}
|
|
42
|
+
if isinstance(invitation_context, tuple) and invitation_context[0] is True else {}
|
|
43
|
+
)
|
|
39
44
|
|
|
40
45
|
template_name = self.util.get_template_by_language("home")
|
|
41
46
|
home_template = self.util.get_company_template(company_short_name, template_name)
|
|
@@ -52,6 +57,7 @@ class HomeView(MethodView):
|
|
|
52
57
|
company_short_name=company_short_name,
|
|
53
58
|
company=company,
|
|
54
59
|
branding=branding_data,
|
|
60
|
+
**login_context,
|
|
55
61
|
)
|
|
56
62
|
|
|
57
63
|
message = self.i18n_service.t(
|
|
@@ -70,6 +76,7 @@ class HomeView(MethodView):
|
|
|
70
76
|
home_template,
|
|
71
77
|
company_short_name=company_short_name,
|
|
72
78
|
branding=branding_data,
|
|
79
|
+
**login_context,
|
|
73
80
|
)
|
|
74
81
|
except Exception as e:
|
|
75
82
|
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|