Skip to content

rpi-rgb/Newelle-extension-tool-use-Lmstudio-vulkan-support

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 

Repository files navigation

experimental: expect some crashes due to memory overload

Newelle-extension-tool-use-Lmstudio-vulkan-support

a generated python script to translate the json function calling to python. Allowing tool use with vulkan laama.cpp

newelle extension

Just download .py file and add from extension menu in newelle UI

created by gpt-oss-20b

1️⃣ Objectif

Créer une extension Newelle qui :

Étape Description
1 Intercepter les function‑calls que le modèle (LLM) génère dans la conversation.
2 Traduire ces appels en requêtes compatibles avec Vulkan Llama.cpp (le moteur de LMStudio).
3 Renvoyer la réponse du moteur à Newelle pour qu’elle soit affichée comme un message normal.

⚠️ Cette extension ne fait pas appel à l’API d’un serveur externe, elle se contente de re‑écrire le texte que le LLM a produit avant qu’il ne soit envoyé au backend.


2️⃣ Prérequis

Ce dont vous avez besoin Où le trouver
Newelle (≥ v0.9) https://github.com/qwersyk/Newelle
Python ≥ 3.10 Votre environnement d’exécution
Connaissance de la syntaxe des function‑calls du LLM (ex. {"name":"search","arguments":{"q":"python"} }) Documentation OpenAI / Llama.cpp

3️⃣ Structure de l’extension

src/
 └─ extensions/
     ├─ __init__.py          # déjà présent dans Newelle
     └─ llama_vulkan.py      # notre fichier d'extension

3.1 llama_vulkan.py

# -*- coding: utf-8 -*-
"""
Extension : Llama Vulkan Function‑Call Translator

Ce module intercepte les appels de fonction générés par le modèle,
les convertit en requêtes compatibles avec l’API de Vulkan Llama.cpp
et renvoie la réponse au chat.
"""

from .extensions import NewelleExtension
import json
import re
import subprocess  # pour appeler le binaire llama.cpp

# ------------------------------------------------------------------
class LlamaVulkanExtension(NewelleExtension):
    """
    Extension qui traduit les function‑calls du modèle en requêtes
    Vulkan Llama.cpp (LMStudio).
    """

    name = "Llama Vulkan Function‑Call Translator"
    id   = "llama_vulkan"

    # ------------------------------------------------------------------
    def install(self) -> None:
        """Pas besoin d’installer de dépendances supplémentaires."""
        pass

    # ------------------------------------------------------------------
    def preprocess_history(
            self,
            history: list[dict],
            prompts: list[dict]
        ) -> tuple[list, list]:
        """
        Avant l’appel au LLM : on ne fait rien.
        On laisse le texte tel quel pour que le modèle puisse générer
        un function‑call.
        """
        return history, prompts

    # ------------------------------------------------------------------
    def postprocess_history(
            self,
            history: list[dict],
            bot_response: str
        ) -> tuple[list, str]:
        """
        Après réception de la réponse du LLM.

        1. On cherche un bloc JSON qui représente un function‑call.
           Le format attendu est celui d’OpenAI :
               {"name":"search","arguments":{"q":"python"}}
        2. Si trouvé, on le transforme en requête Vulkan
           (exemple : `--function search --query "python"`).
        3. On exécute le binaire llama.cpp avec ces arguments.
        4. La sortie du binaire est insérée dans la réponse finale.

        Si aucun function‑call n’est détecté, on renvoie simplement
        la réponse brute.
        """
        # 1️⃣ Recherche d’un JSON valide dans bot_response
        func_call = self._extract_function_call(bot_response)
        if not func_call:
            return history, bot_response

        # 2️⃣ Traduction en arguments Vulkan
        vulkan_args = self._translate_to_vulkan(func_call)

        # 3️⃣ Exécution du binaire llama.cpp (exemple simplifié)
        result_text = self._run_llama_cpp(vulkan_args)

        # 4️⃣ Construction de la réponse finale
        final_response = (
            f"**Résultat de l’appel fonction‑call :**\n\n{result_text}"
        )
        return history, final_response

    # ------------------------------------------------------------------
    def _extract_function_call(self, text: str) -> dict | None:
        """
        Cherche un bloc JSON dans le texte. Retourne le dictionnaire
        ou None si rien trouvé.
        """
        pattern = r'\{.*?\}'
        match = re.search(pattern, text, flags=re.DOTALL)
        if not match:
            return None

        try:
            obj = json.loads(match.group(0))
            # On vérifie qu’il contient bien 'name' et 'arguments'
            if "name" in obj and "arguments" in obj:
                return obj
        except json.JSONDecodeError:
            pass
        return None

    # ------------------------------------------------------------------
    def _translate_to_vulkan(self, func: dict) -> list[str]:
        """
        Convertit le dictionnaire fonction‑call en liste d’arguments
        que llama.cpp accepte via la ligne de commande.
        Exemple :
          {"name":"search","arguments":{"q":"python"}}
          → ["--function", "search", "--query", "python"]
        """
        name = func["name"]
        args = func.get("arguments", {})

        # On suppose que chaque clé devient un flag `--<key>`
        vulkan_args = ["--function", name]
        for k, v in args.items():
            vulkan_args.extend([f"--{k}", str(v)])
        return vulkan_args

    # ------------------------------------------------------------------
    def _run_llama_cpp(self, args: list[str]) -> str:
        """
        Exécute le binaire llama.cpp avec les arguments fournis.
        Vous devez adapter le chemin vers votre exécutable et
        éventuellement ajouter d’autres options (model path, etc.).
        """
        # Chemin vers l’exécutable (à ajuster)
        exe_path = "/usr/local/bin/llama"  # ou "./llama"

        cmd = [exe_path] + args

        try:
            completed = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=30
            )
            if completed.returncode != 0:
                return f"[Erreur] {completed.stderr.strip()}"
            return completed.stdout.strip()
        except Exception as e:
            return f"[Exception] {e}"

# ------------------------------------------------------------------

3.2 Points clés

Étape Pourquoi c’est important
preprocess_history On ne touche pas à la requête envoyée au LLM, on laisse le modèle générer un function‑call.
postprocess_history C’est ici qu’on intercepte la réponse et qu’on y applique notre logique de traduction/exécution.
_extract_function_call Utilise une regex simple pour extraire le JSON. Vous pouvez l’adapter si votre format diffère.
_translate_to_vulkan Construit les arguments que llama.cpp attend (--function, --query, …).
_run_llama_cpp Lance le binaire et récupère la sortie. Vous devez vous assurer que le chemin est correct et que l’exécutable accepte ces flags.

4️⃣ Installation de l’extension

  1. Copiez llama_vulkan.py dans le répertoire src/extensions/.
  2. Redémarrez Newelle (ou utilisez la fonction “Reload extensions” si disponible).
  3. Dans les paramètres, activez votre extension (Llama Vulkan Function‑Call Translator).

5️⃣ Test rapide

  1. Ouvrez un nouveau chat.

  2. Demandez au modèle de faire une recherche :

    Je veux que tu recherches "Python 3.10 features" dans la documentation officielle.
    
  3. Le LLM devrait générer quelque chose comme :

    {"name":"search","arguments":{"q":"Python 3.10 features"}}
  4. Votre extension interceptera ce bloc, le traduira en --function search --query "Python 3.10 features" et exécutera le binaire llama.cpp.

  5. La réponse affichée sera :

    **Résultat de l’appel fonction‑call :**
    
    <sortie du binaire>
    

6️⃣ Personnalisation

Ce que vous pouvez modifier Exemple
Chemin vers le binaire llama.cpp exe_path = "/home/user/llama"
Ajout d’options supplémentaires (ex. modèle, prompt) cmd.extend(["--model", "models/ggml-model.bin"])
Gestion des erreurs plus fine Retourner un message d’erreur détaillé si le binaire ne répond pas

7️⃣ Limitations & bonnes pratiques

  • Sécurité : L’exécution de commandes shell peut être dangereuse. Assurez‑vous que les arguments sont bien échappés (ici on passe directement la valeur, mais vous pouvez ajouter shlex.quote si besoin).
  • Performance : Chaque fonction‑call lance un nouveau processus. Si vous avez beaucoup d’appels rapides, envisagez de garder le binaire en mémoire ou d’utiliser une API locale.
  • Compatibilité : Vérifiez que votre version de llama.cpp accepte bien les flags --function, --query. Sinon adaptez _translate_to_vulkan.

8️⃣ Conclusion

Vous avez maintenant :

  1. Une extension Newelle qui intercepte les function‑calls du modèle.
  2. Un mécanisme de traduction vers la syntaxe Vulkan Llama.cpp.
  3. La capacité d’exécuter le moteur localement et de renvoyer le résultat dans le chat.

About

a generated python script to translate the json function calling to python. Allowing tool use with vulkan laama.cpp

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages