feat(state-hub): integrate llm-connect as dependency (S3.1)
Add llm-connect as an editable local dependency via [tool.uv.sources]. Creates tests/test_llm_connect_integration.py: 7 offline smoke tests covering public symbol imports, MockLLMAdapter execute/reset, RunConfig and LLMResponse fields, and ErrorLLMAdapter error propagation. All 7 tests pass. Satisfies workstream llm-shared-library S3.1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ dependencies = [
|
||||
"fastmcp>=2.0.0",
|
||||
"python-dotenv>=1.0.0",
|
||||
"psycopg2-binary>=2.9.0",
|
||||
"llm-connect",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
@@ -28,6 +29,9 @@ build-backend = "hatchling.build"
|
||||
packages = ["api", "mcp_server"]
|
||||
artifacts = ["custodian_cli.py"]
|
||||
|
||||
[tool.uv.sources]
|
||||
llm-connect = { path = "/home/worsch/llm-connect", editable = true }
|
||||
|
||||
[tool.uv]
|
||||
dev-dependencies = [
|
||||
"pytest>=8.0.0",
|
||||
|
||||
0
state-hub/tests/__init__.py
Normal file
0
state-hub/tests/__init__.py
Normal file
74
state-hub/tests/test_llm_connect_integration.py
Normal file
74
state-hub/tests/test_llm_connect_integration.py
Normal file
@@ -0,0 +1,74 @@
|
||||
"""
|
||||
Smoke test: llm-connect integration in state-hub (S3.1).
|
||||
|
||||
Verifies that the package is importable from the state-hub venv and that
|
||||
the core types and mock adapter work correctly. Does NOT call any live
|
||||
LLM endpoint — CI-safe and offline-safe.
|
||||
"""
|
||||
import llm_connect
|
||||
from llm_connect import (
|
||||
MockLLMAdapter,
|
||||
RunConfig,
|
||||
LLMResponse,
|
||||
LLMError,
|
||||
create_adapter,
|
||||
)
|
||||
|
||||
|
||||
def test_package_version():
|
||||
assert hasattr(llm_connect, "__version__") or True # version attr optional
|
||||
|
||||
|
||||
def test_public_symbols_importable():
|
||||
"""All expected public symbols are present in llm_connect namespace."""
|
||||
expected = [
|
||||
"RunConfig", "LLMResponse",
|
||||
"LLMAdapter", "MockLLMAdapter", "ErrorLLMAdapter",
|
||||
"OpenRouterAdapter", "GeminiAdapter", "OpenAIAdapter", "ClaudeCodeAdapter",
|
||||
"create_adapter",
|
||||
"LLMError", "LLMConfigurationError", "LLMAPIError",
|
||||
"LLMRateLimitError", "LLMTimeoutError", "LLMSubprocessError",
|
||||
"EmbeddingAdapter", "OpenAICompatibleEmbeddingAdapter", "EmbeddingCache",
|
||||
"cosine_similarity",
|
||||
]
|
||||
missing = [name for name in expected if not hasattr(llm_connect, name)]
|
||||
assert missing == [], f"Missing public symbols: {missing}"
|
||||
|
||||
|
||||
def test_mock_adapter_execute():
|
||||
adapter = MockLLMAdapter(mock_response="hello from mock")
|
||||
config = RunConfig()
|
||||
result = adapter.execute_prompt("any prompt", config)
|
||||
|
||||
assert isinstance(result, LLMResponse)
|
||||
assert result.content == "hello from mock"
|
||||
assert adapter.call_count == 1
|
||||
|
||||
|
||||
def test_mock_adapter_reset():
|
||||
adapter = MockLLMAdapter(mock_response="x")
|
||||
adapter.execute_prompt("p", RunConfig())
|
||||
adapter.reset()
|
||||
assert adapter.call_count == 0
|
||||
|
||||
|
||||
def test_run_config_defaults():
|
||||
cfg = RunConfig()
|
||||
assert cfg.temperature >= 0
|
||||
assert cfg.max_tokens > 0
|
||||
|
||||
|
||||
def test_llm_response_fields():
|
||||
r = LLMResponse(content="ok", model="test-model")
|
||||
assert r.content == "ok"
|
||||
assert r.model == "test-model"
|
||||
|
||||
|
||||
def test_error_adapter_raises():
|
||||
from llm_connect import ErrorLLMAdapter
|
||||
adapter = ErrorLLMAdapter(error_message="simulated failure")
|
||||
try:
|
||||
adapter.execute_prompt("p", RunConfig())
|
||||
assert False, "should have raised"
|
||||
except (LLMError, RuntimeError) as e:
|
||||
assert "simulated failure" in str(e)
|
||||
25
state-hub/uv.lock
generated
25
state-hub/uv.lock
generated
@@ -663,6 +663,20 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "llm-connect"
|
||||
version = "0.1.0"
|
||||
source = { editable = "../../llm-connect" }
|
||||
dependencies = [
|
||||
{ name = "toml" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0" },
|
||||
{ name = "toml" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mako"
|
||||
version = "1.3.10"
|
||||
@@ -1405,6 +1419,7 @@ dependencies = [
|
||||
{ name = "fastapi" },
|
||||
{ name = "fastmcp" },
|
||||
{ name = "httpx" },
|
||||
{ name = "llm-connect" },
|
||||
{ name = "psycopg2-binary" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
@@ -1427,6 +1442,7 @@ requires-dist = [
|
||||
{ name = "fastapi", specifier = ">=0.115.0" },
|
||||
{ name = "fastmcp", specifier = ">=2.0.0" },
|
||||
{ name = "httpx", specifier = ">=0.28.0" },
|
||||
{ name = "llm-connect", editable = "../../llm-connect" },
|
||||
{ name = "psycopg2-binary", specifier = ">=2.9.0" },
|
||||
{ name = "pydantic", specifier = ">=2.10.0" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.7.0" },
|
||||
@@ -1442,6 +1458,15 @@ dev = [
|
||||
{ name = "pytest-asyncio", specifier = ">=0.24.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
|
||||
Reference in New Issue
Block a user