iatoolkit 2.3.2__tar.gz → 2.4.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.
Files changed (232) hide show
  1. {iatoolkit-2.3.2/src/iatoolkit.egg-info → iatoolkit-2.4.0}/PKG-INFO +1 -1
  2. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/__init__.py +1 -1
  3. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/config/llm_capabilities.yaml +18 -0
  4. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/config/system_prompts_pack.yaml +16 -2
  5. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +212 -27
  6. iatoolkit-2.4.0/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +62 -0
  7. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_proxy.py +51 -3
  8. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/locales/en.yaml +1 -0
  9. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/locales/es.yaml +1 -0
  10. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/company_context_service.py +24 -14
  11. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/configuration_service.py +51 -0
  12. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/context_builder_service.py +80 -20
  13. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/prompt_service.py +4 -0
  14. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/query_service.py +16 -2
  15. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/system_prompt_catalog.py +51 -1
  16. {iatoolkit-2.3.2 → iatoolkit-2.4.0/src/iatoolkit.egg-info}/PKG-INFO +1 -1
  17. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit.egg-info/SOURCES.txt +1 -0
  18. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/LICENSE +0 -0
  19. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/LICENSE_COMMUNITY.md +0 -0
  20. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/pyproject.toml +0 -0
  21. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/readme.md +0 -0
  22. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/requirements.txt +0 -0
  23. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/setup.cfg +0 -0
  24. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/base_company.py +0 -0
  25. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/cli_commands.py +0 -0
  26. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/__init__.py +0 -0
  27. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/exceptions.py +0 -0
  28. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/__init__.py +0 -0
  29. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
  30. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
  31. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
  32. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/memory_lint_trigger.py +0 -0
  33. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
  34. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
  35. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
  36. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/model_registry.py +0 -0
  37. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/routes.py +0 -0
  38. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/secret_resolver.py +0 -0
  39. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/session_manager.py +0 -0
  40. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/common/util.py +0 -0
  41. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/company_registry.py +0 -0
  42. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/config/__init__.py +0 -0
  43. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
  44. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/core.py +0 -0
  45. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/__init__.py +0 -0
  46. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
  47. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/call_service.py +0 -0
  48. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  49. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  50. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  51. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  52. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  53. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  54. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  55. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/google_auth_client.py +0 -0
  56. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
  57. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
  58. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/inference_handler.py +0 -0
  59. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
  60. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
  61. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
  62. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
  63. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
  64. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
  65. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/llm_response.py +0 -0
  66. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  67. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/__init__.py +0 -0
  68. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/api_key_repo.py +0 -0
  69. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/database_manager.py +0 -0
  70. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/document_repo.py +0 -0
  71. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
  72. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
  73. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  74. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/memory_repo.py +0 -0
  75. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/models.py +0 -0
  76. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
  77. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
  78. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
  79. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
  80. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
  81. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/__init__.py +0 -0
  82. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/api_key_service.py +0 -0
  83. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/attachment_policy_service.py +0 -0
  84. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/auth_service.py +0 -0
  85. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/benchmark_service.py +0 -0
  86. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/branding_service.py +0 -0
  87. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
  88. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/embedding_service.py +0 -0
  89. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/excel_service.py +0 -0
  90. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/file_processor_service.py +0 -0
  91. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/history_manager_service.py +0 -0
  92. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/http_tool_service.py +0 -0
  93. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/i18n_service.py +0 -0
  94. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/inference_service.py +0 -0
  95. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/jwt_service.py +0 -0
  96. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/knowledge_base_service.py +0 -0
  97. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/language_service.py +0 -0
  98. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/license_service.py +0 -0
  99. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/llm_client_service.py +0 -0
  100. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/mail_service.py +0 -0
  101. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/memory_compiler_service.py +0 -0
  102. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/memory_lint_service.py +0 -0
  103. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
  104. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/memory_service.py +0 -0
  105. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/memory_wiki_service.py +0 -0
  106. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
  107. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/noop_memory_lint_trigger.py +0 -0
  108. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/__init__.py +0 -0
  109. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/contracts.py +0 -0
  110. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
  111. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
  112. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
  113. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
  114. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
  115. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
  116. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
  117. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
  118. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/parsers/validator.py +0 -0
  119. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/pdf_service.py +0 -0
  120. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/profile_service.py +0 -0
  121. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/prompt_resource_service.py +0 -0
  122. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
  123. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/sql_dataset_service.py +0 -0
  124. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/sql_service.py +0 -0
  125. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/sql_source_service.py +0 -0
  126. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/storage_service.py +0 -0
  127. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/structured_output_service.py +0 -0
  128. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/system_tools.py +0 -0
  129. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/tool_service.py +0 -0
  130. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/user_feedback_service.py +0 -0
  131. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
  132. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/visual_kb_service.py +0 -0
  133. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/visual_tool_service.py +0 -0
  134. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/warmup_service.py +0 -0
  135. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/web_search/__init__.py +0 -0
  136. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
  137. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
  138. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
  139. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/services/web_search_service.py +0 -0
  140. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  141. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
  142. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
  143. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
  144. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  145. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_help_content.js +0 -0
  146. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_history_button.js +0 -0
  147. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
  148. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_main.js +0 -0
  149. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
  150. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
  151. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
  152. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
  153. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
  154. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
  155. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/styles/chat_modal.css +0 -0
  156. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/styles/chat_public.css +0 -0
  157. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/styles/documents.css +0 -0
  158. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/styles/landing_page.css +0 -0
  159. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
  160. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
  161. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/__init__.py +0 -0
  162. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/chat_state_rules.prompt +0 -0
  163. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/chat_user_profile.prompt +0 -0
  164. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/core_identity.prompt +0 -0
  165. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/email_output.prompt +0 -0
  166. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/file_download_output.prompt +0 -0
  167. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/format_styles.prompt +0 -0
  168. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/html_structures.prompt +0 -0
  169. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/links_documents.prompt +0 -0
  170. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/memory_usage.prompt +0 -0
  171. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/multimodal_basics.prompt +0 -0
  172. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/output_basics.prompt +0 -0
  173. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/presentation_formatting.prompt +0 -0
  174. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/query_main.prompt +0 -0
  175. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/sql_aggregation_scope.prompt +0 -0
  176. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/sql_casting.prompt +0 -0
  177. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/sql_core.prompt +0 -0
  178. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/sql_jsonb.prompt +0 -0
  179. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/sql_rules.prompt +0 -0
  180. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/system_prompts/tool_html_passthrough.prompt +0 -0
  181. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/_company_header.html +0 -0
  182. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/_login_widget.html +0 -0
  183. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/base.html +0 -0
  184. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/change_password.html +0 -0
  185. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/chat.html +0 -0
  186. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
  187. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/chat_modals.html +0 -0
  188. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/error.html +0 -0
  189. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/forgot_password.html +0 -0
  190. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/home_hosted_default.html +0 -0
  191. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
  192. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/onboarding_shell.html +0 -0
  193. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/pdf/base.html +0 -0
  194. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/pdf/letter.html +0 -0
  195. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/pdf/report.html +0 -0
  196. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/pdf/simple.html +0 -0
  197. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/templates/signup.html +0 -0
  198. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/__init__.py +0 -0
  199. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/api_key_api_view.py +0 -0
  200. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/base_login_view.py +0 -0
  201. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/categories_api_view.py +0 -0
  202. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/change_password_view.py +0 -0
  203. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
  204. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/chat_view.py +0 -0
  205. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/configuration_api_view.py +0 -0
  206. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/connectors_api_view.py +0 -0
  207. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/embedding_api_view.py +0 -0
  208. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/forgot_password_view.py +0 -0
  209. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/help_content_api_view.py +0 -0
  210. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/history_api_view.py +0 -0
  211. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/home_view.py +0 -0
  212. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/init_context_api_view.py +0 -0
  213. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/llmquery_api_view.py +0 -0
  214. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/load_document_api_view.py +0 -0
  215. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/login_view.py +0 -0
  216. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/logout_api_view.py +0 -0
  217. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/memory_api_view.py +0 -0
  218. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/profile_api_view.py +0 -0
  219. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/prompt_api_view.py +0 -0
  220. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
  221. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
  222. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/rag_api_view.py +0 -0
  223. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/root_redirect_view.py +0 -0
  224. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/signup_view.py +0 -0
  225. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/static_page_view.py +0 -0
  226. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/tool_api_view.py +0 -0
  227. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
  228. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/users_api_view.py +0 -0
  229. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit/views/verify_user_view.py +0 -0
  230. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  231. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/src/iatoolkit.egg-info/requires.txt +0 -0
  232. {iatoolkit-2.3.2 → iatoolkit-2.4.0}/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.3.2
