Graham Paasch commited on
Commit
b64e5d2
·
1 Parent(s): fe62120

Add modal_custom provider for OpenAI-compatible endpoints

Browse files
Files changed (1) hide show
  1. agent/llm_client.py +52 -0
agent/llm_client.py CHANGED
@@ -113,6 +113,8 @@ class LLMClient:
113
  return "anthropic"
114
  elif self.openai_key:
115
  return "openai"
 
 
116
  elif self.blaxel_key:
117
  return "blaxel"
118
  elif self.sambanova_key:
@@ -151,6 +153,8 @@ class LLMClient:
151
  return self._call_nebius(messages, temperature, max_tokens)
152
  elif self.provider == "modal":
153
  return self._call_modal(messages, temperature, max_tokens)
 
 
154
  elif self.provider == "huggingface":
155
  return self._call_huggingface(messages, temperature, max_tokens)
156
 
@@ -258,6 +262,54 @@ class LLMClient:
258
  if monitor:
259
  monitor.complete_call(call_id, success=False, error_message=str(e))
260
  raise
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
  def _call_anthropic(self, messages, temperature, max_tokens, stream):
263
  """Call Anthropic API"""
 
113
  return "anthropic"
114
  elif self.openai_key:
115
  return "openai"
116
+ elif os.getenv("MODAL_CUSTOM_BASE_URL"):
117
+ return "modal_custom"
118
  elif self.blaxel_key:
119
  return "blaxel"
120
  elif self.sambanova_key:
 
153
  return self._call_nebius(messages, temperature, max_tokens)
154
  elif self.provider == "modal":
155
  return self._call_modal(messages, temperature, max_tokens)
156
+ elif self.provider == "modal_custom":
157
+ return self._call_modal_custom(messages, temperature, max_tokens)
158
  elif self.provider == "huggingface":
159
  return self._call_huggingface(messages, temperature, max_tokens)
160
 
 
262
  if monitor:
263
  monitor.complete_call(call_id, success=False, error_message=str(e))
264
  raise
265
+
266
+ def _call_modal_custom(self, messages, temperature, max_tokens):
267
+ """
268
+ Call an OpenAI-compatible endpoint hosted on Modal (custom vLLM server).
269
+ Uses MODAL_CUSTOM_BASE_URL, MODAL_CUSTOM_MODEL, MODAL_CUSTOM_API_KEY.
270
+ """
271
+ call_id = str(uuid.uuid4())
272
+ model = (
273
+ os.getenv("MODAL_CUSTOM_MODEL")
274
+ or os.getenv("OG_OPENAI_MODEL")
275
+ or "network-llm"
276
+ )
277
+ base_url = os.getenv("MODAL_CUSTOM_BASE_URL") or os.getenv("OPENAI_BASE_URL")
278
+ api_key = (
279
+ os.getenv("MODAL_CUSTOM_API_KEY")
280
+ or os.getenv("OPENAI_API_KEY")
281
+ or os.getenv("OPENAI_MCP_1ST_BDAY")
282
+ or ""
283
+ )
284
+ if not base_url:
285
+ raise RuntimeError("MODAL_CUSTOM_BASE_URL is not set for modal_custom provider.")
286
+
287
+ if monitor:
288
+ monitor.start_call(call_id, "llm", "modal_custom", model, temperature=temperature)
289
+
290
+ try:
291
+ from openai import OpenAI
292
+ client = OpenAI(api_key=api_key, base_url=base_url)
293
+ response = client.chat.completions.create(
294
+ model=model,
295
+ messages=[{"role": m.role, "content": m.content} for m in messages],
296
+ temperature=temperature,
297
+ max_tokens=max_tokens,
298
+ )
299
+ content = response.choices[0].message.content if response.choices else ""
300
+ if monitor and getattr(response, "usage", None):
301
+ monitor.complete_call(
302
+ call_id,
303
+ success=True,
304
+ input_tokens=response.usage.prompt_tokens,
305
+ output_tokens=response.usage.completion_tokens,
306
+ )
307
+ return content
308
+ except Exception as e:
309
+ logger.error(f"Modal custom endpoint error: {e}")
310
+ if monitor:
311
+ monitor.complete_call(call_id, success=False, error_message=str(e))
312
+ raise
313
 
314
  def _call_anthropic(self, messages, temperature, max_tokens, stream):
315
  """Call Anthropic API"""