MCPcopy Create free account
hub / github.com/Emmimal/control-layer / LLMCaller

Class LLMCaller

control_layer.py:788–822  ·  view source on GitHub ↗

Wraps any callable LLM function with timeout enforcement. Production fix over v1: without a timeout, a hung LLM call blocks the thread forever. This uses threading.Timer to enforce a hard deadline on every call, regardless of the LLM backend.

Source from the content-addressed store, hash-verified

786
787
788class LLMCaller:
789 """
790 Wraps any callable LLM function with timeout enforcement.
791
792 Production fix over v1: without a timeout, a hung LLM call
793 blocks the thread forever. This uses threading.Timer to enforce
794 a hard deadline on every call, regardless of the LLM backend.
795 """
796
797 def __init__(self, llm_fn: Callable[[str], str], timeout_seconds: float):
798 self.llm_fn = llm_fn
799 self.timeout_seconds = timeout_seconds
800
801 def call(self, prompt: str) -> str:
802 result: Dict[str, Any] = {}
803 error: Dict[str, Any] = {}
804
805 def target():
806 try:
807 result["value"] = self.llm_fn(prompt)
808 except Exception as exc:
809 error["value"] = exc
810
811 thread = threading.Thread(target=target, daemon=True)
812 thread.start()
813 thread.join(timeout=self.timeout_seconds)
814
815 if thread.is_alive():
816 raise LLMTimeoutError(
817 f"LLM call exceeded {self.timeout_seconds}s timeout"
818 )
819 if "value" in error:
820 raise error["value"]
821
822 return result.get("value", "")
823
824
825# =============================================================================

Callers 3

test_timeout_raisesMethod · 0.90
__init__Method · 0.85

Calls

no outgoing calls

Tested by 2

test_timeout_raisesMethod · 0.72