clm-kernel 0.0.0__py3-none-any.whl
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.
- clm/__init__.py +230 -0
- clm/__main__.py +25 -0
- clm/cross_cutting/__init__.py +50 -0
- clm/cross_cutting/_test_runner.py +36 -0
- clm/cross_cutting/async_utils.py +25 -0
- clm/cross_cutting/cel_builder.py +123 -0
- clm/cross_cutting/cel_converter.py +697 -0
- clm/cross_cutting/cel_engine.py +252 -0
- clm/cross_cutting/cel_ops.py +72 -0
- clm/cross_cutting/cel_ops_db.py +157 -0
- clm/cross_cutting/cel_ops_files.py +99 -0
- clm/cross_cutting/cel_ops_state.py +71 -0
- clm/cross_cutting/cel_ops_strings.py +64 -0
- clm/cross_cutting/cel_resolver.py +63 -0
- clm/cross_cutting/cel_slices.py +56 -0
- clm/cross_cutting/cel_store.py +330 -0
- clm/cross_cutting/clm_logger.py +140 -0
- clm/cross_cutting/config/__init__.py +155 -0
- clm/cross_cutting/config/config_constants.py +392 -0
- clm/cross_cutting/config/env_parameters.py +90 -0
- clm/cross_cutting/config/logging.py +378 -0
- clm/cross_cutting/config/settings.py +504 -0
- clm/cross_cutting/context.py +5 -0
- clm/cross_cutting/domain_models.py +55 -0
- clm/cross_cutting/domain_types.py +61 -0
- clm/cross_cutting/effects.py +67 -0
- clm/cross_cutting/errors.py +153 -0
- clm/cross_cutting/governance.py +331 -0
- clm/cross_cutting/guards.py +41 -0
- clm/cross_cutting/mcard.py +321 -0
- clm/cross_cutting/native.py +185 -0
- clm/cross_cutting/observability.py +289 -0
- clm/cross_cutting/pcard.py +434 -0
- clm/cross_cutting/registry.py +71 -0
- clm/cross_cutting/resources.py +84 -0
- clm/cross_cutting/secrets.py +44 -0
- clm/cross_cutting/subprocess_utils.py +118 -0
- clm/cross_cutting/telemetry.py +164 -0
- clm/cross_cutting/testing/__init__.py +8 -0
- clm/cross_cutting/testing/comparator.py +187 -0
- clm/cross_cutting/testing/datasets.py +87 -0
- clm/cross_cutting/timeutil.py +20 -0
- clm/cross_cutting/types/new_type_check.py +0 -0
- clm/cross_cutting/utils/__init__.py +1 -0
- clm/cross_cutting/utils/url_safety.py +50 -0
- clm/cross_cutting/vcard.py +560 -0
- clm/cross_cutting/writer.py +118 -0
- clm/layer0/README.md +50 -0
- clm/layer0/__init__.py +223 -0
- clm/layer0/algebra.py +60 -0
- clm/layer0/algebra_baldwin.py +133 -0
- clm/layer0/algebra_baldwin_generators.py +36 -0
- clm/layer0/algebra_equivalence.py +262 -0
- clm/layer0/algebra_ingest.py +306 -0
- clm/layer0/algebra_manifest_io.py +156 -0
- clm/layer0/assembler.py +481 -0
- clm/layer0/cel/__init__.py +23 -0
- clm/layer0/cel_eval.py +491 -0
- clm/layer0/codec.py +106 -0
- clm/layer0/context.py +122 -0
- clm/layer0/db.py +160 -0
- clm/layer0/exceptions.py +73 -0
- clm/layer0/fibration.py +106 -0
- clm/layer0/gates.py +50 -0
- clm/layer0/hash.py +80 -0
- clm/layer0/loader.py +826 -0
- clm/layer0/math_utils.py +163 -0
- clm/layer0/mcard.py +96 -0
- clm/layer0/model/__init__.py +0 -0
- clm/layer0/model/action.py +223 -0
- clm/layer0/model/card.py +280 -0
- clm/layer0/model/card_triad.py +427 -0
- clm/layer0/model/compatibility.py +60 -0
- clm/layer0/model/dictionary.py +46 -0
- clm/layer0/model/dots.py +331 -0
- clm/layer0/model/event_producer.py +88 -0
- clm/layer0/model/g_time.py +89 -0
- clm/layer0/model/handle.py +163 -0
- clm/layer0/model/hash/__init__.py +6 -0
- clm/layer0/model/hash/algorithms/__init__.py +3 -0
- clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
- clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
- clm/layer0/model/hash/constants.py +53 -0
- clm/layer0/model/hash/enums.py +60 -0
- clm/layer0/model/hash/validator.py +307 -0
- clm/layer0/model/interpreter.py +275 -0
- clm/layer0/model/pagination.py +45 -0
- clm/layer0/model/pcard.py +716 -0
- clm/layer0/model/schema.py +44 -0
- clm/layer0/model/utils/__init__.py +1 -0
- clm/layer0/model/utils/content_analyzer.py +152 -0
- clm/layer0/model/validators/__init__.py +1 -0
- clm/layer0/model/validators/base_validator.py +44 -0
- clm/layer0/model/validators/binary_validator.py +66 -0
- clm/layer0/model/validators/text_validator.py +82 -0
- clm/layer0/model/validators/validation_registry.py +49 -0
- clm/layer0/model/vcard.py +823 -0
- clm/layer0/model/vcard_ext/__init__.py +39 -0
- clm/layer0/model/vcard_ext/core.py +60 -0
- clm/layer0/model/vcard_ext/network.py +23 -0
- clm/layer0/model/vcard_ext/observability.py +63 -0
- clm/layer0/model/vcard_ext/storage.py +60 -0
- clm/layer0/model/vcard_ext/vendors.py +211 -0
- clm/layer0/model/vcard_sandwich.py +119 -0
- clm/layer0/model/vcard_vocabulary.py +463 -0
- clm/layer0/model/workflow.py +274 -0
- clm/layer0/narrative.py +431 -0
- clm/layer0/ontology/collection.py +125 -0
- clm/layer0/parser.py +429 -0
- clm/layer0/relations.py +73 -0
- clm/layer0/rule_evaluator.py +251 -0
- clm/layer0/schema/__init__.py +38 -0
- clm/layer0/schema/ddl.py +97 -0
- clm/layer0/templates/abstract.yaml +99 -0
- clm/layer0/templates/balanced.yaml +253 -0
- clm/layer0/templates/concrete.yaml +172 -0
- clm/layer0/type_registry.py +223 -0
- clm/layer0/types.py +204 -0
- clm/layer0/utils.py +886 -0
- clm/layer0/verifier_core.py +262 -0
- clm/layer1/__init__.py +31 -0
- clm/layer1/action_dispatcher.py +275 -0
- clm/layer1/adapter_registry.py +233 -0
- clm/layer1/algebra_baldwin_generators.py +192 -0
- clm/layer1/arrow_compiler.py +525 -0
- clm/layer1/batch_processor.py +152 -0
- clm/layer1/cel/__init__.py +27 -0
- clm/layer1/cel/builder.py +173 -0
- clm/layer1/engine.py +759 -0
- clm/layer1/engine_async.py +89 -0
- clm/layer1/eval_callback.py +49 -0
- clm/layer1/gate_composer.py +229 -0
- clm/layer1/hoare_sandwich.py +298 -0
- clm/layer1/identity_guard.py +348 -0
- clm/layer1/matrix.py +138 -0
- clm/layer1/neural_runtime.py +221 -0
- clm/layer1/operations/__init__.py +123 -0
- clm/layer1/operations/augment.py +156 -0
- clm/layer1/operations/base.py +109 -0
- clm/layer1/operations/builtins.py +338 -0
- clm/layer1/operations/dispatch.py +144 -0
- clm/layer1/operations/exclude.py +107 -0
- clm/layer1/operations/handle.py +197 -0
- clm/layer1/operations/identity.py +139 -0
- clm/layer1/operations/invert.py +66 -0
- clm/layer1/operations/loader.py +116 -0
- clm/layer1/operations/manipulators/__init__.py +23 -0
- clm/layer1/operations/manipulators/document.py +211 -0
- clm/layer1/operations/manipulators/media.py +134 -0
- clm/layer1/operations/manipulators/structured.py +159 -0
- clm/layer1/operations/manipulators/tabular.py +334 -0
- clm/layer1/operations/port.py +65 -0
- clm/layer1/operations/services.py +529 -0
- clm/layer1/operations/split.py +117 -0
- clm/layer1/operations/substitute.py +75 -0
- clm/layer1/petri.py +1052 -0
- clm/layer1/pocketflow_orchestrator.py +408 -0
- clm/layer1/pocketflow_scheduler.py +519 -0
- clm/layer1/protocols.py +197 -0
- clm/layer1/runtime_adapter.py +718 -0
- clm/layer1/runtimes/__init__.py +71 -0
- clm/layer1/runtimes/_generated_assertions.py +125 -0
- clm/layer1/runtimes/_generated_types.py +42 -0
- clm/layer1/runtimes/base.py +265 -0
- clm/layer1/runtimes/binary.py +101 -0
- clm/layer1/runtimes/factory.py +203 -0
- clm/layer1/runtimes/javascript.py +321 -0
- clm/layer1/runtimes/javascript_runtime.js +33 -0
- clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
- clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
- clm/layer1/runtimes/lambda_calc.py +126 -0
- clm/layer1/runtimes/python.py +288 -0
- clm/layer1/runtimes/python_runtime.py +41 -0
- clm/layer1/runtimes/script.py +114 -0
- clm/layer1/sandbox.py +334 -0
- clm/layer1/savepoint_guard.py +136 -0
- clm/layer1/sparse_net.py +122 -0
- clm/layer1/spec_tester.py +165 -0
- clm/layer1/store.py +295 -0
- clm/layer1/test_runner.py +498 -0
- clm/layer1/type_inspector.py +166 -0
- clm/layer1/verifier.py +772 -0
- clm/layer1/vm.py +91 -0
- clm/layer2/__init__.py +78 -0
- clm/layer2/card_collection.py +678 -0
- clm/layer2/classifier.py +479 -0
- clm/layer2/engine/__init__.py +1 -0
- clm/layer2/engine/abstract_sql_engine.py +320 -0
- clm/layer2/engine/base.py +193 -0
- clm/layer2/engine/duckdb_engine.py +576 -0
- clm/layer2/engine/sqlite_engine.py +518 -0
- clm/layer2/fiber/__init__.py +31 -0
- clm/layer2/fiber/context.py +89 -0
- clm/layer2/fiber/disposable.py +163 -0
- clm/layer2/fiber/fiber.py +125 -0
- clm/layer2/fiber/hoare.py +191 -0
- clm/layer2/file_io.py +376 -0
- clm/layer2/file_registrar.py +77 -0
- clm/layer2/ingest.py +202 -0
- clm/layer2/lineage.py +322 -0
- clm/layer2/mcard_fs.py +262 -0
- clm/layer2/merkle.py +11 -0
- clm/layer2/mime.py +244 -0
- clm/layer2/mime_detector.py +245 -0
- clm/layer2/private_collection.py +118 -0
- clm/layer2/shared_store.py +11 -0
- clm/layer2/storage/__init__.py +190 -0
- clm/layer2/storage/db_bitemporal.py +141 -0
- clm/layer2/storage/db_driver.py +331 -0
- clm/layer2/storage/db_hyperlinks.py +214 -0
- clm/layer2/storage/db_pool.py +139 -0
- clm/layer2/storage/db_repository.py +229 -0
- clm/layer2/storage/savepoint.py +78 -0
- clm/layer2/storage/sqlite_wal.py +74 -0
- clm/layer2/tridb.py +245 -0
- clm/layer2/vcard_receipt.py +71 -0
- clm/layer2/vfs.py +17 -0
- clm/layer3/__init__.py +141 -0
- clm/layer3/agency/__init__.py +19 -0
- clm/layer3/agency/config.py +220 -0
- clm/layer3/agency/providers/__init__.py +15 -0
- clm/layer3/agency/providers/base.py +91 -0
- clm/layer3/agency/providers/mlc_llm.py +169 -0
- clm/layer3/agency/providers/ollama.py +203 -0
- clm/layer3/agency/router.py +71 -0
- clm/layer3/agency/runtime.py +524 -0
- clm/layer3/gateway.py +353 -0
- clm/layer3/open_interpreter_adapter.py +159 -0
- clm/layer3/rag/__init__.py +70 -0
- clm/layer3/rag/cli.py +228 -0
- clm/layer3/rag/config.py +153 -0
- clm/layer3/rag/embeddings/__init__.py +16 -0
- clm/layer3/rag/embeddings/base.py +79 -0
- clm/layer3/rag/embeddings/ollama.py +211 -0
- clm/layer3/rag/embeddings/vision.py +290 -0
- clm/layer3/rag/engine.py +276 -0
- clm/layer3/rag/graph/__init__.py +22 -0
- clm/layer3/rag/graph/community.py +198 -0
- clm/layer3/rag/graph/engine.py +433 -0
- clm/layer3/rag/graph/extractor.py +255 -0
- clm/layer3/rag/graph/schema.py +115 -0
- clm/layer3/rag/graph/store.py +641 -0
- clm/layer3/rag/indexer.py +333 -0
- clm/layer3/rag/llm_providers.json +52 -0
- clm/layer3/rag/semantic_versioning.py +313 -0
- clm/layer3/rag/vector/__init__.py +28 -0
- clm/layer3/rag/vector/handle_vector_store.py +749 -0
- clm/layer3/rag/vector/schema.py +151 -0
- clm/layer3/rag/vector/store.py +632 -0
- clm/layer3/reticulum/__init__.py +55 -0
- clm/layer3/reticulum/bridge.py +74 -0
- clm/layer3/reticulum/daemon.py +88 -0
- clm/layer3/reticulum/discovery.py +164 -0
- clm/layer3/reticulum/identity.py +107 -0
- clm/layer3/reticulum/media.py +148 -0
- clm/layer3/reticulum/transport.py +133 -0
- clm/layer3/satori/__init__.py +209 -0
- clm/layer3/satori/alpha_conversion.py +168 -0
- clm/layer3/satori/beta_reduction.py +359 -0
- clm/layer3/satori/continuation.py +38 -0
- clm/layer3/satori/eta_conversion.py +205 -0
- clm/layer3/satori/free_variables.py +163 -0
- clm/layer3/satori/io_effects.py +370 -0
- clm/layer3/satori/lambda_runtime.py +726 -0
- clm/layer3/satori/lambda_term.py +230 -0
- clm/layer3/satori/sheaf_audit.py +261 -0
- clm/layer3/satori/speech_act.py +279 -0
- clm/layer4/README.md +9 -0
- clm/layer4/__init__.py +67 -0
- clm/layer4/_sovereign_executor.py +580 -0
- clm/layer4/action_commands.py +719 -0
- clm/layer4/api.py +236 -0
- clm/layer4/bootstrap/__init__.py +13 -0
- clm/layer4/bootstrap/bootstrapper.py +118 -0
- clm/layer4/bootstrap/cleanup.py +44 -0
- clm/layer4/bootstrap/clm_hooks.py +49 -0
- clm/layer4/bootstrap/genesis.py +77 -0
- clm/layer4/bootstrap/injection.py +125 -0
- clm/layer4/cli.py +549 -0
- clm/layer4/collection_manager.py +553 -0
- clm/layer4/commands/__init__.py +81 -0
- clm/layer4/commands/action_cmd.py +42 -0
- clm/layer4/commands/check_cmd.py +82 -0
- clm/layer4/commands/envelope.py +73 -0
- clm/layer4/commands/evaluate_cmd.py +224 -0
- clm/layer4/commands/mcard_cmd.py +24 -0
- clm/layer4/commands/petri_cmd.py +92 -0
- clm/layer4/commands/tridb_cmd.py +319 -0
- clm/layer4/commands/version_cmd.py +27 -0
- clm/layer4/diff_commands.py +167 -0
- clm/layer4/eoa_sponsor.py +232 -0
- clm/layer4/events.py +69 -0
- clm/layer4/flux_gateway.py +133 -0
- clm/layer4/gateway.py +91 -0
- clm/layer4/loader.py +307 -0
- clm/layer4/mcard_commands.py +166 -0
- clm/layer4/membrane.py +273 -0
- clm/layer4/navigation.py +50 -0
- clm/layer4/protocol/protocol_entry_python.py +108 -0
- clm/layer4/protocol/python_sync.py +126 -0
- clm/layer4/runner.py +150 -0
- clm/layer4/satori.py +262 -0
- clm/layer4/server/python_sync_client.py +150 -0
- clm/layer4/server/python_sync_server.py +139 -0
- clm/layer4/server/service_api.py +315 -0
- clm/layer4/server/start_servers.py +107 -0
- clm/layer4/server/stop_servers.py +24 -0
- clm/layer4/simulated_optimization_fix.py +0 -0
- clm/layer4/storage.py +463 -0
- clm/layer4/tridb_admin.py +268 -0
- clm/layer4/websocket/test_ws_client.py +104 -0
- clm/layer4/websocket/test_ws_server.py +138 -0
- clm/layer4/websocket/ws_server_local.py +160 -0
- clm/layer5/__init__.py +51 -0
- clm/layer5/async_batch_writer.py +133 -0
- clm/layer5/learning.py +276 -0
- clm/layer5/telemetry_hook.py +107 -0
- clm/layer5/type_lattice.py +238 -0
- clm/py.typed +0 -0
- clm/schemas/__init__.py +652 -0
- clm/schemas/abstract_face_schema.yaml +77 -0
- clm/schemas/cel_schema.yaml +416 -0
- clm/schemas/lifecycle/__init__.py +45 -0
- clm/schemas/lifecycle/models.py +123 -0
- clm/schemas/lifecycle/service.py +364 -0
- clm/schemas/mcard_schema.sql +192 -0
- clm/schemas/mcard_vector_schema.sql +283 -0
- clm/schemas/mlp-context-v1.json +91 -0
- clm_kernel-0.0.0.dist-info/METADATA +121 -0
- clm_kernel-0.0.0.dist-info/RECORD +333 -0
- clm_kernel-0.0.0.dist-info/WHEEL +4 -0
- clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
- clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Configuration Module
|
|
3
|
+
|
|
4
|
+
Centralized configuration for LLM providers and execution parameters.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import asdict, dataclass, field
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from clm.cross_cutting.config.config_constants import (
|
|
11
|
+
LLM_DEFAULT_RETRY_COUNT,
|
|
12
|
+
LLM_DEFAULT_RETRY_DELAY_SECS,
|
|
13
|
+
LLM_DEFAULT_TIMEOUT_SECS,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
+
# Provider Configurations
|
|
18
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
LLM_PROVIDERS = {
|
|
21
|
+
"ollama": {
|
|
22
|
+
"base_url": "http://localhost:11434",
|
|
23
|
+
"api_path": "/api/generate",
|
|
24
|
+
"chat_path": "/api/chat",
|
|
25
|
+
"models_path": "/api/tags",
|
|
26
|
+
"default_model": "qwen3:0.6b",
|
|
27
|
+
"available_models": ["qwen3:0.6b", "llama3:latest", "qwen3:latest"],
|
|
28
|
+
},
|
|
29
|
+
"mlc-llm": {
|
|
30
|
+
"base_url": "http://localhost:8000",
|
|
31
|
+
"api_path": "/v1/completions",
|
|
32
|
+
"chat_path": "/v1/chat/completions",
|
|
33
|
+
"models_path": "/v1/models",
|
|
34
|
+
"default_model": "Llama-3-8B-Instruct-q4f16_1-MLC",
|
|
35
|
+
"available_models": [],
|
|
36
|
+
},
|
|
37
|
+
"lmstudio": {
|
|
38
|
+
"base_url": "http://localhost:1234",
|
|
39
|
+
"api_path": "/v1/completions",
|
|
40
|
+
"chat_path": "/v1/chat/completions",
|
|
41
|
+
"models_path": "/v1/models",
|
|
42
|
+
"default_model": "local-model",
|
|
43
|
+
"available_models": [],
|
|
44
|
+
},
|
|
45
|
+
"openai": {
|
|
46
|
+
"base_url": "https://api.openai.com",
|
|
47
|
+
"api_path": "/v1/completions",
|
|
48
|
+
"chat_path": "/v1/chat/completions",
|
|
49
|
+
"models_path": "/v1/models",
|
|
50
|
+
"default_model": "gpt-4",
|
|
51
|
+
"available_models": ["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo"],
|
|
52
|
+
},
|
|
53
|
+
"anthropic": {
|
|
54
|
+
"base_url": "https://api.anthropic.com",
|
|
55
|
+
"api_path": "/v1/messages",
|
|
56
|
+
"chat_path": "/v1/messages",
|
|
57
|
+
"models_path": None,
|
|
58
|
+
"default_model": "claude-3-sonnet-20240229",
|
|
59
|
+
"available_models": ["claude-3-opus", "claude-3-sonnet", "claude-3-haiku"],
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
# Default Configuration
|
|
65
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
DEFAULT_LLM_CONFIG = {
|
|
68
|
+
"temperature": 0.7,
|
|
69
|
+
"max_tokens": 2048,
|
|
70
|
+
"top_p": 1.0,
|
|
71
|
+
"top_k": 40,
|
|
72
|
+
"timeout": LLM_DEFAULT_TIMEOUT_SECS,
|
|
73
|
+
"stream": False,
|
|
74
|
+
"response_format": "text",
|
|
75
|
+
"retry_count": LLM_DEFAULT_RETRY_COUNT,
|
|
76
|
+
"retry_delay": LLM_DEFAULT_RETRY_DELAY_SECS,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Output format options
|
|
80
|
+
RESPONSE_FORMATS = ("text", "json", "structured", "markdown")
|
|
81
|
+
|
|
82
|
+
# Default provider
|
|
83
|
+
DEFAULT_PROVIDER = "ollama"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
87
|
+
# LLMConfig Dataclass
|
|
88
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass
|
|
92
|
+
class LLMConfig:
|
|
93
|
+
"""
|
|
94
|
+
Configuration for LLM execution.
|
|
95
|
+
|
|
96
|
+
Supports multiple providers (Ollama, LMStudio, OpenAI, Anthropic) with
|
|
97
|
+
unified configuration interface.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
# Provider settings
|
|
101
|
+
provider: str = DEFAULT_PROVIDER
|
|
102
|
+
model: str | None = None # Uses provider default if None
|
|
103
|
+
endpoint_url: str | None = None # Override provider base_url
|
|
104
|
+
api_key: str | None = None # For authenticated providers
|
|
105
|
+
|
|
106
|
+
# Prompt structure
|
|
107
|
+
system_prompt: str = ""
|
|
108
|
+
assistant_instruction: str = ""
|
|
109
|
+
|
|
110
|
+
# Generation parameters
|
|
111
|
+
temperature: float = DEFAULT_LLM_CONFIG["temperature"]
|
|
112
|
+
max_tokens: int = DEFAULT_LLM_CONFIG["max_tokens"]
|
|
113
|
+
top_p: float = DEFAULT_LLM_CONFIG["top_p"]
|
|
114
|
+
top_k: int | None = DEFAULT_LLM_CONFIG["top_k"]
|
|
115
|
+
frequency_penalty: float = 0.0
|
|
116
|
+
presence_penalty: float = 0.0
|
|
117
|
+
stop_sequences: list[str] = field(default_factory=list)
|
|
118
|
+
|
|
119
|
+
# Response handling
|
|
120
|
+
response_format: str = DEFAULT_LLM_CONFIG["response_format"]
|
|
121
|
+
json_schema: dict | None = None # For structured output
|
|
122
|
+
|
|
123
|
+
# Execution settings
|
|
124
|
+
timeout: int = DEFAULT_LLM_CONFIG["timeout"]
|
|
125
|
+
retry_count: int = DEFAULT_LLM_CONFIG["retry_count"]
|
|
126
|
+
retry_delay: float = DEFAULT_LLM_CONFIG["retry_delay"]
|
|
127
|
+
stream: bool = DEFAULT_LLM_CONFIG["stream"]
|
|
128
|
+
|
|
129
|
+
def __post_init__(self):
|
|
130
|
+
"""Validate configuration after initialization."""
|
|
131
|
+
if self.provider not in LLM_PROVIDERS:
|
|
132
|
+
raise ValueError(
|
|
133
|
+
f"Unknown provider: {self.provider}. "
|
|
134
|
+
f"Available: {list(LLM_PROVIDERS.keys())}"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if self.response_format not in RESPONSE_FORMATS:
|
|
138
|
+
raise ValueError(
|
|
139
|
+
f"Unknown response format: {self.response_format}. "
|
|
140
|
+
f"Available: {RESPONSE_FORMATS}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def effective_model(self) -> str:
|
|
145
|
+
"""Get the model to use, falling back to provider default."""
|
|
146
|
+
if self.model:
|
|
147
|
+
return self.model
|
|
148
|
+
return LLM_PROVIDERS[self.provider]["default_model"]
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def effective_base_url(self) -> str:
|
|
152
|
+
"""Get the base URL, with optional override."""
|
|
153
|
+
if self.endpoint_url:
|
|
154
|
+
return self.endpoint_url.rstrip("/")
|
|
155
|
+
return LLM_PROVIDERS[self.provider]["base_url"]
|
|
156
|
+
|
|
157
|
+
def to_provider_params(self) -> dict[str, Any]:
|
|
158
|
+
"""Convert to provider-specific generation parameters."""
|
|
159
|
+
params = {
|
|
160
|
+
"model": self.effective_model,
|
|
161
|
+
"temperature": self.temperature,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# Provider-specific parameter names
|
|
165
|
+
if self.provider == "ollama":
|
|
166
|
+
params["options"] = {
|
|
167
|
+
"num_predict": self.max_tokens,
|
|
168
|
+
"top_p": self.top_p,
|
|
169
|
+
"top_k": self.top_k,
|
|
170
|
+
"temperature": self.temperature,
|
|
171
|
+
}
|
|
172
|
+
if self.stop_sequences:
|
|
173
|
+
params["options"]["stop"] = self.stop_sequences
|
|
174
|
+
else:
|
|
175
|
+
# OpenAI-compatible format
|
|
176
|
+
params["max_tokens"] = self.max_tokens
|
|
177
|
+
params["top_p"] = self.top_p
|
|
178
|
+
if self.stop_sequences:
|
|
179
|
+
params["stop"] = self.stop_sequences
|
|
180
|
+
if self.frequency_penalty:
|
|
181
|
+
params["frequency_penalty"] = self.frequency_penalty
|
|
182
|
+
if self.presence_penalty:
|
|
183
|
+
params["presence_penalty"] = self.presence_penalty
|
|
184
|
+
|
|
185
|
+
return params
|
|
186
|
+
|
|
187
|
+
def to_dict(self) -> dict[str, Any]:
|
|
188
|
+
"""Convert to dictionary for serialization."""
|
|
189
|
+
return asdict(self)
|
|
190
|
+
|
|
191
|
+
@classmethod
|
|
192
|
+
def from_dict(cls, data: dict[str, Any]) -> "LLMConfig":
|
|
193
|
+
"""Create from dictionary."""
|
|
194
|
+
return cls(**{k: v for k, v in data.items() if k in cls.__dataclass_fields__})
|
|
195
|
+
|
|
196
|
+
@classmethod
|
|
197
|
+
def from_concrete(
|
|
198
|
+
cls, concrete: dict[str, Any], context: dict[str, Any] = None
|
|
199
|
+
) -> "LLMConfig":
|
|
200
|
+
"""
|
|
201
|
+
Create LLMConfig from concrete implementation and context.
|
|
202
|
+
|
|
203
|
+
Merges llm_config from concrete with context overrides.
|
|
204
|
+
"""
|
|
205
|
+
context = context or {}
|
|
206
|
+
|
|
207
|
+
# Start with defaults from concrete's llm_config
|
|
208
|
+
config_data = concrete.get("llm_config", {}).copy()
|
|
209
|
+
|
|
210
|
+
# Override with top-level concrete fields
|
|
211
|
+
for key in ["provider", "model", "system_prompt", "temperature", "max_tokens"]:
|
|
212
|
+
if key in concrete:
|
|
213
|
+
config_data[key] = concrete[key]
|
|
214
|
+
|
|
215
|
+
# Override with context
|
|
216
|
+
for key in cls.__dataclass_fields__:
|
|
217
|
+
if key in context:
|
|
218
|
+
config_data[key] = context[key]
|
|
219
|
+
|
|
220
|
+
return cls.from_dict(config_data)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Providers Package
|
|
3
|
+
|
|
4
|
+
Provider implementations for different LLM services.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .base import LLMProvider
|
|
8
|
+
from .mlc_llm import MLCLLMProvider
|
|
9
|
+
from .ollama import OllamaProvider
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"LLMProvider",
|
|
13
|
+
"OllamaProvider",
|
|
14
|
+
"MLCLLMProvider",
|
|
15
|
+
]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Provider Base Class
|
|
3
|
+
|
|
4
|
+
Abstract base class defining the interface for LLM providers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from clm.layer0.narrative import Either, Left
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LLMProvider(ABC):
|
|
14
|
+
"""
|
|
15
|
+
Abstract base class for LLM providers.
|
|
16
|
+
|
|
17
|
+
Implementations should handle:
|
|
18
|
+
- Connection to the LLM service
|
|
19
|
+
- Request formatting for the specific API
|
|
20
|
+
- Response parsing
|
|
21
|
+
- Error handling
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
provider_name: str = "base"
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def complete(self, prompt: str, params: dict[str, Any]) -> Either[str, str]:
|
|
28
|
+
"""
|
|
29
|
+
Generate text completion for a prompt.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
prompt: The input prompt
|
|
33
|
+
params: Provider-specific generation parameters
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Either[Error, Response]: Left(error) or Right(completion)
|
|
37
|
+
"""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def chat(
|
|
42
|
+
self, messages: list[dict[str, str]], params: dict[str, Any]
|
|
43
|
+
) -> Either[str, dict[str, Any]]:
|
|
44
|
+
"""
|
|
45
|
+
Generate chat completion from messages.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
messages: List of message dicts with 'role' and 'content'
|
|
49
|
+
params: Provider-specific generation parameters
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Either[Error, Response]: Left(error) or Right(response dict)
|
|
53
|
+
"""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def validate_connection(self) -> bool:
|
|
58
|
+
"""
|
|
59
|
+
Check if the provider service is available.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
True if connection is valid, False otherwise
|
|
63
|
+
"""
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def list_models(self) -> Either[str, list[str]]:
|
|
68
|
+
"""
|
|
69
|
+
List available models from the provider.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Either[Error, ModelList]: Left(error) or Right(list of model names)
|
|
73
|
+
"""
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
def get_status(self) -> dict[str, Any]:
|
|
77
|
+
"""
|
|
78
|
+
Get provider status information.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Dictionary with provider status details
|
|
82
|
+
"""
|
|
83
|
+
available = self.validate_connection()
|
|
84
|
+
models_result = self.list_models() if available else Left("Not connected")
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
"provider": self.provider_name,
|
|
88
|
+
"available": available,
|
|
89
|
+
"models": models_result.value if models_result.is_right() else [],
|
|
90
|
+
"error": models_result.value if models_result.is_left() else None,
|
|
91
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MLC LLM Provider Implementation
|
|
3
|
+
|
|
4
|
+
Provider for the MLC LLM REST API (OpenAI compatible).
|
|
5
|
+
Running via `mlc_llm serve`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
import urllib.error
|
|
11
|
+
import urllib.request
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from clm.cross_cutting.config.config_constants import LLM_DEFAULT_TIMEOUT_SECS
|
|
15
|
+
from clm.cross_cutting.utils.url_safety import safe_urlopen
|
|
16
|
+
from clm.layer0.narrative import Either, Left, Right
|
|
17
|
+
|
|
18
|
+
from ..config import LLM_PROVIDERS
|
|
19
|
+
from .base import LLMProvider
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MLCLLMProvider(LLMProvider):
|
|
23
|
+
"""
|
|
24
|
+
MLC LLM provider for local execution via OpenAI-compatible API.
|
|
25
|
+
|
|
26
|
+
Compatible with:
|
|
27
|
+
- /v1/completions
|
|
28
|
+
- /v1/chat/completions
|
|
29
|
+
- /v1/models
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
provider_name = "mlc-llm"
|
|
33
|
+
|
|
34
|
+
def __init__(self, base_url: str = None, timeout: int = LLM_DEFAULT_TIMEOUT_SECS):
|
|
35
|
+
self.logger = logging.getLogger(__name__)
|
|
36
|
+
self.config = LLM_PROVIDERS["mlc-llm"]
|
|
37
|
+
self.base_url = (base_url or self.config["base_url"]).rstrip("/")
|
|
38
|
+
self.timeout = timeout
|
|
39
|
+
|
|
40
|
+
def _make_request(
|
|
41
|
+
self, endpoint: str, data: dict = None, method: str = "POST"
|
|
42
|
+
) -> Either[str, dict]:
|
|
43
|
+
"""Make HTTP request to MLC LLM API."""
|
|
44
|
+
url = f"{self.base_url}{endpoint}"
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
if data:
|
|
48
|
+
request = urllib.request.Request(
|
|
49
|
+
url,
|
|
50
|
+
data=json.dumps(data).encode("utf-8"),
|
|
51
|
+
headers={"Content-Type": "application/json"},
|
|
52
|
+
method=method,
|
|
53
|
+
)
|
|
54
|
+
else:
|
|
55
|
+
request = urllib.request.Request(url, method=method)
|
|
56
|
+
|
|
57
|
+
with safe_urlopen(request, timeout=self.timeout) as response:
|
|
58
|
+
response_text = response.read().decode("utf-8")
|
|
59
|
+
return Right(json.loads(response_text))
|
|
60
|
+
|
|
61
|
+
except urllib.error.HTTPError as e:
|
|
62
|
+
error_body = e.read().decode("utf-8") if e.fp else str(e)
|
|
63
|
+
return Left(f"MLC-LLM HTTP error {e.code}: {error_body}")
|
|
64
|
+
except urllib.error.URLError as e:
|
|
65
|
+
return Left(f"MLC-LLM connection error: {e.reason}")
|
|
66
|
+
except json.JSONDecodeError as e:
|
|
67
|
+
return Left(f"MLC-LLM response parse error: {e}")
|
|
68
|
+
except (OSError, ConnectionError, ValueError) as e:
|
|
69
|
+
return Left(f"MLC-LLM request failed: {e}")
|
|
70
|
+
|
|
71
|
+
def complete(self, prompt: str, params: dict[str, Any]) -> Either[str, str]:
|
|
72
|
+
"""
|
|
73
|
+
Generate text completion.
|
|
74
|
+
Using /v1/completions style.
|
|
75
|
+
"""
|
|
76
|
+
data = {
|
|
77
|
+
"model": params.get("model", self.config["default_model"]),
|
|
78
|
+
"prompt": prompt,
|
|
79
|
+
"max_tokens": params.get("max_tokens", 128),
|
|
80
|
+
"temperature": params.get("temperature", 0.7),
|
|
81
|
+
"top_p": params.get("top_p", 1.0),
|
|
82
|
+
"stream": False,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if "stop" in params:
|
|
86
|
+
data["stop"] = params["stop"]
|
|
87
|
+
|
|
88
|
+
self.logger.debug(f"MLC-LLM complete request: model={data['model']}")
|
|
89
|
+
|
|
90
|
+
result = self._make_request(self.config["api_path"], data)
|
|
91
|
+
|
|
92
|
+
if result.is_left():
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
response = result.value
|
|
96
|
+
# OpenAI format: {'choices': [{'text': '...'}]}
|
|
97
|
+
if "choices" in response and len(response["choices"]) > 0:
|
|
98
|
+
return Right(response["choices"][0].get("text", ""))
|
|
99
|
+
elif "error" in response:
|
|
100
|
+
return Left(f"MLC-LLM error: {response['error']}")
|
|
101
|
+
else:
|
|
102
|
+
return Left(f"Unexpected MLC-LLM response format: {response}")
|
|
103
|
+
|
|
104
|
+
def chat(
|
|
105
|
+
self, messages: list[dict[str, str]], params: dict[str, Any]
|
|
106
|
+
) -> Either[str, dict[str, Any]]:
|
|
107
|
+
"""
|
|
108
|
+
Generate chat completion.
|
|
109
|
+
Using /v1/chat/completions style.
|
|
110
|
+
"""
|
|
111
|
+
data = {
|
|
112
|
+
"model": params.get("model", self.config["default_model"]),
|
|
113
|
+
"messages": messages,
|
|
114
|
+
"max_tokens": params.get("max_tokens", 128),
|
|
115
|
+
"temperature": params.get("temperature", 0.7),
|
|
116
|
+
"top_p": params.get("top_p", 1.0),
|
|
117
|
+
"stream": False,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if "stop" in params:
|
|
121
|
+
data["stop"] = params["stop"]
|
|
122
|
+
|
|
123
|
+
self.logger.debug(f"MLC-LLM chat request: model={data['model']}")
|
|
124
|
+
|
|
125
|
+
result = self._make_request(self.config["chat_path"], data)
|
|
126
|
+
|
|
127
|
+
if result.is_left():
|
|
128
|
+
return result
|
|
129
|
+
|
|
130
|
+
response = result.value
|
|
131
|
+
# OpenAI format: {'choices': [{'message': {'role': 'assistant', 'content': '...'}}]}
|
|
132
|
+
if "choices" in response and len(response["choices"]) > 0:
|
|
133
|
+
choice = response["choices"][0]
|
|
134
|
+
message = choice.get("message", {})
|
|
135
|
+
return Right(
|
|
136
|
+
{
|
|
137
|
+
"content": message.get("content", ""),
|
|
138
|
+
"role": message.get("role", "assistant"),
|
|
139
|
+
"model": response.get("model", data["model"]),
|
|
140
|
+
"usage": response.get("usage", {}),
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
elif "error" in response:
|
|
144
|
+
return Left(f"MLC-LLM error: {response['error']}")
|
|
145
|
+
else:
|
|
146
|
+
return Left(f"Unexpected MLC-LLM response format: {response}")
|
|
147
|
+
|
|
148
|
+
def validate_connection(self) -> bool:
|
|
149
|
+
"""Check if MLC-LLM service is running via models endpoint."""
|
|
150
|
+
try:
|
|
151
|
+
result = self._make_request(self.config["models_path"], method="GET")
|
|
152
|
+
return result.is_right()
|
|
153
|
+
except (OSError, ConnectionError):
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
def list_models(self) -> Either[str, list[str]]:
|
|
157
|
+
"""List available api models."""
|
|
158
|
+
result = self._make_request(self.config["models_path"], method="GET")
|
|
159
|
+
|
|
160
|
+
if result.is_left():
|
|
161
|
+
return result
|
|
162
|
+
|
|
163
|
+
response = result.value
|
|
164
|
+
# OpenAI format: {'data': [{'id': 'model-id', ...}]}
|
|
165
|
+
if "data" in response and isinstance(response["data"], list):
|
|
166
|
+
models = [m.get("id", "unknown") for m in response["data"]]
|
|
167
|
+
return Right(models)
|
|
168
|
+
else:
|
|
169
|
+
return Left(f"Unexpected models response: {response}")
|