3
+ Version: 2.4.0
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.3.2"
6
+ __version__ = "2.4.0"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -58,6 +58,24 @@ openai_compatible:
58
58
  max_file_size_mb: 0
59
59
  max_files_per_request: 0
60
60
 
61
+ openrouter:
62
+ supports_native_files: true
63
+ supports_native_images: true
64
+ supported_mime_types:
65
+ - application/pdf
66
+ - text/plain
67
+ - text/csv
68
+ - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
69
+ - application/vnd.openxmlformats-officedocument.wordprocessingml.document
70
+ - application/vnd.openxmlformats-officedocument.presentationml.presentation
71
+ - application/json
72
+ - application/xml
73
+ - text/xml
74
+ preferred_native_mime_types:
75
+ - application/pdf
76
+ max_file_size_mb: 20
77
+ max_files_per_request: 10
78
+
61
79
  unknown:
62
80
  supports_native_files: false
63
81
  supports_native_images: false
@@ -2,42 +2,47 @@ version: 2
2
2
  prompts:
3
3
  - key: core_identity
4
4
  filename: core_identity.prompt
5
+ section: identity
5
6
  include:
6
7
  execution_modes:
7
8
  - chat
8
9
  - agent
9
10
  - key: chat_user_profile
10
11
  filename: chat_user_profile.prompt
