iatoolkit 2.74.0__tar.gz → 2.74.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. {iatoolkit-2.74.0/src/iatoolkit.egg-info → iatoolkit-2.74.1}/PKG-INFO +1 -1
  2. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/__init__.py +1 -1
  3. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/model_registry.py +42 -5
  4. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_providers/openai_adapter.py +9 -5
  5. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_proxy.py +42 -0
  6. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/attachment_policy_service.py +51 -132
  7. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/configuration_service.py +5 -1
  8. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/system_agent_runner.py +3 -2
  9. {iatoolkit-2.74.0 → iatoolkit-2.74.1/src/iatoolkit.egg-info}/PKG-INFO +1 -1
  10. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/LICENSE +0 -0
  11. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/LICENSE_COMMUNITY.md +0 -0
  12. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/pyproject.toml +0 -0
  13. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/readme.md +0 -0
  14. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/setup.cfg +0 -0
  15. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/base_company.py +0 -0
  16. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/cli_commands.py +0 -0
  17. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/__init__.py +0 -0
  18. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/access.py +0 -0
  19. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/bridge_validation.py +0 -0
  20. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/company_paths.py +0 -0
  21. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/exceptions.py +0 -0
  22. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/__init__.py +0 -0
  23. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
  24. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
  25. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/history_compaction_trigger.py +0 -0
  26. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
  27. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
  28. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
  29. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
  30. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/memory_tools.py +0 -0
  31. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/routes.py +0 -0
  32. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/search_terms.py +0 -0
  33. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/secret_resolver.py +0 -0
  34. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/session_manager.py +0 -0
  35. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/text_splitter.py +0 -0
  36. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/url_safety.py +0 -0
  37. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/common/util.py +0 -0
  38. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/company_registry.py +0 -0
  39. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/__init__.py +0 -0
  40. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
  41. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents/history_compaction.prompt +0 -0
  42. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents/memory_compiler.prompt +0 -0
  43. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents/memory_correction.prompt +0 -0
  44. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents/memory_document_ingest.prompt +0 -0
  45. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents/memory_image_ingest.prompt +0 -0
  46. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents/memory_meeting_ingest.prompt +0 -0
  47. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents/memory_question_review.prompt +0 -0
  48. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_agents_pack.yaml +0 -0
  49. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/channel_business_identity.prompt +0 -0
  50. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/channel_conversation_continuity.prompt +0 -0
  51. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/channel_response_style.prompt +0 -0
  52. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
  53. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
  54. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
  55. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
  56. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
  57. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
  58. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
  59. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
  60. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
  61. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
  62. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
  63. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
  64. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
  65. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
  66. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
  67. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_core.prompt +0 -0
  68. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
  69. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_mysql_casting.prompt +0 -0
  70. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_mysql_json.prompt +0 -0
  71. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_redshift_basics.prompt +0 -0
  72. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_redshift_types.prompt +0 -0
  73. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/sql_rules.prompt +0 -0
  74. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
  75. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
  76. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
  77. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/core.py +0 -0
  78. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/__init__.py +0 -0
  79. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
  80. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/call_service.py +0 -0
  81. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  82. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  83. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  84. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  85. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  86. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  87. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  88. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/google_auth_client.py +0 -0
  89. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/google_chat_app.py +0 -0
  90. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
  91. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/inference_handler.py +0 -0
  92. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
  93. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_gateway_resolver.py +0 -0
  94. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
  95. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
  96. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
  97. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
  98. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
  99. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
  100. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/llm_response.py +0 -0
  101. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  102. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/locales/en.yaml +0 -0
  103. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/locales/es.yaml +0 -0
  104. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/__init__.py +0 -0
  105. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/advisory_lock.py +0 -0
  106. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/api_key_repo.py +0 -0
  107. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/bridge_repo.py +0 -0
  108. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/database_manager.py +0 -0
  109. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/document_repo.py +0 -0
  110. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
  111. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
  112. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/knowledge_wiki_repo.py +0 -0
  113. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  114. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/mcp_token_repo.py +0 -0
  115. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/memory_question_repo.py +0 -0
  116. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/memory_repo.py +0 -0
  117. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/memory_usage_repo.py +0 -0
  118. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/models.py +0 -0
  119. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/profile_repo.py +0 -0
  120. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
  121. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
  122. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
  123. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/repositories/vs_repo.py +0 -0
  124. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/runtime_logging.py +0 -0
  125. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/__init__.py +0 -0
  126. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/api_key_service.py +0 -0
  127. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/auth_service.py +0 -0
  128. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/branding_service.py +0 -0
  129. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/company_context_service.py +0 -0
  130. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/context_builder_service.py +0 -0
  131. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/dispatcher_service.py +0 -0
  132. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/embedding_service.py +0 -0
  133. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/excel_service.py +0 -0
  134. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/file_processor_service.py +0 -0
  135. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/history_compaction_service.py +0 -0
  136. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/history_manager_service.py +0 -0
  137. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/http_tool_service.py +0 -0
  138. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/i18n_service.py +0 -0
  139. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/inference_service.py +0 -0
  140. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/jwt_service.py +0 -0
  141. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/knowledge_base_service.py +0 -0
  142. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/language_service.py +0 -0
  143. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/license_service.py +0 -0
  144. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/llm_client_service.py +0 -0
  145. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/mail_service.py +0 -0
  146. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/markdown_wiki_service.py +0 -0
  147. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/mcp_token_service.py +0 -0
  148. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/memory_compiler_service.py +0 -0
  149. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
  150. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/memory_question_service.py +0 -0
  151. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/memory_service.py +0 -0
  152. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/memory_sources.py +0 -0
  153. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/memory_usage_service.py +0 -0
  154. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/memory_wiki_service.py +0 -0
  155. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/noop_history_compaction_trigger.py +0 -0
  156. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
  157. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/operator_identity_service.py +0 -0
  158. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/__init__.py +0 -0
  159. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/contracts.py +0 -0
  160. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
  161. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
  162. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
  163. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
  164. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
  165. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
  166. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
  167. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
  168. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/parsers/validator.py +0 -0
  169. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/pdf_service.py +0 -0
  170. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/profile_service.py +0 -0
  171. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/prompt_resource_service.py +0 -0
  172. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/prompt_service.py +0 -0
  173. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/query_service.py +0 -0
  174. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/resource_access_scope.py +0 -0
  175. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
  176. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/sql_dataset_service.py +0 -0
  177. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/sql_service.py +0 -0
  178. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/sql_source_service.py +0 -0
  179. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/storage_service.py +0 -0
  180. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/structured_output_service.py +0 -0
  181. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/system_agent_catalog.py +0 -0
  182. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
  183. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/system_tools.py +0 -0
  184. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/telemetry_service.py +0 -0
  185. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/tenant_wiki_service.py +0 -0
  186. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/tool_output_contract.py +0 -0
  187. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/tool_service.py +0 -0
  188. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/user_feedback_service.py +0 -0
  189. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/user_session_context_service.py +0 -0
  190. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/visual_kb_service.py +0 -0
  191. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/visual_tool_service.py +0 -0
  192. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/warmup_service.py +0 -0
  193. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/web_search/__init__.py +0 -0
  194. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
  195. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
  196. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
  197. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/web_search_service.py +0 -0
  198. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/services/wiki_page_index_service.py +0 -0
  199. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/images/favicon.ico +0 -0
  200. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/images/favicon.png +0 -0
  201. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  202. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
  203. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
  204. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
  205. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  206. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_header_navigation.js +0 -0
  207. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_help_content.js +0 -0
  208. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_history_button.js +0 -0
  209. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
  210. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_main.js +0 -0
  211. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
  212. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
  213. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
  214. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
  215. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/account.css +0 -0
  216. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
  217. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/chat_modal.css +0 -0
  218. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/chat_public.css +0 -0
  219. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/documents.css +0 -0
  220. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/landing_page.css +0 -0
  221. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/llm_output.css +0 -0
  222. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/onboarding.css +0 -0
  223. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/static/styles/wiki_page.css +0 -0
  224. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/_chat_header.html +0 -0
  225. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/_company_header.html +0 -0
  226. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/_login_widget.html +0 -0
  227. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/account.html +0 -0
  228. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/base.html +0 -0
  229. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/change_password.html +0 -0
  230. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/chat.html +0 -0
  231. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
  232. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/chat_modals.html +0 -0
  233. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/error.html +0 -0
  234. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/forgot_password.html +0 -0
  235. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/home_hosted_default.html +0 -0
  236. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/login_global.html +0 -0
  237. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
  238. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/onboarding_shell.html +0 -0
  239. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/pdf/base.html +0 -0
  240. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/pdf/letter.html +0 -0
  241. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/pdf/report.html +0 -0
  242. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/pdf/simple.html +0 -0
  243. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/signup.html +0 -0
  244. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/templates/wiki_page.html +0 -0
  245. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/__init__.py +0 -0
  246. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/account_view.py +0 -0
  247. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/api_key_api_view.py +0 -0
  248. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/base_login_view.py +0 -0
  249. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/categories_api_view.py +0 -0
  250. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/change_password_view.py +0 -0
  251. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
  252. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/chat_view.py +0 -0
  253. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/configuration_api_view.py +0 -0
  254. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/connectors_api_view.py +0 -0
  255. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/embedding_api_view.py +0 -0
  256. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/forgot_password_view.py +0 -0
  257. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/help_content_api_view.py +0 -0
  258. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/history_api_view.py +0 -0
  259. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/home_view.py +0 -0
  260. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/init_context_api_view.py +0 -0
  261. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/llmquery_api_view.py +0 -0
  262. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/load_document_api_view.py +0 -0
  263. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/login_view.py +0 -0
  264. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/logout_api_view.py +0 -0
  265. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/memory_api_view.py +0 -0
  266. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/profile_api_view.py +0 -0
  267. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/prompt_api_view.py +0 -0
  268. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
  269. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
  270. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/rag_api_view.py +0 -0
  271. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/root_redirect_view.py +0 -0
  272. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/signup_view.py +0 -0
  273. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/static_page_view.py +0 -0
  274. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/tool_api_view.py +0 -0
  275. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
  276. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/users_api_view.py +0 -0
  277. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/verify_user_view.py +0 -0
  278. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit/views/wiki_page_view.py +0 -0
  279. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit.egg-info/SOURCES.txt +0 -0
  280. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  281. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit.egg-info/requires.txt +0 -0
  282. {iatoolkit-2.74.0 → iatoolkit-2.74.1}/src/iatoolkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 2.74.0
3
+ Version: 2.74.1
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
- __version__ = "2.74.0"
6
+ __version__ = "2.74.1"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -165,21 +165,58 @@ class ModelRegistry:
165
165
  return candidate # type: ignore[return-value]
166
166
  return self.get_provider(model or "")
167
167
 
168
- def get_capabilities(self, model: str, provider: str | None = None) -> dict:
168
+ @staticmethod
169
+ def catalog_capabilities(model_config: dict | None) -> dict | None:
170
+ """The capabilities the model catalogue holds for a model, or None when unknown.
171
+
172
+ Written by `models-sync` from OpenRouter (BL-009, Fase F) and carried in
173
+ the model's configuration. Empty, or a company.yaml model outside the
174
+ catalogue, means unknown: the provider's rules decide.
175
+ """
176
+ capabilities = (model_config or {}).get("capabilities") if isinstance(model_config, dict) else None
177
+ if not isinstance(capabilities, dict):
178
+ return None
179
+ if not capabilities.get("supported_parameters") and not capabilities.get("input_modalities"):
180
+ return None
181
+ return capabilities
182
+
183
+ @staticmethod
184
+ def _declares(capabilities: dict | None, *parameters: str) -> bool | None:
185
+ """Whether the model declares any of `parameters`; None when nothing is known."""
186
+ if not capabilities:
187
+ return None
188
+ declared = {str(value).strip().lower() for value in capabilities.get("supported_parameters") or []}
189
+ if not declared:
190
+ return None
191
+ return any(parameter in declared for parameter in parameters)
192
+
193
+ def get_capabilities(self, model: str, provider: str | None = None, capabilities: dict | None = None) -> dict:
194
+ """What the request may carry for this model.
195
+
196
+ Two halves, both required: what the provider's adapter knows how to send,
197
+ and what the model accepts. The second comes from the model catalogue
198
+ (`capabilities`) when it is known; without it, the provider decides alone.
199
+ The catalogue only ever narrows: a parameter the adapter cannot send is
200
+ never offered because the model would accept it.
201
+ """
169
202
  normalized_provider = self.normalize_provider(provider=provider, model=model)
170
203
  # `openai_compatible` is absent on purpose. Its adapter targets any server
171
204
  # that speaks chat.completions — llama.cpp, vLLM, a private gateway — and
172
205
  # forwards no reasoning field, because one the server does not know earns a
173
206
  # 400. Claiming the capability here made the tenant's Models page offer a
174
207
  # reasoning control whose value went nowhere.
175
- supports_reasoning_effort = normalized_provider in {
208
+ adapter_sends_reasoning = normalized_provider in {
176
209
  "openai",
177
210
  "xai",
178
211
  "openrouter",
179
212
  "deepseek",
180
213
  }
181
- supports_text_verbosity = normalized_provider in {"openai", "xai", "openrouter"}
182
- supports_store = normalized_provider in {"openai", "xai"}
214
+ adapter_sends_verbosity = normalized_provider in {"openai", "xai", "openrouter"}
215
+
216
+ model_reasons = self._declares(capabilities, "reasoning", "reasoning_effort")
217
+ model_takes_verbosity = self._declares(capabilities, "verbosity")
218
+ supports_reasoning_effort = adapter_sends_reasoning and model_reasons is not False
219
+ supports_text_verbosity = adapter_sends_verbosity and model_takes_verbosity is not False
183
220
 
184
221
  return {
185
222
  "provider": normalized_provider,
@@ -187,7 +224,7 @@ class ModelRegistry:
187
224
  "allowed_reasoning_efforts": list(self._reasoning_effort_options) if supports_reasoning_effort else [],
188
225
  "supports_text_verbosity": supports_text_verbosity,
189
226
  "allowed_text_verbosity": list(self._text_verbosity_options) if supports_text_verbosity else [],
190
- "supports_store": supports_store,
227
+ "capabilities_source": "catalog" if model_reasons is not None else "provider",
191
228
  }
192
229
 
193
230
  def get_request_defaults(self, model: str) -> dict:
@@ -19,8 +19,9 @@ class OpenAIAdapter:
19
19
  self.client = openai_client
20
20
 
21
21
  #: Reasoning models whose reasoning can travel between calls as encrypted
22
- #: items. Asked only of these: a model without reasoning answers the
23
- #: `include` with a 400.
22
+ #: items, for a model the catalogue does not describe: a model without
23
+ #: reasoning answers the `include` with a 400. When the catalogue knows the
24
+ #: model, the proxy says so (`carries_reasoning`) and this list is not read.
24
25
  _ENCRYPTED_REASONING_MODEL_PREFIXES = ("gpt-5", "o1", "o3", "o4")
25
26
 
26
27
  def create_response(self,
@@ -35,7 +36,8 @@ class OpenAIAdapter:
35
36
  attachments: Optional[List[Dict]] = None,
36
37
  store: Optional[bool] = None,
37
38
  metadata: Optional[Dict[str, str]] = None,
38
- telemetry_execution: Any = None) -> LLMResponse:
39
+ telemetry_execution: Any = None,
40
+ carries_reasoning: Optional[bool] = None) -> LLMResponse:
39
41
  """Llamada a la API de OpenAI y mapeo a estructura común.
40
42
 
41
43
  IAToolkit owns the history (BL-009): every call carries the whole
@@ -62,7 +64,7 @@ class OpenAIAdapter:
62
64
 
63
65
  # Nothing stays at OpenAI: the next call sends the history again.
64
66
  params['store'] = False
65
- if self._carries_encrypted_reasoning(model):
67
+ if self._carries_encrypted_reasoning(model, carries_reasoning):
66
68
  # Without a stored response the model would lose its reasoning
67
69
  # between tool rounds; it comes back encrypted and is sent again.
68
70
  params['include'] = ["reasoning.encrypted_content"]
@@ -93,7 +95,9 @@ class OpenAIAdapter:
93
95
  raise IAToolkitException(IAToolkitException.ErrorType.LLM_ERROR, error_message)
94
96
 
95
97
  @classmethod
96
- def _carries_encrypted_reasoning(cls, model: str) -> bool:
98
+ def _carries_encrypted_reasoning(cls, model: str, carries_reasoning: Optional[bool] = None) -> bool:
99
+ if carries_reasoning is not None:
100
+ return carries_reasoning
97
101
  name = str(model or "").strip().lower()
98
102
  if "-chat" in name:
99
103
  return False # gpt-5-chat-latest and the like do not reason
@@ -160,6 +160,12 @@ class LLMProxy:
160
160
  provider=provider,
161
161
  request_kwargs=request_kwargs,
162
162
  )
163
+ request_kwargs = self._apply_model_capabilities(
164
+ model=model,
165
+ provider=provider,
166
+ model_config=model_config,
167
+ request_kwargs=request_kwargs,
168
+ )
163
169
  if telemetry_execution is not None:
164
170
  request_kwargs["telemetry_execution"] = telemetry_execution
165
171
 
@@ -451,6 +457,42 @@ class LLMProxy:
451
457
  effective_kwargs["reasoning"] = merged_reasoning
452
458
  return effective_kwargs
453
459
 
460
+ def _apply_model_capabilities(
461
+ self,
462
+ model: str,
463
+ provider: str,
464
+ model_config: Dict[str, Any] | None,
465
+ request_kwargs: Dict[str, Any],
466
+ ) -> Dict[str, Any]:
467
+ """Drops the parameters the model itself does not accept (BL-009, Fase F).
468
+
469
+ The steps before this one decide by provider: every OpenAI model gets a
470
+ reasoning effort and a verbosity, which a model that does not reason
471
+ (gpt-4.1, gpt-5-chat) refuses. When the catalogue knows the model, its
472
+ `supported_parameters` have the last word. When it does not, nothing
473
+ changes: the provider's rules stay as they were.
474
+ """
475
+ catalog_capabilities = ModelRegistry.catalog_capabilities(model_config)
476
+ if catalog_capabilities is None:
477
+ return request_kwargs
478
+
479
+ capabilities = self.model_registry.get_capabilities(
480
+ model, provider=provider, capabilities=catalog_capabilities
481
+ )
482
+ effective_kwargs = dict(request_kwargs or {})
483
+ if not capabilities.get("supports_reasoning_effort"):
484
+ effective_kwargs.pop("reasoning", None)
485
+ effective_kwargs.pop("reasoning_effort", None)
486
+ if not capabilities.get("supports_text_verbosity"):
487
+ text = effective_kwargs.get("text")
488
+ if isinstance(text, dict) and "verbosity" in text:
489
+ effective_kwargs["text"] = {key: value for key, value in text.items() if key != "verbosity"}
490
+ if provider == self.PROVIDER_OPENAI:
491
+ # Whether the model's reasoning can travel between calls: the adapter
492
+ # asks for it only then, instead of guessing from the model's name.
493
+ effective_kwargs["carries_reasoning"] = bool(capabilities.get("supports_reasoning_effort"))
494
+ return effective_kwargs
495
+
454
496
  # -------------------------------------------------------------------------
455
497
  # Client cache
456
498
  # -------------------------------------------------------------------------
@@ -10,13 +10,10 @@ from typing import Any, Dict, List
10
10
  import base64
11
11
  import logging
12
12
  import mimetypes
13
- import threading
14
- import time
15
-
16
- import requests
17
13
 
18
14
  from injector import inject
19
15
 
16
+ from iatoolkit.common.model_registry import ModelRegistry
20
17
  from iatoolkit.services.configuration_service import ConfigurationService
21
18
  from iatoolkit.common.util import Utility
22
19
 
@@ -30,16 +27,12 @@ class AttachmentPolicyService:
30
27
 
31
28
  DEFAULT_MODE = MODE_EXTRACTED_ONLY
32
29
  DEFAULT_FALLBACK = FALLBACK_EXTRACT
33
- OPENROUTER_MODELS_CACHE_TTL_SECONDS = 300
34
- OPENROUTER_MODELS_TIMEOUT_SECONDS = 8
35
30
 
36
31
  @inject
37
32
  def __init__(self, configuration_service: ConfigurationService, util: Utility):
38
33
  self.configuration_service = configuration_service
39
34
  self.util = util
40
35
  self._default_capabilities: dict | None = None
41
- self._openrouter_models_cache: dict[str, dict[str, Any]] = {}
42
- self._openrouter_models_cache_lock = threading.Lock()
43
36
  self._default_capabilities_path = (
44
37
  Path(__file__).resolve().parent.parent / "config" / "llm_capabilities.yaml"
45
38
  )
@@ -72,7 +65,7 @@ class AttachmentPolicyService:
72
65
  ) -> dict:
73
66
  mode = self.normalize_mode((policy or {}).get("attachment_mode"))
74
67
  fallback = self.normalize_fallback((policy or {}).get("attachment_fallback"))
75
- capabilities = self.get_effective_provider_capabilities(company_short_name, provider)
68
+ capabilities = self.get_effective_capabilities(company_short_name, provider, model)
76
69
 
77
70
  if not files:
78
71
  return {
@@ -102,8 +95,6 @@ class AttachmentPolicyService:
102
95
  "fallback_to_extract": 0,
103
96
  "errors": 0,
104
97
  }
105
- openrouter_native_image_error: str | None = None
106
- openrouter_native_image_checked = False
107
98
 
108
99
  for file_obj in files:
109
100
  stats["total_files"] += 1
@@ -114,36 +105,17 @@ class AttachmentPolicyService:
114
105
  wants_native = self._wants_native(mode, meta, capabilities)
115
106
  wants_extract = self._wants_extract(mode, meta, capabilities)
116
107
  native_ok = False
117
- native_blocked_by_model_catalog = False
118
108
 
119
109
  if wants_native:
120
- if str(provider or "").strip().lower() == "openrouter":
121
- if not openrouter_native_image_checked:
122
- openrouter_native_image_error = self._get_openrouter_native_image_error(
123
- company_short_name=company_short_name,
124
- model=model,
125
- )
126
- openrouter_native_image_checked = True
127
- if openrouter_native_image_error:
128
- if fallback == self.FALLBACK_EXTRACT or wants_extract:
129
- stats["fallback_to_extract"] += 1
130
- wants_extract = True
131
- native_blocked_by_model_catalog = True
132
- else:
133
- if openrouter_native_image_error not in errors:
134
- errors.append(openrouter_native_image_error)
135
- continue
136
- if (not native_blocked_by_model_catalog) and bool(capabilities.get("supports_native_images")):
110
+ if bool(capabilities.get("supports_native_images")):
137
111
  files_for_context.append(dict(file_obj))
138
112
  native_ok = True
139
113
  stats["native_sent_count"] += 1
140
- elif (not native_blocked_by_model_catalog) and (fallback == self.FALLBACK_EXTRACT or wants_extract):
114
+ elif fallback == self.FALLBACK_EXTRACT or wants_extract:
141
115
  stats["fallback_to_extract"] += 1
142
116
  wants_extract = True
143
- elif not native_blocked_by_model_catalog:
144
- errors.append(
145
- f"Image attachment '{filename}' cannot be sent as native image for provider '{provider}'."
146
- )
117
+ else:
118
+ errors.append(self._native_image_error(filename, provider, model, capabilities))
147
119
 
148
120
  if wants_extract:
149
121
  extract_copy = dict(file_obj)
@@ -204,6 +176,51 @@ class AttachmentPolicyService:
204
176
  "stats": stats,
205
177
  }
206
178
 
179
+ def get_effective_capabilities(self, company_short_name: str, provider: str, model: str | None) -> dict:
180
+ """What can go natively to this model: what the provider's adapter sends, narrowed by the model.
181
+
182
+ The provider half (llm_capabilities.yaml and the company's overrides)
183
+ says what our adapter knows how to send. The model half comes from the
184
+ model catalogue (BL-009, Fase F): `input_modalities` as OpenRouter
185
+ publishes them. Both must hold, so a provider that takes images does not
186
+ make a text-only model take them. A model the catalogue does not know
187
+ keeps the provider's answer.
188
+ """
189
+ capabilities = dict(self.get_effective_provider_capabilities(company_short_name, provider))
190
+ capabilities["capabilities_source"] = "provider"
191
+ modalities = self._model_input_modalities(company_short_name, model)
192
+ if modalities is None:
193
+ return capabilities
194
+ capabilities["supports_native_images"] = bool(capabilities.get("supports_native_images")) and "image" in modalities
195
+ capabilities["supports_native_files"] = bool(capabilities.get("supports_native_files")) and "file" in modalities
196
+ capabilities["input_modalities"] = sorted(modalities)
197
+ capabilities["capabilities_source"] = "catalog"
198
+ return capabilities
199
+
200
+ def _model_input_modalities(self, company_short_name: str, model: str | None) -> set[str] | None:
201
+ if not model:
202
+ return None
203
+ try:
204
+ model_config = self.configuration_service.get_llm_model_config(company_short_name, model) or {}
205
+ except Exception as e:
206
+ logging.debug("Could not read the configuration of model '%s': %s", model, e)
207
+ return None
208
+ catalog = ModelRegistry.catalog_capabilities(model_config)
209
+ if not catalog or not catalog.get("input_modalities"):
210
+ return None
211
+ return {str(value).strip().lower() for value in catalog["input_modalities"] if str(value or "").strip()}
212
+
213
+ @staticmethod
214
+ def _native_image_error(filename: str, provider: str, model: str | None, capabilities: dict) -> str:
215
+ if capabilities.get("capabilities_source") == "catalog":
216
+ modalities = ", ".join(capabilities.get("input_modalities") or []) or "(none)"
217
+ return (
218
+ f"Image attachment '{filename}' cannot be sent as a native image: the model catalogue "
219
+ f"publishes '{model}' with input modalities {modalities}, without 'image'. "
220
+ "Use a model that takes images, or allow text extraction."
221
+ )
222
+ return f"Image attachment '{filename}' cannot be sent as native image for provider '{provider}'."
223
+
207
224
  def get_effective_provider_capabilities(self, company_short_name: str, provider: str) -> dict:
208
225
  provider_key = str(provider or "unknown").strip().lower() or "unknown"
209
226
  defaults = self._load_default_capabilities().get(provider_key) or self._load_default_capabilities().get("unknown", {})
@@ -270,104 +287,6 @@ class AttachmentPolicyService:
270
287
  merged.setdefault("max_files_per_request", 0)
271
288
  return merged
272
289
 
273
- def _get_openrouter_native_image_error(self, company_short_name: str, model: str | None) -> str | None:
274
- model_id = str(model or "").strip()
275
- if not model_id:
276
- return (
277
- "Este modelo/provider no expone visión nativa por API: no se resolvio el modelo efectivo "
278
- "para OpenRouter, por lo que no puedo confirmar soporte de imagenes nativas."
279
- )
280
-
281
- model_metadata, verified = self._lookup_openrouter_model_metadata(company_short_name, model_id)
282
- if not verified:
283
- return None
284
- if not isinstance(model_metadata, dict):
285
- return (
286
- "Este modelo/provider no expone visión nativa por API verificable: "
287
- f"OpenRouter no publica metadata para el modelo '{model_id}', por lo que no puedo confirmar "
288
- "que acepte imagenes nativas."
289
- )
290
-
291
- architecture = model_metadata.get("architecture") or {}
292
- raw_input_modalities = architecture.get("input_modalities") or []
293
- input_modalities = [
294
- str(modality or "").strip().lower()
295
- for modality in raw_input_modalities
296
- if str(modality or "").strip()
297
- ]
298
- if "image" in input_modalities:
299
- return None
300
-
301
- published_model_id = str(model_metadata.get("id") or model_id).strip() or model_id
302
- published_modalities = ", ".join(input_modalities) if input_modalities else "(vacio)"
303
- return (
304
- "Este modelo/provider no expone visión nativa por API: "
305
- f"OpenRouter publica el modelo '{published_model_id}' con input_modalities={published_modalities}, "
306
- "sin 'image'. Para enviar imagenes nativas usa un modelo/provider que publique 'image' "
307
- "como modalidad de entrada."
308
- )
309
-
310
- def _lookup_openrouter_model_metadata(self, company_short_name: str, model: str) -> tuple[dict | None, bool]:
311
- provider_config = self.configuration_service.get_llm_provider_config(company_short_name, "openrouter") or {}
312
- base_url = str(provider_config.get("base_url") or "https://openrouter.ai/api/v1").strip()
313
- models_url = f"{base_url.rstrip('/')}/models"
314
- catalog = self._get_openrouter_models_catalog(models_url)
315
- if catalog is None:
316
- return None, False
317
-
318
- model_key = str(model or "").strip().lower()
319
- for item in catalog:
320
- if not isinstance(item, dict):
321
- continue
322
- candidates = {
323
- str(item.get("id") or "").strip().lower(),
324
- str(item.get("canonical_slug") or "").strip().lower(),
325
- }
326
- candidates.update(
327
- {
328
- candidate.split("/")[-1]
329
- for candidate in list(candidates)
330
- if candidate and "/" in candidate
331
- }
332
- )
333
- if model_key and model_key in candidates:
334
- return item, True
335
-
336
- return None, True
337
-
338
- def _get_openrouter_models_catalog(self, models_url: str) -> list[dict] | None:
339
- current_time = time.time()
340
- with self._openrouter_models_cache_lock:
341
- cached_entry = self._openrouter_models_cache.get(models_url)
342
- if cached_entry and (current_time - float(cached_entry.get("fetched_at") or 0)) < self.OPENROUTER_MODELS_CACHE_TTL_SECONDS:
343
- cached_data = cached_entry.get("data")
344
- if isinstance(cached_data, list):
345
- return cached_data
346
-
347
- try:
348
- response = requests.get(
349
- models_url,
350
- params={"output_modalities": "all"},
351
- timeout=self.OPENROUTER_MODELS_TIMEOUT_SECONDS,
352
- headers={"User-Agent": "IAToolkit AttachmentPolicy/1.0"},
353
- )
354
- response.raise_for_status()
355
- payload = response.json()
356
- catalog = payload.get("data") if isinstance(payload, dict) else None
357
- if not isinstance(catalog, list):
358
- logging.warning("OpenRouter models API returned an unexpected payload shape for '%s'.", models_url)
359
- return None
360
- except Exception as exc:
361
- logging.warning("Could not fetch OpenRouter model metadata from '%s': %s", models_url, exc)
362
- return None
363
-
364
- with self._openrouter_models_cache_lock:
365
- self._openrouter_models_cache[models_url] = {
366
- "fetched_at": current_time,
367
- "data": catalog,
368
- }
369
- return catalog
370
-
371
290
  def _normalize_file_meta(self, file_obj: dict) -> dict:
372
291
  if not isinstance(file_obj, dict):
373
292
  return {"name": "attachment", "payload": "", "mime_type": "application/octet-stream", "is_image": False}
@@ -1435,7 +1435,11 @@ class ConfigurationService:
1435
1435
  provider=normalized.get("provider"),
1436
1436
  model=model_id,
1437
1437
  )
1438
- capabilities = self.model_registry.get_capabilities(model_id, provider=provider)
1438
+ capabilities = self.model_registry.get_capabilities(
1439
+ model_id,
1440
+ provider=provider,
1441
+ capabilities=self.model_registry.catalog_capabilities(normalized),
1442
+ )
1439
1443
  descriptor = dict(normalized)
1440
1444
  descriptor["id"] = model_id
1441
1445
  descriptor["label"] = str(descriptor.get("label") or model_id).strip()
@@ -250,7 +250,8 @@ class SystemAgentRunner:
250
250
  ignored, ignored_platform)
251
251
 
252
252
  def supports_images(self, company_short_name: str, model: str | None) -> bool:
253
- """Whether the model's provider takes native images (llm_capabilities.yaml and the company's overrides)."""
253
+ """Whether the model takes native images: its provider's adapter sends them and,
254
+ when the model catalogue knows it, the model accepts them (BL-009, Fase F)."""
254
255
  if not model:
255
256
  return False
256
257
  try:
@@ -265,7 +266,7 @@ class SystemAgentRunner:
265
266
  if self._attachment_policy is None:
266
267
  self._attachment_policy = AttachmentPolicyService(self.configuration_service, Utility())
267
268
  try:
268
- capabilities = self._attachment_policy.get_effective_provider_capabilities(company_short_name, provider)
269
+ capabilities = self._attachment_policy.get_effective_capabilities(company_short_name, provider, model)
269
270
  except Exception as exc:
270
271
  logging.warning("Capabilities of provider '%s' could not be read: %s", provider, exc)
271
272
  return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 2.74.0
3
+ Version: 2.74.1
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
File without changes
File without changes
File without changes
File without changes