MrMoz33/tokioai-coder-iot
0
1"""2TokioAI Engine -- Adaptive Memory / Few-Shot Learning3Maintains a persistent store of successful interactions for dynamic few-shot injection.4 5This is the "fine-tuning in real time" -- instead of modifying weights,6we modify the context the model sees, injecting relevant examples that7worked before.8 9Storage: JSON file, indexed by intent + keywords for fast retrieval.10"""11 12import json13import os14import re15import time16from collections import Counter17from typing import Dict, List, Optional18 19DEFAULT_MEMORY_PATH = os.path.expanduser("~/.tokioai-engine/memory.json")20MAX_EXAMPLES_PER_CATEGORY = 10021MAX_EXAMPLE_AGE_DAYS = 9022 23 24class EngineMemory:25 """26 Persistent few-shot memory that makes the model smarter over time.27 28 Stores successful (user_input -> model_output) pairs, tagged by:29 - intent (tool_call, code, text, decision)30 - keywords (extracted from user input)31 - success (was the output valid/useful?)32 - timestamp33 34 On each query, retrieves the most relevant examples for few-shot injection.35 """36 37 def __init__(self, path: str = None):38 self.path = path or DEFAULT_MEMORY_PATH39 os.makedirs(os.path.dirname(self.path), exist_ok=True)40 self.examples: List[Dict] = []41 self._load()42 43 def _load(self):44 if os.path.exists(self.path):45 try:46 with open(self.path, "r") as f:47 self.examples = json.load(f)48 except (json.JSONDecodeError, IOError):49 self.examples = []50 else:51 self.examples = self._seed_examples()52 self._save()53 54 def _save(self):55 with open(self.path, "w") as f:56 json.dump(self.examples, f, indent=2, ensure_ascii=False)57 58 def add(59 self,60 user_input: str,61 model_output: str,62 intent: str,63 success: bool = True,64 tool_name: str = None,65 latency_ms: int = None,66 ):67 """Record a successful interaction as a few-shot example."""68 # NEVER store errors, empty outputs, or hallucinated tool output69 if not model_output or len(model_output.strip()) < 5:70 return71 if "Error calling model" in model_output or "Client Error" in model_output:72 return73 if "Server Error" in model_output or "Traceback" in model_output:74 return75 if not success:76 return77 # Skip duplicate: same user input + same first 100 chars of output78 key = (user_input[:100], model_output[:100])79 for ex in self.examples[-50:]: # Check last 50 only for speed80 if (ex.get("user", "")[:100], ex.get("assistant", "")[:100]) == key:81 return82 83 keywords = self._extract_keywords(user_input)84 85 entry = {86 "user": user_input[:500],87 "assistant": model_output[:1000],88 "intent": intent,89 "keywords": keywords,90 "success": success,91 "tool_name": tool_name,92 "latency_ms": latency_ms,93 "timestamp": time.time(),94 "uses": 0, # How many times this was used as few-shot95 }96 97 self.examples.append(entry)98 99 # Prune old/excess entries100 self._prune()101 self._save()102 103 def retrieve(104 self,105 user_input: str,106 intent: str = None,107 top_k: int = 3,108 ) -> List[Dict]:109 """110 Retrieve the most relevant few-shot examples for a given query.111 Uses keyword overlap + intent matching + recency for ranking.112 """113 if not self.examples:114 return []115 116 query_keywords = set(self._extract_keywords(user_input))117 scored = []118 119 for ex in self.examples:120 if not ex.get("success", True):121 continue # Skip failed examples122 123 score = 0.0124 125 # Keyword overlap (most important)126 ex_keywords = set(ex.get("keywords", []))127 overlap = query_keywords & ex_keywords128 if overlap:129 score += len(overlap) * 3.0130 131 # Intent match132 if intent and ex.get("intent") == intent:133 score += 2.0134 135 # Recency bonus (newer = better, decay over 30 days)136 age_days = (time.time() - ex.get("timestamp", 0)) / 86400137 recency = max(0, 1.0 - age_days / 30)138 score += recency139 140 # Usage penalty (avoid showing the same examples every time)141 score -= ex.get("uses", 0) * 0.5142 143 if score > 0:144 scored.append((score, ex))145 146 # Sort by score descending147 scored.sort(key=lambda x: x[0], reverse=True)148 149 # Mark as used150 results = []151 for score, ex in scored[:top_k]:152 ex["uses"] = ex.get("uses", 0) + 1153 results.append(ex)154 155 if results:156 self._save()157 158 return results159 160 def get_stats(self) -> Dict:161 """Return memory statistics."""162 if not self.examples:163 return {"total": 0}164 165 intents = Counter(ex.get("intent", "unknown") for ex in self.examples)166 tools = Counter(ex.get("tool_name", "none") for ex in self.examples if ex.get("tool_name"))167 success_rate = sum(1 for ex in self.examples if ex.get("success", True)) / len(self.examples)168 169 return {170 "total": len(self.examples),171 "by_intent": dict(intents),172 "by_tool": dict(tools),173 "success_rate": round(success_rate, 2),174 "oldest_days": round((time.time() - min(ex.get("timestamp", time.time()) for ex in self.examples)) / 86400, 1),175 }176 177 def feedback(self, index: int, success: bool):178 """Update success status for an example (for learning from failures)."""179 if 0 <= index < len(self.examples):180 self.examples[index]["success"] = success181 self._save()182 183 def _extract_keywords(self, text: str) -> List[str]:184 """Extract meaningful keywords from text."""185 # Lowercase, split, remove common words186 stopwords = {187 "the", "a", "an", "is", "are", "was", "were", "be", "been",188 "have", "has", "had", "do", "does", "did", "will", "would",189 "could", "should", "may", "might", "can", "shall", "must",190 "to", "of", "in", "for", "on", "with", "at", "by", "from",191 "it", "its", "this", "that", "these", "those", "my", "your",192 "i", "me", "we", "us", "you", "he", "she", "they", "them",193 "and", "or", "but", "not", "if", "then", "else", "so",194 "what", "how", "why", "when", "where", "which", "who",195 "que", "el", "la", "los", "las", "un", "una", "de", "en",196 "por", "para", "con", "es", "no", "si", "como", "me",197 "please", "help", "want", "need", "tell",198 }199 200 words = re.findall(r'[a-z0-9_./:-]+', text.lower())201 keywords = [w for w in words if w not in stopwords and len(w) > 1]202 203 # Also extract paths and commands204 paths = re.findall(r'/[\w./+-]+', text)205 keywords.extend(paths)206 207 return keywords[:20] # Cap at 20 keywords208 209 def _prune(self):210 """Remove old or excess entries."""211 now = time.time()212 max_age = MAX_EXAMPLE_AGE_DAYS * 86400213 214 # Remove old entries215 self.examples = [216 ex for ex in self.examples217 if now - ex.get("timestamp", now) < max_age218 ]219 220 # If still too many, keep the most successful/used ones221 if len(self.examples) > MAX_EXAMPLES_PER_CATEGORY * 5:222 # Sort by (success, -age) and keep top N223 self.examples.sort(224 key=lambda ex: (ex.get("success", True), -ex.get("timestamp", 0)),225 reverse=True,226 )227 self.examples = self.examples[:MAX_EXAMPLES_PER_CATEGORY * 5]228 229 def _seed_examples(self) -> List[Dict]:230 """Seed initial few-shot examples for cold start."""231 now = time.time()232 seeds = [233 # Tool call examples234 {235 "user": "check disk space",236 "assistant": '{"name": "execute_local", "arguments": {"command": "df -h"}}',237 "intent": "tool_call",238 "keywords": ["check", "disk", "space"],239 "tool_name": "execute_local",240 "success": True,241 "timestamp": now,242 "uses": 0,243 },244 {245 "user": "what processes are using the most memory",246 "assistant": '{"name": "execute_local", "arguments": {"command": "ps aux --sort=-%mem | head -20"}}',247 "intent": "tool_call",248 "keywords": ["processes", "memory"],249 "tool_name": "execute_local",250 "success": True,251 "timestamp": now,252 "uses": 0,253 },254 {255 "user": "read the nginx config",256 "assistant": '{"name": "read_file", "arguments": {"path": "/etc/nginx/nginx.conf"}}',257 "intent": "tool_call",258 "keywords": ["read", "nginx", "config"],259 "tool_name": "read_file",260 "success": True,261 "timestamp": now,262 "uses": 0,263 },264 {265 "user": "find all python files with TODO comments",266 "assistant": '{"name": "search_files", "arguments": {"pattern": "TODO", "glob": "*.py"}}',267 "intent": "tool_call",268 "keywords": ["find", "python", "todo"],269 "tool_name": "search_files",270 "success": True,271 "timestamp": now,272 "uses": 0,273 },274 {275 "user": "check system health",276 "assistant": '{"name": "diagnose", "arguments": {"target": "local"}}',277 "intent": "tool_call",278 "keywords": ["check", "system", "health"],279 "tool_name": "diagnose",280 "success": True,281 "timestamp": now,282 "uses": 0,283 },284 {285 "user": "show me the contents of /etc/hostname",286 "assistant": '{"name": "read_file", "arguments": {"path": "/etc/hostname"}}',287 "intent": "tool_call",288 "keywords": ["show", "contents", "/etc/hostname"],289 "tool_name": "read_file",290 "success": True,291 "timestamp": now,292 "uses": 0,293 },294 {295 "user": "list docker containers",296 "assistant": '{"name": "execute_local", "arguments": {"command": "docker ps -a"}}',297 "intent": "tool_call",298 "keywords": ["docker", "containers", "list"],299 "tool_name": "execute_local",300 "success": True,301 "timestamp": now,302 "uses": 0,303 },304 {305 "user": "scan ports on 192.168.1.1",306 "assistant": '{"name": "execute_local", "arguments": {"command": "nmap -sV 192.168.1.1"}}',307 "intent": "tool_call",308 "keywords": ["scan", "ports", "nmap", "192.168.1.1"],309 "tool_name": "execute_local",310 "success": True,311 "timestamp": now,312 "uses": 0,313 },314 # Text examples (NO tool calls)315 {316 "user": "what is SQL injection",317 "assistant": "SQL injection is an attack where malicious SQL code is inserted into application queries through user input. The attacker can read, modify, or delete database data, bypass authentication, or even execute system commands. Prevention: parameterized queries, input validation, least-privilege DB accounts, WAF rules.",318 "intent": "text",319 "keywords": ["sql", "injection"],320 "success": True,321 "timestamp": now,322 "uses": 0,323 },324 {325 "user": "explain the TCP 3-way handshake",326 "assistant": "TCP 3-way handshake establishes a connection: (1) Client sends SYN with initial sequence number, (2) Server responds SYN-ACK with its own sequence number and acknowledges client's, (3) Client sends ACK. After this, data flows bidirectionally. Termination uses a 4-way FIN handshake.",327 "intent": "text",328 "keywords": ["tcp", "handshake"],329 "success": True,330 "timestamp": now,331 "uses": 0,332 },333 {334 "user": "hi",335 "assistant": "Hey. What do you need?",336 "intent": "text",337 "keywords": ["hi"],338 "success": True,339 "timestamp": now,340 "uses": 0,341 },342 # Decision examples (model correctly chose NOT to use tool)343 {344 "user": "what is docker",345 "assistant": "Docker is a containerization platform that packages applications with their dependencies into isolated containers. Containers share the host kernel (unlike VMs), making them lightweight and fast. Key concepts: images (blueprints), containers (running instances), Dockerfile (build instructions), docker-compose (multi-container apps).",346 "intent": "decision",347 "keywords": ["docker"],348 "success": True,349 "timestamp": now,350 "uses": 0,351 },352 ]353 return seeds354 