iatoolkit 0.91.1__py3-none-any.whl → 1.4.2__py3-none-any.whl

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 (69) hide show
  1. iatoolkit/__init__.py +6 -4
  2. iatoolkit/base_company.py +0 -16
  3. iatoolkit/cli_commands.py +3 -14
  4. iatoolkit/common/exceptions.py +1 -0
  5. iatoolkit/common/interfaces/__init__.py +0 -0
  6. iatoolkit/common/interfaces/asset_storage.py +34 -0
  7. iatoolkit/common/interfaces/database_provider.py +38 -0
  8. iatoolkit/common/model_registry.py +159 -0
  9. iatoolkit/common/routes.py +42 -5
  10. iatoolkit/common/util.py +11 -12
  11. iatoolkit/company_registry.py +5 -0
  12. iatoolkit/core.py +51 -20
  13. iatoolkit/infra/llm_providers/__init__.py +0 -0
  14. iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
  15. iatoolkit/infra/{gemini_adapter.py → llm_providers/gemini_adapter.py} +11 -17
  16. iatoolkit/infra/{openai_adapter.py → llm_providers/openai_adapter.py} +41 -7
  17. iatoolkit/infra/llm_proxy.py +235 -134
  18. iatoolkit/infra/llm_response.py +5 -0
  19. iatoolkit/locales/en.yaml +124 -2
  20. iatoolkit/locales/es.yaml +122 -0
  21. iatoolkit/repositories/database_manager.py +44 -19
  22. iatoolkit/repositories/document_repo.py +7 -0
  23. iatoolkit/repositories/filesystem_asset_repository.py +36 -0
  24. iatoolkit/repositories/llm_query_repo.py +2 -0
  25. iatoolkit/repositories/models.py +72 -79
  26. iatoolkit/repositories/profile_repo.py +59 -3
  27. iatoolkit/repositories/vs_repo.py +22 -24
  28. iatoolkit/services/company_context_service.py +88 -39
  29. iatoolkit/services/configuration_service.py +157 -68
  30. iatoolkit/services/dispatcher_service.py +21 -3
  31. iatoolkit/services/file_processor_service.py +0 -5
  32. iatoolkit/services/history_manager_service.py +43 -24
  33. iatoolkit/services/knowledge_base_service.py +412 -0
  34. iatoolkit/{infra/llm_client.py → services/llm_client_service.py} +38 -29
  35. iatoolkit/services/load_documents_service.py +18 -47
  36. iatoolkit/services/profile_service.py +32 -4
  37. iatoolkit/services/prompt_service.py +32 -30
  38. iatoolkit/services/query_service.py +51 -26
  39. iatoolkit/services/sql_service.py +105 -74
  40. iatoolkit/services/tool_service.py +26 -11
  41. iatoolkit/services/user_session_context_service.py +115 -63
  42. iatoolkit/static/js/chat_main.js +44 -4
  43. iatoolkit/static/js/chat_model_selector.js +227 -0
  44. iatoolkit/static/js/chat_onboarding_button.js +1 -1
  45. iatoolkit/static/js/chat_reload_button.js +4 -1
  46. iatoolkit/static/styles/chat_iatoolkit.css +58 -2
  47. iatoolkit/static/styles/llm_output.css +34 -1
  48. iatoolkit/system_prompts/query_main.prompt +26 -2
  49. iatoolkit/templates/base.html +13 -0
  50. iatoolkit/templates/chat.html +44 -2
  51. iatoolkit/templates/onboarding_shell.html +0 -1
  52. iatoolkit/views/base_login_view.py +7 -2
  53. iatoolkit/views/chat_view.py +76 -0
  54. iatoolkit/views/load_company_configuration_api_view.py +49 -0
  55. iatoolkit/views/load_document_api_view.py +14 -10
  56. iatoolkit/views/login_view.py +8 -3
  57. iatoolkit/views/rag_api_view.py +216 -0
  58. iatoolkit/views/users_api_view.py +33 -0
  59. {iatoolkit-0.91.1.dist-info → iatoolkit-1.4.2.dist-info}/METADATA +4 -4
  60. {iatoolkit-0.91.1.dist-info → iatoolkit-1.4.2.dist-info}/RECORD +64 -56
  61. iatoolkit/repositories/tasks_repo.py +0 -52
  62. iatoolkit/services/search_service.py +0 -55
  63. iatoolkit/services/tasks_service.py +0 -188
  64. iatoolkit/views/tasks_api_view.py +0 -72
  65. iatoolkit/views/tasks_review_api_view.py +0 -55
  66. {iatoolkit-0.91.1.dist-info → iatoolkit-1.4.2.dist-info}/WHEEL +0 -0
  67. {iatoolkit-0.91.1.dist-info → iatoolkit-1.4.2.dist-info}/licenses/LICENSE +0 -0
  68. {iatoolkit-0.91.1.dist-info → iatoolkit-1.4.2.dist-info}/licenses/LICENSE_COMMUNITY.md +0 -0
  69. {iatoolkit-0.91.1.dist-info → iatoolkit-1.4.2.dist-info}/top_level.txt +0 -0
