atakan commited on
Commit
9b35e00
·
1 Parent(s): 2d71e4f

feat: Add high-speed C++ GGUF and Ollama engine backends to agent orchestrator

Browse files
Files changed (1) hide show
  1. controlai_agent/orchestrator.py +49 -7
controlai_agent/orchestrator.py CHANGED
@@ -17,6 +17,18 @@ try:
17
  except ImportError:
18
  HAS_MLX = False
19
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  from transformers import AutoModelForCausalLM, AutoTokenizer
21
 
22
  from controlai_agent.prompts import CONTROLAI_SYSTEM_PROMPT
@@ -102,7 +114,7 @@ def _extract_tool_calls(text: str) -> tuple[list[dict[str, Any]], str]:
102
 
103
 
104
  class ControlAIAgent:
105
- """Universal Control Engineering Agent supporting MLX (Apple Silicon) and PyTorch/Transformers (Linux/CUDA)."""
106
 
107
  def __init__(
108
  self,
@@ -117,9 +129,24 @@ class ControlAIAgent:
117
  self.max_tool_steps = max_tool_steps
118
 
119
  # Detect platform & backend
120
- self.is_mlx = HAS_MLX and not model_path.startswith("Qwen/") and not os.environ.get("FORCE_TRANSFORMERS")
121
-
122
- if self.is_mlx:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  if adapter_path:
124
  self.model, self.mlx_tokenizer = mlx_load(model_path, adapter_path=adapter_path)
125
  else:
@@ -127,7 +154,7 @@ class ControlAIAgent:
127
  self.hf_tokenizer = AutoTokenizer.from_pretrained(model_path)
128
  else:
129
  # Universal PyTorch / Transformers fallback on Linux, Colab, HuggingFace, CUDA
130
- hf_id = "Qwen/Qwen2.5-3B-Instruct" if "mlx" in model_path else model_path
131
  self.hf_tokenizer = AutoTokenizer.from_pretrained(hf_id, trust_remote_code=True)
132
  self.model = AutoModelForCausalLM.from_pretrained(
133
  hf_id,
@@ -149,8 +176,23 @@ class ControlAIAgent:
149
  self.rag_index = None
150
 
151
  def _generate(self, prompt: str, max_tokens: int = 2000) -> str:
152
- """Universal text generation handling both MLX and PyTorch backends."""
153
- if self.is_mlx:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  return mlx_generate(
155
  self.model,
156
  self.mlx_tokenizer,
 
17
  except ImportError:
18
  HAS_MLX = False
19
 
20
+ try:
21
+ import llama_cpp
22
+ HAS_LLAMA_CPP = True
23
+ except ImportError:
24
+ HAS_LLAMA_CPP = False
25
+
26
+ try:
27
+ import ollama
28
+ HAS_OLLAMA = True
29
+ except ImportError:
30
+ HAS_OLLAMA = False
31
+
32
  from transformers import AutoModelForCausalLM, AutoTokenizer
33
 
34
  from controlai_agent.prompts import CONTROLAI_SYSTEM_PROMPT
 
114
 
115
 
116
  class ControlAIAgent:
117
+ """Universal Control Engineering Agent supporting GGUF, Ollama C++, Apple MLX, and PyTorch."""
118
 
119
  def __init__(
120
  self,
 
129
  self.max_tool_steps = max_tool_steps
130
 
131
  # Detect platform & backend
132
+ self.is_ollama = str(model_path).startswith("ollama")
133
+ self.is_gguf = str(model_path).endswith(".gguf") or "gguf" in str(model_path).lower()
134
+ self.is_mlx = HAS_MLX and not self.is_ollama and not self.is_gguf and not str(model_path).startswith("Qwen/") and not os.environ.get("FORCE_TRANSFORMERS")
135
+
136
+ if self.is_ollama:
137
+ self.ollama_model = model_path.split(":", 1)[1] if ":" in str(model_path) else "controlai"
138
+ self.hf_tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-3B-Instruct", trust_remote_code=True)
139
+ elif self.is_gguf:
140
+ if not HAS_LLAMA_CPP:
141
+ raise ImportError("llama-cpp-python is required to run GGUF models. Install it with: pip install llama-cpp-python")
142
+ self.llama_model = llama_cpp.Llama(
143
+ model_path=str(model_path),
144
+ n_gpu_layers=-1, # Offload all layers to Metal / CUDA GPU
145
+ n_ctx=4096,
146
+ verbose=False,
147
+ )
148
+ self.hf_tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-3B-Instruct", trust_remote_code=True)
149
+ elif self.is_mlx:
150
  if adapter_path:
151
  self.model, self.mlx_tokenizer = mlx_load(model_path, adapter_path=adapter_path)
152
  else:
 
154
  self.hf_tokenizer = AutoTokenizer.from_pretrained(model_path)
155
  else:
156
  # Universal PyTorch / Transformers fallback on Linux, Colab, HuggingFace, CUDA
157
+ hf_id = "Qwen/Qwen2.5-3B-Instruct" if "mlx" in str(model_path) else model_path
158
  self.hf_tokenizer = AutoTokenizer.from_pretrained(hf_id, trust_remote_code=True)
159
  self.model = AutoModelForCausalLM.from_pretrained(
160
  hf_id,
 
176
  self.rag_index = None
177
 
178
  def _generate(self, prompt: str, max_tokens: int = 2000) -> str:
179
+ """Universal text generation handling Ollama C++, GGUF llama_cpp, MLX, and PyTorch."""
180
+ if self.is_ollama:
181
+ res = ollama.generate(
182
+ model=self.ollama_model,
183
+ prompt=prompt,
184
+ options={"temperature": 0.2, "num_predict": max_tokens},
185
+ )
186
+ return res.get("response", "").strip()
187
+ elif self.is_gguf:
188
+ output = self.llama_model(
189
+ prompt,
190
+ max_tokens=max_tokens,
191
+ stop=["<|im_end|>", "<|endoftext|>"],
192
+ temperature=0.2,
193
+ )
194
+ return output["choices"][0]["text"].strip()
195
+ elif self.is_mlx:
196
  return mlx_generate(
197
  self.model,
198
  self.mlx_tokenizer,