unique_toolkit 1.37.0__py3-none-any.whl → 1.38.0__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.
@@ -61,17 +61,8 @@ def validate_and_init_language_model_info(
61
61
  LanguageModelInfo: The validated and initialized LanguageModelInfo object.
62
62
 
63
63
  """
64
- if isinstance(v, LanguageModelName):
64
+ if isinstance(v, LanguageModelName | str):
65
65
  return LanguageModelInfo.from_name(v)
66
- if isinstance(v, str):
67
- if v in [name.value for name in LanguageModelName]:
68
- return LanguageModelInfo.from_name(LanguageModelName(v))
69
-
70
- return LanguageModelInfo(
71
- name=v,
72
- version="custom",
73
- provider=LanguageModelProvider.CUSTOM,
74
- )
75
66
 
76
67
  return v
77
68
 
@@ -1,5 +1,9 @@
1
+ import json
2
+ import logging
3
+ import os
1
4
  from datetime import date
2
5
  from enum import StrEnum
6
+ from functools import lru_cache
3
7
  from typing import Annotated, Any, ClassVar, Optional, Self
4
8
 
5
9
  from pydantic import BaseModel, Field
@@ -9,6 +13,8 @@ from typing_extensions import deprecated
9
13
  from unique_toolkit._common.pydantic_helpers import get_configuration_dict
10
14
  from unique_toolkit.language_model.schemas import LanguageModelTokenLimits
11
15
 
16
+ _LOGGER = logging.getLogger(__name__)
17
+
12
18
 
13
19
  class LanguageModelName(StrEnum):
14
20
  AZURE_GPT_35_TURBO_0125 = "AZURE_GPT_35_TURBO_0125"
@@ -202,8 +208,84 @@ class LanguageModelInfo(BaseModel):
202
208
 
203
209
  default_options: dict[str, Any] = {}
204
210
 
211
+ _ENV_VAR: ClassVar[str] = "LANGUAGE_MODEL_INFOS"
212
+ """Environment variable name for custom language model infos."""
213
+
214
+ @classmethod
215
+ @lru_cache(maxsize=1)
216
+ def _load_from_env(cls) -> dict[str, dict]:
217
+ """
218
+ Load custom language model infos from environment variable.
219
+
220
+ The environment variable should contain a JSON string with a dict of
221
+ LanguageModelInfo-compatible dictionaries. The key is used for model lookup.
222
+
223
+ Example:
224
+ LANGUAGE_MODEL_INFOS='{"AZURE_GPT_4o_CUSTOM": {"name": "AZURE_GPT_4o_2024_1120",
225
+ "provider": "AZURE", "version": "custom", "capabilities": ["function_calling",
226
+ "streaming", "vision"], "token_limits": {"token_limit_input": 3000,
227
+ "token_limit_output": 150}}}'
228
+
229
+ Returns:
230
+ A dictionary mapping model keys to their info dictionaries.
231
+ """
232
+ env_value = os.getenv(cls._ENV_VAR)
233
+ if not env_value:
234
+ return {}
235
+
236
+ try:
237
+ model_infos_dict = json.loads(env_value)
238
+ if not isinstance(model_infos_dict, dict):
239
+ _LOGGER.error(
240
+ f"{cls._ENV_VAR} must be a JSON dict of model info objects. "
241
+ f"Got {type(model_infos_dict).__name__} instead."
242
+ )
243
+ return {}
244
+
245
+ # Validate each entry in the dictionary
246
+ valid_model_infos: dict[str, dict] = {}
247
+ for model_key, model_info in model_infos_dict.items():
248
+ if not isinstance(model_info, dict):
249
+ _LOGGER.warning(
250
+ f"Skipping invalid model info entry '{model_key}' in {cls._ENV_VAR}: "
251
+ f"expected dict, got {type(model_info).__name__}"
252
+ )
253
+ continue
254
+
255
+ valid_model_infos[model_key] = model_info
256
+
257
+ _LOGGER.debug(
258
+ f"Loaded {len(valid_model_infos)} custom language model infos from {cls._ENV_VAR}"
259
+ )
260
+ return valid_model_infos
261
+
262
+ except json.JSONDecodeError:
263
+ _LOGGER.error(
264
+ f"Failed to parse {cls._ENV_VAR} as JSON. "
265
+ "The environment variable should contain a valid JSON dict of model info objects.",
266
+ exc_info=True,
267
+ )
268
+ return {}
269
+
205
270
  @classmethod
206
- def from_name(cls, model_name: LanguageModelName) -> Self:
271
+ def from_name(cls, model_name: LanguageModelName | str) -> Self:
272
+ # Check environment variable first - env definitions take precedence
273
+ env_model_infos = cls._load_from_env()
274
+ model_name_str = (
275
+ model_name.value
276
+ if isinstance(model_name, LanguageModelName)
277
+ else model_name
278
+ )
279
+ if model_name_str in env_model_infos.keys():
280
+ try:
281
+ return cls.model_validate(env_model_infos[model_name_str])
282
+ except Exception:
283
+ _LOGGER.warning(
284
+ f"Failed to parse model info for '{model_name_str}' from "
285
+ f"{cls._ENV_VAR}. Falling back to default definition.",
286
+ exc_info=True,
287
+ )
288
+
207
289
  match model_name:
208
290
  case LanguageModelName.AZURE_GPT_35_TURBO_0125:
209
291
  return cls(
@@ -1723,14 +1805,7 @@ class LanguageModel:
1723
1805
 
1724
1806
  @classmethod
1725
1807
  def get_model_info(cls, model_name: LanguageModelName | str) -> LanguageModelInfo:
1726
- if isinstance(model_name, LanguageModelName):
1727
- return LanguageModelInfo.from_name(model_name)
1728
-
1729
- return LanguageModelInfo(
1730
- name=model_name,
1731
- version="custom",
1732
- provider=LanguageModelProvider.CUSTOM,
1733
- )
1808
+ return LanguageModelInfo.from_name(model_name)
1734
1809
 
1735
1810
  @classmethod
1736
1811
  def list_models(cls) -> list[LanguageModelInfo]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.37.0
3
+ Version: 1.38.0
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -121,6 +121,9 @@ All notable changes to this project will be documented in this file.
121
121
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
122
122
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
123
123
 
124
+ ## [1.38.0] - 2025-12-15
125
+ - Including capability to load LanguageModelInfos in env variable
126
+
124
127
  ## [1.37.0] - 2025-12-15
125
128
  - Adding a prompt appendix to enforce forced tool calls when using Qwen models
126
129
 
@@ -39,7 +39,7 @@ unique_toolkit/_common/utils/structured_output/__init__.py,sha256=nm_orZrlCXL0FP
39
39
  unique_toolkit/_common/utils/structured_output/schema.py,sha256=Tp7kDYcmKtnUhcuRkH86TSYhylRff0ZZJYb2dLkISts,131
40
40
  unique_toolkit/_common/utils/write_configuration.py,sha256=fzvr4C-XBL3OSM3Od9TbqIxeeDS9_d9CLEyTq6DDknY,1409
41
41
  unique_toolkit/_common/validate_required_values.py,sha256=Y_M1ub9gIKP9qZ45F6Zq3ZHtuIqhmOjl8Z2Vd3avg8w,588
42
- unique_toolkit/_common/validators.py,sha256=LFZmAalNa886EXm1VYamFvfBuUZjYKwDdT_HOYU0BtE,2934
42
+ unique_toolkit/_common/validators.py,sha256=ElnkMsyEY24TfzfTVHvireyT39EnZgW5N40T0P4b6gE,2638
43
43
  unique_toolkit/agentic/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
44
44
  unique_toolkit/agentic/debug_info_manager/debug_info_manager.py,sha256=30ZZaw0vffjZjiu9AYdO1Sm8G9FN6XR2ehdOEUCKqh0,891
45
45
  unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py,sha256=_fIS6_DHA8A3AB64-LPgHgUGa1w0CFUWwtgV-ZbhkzA,10535
@@ -194,7 +194,7 @@ unique_toolkit/language_model/builder.py,sha256=4OKfwJfj3TrgO1ezc_ewIue6W7BCQ2ZY
194
194
  unique_toolkit/language_model/constants.py,sha256=B-topqW0r83dkC_25DeQfnPk3n53qzIHUCBS7YJ0-1U,119
195
195
  unique_toolkit/language_model/default_language_model.py,sha256=-_DBsJhLCsFdaU4ynAkyW0jYIl2lhrPybZm1K-GgVJs,125
196
196
  unique_toolkit/language_model/functions.py,sha256=PTBm2BBkuqISVHoyUqMIGHGXT-RMSAfz0F_Ylo2esQ8,18246
197
- unique_toolkit/language_model/infos.py,sha256=sZJOOij-dfReDxJWfd7ZwP3qx4KcN1LVqNchRafKmrY,79877
197
+ unique_toolkit/language_model/infos.py,sha256=Bh6-Fs_xbqqhEPRbEiudcrLPIHYPyfHuzfRZtBVs9I0,82806
198
198
  unique_toolkit/language_model/prompt.py,sha256=JSawaLjQg3VR-E2fK8engFyJnNdk21zaO8pPIodzN4Q,3991
199
199
  unique_toolkit/language_model/reference.py,sha256=nkX2VFz-IrUz8yqyc3G5jUMNwrNpxITBrMEKkbqqYoI,8583
200
200
  unique_toolkit/language_model/schemas.py,sha256=ATiHjhfGxoubS332XuhL9PKSoFewcWvPTUVBaNGWlJo,23994
@@ -212,7 +212,7 @@ unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBu
212
212
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
213
213
  unique_toolkit/smart_rules/compile.py,sha256=Ozhh70qCn2yOzRWr9d8WmJeTo7AQurwd3tStgBMPFLA,1246
214
214
  unique_toolkit/test_utilities/events.py,sha256=_mwV2bs5iLjxS1ynDCjaIq-gjjKhXYCK-iy3dRfvO3g,6410
215
- unique_toolkit-1.37.0.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
216
- unique_toolkit-1.37.0.dist-info/METADATA,sha256=P8N25tqQqezFmyaOYAXtauCGKHdeGaxMa9kyfd-x1_Q,46284
217
- unique_toolkit-1.37.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
218
- unique_toolkit-1.37.0.dist-info/RECORD,,
215
+ unique_toolkit-1.38.0.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
216
+ unique_toolkit-1.38.0.dist-info/METADATA,sha256=OJdgZ3Hlti9zeds9NTOC6OOibFeUsedeFjtZzVZJMTo,46376
217
+ unique_toolkit-1.38.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
218
+ unique_toolkit-1.38.0.dist-info/RECORD,,