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