langchain-llama-cpp 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bharathan Mudaliar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-llama-cpp
3
+ Version: 0.1.0
4
+ Summary: An integration package connecting llama.cpp's llama-server and LangChain, with reasoning, timings, structured output and tool calling
5
+ Keywords: langchain,llama.cpp,llama-server,llama-swap,llm,local-llm,chat-model
6
+ Author: Bharathan Mudaliar
7
+ Author-email: Bharathan Mudaliar <bharathanmudaliar@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Typing :: Typed
20
+ Requires-Dist: httpx>=0.27,<1
21
+ Requires-Dist: langchain-core>=1.6,<2
22
+ Requires-Python: >=3.10
23
+ Project-URL: Repository, https://github.com/bharat029/langchain-llama-cpp
24
+ Project-URL: Issues, https://github.com/bharat029/langchain-llama-cpp/issues
25
+ Description-Content-Type: text/markdown
26
+
27
+ # langchain-llama-cpp
28
+
29
+ [![PyPI - Version](https://img.shields.io/pypi/v/langchain-llama-cpp?label=%20)](https://pypi.org/project/langchain-llama-cpp/)
30
+ [![PyPI - License](https://img.shields.io/pypi/l/langchain-llama-cpp)](https://opensource.org/licenses/MIT)
31
+
32
+ A LangChain chat model, `ChatLlama`, for llama.cpp's `llama-server`. It's built
33
+ on `langchain-core` and `httpx` only and talks to `/v1/chat/completions`
34
+ directly, so nothing llama-server sends back is lost on the way.
35
+
36
+ **Why not `ChatOpenAI`?** llama-server speaks the OpenAI format, but with extras
37
+ that `ChatOpenAI` drops or gets wrong:
38
+
39
+ - it drops `reasoning_content` (the model's thinking) and llama-server's `timings`;
40
+ - it sends a named `tool_choice` as an object, which llama-server silently turns
41
+ into `"auto"`;
42
+ - it can't send llama.cpp's own sampling fields (`top_k`, `min_p`, `samplers`,
43
+ DRY, XTC, ...) as typed parameters.
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ pip install langchain-llama-cpp
49
+ ```
50
+
51
+ or `uv add langchain-llama-cpp`. Python 3.10+.
52
+
53
+ ## Tested setup
54
+
55
+ - **llama-swap** in front of llama-server. `model` is the llama-swap entry to
56
+ use. A bare llama-server (no llama-swap) is not tested yet.
57
+ - llama-server build **b11429**, with gemma 4, Qwen3.6 and gpt-oss, on
58
+ langchain-core 1.6.
59
+
60
+ ## Quick start
61
+
62
+ ```python
63
+ from langchain_llama_cpp import ChatLlama
64
+
65
+ llm = ChatLlama(model="gemma", max_tokens=2000) # base_url from LLAMA_BASE_URL
66
+ msg = llm.invoke("What is 17 * 23? Answer with the number only.")
67
+
68
+ msg.content # '391'
69
+ msg.additional_kwargs["reasoning_content"] # 'The user wants to know the product...'
70
+ msg.usage_metadata # {'input_tokens': 32, 'output_tokens': 223, ...}
71
+ msg.response_metadata["timings"] # {'prompt_n': 25, 'predicted_n': 223, ...}
72
+ ```
73
+
74
+ Set `max_tokens` with room for thinking. Reasoning length varies from run to
75
+ run: gemma answered this in 223 tokens once, and in another run used all of
76
+ `max_tokens=300` and ended mid-thought, with an empty `content` and
77
+ `finish_reason: "length"`.
78
+
79
+ `base_url` defaults to the `LLAMA_BASE_URL` environment variable, e.g.
80
+ `http://localhost:8080`. Pass `base_url=` to override it.
81
+
82
+ Reasoning is stored where ChatDeepSeek and ChatOllama put it,
83
+ `additional_kwargs["reasoning_content"]`, so `msg.content_blocks` shows it as a
84
+ standard `{"type": "reasoning"}` block. `langchain_llama_cpp.utils.pretty_print(msg)`
85
+ prints a message with its reasoning.
86
+
87
+ ## Usage
88
+
89
+ ### Thinking
90
+
91
+ The switch lives in the chat template, and its name differs per model family:
92
+
93
+ ```python
94
+ ChatLlama(model="gemma", chat_template_kwargs={"enable_thinking": False}) # gemma, qwen
95
+ ChatLlama(model="gpt-oss", chat_template_kwargs={"reasoning_effort": "low"}) # gpt-oss
96
+ ```
97
+
98
+ Thinking tokens count towards `max_tokens` (see Quick start).
99
+
100
+ When you send a conversation back, an `AIMessage`'s reasoning goes back too, and
101
+ the model's chat template decides whether to show it to the model.
102
+
103
+ ### Streaming and async
104
+
105
+ ```python
106
+ for chunk in llm.stream("Count to five."):
107
+ print(chunk.content, end="")
108
+
109
+ msg = await llm.ainvoke("Hello!")
110
+ async for chunk in llm.astream("Hello!"):
111
+ ...
112
+ ```
113
+
114
+ Reasoning arrives in `chunk.additional_kwargs["reasoning_content"]`. Usage and
115
+ timings come in the last chunk (`stream_usage=True`, the default).
116
+
117
+ ### Tool calling
118
+
119
+ ```python
120
+ from langchain_core.tools import tool
121
+
122
+
123
+ @tool
124
+ def get_weather(city: str) -> str:
125
+ """Get the current weather in a city."""
126
+ return f"Sunny in {city}"
127
+
128
+
129
+ llm_with_tools = llm.bind_tools([get_weather])
130
+ msg = llm_with_tools.invoke("What's the weather in Paris?")
131
+ msg.tool_calls # [{'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': '...', ...}]
132
+ ```
133
+
134
+ llama-server accepts only the strings `"auto"`, `"none"` and `"required"` as
135
+ `tool_choice`. A tool's name (or `"any"`, or `True`) is sent as `"required"`:
136
+ the model must call a tool but may pick a different one, because the server
137
+ can't force a particular tool.
138
+
139
+ ### Structured output
140
+
141
+ ```python
142
+ from pydantic import BaseModel, Field
143
+
144
+
145
+ class Person(BaseModel):
146
+ name: str
147
+ age: int = Field(description="Age in years")
148
+
149
+
150
+ structured = llm.with_structured_output(Person)
151
+ structured.invoke("Alice is 30.") # Person(name='Alice', age=30)
152
+ ```
153
+
154
+ Three methods:
155
+
156
+ | `method` | What's sent | The model sees the schema? |
157
+ |---|---|---|
158
+ | `"function_calling"` (default) | the schema as the only tool, `tool_choice: "required"` | yes, through the chat template |
159
+ | `"json_schema"` | `response_format: {"type": "json_schema", ...}` | no: it's enforced by the grammar only |
160
+ | `"json_mode"` | `response_format: {"type": "json_object"}` | no |
161
+
162
+ `function_calling` is the default because with `json_schema` the model never
163
+ sees the schema's field descriptions: asked for an age described as "in months",
164
+ it fills in years. Pass `include_format_instructions=True` with `json_schema` or
165
+ `json_mode` to add the schema to the system message.
166
+
167
+ ### Request parameters
168
+
169
+ Every field `/v1/chat/completions` accepts in b11429 is a typed parameter:
170
+ `temperature`, `top_k`, `top_p`, `min_p`, `samplers`, `repeat_penalty`, the DRY
171
+ and XTC samplers, `grammar`, `json_schema`, `reasoning_budget_tokens`,
172
+ `cache_prompt`, `id_slot`, `lora` and more. Set them on the model or per call:
173
+
174
+ ```python
175
+ llm = ChatLlama(model="gemma", temperature=0.2, top_k=40)
176
+ llm.invoke("Hi", max_tokens=500)
177
+ ```
178
+
179
+ They all default to `None`, which leaves them out of the request so the
180
+ server's per-model defaults apply. To see those defaults:
181
+
182
+ ```python
183
+ llm.get_server_defaults()
184
+ # {'temperature': 1.0, 'top_k': 64, 'top_p': 0.95, 'max_tokens': -1, ..., 'n_ctx': 131072}
185
+ ```
186
+
187
+ ### Errors and retries
188
+
189
+ Errors are subclasses of both the httpx exception and LangChain's `ModelError`
190
+ classes, so either `except` works:
191
+
192
+ ```python
193
+ from langchain_llama_cpp import LlamaContextOverflowError
194
+
195
+ try:
196
+ llm.invoke(very_long_prompt)
197
+ except LlamaContextOverflowError as error:
198
+ print(error.n_prompt_tokens, error.n_ctx)
199
+ ```
200
+
201
+ There are also `LlamaModelNotFoundError` (an unknown llama-swap entry),
202
+ `LlamaInvalidRequestError`, `LlamaRateLimitError`, `LlamaAPIError` (5xx),
203
+ `LlamaConnectionError` and `LlamaTimeoutError`.
204
+
205
+ Connection errors, timeouts, 429 and 5xx are retried `max_retries` times
206
+ (default 2) with exponential backoff, obeying `Retry-After`. `timeout` is in
207
+ seconds and defaults to `None` (no timeout), since local generation can be slow.
208
+
209
+ ## Known limitations
210
+
211
+ - **Forcing a tool with Qwen3.5/3.6.** With `tool_choice="required"` (also used
212
+ by `with_structured_output`'s default method), llama-server's grammar for these
213
+ models lets the model write text before the call and won't let it stop
214
+ without one. A model that doesn't want a tool keeps writing until
215
+ `max_tokens`, and there's no tool call. This is
216
+ [ggml-org/llama.cpp#27217](https://github.com/ggml-org/llama.cpp/issues/27217);
217
+ keep `max_tokens` set.
218
+ - **A named `tool_choice`** is sent as `"required"` (see Tool calling).
219
+ - **JSON schema bounds on numbers** (`minimum`, `maximum`, `multipleOf` on
220
+ `number`) aren't enforced by llama-server's grammar. Integer bounds are.
221
+ - **Bare llama-server** (without llama-swap) isn't tested; `get_server_defaults`
222
+ needs llama-swap's `/upstream/<model>/props`.
223
+
224
+ ## Development
225
+
226
+ Bug reports and pull requests are welcome on
227
+ [GitHub](https://github.com/bharat029/langchain-llama-cpp/issues).
228
+
229
+ ```bash
230
+ uv sync
231
+ uv run pytest tests/unit_tests # offline
232
+ uv run ruff check && uv run ruff format --check && uv run pyright
233
+ ```
234
+
235
+ The integration tests (LangChain's standard `langchain-tests` suite, on gemma,
236
+ qwen and gpt-oss) need a llama-swap server. Copy `.env.example` to `.env` and
237
+ set `LLAMA_BASE_URL`, then:
238
+
239
+ ```bash
240
+ uv run --env-file .env pytest tests/integration_tests
241
+ ```
242
+
243
+ The JSON llama-server sends back is described in
244
+ `src/langchain_llama_cpp/_wire.py`.
245
+
246
+ ## License
247
+
248
+ MIT
@@ -0,0 +1,222 @@
1
+ # langchain-llama-cpp
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/langchain-llama-cpp?label=%20)](https://pypi.org/project/langchain-llama-cpp/)
4
+ [![PyPI - License](https://img.shields.io/pypi/l/langchain-llama-cpp)](https://opensource.org/licenses/MIT)
5
+
6
+ A LangChain chat model, `ChatLlama`, for llama.cpp's `llama-server`. It's built
7
+ on `langchain-core` and `httpx` only and talks to `/v1/chat/completions`
8
+ directly, so nothing llama-server sends back is lost on the way.
9
+
10
+ **Why not `ChatOpenAI`?** llama-server speaks the OpenAI format, but with extras
11
+ that `ChatOpenAI` drops or gets wrong:
12
+
13
+ - it drops `reasoning_content` (the model's thinking) and llama-server's `timings`;
14
+ - it sends a named `tool_choice` as an object, which llama-server silently turns
15
+ into `"auto"`;
16
+ - it can't send llama.cpp's own sampling fields (`top_k`, `min_p`, `samplers`,
17
+ DRY, XTC, ...) as typed parameters.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install langchain-llama-cpp
23
+ ```
24
+
25
+ or `uv add langchain-llama-cpp`. Python 3.10+.
26
+
27
+ ## Tested setup
28
+
29
+ - **llama-swap** in front of llama-server. `model` is the llama-swap entry to
30
+ use. A bare llama-server (no llama-swap) is not tested yet.
31
+ - llama-server build **b11429**, with gemma 4, Qwen3.6 and gpt-oss, on
32
+ langchain-core 1.6.
33
+
34
+ ## Quick start
35
+
36
+ ```python
37
+ from langchain_llama_cpp import ChatLlama
38
+
39
+ llm = ChatLlama(model="gemma", max_tokens=2000) # base_url from LLAMA_BASE_URL
40
+ msg = llm.invoke("What is 17 * 23? Answer with the number only.")
41
+
42
+ msg.content # '391'
43
+ msg.additional_kwargs["reasoning_content"] # 'The user wants to know the product...'
44
+ msg.usage_metadata # {'input_tokens': 32, 'output_tokens': 223, ...}
45
+ msg.response_metadata["timings"] # {'prompt_n': 25, 'predicted_n': 223, ...}
46
+ ```
47
+
48
+ Set `max_tokens` with room for thinking. Reasoning length varies from run to
49
+ run: gemma answered this in 223 tokens once, and in another run used all of
50
+ `max_tokens=300` and ended mid-thought, with an empty `content` and
51
+ `finish_reason: "length"`.
52
+
53
+ `base_url` defaults to the `LLAMA_BASE_URL` environment variable, e.g.
54
+ `http://localhost:8080`. Pass `base_url=` to override it.
55
+
56
+ Reasoning is stored where ChatDeepSeek and ChatOllama put it,
57
+ `additional_kwargs["reasoning_content"]`, so `msg.content_blocks` shows it as a
58
+ standard `{"type": "reasoning"}` block. `langchain_llama_cpp.utils.pretty_print(msg)`
59
+ prints a message with its reasoning.
60
+
61
+ ## Usage
62
+
63
+ ### Thinking
64
+
65
+ The switch lives in the chat template, and its name differs per model family:
66
+
67
+ ```python
68
+ ChatLlama(model="gemma", chat_template_kwargs={"enable_thinking": False}) # gemma, qwen
69
+ ChatLlama(model="gpt-oss", chat_template_kwargs={"reasoning_effort": "low"}) # gpt-oss
70
+ ```
71
+
72
+ Thinking tokens count towards `max_tokens` (see Quick start).
73
+
74
+ When you send a conversation back, an `AIMessage`'s reasoning goes back too, and
75
+ the model's chat template decides whether to show it to the model.
76
+
77
+ ### Streaming and async
78
+
79
+ ```python
80
+ for chunk in llm.stream("Count to five."):
81
+ print(chunk.content, end="")
82
+
83
+ msg = await llm.ainvoke("Hello!")
84
+ async for chunk in llm.astream("Hello!"):
85
+ ...
86
+ ```
87
+
88
+ Reasoning arrives in `chunk.additional_kwargs["reasoning_content"]`. Usage and
89
+ timings come in the last chunk (`stream_usage=True`, the default).
90
+
91
+ ### Tool calling
92
+
93
+ ```python
94
+ from langchain_core.tools import tool
95
+
96
+
97
+ @tool
98
+ def get_weather(city: str) -> str:
99
+ """Get the current weather in a city."""
100
+ return f"Sunny in {city}"
101
+
102
+
103
+ llm_with_tools = llm.bind_tools([get_weather])
104
+ msg = llm_with_tools.invoke("What's the weather in Paris?")
105
+ msg.tool_calls # [{'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': '...', ...}]
106
+ ```
107
+
108
+ llama-server accepts only the strings `"auto"`, `"none"` and `"required"` as
109
+ `tool_choice`. A tool's name (or `"any"`, or `True`) is sent as `"required"`:
110
+ the model must call a tool but may pick a different one, because the server
111
+ can't force a particular tool.
112
+
113
+ ### Structured output
114
+
115
+ ```python
116
+ from pydantic import BaseModel, Field
117
+
118
+
119
+ class Person(BaseModel):
120
+ name: str
121
+ age: int = Field(description="Age in years")
122
+
123
+
124
+ structured = llm.with_structured_output(Person)
125
+ structured.invoke("Alice is 30.") # Person(name='Alice', age=30)
126
+ ```
127
+
128
+ Three methods:
129
+
130
+ | `method` | What's sent | The model sees the schema? |
131
+ |---|---|---|
132
+ | `"function_calling"` (default) | the schema as the only tool, `tool_choice: "required"` | yes, through the chat template |
133
+ | `"json_schema"` | `response_format: {"type": "json_schema", ...}` | no: it's enforced by the grammar only |
134
+ | `"json_mode"` | `response_format: {"type": "json_object"}` | no |
135
+
136
+ `function_calling` is the default because with `json_schema` the model never
137
+ sees the schema's field descriptions: asked for an age described as "in months",
138
+ it fills in years. Pass `include_format_instructions=True` with `json_schema` or
139
+ `json_mode` to add the schema to the system message.
140
+
141
+ ### Request parameters
142
+
143
+ Every field `/v1/chat/completions` accepts in b11429 is a typed parameter:
144
+ `temperature`, `top_k`, `top_p`, `min_p`, `samplers`, `repeat_penalty`, the DRY
145
+ and XTC samplers, `grammar`, `json_schema`, `reasoning_budget_tokens`,
146
+ `cache_prompt`, `id_slot`, `lora` and more. Set them on the model or per call:
147
+
148
+ ```python
149
+ llm = ChatLlama(model="gemma", temperature=0.2, top_k=40)
150
+ llm.invoke("Hi", max_tokens=500)
151
+ ```
152
+
153
+ They all default to `None`, which leaves them out of the request so the
154
+ server's per-model defaults apply. To see those defaults:
155
+
156
+ ```python
157
+ llm.get_server_defaults()
158
+ # {'temperature': 1.0, 'top_k': 64, 'top_p': 0.95, 'max_tokens': -1, ..., 'n_ctx': 131072}
159
+ ```
160
+
161
+ ### Errors and retries
162
+
163
+ Errors are subclasses of both the httpx exception and LangChain's `ModelError`
164
+ classes, so either `except` works:
165
+
166
+ ```python
167
+ from langchain_llama_cpp import LlamaContextOverflowError
168
+
169
+ try:
170
+ llm.invoke(very_long_prompt)
171
+ except LlamaContextOverflowError as error:
172
+ print(error.n_prompt_tokens, error.n_ctx)
173
+ ```
174
+
175
+ There are also `LlamaModelNotFoundError` (an unknown llama-swap entry),
176
+ `LlamaInvalidRequestError`, `LlamaRateLimitError`, `LlamaAPIError` (5xx),
177
+ `LlamaConnectionError` and `LlamaTimeoutError`.
178
+
179
+ Connection errors, timeouts, 429 and 5xx are retried `max_retries` times
180
+ (default 2) with exponential backoff, obeying `Retry-After`. `timeout` is in
181
+ seconds and defaults to `None` (no timeout), since local generation can be slow.
182
+
183
+ ## Known limitations
184
+
185
+ - **Forcing a tool with Qwen3.5/3.6.** With `tool_choice="required"` (also used
186
+ by `with_structured_output`'s default method), llama-server's grammar for these
187
+ models lets the model write text before the call and won't let it stop
188
+ without one. A model that doesn't want a tool keeps writing until
189
+ `max_tokens`, and there's no tool call. This is
190
+ [ggml-org/llama.cpp#27217](https://github.com/ggml-org/llama.cpp/issues/27217);
191
+ keep `max_tokens` set.
192
+ - **A named `tool_choice`** is sent as `"required"` (see Tool calling).
193
+ - **JSON schema bounds on numbers** (`minimum`, `maximum`, `multipleOf` on
194
+ `number`) aren't enforced by llama-server's grammar. Integer bounds are.
195
+ - **Bare llama-server** (without llama-swap) isn't tested; `get_server_defaults`
196
+ needs llama-swap's `/upstream/<model>/props`.
197
+
198
+ ## Development
199
+
200
+ Bug reports and pull requests are welcome on
201
+ [GitHub](https://github.com/bharat029/langchain-llama-cpp/issues).
202
+
203
+ ```bash
204
+ uv sync
205
+ uv run pytest tests/unit_tests # offline
206
+ uv run ruff check && uv run ruff format --check && uv run pyright
207
+ ```
208
+
209
+ The integration tests (LangChain's standard `langchain-tests` suite, on gemma,
210
+ qwen and gpt-oss) need a llama-swap server. Copy `.env.example` to `.env` and
211
+ set `LLAMA_BASE_URL`, then:
212
+
213
+ ```bash
214
+ uv run --env-file .env pytest tests/integration_tests
215
+ ```
216
+
217
+ The JSON llama-server sends back is described in
218
+ `src/langchain_llama_cpp/_wire.py`.
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,112 @@
1
+ [project]
2
+ name = "langchain-llama-cpp"
3
+ version = "0.1.0"
4
+ description = "An integration package connecting llama.cpp's llama-server and LangChain, with reasoning, timings, structured output and tool calling"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.10"
9
+ keywords = [
10
+ "langchain",
11
+ "llama.cpp",
12
+ "llama-server",
13
+ "llama-swap",
14
+ "llm",
15
+ "local-llm",
16
+ "chat-model",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Intended Audience :: Developers",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: 3.14",
27
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
28
+ "Typing :: Typed",
29
+ ]
30
+ dependencies = [
31
+ "httpx>=0.27,<1",
32
+ "langchain-core>=1.6,<2",
33
+ ]
34
+
35
+ [[project.authors]]
36
+ name = "Bharathan Mudaliar"
37
+ email = "bharathanmudaliar@gmail.com"
38
+
39
+ [project.urls]
40
+ Repository = "https://github.com/bharat029/langchain-llama-cpp"
41
+ Issues = "https://github.com/bharat029/langchain-llama-cpp/issues"
42
+
43
+ [build-system]
44
+ requires = ["uv_build>=0.12.5,<0.13.0"]
45
+ build-backend = "uv_build"
46
+
47
+ [dependency-groups]
48
+ dev = [
49
+ "langchain-tests>=1.1.9",
50
+ "pyright>=1.1.414",
51
+ "pytest>=9.1.1",
52
+ "pytest-asyncio>=1.4.0",
53
+ "ruff>=0.17.0",
54
+ ]
55
+
56
+ [tool.ruff.format]
57
+ docstring-code-format = true
58
+ docstring-code-line-length = 100
59
+
60
+ [tool.ruff.lint]
61
+ select = ["ALL"]
62
+ ignore = [
63
+ "CPY001",
64
+ "COM812",
65
+ "ISC001",
66
+ "ANN401",
67
+ "TC002",
68
+ "TC003",
69
+ "RUF012",
70
+ "PLR0913",
71
+ "C901",
72
+ "PLR0912",
73
+ "PLR0915",
74
+ "PERF203",
75
+ "FIX002",
76
+ "TD002",
77
+ "TD003",
78
+ ]
79
+ unfixable = ["B028"]
80
+
81
+ [tool.ruff.lint.pydocstyle]
82
+ convention = "google"
83
+ ignore-var-parameters = true
84
+
85
+ [tool.ruff.lint.flake8-tidy-imports]
86
+ ban-relative-imports = "all"
87
+
88
+ [tool.ruff.lint.extend-per-file-ignores]
89
+ "tests/**/*.py" = [
90
+ "D",
91
+ "INP001",
92
+ "S101",
93
+ "PLR2004",
94
+ "SLF001",
95
+ "ARG001",
96
+ "PT011",
97
+ ]
98
+
99
+ [tool.pytest.ini_options]
100
+ asyncio_mode = "auto"
101
+ asyncio_default_fixture_loop_scope = "function"
102
+
103
+ [tool.pyright]
104
+ include = [
105
+ "src",
106
+ "tests",
107
+ ]
108
+ pythonVersion = "3.10"
109
+ venvPath = "."
110
+ venv = ".venv"
111
+ typeCheckingMode = "standard"
112
+ strict = ["src"]