12
+ section: identity
11
13
  include:
12
14
  execution_modes:
13
15
  - chat
14
16
  - key: chat_state_rules
15
17
  filename: chat_state_rules.prompt
18
+ section: conversation_rules
16
19
  include:
17
20
  execution_modes:
18
21
  - chat
19
22
  - key: links_documents
20
23
  filename: links_documents.prompt
24
+ section: conversation_rules
21
25
  include:
22
26
  execution_modes:
23
27
  - chat
24
28
  - agent
25
29
  - key: memory_usage
26
30
  filename: memory_usage.prompt
31
+ section: conversation_rules
27
32
  include:
28
33
  execution_modes:
29
34
  - chat
30
- - agent
31
35
  all_capabilities:
32
36
  - can_use_memory
33
37
  - key: multimodal_basics
34
38
  filename: multimodal_basics.prompt
39
+ section: conversation_rules
35
40
  include:
36
41
  execution_modes:
37
42
  - chat
38
- - agent
39
43
  - key: output_basics
40
44
  filename: output_basics.prompt
45
+ section: output_contract
41
46
  include:
42
47
  execution_modes:
43
48
  - chat
@@ -46,6 +51,7 @@ prompts:
46
51
  - chat_compatible
47
52
  - key: presentation_formatting
48
53
  filename: presentation_formatting.prompt
54
+ section: output_contract
49
55
  include:
50
56
  execution_modes:
51
57
  - chat
@@ -53,6 +59,7 @@ prompts:
53
59
  - chat_compatible
54
60
  - key: html_structures
55
61
  filename: html_structures.prompt
62
+ section: output_contract
56
63
  include:
57
64
  execution_modes:
58
65
  - chat
@@ -60,12 +67,14 @@ prompts:
60
67
  - chat_compatible
61
68
  - key: tool_html_passthrough
62
69
  filename: tool_html_passthrough.prompt
70
+ section: output_contract
63
71
  include:
64
72
  execution_modes:
65
73
  - chat
66
74
  - agent
67
75
  - key: file_download_output
68
76
  filename: file_download_output.prompt
77
+ section: output_contract
69
78
  include:
70
79
  execution_modes:
71
80
  - chat
@@ -74,6 +83,7 @@ prompts:
74
83
  - can_generate_files
75
84
  - key: email_output
76
85
  filename: email_output.prompt
86
+ section: output_contract
77
87
  include:
78
88
  execution_modes:
79
89
  - chat
@@ -82,6 +92,7 @@ prompts:
82
92
  - can_send_email
83
93
  - key: sql_core
84
94
  filename: sql_core.prompt
95
+ section: data_access_rules
85
96
  include:
86
97
  execution_modes:
87
98
  - chat
@@ -90,6 +101,7 @@ prompts:
90
101
  - can_query_sql
91
102
  - key: sql_jsonb
92
103
  filename: sql_jsonb.prompt
104
+ section: data_access_rules
93
105
  include:
94
106
  execution_modes:
95
107
  - chat
@@ -98,6 +110,7 @@ prompts:
98
110
  - can_query_sql
99
111
  - key: sql_casting
100
112
  filename: sql_casting.prompt
113
+ section: data_access_rules
101
114
  include:
102
115
  execution_modes:
103
116
  - chat
@@ -106,6 +119,7 @@ prompts:
106
119
  - can_query_sql
107
120
  - key: sql_aggregation_scope
108
121
  filename: sql_aggregation_scope.prompt
122
+ section: data_access_rules
109
123
  include:
110
124
  execution_modes:
111
125
  - chat
@@ -3,7 +3,9 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
+ import base64
6
7
  import logging
8
+ import mimetypes
7
9
  from typing import Any, Dict, List, Optional
8
10
 
9
11
  from iatoolkit.common.exceptions import IAToolkitException
@@ -12,12 +14,17 @@ from iatoolkit.infra.llm_response import LLMResponse, ToolCall, Usage
12
14
 
13
15
  class OpenAICompatibleChatAdapter:
14
16
  """
15
- Adapter for OpenAI-compatible Chat Completions APIs.
17
+ Adapter for Chat Completions-style providers.
16
18
 
17
- This adapter is used for providers that expose a `chat.completions` style
18
- interface with `messages`, `tools`, and `tool_calls`.
19
+ This adapter targets providers that expose a `chat.completions` compatible
20
+ endpoint with `messages`, `tools`, `tool_calls`, and `response_format`.
19
21
  """
20
22
 
23
+ supports_multimodal = False
24
+ supports_reasoning = False
25
+ supports_metadata = False
26
+ supports_parallel_tool_calls = False
27
+
21
28
  def __init__(self, openai_compatible_client, provider_label: str = "OpenAI-compatible"):
22
29
  self.client = openai_compatible_client
23
30
  self.provider_label = provider_label
@@ -37,14 +44,10 @@ class OpenAICompatibleChatAdapter:
37
44
  tool_choice = kwargs.get("tool_choice", "auto")
38
45
  context_history = kwargs.get("context_history") or []
39
46
  images = kwargs.get("images") or []
47
+ attachments = kwargs.get("attachments") or []
40
48
  text = kwargs.get("text") or {}
41
-
42
- if images:
43
- logging.warning(
44
- "[%sAdapter] Images provided but these models are not multimodal. Ignoring %s images.",
45
- self.provider_label,
46
- len(images),
47
- )
49
+ reasoning = kwargs.get("reasoning")
50
+ metadata = kwargs.get("metadata")
48
51
 
49
52
  try:
50
53
  messages: List[Dict[str, Any]] = []
@@ -55,6 +58,18 @@ class OpenAICompatibleChatAdapter:
55
58
  current_messages = self._build_messages_from_input(input)
56
59
  messages.extend(current_messages)
57
60
 
61
+ if images or attachments:
62
+ if self.supports_multimodal:
63
+ messages = self._prepare_multimodal_messages(messages, images, attachments)
64
+ else:
65
+ logging.warning(
66
+ "[%sAdapter] Multimodal content provided but this provider is configured as text-only. "
67
+ "Ignoring %s images and %s attachments.",
68
+ self.provider_label,
69
+ len(images),
70
+ len(attachments),
71
+ )
72
+
58
73
  has_function_outputs = any(
59
74
  item.get("type") == "function_call_output" for item in input
60
75
  )
@@ -77,10 +92,25 @@ class OpenAICompatibleChatAdapter:
77
92
  }
78
93
  if tools_payload:
79
94
  call_kwargs["tools"] = tools_payload
80
- if tool_choice:
81
- call_kwargs["tool_choice"] = tool_choice
82
- if isinstance(text, dict) and isinstance(text.get("response_format"), dict):
83
- call_kwargs["response_format"] = text["response_format"]
95
+
96
+ tool_choice_payload = self._map_tool_choice(tool_choice, tools_payload or [])
97
+ if tool_choice_payload is not None:
98
+ call_kwargs["tool_choice"] = tool_choice_payload
99
+
100
+ response_format = self._extract_response_format(text)
101
+ if response_format:
102
+ call_kwargs["response_format"] = response_format
103
+
104
+ if self.supports_reasoning and reasoning:
105
+ call_kwargs["reasoning"] = reasoning
106
+
107
+ if self.supports_metadata and metadata:
108
+ call_kwargs["metadata"] = metadata
109
+
110
+ if self.supports_parallel_tool_calls and kwargs.get("parallel_tool_calls") is not None:
111
+ call_kwargs["parallel_tool_calls"] = bool(kwargs.get("parallel_tool_calls"))
112
+
113
+ self._extend_call_kwargs(call_kwargs, kwargs)
84
114
 
85
115
  logging.debug(
86
116
  "[%sAdapter] Calling chat.completions API with %s messages.",
@@ -100,6 +130,10 @@ class OpenAICompatibleChatAdapter:
100
130
  f"{self.provider_label} error: {ex}"
101
131
  ) from ex
102
132
 
133
+ def _extend_call_kwargs(self, call_kwargs: Dict[str, Any], kwargs: Dict[str, Any]) -> None:
134
+ _ = call_kwargs
135
+ _ = kwargs
136
+
103
137
  def _build_messages_from_input(self, input_items: List[Dict]) -> List[Dict]:
104
138
  messages: List[Dict[str, Any]] = []
105
139
 
@@ -114,29 +148,145 @@ class OpenAICompatibleChatAdapter:
114
148
  )
115
149
  continue
116
150
 
117
- messages.append(
118
- {
119
- "role": "user",
120
- "content": f"Tool result:\n{output}",
121
- }
122
- )
151
+ tool_message: Dict[str, Any] = {
152
+ "role": "tool",
153
+ "content": output,
154
+ }
155
+ call_id = str(item.get("call_id") or "").strip()
156
+ if call_id:
157
+ tool_message["tool_call_id"] = call_id
158
+ messages.append(tool_message)
123
159
  continue
124
160
 
125
- role = item.get("role")
161
+ role = str(item.get("role") or "").strip().lower()
126
162
  content = item.get("content")
127
163
 
128
- if role == "tool":
129
- logging.warning("[%sAdapter] Skipping tool-role message: %s", self.provider_label, item)
130
- continue
131
-
132
164
  if not role:
133
165
  logging.warning("[%sAdapter] Skipping message without role: %s", self.provider_label, item)
134
166
  continue
135
167
 
136
- messages.append({"role": role, "content": content})
168
+ if role == "model":
169
+ role = "assistant"
170
+
171
+ message: Dict[str, Any] = {"role": role, "content": content}
172
+ tool_call_id = str(item.get("tool_call_id") or "").strip()
173
+ if role == "tool" and tool_call_id:
174
+ message["tool_call_id"] = tool_call_id
175
+
176
+ annotations = item.get("annotations")
177
+ if annotations is not None:
178
+ message["annotations"] = annotations
179
+
180
+ messages.append(message)
137
181
 
138
182
  return messages
139
183
 
184
+ def _prepare_multimodal_messages(
185
+ self,
186
+ messages: List[Dict[str, Any]],
187
+ images: List[Dict],
188
+ attachments: List[Dict],
189
+ ) -> List[Dict[str, Any]]:
190
+ target_index = None
191
+ for index in range(len(messages) - 1, -1, -1):
192
+ if messages[index].get("role") == "user":
193
+ target_index = index
194
+ break
195
+
196
+ if target_index is None:
197
+ return messages
198
+
199
+ target_message = dict(messages[target_index])
200
+ content_parts = self._coerce_content_to_parts(target_message.get("content"))
201
+
202
+ for img in images:
203
+ image_part = self._build_image_part(img)
204
+ if image_part is not None:
205
+ content_parts.append(image_part)
206
+
207
+ for attachment in attachments:
208
+ file_part = self._build_file_part(attachment)
209
+ if file_part is not None:
210
+ content_parts.append(file_part)
211
+
212
+ target_message["content"] = content_parts
213
+ updated_messages = list(messages)
214
+ updated_messages[target_index] = target_message
215
+ return updated_messages
216
+
217
+ @staticmethod
218
+ def _coerce_content_to_parts(content: Any) -> List[Dict[str, Any]]:
219
+ if isinstance(content, list):
220
+ return list(content)
221
+ if content in (None, ""):
222
+ return []
223
+ return [{"type": "text", "text": str(content)}]
224
+
225
+ def _build_image_part(self, image: Dict[str, Any]) -> Optional[Dict[str, Any]]:
226
+ if not isinstance(image, dict):
227
+ return None
228
+
229
+ filename = str(image.get("name") or image.get("filename") or "").strip()
230
+ mime_type = str(image.get("mime_type") or image.get("type") or "").strip().lower()
231
+ if not mime_type:
232
+ mime_type = mimetypes.guess_type(filename)[0] or "image/jpeg"
233
+
234
+ raw_url = str(image.get("url") or image.get("image_url") or "").strip()
235
+ if raw_url:
236
+ data_url = raw_url
237
+ else:
238
+ base64_data = str(image.get("base64") or image.get("content") or "").strip()
239
+ if not base64_data:
240
+ return None
241
+ data_url = self._to_data_url(base64_data, mime_type)
242
+
243
+ return {
244
+ "type": "image_url",
245
+ "image_url": {
246
+ "url": data_url,
247
+ },
248
+ }
249
+
250
+ def _build_file_part(self, attachment: Dict[str, Any]) -> Optional[Dict[str, Any]]:
251
+ if not isinstance(attachment, dict):
252
+ return None
253
+
254
+ filename = str(attachment.get("name") or attachment.get("filename") or "attachment").strip()
255
+ mime_type = str(
256
+ attachment.get("mime_type")
257
+ or attachment.get("type")
258
+ or mimetypes.guess_type(filename)[0]
259
+ or "application/octet-stream"
260
+ ).strip().lower()
261
+
262
+ raw_file_data = str(attachment.get("file_data") or attachment.get("url") or "").strip()
263
+ if raw_file_data:
264
+ file_data = raw_file_data
265
+ else:
266
+ base64_data = str(attachment.get("base64") or attachment.get("content") or "").strip()
267
+ if not base64_data:
268
+ return None
269
+ file_data = self._to_data_url(base64_data, mime_type)
270
+
271
+ return {
272
+ "type": "file",
273
+ "file": {
274
+ "filename": filename,
275
+ "file_data": file_data,
276
+ },
277
+ }
278
+
279
+ @staticmethod
280
+ def _to_data_url(base64_data: str, mime_type: str) -> str:
281
+ payload = str(base64_data or "").strip()
282
+ if payload.lower().startswith("data:") and "," in payload:
283
+ return payload
284
+ try:
285
+ base64.b64decode(payload, validate=True)
286
+ return f"data:{mime_type};base64,{payload}"
287
+ except Exception:
288
+ return payload
289
+
140
290
  def _build_tools_payload(self, tools: List[Dict]) -> Optional[List[Dict]]:
141
291
  if not tools:
142
292
  return None
@@ -145,7 +295,7 @@ class OpenAICompatibleChatAdapter:
145
295
 
146
296
  for tool in tools:
147
297
  if "function" in tool:
148
- func_def = tool["function"]
298
+ func_def = dict(tool["function"] or {})
149
299
  else:
150
300
  func_def = {
151
301
  "name": tool.get("name"),
@@ -172,6 +322,41 @@ class OpenAICompatibleChatAdapter:
172
322
 
173
323
  return tools_payload or None
174
324
 
325
+ @staticmethod
326
+ def _map_tool_choice(
327
+ tool_choice: Any,
328
+ tools_payload: List[Dict[str, Any]],
329
+ ) -> Optional[Dict[str, Any] | str]:
330
+ if tool_choice in ("", None, "auto"):
331
+ return None
332
+
333
+ if isinstance(tool_choice, dict):
334
+ return tool_choice
335
+
336
+ if tool_choice in {"none", "required"}:
337
+ return tool_choice
338
+
339
+ tool_names = {
340
+ str((tool.get("function") or {}).get("name") or "").strip()
341
+ for tool in (tools_payload or [])
342
+ if isinstance(tool, dict)
343
+ }
344
+ if str(tool_choice).strip() in tool_names:
345
+ return {
346
+ "type": "function",
347
+ "function": {
348
+ "name": str(tool_choice).strip(),
349
+ },
350
+ }
351
+
352
+ return str(tool_choice)
353
+
354
+ @staticmethod
355
+ def _extract_response_format(text: Dict[str, Any]) -> Optional[Dict[str, Any]]:
356
+ if isinstance(text, dict) and isinstance(text.get("response_format"), dict):
357
+ return dict(text["response_format"])
358
+ return None
359
+
175
360
  def _map_chat_completion_response(self, response: Any) -> LLMResponse:
176
361
  if not response.choices:
177
362
  raise IAToolkitException(
@@ -0,0 +1,62 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ from typing import Any, Dict
7
+
8
+ from iatoolkit.infra.llm_providers.openai_compatible_chat_adapter import OpenAICompatibleChatAdapter
9
+
10
+
11
+ class OpenRouterAdapter(OpenAICompatibleChatAdapter):
12
+ """OpenRouter-specific adapter built on top of the shared chat.completions core."""
13
+
14
+ supports_multimodal = True
15
+ supports_reasoning = False
16
+ supports_metadata = True
17
+ supports_parallel_tool_calls = True
18
+
19
+ def __init__(self, openrouter_client):
20
+ super().__init__(openai_compatible_client=openrouter_client, provider_label="OpenRouter")
21
+
22
+ def _extend_call_kwargs(self, call_kwargs: Dict[str, Any], kwargs: Dict[str, Any]) -> None:
23
+ text = kwargs.get("text") or {}
24
+ verbosity = text.get("verbosity") if isinstance(text, dict) else None
25
+ if verbosity:
26
+ call_kwargs["verbosity"] = verbosity
27
+
28
+ passthrough_keys = (
29
+ "service_tier",
30
+ "temperature",
31
+ "top_p",
32
+ "max_tokens",
33
+ "max_completion_tokens",
34
+ "seed",
35
+ "stop",
36
+ "stream",
37
+ "stream_options",
38
+ "modalities",
39
+ "user",
40
+ )
41
+ for key in passthrough_keys:
42
+ if kwargs.get(key) is not None:
43
+ call_kwargs[key] = kwargs.get(key)
44
+
45
+ extra_body = dict(call_kwargs.get("extra_body") or {})
46
+
47
+ reasoning = kwargs.get("reasoning")
48
+ if isinstance(reasoning, dict) and reasoning:
49
+ extra_body["reasoning"] = dict(reasoning)
50
+
51
+ vendor_specific_keys = (
52
+ "models",
53
+ "provider",
54
+ "plugins",
55
+ "session_id",
56
+ )
57
+ for key in vendor_specific_keys:
58
+ if kwargs.get(key) is not None:
59
+ extra_body[key] = kwargs.get(key)
60
+
61
+ if extra_body:
62
+ call_kwargs["extra_body"] = extra_body
@@ -7,7 +7,9 @@
7
7
  from iatoolkit.services.configuration_service import ConfigurationService
8
8
  from iatoolkit.infra.llm_providers.openai_adapter import OpenAIAdapter
9
9
  from iatoolkit.infra.llm_providers.gemini_adapter import GeminiAdapter
10
+ from iatoolkit.infra.llm_providers.deepseek_adapter import DeepseekAdapter
10
11
  from iatoolkit.infra.llm_providers.openai_compatible_chat_adapter import OpenAICompatibleChatAdapter
12
+ from iatoolkit.infra.llm_providers.openrouter_adapter import OpenRouterAdapter
11
13
  from iatoolkit.infra.llm_providers.anthropic_adapter import AnthropicAdapter
12
14
  from iatoolkit.common.exceptions import IAToolkitException
13
15
  from iatoolkit.common.util import Utility
@@ -39,6 +41,7 @@ class LLMProxy:
39
41
  PROVIDER_XAI = "xai"
40
42
  PROVIDER_ANTHROPIC = "anthropic"
41
43
  PROVIDER_OPENAI_COMPATIBLE = "openai_compatible"
44
+ PROVIDER_OPENROUTER = "openrouter"
42
45
  DEFAULT_CONNECT_TIMEOUT_SECONDS = 10.0
43
46
  DEFAULT_READ_TIMEOUT_SECONDS = 300.0
44
47
  DEFAULT_MAX_RETRIES = 0
@@ -145,6 +148,7 @@ class LLMProxy:
145
148
  client_config = self._get_client_config(company_short_name, provider)
146
149
  api_key = client_config["api_key"]
147
150
  base_url = client_config.get("base_url") or ""
151
+ default_headers = client_config.get("default_headers") or {}
148
152
  connect_timeout_seconds = client_config["connect_timeout_seconds"]
149
153
  read_timeout_seconds = client_config["read_timeout_seconds"]
150
154
  max_retries = client_config["max_retries"]
@@ -152,6 +156,7 @@ class LLMProxy:
152
156
  provider,
153
157
  api_key or "",
154
158
  base_url,
159
+ tuple(sorted(default_headers.items())),
155
160
  connect_timeout_seconds,
156
161
  read_timeout_seconds,
157
162
  max_retries,
@@ -166,6 +171,7 @@ class LLMProxy:
166
171
  provider,
167
172
  api_key,
168
173
  base_url=base_url,
174
+ default_headers=default_headers,
169
175
  connect_timeout_seconds=connect_timeout_seconds,
170
176
  read_timeout_seconds=read_timeout_seconds,
171
177
  max_retries=max_retries,
@@ -177,9 +183,11 @@ class LLMProxy:
177
183
  elif provider == self.PROVIDER_GEMINI:
178
184
  adapter = GeminiAdapter(client)
179
185
  elif provider == self.PROVIDER_DEEPSEEK:
180
- adapter = OpenAICompatibleChatAdapter(client, provider_label="DeepSeek")
186
+ adapter = DeepseekAdapter(client)
181
187
  elif provider == self.PROVIDER_OPENAI_COMPATIBLE:
182
188
  adapter = OpenAICompatibleChatAdapter(client, provider_label="OpenAI-compatible")
189
+ elif provider == self.PROVIDER_OPENROUTER:
190
+ adapter = OpenRouterAdapter(client)
183
191
  elif provider == self.PROVIDER_ANTHROPIC:
184
192
  adapter = AnthropicAdapter(client)
185
193
  else:
@@ -199,7 +207,7 @@ class LLMProxy:
199
207
  ) -> Dict[str, Any]:
200
208
  effective_kwargs = dict(request_kwargs or {})
201
209
 
202
- if provider != self.PROVIDER_OPENAI_COMPATIBLE:
210
+ if provider not in {self.PROVIDER_OPENAI_COMPATIBLE, self.PROVIDER_OPENROUTER}:
203
211
  return effective_kwargs
204
212
 
205
213
  if provider_config.get("disable_tools") is True:
@@ -219,6 +227,7 @@ class LLMProxy:
219
227
  provider: str,
220
228
  api_key: str,
221
229
  base_url: str = "",
230
+ default_headers: Dict[str, str] | None = None,
222
231
  *,
223
232
  connect_timeout_seconds: float | None = None,
224
233
  read_timeout_seconds: float | None = None,
@@ -244,6 +253,7 @@ class LLMProxy:
244
253
  provider,
245
254
  api_key or "",
246
255
  base_url or "",
256
+ tuple(sorted((default_headers or {}).items())),
247
257
  connect_timeout_seconds,
248
258
  read_timeout_seconds,
249
259
  max_retries,
@@ -257,6 +267,7 @@ class LLMProxy:
257
267
  provider,
258
268
  api_key,
259
269
  base_url=base_url,
270
+ default_headers=default_headers,
260
271
  connect_timeout_seconds=connect_timeout_seconds,
261
272
  read_timeout_seconds=read_timeout_seconds,
262
273
  max_retries=max_retries,
@@ -269,6 +280,7 @@ class LLMProxy:
269
280
  provider: str,
270
281
  api_key: str,
271
282
  base_url: str = "",
283
+ default_headers: Dict[str, str] | None = None,
272
284
  *,
273
285
  connect_timeout_seconds: float | None = None,
274
286
  read_timeout_seconds: float | None = None,
@@ -325,6 +337,20 @@ class LLMProxy:
325
337
  max_retries=max_retries,
326
338
  )
327
339
 
340
+ if provider == self.PROVIDER_OPENROUTER:
341
+ if not base_url:
342
+ raise IAToolkitException(
343
+ IAToolkitException.ErrorType.CONFIG_ERROR,
344
+ "Provider 'openrouter' requires a configured base_url."
345
+ )
346
+ return OpenAI(
347
+ api_key=api_key,
348
+ base_url=base_url,
349
+ timeout=timeout,
350
+ max_retries=max_retries,
351
+ default_headers=default_headers or None,
352
+ )
353
+
328
354
  if provider == self.PROVIDER_GEMINI:
329
355
  # Example placeholder: you may already have a Gemini client factory elsewhere.
330
356
  # Here you could create and configure the Gemini client (e.g. google.generativeai).
@@ -353,6 +379,7 @@ class LLMProxy:
353
379
  return {
354
380
  "api_key": self._get_api_key_from_config(company_short_name, provider),
355
381
  "base_url": self._get_base_url_from_config(company_short_name, provider),
382
+ "default_headers": self._get_default_headers_from_config(company_short_name, provider),
356
383
  "connect_timeout_seconds": self._resolve_provider_float(
357
384
  provider_config,
358
385
  ("connect_timeout_seconds",),
@@ -499,7 +526,7 @@ class LLMProxy:
499
526
  return api_key_value
500
527
 
501
528
  def _get_base_url_from_config(self, company_short_name: str, provider: str) -> str:
502
- if provider != self.PROVIDER_OPENAI_COMPATIBLE:
529
+ if provider not in {self.PROVIDER_OPENAI_COMPATIBLE, self.PROVIDER_OPENROUTER}:
503
530
  return ""
504
531
 
505
532
  provider_config = self.configuration_service.get_llm_provider_config(company_short_name, provider) or {}
@@ -528,6 +555,27 @@ class LLMProxy:
528
555
 
529
556
  return base_url
530
557
 
558
+ def _get_default_headers_from_config(self, company_short_name: str, provider: str) -> dict:
559
+ if provider != self.PROVIDER_OPENROUTER:
560
+ return {}
561
+
562
+ provider_config = self.configuration_service.get_llm_provider_config(company_short_name, provider) or {}
563
+ if not isinstance(provider_config, dict):
564
+ provider_config = {}
565
+
566
+ headers: dict[str, str] = {}
567
+
568
+ http_referer = str(provider_config.get("http_referer") or "").strip()
569
+ if http_referer:
570
+ headers["HTTP-Referer"] = http_referer
571
+
572
+ x_title = str(provider_config.get("x_title") or "").strip()
573
+ if x_title:
574
+ headers["X-Title"] = x_title
575
+ headers["X-OpenRouter-Title"] = x_title
576
+
577
+ return headers
578
+
531
579
  @classmethod
532
580
  def clear_low_level_clients_cache(cls):
533
581
  with cls._clients_cache_lock: