llm-sdk-core 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.
Files changed (29) hide show
  1. llm_sdk_core-0.1.0/.gitignore +113 -0
  2. llm_sdk_core-0.1.0/LICENSE +0 -0
  3. llm_sdk_core-0.1.0/PKG-INFO +365 -0
  4. llm_sdk_core-0.1.0/README.md +343 -0
  5. llm_sdk_core-0.1.0/app.py +29 -0
  6. llm_sdk_core-0.1.0/pyproject.toml +34 -0
  7. llm_sdk_core-0.1.0/src/llm_sdk/__init__.py +7 -0
  8. llm_sdk_core-0.1.0/src/llm_sdk/async_sdk.py +354 -0
  9. llm_sdk_core-0.1.0/src/llm_sdk/context.py +22 -0
  10. llm_sdk_core-0.1.0/src/llm_sdk/domain/__init__.py +1 -0
  11. llm_sdk_core-0.1.0/src/llm_sdk/domain/chat.py +205 -0
  12. llm_sdk_core-0.1.0/src/llm_sdk/domain/embeddings.py +38 -0
  13. llm_sdk_core-0.1.0/src/llm_sdk/domain/models.py +17 -0
  14. llm_sdk_core-0.1.0/src/llm_sdk/exceptions.py +64 -0
  15. llm_sdk_core-0.1.0/src/llm_sdk/lifecycle.py +81 -0
  16. llm_sdk_core-0.1.0/src/llm_sdk/plugin_loader.py +72 -0
  17. llm_sdk_core-0.1.0/src/llm_sdk/providers/__init__.py +0 -0
  18. llm_sdk_core-0.1.0/src/llm_sdk/providers/__main__.py +23 -0
  19. llm_sdk_core-0.1.0/src/llm_sdk/providers/async_base.py +88 -0
  20. llm_sdk_core-0.1.0/src/llm_sdk/providers/async_noop_client.py +49 -0
  21. llm_sdk_core-0.1.0/src/llm_sdk/providers/async_registry.py +85 -0
  22. llm_sdk_core-0.1.0/src/llm_sdk/providers/noop_client.py +52 -0
  23. llm_sdk_core-0.1.0/src/llm_sdk/providers/sync_base.py +77 -0
  24. llm_sdk_core-0.1.0/src/llm_sdk/providers/sync_registry.py +105 -0
  25. llm_sdk_core-0.1.0/src/llm_sdk/retries.py +125 -0
  26. llm_sdk_core-0.1.0/src/llm_sdk/settings.py +74 -0
  27. llm_sdk_core-0.1.0/src/llm_sdk/sync_sdk.py +362 -0
  28. llm_sdk_core-0.1.0/src/llm_sdk/timeouts.py +23 -0
  29. llm_sdk_core-0.1.0/src/llm_sdk/typing.py +26 -0
@@ -0,0 +1,113 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # Virtual environments
30
+ venv/
31
+ .venv/
32
+ .virtualenv/
33
+ .virtual-enviroment/
34
+ env_plantillasV2/
35
+ *.venv
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Enviroment variables
40
+ *.env
41
+ .env*
42
+
43
+ # Unit test / coverage reports
44
+ htmlcov/
45
+ .tox/
46
+ .nox/
47
+ .coverage
48
+ .coverage.*
49
+ .cache
50
+ nosetests.xml
51
+ coverage.xml
52
+ *.cover
53
+ *.py,cover
54
+ .hypothesis/
55
+ .pytest_cache/
56
+
57
+ # PyCharm / VSCode / other IDEs
58
+ .idea/
59
+ .vscode/
60
+ *.swp
61
+ *.swo
62
+ *.swn
63
+ *.swp
64
+ *.bak
65
+
66
+ # Jupyter Notebook
67
+ .ipynb_checkpoints
68
+ *.ipynb
69
+
70
+ # Logs
71
+ *.log
72
+ logs/
73
+ *.out
74
+
75
+ # mypy / pytype / pyre
76
+ .mypy_cache/
77
+ .dmypy.json
78
+ dmypy.json
79
+ .pytype/
80
+ .pyre/
81
+
82
+ # Django / Flask stuff
83
+ *.mo
84
+ *.pot
85
+ *.db
86
+ *.sqlite3
87
+ instance/
88
+ .webassets-cache
89
+
90
+ # Static / media
91
+ staticfiles/
92
+ media/
93
+
94
+ # Local config
95
+ config.local.*
96
+ secrets.json
97
+
98
+ # Mac / Linux / Windows system files
99
+ .DS_Store
100
+ Thumbs.db
101
+ desktop.ini
102
+
103
+ # Other
104
+ *.pkl
105
+ *.sage.py
106
+
107
+ # Normal Files
108
+ *.json
109
+ *.csv
110
+ *.xlsx
111
+
112
+ # Node modules
113
+ /node_modules/
File without changes
@@ -0,0 +1,365 @@
1
+ Metadata-Version: 2.4
2
+ Name: llm-sdk-core
3
+ Version: 0.1.0
4
+ Summary: Provider-agnostic SDK for LLMs with async support and plugin providers.
5
+ Project-URL: Homepage, https://github.com/EvanFloresLv/LLM-Generate.git
6
+ Project-URL: Repository, https://github.com/EvanFloresLv/LLM-Generate.git
7
+ Author: Esteban Flores
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: httpx>=0.28.1
12
+ Requires-Dist: pydantic-settings>=2.2
13
+ Requires-Dist: pydantic>=2.6
14
+ Provides-Extra: dev
15
+ Requires-Dist: mypy>=1.8; extra == 'dev'
16
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
17
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
18
+ Requires-Dist: pytest>=8.0; extra == 'dev'
19
+ Requires-Dist: respx>=0.20; extra == 'dev'
20
+ Requires-Dist: ruff>=0.3; extra == 'dev'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # llm-sdk
24
+
25
+ Provider-agnostic Python SDK for Large Language Models (LLMs) with a production-ready async architecture, strong typing, unified errors, retries, logging, and a plugin system based on Python entry points.
26
+
27
+ ---
28
+
29
+ ## Table of Contents
30
+
31
+ - [Overview](#overview)
32
+ - [Architecture](#architecture)
33
+ - [Features](#features)
34
+ - [Installation](#installation)
35
+ - [Usage](#usage)
36
+ - [Configuration](#configuration)
37
+ - [Project Structure](#project-structure)
38
+ - [Development](#development)
39
+ - [Testing](#testing)
40
+ - [Deployment](#deployment)
41
+ - [Roadmap](#roadmap)
42
+ - [Contributing](#contributing)
43
+ - [License](#license)
44
+ - [Contact](#contact)
45
+
46
+ ---
47
+
48
+ ## Overview
49
+
50
+ `llm-sdk` is the **core package** that provides:
51
+
52
+ - A unified API for multiple LLM providers
53
+ - Async-first design (`AsyncSDK`)
54
+ - A provider registry that loads providers via **plugins**
55
+ - Domain models (requests/responses) independent of providers
56
+ - Unified error model
57
+ - Retries, timeouts, and structured logging
58
+
59
+ This package intentionally **does not** ship provider implementations directly.
60
+ Providers are installed as separate packages, for example:
61
+
62
+ - `llm-sdk-provider-gemini`
63
+ - `llm-sdk-provider-openai` (future)
64
+ - `llm-sdk-provider-ollama` (future)
65
+
66
+ ---
67
+
68
+ ## Architecture
69
+
70
+ ### Core design principles
71
+
72
+ - **Provider-agnostic domain layer** (no vendor types leak into the SDK)
73
+ - **Open/Closed Principle**: providers are added via entry points, without modifying core code
74
+ - **SOLID**:
75
+ - `AsyncSDK` orchestrates only
76
+ - Providers implement only provider calls
77
+ - Registry handles discovery
78
+ - Domain models validate input/output
79
+ - **DRY/KISS**: minimal abstractions, strong conventions
80
+
81
+ ### Key components
82
+
83
+ - **AsyncSDK**: main entrypoint (`sdk.chat`, `sdk.embed`, `sdk.stream_chat`)
84
+ - **ProviderRegistry**: discovers provider plugins via entry points
85
+ - **ProviderFactory**: plugin contract (`spec()` + `create(settings)`)
86
+ - **Domain models**: `ChatRequest`, `ChatResponse`, `EmbeddingRequest`, etc.
87
+ - **Unified errors**: `ProviderError`, `ValidationError`, `TimeoutError`
88
+ - **Retries**: async retry policy with exponential backoff + jitter
89
+ - **Settings**: `SDKSettings` (Pydantic Settings)
90
+
91
+ ---
92
+
93
+ ## Features
94
+
95
+ - Async-first API
96
+ - Provider plugins via entry points
97
+ - Chat completions
98
+ - Embeddings
99
+ - Streaming chat (provider-dependent)
100
+ - Strong typing (mypy-friendly)
101
+ - Unified error handling
102
+ - Retry policies with jitter
103
+ - Structured logging support
104
+ - Configuration via environment variables
105
+ - Provider + model resolution at runtime
106
+
107
+ ---
108
+
109
+ ## Installation
110
+
111
+ ### Install core SDK
112
+
113
+ ```bash
114
+ pip install llm-sdk
115
+ ```
116
+
117
+ Install at least one provider plugin
118
+
119
+ ### Example (Gemini):
120
+
121
+ ```bash
122
+ pip install llm-sdk-provider-gemini
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Usage
128
+
129
+ ### Async Quickstart
130
+
131
+ ```python
132
+ import asyncio
133
+ from llm_sdk.async_sdk import AsyncSDK
134
+
135
+
136
+ async def main() -> None:
137
+ sdk = AsyncSDK.default()
138
+
139
+ # IMPORTANT: load provider plugins (entry points)
140
+ sdk.registry.load_plugins()
141
+
142
+ resp = await sdk.chat(
143
+ provider="gemini",
144
+ model="gemini-2.5-flash",
145
+ messages=[("user", "Hola, ¿cómo estás?")],
146
+ )
147
+
148
+ print(resp.content)
149
+
150
+
151
+ if __name__ == "__main__":
152
+ asyncio.run(main())
153
+ ```
154
+
155
+
156
+ ### Streaming chat
157
+
158
+ ```python
159
+ import asyncio
160
+ from llm_sdk.async_sdk import AsyncSDK
161
+
162
+
163
+ async def main() -> None:
164
+ sdk = AsyncSDK.default()
165
+ sdk.registry.load_plugins()
166
+
167
+ async for ev in sdk.stream_chat(
168
+ provider="gemini",
169
+ model="gemini-2.5-flash",
170
+ messages=[("user", "Explica qué es un Transformer en 5 puntos.")],
171
+ ):
172
+ print(ev.delta, end="", flush=True)
173
+
174
+ print("\n[done]")
175
+
176
+
177
+ if __name__ == "__main__":
178
+ asyncio.run(main())
179
+ ```
180
+
181
+ ### Embeddings
182
+
183
+ ```python
184
+ import asyncio
185
+ from llm_sdk.async_sdk import AsyncSDK
186
+
187
+
188
+ async def main() -> None:
189
+ sdk = AsyncSDK.default()
190
+ sdk.registry.load_plugins()
191
+
192
+ resp = await sdk.embed(
193
+ provider="gemini",
194
+ model="text-multilingual-embedding-002",
195
+ input=["Hola mundo", "Hello world"],
196
+ )
197
+
198
+ print(len(resp.vectors), "vectors")
199
+ print("dim:", len(resp.vectors[0]))
200
+
201
+
202
+ if __name__ == "__main__":
203
+ asyncio.run(main())
204
+ ```
205
+
206
+ ### Listing installed providers (debug)
207
+
208
+ ```python
209
+ from llm_sdk.providers.async_registry import ProviderRegistry
210
+
211
+ reg = ProviderRegistry()
212
+ reg.load_plugins()
213
+
214
+ print(reg.available())
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Configuration
220
+
221
+ llm-sdk uses Pydantic Settings.
222
+
223
+ Example environment variables
224
+
225
+ ```bash
226
+ export LLM_SDK_DEFAULT_PROVIDER="gemini"
227
+ export LLM_SDK_DEFAULT_MODEL="gemini-2.5-flash"
228
+ ```
229
+
230
+ ### Typical config options
231
+
232
+ - Default provider
233
+ - Default model
234
+ - Retry policy (max attempts, delays)
235
+ - Timeouts
236
+ - Provider-specific settings (usually defined in provider plugin packages)
237
+
238
+ ---
239
+
240
+ ### Project Structure
241
+
242
+ Typical structure:
243
+
244
+ ```bash
245
+ llm-sdk/
246
+ ├─ src/
247
+ │ └─ llm_sdk/
248
+ │ ├─ async_sdk.py
249
+ │ ├─ sync_sdk.py
250
+ │ ├─ settings.py
251
+ │ ├─ typing.py
252
+ │ ├─ timeouts.py
253
+ │ ├─ exceptions.py
254
+ │ ├─ retries.py
255
+ │ ├─ plugin_loader.py
256
+ │ ├─ lifecycle.py
257
+ │ ├─ context.py
258
+ │ ├─ domain/
259
+ │ │ ├─ chat.py
260
+ │ │ ├─ embeddings.py
261
+ │ │ └─ models.py
262
+ │ └─ providers/
263
+ │ ├─ async_base.py
264
+ │ ├─ sync_base.py
265
+ │ ├─ async_registry.py
266
+ │ ├─ sync_registry.py
267
+ │ └─ __main__.py
268
+ ├─ tests/
269
+ │ ├─ test_registry.py
270
+ │ ├─ test_retries.py
271
+ │ └─ test_contracts.py
272
+ ├─ pyproject.toml
273
+ └─ README.md
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Setup
279
+
280
+ ### Development
281
+
282
+
283
+ ```bash
284
+ python -m venv venv
285
+ source venv/bin/activate
286
+
287
+ pip install -U pip
288
+ pip install -e ".[dev]"
289
+ ```
290
+
291
+ ### Install a provider plugin in editable mode
292
+
293
+ Example:
294
+
295
+ ```bash
296
+ pip install -e ../llm-sdk-provider-gemini
297
+ ```
298
+
299
+ ### Testing
300
+
301
+ ```bash
302
+ pytest -q
303
+ ```
304
+
305
+ ### Notes
306
+ - Core tests should not require any provider network access
307
+ - Provider plugins are tested independently in their own packages
308
+
309
+ ---
310
+
311
+ ## Deployment
312
+
313
+ ### Build package
314
+
315
+ ```bash
316
+ python -m build
317
+ ```
318
+
319
+ ### Upload to TestPyPI
320
+
321
+ ```bash
322
+ python -m twine upload --repository testpypi dist/*
323
+ ```
324
+
325
+ ### Upload to PyPI
326
+
327
+ ```bash
328
+ python -m twine upload dist/*
329
+ ```
330
+
331
+ ---
332
+
333
+ ## Roadmap
334
+
335
+ - Sync SDK wrapper (LLM) built on top of AsyncSDK
336
+ - More providers (OpenAI, Ollama, Anthropic, etc.)
337
+ - Built-in observability hooks (OpenTelemetry)
338
+ - Tool calling abstraction
339
+ - Response caching
340
+ - Rate limiting middleware
341
+
342
+ - First-class tracing
343
+
344
+ ---
345
+
346
+ ## Contributing
347
+
348
+ PRs are welcome.
349
+
350
+ ### Recommended workflow:
351
+ 1. Fork the repo
352
+ 2. Create a feature branch
353
+ 3. Add tests for changes
354
+ 4. Run pytest
355
+ 5. Submit PR
356
+
357
+ ---
358
+
359
+ ## License
360
+ MIT License
361
+
362
+ ---
363
+
364
+ ## Contact
365
+ Author: Esteban Flores