Spaces:
Running on Zero
Running on Zero
atakan commited on
Commit ·
9b35e00
1
Parent(s): 2d71e4f
feat: Add high-speed C++ GGUF and Ollama engine backends to agent orchestrator
Browse files
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
|
| 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.
|
| 121 |
-
|
| 122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 153 |
-
if self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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,
|