iatoolkit/__init__.py CHANGED
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
- __version__ = "0.91.1"
6
+ __version__ = "1.4.2"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -17,13 +17,14 @@ from .base_company import BaseCompany
17
17
  # --- Services ---
18
18
  from iatoolkit.services.query_service import QueryService
19
19
  from iatoolkit.services.document_service import DocumentService
20
- from iatoolkit.services.search_service import SearchService
20
+ from iatoolkit.services.knowledge_base_service import KnowledgeBaseService
21
21
  from iatoolkit.services.sql_service import SqlService
22
22
  from iatoolkit.services.load_documents_service import LoadDocumentsService
23
23
  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',
@@ -35,10 +36,11 @@ __all__ = [
35
36
  'QueryService',
36
37
  'SqlService',
37
38
  'DocumentService',
38
- 'SearchService',
39
+ 'KnowledgeBaseService',
39
40
  'LoadDocumentsService',
40
41
  'CallServiceClient',
41
42
  'ProfileService',
42
43
  'MailService',
43
- 'OrmModel'
44
+ 'OrmModel',
45
+ 'BaseCompany',
44
46
  ]
iatoolkit/base_company.py CHANGED
@@ -5,21 +5,8 @@
5
5
 
6
6
  # companies/base_company.py
7
7
  from abc import ABC, abstractmethod
8
- from iatoolkit.repositories.profile_repo import ProfileRepo
9
- from iatoolkit.repositories.llm_query_repo import LLMQueryRepo
10
- from iatoolkit.repositories.models import Company
11
- from iatoolkit.core import IAToolkit
12
-
13
8
 
14
9
  class BaseCompany(ABC):
15
- def __init__(self):
16
- # Obtener el inyector global y resolver las dependencias internamente
17
- injector = IAToolkit.get_instance().get_injector()
18
- self.profile_repo: ProfileRepo = injector.get(ProfileRepo)
19
- self.llm_query_repo: LLMQueryRepo = injector.get(LLMQueryRepo)
20
- self.company: Company | None = None
21
- self.company_short_name = ''
22
-
23
10
 
24
11
  @abstractmethod
25
12
  # execute the specific action configured in the intent table
@@ -28,9 +15,6 @@ class BaseCompany(ABC):
28
15
 
29
16
  @abstractmethod
30
17
  def register_cli_commands(self, app):
31
- """
32
- optional method for a company definition of it's cli commands
33
- """
34
18
  pass
35
19
 
36
20
  def unsupported_operation(self, tag):
iatoolkit/cli_commands.py CHANGED
@@ -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
- def api_key(company_short_name: str):
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']}")
@@ -44,17 +45,5 @@ def register_core_commands(app):
44
45
  logging.exception(e)
45
46
  click.echo(f"Error: {str(e)}")
46
47
 
47
- @app.cli.command("exec-tasks")
48
- @click.argument("company_short_name")
49
- def exec_pending_tasks(company_short_name: str):
50
- from iatoolkit.services.tasks_service import TaskService
51
- task_service = IAToolkit.get_instance().get_injector().get(TaskService)
52
-
53
- try:
54
- result = task_service.trigger_pending_tasks(company_short_name)
55
- click.echo(result['message'])
56
- except Exception as e:
57
- logging.exception(e)
58
- click.echo(f"Error: {str(e)}")
59
48
 
60
49
 
@@ -38,6 +38,7 @@ class IAToolkitException(Exception):
38
38
  INVALID_USER = 26
39
39
  VECTOR_STORE_ERROR = 27
40
40
  EMBEDDING_ERROR = 28
41
+ MODEL = 29
41
42
 
42
43
 
43
44
 
File without changes
@@ -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
@@ -0,0 +1,159 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ # Copyright (c) 2024 Fernando Libedinsky
7
+ # Product: IAToolkit
8
+ #
9
+ # IAToolkit is open source software.
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+ from injector import inject, singleton
15
+ from typing import Literal
16
+
17
+
18
+ HistoryType = Literal["server_side", "client_side"]
19
+ ProviderType = Literal["openai", "gemini", "deepseek", "xai", "anthropic", "unknown"]
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class ModelMetadata:
24
+ """Static metadata for a logical family of models."""
25
+ provider: ProviderType
26
+ history_type: HistoryType
27
+
28
+
29
+ @singleton
30
+ class ModelRegistry:
31
+ """
32
+ Central registry for model metadata.
33
+
34
+ Responsibilities:
35
+ - Map a model name to its provider (openai, gemini, deepseek, etc.).
36
+ - Decide which history strategy to use for a model (server_side / client_side).
37
+ - Provide convenience helpers (is_openai, is_gemini, is_deepseek, etc.).
38
+ """
39
+
40
+ @inject
41
+ def __init__(self):
42
+ # Hardcoded rules for now; can be extended or loaded from config later.
43
+ # The order of patterns matters: first match wins.
44
+ self._provider_patterns: dict[ProviderType, tuple[str, ...]] = {
45
+ "openai": ("gpt", "gpt-5", "gpt-5-mini", "gpt-5.1"),
46
+ "gemini": ("gemini", "gemini-3"),
47
+ "deepseek": ("deepseek",),
48
+ "xai": ("grok", "grok-1", "grok-beta"),
49
+ "anthropic": ("claude", "claude-3", "claude-2"),
50
+ }
51
+
52
+ # ------------------------------------------------------------------
53
+ # Public API
54
+ # ------------------------------------------------------------------
55
+
56
+ def get_provider(self, model: str) -> ProviderType:
57
+ """
58
+ Returns the logical provider for a given model name.
59
+
60
+ Examples:
61
+ "gpt-4o" -> "openai"
62
+ "gemini-pro" -> "gemini"
63
+ "deepseek-chat" -> "deepseek"
64
+ """
65
+ if not model:
66
+ return "unknown"
67
+
68
+ model_lower = model.lower()
69
+ for provider, patterns in self._provider_patterns.items():
70
+ if any(pat in model_lower for pat in patterns):
71
+ return provider
72
+
73
+ return "unknown"
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
+
126
+ def get_history_type(self, model: str) -> HistoryType:
127
+ """
128
+ Returns the history strategy for a given model.
129
+
130
+ Current rules:
131
+ - openai/xai/anthropic: server_side (API manages conversation state via ids)
132
+ - gemini/deepseek/unknown: client_side (we manage full message history)
133
+ """
134
+ provider = self.get_provider(model)
135
+
136
+ if provider in ("openai", "xai", "anthropic"):
137
+ return "server_side"
138
+
139
+ # Default for gemini, deepseek and any unknown provider
140
+ return "client_side"
141
+
142
+ # ------------------------------------------------------------------
143
+ # Convenience helpers (used during migration)
144
+ # ------------------------------------------------------------------
145
+
146
+ def is_openai_model(self, model: str) -> bool:
147
+ return self.get_provider(model) == "openai"
148
+
149
+ def is_gemini_model(self, model: str) -> bool:
150
+ return self.get_provider(model) == "gemini"
151
+
152
+ def is_deepseek_model(self, model: str) -> bool:
153
+ return self.get_provider(model) == "deepseek"
154
+
155
+ def is_xai_model(self, model: str) -> bool:
156
+ return self.get_provider(model) == "xai"
157
+
158
+ def is_anthropic_model(self, model: str) -> bool:
159
+ return self.get_provider(model) == "anthropic"
@@ -12,8 +12,6 @@ def register_views(app):
12
12
 
13
13
  from iatoolkit.views.init_context_api_view import InitContextApiView
14
14
  from iatoolkit.views.llmquery_api_view import LLMQueryApiView
15
- from iatoolkit.views.tasks_api_view import TaskApiView
16
- from iatoolkit.views.tasks_review_api_view import TaskReviewApiView
17
15
  from iatoolkit.views.signup_view import SignupView
18
16
  from iatoolkit.views.verify_user_view import VerifyAccountView
19
17
  from iatoolkit.views.forgot_password_view import ForgotPasswordView
@@ -26,10 +24,14 @@ def register_views(app):
26
24
  from iatoolkit.views.profile_api_view import UserLanguageApiView
27
25
  from iatoolkit.views.embedding_api_view import EmbeddingApiView
28
26
  from iatoolkit.views.login_view import LoginView, FinalizeContextView
27
+ from iatoolkit.views.load_company_configuration_api_view import LoadCompanyConfigurationApiView
29
28
  from iatoolkit.views.logout_api_view import LogoutApiView
30
29
  from iatoolkit.views.home_view import HomeView
30
+ from iatoolkit.views.chat_view import ChatView
31
31
  from iatoolkit.views.static_page_view import StaticPageView
32
32
  from iatoolkit.views.root_redirect_view import RootRedirectView
33
+ from iatoolkit.views.users_api_view import UsersApiView
34
+ from iatoolkit.views.rag_api_view import RagApiView
33
35
 
34
36
  # assign root '/' to our new redirect logic
