inference-proxy 3.2.2__tar.gz → 3.3.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 (31) hide show
  1. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/PKG-INFO +73 -8
  2. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/README.md +68 -4
  3. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/__main__.py +0 -1
  4. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/app.py +0 -1
  5. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/base_types.py +0 -1
  6. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/bootstrap.py +5 -2
  7. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/config.py +4 -0
  8. inference_proxy-3.3.0/lm_proxy/config_loaders/json.py +11 -0
  9. inference_proxy-3.3.0/lm_proxy/config_loaders/toml.py +11 -0
  10. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/core.py +29 -0
  11. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/pyproject.toml +3 -3
  12. inference_proxy-3.2.2/lm_proxy/config_loaders/json.py +0 -9
  13. inference_proxy-3.2.2/lm_proxy/config_loaders/toml.py +0 -9
  14. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/LICENSE +0 -0
  15. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/__init__.py +0 -0
  16. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/api_key_check/__init__.py +0 -0
  17. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/api_key_check/allow_all.py +0 -0
  18. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/api_key_check/in_config.py +0 -0
  19. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/api_key_check/with_request.py +0 -0
  20. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/config_loaders/__init__.py +0 -0
  21. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/config_loaders/python.py +0 -0
  22. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/config_loaders/yaml.py +0 -0
  23. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/errors.py +0 -0
  24. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/handlers/__init__.py +0 -0
  25. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/handlers/forward_http_headers.py +0 -0
  26. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/handlers/rate_limiter.py +0 -0
  27. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/loggers.py +0 -0
  28. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/models_endpoint.py +0 -0
  29. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/strategies/__init__.py +0 -0
  30. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/strategies/fallback.py +0 -0
  31. {inference_proxy-3.2.2 → inference_proxy-3.3.0}/lm_proxy/utils.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: inference-proxy
3
- Version: 3.2.2
3
+ Version: 3.3.0
4
4
  Summary: Inference Proxy is an OpenAI-compatible http proxy server for inferencing various LLMs capable of working with Google, Anthropic, OpenAI APIs, local PyTorch inference, etc.
5
5
  License: MIT License
6
6
 
@@ -23,6 +23,7 @@ License: MIT License
23
23
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
24
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
25
  SOFTWARE.
26
+ License-File: LICENSE
26
27
  Keywords: llm,large language models,ai,gpt,openai,proxy,http,proxy-server,llm gateway,openai,anthropic,google genai
27
28
  Author: Vitalii Stepanenko
28
29
  Author-email: mail@vitaliy.in
@@ -45,10 +46,10 @@ Provides-Extra: all
45
46
  Provides-Extra: anthropic
46
47
  Provides-Extra: google
47
48
  Provides-Extra: test
48
- Requires-Dist: ai-microcore (>=5.1.2,<7)
49
+ Requires-Dist: ai-microcore (>=6.6.1,<7)
49
50
  Requires-Dist: anthropic (>=0.77,<1) ; extra == "all"
50
51
  Requires-Dist: anthropic (>=0.77,<1) ; extra == "anthropic"
51
- Requires-Dist: fastapi (>=0.121.3,<1)
52
+ Requires-Dist: fastapi (>=0.136.3,<1)
52
53
  Requires-Dist: google-genai (>=1.62.0,<2) ; extra == "all"
53
54
  Requires-Dist: google-genai (>=1.62.0,<2) ; extra == "google"
54
55
  Requires-Dist: pydantic (>=2.12.5,<2.13.0)
@@ -71,7 +72,7 @@ Description-Content-Type: text/markdown
71
72
  <a href="https://pypi.org/project/lm-proxy/"><img src="https://img.shields.io/pypi/v/lm-proxy?color=blue" alt="PyPI"></a>
72
73
  <a href="https://github.com/Nayjest/lm-proxy/actions/workflows/tests.yml"><img src="https://github.com/Nayjest/lm-proxy/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
73
74
  <a href="https://github.com/Nayjest/lm-proxy/actions/workflows/code-style.yml"><img src="https://github.com/Nayjest/lm-proxy/actions/workflows/code-style.yml/badge.svg" alt="Code Style"></a>
74
- <img src="https://raw.githubusercontent.com/Nayjest/lm-proxy/main/coverage.svg" alt="Code Coverage">
75
+ <img src="https://raw.githubusercontent.com/Nayjest/lm-proxy/coverage-badge/coverage.svg" alt="Code Coverage">
75
76
  <a href="https://www.bestpractices.dev/projects/11364"><img src="https://www.bestpractices.dev/projects/11364/badge"></a>
76
77
  <br>
77
78
  <a href="https://github.com/vshymanskyy/StandWithUkraine/blob/main/README.md"><img src="https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/refs/heads/main/badges/StandWithUkraine.svg" alt="Stand With Ukraine"></a>
@@ -91,6 +92,7 @@ It works as a drop-in replacement for OpenAI's API, allowing you to switch betwe
91
92
  - [Getting Started](#-getting-started)
92
93
  - [Installation](#installation)
93
94
  - [Quick Start](#quick-start)
95
+ - [Run with Docker](#run-with-docker)
94
96
  - [Configuration](#-configuration)
95
97
  - [Basic Structure](#basic-structure)
96
98
  - [Environment Variables](#environment-variables)
@@ -114,6 +116,8 @@ It works as a drop-in replacement for OpenAI's API, allowing you to switch betwe
114
116
  - [Guides & Reference](#-guides--reference)
115
117
  - [Known Limitations](#-known-limitations)
116
118
  - [Debugging](#-debugging)
119
+ - [Debugging Mode](#debugging-mode)
120
+ - [Printing LLM Requests and Responses](#printing-llm-requests-and-responses)
117
121
  - [Contributing](#-contributing)
118
122
  - [License](#-license)
119
123
 
@@ -210,6 +214,39 @@ completion = client.chat.completions.create(
210
214
  )
211
215
  ```
212
216
 
217
+ ### Run with Docker<a id="run-with-docker"></a>
218
+
219
+ Official images are published to GitHub Container Registry on every release
220
+ (`latest`, `3`, `3.2`, `3.2.2`, …; `edge` tracks the `main` branch).
221
+ They include the Anthropic and Google connectors and YAML config support out of the box.
222
+
223
+ Mount your `config.toml` and provide API keys via an `.env` file:
224
+
225
+ ```bash
226
+ docker run -d --name inference-proxy \
227
+ -p 8000:8000 \
228
+ -v ./config.toml:/app/config.toml:ro \
229
+ --env-file .env \
230
+ lmproxy/lmproxy:edge
231
+ ```
232
+
233
+ Any value referenced in the config as `env:<VAR_NAME>` (upstream provider keys,
234
+ client API keys, etc.) can be defined in the `.env` file:
235
+
236
+ ```ini
237
+ OPENAI_API_KEY=sk-...
238
+ ANTHROPIC_API_KEY=sk-ant-...
239
+ ```
240
+
241
+ See [examples/docker-compose.yml](examples/docker-compose.yml) for a Docker Compose setup.
242
+
243
+ To bake additional Python packages into the image (e.g. for
244
+ [database log storage](#database-connector)), build it with the `EXTRA_PIP_PACKAGES` argument:
245
+
246
+ ```bash
247
+ docker build --build-arg EXTRA_PIP_PACKAGES="inference-proxy-db-connector sqlalchemy psycopg2-binary" -t inference-proxy .
248
+ ```
249
+
213
250
 
214
251
  ## 📝 Configuration<a id="-configuration"></a>
215
252
 
@@ -220,6 +257,7 @@ Inference Proxy is configured through a TOML/YAML/JSON/Python file that specifie
220
257
  host = "0.0.0.0" # Interface to bind to
221
258
  port = 8000 # Port to listen on
222
259
  dev_autoreload = false # Enable for development
260
+ print_stream = false # Print LLM requests / responses to stdout, see "Debugging"
223
261
 
224
262
  # API key validation function (optional)
225
263
  api_key_check = "lm_proxy.api_key_check.check_api_key_in_config"
@@ -258,7 +296,7 @@ api_keys = [
258
296
  [[loggers]]
259
297
  class = 'lm_proxy.loggers.BaseLogger'
260
298
  [loggers.log_writer]
261
- class = 'lm_proxy.loggers.log_writers.JsonLogWriter'
299
+ class = 'lm_proxy.loggers.JsonLogWriter'
262
300
  file_name = 'storage/json.log'
263
301
  [loggers.entry_transformer]
264
302
  class = 'lm_proxy.loggers.LogEntryTransformer'
@@ -714,6 +752,7 @@ prefix = "SECURITY_AUDIT"
714
752
  For more detailed information, check out these articles:
715
753
  - [HTTP Header Management](https://github.com/Nayjest/lm-proxy/blob/main/doc/http_headers.md)
716
754
  - [Configuring fallbacks](https://github.com/Nayjest/lm-proxy/blob/main/doc/fallback.md)
755
+ - [HTTPS / TLS Setup](https://github.com/Nayjest/lm-proxy/blob/main/doc/https.md)
717
756
 
718
757
 
719
758
  ## 🚧 Known Limitations<a id="-known-limitations"></a>
@@ -725,7 +764,9 @@ For more detailed information, check out these articles:
725
764
 
726
765
  ## 🔍 Debugging<a id="-debugging"></a>
727
766
 
728
- ### Overview
767
+ ### Debugging Mode<a id="debugging-mode"></a>
768
+
769
+ #### Overview
729
770
  When **debugging mode** is enabled,
730
771
  Inference Proxy provides detailed logging information to help diagnose issues:
731
772
  - Stack traces for exceptions are shown in the console
@@ -734,7 +775,7 @@ Inference Proxy provides detailed logging information to help diagnose issues:
734
775
  > **Warning** ⚠️
735
776
  > Never enable debugging mode in production environments, as it may expose sensitive information to the application logs.
736
777
 
737
- ### Enabling Debugging Mode
778
+ #### Enabling Debugging Mode
738
779
  To enable debugging, set the `LM_PROXY_DEBUG` environment variable to a truthy value (e.g., "1", "true", "yes").
739
780
  > **Tip** 💡
740
781
  > Environment variables can also be defined in a `.env` file.
@@ -746,6 +787,30 @@ Alternatively, you can enable or disable debugging via the command-line argument
746
787
  > **Note** ℹ️
747
788
  > CLI arguments override environment variable settings.
748
789
 
790
+ ### Printing LLM Requests and Responses<a id="printing-llm-requests-and-responses"></a>
791
+
792
+ The `print_stream` configuration option makes Inference Proxy print every LLM request
793
+ and response to stdout, with the response appearing token by token as it is generated:
794
+
795
+ ```toml
796
+ print_stream = true
797
+ ```
798
+
799
+ ```text
800
+ Requesting LLM gpt-5:
801
+ [User]:
802
+ What is the capital of France?
803
+ LLM Response:
804
+ The capital of France is Paris.
805
+ ```
806
+
807
+ This works for both streaming and non-streaming client requests.
808
+
809
+ > **Warning** ⚠️
810
+ > Intended for local development and troubleshooting only.
811
+ > Prompts and generated content are written to the console in plain text,
812
+ > and the output of requests processed in parallel is interleaved.
813
+
749
814
 
750
815
  ## 🤝 Contributing<a id="-contributing"></a>
751
816
 
@@ -6,7 +6,7 @@
6
6
  <a href="https://pypi.org/project/lm-proxy/"><img src="https://img.shields.io/pypi/v/lm-proxy?color=blue" alt="PyPI"></a>
7
7
  <a href="https://github.com/Nayjest/lm-proxy/actions/workflows/tests.yml"><img src="https://github.com/Nayjest/lm-proxy/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
8
8
  <a href="https://github.com/Nayjest/lm-proxy/actions/workflows/code-style.yml"><img src="https://github.com/Nayjest/lm-proxy/actions/workflows/code-style.yml/badge.svg" alt="Code Style"></a>
9
- <img src="https://raw.githubusercontent.com/Nayjest/lm-proxy/main/coverage.svg" alt="Code Coverage">
9
+ <img src="https://raw.githubusercontent.com/Nayjest/lm-proxy/coverage-badge/coverage.svg" alt="Code Coverage">
10
10
  <a href="https://www.bestpractices.dev/projects/11364"><img src="https://www.bestpractices.dev/projects/11364/badge"></a>
11
11
  <br>
12
12
  <a href="https://github.com/vshymanskyy/StandWithUkraine/blob/main/README.md"><img src="https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/refs/heads/main/badges/StandWithUkraine.svg" alt="Stand With Ukraine"></a>
@@ -26,6 +26,7 @@ It works as a drop-in replacement for OpenAI's API, allowing you to switch betwe
26
26
  - [Getting Started](#-getting-started)
27
27
  - [Installation](#installation)
28
28
  - [Quick Start](#quick-start)
29
+ - [Run with Docker](#run-with-docker)
29
30
  - [Configuration](#-configuration)
30
31
  - [Basic Structure](#basic-structure)
31
32
  - [Environment Variables](#environment-variables)
@@ -49,6 +50,8 @@ It works as a drop-in replacement for OpenAI's API, allowing you to switch betwe
49
50
  - [Guides & Reference](#-guides--reference)
50
51
  - [Known Limitations](#-known-limitations)
51
52
  - [Debugging](#-debugging)
53
+ - [Debugging Mode](#debugging-mode)
54
+ - [Printing LLM Requests and Responses](#printing-llm-requests-and-responses)
52
55
  - [Contributing](#-contributing)
53
56
  - [License](#-license)
54
57
 
@@ -145,6 +148,39 @@ completion = client.chat.completions.create(
145
148
  )
146
149
  ```
147
150
 
151
+ ### Run with Docker<a id="run-with-docker"></a>
152
+
153
+ Official images are published to GitHub Container Registry on every release
154
+ (`latest`, `3`, `3.2`, `3.2.2`, …; `edge` tracks the `main` branch).
155
+ They include the Anthropic and Google connectors and YAML config support out of the box.
156
+
157
+ Mount your `config.toml` and provide API keys via an `.env` file:
158
+
159
+ ```bash
160
+ docker run -d --name inference-proxy \
161
+ -p 8000:8000 \
162
+ -v ./config.toml:/app/config.toml:ro \
163
+ --env-file .env \
164
+ lmproxy/lmproxy:edge
165
+ ```
166
+
167
+ Any value referenced in the config as `env:<VAR_NAME>` (upstream provider keys,
168
+ client API keys, etc.) can be defined in the `.env` file:
169
+
170
+ ```ini
171
+ OPENAI_API_KEY=sk-...
172
+ ANTHROPIC_API_KEY=sk-ant-...
173
+ ```
174
+
175
+ See [examples/docker-compose.yml](examples/docker-compose.yml) for a Docker Compose setup.
176
+
177
+ To bake additional Python packages into the image (e.g. for
178
+ [database log storage](#database-connector)), build it with the `EXTRA_PIP_PACKAGES` argument:
179
+
180
+ ```bash
181
+ docker build --build-arg EXTRA_PIP_PACKAGES="inference-proxy-db-connector sqlalchemy psycopg2-binary" -t inference-proxy .
182
+ ```
183
+
148
184
 
149
185
  ## 📝 Configuration<a id="-configuration"></a>
150
186
 
@@ -155,6 +191,7 @@ Inference Proxy is configured through a TOML/YAML/JSON/Python file that specifie
155
191
  host = "0.0.0.0" # Interface to bind to
156
192
  port = 8000 # Port to listen on
157
193
  dev_autoreload = false # Enable for development
194
+ print_stream = false # Print LLM requests / responses to stdout, see "Debugging"
158
195
 
159
196
  # API key validation function (optional)
160
197
  api_key_check = "lm_proxy.api_key_check.check_api_key_in_config"
@@ -193,7 +230,7 @@ api_keys = [
193
230
  [[loggers]]
194
231
  class = 'lm_proxy.loggers.BaseLogger'
195
232
  [loggers.log_writer]
196
- class = 'lm_proxy.loggers.log_writers.JsonLogWriter'
233
+ class = 'lm_proxy.loggers.JsonLogWriter'
197
234
  file_name = 'storage/json.log'
198
235
  [loggers.entry_transformer]
199
236
  class = 'lm_proxy.loggers.LogEntryTransformer'
@@ -649,6 +686,7 @@ prefix = "SECURITY_AUDIT"
649
686
  For more detailed information, check out these articles:
650
687
  - [HTTP Header Management](https://github.com/Nayjest/lm-proxy/blob/main/doc/http_headers.md)
651
688
  - [Configuring fallbacks](https://github.com/Nayjest/lm-proxy/blob/main/doc/fallback.md)
689
+ - [HTTPS / TLS Setup](https://github.com/Nayjest/lm-proxy/blob/main/doc/https.md)
652
690
 
653
691
 
654
692
  ## 🚧 Known Limitations<a id="-known-limitations"></a>
@@ -660,7 +698,9 @@ For more detailed information, check out these articles:
660
698
 
661
699
  ## 🔍 Debugging<a id="-debugging"></a>
662
700
 
663
- ### Overview
701
+ ### Debugging Mode<a id="debugging-mode"></a>
702
+
703
+ #### Overview
664
704
  When **debugging mode** is enabled,
665
705
  Inference Proxy provides detailed logging information to help diagnose issues:
666
706
  - Stack traces for exceptions are shown in the console
@@ -669,7 +709,7 @@ Inference Proxy provides detailed logging information to help diagnose issues:
669
709
  > **Warning** ⚠️
670
710
  > Never enable debugging mode in production environments, as it may expose sensitive information to the application logs.
671
711
 
672
- ### Enabling Debugging Mode
712
+ #### Enabling Debugging Mode
673
713
  To enable debugging, set the `LM_PROXY_DEBUG` environment variable to a truthy value (e.g., "1", "true", "yes").
674
714
  > **Tip** 💡
675
715
  > Environment variables can also be defined in a `.env` file.
@@ -681,6 +721,30 @@ Alternatively, you can enable or disable debugging via the command-line argument
681
721
  > **Note** ℹ️
682
722
  > CLI arguments override environment variable settings.
683
723
 
724
+ ### Printing LLM Requests and Responses<a id="printing-llm-requests-and-responses"></a>
725
+
726
+ The `print_stream` configuration option makes Inference Proxy print every LLM request
727
+ and response to stdout, with the response appearing token by token as it is generated:
728
+
729
+ ```toml
730
+ print_stream = true
731
+ ```
732
+
733
+ ```text
734
+ Requesting LLM gpt-5:
735
+ [User]:
736
+ What is the capital of France?
737
+ LLM Response:
738
+ The capital of France is Paris.
739
+ ```
740
+
741
+ This works for both streaming and non-streaming client requests.
742
+
743
+ > **Warning** ⚠️
744
+ > Intended for local development and troubleshooting only.
745
+ > Prompts and generated content are written to the console in plain text,
746
+ > and the output of requests processed in parallel is interleaved.
747
+
684
748
 
685
749
  ## 🤝 Contributing<a id="-contributing"></a>
686
750
 
@@ -2,6 +2,5 @@
2
2
 
3
3
  from .app import cli_app
4
4
 
5
-
6
5
  if __name__ == "__main__":
7
6
  cli_app()
@@ -13,7 +13,6 @@ from .core import chat_completions
13
13
  from .models_endpoint import models
14
14
  from .errors import OpenAIHTTPException
15
15
 
16
-
17
16
  cli_app = typer.Typer()
18
17
 
19
18
 
@@ -9,7 +9,6 @@ import microcore as mc
9
9
  from pydantic import BaseModel
10
10
  from starlette.requests import Request
11
11
 
12
-
13
12
  if TYPE_CHECKING:
14
13
  from .config import Group
15
14
 
@@ -84,7 +84,7 @@ class Env:
84
84
  # initialize connections
85
85
  env.connections = {}
86
86
  for conn_name, conn_config in env.config.connections.items():
87
- logging.info("Initializing \"%s\" LLM proxy connection...", ui.green(conn_name))
87
+ logging.info("Initializing '%s' LLM proxy connection...", ui.green(conn_name))
88
88
  try:
89
89
  fn_or_config = resolve_instance_or_callable(conn_config, allow_types=[dict])
90
90
  if _is_async_callable(fn_or_config):
@@ -94,7 +94,10 @@ class Env:
94
94
  env.connections[conn_name] = mc.env().llm_async_function
95
95
  except mc.LLMConfigError as e:
96
96
  raise ValueError(f"Error in configuration for connection '{conn_name}': {e}") from e
97
-
97
+ if config.print_stream:
98
+ mc.use_logging(stream=True)
99
+ # Proxied prompts are printed in full, without "...(output was truncated)..."
100
+ mc.logging.LoggingConfig.STRIP_REQUEST_LINES = None
98
101
  logging.info("Done initializing %d connections.", len(env.connections))
99
102
 
100
103
 
@@ -90,6 +90,10 @@ class Config(BaseModel):
90
90
  )
91
91
  components: dict[str, Union[str, Callable, dict]] = Field(default_factory=dict)
92
92
  before: list[Union[str, Callable, dict]] = Field(default_factory=list)
93
+ print_stream: bool = Field(
94
+ default=False,
95
+ description="Prints LLM requests / responses to stdout"
96
+ )
93
97
 
94
98
  def __init__(self, **data):
95
99
  super().__init__(**data)
@@ -0,0 +1,11 @@
1
+ """JSON configuration loader."""
2
+
3
+ import json
4
+
5
+
6
+ def load_json_config(config_path: str) -> dict:
7
+ """Loads configuration from a JSON file."""
8
+ # utf-8-sig skips the byte order mark that Windows text editors may add,
9
+ # the JSON parser rejects it
10
+ with open(config_path, "r", encoding="utf-8-sig") as f:
11
+ return json.load(f)
@@ -0,0 +1,11 @@
1
+ """TOML configuration loader."""
2
+
3
+ import tomllib
4
+
5
+
6
+ def load_toml_config(config_path: str) -> dict:
7
+ """Loads configuration from a TOML file."""
8
+ # utf-8-sig skips the byte order mark that Windows text editors may add,
9
+ # tomllib rejects it
10
+ with open(config_path, "r", encoding="utf-8-sig") as f:
11
+ return tomllib.loads(f.read())
@@ -11,6 +11,7 @@ import inspect
11
11
  from datetime import datetime
12
12
  from typing import Optional
13
13
 
14
+ import microcore as mc
14
15
  from fastapi import HTTPException
15
16
  from openai.types.chat.chat_completion import Choice
16
17
  from starlette.requests import Request
@@ -65,6 +66,30 @@ def resolve_connection_and_model(config: Config, external_model: str) -> tuple[s
65
66
  )
66
67
 
67
68
 
69
+ def print_llm_request(ctx: RequestContext):
70
+ """
71
+ Prints the LLM request to stdout when the `print_stream` option is enabled.
72
+
73
+ LM-Proxy queries the LLM API function directly instead of using microcore.allm(),
74
+ so microcore request / response handlers are triggered explicitly.
75
+ """
76
+ if env.config.print_stream:
77
+ for handler in mc.env().llm_before_handlers:
78
+ handler(ctx.request.messages, **ctx.llm_params)
79
+
80
+
81
+ def finish_printing_llm_response(ctx: RequestContext):
82
+ """
83
+ Completes printing of the LLM response to stdout, in particular terminates
84
+ the line of the streamed output, when the `print_stream` option is enabled.
85
+
86
+ See print_llm_request().
87
+ """
88
+ if env.config.print_stream:
89
+ for handler in mc.env().llm_after_handlers:
90
+ handler(ctx.response)
91
+
92
+
68
93
  async def process_stream(
69
94
  async_llm_func,
70
95
  request: ChatCompletionRequest,
@@ -121,6 +146,7 @@ async def process_stream(
121
146
  except Exception as e:
122
147
  ctx.error = e
123
148
  yield make_chunk(error={"message": str(e), "type": type(e).__name__})
149
+ finish_printing_llm_response(ctx)
124
150
 
125
151
  yield make_chunk(finish_reason="error" if ctx.error else "stop")
126
152
  yield "data: [DONE]\n\n"
@@ -252,6 +278,7 @@ async def chat_completions(request: ChatCompletionRequest, raw_request: Request)
252
278
  async_llm_func = env.connections[connection]
253
279
 
254
280
  logging.info("Querying LLM... params: %s", ctx.llm_params)
281
+ print_llm_request(ctx)
255
282
  if request.stream:
256
283
  return StreamingResponse(
257
284
  process_stream(async_llm_func, request, ctx),
@@ -261,9 +288,11 @@ async def chat_completions(request: ChatCompletionRequest, raw_request: Request)
261
288
  try:
262
289
  out = await async_llm_func(request.messages, **ctx.llm_params)
263
290
  ctx.response = out
291
+ finish_printing_llm_response(ctx)
264
292
  logging.info("LLM response: %s", out)
265
293
  except Exception as e:
266
294
  ctx.error = e
295
+ finish_printing_llm_response(ctx)
267
296
  await log_non_blocking(ctx)
268
297
  error_details = f" [{type(e).__name__}]: {e}" if env.debug else ""
269
298
  logging.exception(e)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "inference-proxy"
3
- version = "3.2.2"
3
+ version = "3.3.0"
4
4
  description = "Inference Proxy is an OpenAI-compatible http proxy server for inferencing various LLMs capable of working with Google, Anthropic, OpenAI APIs, local PyTorch inference, etc."
5
5
  readme = "README.md"
6
6
  keywords = ["llm", "large language models", "ai", "gpt", "openai", "proxy", "http", "proxy-server", "llm gateway", "openai", "anthropic", "google genai"]
@@ -35,8 +35,8 @@ documentation = "https://github.com/Nayjest/lm-proxy#readme"
35
35
  license = { file = "LICENSE" }
36
36
 
37
37
  dependencies = [
38
- "ai-microcore>=5.1.2,<7",
39
- "fastapi>=0.121.3,<1",
38
+ "ai-microcore>=6.6.1,<7",
39
+ "fastapi>=0.136.3,<1",
40
40
  "uvicorn>=0.41.0",
41
41
  "typer>=0.24.0,<1",
42
42
  "requests>=2.32.5,<3",
@@ -1,9 +0,0 @@
1
- """JSON configuration loader."""
2
-
3
- import json
4
-
5
-
6
- def load_json_config(config_path: str) -> dict:
7
- """Loads configuration from a JSON file."""
8
- with open(config_path, "r", encoding="utf-8") as f:
9
- return json.load(f)
@@ -1,9 +0,0 @@
1
- """TOML configuration loader."""
2
-
3
- import tomllib
4
-
5
-
6
- def load_toml_config(config_path: str) -> dict:
7
- """Loads configuration from a TOML file."""
8
- with open(config_path, "rb") as f:
9
- return tomllib.load(f)
File without changes