Add activity-core LLM endpoint support
Some checks failed
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled

This commit is contained in:
2026-06-07 19:24:45 +02:00
parent 1d9fc107ed
commit 14ba47c129
25 changed files with 2082 additions and 18 deletions

View File

@@ -17,7 +17,9 @@ from llm_connect._diagnostics import (
record_provider_response,
)
from llm_connect.adapter import MockLLMAdapter, ErrorLLMAdapter
from llm_connect.exceptions import LLMAPIError, LLMConfigurationError, LLMTimeoutError
from llm_connect.models import LLMResponse, RunConfig
from llm_connect.profiles import CUSTODIAN_TRIAGE_BALANCED, ProfiledLLMAdapter, RuntimeProfile
from llm_connect.server import LLMServer
@@ -151,7 +153,8 @@ class TestExecute:
{"prompt": "hello"},
)
assert status == 500
assert "boom" in body["error"]
assert body["error"] == "internal_error"
assert "boom" in body["message"]
finally:
s.stop()
@@ -189,6 +192,142 @@ class TestExecute:
assert status == 400
assert "config" in body["error"]
def test_profile_execute_resolves_model_and_metadata(self):
created: list[MockLLMAdapter] = []
def factory(provider: str, model: str) -> MockLLMAdapter:
created.append(MockLLMAdapter(mock_response="profile response"))
return created[-1]
adapter = ProfiledLLMAdapter(
MockLLMAdapter(mock_response="default"),
{
CUSTODIAN_TRIAGE_BALANCED: RuntimeProfile(
name=CUSTODIAN_TRIAGE_BALANCED,
provider="mock",
model="triage-model",
config=RunConfig(
model_name="triage-model",
temperature=0.2,
max_tokens=1800,
max_depth=2,
model_params={"reasoning_effort": "medium"},
),
)
},
adapter_factory=factory,
)
s = LLMServer(adapter=adapter, port=0)
s.start()
try:
status, body = _post(
f"http://127.0.0.1:{s.port}/execute",
{
"prompt": "Return JSON.",
"config": {
"model_name": CUSTODIAN_TRIAGE_BALANCED,
"model_params": {"json_schema": {"type": "object"}},
},
},
)
finally:
s.stop()
assert status == 200
assert body["model"] == "triage-model"
assert body["metadata"]["profile"] == CUSTODIAN_TRIAGE_BALANCED
assert body["metadata"]["profile_provider"] == "mock"
assert len(created) == 1
assert created[0].last_config.model_name == "triage-model"
assert created[0].last_config.temperature == 0.2
assert created[0].last_config.max_tokens == 1800
assert created[0].last_config.max_depth == 2
assert created[0].last_config.model_params == {
"reasoning_effort": "medium",
"json_schema": {"type": "object"},
}
def test_unknown_profile_returns_400(self):
s = LLMServer(adapter=ProfiledLLMAdapter(MockLLMAdapter(), {}), port=0)
s.start()
try:
status, body = _post(
f"http://127.0.0.1:{s.port}/execute",
{"prompt": "hello", "config": {"model_name": "custodian-missing"}},
)
finally:
s.stop()
assert status == 400
assert body["error"] == "unknown_profile"
assert body["context"]["profile"] == "custodian-missing"
def test_configuration_error_is_sanitized(self):
class SecretConfigAdapter(MockLLMAdapter):
def execute_prompt(self, prompt: str, config: RunConfig) -> LLMResponse:
raise LLMConfigurationError(
"Bad api_key=sk-supersecret with Bearer secret-token",
context={"api_key": "sk-supersecret", "provider": "openai"},
)
s = LLMServer(adapter=SecretConfigAdapter(), port=0)
s.start()
try:
status, body = _post(
f"http://127.0.0.1:{s.port}/execute",
{"prompt": "hello"},
)
finally:
s.stop()
assert status == 500
assert body["error"] == "configuration_error"
assert "sk-supersecret" not in json.dumps(body)
assert "secret-token" not in json.dumps(body)
assert body["context"]["api_key"] == "<redacted>"
assert body["context"]["provider"] == "openai"
def test_provider_errors_are_categorized_and_sanitized(self):
class ProviderErrorAdapter(MockLLMAdapter):
def execute_prompt(self, prompt: str, config: RunConfig) -> LLMResponse:
raise LLMAPIError(
"HTTP 500 from https://provider.example/v1?key=gemini-secret",
status_code=500,
)
s = LLMServer(adapter=ProviderErrorAdapter(), port=0)
s.start()
try:
status, body = _post(
f"http://127.0.0.1:{s.port}/execute",
{"prompt": "hello"},
)
finally:
s.stop()
assert status == 502
assert body["error"] == "provider_api_error"
assert body["provider_status"] == 500
assert "gemini-secret" not in body["message"]
def test_timeout_error_returns_504(self):
class TimeoutAdapter(MockLLMAdapter):
def execute_prompt(self, prompt: str, config: RunConfig) -> LLMResponse:
raise LLMTimeoutError("Request timed out after 300s")
s = LLMServer(adapter=TimeoutAdapter(), port=0)
s.start()
try:
status, body = _post(
f"http://127.0.0.1:{s.port}/execute",
{"prompt": "hello"},
)
finally:
s.stop()
assert status == 504
assert body["error"] == "provider_timeout"
def test_debug_query_returns_diagnostics(self):
s = LLMServer(adapter=DiagnosticLLMAdapter(mock_response="debug body"), port=0)
s.start()