inference-proxy 3.2.3__tar.gz → 3.3.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.
Files changed (31) hide show
  1. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/PKG-INFO +38 -30
  2. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/README.md +32 -3
  3. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/bootstrap.py +4 -1
  4. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/config.py +4 -0
  5. inference_proxy-3.3.1/lm_proxy/config_loaders/json.py +11 -0
  6. inference_proxy-3.3.1/lm_proxy/config_loaders/toml.py +11 -0
  7. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/core.py +29 -0
  8. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/pyproject.toml +6 -7
  9. inference_proxy-3.2.3/lm_proxy/config_loaders/json.py +0 -9
  10. inference_proxy-3.2.3/lm_proxy/config_loaders/toml.py +0 -9
  11. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/LICENSE +0 -0
  12. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/__init__.py +0 -0
  13. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/__main__.py +0 -0
  14. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/api_key_check/__init__.py +0 -0
  15. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/api_key_check/allow_all.py +0 -0
  16. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/api_key_check/in_config.py +0 -0
  17. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/api_key_check/with_request.py +0 -0
  18. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/app.py +0 -0
  19. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/base_types.py +0 -0
  20. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/config_loaders/__init__.py +0 -0
  21. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/config_loaders/python.py +0 -0
  22. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/config_loaders/yaml.py +0 -0
  23. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/errors.py +0 -0
  24. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/handlers/__init__.py +0 -0
  25. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/handlers/forward_http_headers.py +0 -0
  26. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/handlers/rate_limiter.py +0 -0
  27. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/loggers.py +0 -0
  28. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/models_endpoint.py +0 -0
  29. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/strategies/__init__.py +0 -0
  30. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/strategies/fallback.py +0 -0
  31. {inference_proxy-3.2.3 → inference_proxy-3.3.1}/lm_proxy/utils.py +0 -0
@@ -1,28 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inference-proxy
3
- Version: 3.2.3
3
+ Version: 3.3.1
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
- License: MIT License
6
-
7
- Copyright (c) 2025–2026 Vitalii Stepanenko
8
-
9
- Permission is hereby granted, free of charge, to any person obtaining a copy
10
- of this software and associated documentation files (the "Software"), to deal
11
- in the Software without restriction, including without limitation the rights
12
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
- copies of the Software, and to permit persons to whom the Software is
14
- furnished to do so, subject to the following conditions:
15
-
16
- The above copyright notice and this permission notice shall be included in all
17
- copies or substantial portions of the Software.
18
-
19
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
- SOFTWARE.
5
+ License-Expression: MIT
26
6
  License-File: LICENSE
27
7
  Keywords: llm,large language models,ai,gpt,openai,proxy,http,proxy-server,llm gateway,openai,anthropic,google genai
28
8
  Author: Vitalii Stepanenko
@@ -36,7 +16,6 @@ Classifier: Programming Language :: Python :: 3
36
16
  Classifier: Programming Language :: Python :: 3.11
37
17
  Classifier: Programming Language :: Python :: 3.12
38
18
  Classifier: Programming Language :: Python :: 3.13
39
- Classifier: License :: OSI Approved :: MIT License
40
19
  Classifier: Operating System :: OS Independent
41
20
  Classifier: Intended Audience :: Developers
42
21
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
@@ -46,16 +25,16 @@ Provides-Extra: all
46
25
  Provides-Extra: anthropic
47
26
  Provides-Extra: google
48
27
  Provides-Extra: test
49
- Requires-Dist: ai-microcore (>=6.2.1,<7)
28
+ Requires-Dist: ai-microcore (>=6.7.1,<7)
50
29
  Requires-Dist: anthropic (>=0.77,<1) ; extra == "all"
51
30
  Requires-Dist: anthropic (>=0.77,<1) ; extra == "anthropic"
52
31
  Requires-Dist: fastapi (>=0.136.3,<1)
53
32
  Requires-Dist: google-genai (>=1.62.0,<2) ; extra == "all"
54
33
  Requires-Dist: google-genai (>=1.62.0,<2) ; extra == "google"
55
34
  Requires-Dist: pydantic (>=2.12.5,<2.13.0)
56
- Requires-Dist: pytest (>=8.4.2,<8.5.0) ; extra == "test"
57
- Requires-Dist: pytest-asyncio (>=1.2.0,<1.3.0) ; extra == "test"
58
- Requires-Dist: pytest-cov (>=7.0.0,<7.1.0) ; extra == "test"
35
+ Requires-Dist: pytest (>=9.1.1,<9.2.0) ; extra == "test"
36
+ Requires-Dist: pytest-asyncio (>=1.4.0,<1.5.0) ; extra == "test"
37
+ Requires-Dist: pytest-cov (>=7.1.0,<7.2.0) ; extra == "test"
59
38
  Requires-Dist: requests (>=2.32.5,<3)
60
39
  Requires-Dist: typer (>=0.24.0,<1)
61
40
  Requires-Dist: uvicorn (>=0.41.0)
@@ -116,6 +95,8 @@ It works as a drop-in replacement for OpenAI's API, allowing you to switch betwe
116
95
  - [Guides & Reference](#-guides--reference)
117
96
  - [Known Limitations](#-known-limitations)
118
97
  - [Debugging](#-debugging)
98
+ - [Debugging Mode](#debugging-mode)
99
+ - [Printing LLM Requests and Responses](#printing-llm-requests-and-responses)
119
100
  - [Contributing](#-contributing)
120
101
  - [License](#-license)
121
102
 
@@ -215,7 +196,7 @@ completion = client.chat.completions.create(
215
196
  ### Run with Docker<a id="run-with-docker"></a>
216
197
 
217
198
  Official images are published to GitHub Container Registry on every release
218
- (`latest`, `3`, `3.2`, `3.2.2`, …; `edge` tracks the `main` branch).
199
+ (`latest`, `3`, `3.3`, `3.3.0`, …; `edge` tracks the `main` branch).
219
200
  They include the Anthropic and Google connectors and YAML config support out of the box.
220
201
 
221
202
  Mount your `config.toml` and provide API keys via an `.env` file:
@@ -255,6 +236,7 @@ Inference Proxy is configured through a TOML/YAML/JSON/Python file that specifie
255
236
  host = "0.0.0.0" # Interface to bind to
256
237
  port = 8000 # Port to listen on
257
238
  dev_autoreload = false # Enable for development
239
+ print_stream = false # Print LLM requests / responses to stdout, see "Debugging"
258
240
 
259
241
  # API key validation function (optional)
260
242
  api_key_check = "lm_proxy.api_key_check.check_api_key_in_config"
@@ -761,7 +743,9 @@ For more detailed information, check out these articles:
761
743
 
762
744
  ## 🔍 Debugging<a id="-debugging"></a>
763
745
 
764
- ### Overview
746
+ ### Debugging Mode<a id="debugging-mode"></a>
747
+
748
+ #### Overview
765
749
  When **debugging mode** is enabled,
766
750
  Inference Proxy provides detailed logging information to help diagnose issues:
767
751
  - Stack traces for exceptions are shown in the console
@@ -770,7 +754,7 @@ Inference Proxy provides detailed logging information to help diagnose issues:
770
754
  > **Warning** ⚠️
771
755
  > Never enable debugging mode in production environments, as it may expose sensitive information to the application logs.
772
756
 
773
- ### Enabling Debugging Mode
757
+ #### Enabling Debugging Mode
774
758
  To enable debugging, set the `LM_PROXY_DEBUG` environment variable to a truthy value (e.g., "1", "true", "yes").
775
759
  > **Tip** 💡
776
760
  > Environment variables can also be defined in a `.env` file.
@@ -782,6 +766,30 @@ Alternatively, you can enable or disable debugging via the command-line argument
782
766
  > **Note** ℹ️
783
767
  > CLI arguments override environment variable settings.
784
768
 
769
+ ### Printing LLM Requests and Responses<a id="printing-llm-requests-and-responses"></a>
770
+
771
+ The `print_stream` configuration option makes Inference Proxy print every LLM request
772
+ and response to stdout, with the response appearing token by token as it is generated:
773
+
774
+ ```toml
775
+ print_stream = true
776
+ ```
777
+
778
+ ```text
779
+ Requesting LLM gpt-5:
780
+ [User]:
781
+ What is the capital of France?
782
+ LLM Response:
783
+ The capital of France is Paris.
784
+ ```
785
+
786
+ This works for both streaming and non-streaming client requests.
787
+
788
+ > **Warning** ⚠️
789
+ > Intended for local development and troubleshooting only.
790
+ > Prompts and generated content are written to the console in plain text,
791
+ > and the output of requests processed in parallel is interleaved.
792
+
785
793
 
786
794
  ## 🤝 Contributing<a id="-contributing"></a>
787
795
 
@@ -50,6 +50,8 @@ It works as a drop-in replacement for OpenAI's API, allowing you to switch betwe
50
50
  - [Guides & Reference](#-guides--reference)
51
51
  - [Known Limitations](#-known-limitations)
52
52
  - [Debugging](#-debugging)
53
+ - [Debugging Mode](#debugging-mode)
54
+ - [Printing LLM Requests and Responses](#printing-llm-requests-and-responses)
53
55
  - [Contributing](#-contributing)
54
56
  - [License](#-license)
55
57
 
@@ -149,7 +151,7 @@ completion = client.chat.completions.create(
149
151
  ### Run with Docker<a id="run-with-docker"></a>
150
152
 
151
153
  Official images are published to GitHub Container Registry on every release
152
- (`latest`, `3`, `3.2`, `3.2.2`, …; `edge` tracks the `main` branch).
154
+ (`latest`, `3`, `3.3`, `3.3.0`, …; `edge` tracks the `main` branch).
153
155
  They include the Anthropic and Google connectors and YAML config support out of the box.
154
156
 
155
157
  Mount your `config.toml` and provide API keys via an `.env` file:
@@ -189,6 +191,7 @@ Inference Proxy is configured through a TOML/YAML/JSON/Python file that specifie
189
191
  host = "0.0.0.0" # Interface to bind to
190
192
  port = 8000 # Port to listen on
191
193
  dev_autoreload = false # Enable for development
194
+ print_stream = false # Print LLM requests / responses to stdout, see "Debugging"
192
195
 
193
196
  # API key validation function (optional)
194
197
  api_key_check = "lm_proxy.api_key_check.check_api_key_in_config"
@@ -695,7 +698,9 @@ For more detailed information, check out these articles:
695
698
 
696
699
  ## 🔍 Debugging<a id="-debugging"></a>
697
700
 
698
- ### Overview
701
+ ### Debugging Mode<a id="debugging-mode"></a>
702
+
703
+ #### Overview
699
704
  When **debugging mode** is enabled,
700
705
  Inference Proxy provides detailed logging information to help diagnose issues:
701
706
  - Stack traces for exceptions are shown in the console
@@ -704,7 +709,7 @@ Inference Proxy provides detailed logging information to help diagnose issues:
704
709
  > **Warning** ⚠️
705
710
  > Never enable debugging mode in production environments, as it may expose sensitive information to the application logs.
706
711
 
707
- ### Enabling Debugging Mode
712
+ #### Enabling Debugging Mode
708
713
  To enable debugging, set the `LM_PROXY_DEBUG` environment variable to a truthy value (e.g., "1", "true", "yes").
709
714
  > **Tip** 💡
710
715
  > Environment variables can also be defined in a `.env` file.
@@ -716,6 +721,30 @@ Alternatively, you can enable or disable debugging via the command-line argument
716
721
  > **Note** ℹ️
717
722
  > CLI arguments override environment variable settings.
718
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
+
719
748
 
720
749
  ## 🤝 Contributing<a id="-contributing"></a>
721
750
 
@@ -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.3"
3
+ version = "3.3.1"
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"]
@@ -11,7 +11,6 @@ classifiers = [
11
11
  "Programming Language :: Python :: 3.11",
12
12
  "Programming Language :: Python :: 3.12",
13
13
  "Programming Language :: Python :: 3.13",
14
- "License :: OSI Approved :: MIT License",
15
14
  "Operating System :: OS Independent",
16
15
  "Intended Audience :: Developers",
17
16
  "Topic :: Software Development :: Libraries :: Application Frameworks",
@@ -32,10 +31,10 @@ maintainers = [
32
31
  homepage = "https://github.com/Nayjest/lm-proxy"
33
32
  repository = "https://github.com/Nayjest/lm-proxy"
34
33
  documentation = "https://github.com/Nayjest/lm-proxy#readme"
35
- license = { file = "LICENSE" }
34
+ license = "MIT"
36
35
 
37
36
  dependencies = [
38
- "ai-microcore>=6.2.1,<7",
37
+ "ai-microcore>=6.7.1,<7",
39
38
  "fastapi>=0.136.3,<1",
40
39
  "uvicorn>=0.41.0",
41
40
  "typer>=0.24.0,<1",
@@ -46,9 +45,9 @@ dependencies = [
46
45
 
47
46
  [project.optional-dependencies]
48
47
  test = [
49
- "pytest~=8.4.2",
50
- "pytest-asyncio~=1.2.0",
51
- "pytest-cov~=7.0.0"
48
+ "pytest~=9.1.1",
49
+ "pytest-asyncio~=1.4.0",
50
+ "pytest-cov~=7.1.0"
52
51
  ]
53
52
  google = [
54
53
  "google-genai>=1.62.0,<2",
@@ -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