Przejdź do treści

04 - Tools Registry (Qwen orchestrator)

Qwen 32B w kony-brain używa --enable-auto-tool-choice --tool-call-parser hermes. Kony ma 26 tools łącznie: - 12 tools "wewnętrznych" w tools.py (FlexyCRM, Kony Hub, RAG, research) - 14 tools "bridge" w bridge_tools.py (calendar, gmail, HA, drive - przez n8n Kony Bridge webhook)

Każdy tool ma OpenAI JSON schema definition. Qwen wywołuje tool przez function calling, execute_tool() w tools.py dispatchuje.


Tools w tools.py (wewnętrzne, direct HTTP do FlexyCRM/Kony Hub)

FlexyCRM Tasks

list_urgent_tasks {limit?: int} - Priorytetowe zadania (high priority + due date wkrótce)

list_client_tasks {client_hint: str, limit?: int} - Zadania dla konkretnego klienta (fuzzy match po nazwie)

Kony Hub captures

get_kony_capture {kony_number: int} - Pobierz jeden capture po Kony #N

list_recent_captures {limit?: int, hours?: int} - Ostatnie N capture'ów z ostatnich H godzin

search_captures {query: str, limit?: int} - Full-text search przez original_text, agent_suggestion, llm_analysis

search_captures_semantic {query: str, top_k?: int} - RAG search przez kony-embed. Cosine similarity, próg 0.72. Dodane 2026-08-30 (M5 Kierunek 1).

unresolved_count {} - Ile captures nie ma resolved_at (zaległe do rozwiązania)

mark_capture_done {kony_number: int, note?: str} - Ustaw resolved_at=now, ewentualnie dodaj notatkę

mark_capture_undone {kony_number: int} - Reverse (usuń resolved_at)

save_note {text: str, intent?: str, title?: str} - Zapisz nowy capture do Kony Hub jako "kony-conversation" source_app (używa Qwen gdy user w rozmowie mówi "zapisz to")

Meta tools

research {query: str, depth?: 'shallow'|'deep'} - Brave Search + Qwen synthesis. depth=deep = więcej search results + głębszy summary.

execute_capture {kony_number: int} - Uruchom "execute pipeline" na capture (detect tasks w treści → auto-create FlexyCRM tasks). Beta feature.


Bridge tools w bridge_tools.py (via n8n Kony Bridge webhook)

Wszystkie te wywoływane przez POST n8n.chcedointernetu.pl/webhook/kony-bridge z body {intent: 'xxx', args: {...}}. n8n workflow 88zekiBO4NPeMpjn dispatchuje.

Calendar (Google Calendar OAuth)

calendar_today {} - Wydarzenia z dziś (obydwa kalendarze: primary + ratunku@chcedointernetu.pl, merge append, JS date filter Europe/Warsaw)

calendar_this_week {} - Wydarzenia z tego tygodnia (do +7d)

calendar_next_event {} - Najbliższe wydarzenie od teraz (do +30d)

calendar_find_free_slot {duration_minutes: int, day?: str, earliest?: str} - Znajdź wolne okno w dniu (default: dzisiaj)

calendar_create_event {summary: str, start_iso: str, end_iso: str, description?: str, location?: str, calendar?: 'primary'|'ratunku'}

Gmail

mail_unread_count {} - Ile nieprzeczytanych w INBOX

mail_recent {limit?: int, hours?: int} - Ostatnie maile (bez OG spam/promotions)

mail_search {query: str, limit?: int} - Gmail search operator

mail_send {to: str, subject: str, body: str, cc?: str} - Wyślij mail (uwaga: watch out for feedback loops, sprawdź czy adresat nie tworzy triggera dla innego workflow!)

Home Assistant

ha_status {entity_id?: str} - Stany urządzeń (all lub konkretny)

ha_turn_on {entity_id: str} - Włącz (np. light.salon_main, switch.kettle)

ha_turn_off {entity_id: str} - Wyłącz

ha_speak {message: str, target?: str} - TTS na Google Home. Default target: media_player.clock (Lenovo Clock w sypialni - jedyny realnie działający speaker w HA, patrz [[project_ha_speakers]])

Google Drive

drive_create_doc {title: str, content: str, folder?: str} - Utwórz Google Doc w Drive Konrada


Jak Qwen decyduje który tool wywołać

Qwen dostaje w system prompt (QWEN_SYSTEM_PROMPT w app.py) wysokopoziomowy opis Kony + listę tools jako function definitions. Reguły które Qwen intuicyjnie stosuje:

  • "co mam dziś w kalendarzu"calendar_today
  • "znajdź wolne okno na 30 min"calendar_find_free_slot
  • "jakie mam pilne zadania"list_urgent_tasks
  • "co pisałem o Aureliuszu"search_captures_semantic (nie search_captures bo semantic lepiej łapie kontekstualne pytania)
  • "zapisz notatkę: xxx"save_note
  • "włącz kuchnię"ha_turn_on entity_id=switch.kitchen_lights
  • "sprawdź co Anthropic ma nowego"research query="Anthropic latest news" depth=shallow
  • "powiedz w salonie: mam spotkanie za 15 min"ha_speak message="..." target=media_player.clock (bo salon nie ma realnego endpointu)

RAG auto-inject (nie tool, ale kluczowe)

Kony automatycznie robi RAG search PRZED wywołaniem Qwen. Jeśli user query jest pytaniem (nie command), kony-brain:

  1. Embed user query z kony-embed :8018
  2. Cosine similarity vs in-memory index (~200 captures)
  3. Jeśli top-3 sim > 0.72 → wsadzi do system prompt jako ## Kontekst z Twoich notatek:

Efekt: Qwen widzi relevantne notatki bez ręcznego search_captures_semantic. Jeśli user zapyta "co ostatnio mówiłem o Aureliuszu", Qwen dostanie już 3 najbardziej pasujące captures - może odpowiedzieć od razu bez tool call.

Threshold 0.72 dostosowany dla mmlw (roberta-large PL). Za nisko = pollution, za wysoko = zero context.


Dodawanie nowego toola

  1. Definition JSON w tools.py TOOL_DEFS list albo bridge_tools.py BRIDGE_TOOL_DEFS
  2. Implementation function async def tool_xxx(args: dict) -> dict: w tools.py albo add case w execute_bridge_tool() w bridge_tools.py
  3. Dispatcher w execute_tool() (tools.py) albo execute_bridge_tool() (bridge_tools.py)
  4. Restart docker restart kony-brain żeby Qwen widział nowy tool w schema
  5. Test: postaw pytanie w Conversation apce które powinno wywołać nowy tool, sprawdź logi docker logs kony-brain --tail 20

Uwaga context window: Qwen 32B ma 16k tokens context. Każdy tool def zjada ~150-300 tokens w schema. Za dużo tools = mniej miejsca na RAG + history. 26 tools = ~5-6k tokens overhead. Docelowe max ~30 tools zanim trzeba splitować na dedykowane sub-agenty.


Pokrewne