iatoolkit 2.74.2__tar.gz → 2.75.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.74.2/src/iatoolkit.egg-info → iatoolkit-2.75.0}/PKG-INFO +1 -1
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/__init__.py +1 -1
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/history_compaction.prompt +1 -1
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_core.prompt +6 -3
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_tools_pack.yaml +33 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/company_context_service.py +24 -118
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/dispatcher_service.py +2 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/history_compaction_service.py +31 -5
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/llm_client_service.py +3 -2
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/resource_access_scope.py +11 -2
- iatoolkit-2.75.0/src/iatoolkit/services/sql_catalog_service.py +260 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/tool_service.py +30 -1
- {iatoolkit-2.74.2 → iatoolkit-2.75.0/src/iatoolkit.egg-info}/PKG-INFO +1 -1
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit.egg-info/SOURCES.txt +1 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/LICENSE +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/LICENSE_COMMUNITY.md +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/pyproject.toml +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/readme.md +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/setup.cfg +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/base_company.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/cli_commands.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/access.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/bridge_validation.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/company_paths.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/exceptions.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/history_compaction_trigger.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/memory_tools.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/model_registry.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/routes.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/search_terms.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/secret_resolver.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/session_manager.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/text_splitter.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/url_safety.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/common/util.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/company_registry.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/memory_compiler.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/memory_correction.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/memory_document_ingest.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/memory_image_ingest.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/memory_meeting_ingest.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/memory_question_review.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents_pack.yaml +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/channel_business_identity.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/channel_conversation_continuity.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/channel_response_style.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_mysql_casting.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_mysql_json.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_redshift_basics.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_redshift_types.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/sql_rules.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/core.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/call_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/inference_handler.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_gateway_resolver.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_proxy.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/llm_response.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/locales/en.yaml +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/locales/es.yaml +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/advisory_lock.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/bridge_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/database_manager.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/document_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/knowledge_wiki_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/mcp_token_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/memory_question_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/memory_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/memory_usage_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/models.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/runtime_logging.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/api_key_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/auth_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/branding_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/configuration_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/context_builder_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/embedding_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/excel_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/file_processor_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/history_manager_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/http_tool_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/i18n_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/inference_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/jwt_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/knowledge_base_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/language_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/license_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/mail_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/markdown_wiki_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/mcp_token_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/memory_compiler_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/memory_question_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/memory_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/memory_sources.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/memory_usage_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/memory_wiki_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/noop_history_compaction_trigger.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/operator_identity_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/parsers/validator.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/pdf_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/profile_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/prompt_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/query_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/sql_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/sql_source_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/storage_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/structured_output_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/system_agent_catalog.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/system_agent_runner.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/system_tools.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/telemetry_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/tenant_wiki_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/tool_output_contract.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/warmup_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/web_search_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/services/wiki_page_index_service.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/images/favicon.ico +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/images/favicon.png +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_header_navigation.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_main.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/account.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/documents.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/static/styles/wiki_page.css +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/_chat_header.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/_company_header.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/_login_widget.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/account.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/base.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/change_password.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/chat.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/chat_modals.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/error.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/forgot_password.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/login_global.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/pdf/base.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/pdf/report.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/signup.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/templates/wiki_page.html +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/__init__.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/account_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/base_login_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/categories_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/change_password_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/chat_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/history_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/home_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/login_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/logout_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/memory_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/profile_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/rag_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/signup_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/static_page_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/tool_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/users_api_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/verify_user_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/views/wiki_page_view.py +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit.egg-info/requires.txt +0 -0
- {iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit.egg-info/top_level.txt +0 -0
{iatoolkit-2.74.2 → iatoolkit-2.75.0}/src/iatoolkit/config/system_agents/history_compaction.prompt
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
You compact the older part of a conversation between a person and a company's AI assistant. The conversation is too long for the model's context, so the turns below will be replaced by your summary; the most recent turns stay as they are. The assistant will continue the conversation from your summary alone, so anything you leave out is lost.
|
|
2
2
|
|
|
3
|
-
Write the summary in the language of the conversation, as Markdown, with these sections (omit a section only when there is nothing for it):
|
|
3
|
+
Write the summary in the language of the conversation, as Markdown, with these sections (omit a section only when there is nothing for it). Write the section headings in that language too, as level-2 headings (`## …`), and do not wrap the summary in a code block:
|
|
4
4
|
|
|
5
5
|
- **Objective**: what the person is trying to achieve, and how it evolved.
|
|
6
6
|
- **Decisions**: what was agreed, chosen or ruled out, and why when it was said.
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
- Trabaja siempre con el dialecto SQL indicado para la base seleccionada.
|
|
4
4
|
- Antes de escribir la consulta, revisa el contexto de la base y respeta su marcador
|
|
5
5
|
`dialect=...` (por ejemplo `postgresql` o `mysql`).
|
|
6
|
-
-
|
|
6
|
+
- El contexto lista las bases y sus tablas, sin columnas. Antes de escribir la
|
|
7
|
+
consulta, pide con `iat_sql_schema` las columnas de las tablas que vas a usar,
|
|
8
|
+
todas en una sola llamada. Si una columna no aparece, pide la tabla que la tiene
|
|
9
|
+
en vez de suponerla.
|
|
10
|
+
- Usa solo tablas de la lista y columnas que `iat_sql_schema` te haya mostrado.
|
|
7
11
|
No inventes columnas ni supongas nombres parecidos.
|
|
8
|
-
-
|
|
9
|
-
`database_key` correcto.
|
|
12
|
+
- Ejecuta la consulta con `iat_sql_query` y el `database_key` correcto.
|
|
10
13
|
- Si hay mas de una tabla, subconsulta o CTE, califica las columnas con alias
|
|
11
14
|
en `SELECT`, `JOIN`, `ON`, `WHERE`, `GROUP BY`, `HAVING` y `ORDER BY`.
|
|
12
15
|
- No mezcles sintaxis de distintos dialectos en la misma consulta.
|
|
@@ -220,6 +220,39 @@ tools:
|
|
|
220
220
|
required:
|
|
221
221
|
- database_key
|
|
222
222
|
- query
|
|
223
|
+
- function_name: iat_sql_schema
|
|
224
|
+
description: "Columnas de tablas SQL: antes de escribir una consulta para iat_sql_query, pide aquí las columnas de las tablas que vas a usar. El contexto trae la lista de bases y tablas; esta herramienta trae sus columnas, tipos y descripciones. Pide varias tablas en una sola llamada."
|
|
225
|
+
routing:
|
|
226
|
+
force_include_capability: has_sql_sources
|
|
227
|
+
routing_profile:
|
|
228
|
+
tags:
|
|
229
|
+
- sql
|
|
230
|
+
- database
|
|
231
|
+
- schema
|
|
232
|
+
- columns
|
|
233
|
+
intents:
|
|
234
|
+
- Get the columns of SQL tables before writing a query.
|
|
235
|
+
- Inspect the structure of a configured SQL database.
|
|
236
|
+
examples:
|
|
237
|
+
- iat_sql_schema(database_key="erp", table_names=["customers", "orders"])
|
|
238
|
+
cost:
|
|
239
|
+
penalty: 0.05
|
|
240
|
+
latency_class: low
|
|
241
|
+
expensive: false
|
|
242
|
+
parameters:
|
|
243
|
+
type: object
|
|
244
|
+
properties:
|
|
245
|
+
database_key:
|
|
246
|
+
type: string
|
|
247
|
+
description: "Nombre exacto de la base, como aparece en el contexto."
|
|
248
|
+
table_names:
|
|
249
|
+
type: array
|
|
250
|
+
items:
|
|
251
|
+
type: string
|
|
252
|
+
description: "Tablas de esa base cuyas columnas necesitas (hasta 10)."
|
|
253
|
+
required:
|
|
254
|
+
- database_key
|
|
255
|
+
- table_names
|
|
223
256
|
- function_name: iat_document_search
|
|
224
257
|
description: Búsqueda semántica sobre documentos internos de la empresa para traer contexto adicional cuando haga falta. No usar si el usuario pide trabajar exclusivamente con un archivo ya adjunto en el turno actual. Usa metadata_filter solo cuando el usuario o el contexto indiquen un filtro de metadata concreto y necesario; si no hace falta, envía null.
|
|
225
258
|
routing:
|
|
@@ -181,129 +181,35 @@ class CompanyContextService:
|
|
|
181
181
|
return False
|
|
182
182
|
return bool(cls._table_name_candidates(table_name) & allowed_tables)
|
|
183
183
|
|
|
184
|
+
@property
|
|
185
|
+
def sql_catalog(self):
|
|
186
|
+
"""What of each SQL source a person sees (BL-017); built here, it reads this service's schema."""
|
|
187
|
+
if getattr(self, "_sql_catalog", None) is None:
|
|
188
|
+
from iatoolkit.services.sql_catalog_service import SqlCatalogService
|
|
189
|
+
|
|
190
|
+
self._sql_catalog = SqlCatalogService(self, self.sql_source_service, self.sql_service)
|
|
191
|
+
return self._sql_catalog
|
|
192
|
+
|
|
184
193
|
def _get_sql_enriched_context(self, company_short_name: str, allowed_databases: List[str] | None = None,
|
|
185
194
|
table_filter=None):
|
|
186
195
|
"""
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
and formats it into a prompt-friendly string.
|
|
190
|
-
"""
|
|
191
|
-
sql_sources = self.sql_source_service.list_sources(company_short_name, include_inactive=False)
|
|
192
|
-
if not sql_sources:
|
|
193
|
-
return '', []
|
|
194
|
-
|
|
195
|
-
allowed_database_set = {
|
|
196
|
-
str(database or "").strip()
|
|
197
|
-
for database in (allowed_databases or [])
|
|
198
|
-
if str(database or "").strip()
|
|
199
|
-
}
|
|
200
|
-
if allowed_databases is not None and not allowed_database_set:
|
|
201
|
-
return "", []
|
|
202
|
-
|
|
203
|
-
context_output = []
|
|
204
|
-
db_tables=[]
|
|
196
|
+
The SQL block of the base context: a map of each source the person may
|
|
197
|
+
query, its tables with a one-line description and no columns (BL-017).
|
|
205
198
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
allowed_tables = self._resolve_allowed_tables_for_source(source)
|
|
214
|
-
|
|
215
|
-
try:
|
|
216
|
-
# 1. Get the Enriched Schema (Physical + YAML)
|
|
217
|
-
enriched_structure = self.get_enriched_database_schema(company_short_name, db_name)
|
|
218
|
-
if not enriched_structure:
|
|
219
|
-
continue
|
|
220
|
-
|
|
221
|
-
if allowed_tables is not None:
|
|
222
|
-
enriched_structure = {
|
|
223
|
-
table_name: table_data
|
|
224
|
-
for table_name, table_data in enriched_structure.items()
|
|
225
|
-
if self._table_is_allowed(table_name, allowed_tables)
|
|
226
|
-
}
|
|
227
|
-
if not enriched_structure:
|
|
228
|
-
continue
|
|
229
|
-
if table_filter is not None:
|
|
230
|
-
# Tables the person may not query (enterprise's knowledge tables, BL-010).
|
|
231
|
-
enriched_structure = {
|
|
232
|
-
table_name: table_data
|
|
233
|
-
for table_name, table_data in enriched_structure.items()
|
|
234
|
-
if table_filter(db_name, table_name)
|
|
235
|
-
}
|
|
236
|
-
if not enriched_structure:
|
|
237
|
-
continue
|
|
238
|
-
|
|
239
|
-
# 2. Build Header for this Database
|
|
240
|
-
dialect = self.sql_service.get_database_dialect(company_short_name, db_name)
|
|
241
|
-
dialect_suffix = f" [dialect={dialect}]" if dialect else ""
|
|
242
|
-
db_context = f"### Base SQL (`database_key`): {db_name}{dialect_suffix}\n"
|
|
243
|
-
|
|
244
|
-
# Optional: Add DB description from config if available (useful context)
|
|
245
|
-
db_desc = source.get('description', '')
|
|
246
|
-
if db_desc:
|
|
247
|
-
db_context += f"- Descripcion: {db_desc}\n"
|
|
248
|
-
|
|
249
|
-
db_context += (
|
|
250
|
-
f"- Usa `iat_sql_query` con `database_key='{db_name}'` para consultar esta base.\n"
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
# 3. Format Tables
|
|
254
|
-
for table_name, table_data in enriched_structure.items():
|
|
255
|
-
table_desc = table_data.get('description', '')
|
|
256
|
-
columns = table_data.get('columns', [])
|
|
257
|
-
|
|
258
|
-
# Table Header
|
|
259
|
-
table_str = f"\n\n#### Tabla: `{table_name}`"
|
|
260
|
-
if table_desc:
|
|
261
|
-
table_str += f"\n- Descripcion: {table_desc}"
|
|
262
|
-
|
|
263
|
-
table_str += "\n- Columnas:"
|
|
264
|
-
|
|
265
|
-
# Format Columns
|
|
266
|
-
for col in columns:
|
|
267
|
-
col_name = col.get('name')
|
|
268
|
-
col_type = col.get('type', 'unknown')
|
|
269
|
-
col_desc = col.get('description', '')
|
|
270
|
-
col_props = col.get('properties') # Nested JSONB structure
|
|
271
|
-
|
|
272
|
-
col_line = f"\n - `{col_name}` ({col_type})"
|
|
273
|
-
if col_desc:
|
|
274
|
-
col_line += f": {col_desc}"
|
|
275
|
-
|
|
276
|
-
table_str += col_line
|
|
277
|
-
|
|
278
|
-
# If it has nested properties (JSONB enriched from YAML), format them
|
|
279
|
-
if col_props:
|
|
280
|
-
table_str += "\n"
|
|
281
|
-
table_str += self._format_json_schema(col_props, 2) # Indent level 2
|
|
282
|
-
|
|
283
|
-
db_context += table_str
|
|
284
|
-
|
|
285
|
-
# collect the table names for later use
|
|
286
|
-
db_tables.append(
|
|
287
|
-
{'db_name': db_name,
|
|
288
|
-
'table_name': table_name,
|
|
289
|
-
}
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
context_output.append(db_context)
|
|
293
|
-
|
|
294
|
-
except Exception as e:
|
|
295
|
-
logging.warning(f"Could not generate enriched SQL context for '{db_name}': {e}")
|
|
296
|
-
|
|
297
|
-
if not context_output:
|
|
298
|
-
return "", []
|
|
299
|
-
|
|
300
|
-
header = (
|
|
301
|
-
"## Bases de datos SQL disponibles\n\n"
|
|
302
|
-
"Estas son las bases SQL que puedes consultar usando `iat_sql_query`. "
|
|
303
|
-
"El schema a continuacion incluye metadata enriquecida.\n"
|
|
199
|
+
The columns travel only when a question needs them, through
|
|
200
|
+
`iat_sql_schema`: the whole schema in the base context was resent on
|
|
201
|
+
every model call and never compacted (~33k tokens at Maxxa).
|
|
202
|
+
Returns the block and the (db_name, table_name) pairs it covers.
|
|
203
|
+
"""
|
|
204
|
+
sources = self.sql_catalog.sources(
|
|
205
|
+
company_short_name, allowed_databases=allowed_databases, table_filter=table_filter,
|
|
304
206
|
)
|
|
305
|
-
|
|
306
|
-
|
|
207
|
+
db_tables = [
|
|
208
|
+
{"db_name": source["database_key"], "table_name": table["name"]}
|
|
209
|
+
for source in sources
|
|
210
|
+
for table in source["tables"]
|
|
211
|
+
]
|
|
212
|
+
return self.sql_catalog.render_map(sources), db_tables
|
|
307
213
|
|
|
308
214
|
def _get_yaml_schema_context(
|
|
309
215
|
self,
|
|
@@ -33,6 +33,8 @@ class Dispatcher:
|
|
|
33
33
|
"iat_memory_answer_question",
|
|
34
34
|
"iat_wiki_search",
|
|
35
35
|
"iat_wiki_get_page",
|
|
36
|
+
# The schema shown is the person's: their sources and tables (BL-017).
|
|
37
|
+
"iat_sql_schema",
|
|
36
38
|
}
|
|
37
39
|
_tool_execution_hook = None
|
|
38
40
|
# Tool types this module executes itself; an extension cannot take them over.
|
|
@@ -60,7 +60,7 @@ class HistoryCompactionService:
|
|
|
60
60
|
#: Parts per compaction: in the background, enough for a history that grew
|
|
61
61
|
#: without compaction (before BL-009) without summarizing forever; in line,
|
|
62
62
|
#: one, because the person is waiting.
|
|
63
|
-
MAX_CHUNKS =
|
|
63
|
+
MAX_CHUNKS = 4
|
|
64
64
|
|
|
65
65
|
@inject
|
|
66
66
|
def __init__(self,
|
|
@@ -117,7 +117,11 @@ class HistoryCompactionService:
|
|
|
117
117
|
chunks = chunks[-limit:]
|
|
118
118
|
|
|
119
119
|
summary = plan.previous_summary
|
|
120
|
-
for chunk in chunks:
|
|
120
|
+
for index, chunk in enumerate(chunks):
|
|
121
|
+
if index and not self._still_matches(company_short_name, user_identifier, model, plan):
|
|
122
|
+
# Each part costs a model call of minutes; once the history has
|
|
123
|
+
# changed under the plan, the rest would be summarized for nothing.
|
|
124
|
+
return {"status": "skipped", "reason": "history_changed", "summarized_parts": index}
|
|
121
125
|
try:
|
|
122
126
|
response = self.system_agent_runner.run(
|
|
123
127
|
company,
|
|
@@ -276,6 +280,11 @@ class HistoryCompactionService:
|
|
|
276
280
|
# Applying
|
|
277
281
|
# ------------------------------------------------------------------
|
|
278
282
|
|
|
283
|
+
def _still_matches(self, company_short_name: str, user_identifier: str, model: str,
|
|
284
|
+
plan: CompactionPlan) -> bool:
|
|
285
|
+
current = self.session_context.get_context_history(company_short_name, user_identifier, model=model) or []
|
|
286
|
+
return len(current) >= plan.cut and self._fingerprint(current[:plan.cut]) == plan.prefix_hash
|
|
287
|
+
|
|
279
288
|
def _apply(self, company_short_name: str, user_identifier: str, model: str,
|
|
280
289
|
plan: CompactionPlan, summary: str) -> dict:
|
|
281
290
|
lock_key = self.history_manager.history_lock_key(company_short_name, user_identifier, model)
|
|
@@ -326,18 +335,35 @@ class HistoryCompactionService:
|
|
|
326
335
|
for key in ("structured_output", "parsed_output"):
|
|
327
336
|
structured = response.get(key)
|
|
328
337
|
if isinstance(structured, dict) and isinstance(structured.get("summary"), str):
|
|
329
|
-
return structured["summary"]
|
|
338
|
+
return HistoryCompactionService._unfence(structured["summary"])
|
|
330
339
|
answer = response.get("answer")
|
|
331
340
|
if isinstance(answer, str) and answer.strip():
|
|
332
|
-
text =
|
|
341
|
+
text = HistoryCompactionService._unfence(answer)
|
|
333
342
|
try:
|
|
334
343
|
parsed = json.loads(text)
|
|
335
344
|
except (TypeError, ValueError):
|
|
336
345
|
return text
|
|
337
346
|
if isinstance(parsed, dict) and isinstance(parsed.get("summary"), str):
|
|
338
|
-
return parsed["summary"]
|
|
347
|
+
return HistoryCompactionService._unfence(parsed["summary"])
|
|
348
|
+
return text
|
|
339
349
|
return ""
|
|
340
350
|
|
|
351
|
+
@staticmethod
|
|
352
|
+
def _unfence(text: str) -> str:
|
|
353
|
+
"""The text without a Markdown code block around it.
|
|
354
|
+
|
|
355
|
+
Seen in production: the summary came back as ```summary ... ```, which
|
|
356
|
+
stored as is would put the whole summary inside a code block.
|
|
357
|
+
"""
|
|
358
|
+
stripped = str(text or "").strip()
|
|
359
|
+
if not stripped.startswith("```"):
|
|
360
|
+
return stripped
|
|
361
|
+
lines = stripped.split("\n")
|
|
362
|
+
body = lines[1:]
|
|
363
|
+
if body and body[-1].strip() == "```":
|
|
364
|
+
body = body[:-1]
|
|
365
|
+
return "\n".join(body).strip()
|
|
366
|
+
|
|
341
367
|
def _count(self, message: Any) -> int:
|
|
342
368
|
try:
|
|
343
369
|
return int(self.llm_client.count_tokens(json.dumps(message, ensure_ascii=False, default=str)))
|
|
@@ -1606,8 +1606,9 @@ class llmClient:
|
|
|
1606
1606
|
sql {sql_query}
|
|
1607
1607
|
|
|
1608
1608
|
**INSTRUCCIÓN OBLIGATORIA:**
|
|
1609
|
-
1. Analiza el error y corrige la
|
|
1610
|
-
|
|
1609
|
+
1. Analiza el error y corrige la consulta SQL anterior. Si dice que una columna o una tabla
|
|
1610
|
+
no existe, pide primero sus columnas reales con `iat_sql_schema`; no adivines otro nombre.
|
|
1611
|
+
2. Llama a la herramienta `{function_name}` **OTRA VEZ** con la consulta corregida.
|
|
1611
1612
|
3. **NO** respondas al usuario con este mensaje de error. Tu ÚNICA acción debe ser volver a llamar a la herramienta con la solución.
|
|
1612
1613
|
"""
|
|
1613
1614
|
|
|
@@ -32,7 +32,16 @@ from iatoolkit.common.exceptions import IAToolkitException
|
|
|
32
32
|
from iatoolkit.repositories.database_manager import DatabaseManager
|
|
33
33
|
from iatoolkit.repositories.models import CollectionType, Company, Document, KnowledgeWiki
|
|
34
34
|
|
|
35
|
-
SQL_TOOLS = frozenset({"iat_sql_query"})
|
|
35
|
+
SQL_TOOLS = frozenset({"iat_sql_query", "iat_sql_schema"})
|
|
36
|
+
#: Tools whose access follows another tool's (BL-017): whoever may query may read
|
|
37
|
+
#: the schema of what they query, and nobody else. Without this a new tool falls
|
|
38
|
+
#: to the type default and can end up wider or narrower than the one it serves.
|
|
39
|
+
TOOL_ACCESS_ALIASES = {"iat_sql_schema": "iat_sql_query"}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def tool_access_key(function_name: str) -> str:
|
|
43
|
+
"""The tool name whose access list decides this tool's access."""
|
|
44
|
+
return TOOL_ACCESS_ALIASES.get(function_name, function_name)
|
|
36
45
|
COLLECTION_TOOLS = frozenset({"iat_document_search", "iat_document_list", "iat_image_search", "iat_visual_search"})
|
|
37
46
|
DOCUMENT_READ_TOOLS = frozenset({"iat_document_read"})
|
|
38
47
|
WIKI_TOOLS = frozenset({"iat_wiki_search", "iat_wiki_get_page"})
|
|
@@ -55,7 +64,7 @@ class ResourceAccessScope:
|
|
|
55
64
|
"""The call's arguments, narrowed to what the person may reach; raises PERMISSION otherwise."""
|
|
56
65
|
if not user_identifier:
|
|
57
66
|
return arguments
|
|
58
|
-
if not access.can(company_short_name, user_identifier, USE, "tool", function_name):
|
|
67
|
+
if not access.can(company_short_name, user_identifier, USE, "tool", tool_access_key(function_name)):
|
|
59
68
|
raise _denied(f"No access to the tool '{function_name}'.")
|
|
60
69
|
|
|
61
70
|
scoped = dict(arguments)
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
The SQL schema a person can see, in one place (BL-017).
|
|
8
|
+
|
|
9
|
+
Two levels, as the MCP always worked: a map of each source (its tables, without
|
|
10
|
+
columns) that is cheap enough to travel in every model call, and the columns of
|
|
11
|
+
the tables a question needs, asked for when it needs them (`iat_sql_schema` in
|
|
12
|
+
the chat, `get_sql_schema` over MCP).
|
|
13
|
+
|
|
14
|
+
Every filter lives here, so the chat and the MCP cannot show different tables to
|
|
15
|
+
the same person: the source must be active, the person must be allowed the
|
|
16
|
+
source (BL-010), the table must be one of the source's `included_tables`, and
|
|
17
|
+
tables holding resources of their own (enterprise's knowledge tables) must pass
|
|
18
|
+
`access.sql_table_filter`.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import logging
|
|
24
|
+
from typing import Any, Callable, Optional
|
|
25
|
+
|
|
26
|
+
from iatoolkit.common import access
|
|
27
|
+
|
|
28
|
+
TableFilter = Optional[Callable[[str, str], bool]]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SqlCatalogService:
|
|
32
|
+
#: Tables one call to `iat_sql_schema` may describe: the columns of a whole
|
|
33
|
+
#: database in one answer is the cost this service exists to avoid.
|
|
34
|
+
MAX_TABLES_PER_REQUEST = 10
|
|
35
|
+
#: One line per table in the map.
|
|
36
|
+
MAP_DESCRIPTION_MAX_CHARS = 200
|
|
37
|
+
SCHEMA_TOOL_NAME = "iat_sql_schema"
|
|
38
|
+
QUERY_TOOL_NAME = "iat_sql_query"
|
|
39
|
+
|
|
40
|
+
def __init__(self, company_context_service, sql_source_service, sql_service):
|
|
41
|
+
# Built by CompanyContextService itself (it owns the enriched schema and
|
|
42
|
+
# this owns what of it a person sees), so no injector cycle between them.
|
|
43
|
+
self.company_context_service = company_context_service
|
|
44
|
+
self.sql_source_service = sql_source_service
|
|
45
|
+
self.sql_service = sql_service
|
|
46
|
+
|
|
47
|
+
# ------------------------------------------------------------------
|
|
48
|
+
# Scope of a person
|
|
49
|
+
# ------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
def person_scope(self, company_short_name: str, user_identifier: str | None) -> tuple[list[str] | None, TableFilter]:
|
|
52
|
+
"""(allowed databases, table filter) for this person; (None, None) when nothing is restricted."""
|
|
53
|
+
if not user_identifier or not access.Access.registered():
|
|
54
|
+
return None, None
|
|
55
|
+
databases = [str(s.get("database") or "") for s in self._active_sources(company_short_name) if s.get("database")]
|
|
56
|
+
allowed = [d for d in databases
|
|
57
|
+
if access.can(company_short_name, user_identifier, access.USE, "sql_source", d)]
|
|
58
|
+
table_filter = access.sql_table_filter(company_short_name, user_identifier)
|
|
59
|
+
return (None if len(allowed) == len(databases) else allowed), table_filter
|
|
60
|
+
|
|
61
|
+
# ------------------------------------------------------------------
|
|
62
|
+
# The two levels
|
|
63
|
+
# ------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
def sources(self, company_short_name: str, *, allowed_databases: list[str] | None = None,
|
|
66
|
+
table_filter: TableFilter = None) -> list[dict]:
|
|
67
|
+
"""Each visible source with its visible tables (name, kind, description), no columns."""
|
|
68
|
+
allowed = self._allowed_set(allowed_databases)
|
|
69
|
+
if allowed is not None and not allowed:
|
|
70
|
+
return []
|
|
71
|
+
items = []
|
|
72
|
+
for source in self._active_sources(company_short_name):
|
|
73
|
+
database_key = str(source.get("database") or "").strip()
|
|
74
|
+
if not database_key or (allowed is not None and database_key not in allowed):
|
|
75
|
+
continue
|
|
76
|
+
try:
|
|
77
|
+
tables = self.visible_schema(company_short_name, database_key, source=source, table_filter=table_filter)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
logging.warning(f"Could not read the schema of '{database_key}' for '{company_short_name}': {e}")
|
|
80
|
+
continue
|
|
81
|
+
if not tables:
|
|
82
|
+
continue
|
|
83
|
+
items.append({
|
|
84
|
+
"database_key": database_key,
|
|
85
|
+
"dialect": self._dialect(company_short_name, database_key),
|
|
86
|
+
"description": str(source.get("description") or "").strip(),
|
|
87
|
+
"tables": [
|
|
88
|
+
{
|
|
89
|
+
"name": name,
|
|
90
|
+
"object_type": data.get("object_type") or "table",
|
|
91
|
+
"description": self._one_line(data.get("description")),
|
|
92
|
+
}
|
|
93
|
+
for name, data in tables.items()
|
|
94
|
+
],
|
|
95
|
+
})
|
|
96
|
+
return items
|
|
97
|
+
|
|
98
|
+
def describe(self, company_short_name: str, database_key: str, table_names: list[str] | None, *,
|
|
99
|
+
allowed_databases: list[str] | None = None, table_filter: TableFilter = None) -> dict:
|
|
100
|
+
"""The columns of the requested tables of one source, or why they cannot be given."""
|
|
101
|
+
database_key = str(database_key or "").strip()
|
|
102
|
+
source = self._source(company_short_name, database_key)
|
|
103
|
+
allowed = self._allowed_set(allowed_databases)
|
|
104
|
+
if source is None or (allowed is not None and database_key not in allowed):
|
|
105
|
+
return {"database_key": database_key, "error": "unknown_database",
|
|
106
|
+
"available_databases": [s["database_key"] for s in self.sources(
|
|
107
|
+
company_short_name, allowed_databases=allowed_databases, table_filter=table_filter)]}
|
|
108
|
+
|
|
109
|
+
visible = self.visible_schema(company_short_name, database_key, source=source, table_filter=table_filter)
|
|
110
|
+
requested = [str(name or "").strip() for name in (table_names or []) if str(name or "").strip()]
|
|
111
|
+
if not requested:
|
|
112
|
+
return {"database_key": database_key, "error": "table_names_required",
|
|
113
|
+
"available_tables": list(visible.keys())}
|
|
114
|
+
|
|
115
|
+
index = {}
|
|
116
|
+
for name in visible:
|
|
117
|
+
for candidate in self.company_context_service._table_name_candidates(name):
|
|
118
|
+
index.setdefault(candidate, name)
|
|
119
|
+
found: dict[str, dict] = {}
|
|
120
|
+
unknown: list[str] = []
|
|
121
|
+
for name in requested:
|
|
122
|
+
match = next((index[c] for c in self.company_context_service._table_name_candidates(name) if c in index), None)
|
|
123
|
+
if match is None:
|
|
124
|
+
unknown.append(name)
|
|
125
|
+
elif match not in found:
|
|
126
|
+
found[match] = visible[match]
|
|
127
|
+
|
|
128
|
+
omitted = list(found)[self.MAX_TABLES_PER_REQUEST:]
|
|
129
|
+
for name in omitted:
|
|
130
|
+
found.pop(name)
|
|
131
|
+
result = {
|
|
132
|
+
"database_key": database_key,
|
|
133
|
+
"dialect": self._dialect(company_short_name, database_key),
|
|
134
|
+
"tables": found,
|
|
135
|
+
}
|
|
136
|
+
if unknown:
|
|
137
|
+
result["unknown_tables"] = unknown
|
|
138
|
+
result["available_tables"] = list(visible.keys())
|
|
139
|
+
if omitted:
|
|
140
|
+
result["omitted_tables"] = omitted
|
|
141
|
+
return result
|
|
142
|
+
|
|
143
|
+
def visible_schema(self, company_short_name: str, database_key: str, *, source: dict | None = None,
|
|
144
|
+
table_filter: TableFilter = None) -> dict:
|
|
145
|
+
"""The enriched schema of one source, narrowed to the tables a person may see."""
|
|
146
|
+
source = source if source is not None else self._source(company_short_name, database_key)
|
|
147
|
+
if source is None:
|
|
148
|
+
return {}
|
|
149
|
+
ccs = self.company_context_service
|
|
150
|
+
schema = ccs.get_enriched_database_schema(company_short_name, database_key) or {}
|
|
151
|
+
included = ccs._resolve_allowed_tables_for_source(source)
|
|
152
|
+
return {
|
|
153
|
+
name: data
|
|
154
|
+
for name, data in schema.items()
|
|
155
|
+
if ccs._table_is_allowed(name, included)
|
|
156
|
+
and (table_filter is None or table_filter(database_key, name))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# ------------------------------------------------------------------
|
|
160
|
+
# What the model reads
|
|
161
|
+
# ------------------------------------------------------------------
|
|
162
|
+
|
|
163
|
+
def render_map(self, sources: list[dict]) -> str:
|
|
164
|
+
if not sources:
|
|
165
|
+
return ""
|
|
166
|
+
parts = []
|
|
167
|
+
for source in sources:
|
|
168
|
+
dialect = f" [dialect={source['dialect']}]" if source.get("dialect") else ""
|
|
169
|
+
lines = [f"### Base SQL (`database_key`): {source['database_key']}{dialect}"]
|
|
170
|
+
if source.get("description"):
|
|
171
|
+
lines.append(f"- Descripcion: {source['description']}")
|
|
172
|
+
lines.append("- Tablas:")
|
|
173
|
+
for table in source.get("tables") or []:
|
|
174
|
+
kind = " (vista)" if table.get("object_type") == "view" else ""
|
|
175
|
+
description = f": {table['description']}" if table.get("description") else ""
|
|
176
|
+
lines.append(f" - `{table['name']}`{kind}{description}")
|
|
177
|
+
parts.append("\n".join(lines))
|
|
178
|
+
header = (
|
|
179
|
+
"## Bases de datos SQL disponibles\n\n"
|
|
180
|
+
f"Estas son las bases SQL que puedes consultar, con sus tablas. Antes de escribir una consulta, "
|
|
181
|
+
f"pide con `{self.SCHEMA_TOOL_NAME}` las columnas de las tablas que vas a usar (varias en una sola "
|
|
182
|
+
f"llamada); luego consulta con `{self.QUERY_TOOL_NAME}`. Usa solo tablas de esta lista y columnas "
|
|
183
|
+
f"que `{self.SCHEMA_TOOL_NAME}` te haya mostrado.\n"
|
|
184
|
+
)
|
|
185
|
+
return header + "\n\n---\n\n".join(parts)
|
|
186
|
+
|
|
187
|
+
def render_tables(self, description: dict) -> str:
|
|
188
|
+
"""`describe`'s answer as the model reads it: the columns of each table, or what to do instead."""
|
|
189
|
+
database_key = description.get("database_key") or ""
|
|
190
|
+
error = description.get("error")
|
|
191
|
+
if error == "unknown_database":
|
|
192
|
+
available = ", ".join(f"`{d}`" for d in description.get("available_databases") or []) or "(ninguna)"
|
|
193
|
+
return f"La base `{database_key}` no existe o no tienes acceso. Bases disponibles: {available}."
|
|
194
|
+
if error == "table_names_required":
|
|
195
|
+
return (f"Indica en `table_names` las tablas de `{database_key}` que necesitas (hasta "
|
|
196
|
+
f"{self.MAX_TABLES_PER_REQUEST}). Tablas: {self._names(description.get('available_tables'))}.")
|
|
197
|
+
|
|
198
|
+
dialect = f" [dialect={description['dialect']}]" if description.get("dialect") else ""
|
|
199
|
+
out = [f"### Base SQL (`database_key`): {database_key}{dialect}"]
|
|
200
|
+
for table_name, table_data in (description.get("tables") or {}).items():
|
|
201
|
+
out.append(self._render_table(table_name, table_data))
|
|
202
|
+
if description.get("unknown_tables"):
|
|
203
|
+
out.append(
|
|
204
|
+
f"\nNo existen o no tienes acceso: {self._names(description['unknown_tables'])}. "
|
|
205
|
+
f"Tablas de `{database_key}`: {self._names(description.get('available_tables'))}."
|
|
206
|
+
)
|
|
207
|
+
if description.get("omitted_tables"):
|
|
208
|
+
out.append(
|
|
209
|
+
f"\nSe describen hasta {self.MAX_TABLES_PER_REQUEST} tablas por llamada; pide en otra: "
|
|
210
|
+
f"{self._names(description['omitted_tables'])}."
|
|
211
|
+
)
|
|
212
|
+
return "\n".join(out)
|
|
213
|
+
|
|
214
|
+
def _render_table(self, table_name: str, table_data: dict) -> str:
|
|
215
|
+
text = f"\n#### Tabla: `{table_name}`"
|
|
216
|
+
if table_data.get("description"):
|
|
217
|
+
text += f"\n- Descripcion: {table_data['description']}"
|
|
218
|
+
text += "\n- Columnas:"
|
|
219
|
+
for column in table_data.get("columns") or []:
|
|
220
|
+
line = f"\n - `{column.get('name')}` ({column.get('type', 'unknown')})"
|
|
221
|
+
if column.get("description"):
|
|
222
|
+
line += f": {column['description']}"
|
|
223
|
+
text += line
|
|
224
|
+
if column.get("properties"):
|
|
225
|
+
text += "\n" + self.company_context_service._format_json_schema(column["properties"], 2)
|
|
226
|
+
return text
|
|
227
|
+
|
|
228
|
+
# ------------------------------------------------------------------
|
|
229
|
+
# Helpers
|
|
230
|
+
# ------------------------------------------------------------------
|
|
231
|
+
|
|
232
|
+
def _active_sources(self, company_short_name: str) -> list[dict]:
|
|
233
|
+
return self.sql_source_service.list_sources(company_short_name, include_inactive=False) or []
|
|
234
|
+
|
|
235
|
+
def _source(self, company_short_name: str, database_key: str) -> dict | None:
|
|
236
|
+
return next((s for s in self._active_sources(company_short_name)
|
|
237
|
+
if str(s.get("database") or "").strip() == database_key), None)
|
|
238
|
+
|
|
239
|
+
def _dialect(self, company_short_name: str, database_key: str) -> str:
|
|
240
|
+
try:
|
|
241
|
+
return self.sql_service.get_database_dialect(company_short_name, database_key) or ""
|
|
242
|
+
except Exception:
|
|
243
|
+
return ""
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def _allowed_set(allowed_databases: list[str] | None) -> set[str] | None:
|
|
247
|
+
if allowed_databases is None:
|
|
248
|
+
return None
|
|
249
|
+
return {str(d or "").strip() for d in allowed_databases if str(d or "").strip()}
|
|
250
|
+
|
|
251
|
+
@classmethod
|
|
252
|
+
def _one_line(cls, description: Any) -> str:
|
|
253
|
+
text = " ".join(str(description or "").split())
|
|
254
|
+
if len(text) <= cls.MAP_DESCRIPTION_MAX_CHARS:
|
|
255
|
+
return text
|
|
256
|
+
return text[:cls.MAP_DESCRIPTION_MAX_CHARS].rstrip() + "…"
|
|
257
|
+
|
|
258
|
+
@staticmethod
|
|
259
|
+
def _names(names: list[str] | None) -> str:
|
|
260
|
+
return ", ".join(f"`{n}`" for n in names or []) or "(ninguna)"
|