langroid 0.50.10__py3-none-any.whl → 0.50.12__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.
- langroid/language_models/openai_gpt.py +45 -41
- langroid/utils/configuration.py +85 -46
- {langroid-0.50.10.dist-info → langroid-0.50.12.dist-info}/METADATA +1 -1
- {langroid-0.50.10.dist-info → langroid-0.50.12.dist-info}/RECORD +6 -6
- {langroid-0.50.10.dist-info → langroid-0.50.12.dist-info}/WHEEL +0 -0
- {langroid-0.50.10.dist-info → langroid-0.50.12.dist-info}/licenses/LICENSE +0 -0
@@ -157,7 +157,7 @@ class AccessWarning(Warning):
|
|
157
157
|
def gpt_3_5_warning() -> None:
|
158
158
|
warnings.warn(
|
159
159
|
f"""
|
160
|
-
{OpenAIChatModel.GPT4o} is not available,
|
160
|
+
{OpenAIChatModel.GPT4o} is not available,
|
161
161
|
falling back to {OpenAIChatModel.GPT3_5_TURBO}.
|
162
162
|
Examples may not work properly and unexpected behavior may occur.
|
163
163
|
Adjustments to prompts may be necessary.
|
@@ -435,8 +435,8 @@ class OpenAIGPT(LanguageModel):
|
|
435
435
|
self.config.formatter = formatter
|
436
436
|
logging.warning(
|
437
437
|
f"""
|
438
|
-
Using completions (not chat) endpoint with HuggingFace
|
439
|
-
chat_template for {formatter} for
|
438
|
+
Using completions (not chat) endpoint with HuggingFace
|
439
|
+
chat_template for {formatter} for
|
440
440
|
model {self.config.chat_model}
|
441
441
|
"""
|
442
442
|
)
|
@@ -758,13 +758,8 @@ class OpenAIGPT(LanguageModel):
|
|
758
758
|
return tmp
|
759
759
|
|
760
760
|
def get_stream(self) -> bool:
|
761
|
-
"""Get streaming status.
|
762
|
-
return (
|
763
|
-
self.config.stream
|
764
|
-
and settings.stream
|
765
|
-
and self.info().allows_streaming
|
766
|
-
and not settings.quiet
|
767
|
-
)
|
761
|
+
"""Get streaming status."""
|
762
|
+
return self.config.stream and settings.stream and self.info().allows_streaming
|
768
763
|
|
769
764
|
@no_type_check
|
770
765
|
def _process_stream_event(
|
@@ -813,6 +808,7 @@ class OpenAIGPT(LanguageModel):
|
|
813
808
|
event_args = ""
|
814
809
|
event_fn_name = ""
|
815
810
|
event_tool_deltas: Optional[List[Dict[str, Any]]] = None
|
811
|
+
silent = settings.quiet
|
816
812
|
# The first two events in the stream of Azure OpenAI is useless.
|
817
813
|
# In the 1st: choices list is empty, in the 2nd: the dict delta has null content
|
818
814
|
if chat:
|
@@ -852,25 +848,29 @@ class OpenAIGPT(LanguageModel):
|
|
852
848
|
|
853
849
|
if event_text:
|
854
850
|
completion += event_text
|
855
|
-
|
856
|
-
|
851
|
+
if not silent:
|
852
|
+
sys.stdout.write(Colors().GREEN + event_text)
|
853
|
+
sys.stdout.flush()
|
857
854
|
self.config.streamer(event_text, StreamEventType.TEXT)
|
858
855
|
if event_reasoning:
|
859
856
|
reasoning += event_reasoning
|
860
|
-
|
861
|
-
|
857
|
+
if not silent:
|
858
|
+
sys.stdout.write(Colors().GREEN_DIM + event_reasoning)
|
859
|
+
sys.stdout.flush()
|
862
860
|
self.config.streamer(event_reasoning, StreamEventType.TEXT)
|
863
861
|
if event_fn_name:
|
864
862
|
function_name = event_fn_name
|
865
863
|
has_function = True
|
866
|
-
|
867
|
-
|
864
|
+
if not silent:
|
865
|
+
sys.stdout.write(Colors().GREEN + "FUNC: " + event_fn_name + ": ")
|
866
|
+
sys.stdout.flush()
|
868
867
|
self.config.streamer(event_fn_name, StreamEventType.FUNC_NAME)
|
869
868
|
|
870
869
|
if event_args:
|
871
870
|
function_args += event_args
|
872
|
-
|
873
|
-
|
871
|
+
if not silent:
|
872
|
+
sys.stdout.write(Colors().GREEN + event_args)
|
873
|
+
sys.stdout.flush()
|
874
874
|
self.config.streamer(event_args, StreamEventType.FUNC_ARGS)
|
875
875
|
|
876
876
|
if event_tool_deltas is not None:
|
@@ -878,15 +878,17 @@ class OpenAIGPT(LanguageModel):
|
|
878
878
|
for td in event_tool_deltas:
|
879
879
|
if td["function"]["name"] is not None:
|
880
880
|
tool_fn_name = td["function"]["name"]
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
881
|
+
if not silent:
|
882
|
+
sys.stdout.write(
|
883
|
+
Colors().GREEN + "OAI-TOOL: " + tool_fn_name + ": "
|
884
|
+
)
|
885
|
+
sys.stdout.flush()
|
885
886
|
self.config.streamer(tool_fn_name, StreamEventType.TOOL_NAME)
|
886
887
|
if td["function"]["arguments"] != "":
|
887
888
|
tool_fn_args = td["function"]["arguments"]
|
888
|
-
|
889
|
-
|
889
|
+
if not silent:
|
890
|
+
sys.stdout.write(Colors().GREEN + tool_fn_args)
|
891
|
+
sys.stdout.flush()
|
890
892
|
self.config.streamer(tool_fn_args, StreamEventType.TOOL_ARGS)
|
891
893
|
|
892
894
|
# show this delta in the stream
|
@@ -953,7 +955,7 @@ class OpenAIGPT(LanguageModel):
|
|
953
955
|
event_args = ""
|
954
956
|
event_fn_name = ""
|
955
957
|
event_tool_deltas: Optional[List[Dict[str, Any]]] = None
|
956
|
-
silent = self.config.async_stream_quiet
|
958
|
+
silent = self.config.async_stream_quiet or settings.quiet
|
957
959
|
# The first two events in the stream of Azure OpenAI is useless.
|
958
960
|
# In the 1st: choices list is empty, in the 2nd: the dict delta has null content
|
959
961
|
if chat:
|
@@ -980,46 +982,46 @@ class OpenAIGPT(LanguageModel):
|
|
980
982
|
if not silent:
|
981
983
|
sys.stdout.write(Colors().GREEN + event_text)
|
982
984
|
sys.stdout.flush()
|
983
|
-
|
985
|
+
await self.config.streamer_async(event_text, StreamEventType.TEXT)
|
984
986
|
if event_reasoning:
|
985
987
|
reasoning += event_reasoning
|
986
988
|
if not silent:
|
987
989
|
sys.stdout.write(Colors().GREEN + event_reasoning)
|
988
990
|
sys.stdout.flush()
|
989
|
-
|
991
|
+
await self.config.streamer_async(event_reasoning, StreamEventType.TEXT)
|
990
992
|
if event_fn_name:
|
991
993
|
function_name = event_fn_name
|
992
994
|
has_function = True
|
993
995
|
if not silent:
|
994
996
|
sys.stdout.write(Colors().GREEN + "FUNC: " + event_fn_name + ": ")
|
995
997
|
sys.stdout.flush()
|
996
|
-
|
997
|
-
event_fn_name, StreamEventType.FUNC_NAME
|
998
|
-
)
|
998
|
+
await self.config.streamer_async(event_fn_name, StreamEventType.FUNC_NAME)
|
999
999
|
|
1000
1000
|
if event_args:
|
1001
1001
|
function_args += event_args
|
1002
1002
|
if not silent:
|
1003
1003
|
sys.stdout.write(Colors().GREEN + event_args)
|
1004
1004
|
sys.stdout.flush()
|
1005
|
-
|
1005
|
+
await self.config.streamer_async(event_args, StreamEventType.FUNC_ARGS)
|
1006
1006
|
|
1007
|
-
if event_tool_deltas is not None
|
1007
|
+
if event_tool_deltas is not None:
|
1008
1008
|
# print out streaming tool calls, if not async
|
1009
1009
|
for td in event_tool_deltas:
|
1010
1010
|
if td["function"]["name"] is not None:
|
1011
1011
|
tool_fn_name = td["function"]["name"]
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1012
|
+
if not silent:
|
1013
|
+
sys.stdout.write(
|
1014
|
+
Colors().GREEN + "OAI-TOOL: " + tool_fn_name + ": "
|
1015
|
+
)
|
1016
|
+
sys.stdout.flush()
|
1016
1017
|
await self.config.streamer_async(
|
1017
1018
|
tool_fn_name, StreamEventType.TOOL_NAME
|
1018
1019
|
)
|
1019
1020
|
if td["function"]["arguments"] != "":
|
1020
1021
|
tool_fn_args = td["function"]["arguments"]
|
1021
|
-
|
1022
|
-
|
1022
|
+
if not silent:
|
1023
|
+
sys.stdout.write(Colors().GREEN + tool_fn_args)
|
1024
|
+
sys.stdout.flush()
|
1023
1025
|
await self.config.streamer_async(
|
1024
1026
|
tool_fn_args, StreamEventType.TOOL_ARGS
|
1025
1027
|
)
|
@@ -1103,7 +1105,8 @@ class OpenAIGPT(LanguageModel):
|
|
1103
1105
|
except Exception as e:
|
1104
1106
|
logging.warning("Error while processing stream response: %s", str(e))
|
1105
1107
|
|
1106
|
-
|
1108
|
+
if not settings.quiet:
|
1109
|
+
print("")
|
1107
1110
|
# TODO- get usage info in stream mode (?)
|
1108
1111
|
|
1109
1112
|
return self._create_stream_response(
|
@@ -1178,7 +1181,8 @@ class OpenAIGPT(LanguageModel):
|
|
1178
1181
|
except Exception as e:
|
1179
1182
|
logging.warning("Error while processing stream response: %s", str(e))
|
1180
1183
|
|
1181
|
-
|
1184
|
+
if not settings.quiet:
|
1185
|
+
print("")
|
1182
1186
|
# TODO- get usage info in stream mode (?)
|
1183
1187
|
|
1184
1188
|
return self._create_stream_response(
|
@@ -1300,7 +1304,7 @@ class OpenAIGPT(LanguageModel):
|
|
1300
1304
|
if not isinstance(dict_or_list, dict):
|
1301
1305
|
raise ValueError(
|
1302
1306
|
f"""
|
1303
|
-
Invalid function args: {stripped_fn_args}
|
1307
|
+
Invalid function args: {stripped_fn_args}
|
1304
1308
|
parsed as {dict_or_list},
|
1305
1309
|
which is not a valid dict.
|
1306
1310
|
"""
|
langroid/utils/configuration.py
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
import copy
|
2
1
|
import os
|
2
|
+
import threading
|
3
3
|
from contextlib import contextmanager
|
4
|
-
from typing import Iterator, List, Literal
|
4
|
+
from typing import Any, Dict, Iterator, List, Literal, cast
|
5
5
|
|
6
6
|
from dotenv import find_dotenv, load_dotenv
|
7
7
|
|
8
8
|
from langroid.pydantic_v1 import BaseSettings
|
9
9
|
|
10
|
+
# Global reentrant lock to serialize any modifications to the global settings.
|
11
|
+
_global_lock = threading.RLock()
|
12
|
+
|
10
13
|
|
11
14
|
class Settings(BaseSettings):
|
12
|
-
# NOTE all of these can be overridden in your .env file with upper-case names,
|
13
|
-
# for example CACHE_TYPE=momento
|
14
15
|
debug: bool = False # show debug messages?
|
15
16
|
max_turns: int = -1 # maximum number of turns in a task (to avoid inf loop)
|
16
17
|
progress: bool = False # show progress spinners/bars?
|
@@ -25,74 +26,112 @@ class Settings(BaseSettings):
|
|
25
26
|
extra = "forbid"
|
26
27
|
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
# Load environment variables from .env file.
|
30
|
+
load_dotenv(find_dotenv(usecwd=True))
|
31
|
+
|
32
|
+
# The global (default) settings instance.
|
33
|
+
# This is updated by update_global_settings() and set_global().
|
34
|
+
_global_settings = Settings()
|
35
|
+
|
36
|
+
# Thread-local storage for temporary (per-thread) settings overrides.
|
37
|
+
_thread_local = threading.local()
|
38
|
+
|
39
|
+
|
40
|
+
class SettingsProxy:
|
41
|
+
"""
|
42
|
+
A proxy for the settings that returns a thread‐local override if set,
|
43
|
+
or else falls back to the global settings.
|
44
|
+
"""
|
45
|
+
|
46
|
+
def __getattr__(self, name: str) -> Any:
|
47
|
+
# If the calling thread has set an override, use that.
|
48
|
+
if hasattr(_thread_local, "override"):
|
49
|
+
return getattr(_thread_local.override, name)
|
50
|
+
return getattr(_global_settings, name)
|
51
|
+
|
52
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
53
|
+
# All writes go to the global settings.
|
54
|
+
setattr(_global_settings, name, value)
|
55
|
+
|
56
|
+
def update(self, new_settings: Settings) -> None:
|
57
|
+
_global_settings.__dict__.update(new_settings.__dict__)
|
58
|
+
|
59
|
+
def dict(self) -> Dict[str, Any]:
|
60
|
+
# Return a dict view of the settings as seen by the caller.
|
61
|
+
# Note that temporary overrides are not “merged” with global settings.
|
62
|
+
if hasattr(_thread_local, "override"):
|
63
|
+
return cast(Dict[str, Any], cast(Settings, _thread_local.override.dict()))
|
64
|
+
return _global_settings.dict()
|
65
|
+
|
66
|
+
|
67
|
+
settings = SettingsProxy()
|
30
68
|
|
31
69
|
|
32
70
|
def update_global_settings(cfg: BaseSettings, keys: List[str]) -> None:
|
33
71
|
"""
|
34
|
-
Update global settings so modules can access them via
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
Args:
|
41
|
-
cfg: pydantic config, typically from a main script
|
42
|
-
keys: which keys from cfg to use, to update the global settings object
|
72
|
+
Update global settings so that modules can later access them via, e.g.,
|
73
|
+
|
74
|
+
from langroid.utils.configuration import settings
|
75
|
+
if settings.debug: ...
|
76
|
+
|
77
|
+
This updates the global default.
|
43
78
|
"""
|
44
79
|
config_dict = cfg.dict()
|
45
|
-
|
46
|
-
# Filter the config_dict based on the keys
|
47
80
|
filtered_config = {key: config_dict[key] for key in keys if key in config_dict}
|
48
|
-
|
49
|
-
# create a new Settings() object to let pydantic validate it
|
50
81
|
new_settings = Settings(**filtered_config)
|
51
|
-
|
52
|
-
# Update the unique global settings object
|
53
|
-
settings.__dict__.update(new_settings.__dict__)
|
82
|
+
_global_settings.__dict__.update(new_settings.__dict__)
|
54
83
|
|
55
84
|
|
56
85
|
def set_global(key_vals: Settings) -> None:
|
57
|
-
"""
|
58
|
-
settings.
|
86
|
+
"""
|
87
|
+
Update the global settings object.
|
88
|
+
"""
|
89
|
+
_global_settings.__dict__.update(key_vals.__dict__)
|
59
90
|
|
60
91
|
|
61
92
|
@contextmanager
|
62
93
|
def temporary_settings(temp_settings: Settings) -> Iterator[None]:
|
63
|
-
"""
|
64
|
-
|
65
|
-
|
66
|
-
set_global(temp_settings)
|
94
|
+
"""
|
95
|
+
Temporarily override the settings for the calling thread.
|
67
96
|
|
97
|
+
Within the context, any access to "settings" will use the provided temporary
|
98
|
+
settings. Once the context is exited, the thread reverts to the global settings.
|
99
|
+
"""
|
100
|
+
saved = getattr(_thread_local, "override", None)
|
101
|
+
_thread_local.override = temp_settings
|
68
102
|
try:
|
69
103
|
yield
|
70
104
|
finally:
|
71
|
-
|
105
|
+
if saved is not None:
|
106
|
+
_thread_local.override = saved
|
107
|
+
else:
|
108
|
+
del _thread_local.override
|
72
109
|
|
73
110
|
|
74
111
|
@contextmanager
|
75
112
|
def quiet_mode(quiet: bool = True) -> Iterator[None]:
|
76
|
-
"""
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
113
|
+
"""
|
114
|
+
Temporarily override settings.quiet for the current thread.
|
115
|
+
This implementation builds on the thread‑local temporary_settings context manager.
|
116
|
+
The effective quiet mode is merged:
|
117
|
+
if quiet is already True (from an outer context),
|
118
|
+
then it remains True even if a nested context passes quiet=False.
|
119
|
+
"""
|
120
|
+
current_effective = settings.dict() # get the current thread's effective settings
|
121
|
+
# Create a new settings instance from the current effective state.
|
122
|
+
temp = Settings(**current_effective)
|
123
|
+
# Merge the new flag: once quiet is enabled, it stays enabled.
|
124
|
+
temp.quiet = settings.quiet or quiet
|
125
|
+
with temporary_settings(temp):
|
83
126
|
yield
|
84
|
-
finally:
|
85
|
-
if quiet:
|
86
|
-
settings.__dict__.update(original_settings.__dict__)
|
87
127
|
|
88
128
|
|
89
|
-
def set_env(
|
129
|
+
def set_env(settings_instance: BaseSettings) -> None:
|
90
130
|
"""
|
91
|
-
Set environment variables from a BaseSettings instance
|
92
|
-
|
93
|
-
|
94
|
-
Returns:
|
131
|
+
Set environment variables from a BaseSettings instance.
|
132
|
+
|
133
|
+
Each field in the settings is written to os.environ.
|
95
134
|
"""
|
96
|
-
for field_name, field in
|
135
|
+
for field_name, field in settings_instance.__class__.__fields__.items():
|
97
136
|
env_var_name = field.field_info.extra.get("env", field_name).upper()
|
98
|
-
os.environ[env_var_name] = str(
|
137
|
+
os.environ[env_var_name] = str(settings_instance.dict()[field_name])
|
@@ -73,7 +73,7 @@ langroid/language_models/base.py,sha256=sCDC02hqIgjY73KnCvc-YGxZJm_LAs4Z1VVQpIFW
|
|
73
73
|
langroid/language_models/config.py,sha256=9Q8wk5a7RQr8LGMT_0WkpjY8S4ywK06SalVRjXlfCiI,378
|
74
74
|
langroid/language_models/mock_lm.py,sha256=5BgHKDVRWFbUwDT_PFgTZXz9-k8wJSA2e3PZmyDgQ1k,4022
|
75
75
|
langroid/language_models/model_info.py,sha256=tfBBxL0iUf2mVN6CjcvqflzFUVg2oZqOJZexZ8jHTYA,12216
|
76
|
-
langroid/language_models/openai_gpt.py,sha256=
|
76
|
+
langroid/language_models/openai_gpt.py,sha256=FG3eMWedko0kN-n-SkSbwnrm5hSxoW2wmJSBAvOAOYU,84731
|
77
77
|
langroid/language_models/utils.py,sha256=hC5p61P_Qlrowkm5wMap1A1b5ZUCwK_XhPIzAQk1T1s,5483
|
78
78
|
langroid/language_models/prompt_formatter/__init__.py,sha256=2-5cdE24XoFDhifOLl8yiscohil1ogbP1ECkYdBlBsk,372
|
79
79
|
langroid/language_models/prompt_formatter/base.py,sha256=eDS1sgRNZVnoajwV_ZIha6cba5Dt8xjgzdRbPITwx3Q,1221
|
@@ -104,7 +104,7 @@ langroid/prompts/templates.py,sha256=VV84HVf_amOx6xdWQyIsN9i5dNfrbl8rsfFp6hyfOss
|
|
104
104
|
langroid/pydantic_v1/__init__.py,sha256=HxPGVERapVueRUORgSpj2JX_vTZxVlVbWvhpQlpjygE,283
|
105
105
|
langroid/pydantic_v1/main.py,sha256=p_k7kDY9eDrsA5dxNNqXusKLgx7mS_icGnS7fu4goqY,147
|
106
106
|
langroid/utils/__init__.py,sha256=Sruos2tB4G7Tn0vlblvYlX9PEGR0plI2uE0PJ4d_EC4,353
|
107
|
-
langroid/utils/configuration.py,sha256=
|
107
|
+
langroid/utils/configuration.py,sha256=FJVoseN3mkqx5vzpmtkzCLuQEYlWZEK_11YJ-Ge-L5o,4812
|
108
108
|
langroid/utils/constants.py,sha256=CK09kda9bNDEhnwClq7ZTWZOh38guJlfcZ5hKUS1Ijo,1075
|
109
109
|
langroid/utils/git_utils.py,sha256=WnflJ3R3owhlD0LNdSJakcKhExcEehE1UW5jYVQl8JY,7955
|
110
110
|
langroid/utils/globals.py,sha256=Az9dOFqR6n9CoTYSqa2kLikQWS0oCQ9DFQIQAnG-2q8,1355
|
@@ -129,7 +129,7 @@ langroid/vector_store/pineconedb.py,sha256=otxXZNaBKb9f_H75HTaU3lMHiaR2NUp5MqwLZ
|
|
129
129
|
langroid/vector_store/postgres.py,sha256=wHPtIi2qM4fhO4pMQr95pz1ZCe7dTb2hxl4VYspGZoA,16104
|
130
130
|
langroid/vector_store/qdrantdb.py,sha256=O6dSBoDZ0jzfeVBd7LLvsXu083xs2fxXtPa9gGX3JX4,18443
|
131
131
|
langroid/vector_store/weaviatedb.py,sha256=Yn8pg139gOy3zkaPfoTbMXEEBCiLiYa1MU5d_3UA1K4,11847
|
132
|
-
langroid-0.50.
|
133
|
-
langroid-0.50.
|
134
|
-
langroid-0.50.
|
135
|
-
langroid-0.50.
|
132
|
+
langroid-0.50.12.dist-info/METADATA,sha256=b1vQBIkydfimg9r80ud7w07d7540XJAdhpegeqAPPTw,63642
|
133
|
+
langroid-0.50.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
134
|
+
langroid-0.50.12.dist-info/licenses/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
|
135
|
+
langroid-0.50.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|