Instructions to use Tayrrr/KaliSupport with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use Tayrrr/KaliSupport with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf Tayrrr/KaliSupport:Q6_K # Run inference directly in the terminal: llama cli -hf Tayrrr/KaliSupport:Q6_K
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf Tayrrr/KaliSupport:Q6_K # Run inference directly in the terminal: llama cli -hf Tayrrr/KaliSupport:Q6_K
Build from source code
git clone https://github.com/ggml-org/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-app # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama serve -hf Tayrrr/KaliSupport:Q6_K # Run inference directly in the terminal: ./build/bin/llama cli -hf Tayrrr/KaliSupport:Q6_K
Use Docker
docker model run hf.co/Tayrrr/KaliSupport:Q6_K
- Llama new
- LM Studio
- Jan
- Ollama
How to use Tayrrr/KaliSupport with Ollama:
ollama run hf.co/Tayrrr/KaliSupport:Q6_K
- Unsloth Desktop
- Pi
How to use Tayrrr/KaliSupport with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Tayrrr/KaliSupport:Q6_K
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "Tayrrr/KaliSupport:Q6_K" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use Tayrrr/KaliSupport with Docker Model Runner:
docker model run hf.co/Tayrrr/KaliSupport:Q6_K
- Lemonade
How to use Tayrrr/KaliSupport with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull Tayrrr/KaliSupport:Q6_K
Run and chat with the model
lemonade run user.KaliSupport-Q6_K
List all available models
lemonade list
- Hermes Agent
How to use Tayrrr/KaliSupport with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Tayrrr/KaliSupport:Q6_K
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default Tayrrr/KaliSupport:Q6_K
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use Tayrrr/KaliSupport with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Tayrrr/KaliSupport:Q6_K
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "Tayrrr/KaliSupport:Q6_K" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Download agent.py from Tayrrr/KaliSupport: direct link, hf CLI and curl.
- Browser
- Download file 22.8 kB
-
https://huggingface.co/Tayrrr/KaliSupport/resolve/main/agent.py
- Command line
-
hf download hf://Tayrrr/KaliSupport/agent.py
-
curl -L -o agent.py https://huggingface.co/Tayrrr/KaliSupport/resolve/main/agent.py
22.8 kB
| """Kali Agent ana orkestrator. | |
| Mimari ozeti | |
| ------------ | |
| [User] | |
| | | |
| v | |
| [Ollama / BaronLLM] --(ReAct: Thought + Action + Action Input)--> | |
| | | |
| v | |
| [parse_react] --> ParsedResponse (actions, final_answer) | |
| | | |
| v | |
| [ToolDispatcher] | |
| | \ | |
| | +--> [SafetyChecker] (block / warn / ok) | |
| | | |
| v | |
| [KaliSSH.run] --> CommandResult | |
| | | |
| v | |
| "Observation: ..." --geri model'e | |
| Akis bir "Final Answer:" gorene veya max_steps'e ulasana kadar donuyor. | |
| Kullanim | |
| -------- | |
| python agent.py # interaktif REPL | |
| python agent.py "10.0.0.5'i tara" # tek seferlik gorev | |
| Cikis: REPL'de :q / quit / Ctrl+C | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import sys | |
| from dataclasses import dataclass, field | |
| from typing import Optional | |
| import ollama | |
| from config import OllamaConfig, VoiceConfig | |
| from logger import SessionLogger | |
| from safety import SafetyChecker | |
| from ssh_client import KaliSSH, SSHConnectionError | |
| from tool_call import ( | |
| ParsedResponse, | |
| ToolCall, | |
| ToolDispatcher, | |
| format_observation, | |
| parse_react, | |
| ) | |
| from voice import VoiceCancelled, VoiceInput, VoiceUnavailableError | |
| # ----------------------------------------------------------------------------- | |
| # REact format hatirlatici (modele ilk gorevde eklenir) | |
| # ----------------------------------------------------------------------------- | |
| # Modelfile'da SYSTEM mesaji genel kurallari koyuyor; bu reminder ilk gorevde | |
| # enjekte edilen mikro format ozetidir. Modeli klasik ReAct formatina yaklastirir. | |
| _FORMAT_REMINDER = ( | |
| "ZORUNLU CIKTI FORMATI (sirayla, fazlasi yok):\n" | |
| "Thought: <tek paragraf, kisa>\n" | |
| "Action: run_cmd\n" | |
| "Action Input: <tek satir bash komutu>\n" | |
| "\n" | |
| "Sonra DUR. 'Observation:' yazma; biz dolduracagiz. Cevap geldikten sonra:\n" | |
| " - Yeni bir Thought + Action + Action Input ile devam et,\n" | |
| " - veya gorev bittiyse SADECE 'Final Answer: <ozet>'.\n" | |
| "\n" | |
| "YAPILMAYACAKLAR:\n" | |
| "- 'Action: run_cmd(komut)' SEKLINDE PARANTEZLI yazma. Action ve Action Input AYRI satirda olmali.\n" | |
| "- Action Input'ta backtick / kod blogu / yorum / 'Wait for output' gibi ifadeler kullanma.\n" | |
| "- Ayni mesajda birden fazla Action yazma; tek aksiyon -> Observation -> bir sonraki.\n" | |
| "- Final Answer'i Action ile ayni mesajda yazma; once Action calistirilir.\n" | |
| ) | |
| # ----------------------------------------------------------------------------- | |
| # Yardimci: konsol cikti | |
| # ----------------------------------------------------------------------------- | |
| _C_RESET = "\033[0m" | |
| _C_DIM = "\033[2m" | |
| _C_RED = "\033[31m" | |
| _C_GREEN = "\033[32m" | |
| _C_YELLOW = "\033[33m" | |
| _C_CYAN = "\033[36m" | |
| _C_BOLD = "\033[1m" | |
| def _hline(char: str = "-", n: int = 70) -> None: | |
| print(_C_DIM + char * n + _C_RESET) | |
| # ----------------------------------------------------------------------------- | |
| # Agent | |
| # ----------------------------------------------------------------------------- | |
| class AgentConfig: | |
| model: str | |
| host: str | |
| max_steps: int = 20 | |
| stream: bool = True | |
| # auto=False -> her adimda kullanici onayi sorulur (varsayilan) | |
| # auto=True -> Final Answer / max_steps'e kadar otomatik ilerler | |
| auto: bool = False | |
| # Modelfile PARAMETER'larini override etmek icin runtime options. | |
| options: dict = field(default_factory=dict) | |
| # Modelin Ollama daemon belleginde kalma suresi. "-1" sonsuz. | |
| keep_alive: str = "30m" | |
| class KaliAgent: | |
| kali: KaliSSH | |
| dispatcher: ToolDispatcher | |
| llm: ollama.Client | |
| logger: SessionLogger | |
| cfg: AgentConfig | |
| messages: list[dict] = field(default_factory=list) | |
| voice: Optional[VoiceInput] = None | |
| # --- ana akis ------------------------------------------------------- | |
| def run_task(self, task: str) -> str: | |
| """Tek bir kullanici gorevini Final Answer'a kadar surdur.""" | |
| first_turn = not self.messages | |
| first_payload = ( | |
| f"{_FORMAT_REMINDER}\nGOREV: {task}" if first_turn else task | |
| ) | |
| self.messages.append({"role": "user", "content": first_payload}) | |
| self.logger.event("user_task", task=task) | |
| for step in range(1, self.cfg.max_steps + 1): | |
| print(f"\n{_C_DIM}--- adim {step}/{self.cfg.max_steps} ---{_C_RESET}") | |
| response = self._chat_once() | |
| self.messages.append({"role": "assistant", "content": response}) | |
| parsed = parse_react(response) | |
| if parsed.is_final: | |
| final = parsed.final_answer or response.strip() | |
| self.logger.event("final_answer", content=final) | |
| return final | |
| if not parsed.has_action: | |
| # Model ne aksiyon ne final yazdi -> kibarca durtukle. | |
| nudge = ( | |
| "Observation: (Hicbir Action ya da Final Answer bulunamadi. " | |
| "Lutfen ReAct formatinda devam et.)" | |
| ) | |
| print(f"{_C_YELLOW}[uyari] model format dis ciktisi; nudge gonderiliyor{_C_RESET}") | |
| self.messages.append({"role": "user", "content": nudge}) | |
| self.logger.warn("model_off_format") | |
| continue | |
| actions = parsed.actions | |
| if len(actions) > 1: | |
| actions = self._ask_multi_action(actions) | |
| if not actions: | |
| self.messages.append( | |
| {"role": "user", "content": format_observation( | |
| "BLOCKED: kullanici tum aksiyonlari iptal etti." | |
| )} | |
| ) | |
| continue | |
| # Adim onayi (manuel mod). auto=True ise hic sorulmaz. | |
| if not self.cfg.auto: | |
| decision, actions = self._confirm_step(actions) | |
| if decision == "stop": | |
| self.logger.warn("step_stopped_by_user") | |
| print(f"{_C_DIM}[loop kullanici tarafindan duruduruldu; gorev tamamlanmadi]{_C_RESET}") | |
| return "[kullanici loop'u durdurdu]" | |
| if decision == "skip": | |
| self.messages.append({ | |
| "role": "user", | |
| "content": format_observation( | |
| "SKIPPED: kullanici bu komutu atladi. Yeni bir Action veya Final Answer ver." | |
| ), | |
| }) | |
| continue | |
| # decision == "go" -> actions ile devam | |
| for call in actions: | |
| print(f"{_C_CYAN}-> {call.short()}{_C_RESET}") | |
| obs = self.dispatcher.dispatch(call) | |
| self._print_observation(obs) | |
| self.messages.append( | |
| {"role": "user", "content": format_observation(obs)} | |
| ) | |
| self.logger.warn("max_steps_reached", limit=self.cfg.max_steps) | |
| return f"[max_steps={self.cfg.max_steps} asildi; gorev tamamlanmadi]" | |
| # --- LLM cagrisi ---------------------------------------------------- | |
| def _chat_once(self) -> str: | |
| """Ollama'ya bir tur sor, streaming sirasinda konsola yaz, full metni don.""" | |
| # ollama.Client.chat options=None ise bos dict yerine None gondermek | |
| # daha az suprize yol acar. | |
| options = self.cfg.options or None | |
| ka = self.cfg.keep_alive | |
| if self.cfg.stream: | |
| buf: list[str] = [] | |
| print(f"{_C_GREEN}[model] ", end="", flush=True) | |
| try: | |
| for chunk in self.llm.chat( | |
| model=self.cfg.model, | |
| messages=self.messages, | |
| stream=True, | |
| options=options, | |
| keep_alive=ka, | |
| ): | |
| piece = chunk.get("message", {}).get("content", "") | |
| if piece: | |
| buf.append(piece) | |
| print(piece, end="", flush=True) | |
| finally: | |
| print(_C_RESET) | |
| full = "".join(buf) | |
| else: | |
| resp = self.llm.chat( | |
| model=self.cfg.model, | |
| messages=self.messages, | |
| stream=False, | |
| options=options, | |
| keep_alive=ka, | |
| ) | |
| full = resp["message"]["content"] | |
| print(f"{_C_GREEN}[model]{_C_RESET}\n{full}") | |
| self.logger.model(full) | |
| return full | |
| # --- yardimcilar ---------------------------------------------------- | |
| def _print_observation(self, obs: str) -> None: | |
| head = obs.splitlines()[0] if obs else "" | |
| if head.startswith("BLOCKED") or head.startswith("ERROR"): | |
| color = _C_RED | |
| elif head.startswith("WARNING"): | |
| color = _C_YELLOW | |
| else: | |
| color = _C_DIM | |
| print(f"{color}{obs.rstrip()}{_C_RESET}") | |
| def _confirm_step( | |
| self, actions: list[ToolCall] | |
| ) -> tuple[str, list[ToolCall]]: | |
| """Manuel mod adim onayi. | |
| Returns: | |
| ("go", actions) : komut(lar) calistirilsin | |
| ("skip", []) : bu turu atla, modele 'skipped' bildir | |
| ("stop", []) : loop bitsin, REPL'e don | |
| """ | |
| first = actions[0] | |
| print() | |
| print(f"{_C_YELLOW}[ONAY GEREKIYOR] siradaki komut:{_C_RESET}") | |
| print(f" {_C_BOLD}{first.short(200)}{_C_RESET}") | |
| print( | |
| f"{_C_DIM} [Enter]/e calistir " | |
| f"d: komutu duzenle " | |
| f"s: bu adimi atla " | |
| f"q: loop'u durdur{_C_RESET}" | |
| ) | |
| try: | |
| choice = input("Onay > ").strip().lower() | |
| except (EOFError, KeyboardInterrupt): | |
| return "stop", [] | |
| if choice in {"", "e", "evet", "y", "yes", "go"}: | |
| return "go", actions | |
| if choice in {"d", "duzenle", "edit"}: | |
| try: | |
| new_cmd = input("Yeni komut > ").strip() | |
| except (EOFError, KeyboardInterrupt): | |
| return "stop", [] | |
| if not new_cmd: | |
| return "skip", [] | |
| edited = ToolCall(tool=first.tool, args={"cmd": new_cmd}, raw=new_cmd) | |
| self.logger.info( | |
| "user_edited_command", | |
| original=first.args.get("cmd"), | |
| new=new_cmd, | |
| ) | |
| return "go", [edited] | |
| if choice in {"s", "skip", "atla"}: | |
| return "skip", [] | |
| if choice in {"q", "stop", "dur", ":q", "quit", "exit"}: | |
| return "stop", [] | |
| print(f"{_C_DIM}[anlasilmadi -> calistiriliyor]{_C_RESET}") | |
| return "go", actions | |
| def _ask_multi_action(self, actions: list[ToolCall]) -> list[ToolCall]: | |
| print(f"\n{_C_YELLOW}[!] Model ayni mesajda {len(actions)} tool cagrisi yazdi:{_C_RESET}") | |
| for i, a in enumerate(actions, 1): | |
| print(f" {i}. {a.short()}") | |
| print( | |
| f"{_C_DIM}Secim formati: '1' / '1,3' / 'all' / 'first' / 'none'{_C_RESET}" | |
| ) | |
| try: | |
| choice = input("Secim > ").strip().lower() | |
| except (EOFError, KeyboardInterrupt): | |
| return [] | |
| if choice in {"all", "a", "*"}: | |
| self.logger.info("multi_action_choice", choice="all") | |
| return actions | |
| if choice in {"first", "f", ""}: | |
| self.logger.info("multi_action_choice", choice="first") | |
| return [actions[0]] | |
| if choice in {"none", "n", "skip", ":q"}: | |
| self.logger.info("multi_action_choice", choice="none") | |
| return [] | |
| try: | |
| picks = [int(x.strip()) - 1 for x in choice.split(",")] | |
| chosen = [actions[i] for i in picks if 0 <= i < len(actions)] | |
| self.logger.info("multi_action_choice", choice=choice, picked=len(chosen)) | |
| return chosen or [actions[0]] | |
| except ValueError: | |
| print(f"{_C_YELLOW}Anlasilmadi, ilk aksiyon calistiriliyor.{_C_RESET}") | |
| return [actions[0]] | |
| # ----------------------------------------------------------------------------- | |
| # REPL / main | |
| # ----------------------------------------------------------------------------- | |
| def _build_agent(log: SessionLogger) -> KaliAgent: | |
| safety = SafetyChecker.from_env(logger=log) | |
| kali = KaliSSH.from_config(logger=log) | |
| kali.connect() | |
| dispatcher = ToolDispatcher(kali, safety, logger=log) | |
| ocfg = OllamaConfig.from_env() | |
| llm = ollama.Client(host=ocfg.host) | |
| options = ocfg.runtime_options() | |
| # Modelfile'da tanimli stop token'lari runtime'da da gonderiyoruz; aksi | |
| # halde modelin uydurma "Observation: Wait..." yazmasi history'i kirletir. | |
| options["stop"] = [ | |
| "Observation:", | |
| "Tool Output:", | |
| "<|im_end|>", | |
| "<|endoftext|>", | |
| "<think>", | |
| ] | |
| log.info("ollama_options_override", **options) | |
| print(f"{_C_DIM}[ollama options: {options}]{_C_RESET}") | |
| agent_cfg = AgentConfig( | |
| model=ocfg.model, | |
| host=ocfg.host, | |
| options=options, | |
| keep_alive=ocfg.keep_alive, | |
| ) | |
| # Voice (sesli komut) opsiyoneldir; kutuphane eksikse sessizce devre disi. | |
| vcfg = VoiceConfig.from_env() | |
| voice = VoiceInput(vcfg, logger=log) | |
| v_ok, v_why = voice.is_available() | |
| if v_ok: | |
| log.info( | |
| "voice_ready", | |
| model=vcfg.model_size, | |
| device=vcfg.device, | |
| language=vcfg.language, | |
| ) | |
| print( | |
| f"{_C_DIM}[voice hazir: model={vcfg.model_size}, " | |
| f"device={vcfg.device}, lang={vcfg.language}]{_C_RESET}" | |
| ) | |
| # Modeli baslangicta yukle ki ilk :v'de kullanici 30+ saniye | |
| # bekleyip "donmus" sanmasin. Hata olursa lazy moda geri duser. | |
| if vcfg.prewarm: | |
| try: | |
| voice.warmup() | |
| except Exception as exc: # noqa: BLE001 | |
| log.warn("voice_prewarm_error", detail=str(exc)) | |
| print( | |
| f"{_C_YELLOW}[voice on-yukleme atlandi: {exc} " | |
| f"(:v calistirildiginda yeniden denenir){_C_RESET}" | |
| ) | |
| else: | |
| log.info("voice_disabled", reason=v_why or "") | |
| print(f"{_C_DIM}[voice kapali: {v_why}]{_C_RESET}") | |
| voice = None # agent.voice None ise :v komutu net hata doner | |
| return KaliAgent( | |
| kali=kali, | |
| dispatcher=dispatcher, | |
| llm=llm, | |
| logger=log, | |
| cfg=agent_cfg, | |
| voice=voice, | |
| ) | |
| def _verify_model(client: ollama.Client, model_name: str) -> Optional[str]: | |
| """Modelin Ollama'da bulunup bulunmadigini denetle. Bulunmazsa hata mesaji.""" | |
| try: | |
| listed = client.list() | |
| except Exception as exc: # noqa: BLE001 | |
| return f"Ollama'ya ulasilamadi: {exc}" | |
| models = listed.get("models", []) | |
| names = {m.get("name") or m.get("model", "") for m in models} | |
| if model_name not in names and not any( | |
| n.startswith(model_name + ":") for n in names | |
| ): | |
| return ( | |
| f"Ollama'da '{model_name}' modeli yok. Mevcut: {sorted(names) or '[hic]'}\n" | |
| f"Modelfile'dan olusturmak icin: ollama create {model_name} -f Modelfile" | |
| ) | |
| return None | |
| _VOICE_HELP = ( | |
| "[v] Enter -> kullan " | |
| "d -> duzenle " | |
| "r -> tekrar dinle " | |
| "q -> iptal" | |
| ) | |
| def _voice_capture(agent: KaliAgent) -> Optional[str]: | |
| """Bir tur mikrofon dinle, kullaniciyla onayla, gorev metni don. | |
| Donus None ise gorev verilmedi (iptal / bos transkript). | |
| """ | |
| if agent.voice is None: | |
| print( | |
| f"{_C_RED}[voice kapali] kutuphane eksik veya VOICE_ENABLED=false. " | |
| f"Detay icin `python -m voice listen` calistir.{_C_RESET}" | |
| ) | |
| return None | |
| while True: | |
| try: | |
| text = agent.voice.listen_once() | |
| except VoiceCancelled: | |
| return None | |
| except VoiceUnavailableError as exc: | |
| print(f"{_C_RED}[voice hatasi] {exc}{_C_RESET}") | |
| agent.logger.error("voice_error_in_loop", detail=str(exc)) | |
| return None | |
| if not text: | |
| print(f"{_C_YELLOW}[voice] bos transkript; tekrar dene.{_C_RESET}") | |
| continue | |
| print(f"{_C_CYAN}>> duydugum:{_C_RESET} {text}") | |
| if not agent.voice.cfg.confirm: | |
| return text | |
| print(f"{_C_DIM}{_VOICE_HELP}{_C_RESET}") | |
| try: | |
| choice = input("Voice > ").strip().lower() | |
| except (EOFError, KeyboardInterrupt): | |
| return None | |
| if choice in {"", "e", "y", "yes", "evet", "ok", "go"}: | |
| return text | |
| if choice in {"d", "duzenle", "edit"}: | |
| try: | |
| edited = input(f"Duzenle > {text}\nYeni > ").strip() | |
| except (EOFError, KeyboardInterrupt): | |
| return None | |
| return edited or text | |
| if choice in {"r", "again", "tekrar"}: | |
| continue | |
| if choice in {"q", ":q", "quit", "exit", "iptal"}: | |
| return None | |
| # anlasilmadi -> oldugu gibi gonder | |
| return text | |
| def _repl(agent: KaliAgent, *, voice_default: bool = False) -> int: | |
| mode_hint = "AUTO" if agent.cfg.auto else "her adimda onay sorulur" | |
| voice_status = ( | |
| "voice acik" if agent.voice is not None else "voice kapali" | |
| ) | |
| voice_hint = " | her prompt'ta otomatik mikrofon" if voice_default else "" | |
| print(f"{_C_BOLD}Kali Agent baslatildi.{_C_RESET} " | |
| f"{_C_DIM}({mode_hint} | {voice_status} | :q cik | " | |
| f":r reset | :v sesli komut{voice_hint}){_C_RESET}") | |
| _hline("=") | |
| while True: | |
| task: Optional[str] = None | |
| # Voice-first mod: prompt yerine direkt mikrofon ac. | |
| if voice_default and agent.voice is not None: | |
| print(f"\n{_C_BOLD}Gorev (voice) >{_C_RESET} " | |
| f"{_C_DIM}(metin yazmak icin Enter -> sonra normal prompt){_C_RESET}") | |
| try: | |
| pre = input("").strip() | |
| except (EOFError, KeyboardInterrupt): | |
| print() | |
| break | |
| if pre: | |
| # kullanici metin girdi; voice bypass | |
| task = pre | |
| else: | |
| got = _voice_capture(agent) | |
| if not got: | |
| continue | |
| task = got | |
| else: | |
| try: | |
| raw = input(f"\n{_C_BOLD}Gorev > {_C_RESET}").strip() | |
| except (EOFError, KeyboardInterrupt): | |
| print() | |
| break | |
| if not raw: | |
| continue | |
| if raw.lower() in {":q", "quit", "exit"}: | |
| break | |
| if raw.lower() in {":r", "reset"}: | |
| agent.messages.clear() | |
| print(f"{_C_DIM}[mesaj gecmisi temizlendi]{_C_RESET}") | |
| continue | |
| if raw.lower() in {":v", "voice", ":voice"}: | |
| got = _voice_capture(agent) | |
| if not got: | |
| continue | |
| task = got | |
| else: | |
| task = raw | |
| if not task: | |
| continue | |
| try: | |
| answer = agent.run_task(task) | |
| except SSHConnectionError as exc: | |
| print(f"{_C_RED}[SSH HATASI] {exc}{_C_RESET}") | |
| agent.logger.error("ssh_error_in_loop", detail=str(exc)) | |
| continue | |
| except KeyboardInterrupt: | |
| print(f"\n{_C_YELLOW}[gorev iptal edildi]{_C_RESET}") | |
| agent.logger.warn("task_aborted") | |
| continue | |
| _hline("=") | |
| print(f"{_C_BOLD}=== Final Answer ==={_C_RESET}") | |
| print(answer) | |
| _hline("=") | |
| return 0 | |
| def main(argv: Optional[list[str]] = None) -> int: | |
| parser = argparse.ArgumentParser(description="Kali Agent (lokal BaronLLM + SSH)") | |
| parser.add_argument( | |
| "task", | |
| nargs="*", | |
| help="Tek seferlik gorev metni. Bos birakirsan REPL acilir.", | |
| ) | |
| parser.add_argument( | |
| "--max-steps", | |
| type=int, | |
| default=20, | |
| help="ReAct dongusunde maksimum adim sayisi (varsayilan 20).", | |
| ) | |
| parser.add_argument( | |
| "--no-stream", | |
| action="store_true", | |
| help="Streaming kapali (debug icin).", | |
| ) | |
| parser.add_argument( | |
| "--auto", | |
| action="store_true", | |
| help="Final Answer'a kadar her adimi otomatik calistir (manuel onay yok).", | |
| ) | |
| parser.add_argument( | |
| "--voice", | |
| action="store_true", | |
| help="REPL'de her prompt'ta otomatik olarak mikrofonu ac (voice-first mod). " | |
| "Tek seferlik :v ile manuel kullanmak istersen bu bayraga gerek yok.", | |
| ) | |
| args = parser.parse_args(argv) | |
| log = SessionLogger.create() | |
| log.info("agent_start") | |
| try: | |
| agent = _build_agent(log) | |
| except SSHConnectionError as exc: | |
| print(f"{_C_RED}SSH baglanti hatasi: {exc}{_C_RESET}") | |
| log.close() | |
| return 1 | |
| except Exception as exc: # noqa: BLE001 | |
| print(f"{_C_RED}Baslatma hatasi: {exc}{_C_RESET}") | |
| log.error("startup_error", detail=str(exc)) | |
| log.close() | |
| return 2 | |
| agent.cfg = AgentConfig( | |
| model=agent.cfg.model, | |
| host=agent.cfg.host, | |
| max_steps=args.max_steps, | |
| stream=not args.no_stream, | |
| auto=args.auto, | |
| options=agent.cfg.options, | |
| keep_alive=agent.cfg.keep_alive, | |
| ) | |
| mode = "AUTO" if args.auto else "MANUEL (her adimda onay)" | |
| print(f"{_C_DIM}[mod: {mode}]{_C_RESET}") | |
| err = _verify_model(agent.llm, agent.cfg.model) | |
| if err: | |
| print(f"{_C_RED}{err}{_C_RESET}") | |
| agent.kali.close() | |
| log.close() | |
| return 3 | |
| if args.voice and agent.voice is None: | |
| print( | |
| f"{_C_YELLOW}[uyari] --voice istendi ama voice kapali; " | |
| f"normal metin moduna geciliyor.{_C_RESET}" | |
| ) | |
| try: | |
| if args.task: | |
| task = " ".join(args.task) | |
| answer = agent.run_task(task) | |
| _hline("=") | |
| print(f"{_C_BOLD}=== Final Answer ==={_C_RESET}\n{answer}") | |
| return 0 | |
| return _repl(agent, voice_default=args.voice) | |
| finally: | |
| agent.kali.close() | |
| log.close() | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |