iatoolkit 0.95.4__tar.gz → 0.108.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.
- {iatoolkit-0.95.4/src/iatoolkit.egg-info → iatoolkit-0.108.1}/PKG-INFO +1 -2
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/requirements.txt +0 -1
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/__init__.py +4 -2
- iatoolkit-0.108.1/src/iatoolkit/base_company.py +21 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/cli_commands.py +3 -2
- iatoolkit-0.108.1/src/iatoolkit/common/interfaces/asset_storage.py +34 -0
- iatoolkit-0.108.1/src/iatoolkit/common/interfaces/database_provider.py +38 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/common/model_registry.py +52 -1
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/common/routes.py +15 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/common/util.py +11 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/company_registry.py +5 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/core.py +43 -13
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +14 -15
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/llm_providers/openai_adapter.py +41 -3
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/llm_response.py +5 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/locales/en.yaml +52 -2
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/locales/es.yaml +55 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/repositories/database_manager.py +40 -18
- iatoolkit-0.108.1/src/iatoolkit/repositories/filesystem_asset_repository.py +36 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/repositories/llm_query_repo.py +2 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/repositories/models.py +2 -3
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/repositories/profile_repo.py +60 -3
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/company_context_service.py +57 -34
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/configuration_service.py +122 -69
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/dispatcher_service.py +15 -3
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/history_manager_service.py +5 -7
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/llm_client_service.py +14 -10
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/profile_service.py +32 -4
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/prompt_service.py +30 -28
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/query_service.py +6 -6
- iatoolkit-0.108.1/src/iatoolkit/services/sql_service.py +174 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/tool_service.py +15 -4
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/user_session_context_service.py +1 -1
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_main.js +41 -3
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/styles/chat_iatoolkit.css +38 -34
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/styles/llm_output.css +34 -1
- iatoolkit-0.108.1/src/iatoolkit/system_prompts/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/base.html +13 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/chat.html +10 -7
- iatoolkit-0.108.1/src/iatoolkit/views/chat_view.py +76 -0
- iatoolkit-0.108.1/src/iatoolkit/views/load_company_configuration_api_view.py +49 -0
- iatoolkit-0.108.1/src/iatoolkit/views/users_api_view.py +33 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1/src/iatoolkit.egg-info}/PKG-INFO +1 -2
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit.egg-info/SOURCES.txt +7 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit.egg-info/requires.txt +0 -1
- iatoolkit-0.95.4/src/iatoolkit/base_company.py +0 -37
- iatoolkit-0.95.4/src/iatoolkit/services/sql_service.py +0 -159
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/LICENSE +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/LICENSE_COMMUNITY.md +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/pyproject.toml +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/readme.md +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/setup.cfg +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/common/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/common/exceptions.py +0 -0
- {iatoolkit-0.95.4/src/iatoolkit/infra/llm_providers → iatoolkit-0.108.1/src/iatoolkit/common/interfaces}/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/common/session_manager.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/call_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/connectors/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/google_chat_app.py +0 -0
- {iatoolkit-0.95.4/src/iatoolkit/system_prompts → iatoolkit-0.108.1/src/iatoolkit/infra/llm_providers}/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/llm_proxy.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/redis_session_manager.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/repositories/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/repositories/document_repo.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/repositories/vs_repo.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/auth_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/benchmark_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/branding_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/document_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/embedding_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/excel_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/file_processor_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/i18n_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/jwt_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/language_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/license_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/load_documents_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/mail_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/search_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/services/user_feedback_service.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/images/fernando.jpeg +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_filepond.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_help_content.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_history_button.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/styles/chat_modal.css +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/styles/chat_public.css +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/styles/documents.css +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/styles/landing_page.css +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/static/styles/onboarding.css +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/system_prompts/format_styles.prompt +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/system_prompts/query_main.prompt +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/system_prompts/sql_rules.prompt +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/_company_header.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/_login_widget.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/change_password.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/chat_modals.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/error.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/forgot_password.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/onboarding_shell.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/templates/signup.html +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/__init__.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/base_login_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/change_password_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/embedding_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/forgot_password_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/help_content_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/history_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/home_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/init_context_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/llmquery_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/load_document_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/login_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/logout_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/profile_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/prompt_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/root_redirect_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/signup_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/static_page_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/views/verify_user_view.py +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
- {iatoolkit-0.95.4 → iatoolkit-0.108.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: 0.
|
|
3
|
+
Version: 0.108.1
|
|
4
4
|
Summary: IAToolkit
|
|
5
5
|
Author: Fernando Libedinsky
|
|
6
6
|
License-Expression: MIT
|
|
@@ -14,7 +14,6 @@ Requires-Dist: botocore==1.36.22
|
|
|
14
14
|
Requires-Dist: build==1.2.2.post1
|
|
15
15
|
Requires-Dist: click==8.1.8
|
|
16
16
|
Requires-Dist: cryptography==44.0.3
|
|
17
|
-
Requires-Dist: deepseek==1.0.0
|
|
18
17
|
Requires-Dist: Flask==3.1.0
|
|
19
18
|
Requires-Dist: Flask-Bcrypt==1.0.1
|
|
20
19
|
Requires-Dist: flask-cors==6.0.0
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# IAToolkit is open source software.
|
|
5
5
|
|
|
6
|
-
__version__ = "0.
|
|
6
|
+
__version__ = "0.108.1"
|
|
7
7
|
|
|
8
8
|
# Expose main classes and functions at the top level of the package
|
|
9
9
|
|
|
@@ -24,6 +24,7 @@ from iatoolkit.infra.call_service import CallServiceClient
|
|
|
24
24
|
from iatoolkit.services.profile_service import ProfileService
|
|
25
25
|
from iatoolkit.services.mail_service import MailService
|
|
26
26
|
from iatoolkit.repositories.models import Base as OrmModel
|
|
27
|
+
from iatoolkit.base_company import BaseCompany
|
|
27
28
|
|
|
28
29
|
__all__ = [
|
|
29
30
|
'IAToolkit',
|
|
@@ -40,5 +41,6 @@ __all__ = [
|
|
|
40
41
|
'CallServiceClient',
|
|
41
42
|
'ProfileService',
|
|
42
43
|
'MailService',
|
|
43
|
-
'OrmModel'
|
|
44
|
+
'OrmModel',
|
|
45
|
+
'BaseCompany',
|
|
44
46
|
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
# companies/base_company.py
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
|
|
9
|
+
class BaseCompany(ABC):
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
# execute the specific action configured in the intent table
|
|
13
|
+
def handle_request(self, tag: str, params: dict) -> dict:
|
|
14
|
+
raise NotImplementedError("La subclase debe implementar el método handle_request()")
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def register_cli_commands(self, app):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
def unsupported_operation(self, tag):
|
|
21
|
+
raise NotImplementedError(f"La operación '{tag}' no está soportada por esta empresa.")
|
|
@@ -14,12 +14,13 @@ def register_core_commands(app):
|
|
|
14
14
|
|
|
15
15
|
@app.cli.command("api-key")
|
|
16
16
|
@click.argument("company_short_name")
|
|
17
|
-
|
|
17
|
+
@click.argument("key_name")
|
|
18
|
+
def api_key(company_short_name: str, key_name: str):
|
|
18
19
|
"""⚙️ Genera una nueva API key para una compañía ya registrada."""
|
|
19
20
|
try:
|
|
20
21
|
profile_service = IAToolkit.get_instance().get_injector().get(ProfileService)
|
|
21
22
|
click.echo(f"🔑 Generating API-KEY for company: '{company_short_name}'...")
|
|
22
|
-
result = profile_service.new_api_key(company_short_name)
|
|
23
|
+
result = profile_service.new_api_key(company_short_name, key_name)
|
|
23
24
|
|
|
24
25
|
if 'error' in result:
|
|
25
26
|
click.echo(f"❌ Error: {result['error']}")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import List
|
|
3
|
+
import abc
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AssetType(Enum):
|
|
7
|
+
CONFIG = "config"
|
|
8
|
+
PROMPT = "prompts"
|
|
9
|
+
SCHEMA = "schema"
|
|
10
|
+
CONTEXT = "context"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AssetRepository(abc.ABC):
|
|
14
|
+
@abc.abstractmethod
|
|
15
|
+
def exists(self, company_short_name: str, asset_type: AssetType, filename: str) -> bool:
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@abc.abstractmethod
|
|
19
|
+
def read_text(self, company_short_name: str, asset_type: AssetType, filename: str) -> str:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@abc.abstractmethod
|
|
23
|
+
def list_files(self, company_short_name: str, asset_type: AssetType, extension: str = None) -> List[str]:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abc.abstractmethod
|
|
27
|
+
def write_text(self, company_short_name: str, asset_type: AssetType, filename: str, content: str) -> None:
|
|
28
|
+
"""Creates or updates a text asset."""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abc.abstractmethod
|
|
32
|
+
def delete(self, company_short_name: str, asset_type: AssetType, filename: str) -> None:
|
|
33
|
+
"""Deletes an asset if it exists."""
|
|
34
|
+
pass
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from typing import Any, List, Dict, Union
|
|
3
|
+
|
|
4
|
+
class DatabaseProvider(abc.ABC):
|
|
5
|
+
"""
|
|
6
|
+
Abstract interface for interacting with a database source.
|
|
7
|
+
Handles both metadata introspection and query execution.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# --- Schema Methods ---
|
|
11
|
+
@abc.abstractmethod
|
|
12
|
+
def get_all_table_names(self) -> List[str]:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
@abc.abstractmethod
|
|
16
|
+
def get_table_description(self,
|
|
17
|
+
table_name: str,
|
|
18
|
+
schema_object_name: str | None = None,
|
|
19
|
+
exclude_columns: List[str] | None = None) -> str:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
# --- Execution Methods ---
|
|
23
|
+
@abc.abstractmethod
|
|
24
|
+
def execute_query(self, query: str, commit: bool = False) -> Union[List[Dict[str, Any]], Dict[str, int]]:
|
|
25
|
+
"""
|
|
26
|
+
Executes a query and returns:
|
|
27
|
+
- A list of dicts for SELECT (rows).
|
|
28
|
+
- A dict {'rowcount': N} for INSERT/UPDATE/DELETE.
|
|
29
|
+
"""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
@abc.abstractmethod
|
|
33
|
+
def commit(self) -> None:
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
@abc.abstractmethod
|
|
37
|
+
def rollback(self) -> None:
|
|
38
|
+
pass
|
|
@@ -42,7 +42,7 @@ class ModelRegistry:
|
|
|
42
42
|
# Hardcoded rules for now; can be extended or loaded from config later.
|
|
43
43
|
# The order of patterns matters: first match wins.
|
|
44
44
|
self._provider_patterns: dict[ProviderType, tuple[str, ...]] = {
|
|
45
|
-
"openai": ("gpt", "gpt-5"),
|
|
45
|
+
"openai": ("gpt", "gpt-5", "gpt-5-mini", "gpt-5.1"),
|
|
46
46
|
"gemini": ("gemini", "gemini-3"),
|
|
47
47
|
"deepseek": ("deepseek",),
|
|
48
48
|
"xai": ("grok", "grok-1", "grok-beta"),
|
|
@@ -72,6 +72,57 @@ class ModelRegistry:
|
|
|
72
72
|
|
|
73
73
|
return "unknown"
|
|
74
74
|
|
|
75
|
+
def get_request_defaults(self, model: str) -> dict:
|
|
76
|
+
"""
|
|
77
|
+
Return per-model request defaults to keep model-specific policy centralized.
|
|
78
|
+
|
|
79
|
+
Notes:
|
|
80
|
+
- This should only include keys that are supported by the target provider.
|
|
81
|
+
- Callers should merge these defaults with user-provided params (do not mutate inputs).
|
|
82
|
+
"""
|
|
83
|
+
model_lower = (model or "").lower()
|
|
84
|
+
provider = self.get_provider(model_lower)
|
|
85
|
+
|
|
86
|
+
# Conservative defaults: do not send provider-specific knobs unless we know they are supported.
|
|
87
|
+
defaults = {"text": {}, "reasoning": {}}
|
|
88
|
+
|
|
89
|
+
# OpenAI/xAI (OpenAI-compatible) support 'text.verbosity' and 'reasoning.effort' in our current integration.
|
|
90
|
+
if provider in ("openai", "xai"):
|
|
91
|
+
defaults["text"] = {"verbosity": "low"}
|
|
92
|
+
|
|
93
|
+
# Fine-grained per-model tuning.
|
|
94
|
+
if model_lower in ("gpt-5", "gpt-5-mini"):
|
|
95
|
+
defaults["reasoning"] = {"effort": "minimal"}
|
|
96
|
+
elif model_lower == "gpt-5.1":
|
|
97
|
+
defaults["reasoning"] = {"effort": "low", "summary": "auto"}
|
|
98
|
+
|
|
99
|
+
# Gemini/DeepSeek/unknown: keep defaults empty to avoid sending unsupported parameters.
|
|
100
|
+
return defaults
|
|
101
|
+
|
|
102
|
+
def resolve_request_params(self, model: str, text: dict | None = None, reasoning: dict | None = None) -> dict:
|
|
103
|
+
"""
|
|
104
|
+
Resolve provider/model defaults and merge them with caller-provided overrides.
|
|
105
|
+
|
|
106
|
+
Rules:
|
|
107
|
+
- Defaults come from get_request_defaults(model).
|
|
108
|
+
- Caller overrides win over defaults.
|
|
109
|
+
- Input dictionaries are never mutated.
|
|
110
|
+
"""
|
|
111
|
+
defaults = self.get_request_defaults(model)
|
|
112
|
+
|
|
113
|
+
merged_text: dict = {}
|
|
114
|
+
merged_text.update(defaults.get("text") or {})
|
|
115
|
+
merged_text.update(text or {})
|
|
116
|
+
|
|
117
|
+
merged_reasoning: dict = {}
|
|
118
|
+
merged_reasoning.update(defaults.get("reasoning") or {})
|
|
119
|
+
merged_reasoning.update(reasoning or {})
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
"text": merged_text,
|
|
123
|
+
"reasoning": merged_reasoning,
|
|
124
|
+
}
|
|
125
|
+
|
|
75
126
|
def get_history_type(self, model: str) -> HistoryType:
|
|
76
127
|
"""
|
|
77
128
|
Returns the history strategy for a given model.
|
|
@@ -24,10 +24,13 @@ def register_views(app):
|
|
|
24
24
|
from iatoolkit.views.profile_api_view import UserLanguageApiView
|
|
25
25
|
from iatoolkit.views.embedding_api_view import EmbeddingApiView
|
|
26
26
|
from iatoolkit.views.login_view import LoginView, FinalizeContextView
|
|
27
|
+
from iatoolkit.views.load_company_configuration_api_view import LoadCompanyConfigurationApiView
|
|
27
28
|
from iatoolkit.views.logout_api_view import LogoutApiView
|
|
28
29
|
from iatoolkit.views.home_view import HomeView
|
|
30
|
+
from iatoolkit.views.chat_view import ChatView
|
|
29
31
|
from iatoolkit.views.static_page_view import StaticPageView
|
|
30
32
|
from iatoolkit.views.root_redirect_view import RootRedirectView
|
|
33
|
+
from iatoolkit.views.users_api_view import UsersApiView
|
|
31
34
|
|
|
32
35
|
# assign root '/' to our new redirect logic
|
|
33
36
|
app.add_url_rule('/home', view_func=RootRedirectView.as_view('root_redirect'))
|
|
@@ -38,6 +41,10 @@ def register_views(app):
|
|
|
38
41
|
# login for the iatoolkit integrated frontend
|
|
39
42
|
app.add_url_rule('/<company_short_name>/login', view_func=LoginView.as_view('login'))
|
|
40
43
|
|
|
44
|
+
# Chat Route (Direct Access)
|
|
45
|
+
app.add_url_rule('/<company_short_name>/chat',
|
|
46
|
+
view_func=ChatView.as_view('chat'))
|
|
47
|
+
|
|
41
48
|
# this endpoint is called when onboarding_shell finish the context load
|
|
42
49
|
app.add_url_rule(
|
|
43
50
|
'/<company_short_name>/finalize',
|
|
@@ -68,6 +75,10 @@ def register_views(app):
|
|
|
68
75
|
app.add_url_rule('/<company_short_name>/verify/<token>', view_func=VerifyAccountView.as_view('verify_account'))
|
|
69
76
|
app.add_url_rule('/<company_short_name>/forgot-password', view_func=ForgotPasswordView.as_view('forgot_password'))
|
|
70
77
|
app.add_url_rule('/<company_short_name>/change-password/<token>', view_func=ChangePasswordView.as_view('change_password'))
|
|
78
|
+
app.add_url_rule(
|
|
79
|
+
'/<string:company_short_name>/api/company-users',
|
|
80
|
+
view_func=UsersApiView.as_view('company-users')
|
|
81
|
+
)
|
|
71
82
|
|
|
72
83
|
# main chat query, used by the JS in the browser (with credentials)
|
|
73
84
|
# can be used also for executing iatoolkit prompts
|
|
@@ -88,6 +99,10 @@ def register_views(app):
|
|
|
88
99
|
app.add_url_rule('/<company_short_name>/api/embedding',
|
|
89
100
|
view_func=EmbeddingApiView.as_view('embedding_api'))
|
|
90
101
|
|
|
102
|
+
# company configuration
|
|
103
|
+
app.add_url_rule('/<company_short_name>/api/load_configuration',
|
|
104
|
+
view_func=LoadCompanyConfigurationApiView.as_view('load-configuration'))
|
|
105
|
+
|
|
91
106
|
# static pages
|
|
92
107
|
# url: /pages/foundation o /pages/implementation_plan
|
|
93
108
|
static_view = StaticPageView.as_view('static_pages')
|
|
@@ -157,6 +157,17 @@ class Utility:
|
|
|
157
157
|
schema = yaml.safe_load(f)
|
|
158
158
|
return schema
|
|
159
159
|
|
|
160
|
+
def load_yaml_from_string(self, yaml_content: str) -> dict:
|
|
161
|
+
"""
|
|
162
|
+
Parses a YAML string into a dictionary securely.
|
|
163
|
+
"""
|
|
164
|
+
try:
|
|
165
|
+
yaml_content = yaml_content.replace('\t', ' ')
|
|
166
|
+
return yaml.safe_load(yaml_content) or {}
|
|
167
|
+
except yaml.YAMLError as e:
|
|
168
|
+
logging.error(f"Error parsing YAML string: {e}")
|
|
169
|
+
return {}
|
|
170
|
+
|
|
160
171
|
def generate_context_for_schema(self, entity_name: str, schema_file: str = None, schema: dict = {}) -> str:
|
|
161
172
|
if not schema_file and not schema:
|
|
162
173
|
raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
from typing import Dict, Type, Any, Optional
|
|
7
7
|
from .base_company import BaseCompany
|
|
8
8
|
import logging
|
|
9
|
+
from injector import inject
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class CompanyRegistry:
|
|
@@ -14,6 +15,7 @@ class CompanyRegistry:
|
|
|
14
15
|
Allow the client to register companies and instantiate them with dependency injection.
|
|
15
16
|
"""
|
|
16
17
|
|
|
18
|
+
@inject
|
|
17
19
|
def __init__(self):
|
|
18
20
|
self._company_classes: Dict[str, Type[BaseCompany]] = {}
|
|
19
21
|
self._company_instances: Dict[str, BaseCompany] = {}
|
|
@@ -85,6 +87,9 @@ def get_company_registry() -> CompanyRegistry:
|
|
|
85
87
|
"""Get the global company registry instance."""
|
|
86
88
|
return _company_registry
|
|
87
89
|
|
|
90
|
+
def get_registered_companies() -> Dict[str, Type[BaseCompany]]:
|
|
91
|
+
return _company_registry.get_registered_companies()
|
|
92
|
+
|
|
88
93
|
|
|
89
94
|
def set_company_registry(registry: CompanyRegistry) -> None:
|
|
90
95
|
"""
|
|
@@ -9,20 +9,26 @@ from flask_injector import FlaskInjector
|
|
|
9
9
|
from flask_bcrypt import Bcrypt
|
|
10
10
|
from flask_cors import CORS
|
|
11
11
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
12
|
-
from typing import Optional, Dict, Any
|
|
13
12
|
from iatoolkit.repositories.database_manager import DatabaseManager
|
|
13
|
+
from iatoolkit.common.interfaces.asset_storage import AssetRepository
|
|
14
|
+
from iatoolkit.company_registry import get_registered_companies
|
|
14
15
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
15
16
|
from injector import Binder, Injector, singleton
|
|
17
|
+
from typing import Optional, Dict, Any
|
|
16
18
|
from urllib.parse import urlparse
|
|
17
19
|
import redis
|
|
18
20
|
import logging
|
|
19
21
|
import os
|
|
20
22
|
|
|
21
23
|
from iatoolkit import __version__ as IATOOLKIT_VERSION
|
|
24
|
+
from iatoolkit.services.configuration_service import ConfigurationService
|
|
22
25
|
|
|
23
26
|
# global variable for the unique instance of IAToolkit
|
|
24
27
|
_iatoolkit_instance: Optional['IAToolkit'] = None
|
|
25
28
|
|
|
29
|
+
def is_bound(injector: Injector, cls) -> bool:
|
|
30
|
+
return cls in injector.binder._bindings
|
|
31
|
+
|
|
26
32
|
class IAToolkit:
|
|
27
33
|
"""
|
|
28
34
|
IAToolkit main class
|
|
@@ -49,8 +55,8 @@ class IAToolkit:
|
|
|
49
55
|
self.config = config or {}
|
|
50
56
|
self.app = None
|
|
51
57
|
self.db_manager = None
|
|
52
|
-
self._injector =
|
|
53
|
-
self.version = IATOOLKIT_VERSION
|
|
58
|
+
self._injector = Injector() # init empty injector
|
|
59
|
+
self.version = IATOOLKIT_VERSION
|
|
54
60
|
self.license = "Community Edition"
|
|
55
61
|
|
|
56
62
|
@classmethod
|
|
@@ -61,7 +67,7 @@ class IAToolkit:
|
|
|
61
67
|
_iatoolkit_instance = cls()
|
|
62
68
|
return _iatoolkit_instance
|
|
63
69
|
|
|
64
|
-
def create_iatoolkit(self):
|
|
70
|
+
def create_iatoolkit(self, start: bool = True):
|
|
65
71
|
"""
|
|
66
72
|
Creates, configures, and returns the Flask application instance.
|
|
67
73
|
this is the main entry point for the application factory.
|
|
@@ -77,8 +83,8 @@ class IAToolkit:
|
|
|
77
83
|
# Step 2: Set up the core components that DI depends on
|
|
78
84
|
self._setup_database()
|
|
79
85
|
|
|
80
|
-
# Step 3:
|
|
81
|
-
self.
|
|
86
|
+
# Step 3: Configure dependencies using the existing injector
|
|
87
|
+
self._configure_core_dependencies(self._injector)
|
|
82
88
|
|
|
83
89
|
# Step 4: Register routes using the fully configured injector
|
|
84
90
|
self._register_routes()
|
|
@@ -98,6 +104,7 @@ class IAToolkit:
|
|
|
98
104
|
|
|
99
105
|
# Step 8: Finalize setup within the application context
|
|
100
106
|
self._setup_redis_sessions()
|
|
107
|
+
|
|
101
108
|
self._setup_cors()
|
|
102
109
|
self._setup_additional_services()
|
|
103
110
|
self._setup_cli_commands()
|
|
@@ -107,11 +114,21 @@ class IAToolkit:
|
|
|
107
114
|
# Step 9: define the download_dir
|
|
108
115
|
self._setup_download_dir()
|
|
109
116
|
|
|
117
|
+
# register data source
|
|
118
|
+
if start:
|
|
119
|
+
self.register_data_sources()
|
|
120
|
+
|
|
110
121
|
logging.info(f"🎉 IAToolkit {self.license} version {self.version} correctly initialized.")
|
|
111
122
|
self._initialized = True
|
|
112
123
|
|
|
113
124
|
return self.app
|
|
114
125
|
|
|
126
|
+
def register_data_sources(self):
|
|
127
|
+
# load the company configurations
|
|
128
|
+
configuration_service = self._injector.get(ConfigurationService)
|
|
129
|
+
for company in get_registered_companies():
|
|
130
|
+
configuration_service.register_data_sources(company)
|
|
131
|
+
|
|
115
132
|
def _get_config_value(self, key: str, default=None):
|
|
116
133
|
# get a value from the config dict or the environment variable
|
|
117
134
|
return self.config.get(key, os.getenv(key, default))
|
|
@@ -181,11 +198,11 @@ class IAToolkit:
|
|
|
181
198
|
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
|
182
199
|
|
|
183
200
|
def _setup_database(self):
|
|
184
|
-
database_uri = self._get_config_value('DATABASE_URI')
|
|
201
|
+
database_uri = self._get_config_value('DATABASE_URI') or self._get_config_value('DATABASE_URL')
|
|
185
202
|
if not database_uri:
|
|
186
203
|
raise IAToolkitException(
|
|
187
204
|
IAToolkitException.ErrorType.CONFIG_ERROR,
|
|
188
|
-
"DATABASE_URI is
|
|
205
|
+
"DATABASE_URI is required (config dict or env. variable)"
|
|
189
206
|
)
|
|
190
207
|
|
|
191
208
|
self.db_manager = DatabaseManager(database_url=database_uri, schema='iatoolkit')
|
|
@@ -240,8 +257,9 @@ class IAToolkit:
|
|
|
240
257
|
extra_origins = []
|
|
241
258
|
all_company_instances = get_company_registry().get_all_company_instances()
|
|
242
259
|
for company_name, company_instance in all_company_instances.items():
|
|
243
|
-
|
|
244
|
-
|
|
260
|
+
if company_instance.company:
|
|
261
|
+
cors_origin = company_instance.company.parameters.get('cors_origin', [])
|
|
262
|
+
extra_origins += cors_origin
|
|
245
263
|
|
|
246
264
|
all_origins = default_origins + extra_origins
|
|
247
265
|
|
|
@@ -256,8 +274,11 @@ class IAToolkit:
|
|
|
256
274
|
|
|
257
275
|
logging.info(f"✅ CORS configured for: {all_origins}")
|
|
258
276
|
|
|
259
|
-
def _configure_core_dependencies(self,
|
|
277
|
+
def _configure_core_dependencies(self, injector: Injector):
|
|
260
278
|
"""⚙️ Configures all system dependencies."""
|
|
279
|
+
|
|
280
|
+
# get the binder from injector
|
|
281
|
+
binder = injector.binder
|
|
261
282
|
try:
|
|
262
283
|
# Core dependencies
|
|
263
284
|
binder.bind(Flask, to=self.app)
|
|
@@ -282,12 +303,17 @@ class IAToolkit:
|
|
|
282
303
|
from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
283
304
|
from iatoolkit.repositories.llm_query_repo import LLMQueryRepo
|
|
284
305
|
from iatoolkit.repositories.vs_repo import VSRepo
|
|
306
|
+
from iatoolkit.repositories.filesystem_asset_repository import FileSystemAssetRepository
|
|
285
307
|
|
|
286
308
|
binder.bind(DocumentRepo, to=DocumentRepo)
|
|
287
309
|
binder.bind(ProfileRepo, to=ProfileRepo)
|
|
288
310
|
binder.bind(LLMQueryRepo, to=LLMQueryRepo)
|
|
289
311
|
binder.bind(VSRepo, to=VSRepo)
|
|
290
312
|
|
|
313
|
+
# this class can be setup befor by iatoolkit enterprise
|
|
314
|
+
if not is_bound(self._injector, AssetRepository):
|
|
315
|
+
binder.bind(AssetRepository, to=FileSystemAssetRepository)
|
|
316
|
+
|
|
291
317
|
def _bind_services(self, binder: Binder):
|
|
292
318
|
from iatoolkit.services.query_service import QueryService
|
|
293
319
|
from iatoolkit.services.benchmark_service import BenchmarkService
|
|
@@ -308,7 +334,7 @@ class IAToolkit:
|
|
|
308
334
|
from iatoolkit.services.tool_service import ToolService
|
|
309
335
|
from iatoolkit.services.llm_client_service import llmClient
|
|
310
336
|
from iatoolkit.services.auth_service import AuthService
|
|
311
|
-
|
|
337
|
+
from iatoolkit.services.sql_service import SqlService
|
|
312
338
|
|
|
313
339
|
binder.bind(QueryService, to=QueryService)
|
|
314
340
|
binder.bind(BenchmarkService, to=BenchmarkService)
|
|
@@ -329,6 +355,7 @@ class IAToolkit:
|
|
|
329
355
|
binder.bind(ToolService, to=ToolService)
|
|
330
356
|
binder.bind(llmClient, to=llmClient)
|
|
331
357
|
binder.bind(AuthService, to=AuthService)
|
|
358
|
+
binder.bind(SqlService, to=SqlService)
|
|
332
359
|
|
|
333
360
|
def _bind_infrastructure(self, binder: Binder):
|
|
334
361
|
from iatoolkit.infra.llm_proxy import LLMProxy
|
|
@@ -405,11 +432,13 @@ class IAToolkit:
|
|
|
405
432
|
'app_name': 'IAToolkit',
|
|
406
433
|
'user_identifier': SessionManager.get('user_identifier'),
|
|
407
434
|
'company_short_name': SessionManager.get('company_short_name'),
|
|
435
|
+
'user_role': user_profile.get('user_role'),
|
|
408
436
|
'user_is_local': user_profile.get('user_is_local'),
|
|
409
437
|
'user_email': user_profile.get('user_email'),
|
|
410
438
|
'iatoolkit_base_url': request.url_root,
|
|
411
439
|
'flashed_messages': get_flashed_messages(with_categories=True),
|
|
412
|
-
't': translate_for_template
|
|
440
|
+
't': translate_for_template,
|
|
441
|
+
'google_analytics_id': self._get_config_value('GOOGLE_ANALYTICS_ID', ''),
|
|
413
442
|
}
|
|
414
443
|
|
|
415
444
|
def _get_default_static_folder(self) -> str:
|
|
@@ -473,6 +502,7 @@ class IAToolkit:
|
|
|
473
502
|
logging.info(f"✅ download dir created in: {download_dir}")
|
|
474
503
|
|
|
475
504
|
|
|
505
|
+
|
|
476
506
|
def current_iatoolkit() -> IAToolkit:
|
|
477
507
|
return IAToolkit.get_instance()
|
|
478
508
|
|
{iatoolkit-0.95.4 → iatoolkit-0.108.1}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py
RENAMED
|
@@ -9,7 +9,7 @@ from typing import Dict, List, Optional, Any
|
|
|
9
9
|
|
|
10
10
|
from iatoolkit.infra.llm_response import LLMResponse, ToolCall, Usage
|
|
11
11
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
12
|
-
|
|
12
|
+
import json
|
|
13
13
|
|
|
14
14
|
class DeepseekAdapter:
|
|
15
15
|
"""
|
|
@@ -85,6 +85,7 @@ class DeepseekAdapter:
|
|
|
85
85
|
if tool_choice:
|
|
86
86
|
call_kwargs["tool_choice"] = tool_choice
|
|
87
87
|
|
|
88
|
+
logging.debug(f"[DeepseekAdapter] Calling DeepSeek chat.completions API...: {json.dumps(messages, indent=2)}")
|
|
88
89
|
response = self.client.chat.completions.create(**call_kwargs)
|
|
89
90
|
|
|
90
91
|
return self._map_deepseek_chat_response(response)
|
|
@@ -127,7 +128,7 @@ class DeepseekAdapter:
|
|
|
127
128
|
|
|
128
129
|
messages.append(
|
|
129
130
|
{
|
|
130
|
-
"role": "
|
|
131
|
+
"role": "user",
|
|
131
132
|
"content": f"Tool result:\n{output}",
|
|
132
133
|
}
|
|
133
134
|
)
|
|
@@ -141,10 +142,6 @@ class DeepseekAdapter:
|
|
|
141
142
|
logging.warning(f"[DeepseekAdapter] Skipping tool-role message: {item}")
|
|
142
143
|
continue
|
|
143
144
|
|
|
144
|
-
# Map internal 'model' role to 'assistant'
|
|
145
|
-
if role == "model":
|
|
146
|
-
role = "assistant"
|
|
147
|
-
|
|
148
145
|
if not role:
|
|
149
146
|
logging.warning(f"[DeepseekAdapter] Skipping message without role: {item}")
|
|
150
147
|
continue
|
|
@@ -230,13 +227,19 @@ class DeepseekAdapter:
|
|
|
230
227
|
total_tokens=getattr(getattr(response, "usage", None), "total_tokens", 0) or 0,
|
|
231
228
|
)
|
|
232
229
|
|
|
230
|
+
# Capture reasoning content (specific to deepseek-reasoner)
|
|
231
|
+
reasoning_content = getattr(message, "reasoning_content", "") or ""
|
|
232
|
+
|
|
233
|
+
# If the model produced tool calls, fills this list
|
|
233
234
|
tool_calls_out: List[ToolCall] = []
|
|
234
|
-
status = "completed"
|
|
235
|
-
output_text = ""
|
|
236
235
|
|
|
237
|
-
# If the model produced tool calls:
|
|
238
236
|
tool_calls = getattr(message, "tool_calls", None) or []
|
|
239
|
-
if tool_calls:
|
|
237
|
+
if not tool_calls:
|
|
238
|
+
# No tool calls: standard assistant message
|
|
239
|
+
output_text = getattr(message, "content", "") or ""
|
|
240
|
+
status = "completed"
|
|
241
|
+
|
|
242
|
+
else:
|
|
240
243
|
logging.debug(f"[DeepSeek] RAW tool_calls: {tool_calls}")
|
|
241
244
|
|
|
242
245
|
for tc in tool_calls:
|
|
@@ -264,11 +267,6 @@ class DeepseekAdapter:
|
|
|
264
267
|
status = "tool_calls"
|
|
265
268
|
output_text = "" # caller will inspect tool_calls in .output
|
|
266
269
|
|
|
267
|
-
else:
|
|
268
|
-
# No tool calls: standard assistant message
|
|
269
|
-
output_text = getattr(message, "content", "") or ""
|
|
270
|
-
status = "completed"
|
|
271
|
-
|
|
272
270
|
return LLMResponse(
|
|
273
271
|
id=getattr(response, "id", "deepseek-unknown"),
|
|
274
272
|
model=getattr(response, "model", "deepseek-unknown"),
|
|
@@ -276,4 +274,5 @@ class DeepseekAdapter:
|
|
|
276
274
|
output_text=output_text,
|
|
277
275
|
output=tool_calls_out,
|
|
278
276
|
usage=usage,
|
|
277
|
+
reasoning_content=reasoning_content
|
|
279
278
|
)
|
|
@@ -7,7 +7,8 @@ import logging
|
|
|
7
7
|
from typing import Dict, List, Optional
|
|
8
8
|
from iatoolkit.infra.llm_response import LLMResponse, ToolCall, Usage
|
|
9
9
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
10
|
-
|
|
10
|
+
import html
|
|
11
|
+
from typing import List
|
|
11
12
|
|
|
12
13
|
class OpenAIAdapter:
|
|
13
14
|
"""Adaptador para la API de OpenAI"""
|
|
@@ -76,11 +77,48 @@ class OpenAIAdapter:
|
|
|
76
77
|
total_tokens=openai_response.usage.total_tokens if openai_response.usage else 0
|
|
77
78
|
)
|
|
78
79
|
|
|
80
|
+
# Reasoning content extracted from Responses output items (type="reasoning")
|
|
81
|
+
reasoning_list = self._extract_reasoning_content(openai_response)
|
|
82
|
+
reasoning_str = "\n".join(reasoning_list)
|
|
83
|
+
|
|
79
84
|
return LLMResponse(
|
|
80
85
|
id=openai_response.id,
|
|
81
86
|
model=openai_response.model,
|
|
82
87
|
status=openai_response.status,
|
|
83
88
|
output_text=getattr(openai_response, 'output_text', ''),
|
|
84
89
|
output=tool_calls,
|
|
85
|
-
usage=usage
|
|
86
|
-
|
|
90
|
+
usage=usage,
|
|
91
|
+
reasoning_content=reasoning_str
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def _extract_reasoning_content(self, openai_response) -> List[str]:
|
|
95
|
+
"""
|
|
96
|
+
Extract reasoning summaries (preferred) or reasoning content fragments from Responses API output.
|
|
97
|
+
|
|
98
|
+
Format required by caller:
|
|
99
|
+
1. reason is ...
|
|
100
|
+
2. reason is ...
|
|
101
|
+
"""
|
|
102
|
+
reasons: List[str] = []
|
|
103
|
+
|
|
104
|
+
output_items = getattr(openai_response, "output", None) or []
|
|
105
|
+
for item in output_items:
|
|
106
|
+
if getattr(item, "type", None) != "reasoning":
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
# 1) Preferred: reasoning summaries (requires reasoning={"summary":"auto"} or similar)
|
|
110
|
+
summary = getattr(item, "summary", None) or []
|
|
111
|
+
for s in summary:
|
|
112
|
+
text = getattr(s, "text", None)
|
|
113
|
+
if text:
|
|
114
|
+
reasons.append(str(text).strip())
|
|
115
|
+
|
|
116
|
+
# 2) Fallback: some responses may carry reasoning content in "content"
|
|
117
|
+
# (e.g., content parts like {"type":"reasoning_text","text":"..."}).
|
|
118
|
+
content = getattr(item, "content", None) or []
|
|
119
|
+
for c in content:
|
|
120
|
+
text = getattr(c, "text", None)
|
|
121
|
+
if text:
|
|
122
|
+
reasons.append(str(text).strip())
|
|
123
|
+
|
|
124
|
+
return reasons
|
|
@@ -32,9 +32,14 @@ class LLMResponse:
|
|
|
32
32
|
output_text: str
|
|
33
33
|
output: List[ToolCall] # lista de tool calls
|
|
34
34
|
usage: Usage
|
|
35
|
+
reasoning_content: str = None # campo opcional para Chain of Thought
|
|
36
|
+
|
|
35
37
|
|
|
36
38
|
def __post_init__(self):
|
|
37
39
|
"""Asegura que output sea una lista"""
|
|
38
40
|
if self.output is None:
|
|
39
41
|
self.output = []
|
|
40
42
|
|
|
43
|
+
if self.reasoning_content is None:
|
|
44
|
+
self.reasoning_content = ""
|
|
45
|
+
|