35
37
  app.add_url_rule('/home', view_func=RootRedirectView.as_view('root_redirect'))
@@ -40,6 +42,10 @@ def register_views(app):
40
42
  # login for the iatoolkit integrated frontend
41
43
  app.add_url_rule('/<company_short_name>/login', view_func=LoginView.as_view('login'))
42
44
 
45
+ # Chat Route (Direct Access)
46
+ app.add_url_rule('/<company_short_name>/chat',
47
+ view_func=ChatView.as_view('chat'))
48
+
43
49
  # this endpoint is called when onboarding_shell finish the context load
44
50
  app.add_url_rule(
45
51
  '/<company_short_name>/finalize',
@@ -70,6 +76,10 @@ def register_views(app):
70
76
  app.add_url_rule('/<company_short_name>/verify/<token>', view_func=VerifyAccountView.as_view('verify_account'))
71
77
  app.add_url_rule('/<company_short_name>/forgot-password', view_func=ForgotPasswordView.as_view('forgot_password'))
72
78
  app.add_url_rule('/<company_short_name>/change-password/<token>', view_func=ChangePasswordView.as_view('change_password'))
79
+ app.add_url_rule(
80
+ '/<string:company_short_name>/api/company-users',
81
+ view_func=UsersApiView.as_view('company-users')
82
+ )
73
83
 
74
84
  # main chat query, used by the JS in the browser (with credentials)
75
85
  # can be used also for executing iatoolkit prompts
@@ -83,9 +93,32 @@ def register_views(app):
83
93
  app.add_url_rule('/<company_short_name>/api/history', view_func=HistoryApiView.as_view('history'))
84
94
  app.add_url_rule('/<company_short_name>/api/help-content', view_func=HelpContentApiView.as_view('help-content'))
85
95
 
86
- # tasks management endpoints: create task, and review answer
87
- app.add_url_rule('/tasks', view_func=TaskApiView.as_view('tasks'))
88
- app.add_url_rule('/tasks/review/<int:task_id>', view_func=TaskReviewApiView.as_view('tasks-review'))
96
+ # --- RAG API Routes ---
97
+ rag_view = RagApiView.as_view('rag_api')
98
+
99
+ # 1. List Files (POST for filters)
100
+ app.add_url_rule('/api/rag/<company_short_name>/files',
101
+ view_func=rag_view,
102
+ methods=['POST'],
103
+ defaults={'action': 'list_files'})
104
+
105
+ # 2. Delete File
106
+ app.add_url_rule('/api/rag/<company_short_name>/files/<int:document_id>',
107
+ view_func=rag_view,
108
+ methods=['DELETE'],
109
+ defaults={'action': 'delete_file'})
110
+
111
+ # 3. Search Lab
112
+ app.add_url_rule('/api/rag/<company_short_name>/search',
113
+ view_func=rag_view,
114
+ methods=['POST'],
115
+ defaults={'action': 'search'})
116
+
117
+ # 4. Get File Content (View/Download)
118
+ app.add_url_rule('/api/rag/<company_short_name>/files/<int:document_id>/content',
119
+ view_func=rag_view,
120
+ methods=['GET'],
121
+ defaults={'action': 'get_file_content'})
89
122
 
90
123
  # this endpoint is for upload documents into the vector store (api-key)
91
124
  app.add_url_rule('/api/load-document', view_func=LoadDocumentApiView.as_view('load-document'), methods=['POST'])
@@ -94,6 +127,10 @@ def register_views(app):
94
127
  app.add_url_rule('/<company_short_name>/api/embedding',
95
128
  view_func=EmbeddingApiView.as_view('embedding_api'))
96
129
 
130
+ # company configuration
131
+ app.add_url_rule('/<company_short_name>/api/load_configuration',
132
+ view_func=LoadCompanyConfigurationApiView.as_view('load-configuration'))
133
+
97
134
  # static pages
98
135
  # url: /pages/foundation o /pages/implementation_plan
99
136
  static_view = StaticPageView.as_view('static_pages')
iatoolkit/common/util.py CHANGED
@@ -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,
@@ -340,15 +351,3 @@ class Utility:
340
351
  logging.exception(e)
341
352
  raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
342
353
  f'Error al buscar archivos en el directorio {directory}: {str(e)}') from e
343
-
344
- def is_openai_model(self, model: str) -> bool:
345
- openai_models = [
346
- 'gpt-5', 'gpt'
347
- ]
348
- return any(openai_model in model.lower() for openai_model in openai_models)
349
-
350
- def is_gemini_model(self, model: str) -> bool:
351
- gemini_models = [
352
- 'gemini', 'gemini-2.5-pro', 'gemini-3'
353
- ]
354
- return any(gemini_model in model.lower() for gemini_model in gemini_models)
@@ -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
  """