hugpy-engine 0.2.2__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.
- hugpy_engine-0.2.2/LICENSE +41 -0
- hugpy_engine-0.2.2/PKG-INFO +116 -0
- hugpy_engine-0.2.2/README.md +68 -0
- hugpy_engine-0.2.2/docs/ALLOCATION-MODES.md +174 -0
- hugpy_engine-0.2.2/pyproject.toml +82 -0
- hugpy_engine-0.2.2/setup.cfg +4 -0
- hugpy_engine-0.2.2/src/hugpy_engine/__init__.py +163 -0
- hugpy_engine-0.2.2/src/hugpy_engine/alloc_modes.py +1342 -0
- hugpy_engine-0.2.2/src/hugpy_engine/allocation.py +68 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/__init__.py +0 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/call_api.py +149 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/get_module.py +601 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/reclassify.py +238 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/reconcile.py +628 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/serve/__init__.py +22 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/serve/serve.py +33 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/serve/serve_cli.py +9 -0
- hugpy_engine-0.2.2/src/hugpy_engine/apis/systemd_units.py +9 -0
- hugpy_engine-0.2.2/src/hugpy_engine/backend.py +86 -0
- hugpy_engine-0.2.2/src/hugpy_engine/backends/__init__.py +5 -0
- hugpy_engine-0.2.2/src/hugpy_engine/backends/local.py +163 -0
- hugpy_engine-0.2.2/src/hugpy_engine/catalog.py +99 -0
- hugpy_engine-0.2.2/src/hugpy_engine/catalog_bridge.py +223 -0
- hugpy_engine-0.2.2/src/hugpy_engine/categories.py +132 -0
- hugpy_engine-0.2.2/src/hugpy_engine/chat_context/__init__.py +27 -0
- hugpy_engine-0.2.2/src/hugpy_engine/chat_context/chat_context.py +223 -0
- hugpy_engine-0.2.2/src/hugpy_engine/chat_context/context_budget.py +223 -0
- hugpy_engine-0.2.2/src/hugpy_engine/chat_context/unbounded.py +55 -0
- hugpy_engine-0.2.2/src/hugpy_engine/config/__init__.py +0 -0
- hugpy_engine-0.2.2/src/hugpy_engine/config/main.py +270 -0
- hugpy_engine-0.2.2/src/hugpy_engine/config/models/__init__.py +0 -0
- hugpy_engine-0.2.2/src/hugpy_engine/config/models/model_meta.py +198 -0
- hugpy_engine-0.2.2/src/hugpy_engine/config/models/models_config.py +1629 -0
- hugpy_engine-0.2.2/src/hugpy_engine/config/models/models_default.py +196 -0
- hugpy_engine-0.2.2/src/hugpy_engine/config/models/models_dict.py +73 -0
- hugpy_engine-0.2.2/src/hugpy_engine/contracts.py +44 -0
- hugpy_engine-0.2.2/src/hugpy_engine/dispatch/__init__.py +37 -0
- hugpy_engine-0.2.2/src/hugpy_engine/dispatch/acquire.py +59 -0
- hugpy_engine-0.2.2/src/hugpy_engine/dispatch/activity.py +110 -0
- hugpy_engine-0.2.2/src/hugpy_engine/dispatch/dispatch.py +1151 -0
- hugpy_engine-0.2.2/src/hugpy_engine/draft_models.py +72 -0
- hugpy_engine-0.2.2/src/hugpy_engine/engines.py +44 -0
- hugpy_engine-0.2.2/src/hugpy_engine/eviction.py +662 -0
- hugpy_engine-0.2.2/src/hugpy_engine/generate/__init__.py +16 -0
- hugpy_engine-0.2.2/src/hugpy_engine/generate/coder.py +667 -0
- hugpy_engine-0.2.2/src/hugpy_engine/generate/config.py +187 -0
- hugpy_engine-0.2.2/src/hugpy_engine/generate/generate_runner.py +273 -0
- hugpy_engine-0.2.2/src/hugpy_engine/gguf_election.py +259 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/__init__.py +23 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/__init__.py +23 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/chat_runner.py +245 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/get.py +772 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/__init__.py +9 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/base_runner.py +609 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/ccp_runner.py +332 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/imports/__init__.py +25 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/imports/config.py +16 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/imports/constants.py +38 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/imports/init_imports.py +6 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/imports/utils.py +64 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/python_runner.py +476 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/runners/src/shard_server.py +341 -0
- hugpy_engine-0.2.2/src/hugpy_engine/llama/serve.py +9 -0
- hugpy_engine-0.2.2/src/hugpy_engine/manifest.py +53 -0
- hugpy_engine-0.2.2/src/hugpy_engine/model_classifier.py +382 -0
- hugpy_engine-0.2.2/src/hugpy_engine/model_index/__init__.py +82 -0
- hugpy_engine-0.2.2/src/hugpy_engine/model_index/client.py +101 -0
- hugpy_engine-0.2.2/src/hugpy_engine/model_index/query_registry.py +399 -0
- hugpy_engine-0.2.2/src/hugpy_engine/model_index/repositories.py +260 -0
- hugpy_engine-0.2.2/src/hugpy_engine/model_index/service.py +281 -0
- hugpy_engine-0.2.2/src/hugpy_engine/name_match.py +287 -0
- hugpy_engine-0.2.2/src/hugpy_engine/native/__init__.py +19 -0
- hugpy_engine-0.2.2/src/hugpy_engine/native/build.py +98 -0
- hugpy_engine-0.2.2/src/hugpy_engine/native/fetch.py +194 -0
- hugpy_engine-0.2.2/src/hugpy_engine/native/resolve.py +352 -0
- hugpy_engine-0.2.2/src/hugpy_engine/output_repair.py +212 -0
- hugpy_engine-0.2.2/src/hugpy_engine/peft_adapters.py +286 -0
- hugpy_engine-0.2.2/src/hugpy_engine/placement.py +457 -0
- hugpy_engine-0.2.2/src/hugpy_engine/py.typed +0 -0
- hugpy_engine-0.2.2/src/hugpy_engine/query.py +191 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/__init__.py +25 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/allocator.py +126 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/assure_model_key.py +430 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/categories/__init__.py +22 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/categories/builders.py +163 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/categories/frameworks.py +67 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/device_placement.py +212 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/groups.py +651 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/model_dict_resolver.py +23 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/model_resolver.py +628 -0
- hugpy_engine-0.2.2/src/hugpy_engine/resolvers/remote.py +3873 -0
- hugpy_engine-0.2.2/src/hugpy_engine/routing_diagnostics.py +265 -0
- hugpy_engine-0.2.2/src/hugpy_engine/runtime.py +84 -0
- hugpy_engine-0.2.2/src/hugpy_engine/schemas/__init__.py +0 -0
- hugpy_engine-0.2.2/src/hugpy_engine/schemas/chat_schemas.py +336 -0
- hugpy_engine-0.2.2/src/hugpy_engine/schemas/event_schemas.py +57 -0
- hugpy_engine-0.2.2/src/hugpy_engine/schemas/metadata_schemas.py +62 -0
- hugpy_engine-0.2.2/src/hugpy_engine/schemas/model_schemas.py +101 -0
- hugpy_engine-0.2.2/src/hugpy_engine/schemas/runner_schemas.py +33 -0
- hugpy_engine-0.2.2/src/hugpy_engine/schemas/task_schemas.py +45 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/__init__.py +57 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/chunksum_verify.py +213 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/hot_cache.py +1014 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/load_failure.py +188 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/model_cache.py +218 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/overrides.py +1075 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/policy.py +45 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/profiles.py +364 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/serve.py +930 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/serve_cli.py +79 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/slot_agent.py +2444 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/slots.py +799 -0
- hugpy_engine-0.2.2/src/hugpy_engine/serve/supervisor.py +148 -0
- hugpy_engine-0.2.2/src/hugpy_engine/spill.py +1586 -0
- hugpy_engine-0.2.2/src/hugpy_engine/task_deps.py +67 -0
- hugpy_engine-0.2.2/src/hugpy_engine/tasks.py +349 -0
- hugpy_engine-0.2.2/src/hugpy_engine/utils/__init__.py +0 -0
- hugpy_engine-0.2.2/src/hugpy_engine/utils/json_scavenge.py +111 -0
- hugpy_engine-0.2.2/src/hugpy_engine/utils/no_think.py +325 -0
- hugpy_engine-0.2.2/src/hugpy_engine/wire/__init__.py +0 -0
- hugpy_engine-0.2.2/src/hugpy_engine/wire/chat_schemas.py +66 -0
- hugpy_engine-0.2.2/src/hugpy_engine/wire/config_schemas.py +31 -0
- hugpy_engine-0.2.2/src/hugpy_engine/wire/install_schemas.py +17 -0
- hugpy_engine-0.2.2/src/hugpy_engine/wire/model_schemas.py +43 -0
- hugpy_engine-0.2.2/src/hugpy_engine/wire/request_schemas.py +13 -0
- hugpy_engine-0.2.2/src/hugpy_engine/wire/specs_schemas.py +9 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/PKG-INFO +116 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/SOURCES.txt +183 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/dependency_links.txt +1 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/entry_points.txt +2 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/requires.txt +28 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/scm_file_list.json +179 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/scm_version.json +8 -0
- hugpy_engine-0.2.2/src/hugpy_engine.egg-info/top_level.txt +1 -0
- hugpy_engine-0.2.2/tests/conftest.py +23 -0
- hugpy_engine-0.2.2/tests/test_admission_gate_and_diagnostics.py +178 -0
- hugpy_engine-0.2.2/tests/test_allocation_accuracy.py +257 -0
- hugpy_engine-0.2.2/tests/test_budget_bar_spec.py +179 -0
- hugpy_engine-0.2.2/tests/test_catalog_bridge.py +100 -0
- hugpy_engine-0.2.2/tests/test_central_cap_gating.py +264 -0
- hugpy_engine-0.2.2/tests/test_chat_request_caller.py +40 -0
- hugpy_engine-0.2.2/tests/test_chat_role_alternation.py +535 -0
- hugpy_engine-0.2.2/tests/test_chat_tool_messages_schema.py +113 -0
- hugpy_engine-0.2.2/tests/test_chunksum_verify.py +231 -0
- hugpy_engine-0.2.2/tests/test_comms_foundations.py +113 -0
- hugpy_engine-0.2.2/tests/test_ctx_fit.py +288 -0
- hugpy_engine-0.2.2/tests/test_device_placement.py +151 -0
- hugpy_engine-0.2.2/tests/test_engine_boundary.py +98 -0
- hugpy_engine-0.2.2/tests/test_engine_persisted_resolve.py +295 -0
- hugpy_engine-0.2.2/tests/test_eviction_flow.py +411 -0
- hugpy_engine-0.2.2/tests/test_feasible_distribution_engine.py +89 -0
- hugpy_engine-0.2.2/tests/test_gguf_election.py +301 -0
- hugpy_engine-0.2.2/tests/test_gguf_sharded_effective.py +162 -0
- hugpy_engine-0.2.2/tests/test_hot_cache.py +330 -0
- hugpy_engine-0.2.2/tests/test_image_task_classification.py +405 -0
- hugpy_engine-0.2.2/tests/test_import_policy.py +107 -0
- hugpy_engine-0.2.2/tests/test_load_failure_reason.py +188 -0
- hugpy_engine-0.2.2/tests/test_mmproj_effective_bytes.py +79 -0
- hugpy_engine-0.2.2/tests/test_model_aliases.py +86 -0
- hugpy_engine-0.2.2/tests/test_no_makeroom.py +316 -0
- hugpy_engine-0.2.2/tests/test_no_think.py +329 -0
- hugpy_engine-0.2.2/tests/test_peft_adapter_load.py +379 -0
- hugpy_engine-0.2.2/tests/test_per_device_slot.py +125 -0
- hugpy_engine-0.2.2/tests/test_per_request_alloc.py +86 -0
- hugpy_engine-0.2.2/tests/test_placement_defaults.py +104 -0
- hugpy_engine-0.2.2/tests/test_provision_failure_honesty.py +120 -0
- hugpy_engine-0.2.2/tests/test_registry_attribution.py +144 -0
- hugpy_engine-0.2.2/tests/test_registry_symmetry.py +172 -0
- hugpy_engine-0.2.2/tests/test_resolve_routing_key_reconcile.py +92 -0
- hugpy_engine-0.2.2/tests/test_runner_registry_heartbeat_starvation.py +100 -0
- hugpy_engine-0.2.2/tests/test_slot_load_stall_health.py +228 -0
- hugpy_engine-0.2.2/tests/test_slot_moe_vram_preflight.py +169 -0
- hugpy_engine-0.2.2/tests/test_slot_placement_projection.py +37 -0
- hugpy_engine-0.2.2/tests/test_slot_port_guard.py +50 -0
- hugpy_engine-0.2.2/tests/test_slot_relaunch.py +211 -0
- hugpy_engine-0.2.2/tests/test_spill_ctx_reserve.py +406 -0
- hugpy_engine-0.2.2/tests/test_spill_vision_fit.py +233 -0
- hugpy_engine-0.2.2/tests/test_tasks_registry.py +186 -0
- hugpy_engine-0.2.2/tests/test_tok_s_plausible_ceiling.py +51 -0
- hugpy_engine-0.2.2/tests/test_transformers_placement.py +130 -0
- hugpy_engine-0.2.2/tests/test_video_model_classification.py +289 -0
- hugpy_engine-0.2.2/tests/test_vision_needs_slot.py +242 -0
- hugpy_engine-0.2.2/tests/test_vram_cliff.py +766 -0
- hugpy_engine-0.2.2/tests/test_worker_error_attribution.py +66 -0
- hugpy_engine-0.2.2/tests/test_worker_serve_path_central_only.py +104 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
hugpy — Source-Available License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 putkoff (hugpy.ai). All rights reserved.
|
|
4
|
+
|
|
5
|
+
Permission is granted, free of charge, to use this software ("hugpy") for
|
|
6
|
+
personal and non-commercial purposes, and for time-limited commercial
|
|
7
|
+
evaluation, subject to the following conditions:
|
|
8
|
+
|
|
9
|
+
1. Non-commercial use means use by an individual for personal purposes, or
|
|
10
|
+
use by a non-profit or educational institution for its own internal
|
|
11
|
+
purposes. Any use by, for, or on behalf of a for-profit business or in
|
|
12
|
+
connection with revenue-generating activity is commercial use — including
|
|
13
|
+
internal business use, use in producing goods or services, and use on
|
|
14
|
+
paid engagements.
|
|
15
|
+
|
|
16
|
+
2. Commercial use requires a commercial license from the copyright holder.
|
|
17
|
+
Exception: a business may evaluate the software internally for up to
|
|
18
|
+
thirty (30) days free of charge; continued use after that requires a
|
|
19
|
+
commercial license.
|
|
20
|
+
|
|
21
|
+
3. Redistribution of this software, in source or binary form, modified or
|
|
22
|
+
unmodified, is not permitted without prior written permission from the
|
|
23
|
+
copyright holder. Downloading the software from an official distribution
|
|
24
|
+
channel (PyPI, npm, hugpy.ai) is not redistribution.
|
|
25
|
+
|
|
26
|
+
4. Modification for personal use or internal evaluation is permitted;
|
|
27
|
+
distribution of modified versions is not.
|
|
28
|
+
|
|
29
|
+
5. This notice must be retained in all copies or substantial portions of
|
|
30
|
+
the software.
|
|
31
|
+
|
|
32
|
+
6. Any use outside these terms automatically terminates this license.
|
|
33
|
+
|
|
34
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING
|
|
38
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
39
|
+
IN THE SOFTWARE.
|
|
40
|
+
|
|
41
|
+
For commercial licensing or redistribution permission: https://hugpy.ai
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hugpy-engine
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Hugpy engine: model discovery and classification, allocation and eviction, native llama.cpp and GGUF runners, and the prompt-to-reply inference path with task and placement seams
|
|
5
|
+
Author-email: putkoff <support@hugpy.ai>
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
Project-URL: Homepage, https://hugpy.ai
|
|
8
|
+
Project-URL: Documentation, https://github.com/hugpy/hugpy/blob/main/py/inference/hugpy_engine/README.md
|
|
9
|
+
Project-URL: Repository, https://github.com/hugpy/hugpy
|
|
10
|
+
Project-URL: Source, https://github.com/hugpy/hugpy/tree/main/py/inference/hugpy_engine
|
|
11
|
+
Project-URL: Issues, https://github.com/hugpy/hugpy/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/hugpy/hugpy/releases
|
|
13
|
+
Project-URL: Architecture, https://github.com/hugpy/hugpy/blob/main/PARTITION.md
|
|
14
|
+
Keywords: hugpy,llm,self-hosted,inference,llama.cpp,gguf,transformers,model-serving
|
|
15
|
+
Classifier: Development Status :: 3 - Alpha
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: hugpy-platform
|
|
25
|
+
Requires-Dist: hugpy-control
|
|
26
|
+
Requires-Dist: hugpy-storage
|
|
27
|
+
Requires-Dist: abstract-essentials
|
|
28
|
+
Requires-Dist: pydantic>=2
|
|
29
|
+
Requires-Dist: httpx
|
|
30
|
+
Requires-Dist: requests
|
|
31
|
+
Requires-Dist: huggingface-hub
|
|
32
|
+
Requires-Dist: psutil
|
|
33
|
+
Provides-Extra: gguf
|
|
34
|
+
Requires-Dist: llama-cpp-python; extra == "gguf"
|
|
35
|
+
Provides-Extra: transformers
|
|
36
|
+
Requires-Dist: torch; extra == "transformers"
|
|
37
|
+
Requires-Dist: transformers; extra == "transformers"
|
|
38
|
+
Requires-Dist: accelerate; extra == "transformers"
|
|
39
|
+
Requires-Dist: safetensors; extra == "transformers"
|
|
40
|
+
Provides-Extra: finetune
|
|
41
|
+
Requires-Dist: peft; extra == "finetune"
|
|
42
|
+
Provides-Extra: index
|
|
43
|
+
Requires-Dist: psycopg[binary]; extra == "index"
|
|
44
|
+
Provides-Extra: test
|
|
45
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
46
|
+
Requires-Dist: pytest-timeout; extra == "test"
|
|
47
|
+
Dynamic: license-file
|
|
48
|
+
|
|
49
|
+
# hugpy-engine
|
|
50
|
+
|
|
51
|
+
`hugpy-engine` is the standalone boundary for Hugpy's complete inference path:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
prompt/messages
|
|
55
|
+
-> model discovery and resolution
|
|
56
|
+
-> RAM/VRAM allocation and admission
|
|
57
|
+
-> engine and runner selection/loading
|
|
58
|
+
-> generation and continuation
|
|
59
|
+
-> streamed events or a completed reply
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The package is split by responsibility:
|
|
63
|
+
|
|
64
|
+
- `catalog` — discovered models, task/media/default model resolution;
|
|
65
|
+
- `allocation` — feasible modes, default placement, spill and admission plans;
|
|
66
|
+
- `engines` — native llama.cpp discovery and GGUF runner lifecycle;
|
|
67
|
+
- `runtime` — request resolution, execution, runner caching and eviction;
|
|
68
|
+
- `query` — prompt/messages to streamed events, text, or `QueryResult`;
|
|
69
|
+
- `backend` — the injection contract joining those layers to an implementation.
|
|
70
|
+
|
|
71
|
+
The package imports CPU-only: `import hugpy_engine` never loads llama_cpp,
|
|
72
|
+
torch, transformers or peft. Those arrive through extras and are imported by
|
|
73
|
+
the runner that needs them:
|
|
74
|
+
|
|
75
|
+
| extra | provides |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `hugpy-engine[gguf]` | in-process GGUF inference via `llama-cpp-python` |
|
|
78
|
+
| `hugpy-engine[transformers]` | the transformers text-generation runner |
|
|
79
|
+
| `hugpy-engine[finetune]` | PEFT adapter loading |
|
|
80
|
+
| `hugpy-engine[index]` | the optional Postgres model index |
|
|
81
|
+
|
|
82
|
+
The default backend is the in-process `LocalBackend` (`hugpy_engine.backends`),
|
|
83
|
+
built from the engine's own catalog, allocation, native-engine and dispatch
|
|
84
|
+
modules; `configure_backend(...)` / `backend_scope(...)` swap in another
|
|
85
|
+
`InferenceBackend` (a fake in tests, a remote proxy in a thin client).
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from hugpy_engine import query_sync
|
|
89
|
+
|
|
90
|
+
reply = query_sync("Explain tensor parallelism", model_key="my-model")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Async callers use `await query(...)`. `stream_query(...)` yields engine events;
|
|
94
|
+
`query_result(...)` retains request ID, finish reason, usage, and timings.
|
|
95
|
+
|
|
96
|
+
## Seams (what the engine asks of the packages above it)
|
|
97
|
+
|
|
98
|
+
- `hugpy_engine.placement` — Protocols + `get_*()/set_*()` providers for
|
|
99
|
+
everything the engine asks about the fleet (worker registry and key forms,
|
|
100
|
+
worker HTTP transport/breaker, eviction telemetry ledger, blocklist, model
|
|
101
|
+
metrics, priority groups). Null defaults mean "no fleet"; `hugpy_fleet`
|
|
102
|
+
implements them and the server wires them.
|
|
103
|
+
- `hugpy_engine.tasks` — the task-runner registry. Media and video runners
|
|
104
|
+
plug in with `register_task(task, runner=..., build_request=...,
|
|
105
|
+
frameworks=(...), extra=..., source=...)`; `FRAMEWORK_RUNNERS`,
|
|
106
|
+
`MODEL_REQUEST_BUILDERS` and `KNOWN_TASKS_REGISTRY` in
|
|
107
|
+
`hugpy_engine.resolvers.categories` are live views over it. Packages may
|
|
108
|
+
also expose a `hugpy_engine.tasks` entry point (a zero-arg register
|
|
109
|
+
function); the engine loads those on first use.
|
|
110
|
+
- `hugpy_engine.catalog_bridge` — installs the engine's registry as
|
|
111
|
+
`hugpy_storage`'s catalog source, the hot cache as its serve-path hook, and
|
|
112
|
+
refreshes discovery on `hugpy_control.bus` `catalog.changed` events.
|
|
113
|
+
`LocalBackend` installs it lazily.
|
|
114
|
+
- `hugpy_engine.name_match` — the pure eliminate-then-rank name pipeline
|
|
115
|
+
(`resolve_name`, `Candidate`) that `assure_model_key` uses; the oracle
|
|
116
|
+
re-exports it.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# hugpy-engine
|
|
2
|
+
|
|
3
|
+
`hugpy-engine` is the standalone boundary for Hugpy's complete inference path:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
prompt/messages
|
|
7
|
+
-> model discovery and resolution
|
|
8
|
+
-> RAM/VRAM allocation and admission
|
|
9
|
+
-> engine and runner selection/loading
|
|
10
|
+
-> generation and continuation
|
|
11
|
+
-> streamed events or a completed reply
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The package is split by responsibility:
|
|
15
|
+
|
|
16
|
+
- `catalog` — discovered models, task/media/default model resolution;
|
|
17
|
+
- `allocation` — feasible modes, default placement, spill and admission plans;
|
|
18
|
+
- `engines` — native llama.cpp discovery and GGUF runner lifecycle;
|
|
19
|
+
- `runtime` — request resolution, execution, runner caching and eviction;
|
|
20
|
+
- `query` — prompt/messages to streamed events, text, or `QueryResult`;
|
|
21
|
+
- `backend` — the injection contract joining those layers to an implementation.
|
|
22
|
+
|
|
23
|
+
The package imports CPU-only: `import hugpy_engine` never loads llama_cpp,
|
|
24
|
+
torch, transformers or peft. Those arrive through extras and are imported by
|
|
25
|
+
the runner that needs them:
|
|
26
|
+
|
|
27
|
+
| extra | provides |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `hugpy-engine[gguf]` | in-process GGUF inference via `llama-cpp-python` |
|
|
30
|
+
| `hugpy-engine[transformers]` | the transformers text-generation runner |
|
|
31
|
+
| `hugpy-engine[finetune]` | PEFT adapter loading |
|
|
32
|
+
| `hugpy-engine[index]` | the optional Postgres model index |
|
|
33
|
+
|
|
34
|
+
The default backend is the in-process `LocalBackend` (`hugpy_engine.backends`),
|
|
35
|
+
built from the engine's own catalog, allocation, native-engine and dispatch
|
|
36
|
+
modules; `configure_backend(...)` / `backend_scope(...)` swap in another
|
|
37
|
+
`InferenceBackend` (a fake in tests, a remote proxy in a thin client).
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from hugpy_engine import query_sync
|
|
41
|
+
|
|
42
|
+
reply = query_sync("Explain tensor parallelism", model_key="my-model")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Async callers use `await query(...)`. `stream_query(...)` yields engine events;
|
|
46
|
+
`query_result(...)` retains request ID, finish reason, usage, and timings.
|
|
47
|
+
|
|
48
|
+
## Seams (what the engine asks of the packages above it)
|
|
49
|
+
|
|
50
|
+
- `hugpy_engine.placement` — Protocols + `get_*()/set_*()` providers for
|
|
51
|
+
everything the engine asks about the fleet (worker registry and key forms,
|
|
52
|
+
worker HTTP transport/breaker, eviction telemetry ledger, blocklist, model
|
|
53
|
+
metrics, priority groups). Null defaults mean "no fleet"; `hugpy_fleet`
|
|
54
|
+
implements them and the server wires them.
|
|
55
|
+
- `hugpy_engine.tasks` — the task-runner registry. Media and video runners
|
|
56
|
+
plug in with `register_task(task, runner=..., build_request=...,
|
|
57
|
+
frameworks=(...), extra=..., source=...)`; `FRAMEWORK_RUNNERS`,
|
|
58
|
+
`MODEL_REQUEST_BUILDERS` and `KNOWN_TASKS_REGISTRY` in
|
|
59
|
+
`hugpy_engine.resolvers.categories` are live views over it. Packages may
|
|
60
|
+
also expose a `hugpy_engine.tasks` entry point (a zero-arg register
|
|
61
|
+
function); the engine loads those on first use.
|
|
62
|
+
- `hugpy_engine.catalog_bridge` — installs the engine's registry as
|
|
63
|
+
`hugpy_storage`'s catalog source, the hot cache as its serve-path hook, and
|
|
64
|
+
refreshes discovery on `hugpy_control.bus` `catalog.changed` events.
|
|
65
|
+
`LocalBackend` installs it lazily.
|
|
66
|
+
- `hugpy_engine.name_match` — the pure eliminate-then-rank name pipeline
|
|
67
|
+
(`resolve_name`, `Candidate`) that `assure_model_key` uses; the oracle
|
|
68
|
+
re-exports it.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Allocation modes — where your model's memory lives
|
|
2
|
+
|
|
3
|
+
Every model gets **one of five modes** that says how its weights (and KV
|
|
4
|
+
context) are placed across the GPU (VRAM) and system RAM. Pick the intent; the
|
|
5
|
+
fleet does the math.
|
|
6
|
+
|
|
7
|
+
> **The promise:** a *slow* mode you chose is yours; a model with *no working
|
|
8
|
+
> mode at all* is our bug. The default never OOMs — a blank model serves.
|
|
9
|
+
|
|
10
|
+
## The five modes
|
|
11
|
+
|
|
12
|
+
| mode | what it does | when it refuses ("bust") |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| **gpu-only** | Every layer on the GPU, no spill. Fastest when it fits. | Won't fit the GPU (even after evicting idle residents) → refuse. Never a half-load. |
|
|
15
|
+
| **ram-only** | Everything in system RAM; the GPU is never touched (binds the CPU even when a GPU is present). | Won't fit RAM → refuse. |
|
|
16
|
+
| **max-gpu** | *The default.* As much GPU as is available and needed, the rest spills to RAM. Zero knobs — "use my GPU, spill the rest". | Only when GPU + RAM together can't hold it. |
|
|
17
|
+
| **max-ram** | Mirror of max-gpu: fill RAM first, only the overflow rides the GPU. For keeping cards free while big models stay warm. | Only when RAM + GPU together can't hold it. |
|
|
18
|
+
| **explicit** | You set the targets: a VRAM and/or RAM budget, a **leniency %**, and a **priority device** (`gpu` default, or `ram`), plus the tolerance bands/priority you already know. | Can't hit the target *even at the loosened floor* → refuse. |
|
|
19
|
+
|
|
20
|
+
`max-gpu` and `max-ram` are internally explicit-with-generous-leniency — but
|
|
21
|
+
they stay flat, named modes on purpose: simple intent gets a simple pick; the
|
|
22
|
+
moment you want to tune numbers, you reach for `explicit`.
|
|
23
|
+
|
|
24
|
+
## Leniency — how much off-device you tolerate
|
|
25
|
+
|
|
26
|
+
**N% leniency = up to N% of the MODEL may land off its ideal device before we
|
|
27
|
+
refuse.**
|
|
28
|
+
|
|
29
|
+
Example: `100% GPU target + 30% leniency`
|
|
30
|
+
- Try 100% on GPU first.
|
|
31
|
+
- Under pressure, degrade step by step — 90/10, 80/20 … — down to the **floor:
|
|
32
|
+
70% GPU / 30% RAM**.
|
|
33
|
+
- If even 70/30 won't fit, the load refuses **honestly**, naming the mode and
|
|
34
|
+
the floor (e.g. *"explicit: even the loosened floor won't fit — target 100%
|
|
35
|
+
of the model on GPU with 30% leniency gives a floor of 70% …"*).
|
|
36
|
+
|
|
37
|
+
No leniency set = exact target or refuse (no undeclared tolerance is ever
|
|
38
|
+
assumed). Degradation only happens under real contention — a model that fits
|
|
39
|
+
at its target always gets its target.
|
|
40
|
+
|
|
41
|
+
## Engine coverage
|
|
42
|
+
|
|
43
|
+
Two transformers families load differently, so they honor the modes by
|
|
44
|
+
different mechanisms:
|
|
45
|
+
|
|
46
|
+
- **transformers TEXT** (`AutoModelFor*`: the causal-LM generator, the flan /
|
|
47
|
+
seq2seq / summarization back-ends, the vision-language coder) place weights
|
|
48
|
+
with **accelerate** — `device_map="auto"` + a `max_memory` budget map. Every
|
|
49
|
+
mode maps onto that budget map.
|
|
50
|
+
- **diffusers** (text-to-image / image-to-image pipelines) do **not** take
|
|
51
|
+
`device_map`/`max_memory`. They spill via diffusers' own **CPU-offload API**
|
|
52
|
+
instead (see the note below the table).
|
|
53
|
+
|
|
54
|
+
| mode | GGUF (llama.cpp) | transformers TEXT (accelerate) | diffusers (image) |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| gpu-only | ✅ | ✅ whole model on the card (no CPU budget) | ✅ `.to(cuda)` |
|
|
57
|
+
| ram-only | ✅ | ✅ CPU placement (gpu budget 0) | ✅ `enable_sequential_cpu_offload()` |
|
|
58
|
+
| max-gpu | ✅ | ✅ accelerate fit-and-spill | ✅ `.to(cuda)` (auto/default) |
|
|
59
|
+
| max-ram | ✅ | ✅ RAM-priority `max_memory` [^purerram] | ✅ `enable_model_cpu_offload()` |
|
|
60
|
+
| explicit | ✅ | ❌ GGUF-only (banded leniency floor has no transformers analogue) | ❌ GGUF-only (same rationale) |
|
|
61
|
+
|
|
62
|
+
[^purerram]: **Pure-RAM caveat.** Without a resolved `model_need_bytes` the
|
|
63
|
+
transformers loaders take the SAFE pure-RAM path (the whole model on the CPU) —
|
|
64
|
+
they do not yet compute the RAM-first / GPU-overflow split. A follow-up may add
|
|
65
|
+
overflow-to-GPU sizing; until then max-ram on a non-GGUF text model means "RAM
|
|
66
|
+
first" without spilling the remainder onto the card when the size is unknown.
|
|
67
|
+
|
|
68
|
+
**Loader-level vs central gate.** Slice C wired the transformers gap loaders to
|
|
69
|
+
the spill seam, so at the WORKER a transformers text model honors max-ram
|
|
70
|
+
(RAM-priority `max_memory`) and the gpu-only / ram-only / max-gpu placement
|
|
71
|
+
intents. **Central now accepts max-ram for non-GGUF models** (operator-approved
|
|
72
|
+
2026-07-24): the engine gate at `/assign` was opened for the max-ram *mode*
|
|
73
|
+
because all three gap loaders honor it (text via `transformers_max_memory`'s
|
|
74
|
+
RAM-priority branch, imagegen via `enable_model_cpu_offload`). **`explicit`
|
|
75
|
+
stays GGUF-only at the central gate** — its banded leniency floor is a
|
|
76
|
+
llama.cpp concept with no transformers analogue, so admitting it would break the
|
|
77
|
+
mode's promise. The remaining GGUF-only knobs (`gpu_mem_gib` / `cpu_mem_gib` /
|
|
78
|
+
`threads` / `tensor_split` / the t21 bands / MoE `n_cpu_moe`) stay refused for
|
|
79
|
+
non-GGUF exactly as before.
|
|
80
|
+
|
|
81
|
+
**diffusers offload mechanism.** A diffusers pipeline can't shard by a
|
|
82
|
+
`max_memory` map, so the honest spill is diffusers' offload API, chosen from the
|
|
83
|
+
SAME placement seam (`spill.n_gpu_layers_intent` / `alloc_mode_env`):
|
|
84
|
+
- CPU-leaning intent (ram-only / `n_gpu_layers` `off`/`0`) →
|
|
85
|
+
`enable_sequential_cpu_offload()` — submodules stream one at a time,
|
|
86
|
+
smallest VRAM footprint (slowest).
|
|
87
|
+
- max-ram → `enable_model_cpu_offload()` — whole submodules ride RAM, pulled to
|
|
88
|
+
the card only while active (big model, one consumer GPU, no OOM).
|
|
89
|
+
- gpu-only / auto / no intent → today's `.to(cuda)` — byte-identical when the
|
|
90
|
+
seam is silent.
|
|
91
|
+
- A pipeline class without the requested offload method is a **genuine
|
|
92
|
+
capability gap**: it is logged once and falls back to `.to(cuda)` rather than
|
|
93
|
+
silently ignoring the mode.
|
|
94
|
+
|
|
95
|
+
`explicit`'s numeric leniency floor is a llama.cpp-only concept with no
|
|
96
|
+
transformers/diffusers analogue, so `explicit` is refused for non-GGUF at the
|
|
97
|
+
central gate and is not a reachable live path for transformers. (Were the gate
|
|
98
|
+
opened, a transformers/diffusers model under explicit would get only the
|
|
99
|
+
budgeted fit-and-spill, not the banded degrade-to-floor — which is exactly why
|
|
100
|
+
the mode's promise can't be kept there and the gate stays closed.)
|
|
101
|
+
|
|
102
|
+
## MoE models — the expert split (measured, on by default)
|
|
103
|
+
|
|
104
|
+
A Mixture-of-Experts GGUF is mostly **cold expert tensors**: on
|
|
105
|
+
Qwen3-Coder-Next (80B-A3B class, 512 experts / 10 used per token) the expert
|
|
106
|
+
FFN tensors are ~43.6 GiB of the ~45.1 GiB file — the always-hot
|
|
107
|
+
attention/shared/KV share is only ~1.5 GiB. Splitting **by kind of bytes**
|
|
108
|
+
instead of by whole layers changes everything:
|
|
109
|
+
|
|
110
|
+
| plan (ae / RTX 3090, coder-next) | tok/s | VRAM |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| naive layer split (autofit, 17/48 layers) | ~15.2 | 16.6 GiB |
|
|
113
|
+
| **MoE split** (`n_gpu_layers=-1` + `--n-cpu-moe 999`) | **~24.1** | **3.2 GiB** |
|
|
114
|
+
|
|
115
|
+
+59% throughput AND 5× less VRAM — a strict improvement, so it is the
|
|
116
|
+
**default** for the hybrid case:
|
|
117
|
+
|
|
118
|
+
- **Auto policy** (no knobs): a detected-MoE GGUF whose whole file does **not**
|
|
119
|
+
fit the card (exactly when autofit would have produced a partial layer
|
|
120
|
+
split) serves with all layers on the GPU and the expert tensors on CPU.
|
|
121
|
+
*Whole model fits → fully on GPU, unchanged. Dense model → byte-identical to
|
|
122
|
+
before (no expert tensors, nothing to split).* Detection is the GGUF header
|
|
123
|
+
the loader already parses: `expert_count > 0` is a MoE; the expert tensors
|
|
124
|
+
are the `blk.<i>.ffn_*_exps.*` names (`_exps` is the per-tensor expert bit).
|
|
125
|
+
- **The knob**: `n_cpu_moe` — a first-class serve override / spill key (like
|
|
126
|
+
`n_gpu_layers`): the number of MoE layers whose expert tensors stay on CPU
|
|
127
|
+
(`999` = all, `0` = experts on GPU). An explicit value always wins over the
|
|
128
|
+
auto policy, and explicit `n_gpu_layers` designations (gpu-only/ram-only or
|
|
129
|
+
a layer count) always win over the auto split.
|
|
130
|
+
- **Fit/feasibility price the split**: probes, the ⭐ boot load, admission and
|
|
131
|
+
central's feasibility judge a MoE by its **non-expert GPU share** (+KV) when
|
|
132
|
+
the split governs — a 41.6 GB MoE on an empty 24 GB card *fits* (needs
|
|
133
|
+
~3 GiB of VRAM); its expert bytes are checked against host RAM instead.
|
|
134
|
+
- **Engine**: needs a native `llama-server` with `--n-cpu-moe` (probed once;
|
|
135
|
+
an older binary or the `llama_cpp.server` python fallback degrades to the
|
|
136
|
+
layer-split behavior with one log line — never a crash).
|
|
137
|
+
|
|
138
|
+
**Coexistence note**: ae's worker unit currently carries
|
|
139
|
+
`LLAMA_ARG_N_CPU_MOE=999` (the transition-era env hack that proved the win).
|
|
140
|
+
Explicit `--n-cpu-moe` argv beats the env in llama-server, so this feature is
|
|
141
|
+
correct with or without it — the env line can be removed once this ships.
|
|
142
|
+
|
|
143
|
+
## Legacy names (the honest rename)
|
|
144
|
+
|
|
145
|
+
Old controls were misleadingly named; existing settings keep working — old
|
|
146
|
+
names are accepted on input, resolved, and never written back:
|
|
147
|
+
|
|
148
|
+
| old name / setting | is now | why |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| **autofit** ({} / no knobs) | **max-gpu** | it always was "as much GPU as fits, spill the rest" |
|
|
151
|
+
| **Max GPU** (`n_gpu_layers: -1`) | **gpu-only** | it was all-or-OOM, not "maximize" — now it refuses instead of crashing |
|
|
152
|
+
| **CPU only** (`n_gpu_layers: "off"`) | **ram-only** | RAM is what it actually binds |
|
|
153
|
+
| **budget** / **bands** (chaos) | **explicit** | a budget/band IS an explicit allocation |
|
|
154
|
+
|
|
155
|
+
Nothing on the wire changed for these three: `gpu-only` still rides
|
|
156
|
+
`n_gpu_layers: -1`, `ram-only` still rides `"off"`, `max-gpu` is still `{}`.
|
|
157
|
+
Your `serve_overrides.json` is never rewritten — the mode is **derived at read
|
|
158
|
+
time** (`-1` → gpu-only, `0/"off"` → ram-only, budgets/bands → explicit, unset
|
|
159
|
+
→ max-gpu).
|
|
160
|
+
|
|
161
|
+
## Old workers
|
|
162
|
+
|
|
163
|
+
`max-ram` and `explicit` ride new spill keys (`alloc_mode`, `leniency_pct`,
|
|
164
|
+
`priority_device`), and the MoE `n_cpu_moe` knob rides the same gate.
|
|
165
|
+
Central only emits them to workers running **0.1.203+**;
|
|
166
|
+
an older worker gets max-gpu (autofit) for that request and the downgrade is
|
|
167
|
+
logged — your persisted choice is kept and applies the moment the worker
|
|
168
|
+
updates. A selected mode is never a silent dead knob.
|
|
169
|
+
|
|
170
|
+
## Protection is unchanged
|
|
171
|
+
|
|
172
|
+
Modes reorder *placement*, never protection: 🔒 static residents and models
|
|
173
|
+
actively answering are never evicted to make room, whatever mode the incoming
|
|
174
|
+
model carries.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "setuptools-scm>=8"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hugpy-engine"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Hugpy engine: model discovery and classification, allocation and eviction, native llama.cpp and GGUF runners, and the prompt-to-reply inference path with task and placement seams"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "LicenseRef-Proprietary"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "putkoff", email = "support@hugpy.ai" }]
|
|
14
|
+
keywords = [
|
|
15
|
+
"hugpy",
|
|
16
|
+
"llm",
|
|
17
|
+
"self-hosted",
|
|
18
|
+
"inference",
|
|
19
|
+
"llama.cpp",
|
|
20
|
+
"gguf",
|
|
21
|
+
"transformers",
|
|
22
|
+
"model-serving",
|
|
23
|
+
]
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Development Status :: 3 - Alpha",
|
|
26
|
+
"Intended Audience :: Developers",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
30
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
"hugpy-platform",
|
|
34
|
+
"hugpy-control",
|
|
35
|
+
"hugpy-storage",
|
|
36
|
+
"abstract-essentials",
|
|
37
|
+
"pydantic>=2",
|
|
38
|
+
"httpx",
|
|
39
|
+
"requests",
|
|
40
|
+
"huggingface-hub",
|
|
41
|
+
"psutil",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://hugpy.ai"
|
|
46
|
+
Documentation = "https://github.com/hugpy/hugpy/blob/main/py/inference/hugpy_engine/README.md"
|
|
47
|
+
Repository = "https://github.com/hugpy/hugpy"
|
|
48
|
+
Source = "https://github.com/hugpy/hugpy/tree/main/py/inference/hugpy_engine"
|
|
49
|
+
Issues = "https://github.com/hugpy/hugpy/issues"
|
|
50
|
+
Changelog = "https://github.com/hugpy/hugpy/releases"
|
|
51
|
+
Architecture = "https://github.com/hugpy/hugpy/blob/main/PARTITION.md"
|
|
52
|
+
|
|
53
|
+
[project.optional-dependencies]
|
|
54
|
+
# In-process GGUF inference (LlamaCppPythonRunner). Without it the engine
|
|
55
|
+
# still serves GGUF models through llama-server slots or remote workers.
|
|
56
|
+
gguf = ["llama-cpp-python"]
|
|
57
|
+
# transformers text-generation runner (DeepCoderChatRunner).
|
|
58
|
+
transformers = ["torch", "transformers", "accelerate", "safetensors"]
|
|
59
|
+
# PEFT adapter loading on top of a transformers base.
|
|
60
|
+
finetune = ["peft"]
|
|
61
|
+
# Postgres-backed model index (HUGPY_REGISTRY_DB=pg); inert without it.
|
|
62
|
+
index = ["psycopg[binary]"]
|
|
63
|
+
test = ["pytest>=8", "pytest-timeout"]
|
|
64
|
+
|
|
65
|
+
[project.scripts]
|
|
66
|
+
hugpy-serve = "hugpy_engine.serve.serve_cli:main"
|
|
67
|
+
|
|
68
|
+
[tool.setuptools.packages.find]
|
|
69
|
+
where = ["src"]
|
|
70
|
+
|
|
71
|
+
[tool.setuptools.package-data]
|
|
72
|
+
hugpy_engine = ["py.typed"]
|
|
73
|
+
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
# Lockstep workspace version (2026-09-22): every in-tree hugpy-* distribution
|
|
76
|
+
# takes ONE version from the workspace git tag (vX.Y.Z at the repo root), so a
|
|
77
|
+
# release is a tag and a build always carries the commit it came from
|
|
78
|
+
# (X.Y.Z.devN+g<sha>[.dirty] between tags). A checkout without git metadata
|
|
79
|
+
# builds as 0.0.0+unknown, which central refuses to advertise to workers.
|
|
80
|
+
[tool.setuptools_scm]
|
|
81
|
+
root = "../../.."
|
|
82
|
+
fallback_version = "0.0.0+unknown"
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Standalone Hugpy inference boundary.
|
|
2
|
+
|
|
3
|
+
Prompt/messages -> model discovery and resolution -> RAM/VRAM allocation ->
|
|
4
|
+
engine/runner selection -> generation -> streamed events or a completed reply.
|
|
5
|
+
|
|
6
|
+
The package imports CPU-only: llama_cpp / torch / transformers / peft load
|
|
7
|
+
lazily inside the runner that needs them (``pip install hugpy-engine[gguf]``,
|
|
8
|
+
``[transformers]``, ``[finetune]``). Engine-owned contracts (task capability
|
|
9
|
+
map, catalog vocabulary, manifest helpers, wire schemas, the placement and
|
|
10
|
+
task-plugin seams) are exposed lazily via ``__getattr__`` so ``import
|
|
11
|
+
hugpy_engine`` stays light.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import importlib
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from importlib.metadata import version as _package_version
|
|
20
|
+
|
|
21
|
+
__version__ = _package_version("hugpy-engine")
|
|
22
|
+
except Exception:
|
|
23
|
+
__version__ = "0.0.0+unknown" # source tree without metadata
|
|
24
|
+
|
|
25
|
+
from .allocation import (
|
|
26
|
+
allocation_spill,
|
|
27
|
+
choose_allocation,
|
|
28
|
+
feasible_allocations,
|
|
29
|
+
plan_admission,
|
|
30
|
+
resource_status,
|
|
31
|
+
)
|
|
32
|
+
from .backend import InferenceBackend, backend_scope, configure_backend, get_backend
|
|
33
|
+
from .catalog import get_model, list_models, refresh_models, resolve_model, text_chat_task
|
|
34
|
+
from .contracts import ModelDescriptor, QueryError, QueryResult
|
|
35
|
+
from .engines import (
|
|
36
|
+
build_native_engine,
|
|
37
|
+
evict_llama_runner,
|
|
38
|
+
install_native_engine,
|
|
39
|
+
llama_runner,
|
|
40
|
+
loaded_llama_runners,
|
|
41
|
+
native_engine_binaries,
|
|
42
|
+
native_engine_status,
|
|
43
|
+
)
|
|
44
|
+
from .query import query, query_result, query_result_sync, query_sync, stream_query
|
|
45
|
+
from .runtime import (
|
|
46
|
+
clear_models,
|
|
47
|
+
evict_model,
|
|
48
|
+
execute_request,
|
|
49
|
+
loaded_models,
|
|
50
|
+
loading_models,
|
|
51
|
+
resolve_request,
|
|
52
|
+
runner_for,
|
|
53
|
+
stream_chat_request,
|
|
54
|
+
stream_request,
|
|
55
|
+
supported_tasks,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Engine-owned contracts and seams, resolved on first attribute access
|
|
59
|
+
# (PEP 562) so the package import never touches discovery or pydantic.
|
|
60
|
+
_LAZY = {
|
|
61
|
+
# task capability map (consumed by fleet, oracle, server)
|
|
62
|
+
"TASK_DEPS": ("hugpy_engine.task_deps", "TASK_DEPS"),
|
|
63
|
+
"task_capabilities": ("hugpy_engine.task_deps", "task_capabilities"),
|
|
64
|
+
# catalog vocabulary
|
|
65
|
+
"HF_TASK_TO_TASKS": ("hugpy_engine.categories", "HF_TASK_TO_TASKS"),
|
|
66
|
+
"RUNNER_PAIRS": ("hugpy_engine.categories", "RUNNER_PAIRS"),
|
|
67
|
+
"TASK_DEFAULTS": ("hugpy_engine.categories", "TASK_DEFAULTS"),
|
|
68
|
+
"MEDIA_DEFAULTS": ("hugpy_engine.categories", "MEDIA_DEFAULTS"),
|
|
69
|
+
# manifest helpers
|
|
70
|
+
"load_manifest": ("hugpy_engine.manifest", "load_manifest"),
|
|
71
|
+
"load_manifest_or_empty": ("hugpy_engine.manifest", "load_manifest_or_empty"),
|
|
72
|
+
"save_manifest": ("hugpy_engine.manifest", "save_manifest"),
|
|
73
|
+
"key_for_hub_id": ("hugpy_engine.manifest", "key_for_hub_id"),
|
|
74
|
+
"upsert_model": ("hugpy_engine.manifest", "upsert_model"),
|
|
75
|
+
# seams
|
|
76
|
+
"placement": ("hugpy_engine.placement", None),
|
|
77
|
+
"tasks": ("hugpy_engine.tasks", None),
|
|
78
|
+
"register_task": ("hugpy_engine.tasks", "register_task"),
|
|
79
|
+
"runner_for_task": ("hugpy_engine.tasks", "runner_for_task"),
|
|
80
|
+
"request_builder_for_task": ("hugpy_engine.tasks", "request_builder_for_task"),
|
|
81
|
+
"catalog_bridge": ("hugpy_engine.catalog_bridge", None),
|
|
82
|
+
"LocalBackend": ("hugpy_engine.backends.local", "LocalBackend"),
|
|
83
|
+
# wire schema modules (pydantic bodies shared with the HTTP layer)
|
|
84
|
+
"wire": ("hugpy_engine.wire", None),
|
|
85
|
+
"schemas": ("hugpy_engine.schemas", None),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def __getattr__(name: str):
|
|
90
|
+
target = _LAZY.get(name)
|
|
91
|
+
if target is None:
|
|
92
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
93
|
+
module = importlib.import_module(target[0])
|
|
94
|
+
value = module if target[1] is None else getattr(module, target[1])
|
|
95
|
+
globals()[name] = value
|
|
96
|
+
return value
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def __dir__():
|
|
100
|
+
return sorted(set(globals()) | set(_LAZY))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
__all__ = [
|
|
104
|
+
"HF_TASK_TO_TASKS",
|
|
105
|
+
"InferenceBackend",
|
|
106
|
+
"LocalBackend",
|
|
107
|
+
"MEDIA_DEFAULTS",
|
|
108
|
+
"ModelDescriptor",
|
|
109
|
+
"QueryError",
|
|
110
|
+
"QueryResult",
|
|
111
|
+
"RUNNER_PAIRS",
|
|
112
|
+
"TASK_DEFAULTS",
|
|
113
|
+
"TASK_DEPS",
|
|
114
|
+
"allocation_spill",
|
|
115
|
+
"backend_scope",
|
|
116
|
+
"build_native_engine",
|
|
117
|
+
"catalog_bridge",
|
|
118
|
+
"choose_allocation",
|
|
119
|
+
"clear_models",
|
|
120
|
+
"configure_backend",
|
|
121
|
+
"evict_llama_runner",
|
|
122
|
+
"evict_model",
|
|
123
|
+
"execute_request",
|
|
124
|
+
"feasible_allocations",
|
|
125
|
+
"get_backend",
|
|
126
|
+
"get_model",
|
|
127
|
+
"install_native_engine",
|
|
128
|
+
"key_for_hub_id",
|
|
129
|
+
"list_models",
|
|
130
|
+
"llama_runner",
|
|
131
|
+
"load_manifest",
|
|
132
|
+
"load_manifest_or_empty",
|
|
133
|
+
"loaded_llama_runners",
|
|
134
|
+
"loaded_models",
|
|
135
|
+
"loading_models",
|
|
136
|
+
"native_engine_binaries",
|
|
137
|
+
"native_engine_status",
|
|
138
|
+
"placement",
|
|
139
|
+
"plan_admission",
|
|
140
|
+
"query",
|
|
141
|
+
"query_result",
|
|
142
|
+
"query_result_sync",
|
|
143
|
+
"query_sync",
|
|
144
|
+
"refresh_models",
|
|
145
|
+
"register_task",
|
|
146
|
+
"request_builder_for_task",
|
|
147
|
+
"resolve_model",
|
|
148
|
+
"resolve_request",
|
|
149
|
+
"resource_status",
|
|
150
|
+
"runner_for",
|
|
151
|
+
"runner_for_task",
|
|
152
|
+
"save_manifest",
|
|
153
|
+
"schemas",
|
|
154
|
+
"stream_chat_request",
|
|
155
|
+
"stream_query",
|
|
156
|
+
"stream_request",
|
|
157
|
+
"supported_tasks",
|
|
158
|
+
"task_capabilities",
|
|
159
|
+
"tasks",
|
|
160
|
+
"text_chat_task",
|
|
161
|
+
"upsert_model",
|
|
162
|
+
"wire",
|
|
163
|
+
]
|