llmshim 0.3.3__tar.gz → 0.3.4__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 (116) hide show
  1. {llmshim-0.3.3 → llmshim-0.3.4}/CLAUDE.md +1 -1
  2. {llmshim-0.3.3 → llmshim-0.3.4}/Cargo.lock +1 -1
  3. {llmshim-0.3.3 → llmshim-0.3.4}/Cargo.toml +1 -1
  4. {llmshim-0.3.3 → llmshim-0.3.4}/PKG-INFO +81 -5
  5. {llmshim-0.3.3 → llmshim-0.3.4}/README.md +1 -1
  6. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/guides/reasoning.md +1 -1
  7. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/models.md +2 -1
  8. {llmshim-0.3.3 → llmshim-0.3.4}/llmshim/__init__.py +6 -1
  9. {llmshim-0.3.3 → llmshim-0.3.4}/llmshim/_client.py +18 -0
  10. {llmshim-0.3.3 → llmshim-0.3.4}/src/main.rs +1 -0
  11. {llmshim-0.3.3 → llmshim-0.3.4}/src/models.rs +9 -0
  12. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_gemini.rs +20 -0
  13. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_gemini.rs +1 -0
  14. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_models.rs +1 -1
  15. {llmshim-0.3.3 → llmshim-0.3.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  16. {llmshim-0.3.3 → llmshim-0.3.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  17. {llmshim-0.3.3 → llmshim-0.3.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  18. {llmshim-0.3.3 → llmshim-0.3.4}/.github/workflows/pages.yml +0 -0
  19. {llmshim-0.3.3 → llmshim-0.3.4}/.github/workflows/release.yml +0 -0
  20. {llmshim-0.3.3 → llmshim-0.3.4}/.gitignore +0 -0
  21. {llmshim-0.3.3 → llmshim-0.3.4}/CODE_OF_CONDUCT.md +0 -0
  22. {llmshim-0.3.3 → llmshim-0.3.4}/CONTRIBUTING.md +0 -0
  23. {llmshim-0.3.3 → llmshim-0.3.4}/LICENSE-APACHE +0 -0
  24. {llmshim-0.3.3 → llmshim-0.3.4}/LICENSE-MIT +0 -0
  25. {llmshim-0.3.3 → llmshim-0.3.4}/NOTICE +0 -0
  26. {llmshim-0.3.3 → llmshim-0.3.4}/SECURITY.md +0 -0
  27. {llmshim-0.3.3 → llmshim-0.3.4}/benchmarks/bench.rs +0 -0
  28. {llmshim-0.3.3 → llmshim-0.3.4}/benchmarks/bench_python.py +0 -0
  29. {llmshim-0.3.3 → llmshim-0.3.4}/benchmarks/loadtest.rs +0 -0
  30. {llmshim-0.3.3 → llmshim-0.3.4}/docs/.gitignore +0 -0
  31. {llmshim-0.3.3 → llmshim-0.3.4}/docs/book.toml +0 -0
  32. {llmshim-0.3.3 → llmshim-0.3.4}/docs/mermaid-init.js +0 -0
  33. {llmshim-0.3.3 → llmshim-0.3.4}/docs/mermaid.min.js +0 -0
  34. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/SUMMARY.md +0 -0
  35. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/concepts/contracts.md +0 -0
  36. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/concepts/conversations.md +0 -0
  37. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/concepts/portability.md +0 -0
  38. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/concepts/routing.md +0 -0
  39. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/concepts/translation-flow.md +0 -0
  40. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/guides/fallbacks.md +0 -0
  41. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/guides/images.md +0 -0
  42. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/guides/native-controls.md +0 -0
  43. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/guides/streaming.md +0 -0
  44. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/guides/tools.md +0 -0
  45. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/introduction.md +0 -0
  46. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/proxy/deployment.md +0 -0
  47. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/proxy/http-api.md +0 -0
  48. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/proxy/scaling.md +0 -0
  49. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/api.md +0 -0
  50. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/cli.md +0 -0
  51. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/configuration.md +0 -0
  52. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/errors.md +0 -0
  53. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/providers.md +0 -0
  54. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/request-fields.md +0 -0
  55. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/reference/surfaces.md +0 -0
  56. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/start/choose.md +0 -0
  57. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/start/cli.md +0 -0
  58. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/start/clients.md +0 -0
  59. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/start/configure.md +0 -0
  60. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/start/proxy.md +0 -0
  61. {llmshim-0.3.3 → llmshim-0.3.4}/docs/src/start/rust.md +0 -0
  62. {llmshim-0.3.3 → llmshim-0.3.4}/examples/chat.rs +0 -0
  63. {llmshim-0.3.3 → llmshim-0.3.4}/examples/stream.rs +0 -0
  64. {llmshim-0.3.3 → llmshim-0.3.4}/llmshim/_server.py +0 -0
  65. {llmshim-0.3.3 → llmshim-0.3.4}/llmshim/types.py +0 -0
  66. {llmshim-0.3.3 → llmshim-0.3.4}/pyproject.toml +0 -0
  67. {llmshim-0.3.3 → llmshim-0.3.4}/src/client.rs +0 -0
  68. {llmshim-0.3.3 → llmshim-0.3.4}/src/config.rs +0 -0
  69. {llmshim-0.3.3 → llmshim-0.3.4}/src/env.rs +0 -0
  70. {llmshim-0.3.3 → llmshim-0.3.4}/src/error.rs +0 -0
  71. {llmshim-0.3.3 → llmshim-0.3.4}/src/fallback.rs +0 -0
  72. {llmshim-0.3.3 → llmshim-0.3.4}/src/lib.rs +0 -0
  73. {llmshim-0.3.3 → llmshim-0.3.4}/src/log.rs +0 -0
  74. {llmshim-0.3.3 → llmshim-0.3.4}/src/provider.rs +0 -0
  75. {llmshim-0.3.3 → llmshim-0.3.4}/src/providers/anthropic.rs +0 -0
  76. {llmshim-0.3.3 → llmshim-0.3.4}/src/providers/gemini.rs +0 -0
  77. {llmshim-0.3.3 → llmshim-0.3.4}/src/providers/mod.rs +0 -0
  78. {llmshim-0.3.3 → llmshim-0.3.4}/src/providers/openai.rs +0 -0
  79. {llmshim-0.3.3 → llmshim-0.3.4}/src/providers/openai_compat.rs +0 -0
  80. {llmshim-0.3.3 → llmshim-0.3.4}/src/providers/openrouter.rs +0 -0
  81. {llmshim-0.3.3 → llmshim-0.3.4}/src/providers/xai.rs +0 -0
  82. {llmshim-0.3.3 → llmshim-0.3.4}/src/proxy/convert.rs +0 -0
  83. {llmshim-0.3.3 → llmshim-0.3.4}/src/proxy/error.rs +0 -0
  84. {llmshim-0.3.3 → llmshim-0.3.4}/src/proxy/handlers.rs +0 -0
  85. {llmshim-0.3.3 → llmshim-0.3.4}/src/proxy/mod.rs +0 -0
  86. {llmshim-0.3.3 → llmshim-0.3.4}/src/proxy/ratelimit.rs +0 -0
  87. {llmshim-0.3.3 → llmshim-0.3.4}/src/proxy/types.rs +0 -0
  88. {llmshim-0.3.3 → llmshim-0.3.4}/src/router.rs +0 -0
  89. {llmshim-0.3.3 → llmshim-0.3.4}/src/vision.rs +0 -0
  90. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration.rs +0 -0
  91. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_fallback.rs +0 -0
  92. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_gemini_tools.rs +0 -0
  93. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_long_context.rs +0 -0
  94. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_multimodel.rs +0 -0
  95. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_openrouter.rs +0 -0
  96. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_proxy.rs +0 -0
  97. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_sglang.rs +0 -0
  98. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_thinking.rs +0 -0
  99. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_tool_roundtrip.rs +0 -0
  100. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_vision.rs +0 -0
  101. {llmshim-0.3.3 → llmshim-0.3.4}/tests/integration_xai.rs +0 -0
  102. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_anthropic.rs +0 -0
  103. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_fallback.rs +0 -0
  104. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_fast_mode.rs +0 -0
  105. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_log.rs +0 -0
  106. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_multimodel.rs +0 -0
  107. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_openai.rs +0 -0
  108. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_openai_compat.rs +0 -0
  109. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_openrouter.rs +0 -0
  110. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_proxy.rs +0 -0
  111. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_proxy_convert.rs +0 -0
  112. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_router.rs +0 -0
  113. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_sse.rs +0 -0
  114. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_tools.rs +0 -0
  115. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_vision.rs +0 -0
  116. {llmshim-0.3.3 → llmshim-0.3.4}/tests/unit_xai.rs +0 -0
@@ -14,7 +14,7 @@ This is a public crate on crates.io. Do NOT make breaking changes to `pub` items
14
14
 
15
15
  - **OpenAI:** `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`, `gpt-5.5-pro`, `gpt-5.4`, `gpt-5.4-pro`, `gpt-5.4-mini`, `gpt-5.4-nano`
16
16
  - **Anthropic:** `claude-opus-5`, `claude-opus-4-8`, `claude-sonnet-5`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-sonnet-4-6`, `claude-haiku-4-5-20251001`
17
- - **Gemini:** `gemini-3.7-flash`, `gemini-3.6-flash`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`
17
+ - **Gemini:** `gemini-3.7-flash`, `gemini-3.6-flash`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`, `gemini-3.1-flash-lite`
18
18
  - **xAI:** `grok-4.6`, `grok-4.5`, `grok-4.3`, `grok-4.20-multi-agent-beta-0309`, `grok-4.20-beta-0309-reasoning`, `grok-4.20-beta-0309-non-reasoning`
19
19
  - **OpenRouter:** not enumerated (huge/dynamic catalog) — any `openrouter/<vendor>/<model>` slug routes through, e.g. `openrouter/anthropic/claude-sonnet-4.5`.
20
20
  - **vLLM / SGLang:** not enumerated (self-hosted) — any `vllm/<served-model>` or `sglang/<served-model>` routes through to the configured server, e.g. `sglang/Qwen/Qwen3.6-35B-A3B-FP8`.
@@ -958,7 +958,7 @@ checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
958
958
 
959
959
  [[package]]
960
960
  name = "llmshim"
961
- version = "0.3.3"
961
+ version = "0.3.4"
962
962
  dependencies = [
963
963
  "async-stream",
964
964
  "async-trait",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "llmshim"
3
- version = "0.3.3"
3
+ version = "0.3.4"
4
4
  edition = "2021"
5
5
  description = "Blazing fast LLM API translation layer in pure Rust"
6
6
  license = "MIT OR Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llmshim
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -37,11 +37,30 @@ llmshim.configure(
37
37
  openai="sk-...",
38
38
  gemini="AIza...",
39
39
  xai="xai-...",
40
+ openrouter="sk-or-...",
40
41
  )
41
42
  ```
42
43
 
43
44
  Or from the CLI: `llmshim configure`
44
45
 
46
+ ### Self-hosted servers (vLLM / SGLang)
47
+
48
+ vLLM and SGLang are configured via **environment variables** (not
49
+ `config.toml`) — the auto-spawned proxy inherits them from your Python
50
+ process. Set them before your first call:
51
+
52
+ ```python
53
+ import os
54
+
55
+ os.environ["VLLM_BASE_URL"] = "http://localhost:8000/v1"
56
+ os.environ["VLLM_API_KEY"] = "..." # optional
57
+ os.environ["SGLANG_BASE_URL"] = "http://localhost:30000/v1"
58
+ os.environ["SGLANG_API_KEY"] = "..." # optional
59
+ ```
60
+
61
+ Then address them via the model string — `vllm/<served-model>` or
62
+ `sglang/<served-model>` (see the model table below).
63
+
45
64
  ## Chat
46
65
 
47
66
  ```python
@@ -106,17 +125,63 @@ print(f"GPT: {r2['message']['content']}")
106
125
 
107
126
  ## Reasoning / Thinking
108
127
 
128
+ Two provider-agnostic knobs control reasoning; both are clamped to the
129
+ nearest tier the target model supports:
130
+
131
+ - `reasoning_effort` — `"none"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`, or `"max"`
132
+ - `reasoning_mode` — `"standard"` (default) or `"pro"` (requests substantially
133
+ more model work; native on OpenAI gpt-5.6/-pro, emulated as an effort bump
134
+ elsewhere)
135
+
109
136
  ```python
110
137
  resp = llmshim.chat(
111
- "claude-sonnet-4-6",
138
+ "claude-sonnet-5",
112
139
  "Solve: x^2 - 5x + 6 = 0",
113
140
  max_tokens=4000,
114
141
  reasoning_effort="high",
142
+ reasoning_mode="pro",
115
143
  )
116
144
  print(resp["reasoning"]) # thinking content
117
145
  print(resp["message"]["content"]) # answer
118
146
  ```
119
147
 
148
+ For full native control, bypass the unified mapping with a namespaced
149
+ `provider_config` (see below), e.g.
150
+ `provider_config={"x-anthropic": {"thinking": {"type": "enabled", "budget_tokens": 4000}}}`.
151
+
152
+ ## Provider-Specific Controls (`provider_config`)
153
+
154
+ `provider_config` merges into the request **root** and carries anything the
155
+ unified `config` doesn't cover. Native provider controls MUST be **namespaced**
156
+ per provider (`x-anthropic`, `x-openai`, `x-gemini`, `x-openrouter`, `x-vllm`,
157
+ `x-sglang`); it also carries the top-level `tools`, `response_format`, and
158
+ `reasoning_summary` keys.
159
+
160
+ ```python
161
+ resp = llmshim.chat(
162
+ "anthropic/claude-sonnet-5",
163
+ "Solve this step by step: 17 * 23",
164
+ max_tokens=4000,
165
+ provider_config={
166
+ # native Anthropic extended-thinking control
167
+ "x-anthropic": {"thinking": {"type": "enabled", "budget_tokens": 4000}},
168
+ # structured output
169
+ "response_format": {"type": "json_object"},
170
+ },
171
+ )
172
+ ```
173
+
174
+ OpenRouter routing preferences use the `x-openrouter` namespace:
175
+
176
+ ```python
177
+ resp = llmshim.chat(
178
+ "openrouter/anthropic/claude-sonnet-4.5",
179
+ "Hello",
180
+ max_tokens=200,
181
+ provider_config={"x-openrouter": {"provider": {"sort": "throughput"}}},
182
+ )
183
+ ```
184
+
120
185
  ## Tool Use / Function Calling
121
186
 
122
187
  ```python
@@ -147,7 +212,7 @@ resp = llmshim.chat(
147
212
  "anthropic/claude-sonnet-4-6",
148
213
  "Hello",
149
214
  max_tokens=100,
150
- fallback=["openai/gpt-5.5", "gemini/gemini-3-flash-preview"],
215
+ fallback=["openai/gpt-5.6-sol", "gemini/gemini-3.5-flash"],
151
216
  )
152
217
  ```
153
218
 
@@ -220,10 +285,21 @@ billed provider calls; run it only when you deliberately want to hit real APIs.
220
285
 
221
286
  | Provider | Models |
222
287
  |----------|--------|
223
- | OpenAI | `gpt-5.5`, `gpt-5.5-pro`, `gpt-5.4`, `gpt-5.4-pro`, `gpt-5.4-mini`, `gpt-5.4-nano` |
288
+ | OpenAI | `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`, `gpt-5.5-pro`, `gpt-5.4`, `gpt-5.4-pro`, `gpt-5.4-mini`, `gpt-5.4-nano` |
224
289
  | Anthropic | `claude-opus-5`, `claude-opus-4-8`, `claude-sonnet-5`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-sonnet-4-6`, `claude-haiku-4-5-20251001` |
225
- | Gemini | `gemini-3.7-flash`, `gemini-3.6-flash`, `gemini-3.5-flash`, `gemini-3.5-flash-lite` |
290
+ | Gemini | `gemini-3.7-flash`, `gemini-3.6-flash`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`, `gemini-3.1-flash-lite` |
226
291
  | xAI | `grok-4.6`, `grok-4.5`, `grok-4.3`, `grok-4.20-multi-agent-beta-0309`, `grok-4.20-beta-0309-reasoning`, `grok-4.20-beta-0309-non-reasoning` |
227
292
 
228
293
  Call `llmshim.models()` for the live list filtered to your configured providers.
229
294
 
295
+ ### OpenRouter & self-hosted (vLLM / SGLang)
296
+
297
+ These providers are addressed by the model string plus environment variables —
298
+ any model the upstream serves is reachable, so they aren't in the table above.
299
+
300
+ | Provider | Address as | Env vars | Native controls |
301
+ |----------|-----------|----------|-----------------|
302
+ | OpenRouter | `openrouter/<vendor>/<model>` (e.g. `openrouter/anthropic/claude-sonnet-4.5`) | `OPENROUTER_API_KEY` (or `llmshim.configure(openrouter=...)`) | `provider_config={"x-openrouter": {...}}` (`provider`, `models`, `transforms`) |
303
+ | vLLM | `vllm/<served-model>` | `VLLM_BASE_URL` (+ optional `VLLM_API_KEY`) | `provider_config={"x-vllm": {...}}` |
304
+ | SGLang | `sglang/<served-model>` | `SGLANG_BASE_URL` (+ optional `SGLANG_API_KEY`) | `provider_config={"x-sglang": {...}}` |
305
+
@@ -364,7 +364,7 @@ Standard library only. Full docs: [`clients/ruby/README.md`](clients/ruby/README
364
364
  |----------|--------|-------------------|
365
365
  | **OpenAI** | `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`, `gpt-5.5-pro`, `gpt-5.4`, `gpt-5.4-pro`, `gpt-5.4-mini`, `gpt-5.4-nano` | Yes (summaries) |
366
366
  | **Anthropic** | `claude-opus-5`, `claude-opus-4-8`, `claude-sonnet-5`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-sonnet-4-6`, `claude-haiku-4-5-20251001` | Yes (full thinking) |
367
- | **Google Gemini** | `gemini-3.7-flash`, `gemini-3.6-flash`, `gemini-3.5-flash`, `gemini-3.5-flash-lite` | Yes (thought summaries) |
367
+ | **Google Gemini** | `gemini-3.7-flash`, `gemini-3.6-flash`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`, `gemini-3.1-flash-lite` | Yes (thought summaries) |
368
368
  | **xAI** | `grok-4.6`, `grok-4.5`, `grok-4.3`, `grok-4.20-multi-agent-beta-0309`, `grok-4.20-beta-0309-reasoning`, `grok-4.20-beta-0309-non-reasoning` | No (hidden) |
369
369
 
370
370
  Use a bare model name (auto-detected by prefix) or an explicit `provider/model` string.
@@ -117,7 +117,7 @@ token budget scaled from `max_tokens` and floored at 1024:
117
117
  Gemini uses the four-rung
118
118
  `generationConfig.thinkingConfig.thinkingLevel` enum:
119
119
 
120
- | unified | gemini-3.5-flash / 3.6-flash / 3.5-flash-lite | gemini-3.7-flash (and gemini-3.1-pro) |
120
+ | unified | gemini-3.5-flash / 3.6-flash / 3.5-flash-lite / 3.1-flash-lite | gemini-3.7-flash (and gemini-3.1-pro) |
121
121
  |---|---|---|
122
122
  | `none` | `minimal` (zero thinking tokens) | **`low`** (this model cannot disable thinking) |
123
123
  | `low` | `low` | `low` |
@@ -14,7 +14,7 @@ the ID and display label.
14
14
 
15
15
  ## Registered catalog
16
16
 
17
- The current registry contains 26 entries, newest first within each provider.
17
+ The current registry contains 27 entries, newest first within each provider.
18
18
  This page mirrors `src/models.rs`; use runtime discovery rather than parsing
19
19
  this table in applications.
20
20
 
@@ -52,6 +52,7 @@ this table in applications.
52
52
  | `gemini/gemini-3.6-flash` | Gemini 3.6 Flash |
53
53
  | `gemini/gemini-3.5-flash` | Gemini 3.5 Flash |
54
54
  | `gemini/gemini-3.5-flash-lite` | Gemini 3.5 Flash Lite |
55
+ | `gemini/gemini-3.1-flash-lite` | Gemini 3.1 Flash Lite |
55
56
 
56
57
  ### xAI
57
58
 
@@ -14,6 +14,8 @@ Spec-faithful TypedDicts live in ``llmshim.types`` (also re-exported here) for
14
14
  static type-checking of requests, responses, and stream events.
15
15
  """
16
16
 
17
+ from importlib.metadata import PackageNotFoundError, version
18
+
17
19
  from llmshim import types
18
20
  from llmshim._client import LlmShimError, chat, configure, health, models, stream
19
21
  from llmshim.types import (
@@ -55,4 +57,7 @@ __all__ = [
55
57
  "ToolCall",
56
58
  "Usage",
57
59
  ]
58
- __version__ = "0.1.22"
60
+ try:
61
+ __version__ = version("llmshim")
62
+ except PackageNotFoundError: # not installed (e.g. running from source tree)
63
+ __version__ = "0.0.0"
@@ -89,6 +89,7 @@ def configure(
89
89
  anthropic: Optional[str] = None,
90
90
  gemini: Optional[str] = None,
91
91
  xai: Optional[str] = None,
92
+ openrouter: Optional[str] = None,
92
93
  ) -> None:
93
94
  """Configure API keys. Writes to ~/.llmshim/config.toml.
94
95
 
@@ -98,6 +99,19 @@ def configure(
98
99
  Usage:
99
100
  import llmshim
100
101
  llmshim.configure(anthropic="sk-ant-...", openai="sk-...")
102
+
103
+ Self-hosted servers (vLLM, SGLang) are configured via environment
104
+ variables — NOT config.toml — which the auto-spawned proxy inherits from
105
+ the Python process. Set them before your first call, e.g.::
106
+
107
+ import os
108
+ os.environ["VLLM_BASE_URL"] = "http://localhost:8000/v1"
109
+ os.environ["VLLM_API_KEY"] = "..." # optional
110
+ os.environ["SGLANG_BASE_URL"] = "http://localhost:30000/v1"
111
+ os.environ["SGLANG_API_KEY"] = "..." # optional
112
+
113
+ Then address them via the model string, e.g. ``vllm/<served-model>`` or
114
+ ``sglang/<served-model>``.
101
115
  """
102
116
  config_dir = Path.home() / ".llmshim"
103
117
  config_path = config_dir / "config.toml"
@@ -125,6 +139,8 @@ def configure(
125
139
  keys["gemini"] = gemini
126
140
  if xai is not None:
127
141
  keys["xai"] = xai
142
+ if openrouter is not None:
143
+ keys["openrouter"] = openrouter
128
144
 
129
145
  # Write back
130
146
  config_dir.mkdir(parents=True, exist_ok=True)
@@ -152,6 +168,8 @@ def configure(
152
168
  os.environ["GEMINI_API_KEY"] = gemini
153
169
  if xai:
154
170
  os.environ["XAI_API_KEY"] = xai
171
+ if openrouter:
172
+ os.environ["OPENROUTER_API_KEY"] = openrouter
155
173
 
156
174
  # If server is already running, it won't pick up new keys until restart.
157
175
  # Force restart on next call.
@@ -26,6 +26,7 @@ const MODELS: &[(&str, &str)] = &[
26
26
  ("gemini/gemini-3.6-flash", "Gemini 3.6 Flash"),
27
27
  ("gemini/gemini-3.5-flash", "Gemini 3.5 Flash"),
28
28
  ("gemini/gemini-3.5-flash-lite", "Gemini 3.5 Flash Lite"),
29
+ ("gemini/gemini-3.1-flash-lite", "Gemini 3.1 Flash Lite"),
29
30
  ("xai/grok-4.6", "Grok 4.6"),
30
31
  ("xai/grok-4.5", "Grok 4.5"),
31
32
  ("xai/grok-4.3", "Grok 4.3"),
@@ -361,6 +361,15 @@ pub const MODELS: &[ModelInfo] = &[
361
361
  max_output_tokens: Some(65_536),
362
362
  capabilities: CAPS_STD,
363
363
  },
364
+ ModelInfo {
365
+ id: "gemini/gemini-3.1-flash-lite",
366
+ provider: "gemini",
367
+ name: "gemini-3.1-flash-lite",
368
+ label: "Gemini 3.1 Flash Lite",
369
+ context_window_tokens: Some(1_048_576),
370
+ max_output_tokens: Some(65_536),
371
+ capabilities: CAPS_STD,
372
+ },
364
373
  ModelInfo {
365
374
  id: "xai/grok-4.6",
366
375
  provider: "xai",
@@ -478,3 +478,23 @@ async fn gemini_3_7_flash_none_clamps_to_low() {
478
478
  assert_eq!(resp["object"], "chat.completion");
479
479
  println!("gemini-3.7-flash none->low clamp OK");
480
480
  }
481
+
482
+ #[tokio::test]
483
+ #[ignore]
484
+ async fn gemini_3_1_flash_lite_completion() {
485
+ if std::env::var("GEMINI_API_KEY").is_err() {
486
+ return;
487
+ }
488
+ let router = router();
489
+ let req = json!({
490
+ "model": "gemini/gemini-3.1-flash-lite",
491
+ "messages": [{"role": "user", "content": "In one short sentence, what is Rust?"}],
492
+ "max_tokens": 2000,
493
+ });
494
+ let resp = llmshim::completion(&router, &req).await.unwrap();
495
+ let content = resp["choices"][0]["message"]["content"]
496
+ .as_str()
497
+ .unwrap_or("");
498
+ assert!(!content.is_empty(), "expected a response, got: {resp}");
499
+ println!("gemini-3.1-flash-lite said: {content}");
500
+ }
@@ -1549,6 +1549,7 @@ fn reasoning_none_clamps_per_model_disable_capability() {
1549
1549
  "gemini-3.6-flash",
1550
1550
  "gemini-3.5-flash",
1551
1551
  "gemini-3.5-flash-lite",
1552
+ "gemini-3.1-flash-lite",
1552
1553
  ] {
1553
1554
  let r = p.transform_request(m, &req).unwrap();
1554
1555
  assert_eq!(
@@ -11,7 +11,7 @@ fn models_registry_has_all_providers() {
11
11
 
12
12
  #[test]
13
13
  fn models_registry_has_expected_count() {
14
- assert_eq!(MODELS.len(), 26);
14
+ assert_eq!(MODELS.len(), 27);
15
15
  }
16
16
 
17
17
  #[test]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes